diff --git a/.gitignore b/.gitignore index 05e8466434..20ea9aed3a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,10 +11,9 @@ distribution/windows/*.exe # Build artifacts .cache -#libcurl -lib/libcurl/ -#libjansson -lib/jansson/ +#lib +lib +libversion ################# ## Eclipse @@ -58,6 +57,7 @@ local.properties *.suo *.user *.sln.docstates +.vs/ # Build results @@ -65,6 +65,7 @@ local.properties [Rr]elease/ x64/ build/ +build_*/ [Bb]in/ [Oo]bj/ diff --git a/.travis.yml b/.travis.yml index 067ef67593..4a7ae74da1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,11 +7,28 @@ script: - bash build.sh notifications: - irc: "irc.freenode.net#openrct2-dev" - on_failure: always + on_failure: change on_success: change -cache: +cache: directories: - - cache + - .cache apt: true + +env: + - OPENRCT2_CMAKE_OPTS="-DDISABLE_NETWORK=ON -DDISABLE_HTTP_TWITCH=ON -DCMAKE_C_COMPILER=gcc-4.8 -DCMAKE_CXX_COMPILER=g++-4.8" + - OPENRCT2_CMAKE_OPTS="-DDISABLE_NETWORK=ON -DDISABLE_HTTP_TWITCH=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++" + - OPENRCT2_CMAKE_OPTS="-DDISABLE_NETWORK=OFF -DDISABLE_HTTP_TWITCH=ON -DCMAKE_C_COMPILER=gcc-4.8 -DCMAKE_CXX_COMPILER=g++-4.8" + - OPENRCT2_CMAKE_OPTS="-DDISABLE_NETWORK=OFF -DDISABLE_HTTP_TWITCH=OFF -DCMAKE_C_COMPILER=gcc-4.8 -DCMAKE_CXX_COMPILER=g++-4.8" + - OPENRCT2_CMAKE_OPTS="-DCMAKE_TOOLCHAIN_FILE=../CMakeLists_mingw.txt" TARGET=windows + - OPENRCT2_CMAKE_OPTS="-DDISABLE_NETWORK=ON -DCMAKE_TOOLCHAIN_FILE=../CMakeLists_mingw.txt" TARGET=windows + - OPENRCT2_CMAKE_OPTS="-DDISABLE_NETWORK=ON -DDISABLE_HTTP_TWITCH=ON -DCMAKE_TOOLCHAIN_FILE=../CMakeLists_mingw.txt" TARGET=windows + - OPENRCT2_CMAKE_OPTS="-DDISABLE_HTTP_TWITCH=ON -DCMAKE_TOOLCHAIN_FILE=../CMakeLists_mingw.txt" TARGET=windows + - TARGET=docker32 + - OPENRCT2_CMAKE_OPTS="-DDISABLE_NETWORK=ON -DDISABLE_HTTP_TWITCH=ON" TARGET=docker32 + +sudo: required +dist: trusty + +services: + - docker diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f830b4805..3eba8200d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,37 +26,75 @@ 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(FindPkgConfig) + +option(DISABLE_HTTP_TWITCH "Disable HTTP and Twitch support.") +if (DISABLE_HTTP_TWITCH) + add_definitions(-DDISABLE_HTTP -DDISABLE_TWITCH) +else (DISABLE_HTTP_TWITCH) + PKG_CHECK_MODULES(LIBCURL REQUIRED libcurl) + PKG_CHECK_MODULES(JANSSON REQUIRED jansson) + SET(HTTPLIBS ${LIBCURL_LIBRARIES} ${JANSSON_LIBRARIES}) + if (WIN32) + SET(HTTPLIBS ${HTTPLIBS} ssl crypto winmm.lib ws2_32) + endif (WIN32) +endif (DISABLE_HTTP_TWITCH) + +option(DISABLE_NETWORK "Disable multiplayer functionality. Mainly for testing.") +if (DISABLE_NETWORK) + add_definitions(-DDISABLE_NETWORK) +else (DISABLE_NETWORK) + if (WIN32) + SET(NETWORKLIBS ${NETWORKLIBS} ws2_32) + endif (WIN32) +endif (DISABLE_NETWORK) + +set(DEBUG_LEVEL 0 CACHE STRING "Select debug level for compilation. Use value in range 0–3.") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEBUG=${DEBUG_LEVEL}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG=${DEBUG_LEVEL}") # include lib include_directories("lib/") -# include speex header -include_directories("lib/libspeex/") # add source files -file(GLOB_RECURSE ORCT2_SOURCES "src/*.c" "src/*.cpp" "lib/*.c") +file(GLOB_RECURSE ORCT2_SOURCES "src/*.c" "src/*.cpp" "lib/argparse/*.c" "lib/cutest/*.c" "lib/lodepng/*.c") if (UNIX) # force 32bit build for now and set necessary flags to compile code as is - set(CMAKE_C_FLAGS "-m32 -masm=intel -std=gnu99") - set(CMAKE_LDFLAGS_FLAGS "-m32") - - # find and include SDL2 - INCLUDE(FindPkgConfig) - PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2) - INCLUDE_DIRECTORIES(${SDL2_INCLUDE_DIRS}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -std=gnu99 -fno-omit-frame-pointer") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32 -std=gnu++11 -fno-omit-frame-pointer") + set(CMAKE_SHARED_LINKER_FLAGS "-m32") + set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}) endif (UNIX) -INCLUDE_DIRECTORIES(${ORCALIBS_INCLUDE} ${JANSSON_INCLUDE}) -LINK_DIRECTORIES(${SDL2_LIBRARY_DIRS} ${ORCALIBS_LIB_DIR}) +# find and include SDL2 +PKG_CHECK_MODULES(SDL2 REQUIRED sdl2 SDL2_ttf) -# build as library for now, replace with add_executable -add_library(${PROJECT} SHARED ${ORCT2_SOURCES}) +# speex v1.1.15 is supplied in our zipped library, but distributions provide +# updated version, with required functions extracted out to libspeexdsp. +# This largely takes care of the problem +if (WIN32) + include_directories("lib/libspeex/") + file(GLOB_RECURSE SPEEX_SOURCES "lib/libspeex/*.c") +else (WIN32) + PKG_CHECK_MODULES(SPEEX REQUIRED speexdsp) +endif (WIN32) + +# Include libdl for dlopen +if (UNIX) + set(DLLIB dl) +endif (UNIX) + +INCLUDE_DIRECTORIES(${SDL2_INCLUDE_DIRS} ${LIBCURL_INCLUDE_DIRS} ${JANSSON_INCLUDE_DIRS} ${SPEEX_INCLUDE_DIRS}) + +LINK_DIRECTORIES(${SDL2_LIBRARY_DIRS} ${JANSSON_LIBRARY_DIRS} ${LIBCURL_LIBRARY_DIRS}) + +if (WIN32) + # build as library for now, replace with add_executable + add_library(${PROJECT} SHARED ${ORCT2_SOURCES} ${SPEEX_SOURCES}) +else (WIN32) + add_executable(${PROJECT} ${ORCT2_SOURCES}) +endif (WIN32) # install into ${CMAKE_INSTALL_PREFIX}/bin/ #install (TARGETS ${PROJECT} DESTINATION bin) @@ -64,9 +102,4 @@ add_library(${PROJECT} SHARED ${ORCT2_SOURCES}) # libopenrct2.dll -> openrct2.dll set_target_properties(${PROJECT} PROPERTIES PREFIX "") -TARGET_LINK_LIBRARIES(${PROJECT} ${SDL2_LIBRARIES} ${ORCALIBS_LIB}) - -if (WIN32) - target_link_libraries(${PROJECT} winmm.lib -limm32 -lversion -ldsound) -endif (WIN32) - +TARGET_LINK_LIBRARIES(${PROJECT} ${SDL2_LIBRARIES} ${ORCTLIBS_LIB} ${JANSSON_LIBRARIES} ${HTTPLIBS} ${NETWORKLIBS} ${SPEEX_LIBRARIES} ${DLLIB}) diff --git a/CMakeLists_mingw.txt b/CMakeLists_mingw.txt index 96fae66e68..d4817994d1 100644 --- a/CMakeLists_mingw.txt +++ b/CMakeLists_mingw.txt @@ -1,3 +1,4 @@ +SET(ACTUAL_SYSTEM ${CMAKE_SYSTEM_NAME}) SET(CMAKE_SYSTEM_NAME Windows) SET(COMPILER_PREFIX i686-w64-mingw32) @@ -10,14 +11,13 @@ 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=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 -INCLUDE(FindPkgConfig) -PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2) -INCLUDE_DIRECTORIES(${SDL2_INCLUDE_DIRS}) +set(CMAKE_C_FLAGS "-std=gnu99 -fpack-struct=1" CACHE STRING "" FORCE) +set(CMAKE_CXX_FLAGS "-std=c++0x -std=gnu++0x -fpack-struct=1" CACHE STRING "" FORCE) +if(${ACTUAL_SYSTEM} MATCHES "Linux") + set(CMAKE_SHARED_LINKER_FLAGS "-O3 -static-libgcc -static-libstdc++ -static -lpthread" CACHE STRING "" FORCE) +else() + set(CMAKE_SHARED_LINKER_FLAGS "-static-libgcc -static-libstdc++" CACHE STRING "" FORCE) +endif(${ACTUAL_SYSTEM} MATCHES "Linux") if(APPLE) SET(TARGET_ENVIRONMENT /usr/local/mingw-w32-bin_i686-darwin/i686-w64-mingw32) @@ -34,3 +34,5 @@ SET(CMAKE_FIND_ROOT_PATH ${TARGET_ENVIRONMENT}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +# INCLUDE_DIRECTORIES(${ORCTLIBS_INCLUDE} ${JANSSON_INCLUDE}) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..e58c2296e3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,42 @@ +# Contributing to OpenRCT2 +Any contribution to OpenRCT2 is welcome and valued. Contributions can be in the form of bug reports, translation or code +additions / changes. Please read this document to learn how to contribute as effectively as possible. If you have any +questions or concerns, please ask in the [gitter](https://gitter.im/OpenRCT2/OpenRCT2) chat room. + +# Reporting bugs +To report a bug, ensure you have a GitHub account. Search the issues page to see if the bug has already been reported. +If not, create a new issue and write the steps to reproduce. Upload a saved game if possible and this is very helpful +for users to replicate the bug. Please state which version of the game you are running and where you downloaded it from, e.g. *openrct2.com develop 0.0.3 build 1255 (ec25b2f)*. + +# Translation +Translation is managed in a separate repository, [OpenRCT2/Localisation](https://github.com/OpenRCT2/Localisation). +You will find more information there. + +# Contributing code +## Steps +1. First, ensure you have a GitHub account and [fork](https://help.github.com/articles/fork-a-repo/) the OpenRCT2 repository. +2. Create a new branch from develop (unless you are contributing to another) and commit your changes to that. +3. Submit a new [pull request](https://help.github.com/articles/using-pull-requests/). +4. Wait for other users to test and review your changes. + +## Credits +If you are contributing to OpenRCT2, please add your name to ```./contributors.md``` so that you can be credited for your +work outside and inside the game. + +## Code hints +### Adding new strings +If you need to add a new localisable string to OpenRCT2, please add your new string entry to ```./data/language/english_uk.txt```. +It is important that you only edit English (UK) in the OpenRCT2 repository as this is the base language that is used for +translation to other languages. A separate repository OpenRCT2/Localisation is used for translation pull requests, and changes +to that repository are merged with the OpenRCT2 main repository every night. When your pull request is merged, it is helpful +to create a new issue in the OpenRCT2/Localisation repository about the new strings you have added. This notifies translators +so that they can translate the new strings as quick as possible. Similarly if you change any existing string, it is more +important that you create an issue as this can be more easily overlooked. + +When coding, please also add a string constant for your strings to ```./src/localisation/string_ids.h```. + +### Coding style / language +OpenRCT2 currently does not have a strict coding style. This will be implemented after the entire game is implemented and +undergoes heavy refactoring. For now, it is recommended that you only write C files as the majority of the game is currenlty in +C. Exceptions are to modules that have no direct relationship to original code such as the new software audio mixer, the +HTTP integration and the Twitch integration. diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000000..b9d7498dca --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,4 @@ +version: 0.0.3.{build} +build_script: +- set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH% +- .\build.bat \ No newline at end of file diff --git a/build.sh b/build.sh index 49df49f378..d1dc442fa3 100755 --- a/build.sh +++ b/build.sh @@ -2,27 +2,99 @@ set -e +cachedir=.cache +mkdir -p $cachedir + +# Sets default target to "linux", if none specified +TARGET=${TARGET-linux} + if [[ ! -d build ]]; then mkdir -p build fi +# keep in sync with version in install.sh +sha256sum=69ff98c9544838fb16384bc78af9dc1c452b9d01d919e43f5fec686d02c9bdd8 +libVFile="./libversion" +libdir="./lib" +currentversion=0 +needsdownload="true" + +if [ -f $libVFile ]; then + while read line; do + currentversion=$line + continue + done < $libVFile +fi + +if [ "z$currentversion" == "z$sha256sum" ]; then + needsdownload="false" +fi + +if [ ! -d $libdir ]; then + needsdownload="true" +fi + +if [[ "$needsdownload" = "true" ]]; then + echo "Found library had sha256sum $currentversion, expected $sha256sum" + echo "New libraries need to be downloaded. Clearing cache and calling ./install.sh" + rm -rf ./lib + if [[ -f $cachedir/orctlibs.zip ]]; then + rm -rf $cachedir/orctlibs.zip + fi + if [[ -d /usr/local/cross-tools/orctlibs ]]; then + sudo rm -rf /usr/local/cross-tools/orctlibs + fi + if [[ -d $cachedir/orctlibs ]]; then + rm -rf $cachedir/orctlibs + fi + ./install.sh +fi + pushd build - cmake -DCMAKE_TOOLCHAIN_FILE=../CMakeLists_mingw.txt -DCMAKE_BUILD_TYPE=Debug .. - make + echo OPENRCT2_CMAKE_OPTS = $OPENRCT2_CMAKE_OPTS + if [[ $TARGET == "docker32" ]] + then + PARENT=$(readlink -f ../) + chmod a+rwx $(pwd) + chmod g+s $(pwd) + docker run -u travis -v $PARENT:/work/openrct2 -w /work/openrct2/build -i -t openrct2/openrct2:32bit-only bash -c "cmake ../ $OPENRCT2_CMAKE_OPTS && make" + else + cmake -DCMAKE_BUILD_TYPE=Debug $OPENRCT2_CMAKE_OPTS .. + make + fi popd +if [[ $TARGET == "windows" ]]; then + if [[ ! -h openrct2.dll ]]; then + ln -s build/openrct2.dll openrct2.dll + fi +fi + +if [[ ! -h build/data ]]; then + ln -s ../data build/data +fi + +if [[ $TARGET == "linux" ]] || [[ $TARGET == "docker32" ]]; then + if [[ ! -h openrct2 ]]; then + ln -s build/openrct2 openrct2 + fi +fi + 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 - -if [[ -t 1 ]]; then - echo -e "\nDone! Run OpenRCT2 by typing:\n\n\033[95mwine openrct2.exe\n\033[0m" +if [[ $TARGET == "windows" ]]; then + if [[ -t 1 ]]; then + echo -e "\nDone! Run OpenRCT2 by typing:\n\n\033[95mwine openrct2.exe\n\033[0m" + else + echo -e "\nDone! Run OpenRCT2 by typing:\n\nwine openrct2.exe\n" + fi else - echo -e "\nDone! Run OpenRCT2 by typing:\n\nwine openrct2.exe\n" + if [[ -t 1 ]]; then + echo -e "\nDone! Run OpenRCT2 by typing:\n\n\033[95m./openrct2\n\033[0m" + else + echo -e "\nDone! Run OpenRCT2 by typing:\n\n./openrct2\n" + fi fi - diff --git a/build_g2.sh b/build_g2.sh index d870c40205..3d3a72b307 100755 --- a/build_g2.sh +++ b/build_g2.sh @@ -1,3 +1,7 @@ #!/bin/bash -wine openrct2.exe sprite build data/g2.dat resources/g2/ +if [[ $TARGET == "windows" ]]; then + wine openrct2.exe sprite build data/g2.dat resources/g2/ +else + ./openrct2 sprite build data/g2.dat resources/g2/ +fi diff --git a/clean.sh b/clean.sh index 85a5dac6d8..24517377fa 100755 --- a/clean.sh +++ b/clean.sh @@ -4,5 +4,6 @@ set -ev sudo rm -rf /usr/local/cross-tools/i686-w64-mingw32 sudo rm -rf /usr/local/cross-tools/orcalibs +sudo rm -rf /usr/local/cross-tools/orctlibs rm -rf .cache rm -rf build diff --git a/contributors.md b/contributors.md index 7ef94f24ca..358ba95111 100644 --- a/contributors.md +++ b/contributors.md @@ -2,11 +2,17 @@ Includes all git commit authors. Aliases are GitHub user names. ## Project team -* Ted John (IntelOrca) - Owner +* Ted John (IntelOrca) - Owner, merger, issue management +* Duncan Frost (duncanspumpkin) - Merger, issue management +* Michael Steenbeek (Gymnasiast) - Translation management +* Rune Laenen (runelaenen) - Translation management +* Miso Zmiric (mzmiric5) - Dependency / library management ## Long term developers * Ted John (IntelOrca) * Duncan Frost (duncanspumpkin) +* Michael Steenbeek (Gymnasiast) +* (zsilencer) ## Implementation (RCT2) * Ted John (IntelOrca) @@ -14,12 +20,11 @@ Includes all git commit authors. Aliases are GitHub user names. * Peter Hill (ZedThree) - String handling, misc. * (qcz) - Scenery window, misc. * Matthias Lanzinger (lnz) - Climate, finance, scenario, ride reachability -* (zsilencer) - Audio, misc. +* (zsilencer) - Audio, multiplayer, 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. @@ -29,11 +34,11 @@ Includes all git commit authors. Aliases are GitHub user names. * (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 +* Michael Steenbeek (Gymnasiast) - Cheats, RCT1 ride style, misc. * Miso Zmiric (mzmiric5) - Misc. * (DutchRPW) - Housecleaning, initialisation * Jørn Lomax (jvlomax) - User configuration @@ -41,11 +46,16 @@ Includes all git commit authors. Aliases are GitHub user names. * Alexander Overvoorde (Overv) - Misc. * (eezstreet) - Misc. * Thomas den Hollander (ThomasdenH) - Misc. +* James Robertson (rd3k) - Misc. +* Robert Jordan (trigger-death) - UI theming, title sequence editor, misc. ## Bug fixes * (halfbro) * (Myrtle) * (nean) +* Ed Foley (e-foley) +* Michael Pham (nightroan) +* Hielke Morsink (Broxzier) ## Toolchain * (Balletie) - OSX @@ -53,6 +63,7 @@ Includes all git commit authors. Aliases are GitHub user names. * Miso Zmiric (mzmiric5) - OSX * Jarno Veuger (JarnoVgr) - Windows build server * Ted John (IntelOrca) - Windows +* Michał Janiszewski (janisozaur) - Linux, Travis CI ## Documentation * (honzi) @@ -60,16 +71,27 @@ Includes all git commit authors. Aliases are GitHub user names. * James Robertson (rd3k) * Max Boße (MakaHost) * (MaxBareiss) -* Philip Plarkson (Philpax) +* Mithun Hunsur (Philpax) * (RollingStar) ## Translation +* Extracting from original files: Ted John (IntelOrca) +* Reviewing and merging: Rune Laenen (runelaenen), Michael Steenbeek (Gymnasiast) +* Fixing unmaintained languages: Michael Steenbeek (Gymnasiast) * English (UK) - Ted John (IntelOrca), (Tinytimrob) -* French - (fbourigault) -* German - (atmaxinger), (Yepoleb) -* Dutch - Michael Steenbeek (Gymnasiast), (hostbrute), (mrtnptrs), (xzbobzx) +* English (US) - Ted John (IntelOrca), Michael Steenbeek (Gymnasiast) +* Dutch - Michael Steenbeek (Gymnasiast), (xzbobzx), (mrtnptrs), Thomas den Hollander (ThomasdenH), (hostbrute); reviewing and discussion: Aaron van Geffen (AaronVanGeffen), (Balletie) and Sijmen Schoon (Vijfhoek). +* Finnish - (DJHasis) +* French - (fbourigault), Joël Troch (JoelTroch), Michael Steenbeek (Gymnasiast) +* German - (danidoedel), (atmaxinger), (Yepoleb), Daniel Kessel (dkessel), Leon (AllGoodNamesAreTaken) +* Korean - "TELK" (telk5093) +* Polish - Adrian Wielgosik (adrian17) +* Portuguese (BR) - (kaudy) +* Russian - (Soosisya) +* Simplified Chinese - Naiji Ma (naijim) * Spanish - (mdtrooper) -* Swedish - (Jinxit), (mharrys) +* Swedish - (Jinxit), (mharrys), (Slimeyo) +* Traditional Chinese - Harry Lam (daihakken) ## Graphics * OpenRCT2 Logo - xzbobzx diff --git a/data/language/chinese_simplified.txt b/data/language/chinese_simplified.txt new file mode 100644 index 0000000000..e6e1d54475 --- /dev/null +++ b/data/language/chinese_simplified.txt @@ -0,0 +1,3829 @@ +# 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 :螺旋过山车 +STR_0003 :站立过山车 +STR_0004 :悬挂摇摆过山车 +STR_0005 :回转过山车 +STR_0006 :儿童过山车 +STR_0007 :迷你火车 +STR_0008 :单轨电车 +STR_0009 :迷你悬挂过山车 +STR_0010 :游船出租 +STR_0011 :木制疯狂老鼠过山车 +STR_0012 :赛马过山车 +STR_0013 :轨道小车 +STR_0014 :喷射-自由落体 +STR_0015 :雪橇过山车 +STR_0016 :观景塔 +# I could not find this thing in the game +STR_0017 :Looping Roller Coaster +STR_0018 :充气小艇滑道 +STR_0019 :矿车过山车 +STR_0020 :缆车 +# STR_0021 has the same meaning as STR_0001 in chinese +STR_0021 :Corkscrew Roller Coaster +STR_0022 :迷宫 +STR_0023 :螺旋滑梯 +STR_0024 :卡丁车 +STR_0025 :原木滑水道 +STR_0026 :激流探险 +STR_0027 :碰碰车 +STR_0028 :海盗船 +STR_0029 :摇摆海盗船 +STR_0030 :食品小站 +STR_0031 :Unknown Stall (1D) +STR_0032 :饮料铺 +STR_0033 :Unknown Stall (1F) +STR_0034 :商店 +STR_0035 :旋转木马 +STR_0036 :Unknown Stall (22) +STR_0037 :问讯处 +STR_0038 :厕所 +STR_0039 :摩天轮 +STR_0040 :动感模拟器 +STR_0041 :3D电影院 +# passengers ride in a gondola +STR_0042 :旋转贡多拉 +# alternative may be 失速模拟 +STR_0043 :太空转轮 +STR_0044 :反向自由落体过山车 +STR_0045 :升降观景台 +STR_0046 :垂直坠落过山车 +STR_0047 :自动取款机 +STR_0048 :龙卷风 +STR_0049 :鬼屋 +STR_0050 :急救室 +STR_0051 :马戏表演 +STR_0052 :Tunnel Of Horror +STR_0053 :Steel Twister Roller Coaster +STR_0054 :木制过山车 +STR_0055 :Side-Friction Roller Coaster +STR_0056 :疯狂老鼠过山车 +STR_0057 :多维过山车 +STR_0058 :Unknown Ride (38) +STR_0059 :飞翔过山车 +STR_0060 :Unknown Ride (3A) +STR_0061 :弗吉尼亚卷轴 +STR_0062 :Splash Boats +STR_0063 :迷你直升机 +STR_0064 :躺卧过山车 +STR_0065 :悬挂式单轨电车 +STR_0066 :Unknown Ride (40) +STR_0067 :反转过山车 +STR_0068 :Heartline Twister Coaster +STR_0069 :迷你高尔夫 +STR_0070 :巨型过山车 +STR_0071 :Roto-Drop +STR_0072 :转转飞碟 +STR_0073 :鬼怪屋 +STR_0074 :单轨自行车 +STR_0075 :紧凑回转过山车 +STR_0076 :Water Coaster +STR_0077 :喷气弹射过山车 +STR_0078 :回转发卡过山车 +STR_0079 :魔毯 +STR_0080 :迷你潜艇 +STR_0081 :小木筏 +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 :回转冲力过山车 +STR_0089 :迷你过山车 +STR_0090 :Mine Ride +STR_0091 :Unknown Ride (59) +# LIM: Linear Induction Motors +STR_0092 :LIM喷射过山车 +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 :A looping roller coaster where the riders ride in a standing position +STR_0514 :Trains suspended beneath the roller coaster track swing out to the side around corners +STR_0515 :A steel roller coaster with trains that are held beneath the track, with many complex and twisting track elements +STR_0516 :A gentle roller coaster for people who haven't yet got the courage to face the larger rides +STR_0517 :Passengers ride in miniature trains along a narrow-gauge railway track +STR_0518 :Passengers travel in electric trains along a monorail track +STR_0519 :Passengers ride in small cars hanging beneath the single-rail track, swinging freely from side to side around corners +STR_0520 :A dock platform where guests can drive/row personal watercraft on a body of water +STR_0521 :A fast and twisting roller coaster with tight turns and steep drops. Intensity is bound to be high. +STR_0522 :A smaller roller coaster where the riders sit above the track with no car around them +STR_0523 :Riders travel slowly in powered vehicles along a track-based route +STR_0524 :Freefall car is pneumatically launched up a tall steel tower and then allowed to freefall down +STR_0525 :Riders career down a twisting track guided only by the curvature and banking of the semi-circular track +STR_0526 :Passengers travel in a rotating observation cabin which travels up a tall tower +STR_0527 :A smooth steel-tracked roller coaster capable of vertical loops +STR_0528 :Riders travel in inflatable dinghies down a twisting semi-circular or completely enclosed tube track +STR_0529 :Mine train themed roller coaster trains career along steel roller coaster track made to look like old railway track +STR_0530 :Cars hang from a steel cable which runs continuously from one end of the ride to the other and back again +STR_0531 :A compact steel-tracked roller coaster where the train travels through corkscrews and loops +STR_0532 : +STR_0533 : +STR_0534 :Self-drive petrol-engined go karts +STR_0535 :Log-shaped boats travel along a water channel, splashing down steep slopes to soak the riders +STR_0536 :Circular boats meander along a wide water channel, splashing through waterfalls and thrilling riders through foaming rapids +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 :The car is accelerated out of the station along a long level track using Linear Induction Motors, then heads straight up a vertical spike of track, freefalling back down to return to the station +STR_0555 :Guests ride in an elevator up or down a vertical tower to get from one level to another +STR_0556 :Extra-wide cars descend completely vertical sloped track for the ultimate freefall roller coaster experience +STR_0557 : +STR_0558 : +STR_0559 : +STR_0560 : +STR_0561 : +STR_0562 :Powered cars travel along a multi-level track past spooky scenery and special effects +STR_0563 :Sitting in comfortable trains with only simple lap restraints riders enjoy giant smooth drops and twisting track as well as plenty of 'air time' over the hills +STR_0564 :Running on wooden track, this coaster is fast, rough, noisy, and gives an 'out of control' riding experience with plenty of 'air time' +STR_0565 :A simple wooden roller coaster capable of only gentle slopes and turns, where the cars are only kept on the track by side friction wheels and gravity +STR_0566 :Individual roller coaster cars zip around a tight zig-zag layout of track with sharp corners and short sharp drops +STR_0567 :Sitting in seats suspended either side of the track, riders are pitched head-over-heels while they plunge down steep drops and travel through various inversions +STR_0568 : +STR_0569 :Riding in special harnesses below the track, riders experience the feeling of flight as they swoop through the air +STR_0570 : +STR_0571 :Circular cars spin around as they travel along the zig-zagging wooden track +STR_0572 :Large capacity boats travel along a wide water channel, propelled up slopes by a conveyer belt, accelerating down steep slopes to soak the riders with a gaint splash +STR_0573 :Powered helicoper shaped cars running on a steel track, controlled by the pedalling of the riders +STR_0574 :Riders are held in special harnesses in a lying-down position, travlling through twisted track and inversions either on their backs or facing the ground +STR_0575 :Powered trains hanging from a single rail transport people around the park +STR_0576 : +STR_0577 :Bogied cars run on wooden tracks, turning around on special reversing sections +STR_0578 :Cars run along track enclosed by circular hoops, traversing steep drops and heartline twists +STR_0579 : +STR_0580 :A giant steel roller coaster capable of smooth drops and hills of over 300ft +STR_0581 :A ring of seats is pulled to the top of a tall tower while gently rotating, then allowed to free-fall down, stopping gently at the bottom using magnetic brakes +STR_0582 : +STR_0583 : +STR_0584 :Special bicycles run on a steel monorail track, propelled by the pedalling of the riders +STR_0585 :Riders sit in pairs of seats suspended beneath the track as they loop and twist through tight inversions +STR_0586 :Boat shaped cars run on roller coaster track to allow twisting curves and steep drops, splashing down into sections of water for gentle river sections +STR_0587 :After an exhilarating air-powered launch, the train speeds up a vertical track, over the top, and vertically down the other side to return to the station +STR_0588 :Individual cars run beneath a zig-zagging track with hairpin turns and sharp drops +STR_0589 : +STR_0590 :Riders ride in a submerged submarine through an underwater course +STR_0591 :Raft-shaped boats gently meander around a river track +STR_0592 : +STR_0593 : +STR_0594 : +STR_0595 : +STR_0596 : +STR_0597 : +STR_0598 :Inverted roller coaster trains are accelerated out of the station to travel up a vertical spike of track, then reverse back through the station to travel backwards up another vertical spike of track +STR_0599 :A compact roller coaster with individual cars and smooth twisting drops +STR_0600 :Powered mine trains career along a smooth and twisted track layout +STR_0601 : +STR_0602 :Roller coaster trains are accelerated out of the station by linear induction motors to speed through twisting inversions +STR_0603 :游客 {INT32} +STR_0604 :游客 {INT32} +STR_0605 :游客 {INT32} +STR_0606 :游客 {INT32} +STR_0607 :游客 {INT32} +STR_0608 :游客 {INT32} +STR_0609 :游客 {INT32} +STR_0610 :游客 {INT32} +STR_0611 :游客 {INT32} +STR_0612 :游客 {INT32} +STR_0613 :游客 {INT32} +STR_0614 :游客 {INT32} +STR_0615 :游客 {INT32} +STR_0616 :游客 {INT32} +STR_0617 :游客 {INT32} +STR_0618 :游客 {INT32} +STR_0619 :游客 {INT32} +STR_0620 :游客 {INT32} +STR_0621 :游客 {INT32} +STR_0622 :游客 {INT32} +STR_0623 :游客 {INT32} +STR_0624 :游客 {INT32} +STR_0625 :游客 {INT32} +STR_0626 :游客 {INT32} +STR_0627 :游客 {INT32} +STR_0628 :游客 {INT32} +STR_0629 :游客 {INT32} +STR_0630 :游客 {INT32} +STR_0631 :游客 {INT32} +STR_0632 :游客 {INT32} +STR_0633 :游客 {INT32} +STR_0634 :游客 {INT32} +STR_0635 :游客 {INT32} +STR_0636 :游客 {INT32} +STR_0637 :游客 {INT32} +STR_0638 :游客 {INT32} +STR_0639 :游客 {INT32} +STR_0640 :游客 {INT32} +STR_0641 :游客 {INT32} +STR_0642 :游客 {INT32} +STR_0643 :游客 {INT32} +STR_0644 :游客 {INT32} +STR_0645 :游客 {INT32} +STR_0646 :游客 {INT32} +STR_0647 :游客 {INT32} +STR_0648 :游客 {INT32} +STR_0649 :游客 {INT32} +STR_0650 :游客 {INT32} +STR_0651 :游客 {INT32} +STR_0652 :游客 {INT32} +STR_0653 :游客 {INT32} +STR_0654 :游客 {INT32} +STR_0655 :游客 {INT32} +STR_0656 :游客 {INT32} +STR_0657 :游客 {INT32} +STR_0658 :游客 {INT32} +STR_0659 :游客 {INT32} +STR_0660 :游客 {INT32} +STR_0661 :游客 {INT32} +STR_0662 :游客 {INT32} +STR_0663 :游客 {INT32} +STR_0664 :游客 {INT32} +STR_0665 :游客 {INT32} +STR_0666 :游客 {INT32} +STR_0667 :游客 {INT32} +STR_0668 :游客 {INT32} +STR_0669 :游客 {INT32} +STR_0670 :游客 {INT32} +STR_0671 :游客 {INT32} +STR_0672 :游客 {INT32} +STR_0673 :游客 {INT32} +STR_0674 :游客 {INT32} +STR_0675 :游客 {INT32} +STR_0676 :游客 {INT32} +STR_0677 :游客 {INT32} +STR_0678 :游客 {INT32} +STR_0679 :游客 {INT32} +STR_0680 :游客 {INT32} +STR_0681 :游客 {INT32} +STR_0682 :游客 {INT32} +STR_0683 :游客 {INT32} +STR_0684 :游客 {INT32} +STR_0685 :游客 {INT32} +STR_0686 :游客 {INT32} +STR_0687 :游客 {INT32} +STR_0688 :游客 {INT32} +STR_0689 :游客 {INT32} +STR_0690 :游客 {INT32} +STR_0691 :游客 {INT32} +STR_0692 :游客 {INT32} +STR_0693 :游客 {INT32} +STR_0694 :游客 {INT32} +STR_0695 :游客 {INT32} +STR_0696 :游客 {INT32} +STR_0697 :游客 {INT32} +STR_0698 :游客 {INT32} +STR_0699 :游客 {INT32} +STR_0700 :游客 {INT32} +STR_0701 :游客 {INT32} +STR_0702 :游客 {INT32} +STR_0703 :游客 {INT32} +STR_0704 :游客 {INT32} +STR_0705 :游客 {INT32} +STR_0706 :游客 {INT32} +STR_0707 :游客 {INT32} +STR_0708 :游客 {INT32} +STR_0709 :游客 {INT32} +STR_0710 :游客 {INT32} +STR_0711 :游客 {INT32} +STR_0712 :游客 {INT32} +STR_0713 :游客 {INT32} +STR_0714 :游客 {INT32} +STR_0715 :游客 {INT32} +STR_0716 :游客 {INT32} +STR_0717 :游客 {INT32} +STR_0718 :游客 {INT32} +STR_0719 :游客 {INT32} +STR_0720 :游客 {INT32} +STR_0721 :游客 {INT32} +STR_0722 :游客 {INT32} +STR_0723 :游客 {INT32} +STR_0724 :游客 {INT32} +STR_0725 :游客 {INT32} +STR_0726 :游客 {INT32} +STR_0727 :游客 {INT32} +STR_0728 :游客 {INT32} +STR_0729 :游客 {INT32} +STR_0730 :游客 {INT32} +STR_0731 :游客 {INT32} +STR_0732 :游客 {INT32} +STR_0733 :游客 {INT32} +STR_0734 :游客 {INT32} +STR_0735 :游客 {INT32} +STR_0736 :游客 {INT32} +STR_0737 :游客 {INT32} +STR_0738 :游客 {INT32} +STR_0739 :游客 {INT32} +STR_0740 :游客 {INT32} +STR_0741 :游客 {INT32} +STR_0742 :游客 {INT32} +STR_0743 :游客 {INT32} +STR_0744 :游客 {INT32} +STR_0745 :游客 {INT32} +STR_0746 :游客 {INT32} +STR_0747 :游客 {INT32} +STR_0748 :游客 {INT32} +STR_0749 :游客 {INT32} +STR_0750 :游客 {INT32} +STR_0751 :游客 {INT32} +STR_0752 :游客 {INT32} +STR_0753 :游客 {INT32} +STR_0754 :游客 {INT32} +STR_0755 :游客 {INT32} +STR_0756 :游客 {INT32} +STR_0757 :游客 {INT32} +STR_0758 :游客 {INT32} +STR_0759 :游客 {INT32} +STR_0760 :游客 {INT32} +STR_0761 :游客 {INT32} +STR_0762 :游客 {INT32} +STR_0763 :游客 {INT32} +STR_0764 :游客 {INT32} +STR_0765 :游客 {INT32} +STR_0766 :游客 {INT32} +STR_0767 :游客 {INT32} +STR_0768 :勤杂工 {INT32} +STR_0769 :维修员 {INT32} +STR_0770 :警卫 {INT32} +STR_0771 :表演人员 {INT32} +STR_0772 :未命名游乐园{POP16}{POP16} +STR_0773 :未命名游乐园{POP16}{POP16} +STR_0774 :未命名游乐园{POP16}{POP16} +STR_0775 :未命名游乐园{POP16}{POP16} +STR_0776 :未命名游乐园{POP16}{POP16} +STR_0777 :未命名游乐园{POP16}{POP16} +STR_0778 :Sign +STR_0779 :1日 +STR_0780 :2日 +STR_0781 :3日 +STR_0782 :4日 +STR_0783 :5日 +STR_0784 :6日 +STR_0785 :7日 +STR_0786 :8日 +STR_0787 :9日 +STR_0788 :10日 +STR_0789 :11日 +STR_0790 :12日 +STR_0791 :13日 +STR_0792 :14日 +STR_0793 :15日 +STR_0794 :16日 +STR_0795 :17日 +STR_0796 :18日 +STR_0797 :19日 +STR_0798 :20日 +STR_0799 :21日 +STR_0800 :22日 +STR_0801 :23日 +STR_0802 :24日 +STR_0803 :25日 +STR_0804 :26日 +STR_0805 :27日 +STR_0806 :28日 +STR_0807 :29日 +STR_0808 :30日 +STR_0809 :31日 +STR_0810 :1月 +STR_0811 :2月 +STR_0812 :3月 +STR_0813 :4月 +STR_0814 :5月 +STR_0815 :6月 +STR_0816 :7月 +STR_0817 :8月 +STR_0818 :9月 +STR_0819 :10月 +STR_0820 :11月 +STR_0821 :12月 +STR_0822 :无法访问图形数据 +STR_0823 :数据文件丢失或不可访问 +STR_0824 :{BLACK}{CROSS} +STR_0825 :该名称已被使用 +STR_0826 :过多名称被定义 +STR_0827 :现金不足 - 需要 {CURRENCY2DP} +STR_0828 :{SMALLFONT}{BLACK}关闭窗口 +STR_0829 :{SMALLFONT}{BLACK}窗口标题 - 拖拽来移动窗口 +STR_0830 :{SMALLFONT}{BLACK}放大 +STR_0831 :{SMALLFONT}{BLACK}缩小 +STR_0832 :{SMALLFONT}{BLACK}顺时针旋转90{DEGREE} +STR_0833 :{SMALLFONT}{BLACK}暂停游戏 +STR_0834 :{SMALLFONT}{BLACK}磁盘和游戏选项 +STR_0835 :游戏初始化失败 +STR_0836 :最小化状态下无法启动游戏 +STR_0837 :无法初始化图形系统 +STR_0838 : +STR_0839 :{UINT16} x {UINT16} +STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +STR_0847 :关于'OpenRCT2' +STR_0848 :RollerCoaster Tycoon 2 +STR_0849 :{WINDOW_COLOUR_2}版本 2.01.028 +STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, all rights reserved +STR_0851 :{WINDOW_COLOUR_2}Designed and programmed by Chris Sawyer +STR_0852 :{WINDOW_COLOUR_2}Graphics by Simon Foster +STR_0853 :{WINDOW_COLOUR_2}Sound and music by Allister Brimble +STR_0854 :{WINDOW_COLOUR_2}Additional sounds recorded by David Ellis +STR_0855 :{WINDOW_COLOUR_2}Representation by Jacqui Lyons at Marjacq Ltd. +STR_0856 :{WINDOW_COLOUR_2}致谢: +STR_0857 :{WINDOW_COLOUR_2}Peter James Adcock, Joe Booth, and 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 :太低! +STR_0878 :太高! +STR_0879 :不能降低土地... +STR_0880 :不能抬升土地... +STR_0881 :有物体挡住去路 +STR_0882 :载入游戏 +STR_0883 :保存游戏 +STR_0884 :载入地形 +STR_0885 :保存地形 +STR_0886 :退出游戏 +STR_0887 :退出场景编辑器 +STR_0888 :退出过山车设计工具 +STR_0889 :退出轨道设计管理工具 +STR_0890 :SCR{COMMA16}.BMP +STR_0891 :截图 +STR_0892 :截图 '{STRINGID}' 已保存 +STR_0893 :截图失败! +STR_0894 :Landscape data area full ! +STR_0895 :Can't build partly above and partly below ground +STR_0896 :{POP16}{POP16}{STRINGID} Construction +STR_0897 :方向 +STR_0898 :{SMALLFONT}{BLACK}左转 +STR_0899 :{SMALLFONT}{BLACK}右转 +STR_0900 :{SMALLFONT}{BLACK}左转 (小弧度) +STR_0901 :{SMALLFONT}{BLACK}右转 (小弧度) +STR_0902 :{SMALLFONT}{BLACK}Left-hand curve (very small radius) +STR_0903 :{SMALLFONT}{BLACK}Right-hand curve (very small radius) +STR_0904 :{SMALLFONT}{BLACK}Left-hand curve (large radius) +STR_0905 :{SMALLFONT}{BLACK}Right-hand curve (large radius) +STR_0906 :{SMALLFONT}{BLACK}Straight +STR_0907 :Slope +STR_0908 :Roll/Banking +STR_0909 :Seat Rot. +STR_0910 :{SMALLFONT}{BLACK}Roll for left-hand curve +STR_0911 :{SMALLFONT}{BLACK}Roll for right-hand curve +STR_0912 :{SMALLFONT}{BLACK}No roll +STR_0913 :{SMALLFONT}{BLACK}Move to previous section +STR_0914 :{SMALLFONT}{BLACK}Move to next section +STR_0915 :{SMALLFONT}{BLACK}Construct the selected section +STR_0916 :{SMALLFONT}{BLACK}Remove the highlighted section +STR_0917 :{SMALLFONT}{BLACK}Vertical drop +STR_0918 :{SMALLFONT}{BLACK}Steep slope down +STR_0919 :{SMALLFONT}{BLACK}Slope down +STR_0920 :{SMALLFONT}{BLACK}Level +STR_0921 :{SMALLFONT}{BLACK}Slope up +STR_0922 :{SMALLFONT}{BLACK}Steep slope up +STR_0923 :{SMALLFONT}{BLACK}Vertical rise +STR_0924 :{SMALLFONT}{BLACK}Helix down +STR_0925 :{SMALLFONT}{BLACK}Helix up +STR_0926 :Can't remove this... +STR_0927 :Can't construct this here... +STR_0928 :{SMALLFONT}{BLACK}Chain lift, to pull cars up slopes +STR_0929 :'S' Bend (left) +STR_0930 :'S' Bend (right) +STR_0931 :Vertical Loop (left) +STR_0932 :Vertical Loop (right) +STR_0933 :Raise or lower land first +STR_0934 :Ride entrance in the way +STR_0935 :Ride exit in the way +STR_0936 :Park entrance in the way +STR_0937 :{SMALLFONT}{BLACK}View options +STR_0938 :{SMALLFONT}{BLACK}Adjust land height and slope +STR_0939 :Underground/Inside View +STR_0940 :Remove Base Land +STR_0941 :Remove Vertical Faces +STR_0942 :See-Through Rides +STR_0943 :See-Through Scenery +STR_0944 :Save +STR_0945 :Don't Save +STR_0946 :Cancel +STR_0947 :Save this before loading ? +STR_0948 :Save this before quitting ? +STR_0949 :Save this before quitting ? +STR_0950 :Load Game +STR_0951 :Quit Game +STR_0952 :Quit Game +STR_0953 :Load Landscape +STR_0954 : +STR_0955 :{SMALLFONT}{BLACK}Select seat rotation angle for this track section +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 :Cancel +STR_0973 :OK +STR_0974 :Rides +STR_0975 :Shops and Stalls +STR_0976 :Restrooms and Information Kiosks +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_0984 :{WINDOW_COLOUR_2}{UP}{BLACK} {CURRENCY2DP} +STR_0985 :{WINDOW_COLOUR_2}{DOWN}{BLACK} {CURRENCY2DP} +STR_0986 :{BLACK}{CURRENCY2DP} +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 +STR_0998 :No more stations allowed on this ride +STR_0999 :Requires a station platform +STR_1000 :Track is not a complete circuit +STR_1001 :Track unsuitable for type of train +STR_1002 :Can't open {POP16}{POP16}{POP16}{STRINGID}... +STR_1003 :Can't test {POP16}{POP16}{POP16}{STRINGID}... +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 +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... +STR_1018 :Can't make changes... +STR_1019 :Can't make changes... +STR_1020 :Can't make changes... +STR_1021 :{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_1022 :{POP16}{POP16}{POP16}{COMMA16} car per train +STR_1023 :{POP16}{POP16}{POP16}{COMMA16} cars per train +STR_1024 :{COMMA16} car per train +STR_1025 :{COMMA16} cars per train +STR_1026 :Station platform too long! +STR_1027 :{SMALLFONT}{BLACK}Locate this on Main View +STR_1028 :Off edge of map! +STR_1029 :Cannot build partly above and partly below water! +STR_1030 :Can only build this underwater! +STR_1031 :Can't build this underwater! +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 :OpenRCT2 Saved Game +STR_1044 :OpenRCT2 Scenario File +STR_1045 :OpenRCT2 Landscape File +STR_1046 :OpenRCT2 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 +STR_1057 :Ride/attraction name +STR_1058 :Enter new name for this ride/attraction: +STR_1059 :Can't rename ride/attraction... +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 (passing station) +STR_1065 :Shuttle mode +STR_1066 :Boat hire mode +STR_1067 :Upward launch +STR_1068 :Rotating lift mode +STR_1069 :Station to station mode +STR_1070 :Single ride per admission +STR_1071 :Unlimited rides per admission +STR_1072 :Maze mode +STR_1073 :Race mode +STR_1074 :Bumper-car mode +STR_1075 :Swing mode +STR_1076 :Shop stall mode +STR_1077 :Rotation mode +STR_1078 :Forward rotation +STR_1079 :Backward rotation +STR_1080 :Film: {ENDQUOTES}Avenging aviators{ENDQUOTES} +STR_1081 :3D film: {ENDQUOTES}Mouse tails{ENDQUOTES} +STR_1082 :Space rings mode +STR_1083 :Beginners mode +STR_1084 :LIM-powered launch +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 mode +STR_1089 :Berserk mode +STR_1090 :Haunted house mode +STR_1091 :Circus show mode +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 (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} +STR_1100 :Waiting to depart {POP16}{STRINGID} +STR_1101 :Departing {POP16}{STRINGID} +STR_1102 :Traveling at {VELOCITY} +STR_1103 :Arriving at {POP16}{STRINGID} +STR_1104 :Unloading passengers at {POP16}{STRINGID} +STR_1105 :Traveling at {VELOCITY} +STR_1106 :Crashing! +STR_1107 :Crashed! +STR_1108 :Traveling at {VELOCITY} +STR_1109 :Swinging +STR_1110 :Rotating +STR_1111 :Rotating +STR_1112 :Operating +STR_1113 :Showing film +STR_1114 :Rotating +STR_1115 :Operating +STR_1116 :Operating +STR_1117 :Doing circus show +STR_1118 :Operating +STR_1119 :Waiting for cable lift +STR_1120 :Traveling at {VELOCITY} +STR_1121 :Stopping +STR_1122 :Waiting for passengers +STR_1123 :Waiting to start +STR_1124 :Starting +STR_1125 :Operating +STR_1126 :Stopping +STR_1127 :Unloading passengers +STR_1128 :Stopped by block brakes +STR_1129 :All vehicles in same colors +STR_1130 :Different colors per {STRINGID} +STR_1131 :Different colors per vehicle +STR_1132 :Vehicle {POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1133 :Vehicle {POP16}{COMMA16} +STR_1134 :{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} {COMMA16} +STR_1135 :{STRINGID} {COMMA16} +STR_1136 :{SMALLFONT}{BLACK}Select main color +STR_1137 :{SMALLFONT}{BLACK}Select additional color 1 +STR_1138 :{SMALLFONT}{BLACK}Select additional color 2 +STR_1139 :{SMALLFONT}{BLACK}Select support structure color +STR_1140 :{SMALLFONT}{BLACK}Select vehicle color scheme option +STR_1141 :{SMALLFONT}{BLACK}Select which vehicle/train to modify +STR_1142 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1143 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRINGID} +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 +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_1162 :{OUTLINE}{TOPAZ}{STRINGID} +STR_1163 :{STRINGID}{NEWLINE}(Right-Click to Modify) +STR_1164 :{STRINGID}{NEWLINE}(Right-Click to Remove) +STR_1165 :{STRINGID} - {STRINGID} {COMMA16} +STR_1166 :Can't lower water level here... +STR_1167 :Can't raise water level here... +STR_1168 :Options +STR_1169 :(None) +STR_1170 :{STRING} +STR_1171 :{RED}Closed - - +STR_1172 :{YELLOW}{STRINGID} - - +STR_1173 :{SMALLFONT}{BLACK}Build footpaths and queue lines +STR_1174 :Banner sign in the way +STR_1175 :Can't build this on sloped footpath +STR_1176 :Can't build footpath here... +STR_1177 :Can't remove footpath from here... +STR_1178 :Land slope unsuitable +STR_1179 :Footpath in the way +STR_1180 :Can't build this underwater! +STR_1181 :Footpaths +STR_1182 :Type +STR_1183 :Direction +STR_1184 :Slope +STR_1185 :{SMALLFONT}{BLACK}Direction +STR_1186 :{SMALLFONT}{BLACK}Slope down +STR_1187 :{SMALLFONT}{BLACK}Level +STR_1188 :{SMALLFONT}{BLACK}Slope up +STR_1189 :{SMALLFONT}{BLACK}Construct the selected footpath section +STR_1190 :{SMALLFONT}{BLACK}Remove previous footpath section +STR_1191 :{BLACK}{STRINGID} +STR_1192 :{OUTLINE}{RED}{STRINGID} +STR_1193 :{WINDOW_COLOUR_2}{STRINGID} +STR_1194 :Closed +STR_1195 :Test Run +STR_1196 :Open +STR_1197 :Broken Down +STR_1198 :Crashed! +STR_1199 :{COMMA16} person on ride +STR_1200 :{COMMA16} people on ride +STR_1201 :Nobody in queue line +STR_1202 :1 person in queue line +STR_1203 :{COMMA16} people in queue line +STR_1204 :{COMMA16} minute queue time +STR_1205 :{COMMA16} minutes queue time +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_1218 :{BLACK}{SMALLUP} +STR_1219 :{BLACK}{SMALLDOWN} +STR_1220 :Exit only +STR_1221 :No entrance +STR_1222 :No exit +STR_1223 :{SMALLFONT}{BLACK}Transport rides +STR_1224 :{SMALLFONT}{BLACK}Gentle rides +STR_1225 :{SMALLFONT}{BLACK}Roller coasters +STR_1226 :{SMALLFONT}{BLACK}Thrill rides +STR_1227 :{SMALLFONT}{BLACK}Water rides +STR_1228 :{SMALLFONT}{BLACK}Shops & stalls +STR_1229 :train +STR_1230 :trains +STR_1231 :Train +STR_1232 :Trains +STR_1233 :{COMMA16} train +STR_1234 :{COMMA16} trains +STR_1235 :Train {COMMA16} +STR_1236 :boat +STR_1237 :boats +STR_1238 :Boat +STR_1239 :Boats +STR_1240 :{COMMA16} boat +STR_1241 :{COMMA16} boats +STR_1242 :Boat {COMMA16} +STR_1243 :track +STR_1244 :tracks +STR_1245 :Track +STR_1246 :Tracks +STR_1247 :{COMMA16} track +STR_1248 :{COMMA16} tracks +STR_1249 :Track {COMMA16} +STR_1250 :docking platform +STR_1251 :docking platforms +STR_1252 :Docking platform +STR_1253 :Docking platforms +STR_1254 :{COMMA16} docking platform +STR_1255 :{COMMA16} docking platforms +STR_1256 :Docking platform {COMMA16} +STR_1257 :station +STR_1258 :stations +STR_1259 :Station +STR_1260 :Stations +STR_1261 :{COMMA16} station +STR_1262 :{COMMA16} stations +STR_1263 :Station {COMMA16} +STR_1264 :car +STR_1265 :cars +STR_1266 :Car +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_1278 :structure +STR_1279 :structures +STR_1280 :Structure +STR_1281 :Structures +STR_1282 :{COMMA16} structure +STR_1283 :{COMMA16} structures +STR_1284 :Structure {COMMA16} +STR_1285 :ship +STR_1286 :ships +STR_1287 :Ship +STR_1288 :Ships +STR_1289 :{COMMA16} ship +STR_1290 :{COMMA16} ships +STR_1291 :Ship {COMMA16} +STR_1292 :cabin +STR_1293 :cabins +STR_1294 :Cabin +STR_1295 :Cabins +STR_1296 :{COMMA16} cabin +STR_1297 :{COMMA16} cabins +STR_1298 :Cabin {COMMA16} +STR_1299 :wheel +STR_1300 :wheels +STR_1301 :Wheel +STR_1302 :Wheels +STR_1303 :{COMMA16} wheel +STR_1304 :{COMMA16} wheels +STR_1305 :Wheel {COMMA16} +STR_1306 :ring +STR_1307 :rings +STR_1308 :Ring +STR_1309 :Rings +STR_1310 :{COMMA16} ring +STR_1311 :{COMMA16} rings +STR_1312 :Ring {COMMA16} +STR_1313 :player +STR_1314 :players +STR_1315 :Player +STR_1316 :Players +STR_1317 :{COMMA16} player +STR_1318 :{COMMA16} players +STR_1319 :Player {COMMA16} +STR_1320 :course +STR_1321 :courses +STR_1322 :Course +STR_1323 :Courses +STR_1324 :{COMMA16} course +STR_1325 :{COMMA16} courses +STR_1326 :Course {COMMA16} +STR_1327 :{SMALLFONT}{BLACK}Rotate objects by 90{DEGREE} +STR_1328 :Level land required +STR_1329 :{WINDOW_COLOUR_2}Launch speed: +STR_1330 :{SMALLFONT}{BLACK}Maximum speed when leaving station +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} - Entrance{POP16}{POP16} +STR_1336 :{STRINGID} - Station {POP16}{COMMA16} Entrance +STR_1337 :{STRINGID} - Exit{POP16}{POP16} +STR_1338 :{STRINGID} - Station {POP16}{COMMA16} Exit +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} +STR_1342 :{DURATION} +STR_1343 :{DURATION} / +STR_1344 :{WINDOW_COLOUR_2}Ride length: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1345 :{LENGTH} +STR_1346 :{LENGTH} / +STR_1347 :{WINDOW_COLOUR_2}Average speed: {BLACK}{VELOCITY} +STR_1348 :{WINDOW_COLOUR_2}Max. positive vertical G's: {BLACK}{COMMA2DP32}g +STR_1349 :{WINDOW_COLOUR_2}Max. positive vertical G's: {OUTLINE}{RED}{COMMA2DP32}g +STR_1350 :{WINDOW_COLOUR_2}Max. negative vertical G's: {BLACK}{COMMA2DP32}g +STR_1351 :{WINDOW_COLOUR_2}Max. negative vertical G's: {OUTLINE}{RED}{COMMA2DP32}g +STR_1352 :{WINDOW_COLOUR_2}Max. lateral G's: {BLACK}{COMMA2DP32}g +STR_1353 :{WINDOW_COLOUR_2}Max. lateral G's: {OUTLINE}{RED}{COMMA2DP32}g +STR_1354 :{WINDOW_COLOUR_2}Highest drop height: {BLACK}{LENGTH} +STR_1355 :{WINDOW_COLOUR_2}Drops: {BLACK}{COMMA16} +STR_1356 :{WINDOW_COLOUR_2}Inversions: {BLACK}{COMMA16} +STR_1357 :{WINDOW_COLOUR_2}Holes: {BLACK}{COMMA16} +STR_1358 :{WINDOW_COLOUR_2}Total 'air' time: {BLACK}{COMMA2DP32}secs +STR_1359 :{WINDOW_COLOUR_2}Queue time: {BLACK}{COMMA16} minute +STR_1360 :{WINDOW_COLOUR_2}Queue time: {BLACK}{COMMA16} minutes +STR_1361 :Can't change speed... +STR_1362 :Can't change launch speed... +STR_1363 :Too high for supports! +STR_1364 :Supports for track above can't be extended any further! +STR_1365 :In-line Twist (left) +STR_1366 :In-line Twist (right) +STR_1367 :Half Loop +STR_1368 :Half Corkscrew (left) +STR_1369 :Half Corkscrew (right) +STR_1370 :Barrel Roll (left) +STR_1371 :Barrel Roll (right) +STR_1372 :Launched Lift Hill +STR_1373 :Large Half Loop (left) +STR_1374 :Large Half Loop (right) +STR_1375 :Upper Transfer +STR_1376 :Lower Transfer +STR_1377 :Heartline Roll (left) +STR_1378 :Heartline Roll (right) +STR_1379 :Reverser (left) +STR_1380 :Reverser (right) +STR_1381 :Curved Lift Hill (left) +STR_1382 :Curved Lift Hill (right) +STR_1383 :Quarter Loop +STR_1384 :{YELLOW}{STRINGID} +STR_1385 :{SMALLFONT}{BLACK}Other track configurations +STR_1386 :Special... +STR_1387 :Can't change land type... +STR_1388 :{OUTLINE}{GREEN}+ {CURRENCY} +STR_1389 :{OUTLINE}{RED}- {CURRENCY} +STR_1390 :{CURRENCY2DP} +STR_1391 :{RED}{CURRENCY2DP} +STR_1392 :{SMALLFONT}{BLACK}View of ride/attraction +STR_1393 :{SMALLFONT}{BLACK}Vehicle details and options +STR_1394 :{SMALLFONT}{BLACK}Operating options +STR_1395 :{SMALLFONT}{BLACK}Maintenance options +STR_1396 :{SMALLFONT}{BLACK}Color scheme options +STR_1397 :{SMALLFONT}{BLACK}Sound & music options +STR_1398 :{SMALLFONT}{BLACK}Measurements and test data +STR_1399 :{SMALLFONT}{BLACK}Graphs +STR_1400 :Entrance +STR_1401 :Exit +STR_1402 :{SMALLFONT}{BLACK}Build or move entrance to ride/attraction +STR_1403 :{SMALLFONT}{BLACK}Build or move exit from ride/attraction +STR_1404 :{SMALLFONT}{BLACK}Rotate 90{DEGREE} +STR_1405 :{SMALLFONT}{BLACK}Mirror image +STR_1406 :{SMALLFONT}{BLACK}Toggle scenery on/off (if available for this design) +STR_1407 :{WINDOW_COLOUR_2}Build this... +STR_1408 :{WINDOW_COLOUR_2}Cost: {BLACK}{CURRENCY} +STR_1409 :Entry/Exit Platform +STR_1410 :Vertical Tower +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_1416 :{WINDOW_COLOUR_2}Altitude +STR_1417 :{WINDOW_COLOUR_2}Vert.G's +STR_1418 :{WINDOW_COLOUR_2}Lat.G's +STR_1419 :{SMALLFONT}{BLACK}{VELOCITY} +STR_1420 :{SMALLFONT}{BLACK}{LENGTH} +STR_1421 :{SMALLFONT}{BLACK}{COMMA16}g +STR_1422 :{SMALLFONT}{BLACK}Logging data from {POP16}{STRINGID} +STR_1423 :{SMALLFONT}{BLACK}Queue line path +STR_1424 :{SMALLFONT}{BLACK}Footpath +STR_1425 :Footpath +STR_1426 :Queue Line +STR_1427 :{WINDOW_COLOUR_2}Customers: {BLACK}{COMMA32} per hour +STR_1428 :{WINDOW_COLOUR_2}Admission price: +STR_1429 :{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1430 :Free +STR_1431 :Walking +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_1438 :Sitting +STR_1439 :(select location) +STR_1440 :Mowing grass +STR_1441 :Sweeping footpath +STR_1442 :Emptying litter bin +STR_1443 :Watering gardens +STR_1444 :Watching {STRINGID} +STR_1445 :Watching construction of {STRINGID} +STR_1446 :Looking at scenery +STR_1447 :Leaving the park +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_1453 :Enter name for this guest: +STR_1454 :Can't name guest... +STR_1455 :Invalid name for guest +STR_1456 :{WINDOW_COLOUR_2}Cash spent: {BLACK}{CURRENCY2DP} +STR_1457 :{WINDOW_COLOUR_2}Cash in pocket: {BLACK}{CURRENCY2DP} +STR_1458 :{WINDOW_COLOUR_2}Time in park: {BLACK}{REALTIME} +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_1464 :Helix up (small) +STR_1465 :Helix up (large) +STR_1466 :Helix down (small) +STR_1467 :Helix down (large) +STR_1468 :Staff +STR_1469 :Ride must start and end with stations +STR_1470 :Station not long enough +STR_1471 :{WINDOW_COLOUR_2}Speed: +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 +STR_1475 :{WINDOW_COLOUR_2}Intensity rating: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1476 :{WINDOW_COLOUR_2}Intensity rating: {BLACK}Not yet available +STR_1477 :{WINDOW_COLOUR_2}Intensity rating: {OUTLINE}{RED}{COMMA2DP32} ({STRINGID}) +STR_1478 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1479 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}Not yet available +STR_1480 :{SMALLFONT}{OPENQUOTES}I can't afford {STRINGID}{ENDQUOTES} +STR_1481 :{SMALLFONT}{OPENQUOTES}I've spent all my money{ENDQUOTES} +STR_1482 :{SMALLFONT}{OPENQUOTES}I feel sick{ENDQUOTES} +STR_1483 :{SMALLFONT}{OPENQUOTES}I feel very sick{ENDQUOTES} +STR_1484 :{SMALLFONT}{OPENQUOTES}I want to go on something more thrilling than {STRINGID}{ENDQUOTES} +STR_1485 :{SMALLFONT}{OPENQUOTES}{STRINGID} looks too intense for me{ENDQUOTES} +STR_1486 :{SMALLFONT}{OPENQUOTES}I haven't finished my {STRINGID} yet{ENDQUOTES} +STR_1487 :{SMALLFONT}{OPENQUOTES}Just looking at {STRINGID} makes me feel sick{ENDQUOTES} +STR_1488 :{SMALLFONT}{OPENQUOTES}I'm not paying that much to go on {STRINGID}{ENDQUOTES} +STR_1489 :{SMALLFONT}{OPENQUOTES}I want to go home{ENDQUOTES} +STR_1490 :{SMALLFONT}{OPENQUOTES}{STRINGID} is really good value{ENDQUOTES} +STR_1491 :{SMALLFONT}{OPENQUOTES}I've already got {STRINGID}{ENDQUOTES} +STR_1492 :{SMALLFONT}{OPENQUOTES}I can't afford {STRINGID}{ENDQUOTES} +STR_1493 :{SMALLFONT}{OPENQUOTES}I'm not hungry{ENDQUOTES} +STR_1494 :{SMALLFONT}{OPENQUOTES}I'm not thirsty{ENDQUOTES} +STR_1495 :{SMALLFONT}{OPENQUOTES}Help! I'm drowning!{ENDQUOTES} +STR_1496 :{SMALLFONT}{OPENQUOTES}I'm lost!{ENDQUOTES} +STR_1497 :{SMALLFONT}{OPENQUOTES}{STRINGID} was great{ENDQUOTES} +STR_1498 :{SMALLFONT}{OPENQUOTES}I've been queuing for {STRINGID} for ages{ENDQUOTES} +STR_1499 :{SMALLFONT}{OPENQUOTES}I'm tired{ENDQUOTES} +STR_1500 :{SMALLFONT}{OPENQUOTES}I'm hungry{ENDQUOTES} +STR_1501 :{SMALLFONT}{OPENQUOTES}I'm thirsty{ENDQUOTES} +STR_1502 :{SMALLFONT}{OPENQUOTES}I need to go to the bathroom{ENDQUOTES} +STR_1503 :{SMALLFONT}{OPENQUOTES}I can't find {STRINGID}{ENDQUOTES} +STR_1504 :{SMALLFONT}{OPENQUOTES}I'm not paying that much to use {STRINGID}{ENDQUOTES} +STR_1505 :{SMALLFONT}{OPENQUOTES}I'm not going on {STRINGID} while it's raining{ENDQUOTES} +STR_1506 :{SMALLFONT}{OPENQUOTES}The litter here is really bad{ENDQUOTES} +STR_1507 :{SMALLFONT}{OPENQUOTES}I can't find the park exit{ENDQUOTES} +STR_1508 :{SMALLFONT}{OPENQUOTES}I want to get off {STRINGID}{ENDQUOTES} +STR_1509 :{SMALLFONT}{OPENQUOTES}I want to get out of {STRINGID}{ENDQUOTES} +STR_1510 :{SMALLFONT}{OPENQUOTES}I'm not going on {STRINGID} - It isn't safe{ENDQUOTES} +STR_1511 :{SMALLFONT}{OPENQUOTES}This path is disgusting{ENDQUOTES} +STR_1512 :{SMALLFONT}{OPENQUOTES}It's too crowded here{ENDQUOTES} +STR_1513 :{SMALLFONT}{OPENQUOTES}The vandalism here is really bad{ENDQUOTES} +STR_1514 :{SMALLFONT}{OPENQUOTES}Great scenery!{ENDQUOTES} +STR_1515 :{SMALLFONT}{OPENQUOTES}This park is really clean and tidy{ENDQUOTES} +STR_1516 :{SMALLFONT}{OPENQUOTES}The jumping fountains are great{ENDQUOTES} +STR_1517 :{SMALLFONT}{OPENQUOTES}The music is nice here{ENDQUOTES} +STR_1518 :{SMALLFONT}{OPENQUOTES}This balloon from {STRINGID} is really good value{ENDQUOTES} +STR_1519 :{SMALLFONT}{OPENQUOTES}This cuddly toy from {STRINGID} is really good value{ENDQUOTES} +STR_1520 :{SMALLFONT}{OPENQUOTES}This park map from {STRINGID} is really good value{ENDQUOTES} +STR_1521 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} +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_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_1528 : +STR_1529 : +STR_1530 : +STR_1531 :{SMALLFONT}{OPENQUOTES}This pizza from {STRINGID} is really good value{ENDQUOTES} +STR_1532 : +STR_1533 :{SMALLFONT}{OPENQUOTES}This popcorn from {STRINGID} is really good value{ENDQUOTES} +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_1538 :{SMALLFONT}{OPENQUOTES}This T-shirt from {STRINGID} is really good value{ENDQUOTES} +STR_1539 :{SMALLFONT}{OPENQUOTES}This donut from {STRINGID} is really good value{ENDQUOTES} +STR_1540 :{SMALLFONT}{OPENQUOTES}This coffee from {STRINGID} is really good value{ENDQUOTES} +STR_1541 : +STR_1542 :{SMALLFONT}{OPENQUOTES}This fried chicken from {STRINGID} is really good value{ENDQUOTES} +STR_1543 :{SMALLFONT}{OPENQUOTES}This lemonade from {STRINGID} is really good value{ENDQUOTES} +STR_1544 : +STR_1545 : +STR_1546 : +STR_1547 : +STR_1548 : +STR_1549 : +STR_1550 :{SMALLFONT}{OPENQUOTES}Wow!{ENDQUOTES} +STR_1551 :{SMALLFONT}{OPENQUOTES}I have the strangest feeling someone is watching me{ENDQUOTES} +STR_1552 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a balloon from {STRINGID}{ENDQUOTES} +STR_1553 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a cuddly toy from {STRINGID}{ENDQUOTES} +STR_1554 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a park map from {STRINGID}{ENDQUOTES} +STR_1555 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} +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_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_1562 : +STR_1563 : +STR_1564 : +STR_1565 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for pizza from {STRINGID}{ENDQUOTES} +STR_1566 : +STR_1567 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for popcorn from {STRINGID}{ENDQUOTES} +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_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 donut from {STRINGID}{ENDQUOTES} +STR_1574 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for coffee from {STRINGID}{ENDQUOTES} +STR_1575 : +STR_1576 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fried chicken from {STRINGID}{ENDQUOTES} +STR_1577 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for lemonade from {STRINGID}{ENDQUOTES} +STR_1578 : +STR_1579 : +STR_1580 : +STR_1581 : +STR_1582 : +STR_1583 : +STR_1584 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} +STR_1585 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} +STR_1586 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} +STR_1587 :{SMALLFONT}{OPENQUOTES}This pretzel from {STRINGID} is really good value{ENDQUOTES} +STR_1588 :{SMALLFONT}{OPENQUOTES}This hot chocolate from {STRINGID} is really good value{ENDQUOTES} +STR_1589 :{SMALLFONT}{OPENQUOTES}This iced tea from {STRINGID} is really good value{ENDQUOTES} +STR_1590 :{SMALLFONT}{OPENQUOTES}This funnel cake from {STRINGID} is really good value{ENDQUOTES} +STR_1591 :{SMALLFONT}{OPENQUOTES}These sunglasses from {STRINGID} are really good value{ENDQUOTES} +STR_1592 :{SMALLFONT}{OPENQUOTES}These beef noodles from {STRINGID} are really good value{ENDQUOTES} +STR_1593 :{SMALLFONT}{OPENQUOTES}These fried rice noodles from {STRINGID} are really good value{ENDQUOTES} +STR_1594 :{SMALLFONT}{OPENQUOTES}This wonton soup from {STRINGID} is really good value{ENDQUOTES} +STR_1595 :{SMALLFONT}{OPENQUOTES}This meatball soup from {STRINGID} is really good value{ENDQUOTES} +STR_1596 :{SMALLFONT}{OPENQUOTES}This fruit juice from {STRINGID} is really good value{ENDQUOTES} +STR_1597 :{SMALLFONT}{OPENQUOTES}This soybean milk from {STRINGID} is really good value{ENDQUOTES} +STR_1598 :{SMALLFONT}{OPENQUOTES}This sujongkwa from {STRINGID} is really good value{ENDQUOTES} +STR_1599 :{SMALLFONT}{OPENQUOTES}This sub sandwich from {STRINGID} is really good value{ENDQUOTES} +STR_1600 :{SMALLFONT}{OPENQUOTES}This cookie from {STRINGID} is really good value{ENDQUOTES} +STR_1601 : +STR_1602 : +STR_1603 : +STR_1604 :{SMALLFONT}{OPENQUOTES}This roast sausage from {STRINGID} are really good value{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}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} +STR_1617 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} +STR_1618 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} +STR_1619 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a pretzel from {STRINGID}{ENDQUOTES} +STR_1620 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for hot chocolate from {STRINGID}{ENDQUOTES} +STR_1621 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for iced tea from {STRINGID}{ENDQUOTES} +STR_1622 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a funnel cake from {STRINGID}{ENDQUOTES} +STR_1623 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for sunglasses from {STRINGID}{ENDQUOTES} +STR_1624 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for beef noodles from {STRINGID}{ENDQUOTES} +STR_1625 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fried rice noodles from {STRINGID}{ENDQUOTES} +STR_1626 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for wonton soup from {STRINGID}{ENDQUOTES} +STR_1627 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for meatball soup from {STRINGID}{ENDQUOTES} +STR_1628 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fruit juice from {STRINGID}{ENDQUOTES} +STR_1629 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for soybean milk from {STRINGID}{ENDQUOTES} +STR_1630 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for sujongkwa from {STRINGID}{ENDQUOTES} +STR_1631 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a sub sandwich from {STRINGID}{ENDQUOTES} +STR_1632 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a cookie from {STRINGID}{ENDQUOTES} +STR_1633 : +STR_1634 : +STR_1635 : +STR_1636 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a roast sausage from {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}Help! Put me down!{ENDQUOTES} +STR_1649 :{SMALLFONT}{OPENQUOTES}I'm running out of cash!{ENDQUOTES} +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: +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_1673 :Spinning Control Toggle Track +STR_1674 :Brake speed +STR_1675 :{POP16}{VELOCITY} +STR_1676 :{SMALLFONT}{BLACK}Set speed limit for brakes +STR_1677 :{WINDOW_COLOUR_2}Popularity: {BLACK}Unknown +STR_1678 :{WINDOW_COLOUR_2}Popularity: {BLACK}{COMMA16}% +STR_1679 :Helix up (left) +STR_1680 :Helix up (right) +STR_1681 :Helix down (left) +STR_1682 :Helix down (right) +STR_1683 :Base size 2 x 2 +STR_1684 :Base size 4 x 4 +STR_1685 :Base size 2 x 4 +STR_1686 :Base size 5 x 1 +STR_1687 :Water splash +STR_1688 :Base size 4 x 1 +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_1694 :{SMALLFONT}{BLACK}Staff +STR_1695 :{SMALLFONT}{BLACK}Income and costs +STR_1696 :{SMALLFONT}{BLACK}Customer information +STR_1697 :Cannot place these on queue line area +STR_1698 :Can only place these on queue area +STR_1699 :Too many people in game +STR_1700 :Hire new Handyman +STR_1701 :Hire new Mechanic +STR_1702 :Hire new Security Guard +STR_1703 :Hire new Entertainer +STR_1704 :Can't hire new staff... +STR_1705 :{SMALLFONT}{BLACK}Sack this staff member +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_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 +STR_1714 :{INLINE_SPRITE}{249}{19}{00}{00}{WINDOW_COLOUR_2}Empty litter bins +STR_1715 :{INLINE_SPRITE}{250}{19}{00}{00}{WINDOW_COLOUR_2}Mow grass +STR_1716 :Invalid name for park +STR_1717 :Can't rename park... +STR_1718 :Park Name +STR_1719 :Enter name for park: +STR_1720 :{SMALLFONT}{BLACK}Name park +STR_1721 :Park closed +STR_1722 :Park open +STR_1723 :Can't open park... +STR_1724 :Can't close park... +STR_1725 :Can't buy land... +STR_1726 :Land not for sale! +STR_1727 :Construction rights not for sale! +STR_1728 :Can't buy construction rights here... +STR_1729 :Land not owned by park! +STR_1730 :{RED}Closed - - +STR_1731 :{WHITE}{STRINGID} - - +STR_1732 :Build +STR_1733 :Mode +STR_1734 :{WINDOW_COLOUR_2}Number of laps: +STR_1735 :{SMALLFONT}{BLACK}Number of laps of circuit +STR_1736 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1737 :{COMMA16} +STR_1738 :Can't change number of laps... +STR_1739 :Race won by guest {INT32} +STR_1740 :Race won by {STRINGID} +STR_1741 :Not yet constructed ! +STR_1742 :{WINDOW_COLOUR_2}Max. people on ride: +STR_1743 :{SMALLFONT}{BLACK}Maximum number of people allowed on this ride at one time +STR_1744 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1745 :{COMMA16} +STR_1746 :Can't change this... +STR_1747 :{WINDOW_COLOUR_2}Time limit: +STR_1748 :{SMALLFONT}{BLACK}Time limit for ride +STR_1749 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{DURATION} +STR_1750 :{DURATION} +STR_1751 :Can't change time limit for ride... +STR_1752 :{SMALLFONT}{BLACK}Show list of individual guests in park +STR_1753 :{SMALLFONT}{BLACK}Show summarized list of guests in park +STR_1754 :{BLACK}{COMMA16} guests +STR_1755 :{BLACK}{COMMA16} guest +STR_1756 :{WINDOW_COLOUR_2}Admission price: +STR_1757 :{WINDOW_COLOUR_2}Reliability: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1758 :{SMALLFONT}{BLACK}Build mode +STR_1759 :{SMALLFONT}{BLACK}Move mode +STR_1760 :{SMALLFONT}{BLACK}Fill-in mode +STR_1761 :{SMALLFONT}{BLACK}Build maze in this direction +STR_1762 :Waterfalls +STR_1763 :Rapids +STR_1764 :Log Bumps +STR_1765 :On-ride photo section +STR_1766 :Reverser turntable +STR_1767 :Spinning tunnel +STR_1768 :Can't change number of swings... +STR_1769 :{WINDOW_COLOUR_2}Number of swings: +STR_1770 :{SMALLFONT}{BLACK}Number of complete swings +STR_1771 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1772 :{COMMA16} +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_1778 :{STRINGID} - - +STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Panda costume +STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tiger costume +STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} Elephant costume +STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} Roman costume +STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} Gorilla costume +STR_1784 :{INLINE_SPRITE}{03}{20}{00}{00} Snowman costume +STR_1785 :{INLINE_SPRITE}{04}{20}{00}{00} Knight costume +STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} Astronaut costume +STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} Bandit costume +STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} Sheriff costume +STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} Pirate costume +STR_1790 :{SMALLFONT}{BLACK}Select uniform color for this type of staff +STR_1791 :{WINDOW_COLOUR_2}Uniform color: +STR_1792 :Responding to {STRINGID} breakdown call +STR_1793 :Heading to {STRINGID} for an inspection +STR_1794 :Fixing {STRINGID} +STR_1795 :Answering radio call +STR_1796 :Has broken down and requires fixing +STR_1797 :This option cannot be changed for this ride +STR_1798 :Whirlpool +STR_1799 :{POP16}{POP16}{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1800 :Safety cut-out +STR_1801 :Restraints stuck closed +STR_1802 :Restraints stuck open +STR_1803 :Doors stuck closed +STR_1804 :Doors stuck open +STR_1805 :Vehicle malfunction +STR_1806 :Brakes failure +STR_1807 :Control failure +STR_1808 :{WINDOW_COLOUR_2}Last breakdown: {BLACK}{STRINGID} +STR_1809 :{WINDOW_COLOUR_2}Current breakdown: {OUTLINE}{RED}{STRINGID} +STR_1810 :{WINDOW_COLOUR_2}Carrying: +STR_1811 :Can't build this here... +STR_1812 :{SMALLFONT}{BLACK}{STRINGID} +STR_1813 :Miscellaneous Objects +STR_1814 :Actions +STR_1815 :Thoughts +STR_1816 :{SMALLFONT}{BLACK}Select information type to show in guest list +STR_1817 :({COMMA16}) +STR_1818 :{WINDOW_COLOUR_2}All guests +STR_1819 :{WINDOW_COLOUR_2}All guests (summarized) +STR_1820 :{WINDOW_COLOUR_2}Guests {STRINGID} +STR_1821 :{WINDOW_COLOUR_2}Guests thinking {STRINGID} +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: {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 +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}{CURRENCY2DP} 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_1867 :{BLACK}{COMMA16} {STRINGID} +STR_1868 :Can't change number of rotations... +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}{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 +STR_1878 :{WINDOW_COLOUR_2}Inspection: +STR_1879 :Every 10 minutes +STR_1880 :Every 20 minutes +STR_1881 :Every 30 minutes +STR_1882 :Every 45 minutes +STR_1883 :Every hour +STR_1884 :Every 2 hours +STR_1885 :Never +STR_1886 :Inspecting {STRINGID} +STR_1887 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}{COMMA16} minutes +STR_1888 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}more than 4 hours +STR_1889 :{WINDOW_COLOUR_2}Down-Time: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1890 :{SMALLFONT}{BLACK}Select how often a mechanic should check this ride +STR_1891 :No {STRINGID} in park yet! +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 : +STR_1893 : +STR_1894 :{WINDOW_COLOUR_2}{STRINGID} sold: {BLACK}{COMMA32} +STR_1895 :{SMALLFONT}{BLACK}Build new ride/attraction +STR_1896 :{WINDOW_COLOUR_2}Expenditure/Income +STR_1897 :{WINDOW_COLOUR_2}Ride construction +STR_1898 :{WINDOW_COLOUR_2}Ride running costs +STR_1899 :{WINDOW_COLOUR_2}Land purchase +STR_1900 :{WINDOW_COLOUR_2}Landscaping +STR_1901 :{WINDOW_COLOUR_2}Park entrance tickets +STR_1902 :{WINDOW_COLOUR_2}Ride tickets +STR_1903 :{WINDOW_COLOUR_2}Shop sales +STR_1904 :{WINDOW_COLOUR_2}Shop stock +STR_1905 :{WINDOW_COLOUR_2}Food/drink sales +STR_1906 :{WINDOW_COLOUR_2}Food/drink stock +STR_1907 :{WINDOW_COLOUR_2}Staff wages +STR_1908 :{WINDOW_COLOUR_2}Marketing +STR_1909 :{WINDOW_COLOUR_2}Research +STR_1910 :{WINDOW_COLOUR_2}Loan interest +STR_1911 :{BLACK} at {COMMA16}% per year +STR_1912 :{MONTH} +STR_1913 :{BLACK}+{CURRENCY2DP} +STR_1914 :{BLACK}{CURRENCY2DP} +STR_1915 :{RED}{CURRENCY2DP} +STR_1916 :{WINDOW_COLOUR_2}Loan: +STR_1917 :{POP16}{POP16}{POP16}{CURRENCY} +STR_1918 :Can't borrow any more money! +STR_1919 :Not enough cash available! +STR_1920 :Can't pay back loan! +STR_1921 :{SMALLFONT}{BLACK}Start a new game +STR_1922 :{SMALLFONT}{BLACK}Continue playing a saved game +STR_1923 :{SMALLFONT}{BLACK}Show tutorial +STR_1924 :{SMALLFONT}{BLACK}Exit +STR_1925 :Can't place person here... +STR_1926 :{SMALLFONT} +STR_1927 :{YELLOW}{STRINGID} has broken down +STR_1928 :{RED}{STRINGID} has crashed! +STR_1929 :{RED}{STRINGID} still hasn't been fixed{NEWLINE}Check where your mechanics are and consider organizing them better +STR_1930 :{SMALLFONT}{BLACK}Turn on/off tracking information for this guest - (If tracking is on, guest's movements will be reported in the message area) +STR_1931 :{STRINGID} has joined the queue line for {STRINGID} +STR_1932 :{STRINGID} is on {STRINGID} +STR_1933 :{STRINGID} is in {STRINGID} +STR_1934 :{STRINGID} has left {STRINGID} +STR_1935 :{STRINGID} has left the park +STR_1936 :{STRINGID} has bought {STRINGID} +STR_1937 :{SMALLFONT}{BLACK}Show information about the subject of this message +STR_1938 :{SMALLFONT}{BLACK}Show view of guest +STR_1939 :{SMALLFONT}{BLACK}Show view of staff member +STR_1940 :{SMALLFONT}{BLACK}Show happiness, energy, hunger etc. for this guest +STR_1941 :{SMALLFONT}{BLACK}Show which rides this guest has been on +STR_1942 :{SMALLFONT}{BLACK}Show financial information about this guest +STR_1943 :{SMALLFONT}{BLACK}Show guest's recent thoughts +STR_1944 :{SMALLFONT}{BLACK}Show items guest is carrying +STR_1945 :{SMALLFONT}{BLACK}Show orders and options for this staff member +STR_1946 :{SMALLFONT}{BLACK}Select costume for this entertainer +STR_1947 :{SMALLFONT}{BLACK}Show areas patrolled by selected staff type, and locate the nearest staff member +STR_1948 :{SMALLFONT}{BLACK}Hire a new staff member of the selected type +STR_1949 :Financial Summary +STR_1950 :Financial Graph +STR_1951 :Park Value Graph +STR_1952 :Profit Graph +STR_1953 :Marketing +STR_1954 :Research Funding +STR_1955 :{WINDOW_COLOUR_2}Number of circuits: +STR_1956 :{SMALLFONT}{BLACK}Number of circuits of track per ride +STR_1957 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1958 :{COMMA16} +STR_1959 :Can't change number of circuits... +STR_1960 :{WINDOW_COLOUR_2}Balloon price: +STR_1961 :{WINDOW_COLOUR_2}Cuddly Toy price: +STR_1962 :{WINDOW_COLOUR_2}Park Map price: +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_1968 :{WINDOW_COLOUR_2}Ice Cream price: +STR_1969 :{WINDOW_COLOUR_2}Cotton Candy price: +STR_1970 :{WINDOW_COLOUR_2} +STR_1971 :{WINDOW_COLOUR_2} +STR_1972 :{WINDOW_COLOUR_2} +STR_1973 :{WINDOW_COLOUR_2}Pizza price: +STR_1974 :{WINDOW_COLOUR_2} +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_1980 :{WINDOW_COLOUR_2}T-Shirt price: +STR_1981 :{WINDOW_COLOUR_2}Donut price: +STR_1982 :{WINDOW_COLOUR_2}Coffee price: +STR_1983 :{WINDOW_COLOUR_2} +STR_1984 :{WINDOW_COLOUR_2}Fried Chicken price: +STR_1985 :{WINDOW_COLOUR_2}Lemonade price: +STR_1986 :{WINDOW_COLOUR_2} +STR_1987 :{WINDOW_COLOUR_2} +STR_1988 :Balloon +STR_1989 :Cuddly Toy +STR_1990 :Park Map +STR_1991 :On-Ride Photo +STR_1992 :Umbrella +STR_1993 :Drink +STR_1994 :Burger +STR_1995 :Fries +STR_1996 :Ice Cream +STR_1997 :Cotton Candy +STR_1998 :Empty Can +STR_1999 :Rubbish +STR_2000 :Empty Burger Box +STR_2001 :Pizza +STR_2002 :Voucher +STR_2003 :Popcorn +STR_2004 :Hot Dog +STR_2005 :Tentacle +STR_2006 :Hat +STR_2007 :Candy Apple +STR_2008 :T-Shirt +STR_2009 :Donut +STR_2010 :Coffee +STR_2011 :Empty Cup +STR_2012 :Fried Chicken +STR_2013 :Lemonade +STR_2014 :Empty Box +STR_2015 :Empty Bottle +STR_2016 :Balloons +STR_2017 :Cuddly Toys +STR_2018 :Park Maps +STR_2019 :On-Ride Photos +STR_2020 :Umbrellas +STR_2021 :Drinks +STR_2022 :Burgers +STR_2023 :Fries +STR_2024 :Ice Creams +STR_2025 :Cotton Candy +STR_2026 :Empty Cans +STR_2027 :Rubbish +STR_2028 :Empty Burger Boxes +STR_2029 :Pizzas +STR_2030 :Vouchers +STR_2031 :Popcorn +STR_2032 :Hot Dogs +STR_2033 :Tentacles +STR_2034 :Hats +STR_2035 :Candy Apples +STR_2036 :T-Shirts +STR_2037 :Donuts +STR_2038 :Coffees +STR_2039 :Empty Cups +STR_2040 :Fried Chicken +STR_2041 :Lemonade +STR_2042 :Empty Boxes +STR_2043 :Empty Bottles +STR_2044 :a Balloon +STR_2045 :a Cuddly Toy +STR_2046 :a Park Map +STR_2047 :an On-Ride Photo +STR_2048 :an Umbrella +STR_2049 :a Drink +STR_2050 :a Burger +STR_2051 :some Fries +STR_2052 :an Ice Cream +STR_2053 :some Cotton Candy +STR_2054 :an Empty Can +STR_2055 :some Rubbish +STR_2056 :an Empty Burger Box +STR_2057 :a Pizza +STR_2058 :a Voucher +STR_2059 :some Popcorn +STR_2060 :a Hot Dog +STR_2061 :a Tentacle +STR_2062 :a Hat +STR_2063 :a Candy Apple +STR_2064 :a T-Shirt +STR_2065 :a Donut +STR_2066 :a Coffee +STR_2067 :an Empty Cup +STR_2068 :some Fried Chicken +STR_2069 :some Lemonade +STR_2070 :an Empty Box +STR_2071 :an Empty Bottle +STR_2072 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Balloon +STR_2073 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Cuddly Toy +STR_2074 :Map of {STRINGID} +STR_2075 :On-Ride Photo of {STRINGID} +STR_2076 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Umbrella +STR_2077 :Drink +STR_2078 :Burger +STR_2079 :Fries +STR_2080 :Ice Cream +STR_2081 :Cotton Candy +STR_2082 :Empty Can +STR_2083 :Rubbish +STR_2084 :Empty Burger Box +STR_2085 :Pizza +STR_2086 :Voucher for {STRINGID} +STR_2087 :Popcorn +STR_2088 :Hot Dog +STR_2089 :Tentacle +STR_2090 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Hat +STR_2091 :Candy Apple +STR_2092 :{OPENQUOTES}{STRINGID}{ENDQUOTES} T-Shirt +STR_2093 :Donut +STR_2094 :Coffee +STR_2095 :Empty Cup +STR_2096 :Fried Chicken +STR_2097 :Lemonade +STR_2098 :Empty Box +STR_2099 :Empty Bottle +STR_2100 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_2101 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_2102 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_2103 :{WINDOW_COLOUR_2}Pretzel price: +STR_2104 :{WINDOW_COLOUR_2}Hot Chocolate price: +STR_2105 :{WINDOW_COLOUR_2}Iced Tea price: +STR_2106 :{WINDOW_COLOUR_2}Funnel Cake price: +STR_2107 :{WINDOW_COLOUR_2}Sunglasses price: +STR_2108 :{WINDOW_COLOUR_2}Beef Noodles price: +STR_2109 :{WINDOW_COLOUR_2}Fried Rice Noodles price: +STR_2110 :{WINDOW_COLOUR_2}Wonton Soup price: +STR_2111 :{WINDOW_COLOUR_2}Meatball Soup price: +STR_2112 :{WINDOW_COLOUR_2}Fruit Juice price: +STR_2113 :{WINDOW_COLOUR_2}Soybean Milk price: +STR_2114 :{WINDOW_COLOUR_2}Sujongkwa price: +STR_2115 :{WINDOW_COLOUR_2}Sub Sandwich price: +STR_2116 :{WINDOW_COLOUR_2}Cookie price: +STR_2117 :{WINDOW_COLOUR_2} +STR_2118 :{WINDOW_COLOUR_2} +STR_2119 :{WINDOW_COLOUR_2} +STR_2120 :{WINDOW_COLOUR_2}Roast Sausage price: +STR_2121 :{WINDOW_COLOUR_2} +STR_2122 :On-Ride Photo +STR_2123 :On-Ride Photo +STR_2124 :On-Ride Photo +STR_2125 :Pretzel +STR_2126 :Hot Chocolate +STR_2127 :Iced Tea +STR_2128 :Funnel Cake +STR_2129 :Sunglasses +STR_2130 :Beef Noodles +STR_2131 :Fried Rice Noodles +STR_2132 :Wonton Soup +STR_2133 :Meatball Soup +STR_2134 :Fruit Juice +STR_2135 :Soybean Milk +STR_2136 :Sujongkwa +STR_2137 :Sub Sandwich +STR_2138 :Cookie +STR_2139 :Empty Bowl +STR_2140 :Empty Drink Carton +STR_2141 :Empty Juice Cup +STR_2142 :Roast Sausage +STR_2143 :Empty Bowl +STR_2144 :On-Ride Photos +STR_2145 :On-Ride Photos +STR_2146 :On-Ride Photos +STR_2147 :Pretzels +STR_2148 :Hot Chocolates +STR_2149 :Iced Teas +STR_2150 :Funnel Cakes +STR_2151 :Sunglasses +STR_2152 :Beef Noodles +STR_2153 :Fried Rice Noodles +STR_2154 :Wonton Soups +STR_2155 :Meatball Soups +STR_2156 :Fruit Juices +STR_2157 :Soybean Milks +STR_2158 :Sujongkwa +STR_2159 :Sub Sandwiches +STR_2160 :Cookies +STR_2161 :Empty Bowls +STR_2162 :Empty Drink Cartons +STR_2163 :Empty Juice cups +STR_2164 :Roast Sausages +STR_2165 :Empty Bowls +STR_2166 :an On-Ride Photo +STR_2167 :an On-Ride Photo +STR_2168 :an On-Ride Photo +STR_2169 :a Pretzel +STR_2170 :a Hot Chocolate +STR_2171 :an Iced Tea +STR_2172 :a Funnel Cake +STR_2173 :a pair of Sunglasses +STR_2174 :some Beef Noodles +STR_2175 :some Fried Rice Noodles +STR_2176 :some Wonton Soup +STR_2177 :some Meatball Soup +STR_2178 :a Fruit Juice +STR_2179 :some Soybean Milk +STR_2180 :some Sujongkwa +STR_2181 :a Sub Sandwich +STR_2182 :a Cookie +STR_2183 :an Empty Bowl +STR_2184 :an Empty Drink Carton +STR_2185 :an Empty Juice Cup +STR_2186 :a Roast Sausage +STR_2187 :an Empty Bowl +STR_2188 :On-Ride Photo of {STRINGID} +STR_2189 :On-Ride Photo of {STRINGID} +STR_2190 :On-Ride Photo of {STRINGID} +STR_2191 :Pretzel +STR_2192 :Hot Chocolate +STR_2193 :Iced Tea +STR_2194 :Funnel Cake +STR_2195 :Sunglasses +STR_2196 :Beef Noodles +STR_2197 :Fried Rice Noodles +STR_2198 :Wonton Soup +STR_2199 :Meatball Soup +STR_2200 :Fruit Juice +STR_2201 :Soybean Milk +STR_2202 :Sujongkwa +STR_2203 :Sub Sandwich +STR_2204 :Cookie +STR_2205 :Empty Bowl +STR_2206 :Empty Drink Carton +STR_2207 :Empty Juice Cup +STR_2208 :Roast Sausage +STR_2209 :Empty Bowl +STR_2210 :{SMALLFONT}{BLACK}Show list of handymen in park +STR_2211 :{SMALLFONT}{BLACK}Show list of mechanics in park +STR_2212 :{SMALLFONT}{BLACK}Show list of security guards in park +STR_2213 :{SMALLFONT}{BLACK}Show list of entertainers in park +STR_2214 :Construction not possible while game is paused! +STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) +STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F +STR_2218 :{RED}{STRINGID} on {STRINGID} hasn't returned to the {STRINGID} yet!{NEWLINE}Check whether it is stuck or has stalled +STR_2219 :{RED}{COMMA16} people have died in an accident on {STRINGID} +STR_2220 :{WINDOW_COLOUR_2}Park Rating: {BLACK}{COMMA16} +STR_2221 :{SMALLFONT}{BLACK}Park Rating: {COMMA16} +STR_2222 :{SMALLFONT}{BLACK}{STRINGID} +STR_2223 :{WINDOW_COLOUR_2}Guests in park: {BLACK}{COMMA16} +STR_2224 :{WINDOW_COLOUR_2}Cash: {BLACK}{CURRENCY2DP} +STR_2225 :{WINDOW_COLOUR_2}Cash: {RED}{CURRENCY2DP} +STR_2226 :{WINDOW_COLOUR_2}Park value: {BLACK}{CURRENCY} +STR_2227 :{WINDOW_COLOUR_2}Company value: {BLACK}{CURRENCY} +STR_2228 :{WINDOW_COLOUR_2}Last month's profit from food/drink and{NEWLINE}merchandise sales: {BLACK}{CURRENCY} +STR_2229 :Slope up to vertical +STR_2230 :Vertical track +STR_2231 :Holding brake for drop +STR_2232 :Cable lift hill +STR_2233 :{SMALLFONT}{BLACK}Park information +STR_2234 :Recent Messages +STR_2235 :{SMALLFONT}{STRINGID} {STRINGID} +STR_2236 :January +STR_2237 :February +STR_2238 :March +STR_2239 :April +STR_2240 :May +STR_2241 :June +STR_2242 :July +STR_2243 :August +STR_2244 :September +STR_2245 :October +STR_2246 :November +STR_2247 :December +STR_2248 :Can't demolish ride/attraction... +STR_2249 :{BABYBLUE}New ride/attraction now available:{NEWLINE}{STRINGID} +STR_2250 :{BABYBLUE}New scenery/themeing now available:{NEWLINE}{STRINGID} +STR_2251 :Can only be built on paths! +STR_2252 :Can only be built across paths! +STR_2253 :Transport Rides +STR_2254 :Gentle Rides +STR_2255 :Roller Coasters +STR_2256 :Thrill Rides +STR_2257 :Water Rides +STR_2258 :Shops & Stalls +STR_2259 :Scenery & Themeing +STR_2260 :No funding +STR_2261 :Minimum funding +STR_2262 :Normal funding +STR_2263 :Maximum funding +STR_2264 :Research funding +STR_2265 :{WINDOW_COLOUR_2}Cost: {BLACK}{CURRENCY} per month +STR_2266 :Research priorities +STR_2267 :Currently in development +STR_2268 :Last development +STR_2269 :{WINDOW_COLOUR_2}Type: {BLACK}{STRINGID} +STR_2270 :{WINDOW_COLOUR_2}Progress: {BLACK}{STRINGID} +STR_2271 :{WINDOW_COLOUR_2}Expected: {BLACK}{STRINGID} +STR_2272 :{WINDOW_COLOUR_2}Ride/attraction:{NEWLINE}{BLACK}{STRINGID} +STR_2273 :{WINDOW_COLOUR_2}Scenery/themeing:{NEWLINE}{BLACK}{STRINGID} +STR_2274 :{SMALLFONT}{BLACK}Show details of this invention or development +STR_2275 :{SMALLFONT}{BLACK}Show funding and options for research & development +STR_2276 :{SMALLFONT}{BLACK}Show research & development status +STR_2277 :Unknown +STR_2278 :Transport Ride +STR_2279 :Gentle Ride +STR_2280 :Roller Coaster +STR_2281 :Thrill Ride +STR_2282 :Water Ride +STR_2283 :Shop/Stall +STR_2284 :Scenery/Themeing +STR_2285 :Initial research +STR_2286 :Designing +STR_2287 :Completing design +STR_2288 :Unknown +STR_2289 :{STRINGID} {STRINGID} +STR_2290 :{SMALLFONT}{BLACK}{STRINGID} {STRINGID} +STR_2291 :Select scenario for new game +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 +STR_2305 :Track design files +STR_2306 :Save track design +STR_2307 :Select {STRINGID} design +STR_2308 :{STRINGID} Track Designs +STR_2309 :Install New Track Design +STR_2310 :Build custom design +STR_2311 :{WINDOW_COLOUR_2}Excitement rating: {BLACK}{COMMA2DP32} (approx.) +STR_2312 :{WINDOW_COLOUR_2}Intensity rating: {BLACK}{COMMA2DP32} (approx.) +STR_2313 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}{COMMA2DP32} (approx.) +STR_2314 :{WINDOW_COLOUR_2}Ride length: {BLACK}{STRINGID} +STR_2315 :{WINDOW_COLOUR_2}Cost: {BLACK}around {CURRENCY} +STR_2316 :{WINDOW_COLOUR_2}Space required: {BLACK}{COMMA16} x {COMMA16} blocks +STR_2317 :{WINDOW_COLOUR_2}Sound Quality: +STR_2318 :Low +STR_2319 :Medium +STR_2320 :High +STR_2321 :{WINDOW_COLOUR_2}Number of rides/attractions: {BLACK}{COMMA16} +STR_2322 :{WINDOW_COLOUR_2}Staff: {BLACK}{COMMA16} +STR_2323 :{WINDOW_COLOUR_2}Park size: {BLACK}{COMMA32}m{SQUARED} +STR_2324 :{WINDOW_COLOUR_2}Park size: {BLACK}{COMMA32}sq.ft. +STR_2325 :{SMALLFONT}{BLACK}Buy land to extend park +STR_2326 :{SMALLFONT}{BLACK}Buy construction rights to allow construction above or below land outside the park +STR_2327 :Options +STR_2328 :{WINDOW_COLOUR_2}Currency: +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_2334 :Pounds ({POUND}) +STR_2335 :Dollars ($) +STR_2336 :Franc (F) +STR_2337 :Deutschmark (DM) +STR_2338 :Yen ({YEN}) +STR_2339 :Peseta (Pts) +STR_2340 :Lira (L) +STR_2341 :Guilders (fl.) +STR_2342 :Krona (kr) +STR_2343 :Euros ({EURO}) +STR_2344 :Imperial +STR_2345 :Metric +STR_2346 :Display +STR_2347 :{RED}{STRINGID} has drowned! +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 +STR_2358 :Units +STR_2359 :Real Values +STR_2360 :{WINDOW_COLOUR_2}Display Resolution: +STR_2361 :Landscape Smoothing +STR_2362 :{SMALLFONT}{BLACK}Toggle landscape tile edge smoothing on/off +STR_2363 :Gridlines on Landscape +STR_2364 :{SMALLFONT}{BLACK}Toggle gridlines on landscape on/off +STR_2365 :The bank refuses to increase your loan! +STR_2366 :Celsius ({DEGREE}C) +STR_2367 :Fahrenheit ({DEGREE}F) +STR_2368 :None +STR_2369 :Low +STR_2370 :Average +STR_2371 :High +STR_2372 :Low +STR_2373 :Medium +STR_2374 :High +STR_2375 :Very high +STR_2376 :Extreme +STR_2377 :Ultra-Extreme +STR_2378 :{SMALLFONT}{BLACK}Adjust smaller area of land +STR_2379 :{SMALLFONT}{BLACK}Adjust larger area of land +STR_2380 :{SMALLFONT}{BLACK}Adjust smaller area of water +STR_2381 :{SMALLFONT}{BLACK}Adjust larger area of water +STR_2382 :Land +STR_2383 :Water +STR_2384 :{WINDOW_COLOUR_2}Your objective: +STR_2385 :{BLACK}None +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! +STR_2389 :{BLACK}Build the best {STRINGID} you can! +STR_2390 :{BLACK}To have 10 different types of roller coasters operating in your park, each with an excitement value of at least 6.00 +STR_2391 :{BLACK}To have at least {COMMA16} guests in your park. You must not let the park rating drop below 700 at any time! +STR_2392 :{BLACK}To achieve a monthly income from ride tickets of at least {POP16}{POP16}{CURRENCY} +STR_2393 :{BLACK}To have 10 different types of roller coasters operating in your park, each with a minimum length of {LENGTH}, and an excitement rating of at least 7.00 +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_2398 :Number of guests at a given date +STR_2399 :Park value at a given date +STR_2400 :Have fun +STR_2401 :Build the best ride you can +STR_2402 :Build 10 roller coasters +STR_2403 :Number of guests in park +STR_2404 :Monthly income from ride tickets +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 +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} - +STR_2455 :{SMALLFONT}{BLACK}+{CURRENCY2DP} - +STR_2456 :{SMALLFONT}{BLACK}{CURRENCY2DP} - +STR_2457 :{SMALLFONT}{BLACK}Show financial accounts +STR_2458 :{SMALLFONT}{BLACK}Show graph of cash (less loan) over time +STR_2459 :{SMALLFONT}{BLACK}Show graph of park value over time +STR_2460 :{SMALLFONT}{BLACK}Show graph of weekly profit +STR_2461 :{SMALLFONT}{BLACK}Show marketing campaigns +STR_2462 :{SMALLFONT}{BLACK}Show view of park entrance +STR_2463 :{SMALLFONT}{BLACK}Show graph of park ratings over time +STR_2464 :{SMALLFONT}{BLACK}Show graph of guest numbers over time +STR_2465 :{SMALLFONT}{BLACK}Show park entrance price and information +STR_2466 :{SMALLFONT}{BLACK}Show park statistics +STR_2467 :{SMALLFONT}{BLACK}Show objectives for this game +STR_2468 :{SMALLFONT}{BLACK}Show recent awards this park has received +STR_2469 :{SMALLFONT}{BLACK}Select level of research & development +STR_2470 :{SMALLFONT}{BLACK}Research new transport rides +STR_2471 :{SMALLFONT}{BLACK}Research new gentle rides +STR_2472 :{SMALLFONT}{BLACK}Research new roller coasters +STR_2473 :{SMALLFONT}{BLACK}Research new thrill rides +STR_2474 :{SMALLFONT}{BLACK}Research new water rides +STR_2475 :{SMALLFONT}{BLACK}Research new shops and stalls +STR_2476 :{SMALLFONT}{BLACK}Research new scenery and themeing +STR_2477 :{SMALLFONT}{BLACK}Select operating mode for this ride/attraction +STR_2478 :{SMALLFONT}{BLACK}Show graph of velocity against time +STR_2479 :{SMALLFONT}{BLACK}Show graph of altitude against time +STR_2480 :{SMALLFONT}{BLACK}Show graph of vertical acceleration against time +STR_2481 :{SMALLFONT}{BLACK}Show graph of lateral acceleration against time +STR_2482 :{SMALLFONT}{BLACK}Profit: {CURRENCY} per week, Park Value: {CURRENCY} +STR_2483 :{WINDOW_COLOUR_2}Weekly profit: {BLACK}+{CURRENCY2DP} +STR_2484 :{WINDOW_COLOUR_2}Weekly profit: {RED}{CURRENCY2DP} +STR_2485 :Controls +STR_2486 :General +STR_2487 :Show 'real' names of guests +STR_2488 :{SMALLFONT}{BLACK}Toggle between showing 'real' names of guests and guest numbers +STR_2489 :Shortcut keys... +STR_2490 :Keyboard shortcuts +STR_2491 :Reset keys +STR_2492 :{SMALLFONT}{BLACK}Set all keyboard shortcuts back to default settings +STR_2493 :Close top-most window +STR_2494 :Close all floating windows +STR_2495 :Cancel construction mode +STR_2496 :Pause game +STR_2497 :Zoom view out +STR_2498 :Zoom view in +STR_2499 :Rotate view +STR_2500 :Rotate construction object +STR_2501 :Underground view toggle +STR_2502 :Remove base land toggle +STR_2503 :Remove vertical land toggle +STR_2504 :See-through rides toggle +STR_2505 :See-through scenery toggle +STR_2506 :Invisible supports toggle +STR_2507 :Invisible people toggle +STR_2508 :Height marks on land toggle +STR_2509 :Height marks on ride tracks toggle +STR_2510 :Height marks on paths toggle +STR_2511 :Adjust land +STR_2512 :Adjust water +STR_2513 :Build scenery +STR_2514 :Build paths +STR_2515 :Build new ride +STR_2516 :Show financial information +STR_2517 :Show research information +STR_2518 :Show rides list +STR_2519 :Show park information +STR_2520 :Show guest list +STR_2521 :Show staff list +STR_2522 :Show recent messages +STR_2523 :Show map +STR_2524 :Screenshot + +STR_2525 :??? +STR_2526 :??? +STR_2527 :??? +STR_2528 :??? +STR_2529 :??? +STR_2530 :??? +STR_2531 :??? +STR_2532 :??? +STR_2533 :Backspace +STR_2534 :Tab +STR_2535 :??? +STR_2536 :??? +STR_2537 :Clear +STR_2538 :Return +STR_2539 :??? +STR_2540 :??? +STR_2541 :??? +STR_2542 :??? +STR_2543 :Alt/Menu +STR_2544 :Pause +STR_2545 :Caps +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 :Spacebar +STR_2558 :PgUp +STR_2559 :PgDn +STR_2560 :End +STR_2561 :Home +STR_2562 :Left +STR_2563 :Up +STR_2564 :Right +STR_2565 :Down +STR_2566 :Select +STR_2567 :Print +STR_2568 :Execute +STR_2569 :Snapshot +STR_2570 :Insert +STR_2571 :Delete +STR_2572 :Help +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 :NumPad 0 +STR_2622 :NumPad 1 +STR_2623 :NumPad 2 +STR_2624 :NumPad 3 +STR_2625 :NumPad 4 +STR_2626 :NumPad 5 +STR_2627 :NumPad 6 +STR_2628 :NumPad 7 +STR_2629 :NumPad 8 +STR_2630 :NumPad 9 +STR_2631 :NumPad * +STR_2632 :NumPad + +STR_2633 :??? +STR_2634 :NumPad - +STR_2635 :NumPad . +STR_2636 :NumPad / +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 :NumLock +STR_2670 :Scroll +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 {CURRENCY} +STR_2682 : +STR_2683 : +STR_2684 :{SMALLFONT}{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 minute +STR_2702 :Every 5 minutes +STR_2703 :Every 15 minutes +STR_2704 :Every 30 minutes +STR_2705 :Every hour +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}, 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 :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 :+{CURRENCY} +STR_2761 : +STR_2762 : +STR_2763 :??? +STR_2764 : +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 +# End of new strings + + +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} +STR_2782 :SHIFT + +STR_2783 :CTRL + +STR_2784 :Change keyboard shortcut +STR_2785 :{WINDOW_COLOUR_2}Press new shortcut key for:{NEWLINE}{OPENQUOTES}{STRINGID}{ENDQUOTES} +STR_2786 :{SMALLFONT}{BLACK}Click on shortcut description to select new key +STR_2787 :{WINDOW_COLOUR_2}Park value: {BLACK}{CURRENCY} +STR_2788 :{WINDOW_COLOUR_2}Congratulations !{NEWLINE}{BLACK}You achieved your objective with a company value of {CURRENCY} ! +STR_2789 :{WINDOW_COLOUR_2}You have failed your objective ! +STR_2790 :Enter name into scenario chart +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_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_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 +STR_2806 :{RED}Guests are complaining about the disgusting state of the paths in your park{NEWLINE}Check where your handymen are and consider organizing them better +STR_2807 :{RED}Guests are complaining about the amount of litter in your park{NEWLINE}Check where your handymen are and consider organizing them better +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_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 +STR_2815 :{WINDOW_COLOUR_2}Tidiest park award +STR_2816 :{WINDOW_COLOUR_2}Award for the park with the best roller coasters +STR_2817 :{WINDOW_COLOUR_2}Best value park award +STR_2818 :{WINDOW_COLOUR_2}Most beautiful park award +STR_2819 :{WINDOW_COLOUR_2}Worst value park award +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_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 +STR_2828 :{WINDOW_COLOUR_2}Most dazzling ride color schemes award +STR_2829 :{WINDOW_COLOUR_2}Most confusing park layout award +STR_2830 :{WINDOW_COLOUR_2}Best gentle ride award +STR_2831 :{TOPAZ}Your park has received an award for being 'The most untidy park in the country'! +STR_2832 :{TOPAZ}Your park has received an award for being 'The tidiest park in the country'! +STR_2833 :{TOPAZ}Your park has received an award for being 'The park with the best roller coasters'! +STR_2834 :{TOPAZ}Your park has received an award for being 'The best value park in the country'! +STR_2835 :{TOPAZ}Your park has received an award for being 'The most beautiful park in the country'! +STR_2836 :{TOPAZ}Your park has received an award for being 'The worst value park in the country'! +STR_2837 :{TOPAZ}Your park has received an award for being 'The safest park in the country'! +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_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'! +STR_2845 :{TOPAZ}Your park has received an award for being 'The park with the most dazzling choice of color schemes'! +STR_2846 :{TOPAZ}Your park has received an award for being 'The park with the most confusing layout'! +STR_2847 :{TOPAZ}Your park has received an award for being 'The park with the best gentle rides'! +STR_2848 :{WINDOW_COLOUR_2}No recent awards +STR_2849 :New scenario installed successfully +STR_2850 :New track design installed successfully +STR_2851 :Scenario already installed +STR_2852 :Track design already installed +STR_2853 :Forbidden by the local authority! +STR_2854 :{RED}Guests can't get to the entrance of {STRINGID} !{NEWLINE}Construct a path to the entrance +STR_2855 :{RED}{STRINGID} has no path leading from its exit !{NEWLINE}Construct a path from the ride exit +STR_2856 :{WINDOW_COLOUR_2}Tutorial +STR_2857 :{WINDOW_COLOUR_2}(Press a key or mouse button to take control) +STR_2858 :Can't start marketing campaign... +STR_2859 :Another instance of OpenRCT2 is already running +STR_2860 :Infogrames Interactive credits... +STR_2861 :{WINDOW_COLOUR_2}Licensed to Infogrames Interactive Inc. +STR_2862 :Music acknowledgements... +STR_2863 :Music acknowledgements +STR_2864 :{WINDOW_COLOUR_2}March - Children of the Regiment: (Fucik) non copyright +STR_2865 :{WINDOW_COLOUR_2}Heyken's Serenade: (J.Heyken) British Standard Music Coy; GEMA, BRITICO +STR_2866 :{WINDOW_COLOUR_2}In Continental Mood: (Composer unknown) Copyright Control +STR_2867 :{WINDOW_COLOUR_2}Wedding Journey: (Traditional) +STR_2868 :{WINDOW_COLOUR_2}Tales from the Vienna Woods: (Johann Strauss) non copyright +STR_2869 :{WINDOW_COLOUR_2}Slavonic Dance: (Traditional) +STR_2870 :{WINDOW_COLOUR_2}Das Alpenhorn: (Traditional) +STR_2871 :{WINDOW_COLOUR_2}The Blond Sailor: (Traditional) +STR_2872 :{WINDOW_COLOUR_2}Overture - Poet and Peasant: (Suppe) non copyright +STR_2873 :{WINDOW_COLOUR_2}Waltz Medley: (Johann Strauss) non copyright +STR_2874 :{WINDOW_COLOUR_2}Bella Bella Bimba: (Traditional) +STR_2875 :{WINDOW_COLOUR_2}Original recordings (P) 1976 C.J.Mears Organization, used with consent +STR_2876 :{WINDOW_COLOUR_2}RollerCoaster Tycoon 2 Title Music: (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, played by Peter James Adcock) recording {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}Senior Producer: Thomas J. Zahorik +STR_2910 :{WINDOW_COLOUR_2}Executive Producer: Bill Levay +STR_2911 :{WINDOW_COLOUR_2}Senior Marketing Product Manager: Scott Triola +STR_2912 :{WINDOW_COLOUR_2}V.P. of Product Development: Scott Walker +STR_2913 :{WINDOW_COLOUR_2}General Manager: John Hurlbut +STR_2914 :{WINDOW_COLOUR_2}Director of Quality Assurance: Michael Craighead +STR_2915 :{WINDOW_COLOUR_2}Q.A. Certification Manager: Kurt Boutin +STR_2916 :{WINDOW_COLOUR_2}Q.A. Certification Lead: Mark Huggins +STR_2917 :{WINDOW_COLOUR_2}Testers: Dena Irene Fitzgerald, Scott Rollins, Christopher McPhail +STR_2918 :{WINDOW_COLOUR_2}Clif McClure, Erik Maramaldi, Erik Jeffery +STR_2919 :{WINDOW_COLOUR_2}Director of Marketing: Ann Marie Bland +STR_2920 :{WINDOW_COLOUR_2}Manager of Creative Services: Steve Martin +STR_2921 :{WINDOW_COLOUR_2}Manager of Editorial & Documentation Services: Elizabeth Mackney +STR_2922 :{WINDOW_COLOUR_2}Graphic Designer: Paul Anselmi +STR_2923 :{WINDOW_COLOUR_2}Copywriter: Kurt Carlson +STR_2924 :{WINDOW_COLOUR_2}Special Thanks to: Peter Matiss +STR_2925 :{WINDOW_COLOUR_2}Engineering Specialist: Ken Edwards +STR_2926 :{WINDOW_COLOUR_2}Engineering Services Manager: Luis Rivas +STR_2927 :{WINDOW_COLOUR_2}Lead Compatibility Analyst: Geoffrey Smith +STR_2928 :{WINDOW_COLOUR_2}Compatibility Analysts: Jason Cordero, Burke McQuinn, Kim Jardin +STR_2929 :{WINDOW_COLOUR_2}Lead Tester: Daniel Frisoli +STR_2930 :{WINDOW_COLOUR_2}Senior Tester: 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 :Use of this product is subject to the terms of a license agreement +STR_2970 :found in the product's {OPENQUOTES}ReadMe{ENDQUOTES} file and in the manual +STR_2971 :Main color scheme +STR_2972 :Alternative color scheme 1 +STR_2973 :Alternative color scheme 2 +STR_2974 :Alternative color scheme 3 +STR_2975 :{SMALLFONT}{BLACK}Select which color scheme to change, or paint ride with +STR_2976 :{SMALLFONT}{BLACK}Paint an individual area of this ride using the selected color scheme +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_2982 :Banner text +STR_2983 :Enter new text for this banner: +STR_2984 :Can't set new text for banner... +STR_2985 :Banner +STR_2986 :{SMALLFONT}{BLACK}Change text on banner +STR_2987 :{SMALLFONT}{BLACK}Set this banner as a 'no-entry' sign for guests +STR_2988 :{SMALLFONT}{BLACK}Demolish this banner +STR_2989 :{SMALLFONT}{BLACK}Select main color +STR_2990 :{SMALLFONT}{BLACK}Select text color +STR_2991 :Sign +STR_2992 :Sign text +STR_2993 :Enter new text for this sign: +STR_2994 :{SMALLFONT}{BLACK}Change text on sign +STR_2995 :{SMALLFONT}{BLACK}Demolish this sign +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 :Unable to load file... +STR_3011 :File contains invalid data +STR_3012 :Dodgems beat style +STR_3013 :Fairground organ style +STR_3014 :Roman fanfare style +STR_3015 :Oriental style +STR_3016 :Martian style +STR_3017 :Jungle drums style +STR_3018 :Egyptian style +STR_3019 :Toyland style +STR_3020 : +STR_3021 :Space style +STR_3022 :Horror style +STR_3023 :Techno style +STR_3024 :Gentle style +STR_3025 :Summer style +STR_3026 :Water style +STR_3027 :Wild west style +STR_3028 :Jurassic style +STR_3029 :Rock style +STR_3030 :Ragtime style +STR_3031 :Fantasy style +STR_3032 :Rock style 2 +STR_3033 :Ice style +STR_3034 :Snow style +STR_3035 :Custom music 1 +STR_3036 :Custom music 2 +STR_3037 :Medieval style +STR_3038 :Urban style +STR_3039 :Organ style +STR_3040 :Mechanical style +STR_3041 :Modern style +STR_3042 :Pirates style +STR_3043 :Rock style 3 +STR_3044 :Candy style +STR_3045 :{SMALLFONT}{BLACK}Select style of music to play +STR_3046 :This ride cannot be modified +STR_3047 :Local authority forbids demolition or modifications to this ride +STR_3048 :Marketing campaigns forbidden by local authority +STR_3049 :Golf hole A +STR_3050 :Golf hole B +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_3057 :{WINDOW_COLOUR_2}Construction Marker: +STR_3058 :Brick walls +STR_3059 :Hedges +STR_3060 :Ice blocks +STR_3061 :Wooden fences +STR_3062 :{SMALLFONT}{BLACK}Standard roller coaster track +STR_3063 :{SMALLFONT}{BLACK}Water channel (track submerged) +STR_3064 :Beginner Parks +STR_3065 :Challenging Parks +STR_3066 :Expert Parks +STR_3067 :{OPENQUOTES}Real{ENDQUOTES} Parks +STR_3068 :Other Parks +STR_3069 :Top Section +STR_3070 :Slope to Level +STR_3071 :{WINDOW_COLOUR_2}Same price throughout park +STR_3072 :{SMALLFONT}{BLACK}Select whether this price is used throughout the entire park +STR_3073 :{RED}WARNING: Your park rating has dropped below 700 !{NEWLINE}If you haven't raised the park rating in 4 weeks, your park will be closed down +STR_3074 :{RED}WARNING: Your park rating is still below 700 !{NEWLINE}You have 3 weeks to raise the park rating +STR_3075 :{RED}WARNING: Your park rating is still below 700 !{NEWLINE}You have only 2 weeks to raise the park rating, or your park will be closed down +STR_3076 :{RED}FINAL WARNING: Your park rating is still below 700 !{NEWLINE}In just 7 days your park will be closed down unless you can raise the rating +STR_3077 :{RED}CLOSURE NOTICE: Your park has been closed down ! +STR_3078 :Plain entrance +STR_3079 :Wooden entrance +STR_3080 :Canvas tent entrance +STR_3081 :Castle entrance (gray) +STR_3082 :Castle entrance (brown) +STR_3083 :Jungle entrance +STR_3084 :Log cabin entrance +STR_3085 :Classical/Roman entrance +STR_3086 :Abstract entrance +STR_3087 :Snow/Ice entrance +STR_3088 :Pagoda entrance +STR_3089 :Space entrance +STR_3090 :{SMALLFONT}{BLACK}Select style of entrance, exit, and station +STR_3091 :You are not allowed to remove this section! +STR_3092 :You are not allowed to move or modify the station for this ride! +STR_3093 :{WINDOW_COLOUR_2}Favorite: {BLACK}{STRINGID} +STR_3094 :N/A +STR_3095 :{WINDOW_COLOUR_2}Lift hill chain speed: +STR_3096 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} +STR_3097 :{SMALLFONT}{BLACK}Select lift hill chain speed +STR_3098 :Can't change lift hill speed... +STR_3099 :{SMALLFONT}{BLACK}Select color +STR_3100 :{SMALLFONT}{BLACK}Select second color +STR_3101 :{SMALLFONT}{BLACK}Select third color +STR_3102 :{SMALLFONT}{BLACK}Re-paint colored scenery on landscape +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 +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 +STR_3113 :Select a different design +STR_3114 :{SMALLFONT}{BLACK}Go back to design selection window +STR_3115 :{SMALLFONT}{BLACK}Save track design +STR_3116 :{SMALLFONT}{BLACK}Save track design (Not possible until ride has been tested and statistics have been generated) +STR_3117 :{BLACK}Calling mechanic... +STR_3118 :{BLACK}{STRINGID} is heading for the ride +STR_3119 :{BLACK}{STRINGID} is fixing the ride +STR_3120 :{SMALLFONT}{BLACK}Locate nearest available mechanic, or mechanic fixing ride +STR_3121 :Unable to locate mechanic, or all nearby mechanics are busy +STR_3122 :{WINDOW_COLOUR_2}Favorite ride of: {BLACK}{COMMA16} guest +STR_3123 :{WINDOW_COLOUR_2}Favorite ride of: {BLACK}{COMMA16} guests +STR_3124 :Broken {STRINGID} +STR_3125 :{WINDOW_COLOUR_2}Excitement Factor: {BLACK}+{COMMA16}% +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_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) +STR_3135 :{RED}(Vehicle design unavailable - Ride performance may be affected) +STR_3136 :Warning: This design will be built with an alternative vehicle type and may not perform as expected +STR_3137 :Select Nearby Scenery +STR_3138 :Reset Selection +STR_3139 :Cable lift unable to work in this operating mode +STR_3140 :Cable lift hill must start immediately after station +STR_3141 :Multi-circuit per ride not possible with cable lift hill +STR_3142 :{WINDOW_COLOUR_2}Capacity: {BLACK}{STRINGID} +STR_3143 :{SMALLFONT}{BLACK}Show people on map +STR_3144 :{SMALLFONT}{BLACK}Show rides and stalls on map +STR_3145 :{SMALLFONT}{BLACK}Scroll {STRINGID} left +STR_3146 :{SMALLFONT}{BLACK}Scroll {STRINGID} right +STR_3147 :{SMALLFONT}{BLACK}Scroll {STRINGID} left fast +STR_3148 :{SMALLFONT}{BLACK}Scroll {STRINGID} right fast +STR_3149 :{SMALLFONT}{BLACK}Scroll {STRINGID} left/right +STR_3150 :{SMALLFONT}{BLACK}Scroll {STRINGID} up +STR_3151 :{SMALLFONT}{BLACK}Scroll {STRINGID} down +STR_3152 :{SMALLFONT}{BLACK}Scroll {STRINGID} up fast +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_3160 : +STR_3161 : +STR_3162 :Unable to allocate enough memory +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_3169 :Data for the following object not found: +STR_3170 :Not enough space for graphics +STR_3171 :Too many objects of this type selected +STR_3172 :The following object must be selected first: {STRING} +STR_3173 :This object is currently in use +STR_3174 :This object is required by another object +STR_3175 :This object is always required +STR_3176 :Unable to select this object +STR_3177 :Unable to de-select this object +STR_3178 :At least one path object must be selected +STR_3179 :At least one ride vehicle/attraction object must be selected +STR_3180 :Invalid selection of objects +STR_3181 :Object Selection - {STRINGID} +STR_3182 :Park entrance type must be selected +STR_3183 :Water type must be selected +STR_3184 :Ride Vehicles/Attractions +STR_3185 :Small Scenery +STR_3186 :Large Scenery +STR_3187 :Walls/Fences +STR_3188 :Path Signs +STR_3189 :Footpaths +STR_3190 :Path Extras +STR_3191 :Scenery Groups +STR_3192 :Park Entrance +STR_3193 :Water +STR_3194 :Scenario Description +STR_3195 :Invention List +STR_3196 :{WINDOW_COLOUR_2}Research Group: {BLACK}{STRINGID} +STR_3197 :{WINDOW_COLOUR_2}Items pre-invented at start of game: +STR_3198 :{WINDOW_COLOUR_2}Items to invent during game: +STR_3199 :Random Shuffle +STR_3200 :{SMALLFONT}{BLACK}Randomly shuffle the list of items to invent during the game +STR_3201 :Object Selection +STR_3202 :Landscape Editor +STR_3203 :Invention List Set Up +STR_3204 :Options Selection +STR_3205 :Objective Selection +STR_3206 :Save Scenario +STR_3207 :Roller Coaster Designer +STR_3208 :Track Designs Manager +STR_3209 :Back to Previous Step: +STR_3210 :Forward to Next Step: +STR_3211 :{WINDOW_COLOUR_2}Map size: +STR_3212 :{POP16}{COMMA16} x {PUSH16}{COMMA16} +STR_3213 :Can't decrease map size any further +STR_3214 :Can't increase map size any further +STR_3215 :Too close to edge of map +STR_3216 :{SMALLFONT}{BLACK}Select park-owned land etc. +STR_3217 :Land Owned +STR_3218 :Construction Rights Owned +STR_3219 :Land For Sale +STR_3220 :Construction Rights For Sale +STR_3221 :{SMALLFONT}{BLACK}Set land to be owned by the park +STR_3222 :{SMALLFONT}{BLACK}Set construction rights only to be owned by the park +STR_3223 :{SMALLFONT}{BLACK}Set land to be available to purchase by the park +STR_3224 :{SMALLFONT}{BLACK}Set construction rights to be available to purchase by the park +STR_3225 :{SMALLFONT}{BLACK}Toggle on/off building a random cluster of objects around the selected position +STR_3226 :{SMALLFONT}{BLACK}Build park entrance +STR_3227 :Too many park entrances! +STR_3228 :{SMALLFONT}{BLACK}Set starting positions for people +STR_3229 :Block Brakes cannot be used directly after station +STR_3230 :Block Brakes cannot be used directly after each other +STR_3231 :Block Brakes cannot be used directly after the top of this lift hill +STR_3232 :Options - Financial +STR_3233 :Options - Guests +STR_3234 :Options - Park +STR_3235 :{SMALLFONT}{BLACK}Show financial options +STR_3236 :{SMALLFONT}{BLACK}Show guest options +STR_3237 :{SMALLFONT}{BLACK}Show park options +STR_3238 :No Money +STR_3239 :{SMALLFONT}{BLACK}Make this park a 'no money' park with no financial restrictions +STR_3240 :{WINDOW_COLOUR_2}Initial cash: +STR_3241 :{WINDOW_COLOUR_2}Initial loan: +STR_3242 :{WINDOW_COLOUR_2}Maximum loan size: +STR_3243 :{WINDOW_COLOUR_2}Annual interest rate: +STR_3244 :Forbid marketing campaigns +STR_3245 :{SMALLFONT}{BLACK}Forbid advertising, promotional schemes, and other marketing campaigns +STR_3246 :{WINDOW_COLOUR_2}{CURRENCY} +STR_3247 :{WINDOW_COLOUR_2}{COMMA16}% +STR_3248 :Can't increase initial cash any further! +STR_3249 :Can't reduce initial cash any further! +STR_3250 :Can't increase initial loan any further! +STR_3251 :Can't reduce initial loan any further! +STR_3252 :Can't increase maximum loan size any further! +STR_3253 :Can't reduce maximum loan size any further! +STR_3254 :Can't increase interest rate any further! +STR_3255 :Can't reduce interest rate any further! +STR_3256 :Guests prefer less intense rides +STR_3257 :{SMALLFONT}{BLACK}Select whether guests should generally prefer less intense rides only +STR_3258 :Guests prefer more intense rides +STR_3259 :{SMALLFONT}{BLACK}Select whether guests should generally prefer more intense rides only +STR_3260 :{WINDOW_COLOUR_2}Cash per guest (average): +STR_3261 :{WINDOW_COLOUR_2}Guests initial happiness: +STR_3262 :{WINDOW_COLOUR_2}Guests initial hunger: +STR_3263 :{WINDOW_COLOUR_2}Guests initial thirst: +STR_3264 :Can't increase this any further! +STR_3265 :Can't reduce this any further! +STR_3266 :{SMALLFONT}{BLACK}Select how this park charges for entrance and rides +STR_3267 :Forbid tree removal +STR_3268 :{SMALLFONT}{BLACK}Forbid tall trees being removed +STR_3269 :Forbid landscape changes +STR_3270 :{SMALLFONT}{BLACK}Forbid any changes to the landscape +STR_3271 :Forbid high construction +STR_3272 :{SMALLFONT}{BLACK}Forbid any tall construction +STR_3273 :Park rating higher difficult level +STR_3274 :{SMALLFONT}{BLACK}Make the park rating value more challenging +STR_3275 :Guest generation higher difficult level +STR_3276 :{SMALLFONT}{BLACK}Make it more difficult to attract guests to the park +STR_3277 :{WINDOW_COLOUR_2}Cost to buy land: +STR_3278 :{WINDOW_COLOUR_2}Cost to buy construction rights: +STR_3279 :Free park entry / Pay per ride +STR_3280 :Pay to enter park / Free rides +STR_3281 :{WINDOW_COLOUR_2}Entry price: +STR_3282 :{SMALLFONT}{BLACK}Select objective and park name +STR_3283 :{SMALLFONT}{BLACK}Select rides to be preserved +STR_3284 :Objective Selection +STR_3285 :Preserved Rides +STR_3286 :{SMALLFONT}{BLACK}Select objective for this scenario +STR_3287 :{WINDOW_COLOUR_2}Objective: +STR_3288 :{SMALLFONT}{BLACK}Select climate +STR_3289 :{WINDOW_COLOUR_2}Climate: +STR_3290 :Cool and wet +STR_3291 :Warm +STR_3292 :Hot and dry +STR_3293 :Cold +STR_3294 :Change... +STR_3295 :{SMALLFONT}{BLACK}Change name of park +STR_3296 :{SMALLFONT}{BLACK}Change name of scenario +STR_3297 :{SMALLFONT}{BLACK}Change detail notes about park / scenario +STR_3298 :{WINDOW_COLOUR_2}Park Name: {BLACK}{STRINGID} +STR_3299 :{WINDOW_COLOUR_2}Park/Scenario Details: +STR_3300 :{WINDOW_COLOUR_2}Scenario Name: {BLACK}{STRINGID} +STR_3301 :{WINDOW_COLOUR_2}Objective Date: +STR_3302 :{WINDOW_COLOUR_2}{MONTHYEAR} +STR_3303 :{WINDOW_COLOUR_2}Number of guests: +STR_3304 :{WINDOW_COLOUR_2}Park value: +STR_3305 :{WINDOW_COLOUR_2}Monthly income: +STR_3306 :{WINDOW_COLOUR_2}Monthly profit: +STR_3307 :{WINDOW_COLOUR_2}Minimum length: +STR_3308 :{WINDOW_COLOUR_2}Excitement rating: +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_3314 :Enter name for scenario: +STR_3315 :Park/Scenario Details +STR_3316 :Enter description of this scenario: +STR_3317 :No details yet +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_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_3327 :Starting positions for people not set +STR_3328 :Can't advance to next editor stage... +STR_3329 :Park entrance not yet built +STR_3330 :Park must own some land +STR_3331 :Path from park entrance to map edge either not complete or too complex - Path must be single-width with as few junctions and corners as possible +STR_3332 :Park entrance is the wrong way round or has no path leading to the map edge +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_3341 :{SMALLFONT}{BLACK}Game tools +STR_3342 :Scenario Editor +STR_3343 :Convert Saved Game to Scenario +STR_3344 :Roller Coaster Designer +STR_3345 :Track Designs Manager +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_3385 :Beginners Tutorial +STR_3386 :Custom Rides Tutorial +STR_3387 :Roller Coaster Building Tutorial +STR_3388 :Unable to switch to selected mode +STR_3389 :Unable to select additional item of scenery... +STR_3390 :Too many items selected +STR_3391 :{SMALLFONT}{BLACK}Here is our park - Let's have a quick look around... +STR_3392 :{SMALLFONT}{BLACK}Holding down the RIGHT mouse button and moving the mouse is the quickest way to move the view... +STR_3393 :{SMALLFONT}{BLACK}To view more of the park, you can zoom the view out using the icon at the top of the screen... +STR_3394 :{SMALLFONT}{BLACK}You can also rotate the view in 90 degree steps... +STR_3395 :{SMALLFONT}{BLACK}Building anything at this scale is a bit difficult, so let's zoom the view back in again... +STR_3396 :{SMALLFONT}{BLACK}Let's build a simple ride to get the park started... +STR_3397 :{SMALLFONT}{BLACK}The white 'ghost' image shows where the ride will be built. We'll move the pointer to select the position then click to build it... +STR_3398 :{SMALLFONT}{BLACK}Rides need an entrance and an exit. We'll move the pointer to a square on the edge of the ride and then click to build first the entrance and then the exit... +STR_3399 :{SMALLFONT}{BLACK}We need to build footpaths to allow guests to reach our new ride... +STR_3400 :{SMALLFONT}{BLACK}For the path to the ride entrance we'll use a special 'queue line' path... +STR_3401 :{SMALLFONT}{BLACK}For the exit path, just an 'ordinary' path will do... +STR_3402 :{SMALLFONT}{BLACK}Right, lets open the ride! To open the ride we click the flag icon on the ride window and select 'open'... +STR_3403 :{SMALLFONT}{BLACK}But where are the guests? +STR_3404 :{SMALLFONT}{BLACK}Oh - The park is still closed! Right - Let's open it... +STR_3405 :{SMALLFONT}{BLACK}While we're waiting for our first guests, let's build some scenery... +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_3439 :Clear Scenery +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 + +# New strings, cleaner +STR_5120 :Finances +STR_5121 :Research +STR_5122 :Select rides by track type (like in RCT1) +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 :Cheats +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 :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 :{POP16}{MONTH} {PUSH16}{PUSH16}{STRINGID}, Year {POP16}{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 :Create +STR_5255 :{SMALLFONT}{BLACK}Create a new title sequence from scratch +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 and interface +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 :{SMALLFONT}{BLACK}Makes some 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 :Park cheats +STR_5348 :Ride cheats +STR_5349 :{SMALLFONT}{BLACK}All Rides +STR_5350 :Max +STR_5351 :Min +STR_5352 :{BLACK}Happiness: +STR_5353 :{BLACK}Energy: +STR_5354 :{BLACK}Hunger: +STR_5355 :{BLACK}Thirst: +STR_5356 :{BLACK}Nausea: +STR_5357 :{BLACK}Nausea tolerance: +STR_5358 :{BLACK}Bathroom: +STR_5359 :Remove guests +STR_5360 :{SMALLFONT}{BLACK}Removes all guests from the map +STR_5361 :Give all guests: +STR_5362 :{BLACK}Set all guests' preferred ride intensity to: +STR_5363 :More than 1 +STR_5364 :Less than 15 +STR_5365 :{BLACK}Staff speed: +STR_5366 :Normal +STR_5367 :Fast +STR_5368 :Reset crash status +STR_5369 :Park parameters... +STR_5370 :{SMALLFONT}{BLACK}Click this button to modify park{NEWLINE}parameters like restrictions,{NEWLINE}guest generation and money. +STR_5371 :Object Selection +STR_5372 :Invert right mouse dragging +STR_5373 :Name {STRINGID} +STR_5374 :Date {STRINGID} +STR_5375 :{UP} +STR_5376 :{DOWN} +STR_5377 :{SMALLFONT}{BLACK}Saves +STR_5378 :{SMALLFONT}{BLACK}Script +STR_5379 :{SMALLFONT}{BLACK}Skip to next wait command +STR_5380 :{SMALLFONT}{BLACK}Start playing title sequence +STR_5381 :{SMALLFONT}{BLACK}Stop playing title sequence +STR_5382 :{SMALLFONT}{BLACK}Restart title sequence +STR_5383 :{SMALLFONT}{BLACK}Create a new title sequence based on the current one +STR_5384 :{SMALLFONT}{BLACK}Delete the current title sequence +STR_5385 :{SMALLFONT}{BLACK}Rename the current title sequence +STR_5386 :{SMALLFONT}{BLACK}Insert a new command +STR_5387 :{SMALLFONT}{BLACK}Edit the selected command +STR_5388 :{SMALLFONT}{BLACK}Delete the selected command +STR_5389 :{SMALLFONT}{BLACK}Skip to the selected command in the title sequence +STR_5390 :{SMALLFONT}{BLACK}Move the selected command down +STR_5391 :{SMALLFONT}{BLACK}Move the selected command up +STR_5392 :{SMALLFONT}{BLACK}Add a save to the title sequence +STR_5393 :{SMALLFONT}{BLACK}Remove the selected save from the title sequence +STR_5394 :{SMALLFONT}{BLACK}Rename the selected save +STR_5395 :{SMALLFONT}{BLACK}Load the selected save in game +STR_5396 :{SMALLFONT}{BLACK}Reload the title sequence if changes have been made to it outside of the game +STR_5397 :Can only be used on the title screen +STR_5398 :Cannot edit title sequence while it's playing +STR_5399 :Press the stop button to continue editing +STR_5400 :Can't change this title sequence +STR_5401 :Create a new title sequence to make changes to +STR_5402 :Failed to load title sequence +STR_5403 :There may be no Load or Wait command or a save may be invalid +STR_5404 :Name already exists +STR_5405 :Enter a name for the save +STR_5406 :Enter a name for the title sequence +STR_5407 :Add +STR_5408 :Remove +STR_5409 :Insert +STR_5410 :Edit +STR_5411 :Reload +STR_5412 :Skip to +STR_5413 :Load +STR_5414 :Load{MOVE_X}{87}Six Flags Magic Mountain.SC6 +STR_5415 :Load{MOVE_X}{87}{STRING} +STR_5416 :Load{MOVE_X}{87}No save selected +STR_5417 :Location +STR_5418 :Location{MOVE_X}{87}{COMMA16} {COMMA16} +STR_5419 :Rotate +STR_5420 :Rotate{MOVE_X}{87}{COMMA16} +STR_5421 :Zoom +STR_5422 :Zoom{MOVE_X}{87}{COMMA16} +STR_5423 :Wait +STR_5424 :Wait{MOVE_X}{87}{COMMA16} +STR_5425 :Restart +STR_5426 :End +STR_5427 :Coordinates: +STR_5428 :Counter-clockwise rotations: +STR_5429 :Zoom level: +STR_5430 :Seconds to wait: +STR_5431 :Save to load: +STR_5432 :Command: +STR_5433 :Title Sequences +STR_5434 :Command Editor +STR_5435 :Rename save +STR_5436 :Edit Title Sequences... +STR_5437 :No save selected +STR_5438 :Can't make changes while command editor is open +STR_5439 :A wait command with at least 4 seconds is required with a restart command +STR_5440 :Minimize fullscreen on focus loss +STR_5441 :{SMALLFONT}{BLACK}Identifies rides by track type,{NEWLINE}so vehicles can be changed{NEWLINE}afterwards, like in RCT1. +STR_5442 :Force park rating: +STR_5443 :Speed{MOVE_X}{87}{STRINGID} +STR_5444 :Speed: +STR_5445 :Speed +STR_5446 :Get +STR_5447 :Type {STRINGID} +STR_5448 :Ride / Vehicle {STRINGID} +STR_5449 :Reduce game speed +STR_5450 :Increase game speed +STR_5451 :Open cheats window +STR_5452 :Toggle visibility of toolbars +STR_5453 :Select another ride +STR_5454 :Uncap FPS +STR_5455 :Enable sandbox mode +STR_5456 :Disable clearance checks +STR_5457 :Disable support limits +STR_5458 :Rotate clockwise +STR_5459 :Rotate counterclockwise +STR_5460 :Rotate view counterclockwise +STR_5461 :Set guests' parameters +STR_5462 :{CURRENCY} +STR_5463 :Goal: Have fun! +STR_5464 :General +STR_5465 :Climate +STR_5466 :Staff +STR_5467 :ALT + +STR_5468 :Recent messages +STR_5469 :Scroll map up +STR_5470 :Scroll map left +STR_5471 :Scroll map down +STR_5472 :Scroll map right +STR_5473 :Cycle day / night +STR_5474 :Display text on banners in upper case +STR_5476 :Hardware +STR_5477 :Map rendering +STR_5478 :Controls +STR_5479 :Toolbar +STR_5480 :Show toolbar buttons for: +STR_5481 :Themes diff --git a/data/language/chinese_traditional.txt b/data/language/chinese_traditional.txt new file mode 100644 index 0000000000..f7c6349065 --- /dev/null +++ b/data/language/chinese_traditional.txt @@ -0,0 +1,4030 @@ +# 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 :螺旋式雲霄飛車 +STR_0003 :站立式雲霄飛車 +STR_0004 :懸吊式雲霄飛車 +STR_0005 :反轉式雲霄飛車 +STR_0006 :兒童雲霄飛車 +STR_0007 :小火車 +STR_0008 :單軌電車 +STR_0009 :迷你懸吊式雲霄飛車 +STR_0010 :小船出租 +STR_0011 :木製飛鼠式雲霄飛車 +STR_0012 :越野賽馬式雲霄飛車 +STR_0013 :自駕軌道車輛 +STR_0014 :自由落體 +STR_0015 :雪橇式雲霄飛車 +STR_0016 :觀景塔 +STR_0017 :迴環式雲霄飛車 +STR_0018 :滑水道 +STR_0019 :採礦列車雲霄飛車 +STR_0020 :纜車 +STR_0021 :瓶塞鑽式雲霄飛車 +STR_0022 :迷宮 +STR_0023 :螺旋滑道 +STR_0024 :小型賽車 +STR_0025 :運木水道 +STR_0026 :激流船 +STR_0027 :碰碰車 +STR_0028 :海盜船 +STR_0029 :垂直迴轉海盜船 +STR_0030 :食物店鋪 +STR_0031 :Unknown Stall (1D) +STR_0032 :飲料店鋪 +STR_0033 :Unknown Stall (1F) +STR_0034 :商店 +STR_0035 :旋轉木馬 +STR_0036 :Unknown Stall (22) +STR_0037 :訪客資訊中心 +STR_0038 :廁所 +STR_0039 :摩天輪 +STR_0040 :動感模擬器 +STR_0041 :3D戲院 +STR_0042 :上旋搖擺 +STR_0043 :太空飛輪 +STR_0044 :向後自由落體式雲霄飛車 +STR_0045 :升降機 +STR_0046 :垂直雲霄飛車 +STR_0047 :提款機 +STR_0048 :龍捲風 +STR_0049 :鬼屋 +STR_0050 :急救室 +STR_0051 :馬戲團 +STR_0052 :驚奇之旅 +STR_0053 :鐵架旋轉式雲霄飛車 +STR_0054 :木製雲霄飛車 +STR_0055 :木製軌道阻力式雲霄飛車 +STR_0056 :飛鼠式雲霄飛車 +STR_0057 :多維度雲霄飛車 +STR_0058 :Unknown Ride (38) +STR_0059 :飛行式雲霄飛車 +STR_0060 :Unknown Ride (3A) +STR_0061 :木製旋轉杯式雲霄飛車 +STR_0062 :濺水船 +STR_0063 :迷你直升機 +STR_0064 :躺身式雲霄飛車 +STR_0065 :懸吊式單軌電車 +STR_0066 :Unknown Ride (40) +STR_0067 :木製倒轉車式雲霄飛車 +STR_0068 :管道旋轉式雲霄飛車 +STR_0069 :迷你高爾夫 +STR_0070 :巨型雲霄飛車 +STR_0071 :旋轉落體 +STR_0072 :碰碰飛碟 +STR_0073 :古怪屋 +STR_0074 :單軌單車 +STR_0075 :緊湊的反轉式雲霄飛車 +STR_0076 :濺水式雲霄飛車 +STR_0077 :以空氣為動力的垂直式雲霄飛車 +STR_0078 :反轉髮夾彎式雲霄飛車 +STR_0079 :魔法地毯 +STR_0080 :潛艇遊道 +STR_0081 :木筏河道 +STR_0082 :Unknown Ride (50) +STR_0083 :太空摩天輪 +STR_0084 :Unknown Ride (52) +STR_0085 :Unknown Ride (53) +STR_0086 :Unknown Ride (54) +STR_0087 :Unknown Ride (55) +STR_0088 :反轉極速式雲霄飛車 +STR_0089 :迷你雲霄飛車 +STR_0090 :礦遊式雲霄飛車 +STR_0091 :Unknown Ride (59) +STR_0092 :直線電動機發車雲霄飛車 +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 :列車懸吊在雲霄飛車的軌道下, 並會在拐彎的時候搖擺乘客到旁邊 +STR_0515 :一款鐵架式雲霄飛車但列車於軌道下方行駛, 附帶很多複雜及扭曲的軌道配置 +STR_0516 :一款較溫和的雲霄飛車, 設計給不敢乘坐雲霄飛車的乘客壯膽 +STR_0517 :乘客乘坐於小型火車延著窄軌鐵道行走 +STR_0518 :乘客乘坐於電氣化列車延著單軌鐵路行走 +STR_0519 :乘客乘坐於單軌軌道下的小型車廂裡, 然後在途中被不斷搖擺到一旁 +STR_0520 :一個遊客可以駕駛/划駛個人小船的船用月台 +STR_0521 :一款極快而有複雜軌道配置的雲霄飛車, 附有緊接的彎道及陡斜的落坡. 這款雲霄飛車刺激度注定會偏高. +STR_0522 :一款較小型的雲霄飛車, 乘客坐在軌道上而並沒有其他車卡包圍他們 +STR_0523 :乘客會坐在有動力的車輛內, 慢慢地依照軌道路線遊覽 +STR_0524 :自由落體的車輛會被氣體噴射到高塔頂, 並隨後自由落下 +STR_0525 :乘客飛馳在扭曲的軌道上, 只靠彎道及半月型的軌道引領他們 +STR_0526 :乘客會在不斷旋轉並上升到最頂的座艙內觀看樂園景色 +STR_0527 :一款以順滑軌道為特徵的雲霄飛車, 並附有垂直迴環可供使用 +STR_0528 :乘客坐在充氣小艇中於半月型或完全封閉的軌道上滑翔 +STR_0529 :以採礦列車為主題的雲霄飛車沿著鐵架軌道行駛, 令它很像在古老的軌道行駛上 +STR_0530 :列車懸掛在鋼纜下並不斷於車站與車站之間遊走 +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 :列車會被又長又直的軌道上的直線發動機加速, 然後衝上垂直軌道, 自由落體後回到車站 +STR_0555 :遊客乘搭升降機上下穿梭於垂直的管道中, 並借此訪問另一層 +STR_0556 :加闊的列車於垂直下坡上完全滑落, 給予人終極的雲霄飛車自由落體體驗 +STR_0557 : +STR_0558 : +STR_0559 : +STR_0560 : +STR_0561 : +STR_0562 :有動力的車輛將會穿梭於有著恐怖景物及特效的多層軌道中 +STR_0563 :乘客坐在舒適並只有簡單安全裝備的列車上享受巨大而順滑的下滑, 扭曲的軌道和充足的'空中'時間 +STR_0564 :一款在木製軌道運行的雲霄飛車, 這個雲霄飛車會嘈吵地飛馳過高低不平的軌道, 給乘客充足的'空中時間'之餘, 同時會給人一種'失去控制'的乘坐體驗 +STR_0565 :一款只能使用普通下坡及彎道的簡單木製雲霄飛車, 車輛只靠產生軌道阻力的車輪及重力滑翔於軌道上 +STR_0566 :每輛單獨的雲霄飛車都會遊走在附有急彎及急短下坡的Z型軌道上 +STR_0567 :乘客坐在懸掛在軌道的不同位置下, 衝下陡下坡及各種倒轉軌道時, 會被翻騰得四腳朝天 +STR_0568 : +STR_0569 :乘客將會乘坐在軌道下的特別繫帶, 在空中盤旋時體驗飛一般的感受 +STR_0570 : +STR_0571 :圓型的車輛於他們行走在Z型軌道上被不停的轉動 +STR_0572 :載客量大的小船遊走於寬敞的水道上, 由輸送帶送他們上坡, 並於下坡中加速, 務求濺出巨型的水花令到乘客全身濕透 +STR_0573 :有動力的直升機型車輔於鋼軌上遊走, 他們由乘客的腳踏所控制 +STR_0574 :乘客躺臥在特別繫帶中, 以他們面向的背或頭遊走於曲折的軌道及翻轉 +STR_0575 :有動力的列車懸掛在單軌下運送乘客到樂園內的不同地方 +STR_0576 : +STR_0577 :擁有轉向架的車輔於木製軌道上, 被特別的倒轉裝置轉向 +STR_0578 :車輛運行於O型的軌道中, 並會穿過陡下坡及橫滾軌道 +STR_0579 : +STR_0580 :一款可建造順滑下坡及高達300英尺坡道的巨型鐵製雲霄飛車 +STR_0581 :圍繞著塔的座位會在不斷慢慢旋轉中被拉至塔頂, 然後便自由落體, 再被有磁力的煞車裝置慢慢煞停於站台 +STR_0582 : +STR_0583 : +STR_0584 :運行在鐵製單軌上的特別單車, 像一般單車一樣, 會被乘客踏行 +STR_0585 :乘客坐在軌道懸掛下的一對對的座位經歷被緊密的軌道上旋轉及迴轉 +STR_0586 :船型的車輛行駛於雲霄飛車的軌道上, 允許他們能夠擁有扭曲式的彎道陡下坡等軌道配置, 更會被普通的水道所濺濕 +STR_0587 :雲霄飛車列車被令人膽跳心驚的氣動發車加速衝上垂直軌道後, 穿過最頂, 然後垂直下落到另一邊回到車站 +STR_0588 :每輛單獨的雲霄飛車遊走在附有髮夾彎及急下坡的Z型軌道上 +STR_0589 : +STR_0590 :乘客在潛艇中觀賞水底的景觀 +STR_0591 :木筏造型船於河道上慢慢地遊覽著 +STR_0592 : +STR_0593 : +STR_0594 : +STR_0595 : +STR_0596 : +STR_0597 : +STR_0598 :反轉式雲霄飛車加速離開車站, 穿過到垂直軌道的尖端, 然後倒轉返回到車站, 再穿越到另一邊垂直軌道的尖端 +STR_0599 :一款擁有獨立車輛及順滑又彎曲的下坡的緊湊式雲霄飛車 +STR_0600 :有動車的採礦列車遊走在順滑但又曲折的軌道配置中 +STR_0601 : +STR_0602 :雲霄飛車列車由直線發動機加速離開車站, 穿過盤繞的倒轉軌道後回到車站 +STR_0603 :遊客{INT32} +STR_0604 :遊客{INT32} +STR_0605 :遊客{INT32} +STR_0606 :遊客{INT32} +STR_0607 :遊客{INT32} +STR_0608 :遊客{INT32} +STR_0609 :遊客{INT32} +STR_0610 :遊客{INT32} +STR_0611 :遊客{INT32} +STR_0612 :遊客{INT32} +STR_0613 :遊客{INT32} +STR_0614 :遊客{INT32} +STR_0615 :遊客{INT32} +STR_0616 :遊客{INT32} +STR_0617 :遊客{INT32} +STR_0618 :遊客{INT32} +STR_0619 :遊客{INT32} +STR_0620 :遊客{INT32} +STR_0621 :遊客{INT32} +STR_0622 :遊客{INT32} +STR_0623 :遊客{INT32} +STR_0624 :遊客{INT32} +STR_0625 :遊客{INT32} +STR_0626 :遊客{INT32} +STR_0627 :遊客{INT32} +STR_0628 :遊客{INT32} +STR_0629 :遊客{INT32} +STR_0630 :遊客{INT32} +STR_0631 :遊客{INT32} +STR_0632 :遊客{INT32} +STR_0633 :遊客{INT32} +STR_0634 :遊客{INT32} +STR_0635 :遊客{INT32} +STR_0636 :遊客{INT32} +STR_0637 :遊客{INT32} +STR_0638 :遊客{INT32} +STR_0639 :遊客{INT32} +STR_0640 :遊客{INT32} +STR_0641 :遊客{INT32} +STR_0642 :遊客{INT32} +STR_0643 :遊客{INT32} +STR_0644 :遊客{INT32} +STR_0645 :遊客{INT32} +STR_0646 :遊客{INT32} +STR_0647 :遊客{INT32} +STR_0648 :遊客{INT32} +STR_0649 :遊客{INT32} +STR_0650 :遊客{INT32} +STR_0651 :遊客{INT32} +STR_0652 :遊客{INT32} +STR_0653 :遊客{INT32} +STR_0654 :遊客{INT32} +STR_0655 :遊客{INT32} +STR_0656 :遊客{INT32} +STR_0657 :遊客{INT32} +STR_0658 :遊客{INT32} +STR_0659 :遊客{INT32} +STR_0660 :遊客{INT32} +STR_0661 :遊客{INT32} +STR_0662 :遊客{INT32} +STR_0663 :遊客{INT32} +STR_0664 :遊客{INT32} +STR_0665 :遊客{INT32} +STR_0666 :遊客{INT32} +STR_0667 :遊客{INT32} +STR_0668 :遊客{INT32} +STR_0669 :遊客{INT32} +STR_0670 :遊客{INT32} +STR_0671 :遊客{INT32} +STR_0672 :遊客{INT32} +STR_0673 :遊客{INT32} +STR_0674 :遊客{INT32} +STR_0675 :遊客{INT32} +STR_0676 :遊客{INT32} +STR_0677 :遊客{INT32} +STR_0678 :遊客{INT32} +STR_0679 :遊客{INT32} +STR_0680 :遊客{INT32} +STR_0681 :遊客{INT32} +STR_0682 :遊客{INT32} +STR_0683 :遊客{INT32} +STR_0684 :遊客{INT32} +STR_0685 :遊客{INT32} +STR_0686 :遊客{INT32} +STR_0687 :遊客{INT32} +STR_0688 :遊客{INT32} +STR_0689 :遊客{INT32} +STR_0690 :遊客{INT32} +STR_0691 :遊客{INT32} +STR_0692 :遊客{INT32} +STR_0693 :遊客{INT32} +STR_0694 :遊客{INT32} +STR_0695 :遊客{INT32} +STR_0696 :遊客{INT32} +STR_0697 :遊客{INT32} +STR_0698 :遊客{INT32} +STR_0699 :遊客{INT32} +STR_0700 :遊客{INT32} +STR_0701 :遊客{INT32} +STR_0702 :遊客{INT32} +STR_0703 :遊客{INT32} +STR_0704 :遊客{INT32} +STR_0705 :遊客{INT32} +STR_0706 :遊客{INT32} +STR_0707 :遊客{INT32} +STR_0708 :遊客{INT32} +STR_0709 :遊客{INT32} +STR_0710 :遊客{INT32} +STR_0711 :遊客{INT32} +STR_0712 :遊客{INT32} +STR_0713 :遊客{INT32} +STR_0714 :遊客{INT32} +STR_0715 :遊客{INT32} +STR_0716 :遊客{INT32} +STR_0717 :遊客{INT32} +STR_0718 :遊客{INT32} +STR_0719 :遊客{INT32} +STR_0720 :遊客{INT32} +STR_0721 :遊客{INT32} +STR_0722 :遊客{INT32} +STR_0723 :遊客{INT32} +STR_0724 :遊客{INT32} +STR_0725 :遊客{INT32} +STR_0726 :遊客{INT32} +STR_0727 :遊客{INT32} +STR_0728 :遊客{INT32} +STR_0729 :遊客{INT32} +STR_0730 :遊客{INT32} +STR_0731 :遊客{INT32} +STR_0732 :遊客{INT32} +STR_0733 :遊客{INT32} +STR_0734 :遊客{INT32} +STR_0735 :遊客{INT32} +STR_0736 :遊客{INT32} +STR_0737 :遊客{INT32} +STR_0738 :遊客{INT32} +STR_0739 :遊客{INT32} +STR_0740 :遊客{INT32} +STR_0741 :遊客{INT32} +STR_0742 :遊客{INT32} +STR_0743 :遊客{INT32} +STR_0744 :遊客{INT32} +STR_0745 :遊客{INT32} +STR_0746 :遊客{INT32} +STR_0747 :遊客{INT32} +STR_0748 :遊客{INT32} +STR_0749 :遊客{INT32} +STR_0750 :遊客{INT32} +STR_0751 :遊客{INT32} +STR_0752 :遊客{INT32} +STR_0753 :遊客{INT32} +STR_0754 :遊客{INT32} +STR_0755 :遊客{INT32} +STR_0756 :遊客{INT32} +STR_0757 :遊客{INT32} +STR_0758 :遊客{INT32} +STR_0759 :遊客{INT32} +STR_0760 :遊客{INT32} +STR_0761 :遊客{INT32} +STR_0762 :遊客{INT32} +STR_0763 :遊客{INT32} +STR_0764 :遊客{INT32} +STR_0765 :遊客{INT32} +STR_0766 :遊客{INT32} +STR_0767 :遊客{INT32} +STR_0768 :清潔工人{INT32} +STR_0769 :維修人員{INT32} +STR_0770 :安全警衛{INT32} +STR_0771 :表演人員{INT32} +STR_0772 :未命名樂園{POP16}{POP16} +STR_0773 :未命名樂園{POP16}{POP16} +STR_0774 :未命名樂園{POP16}{POP16} +STR_0775 :未命名樂園{POP16}{POP16} +STR_0776 :未命名樂園{POP16}{POP16} +STR_0777 :未命名樂園{POP16}{POP16} +STR_0778 :招牌 +STR_0779 :1日 +STR_0780 :2日 +STR_0781 :3日 +STR_0782 :4日 +STR_0783 :5日 +STR_0784 :6日 +STR_0785 :7日 +STR_0786 :8日 +STR_0787 :9日 +STR_0788 :10日 +STR_0789 :11日 +STR_0790 :12日 +STR_0791 :13日 +STR_0792 :14日 +STR_0793 :15日 +STR_0794 :16日 +STR_0795 :17日 +STR_0796 :18日 +STR_0797 :19日 +STR_0798 :20日 +STR_0799 :21日 +STR_0800 :22日 +STR_0801 :23日 +STR_0802 :24日 +STR_0803 :25日 +STR_0804 :26日 +STR_0805 :27日 +STR_0806 :28日 +STR_0807 :29日 +STR_0808 :30日 +STR_0809 :31日 +STR_0810 :1月 +STR_0811 :2月 +STR_0812 :3月 +STR_0813 :4月 +STR_0814 :5月 +STR_0815 :6月 +STR_0816 :7月 +STR_0817 :8月 +STR_0818 :9月 +STR_0819 :10月 +STR_0820 :11月 +STR_0821 :12月 +STR_0822 :無法讀取圖像檔案 +STR_0823 :缺少或不能讀取檔案 +STR_0824 :{BLACK}{CROSS} +STR_0825 :此名字已被使用 +STR_0826 :太多名稱被命名 +STR_0827 :沒有足夠現金 - 需要{CURRENCY2DP} +STR_0828 :{SMALLFONT}{BLACK}關閉視窗 +STR_0829 :{SMALLFONT}{BLACK}視窗標題 - 拖曳此來移動本視窗 +STR_0830 :{SMALLFONT}{BLACK}放大檢視區域 +STR_0831 :{SMALLFONT}{BLACK}縮小檢視區域 +STR_0832 :{SMALLFONT}{BLACK}將檢視區域順時針旋轉90{DEGREE} +STR_0833 :{SMALLFONT}{BLACK}暫停遊戲 +STR_0834 :{SMALLFONT}{BLACK}硬碟及遊戲設定 +STR_0835 :遊戲初始化失敗 +STR_0836 :無法於最小化的狀態下啟動遊戲 +STR_0837 :無法初始化繪製圖像系統 +STR_0838 : +STR_0839 :{UINT16} x {UINT16} +STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +STR_0847 :有關'OpenRCT2' +STR_0848 :RollerCoaster Tycoon 2 +STR_0849 :{WINDOW_COLOUR_2}版本 2.01.028 +STR_0850 :{WINDOW_COLOUR_2}版權商標 {COPYRIGHT} 2002 Chris Sawyer, 版權所有 +STR_0851 :{WINDOW_COLOUR_2}Designed and programmed by Chris Sawyer +STR_0852 :{WINDOW_COLOUR_2}Graphics by Simon Foster +STR_0853 :{WINDOW_COLOUR_2}Sound and music by Allister Brimble +STR_0854 :{WINDOW_COLOUR_2}Additional sounds recorded by David Ellis +STR_0855 :{WINDOW_COLOUR_2}Representation by Jacqui Lyons at Marjacq Ltd. +STR_0856 :{WINDOW_COLOUR_2}感謝: +STR_0857 :{WINDOW_COLOUR_2}Peter James Adcock, Joe Booth, and 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 :太低! +STR_0878 :太高! +STR_0879 :不能降低此地... +STR_0880 :不能升高此地... +STR_0881 :物件擋於此地 +STR_0882 :載入遊戲 +STR_0883 :儲存遊戲 +STR_0884 :載入地形 +STR_0885 :儲存地形 +STR_0886 :離開遊戲 +STR_0887 :離開劇情編輯工具 +STR_0888 :離開雲霄飛車設計工具 +STR_0889 :離開軌道設計管理工具 +STR_0890 :SCR{COMMA16}.BMP +STR_0891 :截圖 +STR_0892 :截圖'{STRINGID}'已儲存到硬碟中 +STR_0893 :截圖失敗! +STR_0894 :地形資料的範圍已滿! +STR_0895 :不能建造在一半露天一半地底的地勢中 +STR_0896 :{POP16}{POP16}{STRINGID} 建造 +STR_0897 :方向 +STR_0898 :{SMALLFONT}{BLACK}左彎 +STR_0899 :{SMALLFONT}{BLACK}右彎 +STR_0900 :{SMALLFONT}{BLACK}左彎 (小弧度) +STR_0901 :{SMALLFONT}{BLACK}右彎 (小弧度) +STR_0902 :{SMALLFONT}{BLACK}左彎 (很小弧度) +STR_0903 :{SMALLFONT}{BLACK}右彎 (很小弧度) +STR_0904 :{SMALLFONT}{BLACK}左彎 (大弧度) +STR_0905 :{SMALLFONT}{BLACK}右彎 (大弧度) +STR_0906 :{SMALLFONT}{BLACK}直向前 +STR_0907 :斜度 +STR_0908 :滾動/傾斜 +STR_0909 :旋轉座位 +STR_0910 :{SMALLFONT}{BLACK}向左傾斜 +STR_0911 :{SMALLFONT}{BLACK}向右傾斜 +STR_0912 :{SMALLFONT}{BLACK}無傾斜 +STR_0913 :{SMALLFONT}{BLACK}移動到前一個軌道 +STR_0914 :{SMALLFONT}{BLACK}移動到後一個軌道 +STR_0915 :{SMALLFONT}{BLACK}建造此被選中的軌道 +STR_0916 :{SMALLFONT}{BLACK}拆除被高亮選中的軌道 +STR_0917 :{SMALLFONT}{BLACK}垂直下坡 +STR_0918 :{SMALLFONT}{BLACK}陡下坡 +STR_0919 :{SMALLFONT}{BLACK}下坡 +STR_0920 :{SMALLFONT}{BLACK}水平 +STR_0921 :{SMALLFONT}{BLACK}上坡 +STR_0922 :{SMALLFONT}{BLACK}陡上坡 +STR_0923 :{SMALLFONT}{BLACK}垂直上坡 +STR_0924 :{SMALLFONT}{BLACK}向下盤旋 +STR_0925 :{SMALLFONT}{BLACK}向上盤旋 +STR_0926 :不能移除... +STR_0927 :不能在此建造... +STR_0928 :{SMALLFONT}{BLACK}帶有鏈條的坡道, 會將車卡拉上坡 +STR_0929 :'S'型彎道 (向左) +STR_0930 :'S'型彎道 (向右) +STR_0931 :垂直回環 (向左) +STR_0932 :垂直回環 (向右) +STR_0933 :先把地面降低或升高 +STR_0934 :遊樂設施的入口擋在路上 +STR_0935 :遊樂設施的出口擋在路上 +STR_0936 :樂園入口擋於此地 +STR_0937 :{SMALLFONT}{BLACK}檢視選項 +STR_0938 :{SMALLFONT}{BLACK}調整地勢高低及陡峭 +STR_0939 :地底/內部檢視模式 +STR_0940 :移除地表 +STR_0941 :移除垂直表面 +STR_0942 :略過遊樂設施 +STR_0943 :略過景物 +STR_0944 :儲存 +STR_0945 :不要儲存 +STR_0946 :取消 +STR_0947 :載入其他遊戲之前儲存此遊戲? +STR_0948 :離開遊戲之前儲存此遊戲? +STR_0949 :離開遊戲之前儲存此遊戲? +STR_0950 :載入遊戲 +STR_0951 :離開遊戲 +STR_0952 :離開遊戲 +STR_0953 :載入地形 +STR_0954 : +STR_0955 :{SMALLFONT}{BLACK}選擇此軌道的座位旋轉角度 +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 :取消 +STR_0973 :確定 +STR_0974 :遊樂設施 +STR_0975 :商店及攤販 +STR_0976 :洗手間及服務台 +STR_0977 :建造新的運輸類遊樂設施 +STR_0978 :建造新的溫和類遊樂設施 +STR_0979 :建造新的雲霄飛車 +STR_0980 :建造新的剌激類遊樂設施 +STR_0981 :建造新的水文類遊樂設施 +STR_0982 :建造新的商店及攤販 +STR_0983 :研究及開發 +STR_0984 :{WINDOW_COLOUR_2}{UP}{BLACK} {CURRENCY2DP} +STR_0985 :{WINDOW_COLOUR_2}{DOWN}{BLACK} {CURRENCY2DP} +STR_0986 :{BLACK}{CURRENCY2DP} +STR_0987 :太多遊樂設施/店鋪... +STR_0988 :不能興建遊樂設施/店鋪... +STR_0989 :{STRINGID} +STR_0990 :{SMALLFONT}{BLACK}建造 +STR_0991 :車站月台 +STR_0992 :{SMALLFONT}{BLACK}拆除整個遊樂設施/店鋪 +STR_0993 :拆除遊樂設施/店鋪 +STR_0994 :拆除 +STR_0995 :{WINDOW_COLOUR_1}你確定要拆除整個{STRINGID}? +STR_0996 :整體外觀 +STR_0997 :{SMALLFONT}{BLACK}選擇檢視範圍 +STR_0998 :此遊樂設施的車站數量已達到上限 +STR_0999 :需要一個車站月台 +STR_1000 :軌道並未完整地連接好 +STR_1001 :軌道不適合此類型的車卡 +STR_1002 :不能開啟{POP16}{POP16}{POP16}{STRINGID}... +STR_1003 :不能測試{POP16}{POP16}{POP16}{STRINGID}... +STR_1004 :不能關閉{POP16}{POP16}{POP16}{STRINGID}... +STR_1005 :不能於{POP16}{POP16}{POP16}{STRINGID}中建設... +STR_1006 :必需先行關閉 +STR_1007 :無法創建足夠的車輛 +STR_1008 :{SMALLFONT}{BLACK}關閉, 開啟或測試遊樂設施/店鋪 +STR_1009 :{SMALLFONT}{BLACK}關閉或開放所有遊樂設施/店鋪 +STR_1010 :{SMALLFONT}{BLACK}關閉或開放樂園 +STR_1011 :關閉所有遊樂設施 +STR_1012 :開啟所有遊樂設施 +STR_1013 :關閉樂園 +STR_1014 :開放樂園 +STR_1015 :在這個模式下, 多過一個車站的遊樂設施將無法運作 +STR_1016 :在這個模式下, 少於兩個車站的遊樂設施將無法運作 +STR_1017 :不能改變運作模式... +STR_1018 :不能作出更變... +STR_1019 :不能作出更變... +STR_1020 :不能作出更變... +STR_1021 :{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_1022 :每列車{POP16}{POP16}{POP16}{COMMA16}車卡 +STR_1023 :每列車{POP16}{POP16}{POP16}{COMMA16}車卡 +STR_1024 :每列車{COMMA16}車卡 +STR_1025 :每列車{COMMA16}車卡 +STR_1026 :車站月台太長! +STR_1027 :{SMALLFONT}{BLACK}在主視範圍裡將此定位 +STR_1028 :離開了地圖邊緣! +STR_1029 :不能建造於一半地上一半水底的地勢中! +STR_1030 :只能建造於水底! +STR_1031 :不能建造於水底! +STR_1032 :只能建造此於水上! +STR_1033 :只能建造此於地上! +STR_1034 :只能建造此於地面! +STR_1035 :當地政府不允許建造高於樹木的物件! +STR_1036 :載入遊戲 +STR_1037 :載入地形 +STR_1038 :將存檔轉換成劇情 +STR_1039 :安裝新軌道設計 +STR_1040 :儲存遊戲 +STR_1041 :儲存劇情 +STR_1042 :儲存地形 +STR_1043 :OpenRCT2 遊戲存檔 +STR_1044 :OpenRCT2 劇情檔案 +STR_1045 :OpenRCT2 地形檔案 +STR_1046 :OpenRCT2 軌道設計檔案 +STR_1047 :儲存遊戲失敗! +STR_1048 :儲存劇情失敗! +STR_1049 :儲存地形失敗! +STR_1050 :載入失敗...{NEWLINE}檔案中含有非法資料! +STR_1051 :透明化支撐 +STR_1052 :透明化遊客 +STR_1053 :{SMALLFONT}{BLACK}樂園內的遊樂設施/店鋪 +STR_1054 :{SMALLFONT}{BLACK}命名遊樂設施/店鋪 +STR_1055 :{SMALLFONT}{BLACK}命名遊客 +STR_1056 :{SMALLFONT}{BLACK}命名員工 +STR_1057 :遊樂設施/店鋪名稱 +STR_1058 :請輸入這個遊樂設施/店鋪的新名稱: +STR_1059 :不能重命名遊樂設施/店鋪... +STR_1060 :不適合的遊樂設施/店鋪名稱 +STR_1061 :正常模式 +STR_1062 :連續循環模式 +STR_1063 :反向發車循環模式 +STR_1064 :動力發車 (穿過車站) +STR_1065 :穿梭模式 +STR_1066 :出租小船模式 +STR_1067 :向上發車 +STR_1068 :旋轉升降模式 +STR_1069 :站對站模式 +STR_1070 :一次付費單次溜滑梯 +STR_1071 :一次付費無限次溜滑梯 +STR_1072 :迷宮模式 +STR_1073 :賽車模式 +STR_1074 :碰碰車模式 +STR_1075 :搖擺模式 +STR_1076 :店面模式 +STR_1077 :旋轉模式 +STR_1078 :向前旋轉 +STR_1079 :向後旋轉 +STR_1080 :電影: {ENDQUOTES}飛行師復仇行{ENDQUOTES} +STR_1081 :3D電影: {ENDQUOTES}鼠尾擺擺擺{ENDQUOTES} +STR_1082 :太空飛輪模式 +STR_1083 :初學者模式 +STR_1084 :直線電動機發車 +STR_1085 :電影: {ENDQUOTES}驚天乘客{ENDQUOTES} +STR_1086 :3D電影: {ENDQUOTES}追風者{ENDQUOTES} +STR_1087 :3D電影: {ENDQUOTES}太空海盜{ENDQUOTES} +STR_1088 :剌激模式 +STR_1089 :狂暴模式 +STR_1090 :鬼屋模式 +STR_1091 :馬戲團表演模式 +STR_1092 :向下發車 +STR_1093 :古怪屋模式 +STR_1094 :自由落體模式 +STR_1095 :含區域煞車的連續循環模式 +STR_1096 :動力發車 (不穿過車站) +STR_1097 :含區域煞車的動力發車模式 +STR_1098 :移動到{POP16}{STRINGID}的最尾中 +STR_1099 :在{POP16}{STRINGID}等待乘客中 +STR_1100 :等待離開{POP16}{STRINGID}中 +STR_1101 :離開{POP16}{STRINGID} +STR_1102 :以{VELOCITY}行走中 +STR_1103 :到達{POP16}{STRINGID} +STR_1104 :在{POP16}{STRINGID}卸去乘客中 +STR_1105 :以{VELOCITY}行走中 +STR_1106 :毀壞中! +STR_1107 :毀壞了! +STR_1108 :以{VELOCITY}行走中 +STR_1109 :擺動中 +STR_1110 :旋轉中 +STR_1111 :旋轉中 +STR_1112 :運作中 +STR_1113 :放映中 +STR_1114 :旋轉中 +STR_1115 :運作中 +STR_1116 :運作中 +STR_1117 :馬戲團表演中 +STR_1118 :運作中 +STR_1119 :等候纜索拉上坡中 +STR_1120 :以{VELOCITY}行走中 +STR_1121 :停止中 +STR_1122 :等待乘客中 +STR_1123 :等待開始中 +STR_1124 :開始中 +STR_1125 :運作中 +STR_1126 :停止中 +STR_1127 :卸客中 +STR_1128 :被區域煞車裝置煞停了 +STR_1129 :全部車卡使用相同顏色 +STR_1130 :不同{STRINGID}使用不同顏色 +STR_1131 :不同車卡使用不同顏色 +STR_1132 :車卡{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1133 :車卡{POP16}{COMMA16} +STR_1134 :{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} {COMMA16} +STR_1135 :{STRINGID} {COMMA16} +STR_1136 :{SMALLFONT}{BLACK}選擇主要色彩選配 +STR_1137 :{SMALLFONT}{BLACK}選擇額外色彩選配1 +STR_1138 :{SMALLFONT}{BLACK}選擇額外色彩選配2 +STR_1139 :{SMALLFONT}{BLACK}選擇支撐顏色 +STR_1140 :{SMALLFONT}{BLACK}選擇有關車卡顏色調配的選項 +STR_1141 :{SMALLFONT}{BLACK}選擇要修改的車卡/列車 +STR_1142 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1143 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRINGID} +STR_1144 :不能建造/移動這個遊樂設施的入口... +STR_1145 :不能建造/移動這個遊樂設施的出口... +STR_1146 :尚未建造入口 +STR_1147 :尚未建造出口 +STR_1148 :四分之一載客量 +STR_1149 :一半載客量 +STR_1150 :四分之三載客量 +STR_1151 :最大載客量 +STR_1152 :任意載客量 +STR_1153 :在設施軌道上標記高度 +STR_1154 :在土地上標記高度 +STR_1155 :在道路上標記高度 +STR_1156 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1157 :{TICK}{MOVE_X}{SMALLFONT}{STRINGID} +STR_1158 :不能移除... +STR_1159 :{SMALLFONT}{BLACK}放置景物, 花圃及其他裝飾物 +STR_1160 :{SMALLFONT}{BLACK}創造或調整湖泊及水塘 +STR_1161 :不能放置於此... +STR_1162 :{OUTLINE}{TOPAZ}{STRINGID} +STR_1163 :{STRINGID}{NEWLINE}(按右鍵修改) +STR_1164 :{STRINGID}{NEWLINE}(按右鍵移除) +STR_1165 :{STRINGID} - {STRINGID} {COMMA16} +STR_1166 :不能在此降低水位... +STR_1167 :不能在此升高水位... +STR_1168 :選項 +STR_1169 :(無) +STR_1170 :{STRING} +STR_1171 :{RED}已關閉 - - +STR_1172 :{YELLOW}{STRINGID} - - +STR_1173 :{SMALLFONT}{BLACK}建造道路及'輪候區'道路 +STR_1174 :橫額擋在路上 +STR_1175 :不能在斜路上建造此物件 +STR_1176 :不能在此建造道路... +STR_1177 :不能移除此處道路... +STR_1178 :不適合的土地斜度 +STR_1179 :道路擋在路上 +STR_1180 :不能建造此於水底! +STR_1181 :道路 +STR_1182 :類別 +STR_1183 :方向 +STR_1184 :坡道 +STR_1185 :{SMALLFONT}{BLACK}方向 +STR_1186 :{SMALLFONT}{BLACK}下坡 +STR_1187 :{SMALLFONT}{BLACK}水平 +STR_1188 :{SMALLFONT}{BLACK}上坡 +STR_1189 :{SMALLFONT}{BLACK}建造此被選中的道路 +STR_1190 :{SMALLFONT}{BLACK}移除上一段道路 +STR_1191 :{BLACK}{STRINGID} +STR_1192 :{OUTLINE}{RED}{STRINGID} +STR_1193 :{WINDOW_COLOUR_2}{STRINGID} +STR_1194 :已關閉 +STR_1195 :測試中 +STR_1196 :已開啟 +STR_1197 :故障了 +STR_1198 :毀壞了! +STR_1199 :{COMMA16} 個遊客在這個遊樂設施上 +STR_1200 :{COMMA16} 個遊客在這個遊樂設施上 +STR_1201 :無人在排隊 +STR_1202 :1個遊客在排隊 +STR_1203 :{COMMA16}個遊客在排隊 +STR_1204 :{COMMA16}分鐘的輪候時間 +STR_1205 :{COMMA16}分鐘的輪候時間 +STR_1206 :{WINDOW_COLOUR_2}等待至: +STR_1207 :{WINDOW_COLOUR_2}當另一客列車到達車站後便發車 +STR_1208 :{WINDOW_COLOUR_2}當另一艘小船到達船用月台後便發車 +STR_1209 :{SMALLFONT}{BLACK}選擇發車前是否等候乘客 +STR_1210 :{SMALLFONT}{BLACK}選擇當另一列車/小船到達車站時是否發車 +STR_1211 :{WINDOW_COLOUR_2}最短等待時間: +STR_1212 :{WINDOW_COLOUR_2}最長等待時間: +STR_1213 :{SMALLFONT}{BLACK}選擇發車前最少的等待時長 +STR_1214 :{SMALLFONT}{BLACK}選擇發車前最多的等待時長 +STR_1215 :{WINDOW_COLOUR_2}與鄰近車站同步發車 +STR_1216 :{SMALLFONT}{BLACK}選擇是否與全部鄰近車站同步發車 (以便'競賽') +STR_1217 :{COMMA16}秒 +STR_1218 :{BLACK}{SMALLUP} +STR_1219 :{BLACK}{SMALLDOWN} +STR_1220 :只准卸客 +STR_1221 :尚未建造入口 +STR_1222 :尚未建造出口 +STR_1223 :{SMALLFONT}{BLACK}運輸類遊樂設施 +STR_1224 :{SMALLFONT}{BLACK}溫和類遊樂設施 +STR_1225 :{SMALLFONT}{BLACK}雲霄飛車 +STR_1226 :{SMALLFONT}{BLACK}剌激類遊樂設施 +STR_1227 :{SMALLFONT}{BLACK}水文類遊樂設施 +STR_1228 :{SMALLFONT}{BLACK}商店及攤販 +STR_1229 :列車 +STR_1230 :列車 +STR_1231 :列車 +STR_1232 :列車 +STR_1233 :{COMMA16}列車 +STR_1234 :{COMMA16}列車 +STR_1235 :列車{COMMA16} +STR_1236 :小船 +STR_1237 :小船 +STR_1238 :小船 +STR_1239 :小船 +STR_1240 :{COMMA16}小船 +STR_1241 :{COMMA16}小船 +STR_1242 :小船{COMMA16} +STR_1243 :軌道 +STR_1244 :軌道 +STR_1245 :軌道 +STR_1246 :軌道 +STR_1247 :{COMMA16}軌道 +STR_1248 :{COMMA16}軌道 +STR_1249 :Track {COMMA16} +STR_1250 :船用月台 +STR_1251 :船用月台 +STR_1252 :船用月台 +STR_1253 :船用月台 +STR_1254 :{COMMA16}船用月台 +STR_1255 :{COMMA16}船用月台 +STR_1256 :船用月台{COMMA16} +STR_1257 :車站 +STR_1258 :車站 +STR_1259 :車站 +STR_1260 :車站 +STR_1261 :{COMMA16}車站 +STR_1262 :{COMMA16}車站 +STR_1263 :車站{COMMA16} +STR_1264 :車輛 +STR_1265 :車輛 +STR_1266 :車輛 +STR_1267 :車輛 +STR_1268 :{COMMA16}車輛 +STR_1269 :{COMMA16}車輛 +STR_1270 :車輛{COMMA16} +STR_1271 :建築物 +STR_1272 :建築物 +STR_1273 :建築物 +STR_1274 :建築物 +STR_1275 :{COMMA16}建築物 +STR_1276 :{COMMA16}建築物 +STR_1277 :建築物{COMMA16} +STR_1278 :結構 +STR_1279 :結構 +STR_1280 :結構 +STR_1281 :結構 +STR_1282 :{COMMA16}結構 +STR_1283 :{COMMA16}結構 +STR_1284 :結構{COMMA16} +STR_1285 :船隻 +STR_1286 :船隻 +STR_1287 :船隻 +STR_1288 :船隻 +STR_1289 :{COMMA16}船隻 +STR_1290 :{COMMA16}船隻 +STR_1291 :船隻{COMMA16} +STR_1292 :座艙 +STR_1293 :座艙 +STR_1294 :座艙 +STR_1295 :座艙 +STR_1296 :{COMMA16}個座艙 +STR_1297 :{COMMA16}個座艙 +STR_1298 :座艙{COMMA16} +STR_1299 :摩天輪 +STR_1300 :摩天輪 +STR_1301 :摩天輪 +STR_1302 :摩天輪 +STR_1303 :{COMMA16}個摩天輪 +STR_1304 :{COMMA16}個摩天輪 +STR_1305 :摩天輪{COMMA16} +STR_1306 :飛輪 +STR_1307 :飛輪 +STR_1308 :飛輪 +STR_1309 :飛輪 +STR_1310 :{COMMA16}個飛輪 +STR_1311 :{COMMA16}個飛輪 +STR_1312 :飛輪{COMMA16} +STR_1313 :玩家 +STR_1314 :玩家 +STR_1315 :玩家 +STR_1316 :玩家 +STR_1317 :{COMMA16}位玩家 +STR_1318 :{COMMA16}位玩家 +STR_1319 :玩家{COMMA16} +STR_1320 :場地 +STR_1321 :場地 +STR_1322 :場地 +STR_1323 :場地 +STR_1324 :{COMMA16}個場地 +STR_1325 :{COMMA16}個場地 +STR_1326 :場地{COMMA16} +STR_1327 :{SMALLFONT}{BLACK}將物件旋轉90{DEGREE} +STR_1328 :需要升高或降低土地 +STR_1329 :{WINDOW_COLOUR_2}發車速度: +STR_1330 :{SMALLFONT}{BLACK}離開車站時的最高速度 +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} - 入口{POP16}{POP16} +STR_1336 :{STRINGID} - 車站{POP16}{COMMA16}入口 +STR_1337 :{STRINGID} - 出口{POP16}{POP16} +STR_1338 :{STRINGID} - 車站{POP16}{COMMA16}出口 +STR_1339 :{BLACK}暫無測試結果... +STR_1340 :{WINDOW_COLOUR_2}最高速度: {BLACK}{VELOCITY} +STR_1341 :{WINDOW_COLOUR_2}遊玩時間: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1342 :{DURATION} +STR_1343 :{DURATION} / +STR_1344 :{WINDOW_COLOUR_2}軌道長度: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1345 :{LENGTH} +STR_1346 :{LENGTH} / +STR_1347 :{WINDOW_COLOUR_2}平均速度: {BLACK}{VELOCITY} +STR_1348 :{WINDOW_COLOUR_2}最大正垂直重力: {BLACK}{COMMA2DP32}g +STR_1349 :{WINDOW_COLOUR_2}最大正垂直重力: {OUTLINE}{RED}{COMMA2DP32}g +STR_1350 :{WINDOW_COLOUR_2}最大負垂直重力: {BLACK}{COMMA2DP32}g +STR_1351 :{WINDOW_COLOUR_2}最大負垂直重力: {OUTLINE}{RED}{COMMA2DP32}g +STR_1352 :{WINDOW_COLOUR_2}最大橫向重力: {BLACK}{COMMA2DP32}g +STR_1353 :{WINDOW_COLOUR_2}最大橫向重力: {OUTLINE}{RED}{COMMA2DP32}g +STR_1354 :{WINDOW_COLOUR_2}最高下落高度: {BLACK}{LENGTH} +STR_1355 :{WINDOW_COLOUR_2}下落數量: {BLACK}{COMMA16} +STR_1356 :{WINDOW_COLOUR_2}反轉數量: {BLACK}{COMMA16} +STR_1357 :{WINDOW_COLOUR_2}桿洞數量: {BLACK}{COMMA16} +STR_1358 :{WINDOW_COLOUR_2}總'空中'時間: {BLACK}{COMMA2DP32}秒 +STR_1359 :{WINDOW_COLOUR_2}輪候時間: {BLACK}{COMMA16}分鐘 +STR_1360 :{WINDOW_COLOUR_2}輪候時間: {BLACK}{COMMA16}分鐘 +STR_1361 :不能改變速度... +STR_1362 :不能改變發車速度... +STR_1363 :高度過高無法支撐! +STR_1364 :無法再擴展空中軌道的支撐! +STR_1365 :直線滾翻 (向左) +STR_1366 :直線滾翻 (向右) +STR_1367 :二分之一迴環 +STR_1368 :二分之一螺旋 (向左) +STR_1369 :二分之一螺旋 (向右) +STR_1370 :直線滾翻 (向左) +STR_1371 :直線滾翻 (向右) +STR_1372 :加速式的鏈條坡道 +STR_1373 :巨型的二分之一迴環 (向左) +STR_1374 :巨型的二分之一迴環 (向右) +STR_1375 :向上的傳輸裝置 +STR_1376 :向下的蝕輸裝置 +STR_1377 :橫滾軌道 (向左) +STR_1378 :橫滾軌道 (向右) +STR_1379 :逆向裝置 (向左) +STR_1380 :逆向裝置 (向右) +STR_1381 :彎型的鏈條坡道 (向左) +STR_1382 :彎型的鏈條坡道 (向右) +STR_1383 :四分之一迴環 +STR_1384 :{YELLOW}{STRINGID} +STR_1385 :{SMALLFONT}{BLACK}其他軌道選項 +STR_1386 :特殊軌道... +STR_1387 :不能改變土地類型... +STR_1388 :{OUTLINE}{GREEN}+ {CURRENCY} +STR_1389 :{OUTLINE}{RED}- {CURRENCY} +STR_1390 :{CURRENCY2DP} +STR_1391 :{RED}{CURRENCY2DP} +STR_1392 :{SMALLFONT}{BLACK}觀看遊樂設施/店鋪 +STR_1393 :{SMALLFONT}{BLACK}車卡詳情及選項 +STR_1394 :{SMALLFONT}{BLACK}運作選項 +STR_1395 :{SMALLFONT}{BLACK}維修選項 +STR_1396 :{SMALLFONT}{BLACK}色彩選配選項 +STR_1397 :{SMALLFONT}{BLACK}聲音及音樂選項 +STR_1398 :{SMALLFONT}{BLACK}測試數據及統計資料 +STR_1399 :{SMALLFONT}{BLACK}圖表 +STR_1400 :入口 +STR_1401 :出口 +STR_1402 :{SMALLFONT}{BLACK}建造或移動遊樂設施的入口 +STR_1403 :{SMALLFONT}{BLACK}建造或移動遊樂設施的出口 +STR_1404 :{SMALLFONT}{BLACK}90{DEGREE}旋轉 +STR_1405 :{SMALLFONT}{BLACK}反轉鬼影 +STR_1406 :{SMALLFONT}{BLACK}使用/棄用景物 (如果這個軌道設計附帶景物) +STR_1407 :{WINDOW_COLOUR_2}建造此軌道... +STR_1408 :{WINDOW_COLOUR_2}費用: {BLACK}{CURRENCY} +STR_1409 :入口/出口平台 +STR_1410 :垂直高塔 +STR_1411 :{STRINGID}擋在路上 +STR_1412 :{WINDOW_COLOUR_3}數據記錄並不適合這類型的遊樂設施 +STR_1413 :{WINDOW_COLOUR_3}數據會於{STRINGID}離開{STRINGID}後記錄 +STR_1414 :{SMALLFONT}{BLACK}{DURATION} +STR_1415 :{WINDOW_COLOUR_2}速度 +STR_1416 :{WINDOW_COLOUR_2}高度 +STR_1417 :{WINDOW_COLOUR_2}垂直重力 +STR_1418 :{WINDOW_COLOUR_2}橫向重力 +STR_1419 :{SMALLFONT}{BLACK}{VELOCITY} +STR_1420 :{SMALLFONT}{BLACK}{LENGTH} +STR_1421 :{SMALLFONT}{BLACK}{COMMA16}g +STR_1422 :{SMALLFONT}{BLACK}從{POP16}{STRINGID}記錄資料中 +STR_1423 :{SMALLFONT}{BLACK}輪侯區道路 +STR_1424 :{SMALLFONT}{BLACK}道路 +STR_1425 :道路 +STR_1426 :輪侯區 +STR_1427 :{WINDOW_COLOUR_2}乘客: {BLACK}每小時{COMMA32}個 +STR_1428 :{WINDOW_COLOUR_2}門票價格: +STR_1429 :{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1430 :免費 +STR_1431 :行走中 +STR_1432 :前往{STRINGID}中 +STR_1433 :輪候{STRINGID}中 +STR_1434 :溺水中 +STR_1435 :在{STRINGID}上 +STR_1436 :在{STRINGID}中 +STR_1437 :在{STRINGID}中 +STR_1438 :坐下中 +STR_1439 :(請選擇位置) +STR_1440 :修剪草皮中 +STR_1441 :清掃道路中 +STR_1442 :清空垃圾筒中 +STR_1443 :灌溉花圃中 +STR_1444 :觀看{STRINGID}中 +STR_1445 :觀看{STRINGID}的建造中 +STR_1446 :觀看景物中 +STR_1447 :離開樂園中 +STR_1448 :觀看新遊樂設施的建造過程中 +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 :遊客命名 +STR_1453 :請輸入這位遊客的新姓名: +STR_1454 :不能命名這位遊客... +STR_1455 :不適合的遊客姓名 +STR_1456 :{WINDOW_COLOUR_2}已花費的現金: {BLACK}{CURRENCY2DP} +STR_1457 :{WINDOW_COLOUR_2}在銀包中的現金: {BLACK}{CURRENCY2DP} +STR_1458 :{WINDOW_COLOUR_2}已逗留在樂園的時間: {BLACK}{REALTIME} +STR_1459 :軌道款式 +STR_1460 :{SMALLFONT}{BLACK}'U'型的開放式軌道 +STR_1461 :{SMALLFONT}{BLACK}'O'型的封閉式軌道 +STR_1462 :對於帶有鏈條的坡道來說太陡斜 +STR_1463 :遊客 +STR_1464 :向上盤旋 (小型) +STR_1465 :向上盤旋 (大型) +STR_1466 :向下盤旋 (小型) +STR_1467 :向下盤旋 (大型) +STR_1468 :員工 +STR_1469 :遊樂設施必需要由車站發車後到達車站卸客 +STR_1470 :車站長度不足 +STR_1471 :{WINDOW_COLOUR_2}速度: +STR_1472 :{SMALLFONT}{BLACK}此遊樂設施的速度 +STR_1473 :{WINDOW_COLOUR_2}興奮度: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1474 :{WINDOW_COLOUR_2}興奮度: {BLACK}暫無 +STR_1475 :{WINDOW_COLOUR_2}刺激度: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1476 :{WINDOW_COLOUR_2}刺激度: {BLACK}暫無 +STR_1477 :{WINDOW_COLOUR_2}刺激度: {OUTLINE}{RED}{COMMA2DP32} ({STRINGID}) +STR_1478 :{WINDOW_COLOUR_2}噁心度: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1479 :{WINDOW_COLOUR_2}噁心度: {BLACK}暫無 +STR_1480 :{SMALLFONT}{OPENQUOTES}我已經沒錢去乘坐{STRINGID}了{ENDQUOTES} +STR_1481 :{SMALLFONT}{OPENQUOTES}我已經花光我的錢了{ENDQUOTES} +STR_1482 :{SMALLFONT}{OPENQUOTES}我感到不適{ENDQUOTES} +STR_1483 :{SMALLFONT}{OPENQUOTES}我感到非常不適{ENDQUOTES} +STR_1484 :{SMALLFONT}{OPENQUOTES}我想去試試比{STRINGID}更刺激的遊樂設施{ENDQUOTES} +STR_1485 :{SMALLFONT}{OPENQUOTES}對我來說, {STRINGID}看起來太刺激了{ENDQUOTES} +STR_1486 :{SMALLFONT}{OPENQUOTES}我還未吃/喝完我的{STRINGID}{ENDQUOTES} +STR_1487 :{SMALLFONT}{OPENQUOTES}只是看著{STRINGID}已經讓我感到不適{ENDQUOTES} +STR_1488 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢去乘坐{STRINGID}{ENDQUOTES} +STR_1489 :{SMALLFONT}{OPENQUOTES}我想回家{ENDQUOTES} +STR_1490 :{SMALLFONT}{OPENQUOTES}{STRINGID}真的是超值{ENDQUOTES} +STR_1491 :{SMALLFONT}{OPENQUOTES}我已經擁有{STRINGID}了{ENDQUOTES} +STR_1492 :{SMALLFONT}{OPENQUOTES}我已經不夠錢從{STRINGID}購買東西了{ENDQUOTES} +STR_1493 :{SMALLFONT}{OPENQUOTES}我還未餓{ENDQUOTES} +STR_1494 :{SMALLFONT}{OPENQUOTES}我還未渴{ENDQUOTES} +STR_1495 :{SMALLFONT}{OPENQUOTES}救命! 我快要溺死了!{ENDQUOTES} +STR_1496 :{SMALLFONT}{OPENQUOTES}我迷路了!{ENDQUOTES} +STR_1497 :{SMALLFONT}{OPENQUOTES}{STRINGID}真棒{ENDQUOTES} +STR_1498 :{SMALLFONT}{OPENQUOTES}我輪候{STRINGID}很長時間了{ENDQUOTES} +STR_1499 :{SMALLFONT}{OPENQUOTES}我累了{ENDQUOTES} +STR_1500 :{SMALLFONT}{OPENQUOTES}我餓了{ENDQUOTES} +STR_1501 :{SMALLFONT}{OPENQUOTES}我渴了{ENDQUOTES} +STR_1502 :{SMALLFONT}{OPENQUOTES}我要上廁所{ENDQUOTES} +STR_1503 :{SMALLFONT}{OPENQUOTES}我找不到{STRINGID}{ENDQUOTES} +STR_1504 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢去使用{STRINGID}{ENDQUOTES} +STR_1505 :{SMALLFONT}{OPENQUOTES}我不會在下雨時乘坐{STRINGID}{ENDQUOTES} +STR_1506 :{SMALLFONT}{OPENQUOTES}這裡真多垃圾{ENDQUOTES} +STR_1507 :{SMALLFONT}{OPENQUOTES}我找不到樂園出口{ENDQUOTES} +STR_1508 :{SMALLFONT}{OPENQUOTES}我想從{STRINGID}中下來{ENDQUOTES} +STR_1509 :{SMALLFONT}{OPENQUOTES}我想從{STRINGID}中出來{ENDQUOTES} +STR_1510 :{SMALLFONT}{OPENQUOTES}我不會乘坐{STRINGID} - 它一點都不安全{ENDQUOTES} +STR_1511 :{SMALLFONT}{OPENQUOTES}這道路真是令人噁心{ENDQUOTES} +STR_1512 :{SMALLFONT}{OPENQUOTES}這裡實在太擠迫了{ENDQUOTES} +STR_1513 :{SMALLFONT}{OPENQUOTES}這裡真多被刻意毀壞的設施{ENDQUOTES} +STR_1514 :{SMALLFONT}{OPENQUOTES}這裡的景色真是美不勝收!{ENDQUOTES} +STR_1515 :{SMALLFONT}{OPENQUOTES}這樂園真是又整齊又乾淨{ENDQUOTES} +STR_1516 :{SMALLFONT}{OPENQUOTES}這些跳躍噴泉真棒{ENDQUOTES} +STR_1517 :{SMALLFONT}{OPENQUOTES}這裡播放的音樂挺不錯{ENDQUOTES} +STR_1518 :{SMALLFONT}{OPENQUOTES}這個由{STRINGID}購買的氣球真的是超值{ENDQUOTES} +STR_1519 :{SMALLFONT}{OPENQUOTES}這隻由{STRINGID}購買的毛公仔真的是超值{ENDQUOTES} +STR_1520 :{SMALLFONT}{OPENQUOTES}這份由{STRINGID}購買的樂園地圖真的是超值{ENDQUOTES} +STR_1521 :{SMALLFONT}{OPENQUOTES}這張由{STRINGID}購買的即時照片真的是超值{ENDQUOTES} +STR_1522 :{SMALLFONT}{OPENQUOTES}這把由{STRINGID}購買的雨傘真的是超值{ENDQUOTES} +STR_1523 :{SMALLFONT}{OPENQUOTES}這杯由{STRINGID}購買的飲料真的是超值{ENDQUOTES} +STR_1524 :{SMALLFONT}{OPENQUOTES}這個由{STRINGID}購買的漢堡真的是超值{ENDQUOTES} +STR_1525 :{SMALLFONT}{OPENQUOTES}這客由{STRINGID}購買的薯條真的是超值{ENDQUOTES} +STR_1526 :{SMALLFONT}{OPENQUOTES}這個由{STRINGID}購買的冰淇淋真的是超值{ENDQUOTES} +STR_1527 :{SMALLFONT}{OPENQUOTES}這個由{STRINGID}購買的棉花糖真的是超值{ENDQUOTES} +STR_1528 : +STR_1529 : +STR_1530 : +STR_1531 :{SMALLFONT}{OPENQUOTES}這件由{STRINGID}購買的批薩真的是超值{ENDQUOTES} +STR_1532 : +STR_1533 :{SMALLFONT}{OPENQUOTES}這客由{STRINGID}購買的爆米花真的是超值{ENDQUOTES} +STR_1534 :{SMALLFONT}{OPENQUOTES}這隻由{STRINGID}購買的熱狗真的是超值{ENDQUOTES} +STR_1535 :{SMALLFONT}{OPENQUOTES}這隻由{STRINGID}購買的觸手真的是超值{ENDQUOTES} +STR_1536 :{SMALLFONT}{OPENQUOTES}這頂由{STRINGID}購買的帽子真的是超值{ENDQUOTES} +STR_1537 :{SMALLFONT}{OPENQUOTES}這個由{STRINGID}購買的太妃蘋果糖真的是超值{ENDQUOTES} +STR_1538 :{SMALLFONT}{OPENQUOTES}這件由{STRINGID}購買的T-shirt真的是超值{ENDQUOTES} +STR_1539 :{SMALLFONT}{OPENQUOTES}這件由{STRINGID}購買的甜甜圈真的是超值{ENDQUOTES} +STR_1540 :{SMALLFONT}{OPENQUOTES}這杯由{STRINGID}購買的咖啡真的是超值{ENDQUOTES} +STR_1541 : +STR_1542 :{SMALLFONT}{OPENQUOTES}這客由{STRINGID}購買的炸雞真的是超值{ENDQUOTES} +STR_1543 :{SMALLFONT}{OPENQUOTES}這杯由{STRINGID}購買的檸檬水真的是超值{ENDQUOTES} +STR_1544 : +STR_1545 : +STR_1546 : +STR_1547 : +STR_1548 : +STR_1549 : +STR_1550 :{SMALLFONT}{OPENQUOTES}嘩!{ENDQUOTES} +STR_1551 :{SMALLFONT}{OPENQUOTES}奇怪, 我覺得有人在悄悄地監視我{ENDQUOTES} +STR_1552 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一個氣球{ENDQUOTES} +STR_1553 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一隻毛公仔{ENDQUOTES} +STR_1554 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一份樂園地圖{ENDQUOTES} +STR_1555 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一張即時照片{ENDQUOTES} +STR_1556 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一把雨傘{ENDQUOTES} +STR_1557 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一杯飲料{ENDQUOTES} +STR_1558 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一個漢堡{ENDQUOTES} +STR_1559 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一客薯條{ENDQUOTES} +STR_1560 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一個冰淇淋{ENDQUOTES} +STR_1561 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一球棉花糖{ENDQUOTES} +STR_1562 : +STR_1563 : +STR_1564 : +STR_1565 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一件批薩{ENDQUOTES} +STR_1566 : +STR_1567 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一客爆米花{ENDQUOTES} +STR_1568 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一隻熱狗{ENDQUOTES} +STR_1569 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一隻觸手{ENDQUOTES} +STR_1570 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一頂帽子{ENDQUOTES} +STR_1571 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一個太妃蘋果糖{ENDQUOTES} +STR_1572 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一件T-shirt{ENDQUOTES} +STR_1573 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一件甜甜圈{ENDQUOTES} +STR_1574 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一杯咖啡{ENDQUOTES} +STR_1575 : +STR_1576 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一客炸雞{ENDQUOTES} +STR_1577 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一杯檸檬水{ENDQUOTES} +STR_1578 : +STR_1579 : +STR_1580 : +STR_1581 : +STR_1582 : +STR_1583 : +STR_1584 :{SMALLFONT}{OPENQUOTES}這張由{STRINGID}購買的即時照片真的是超值{ENDQUOTES} +STR_1585 :{SMALLFONT}{OPENQUOTES}這張由{STRINGID}購買的即時照片真的是超值{ENDQUOTES} +STR_1586 :{SMALLFONT}{OPENQUOTES}這張由{STRINGID}購買的即時照片真的是超值{ENDQUOTES} +STR_1587 :{SMALLFONT}{OPENQUOTES}這件由{STRINGID}購買的椒鹽卷餅真的是超值{ENDQUOTES} +STR_1588 :{SMALLFONT}{OPENQUOTES}這杯由{STRINGID}購買的熱巧克力真的是超值{ENDQUOTES} +STR_1589 :{SMALLFONT}{OPENQUOTES}這杯由{STRINGID}購買的冰紅茶真的是超值{ENDQUOTES} +STR_1590 :{SMALLFONT}{OPENQUOTES}這個由{STRINGID}購買的漏斗蛋糕真的是超值{ENDQUOTES} +STR_1591 :{SMALLFONT}{OPENQUOTES}這副由{STRINGID}購買的太陽眼鏡真的是超值{ENDQUOTES} +STR_1592 :{SMALLFONT}{OPENQUOTES}這份由{STRINGID}購買的牛肉麵真的是超值{ENDQUOTES} +STR_1593 :{SMALLFONT}{OPENQUOTES}這份由{STRINGID}購買的炒米粉真的是超值{ENDQUOTES} +STR_1594 :{SMALLFONT}{OPENQUOTES}這客由{STRINGID}購買的湯雲吞真的是超值{ENDQUOTES} +STR_1595 :{SMALLFONT}{OPENQUOTES}這客由{STRINGID}購買的肉丸湯真的是超值{ENDQUOTES} +STR_1596 :{SMALLFONT}{OPENQUOTES}這杯由{STRINGID}購買的果汁真的是超值{ENDQUOTES} +STR_1597 :{SMALLFONT}{OPENQUOTES}這杯由{STRINGID}購買的豆漿真的是超值{ENDQUOTES} +STR_1598 :{SMALLFONT}{OPENQUOTES}這杯由{STRINGID}購買的水正果真的是超值{ENDQUOTES} +STR_1599 :{SMALLFONT}{OPENQUOTES}這件由{STRINGID}購買的潛艇三文治真的是超值{ENDQUOTES} +STR_1600 :{SMALLFONT}{OPENQUOTES}這件由{STRINGID}購買的曲奇真的是超值{ENDQUOTES} +STR_1601 : +STR_1602 : +STR_1603 : +STR_1604 :{SMALLFONT}{OPENQUOTES}這條由{STRINGID}購買的烤香腸真的是超值{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}我不會花這麼多錢在{STRINGID}購買一張即時照片{ENDQUOTES} +STR_1617 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一張即時照片{ENDQUOTES} +STR_1618 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一張即時照片{ENDQUOTES} +STR_1619 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一件椒鹽卷餅{ENDQUOTES} +STR_1620 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一杯熱巧克力{ENDQUOTES} +STR_1621 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一杯冰紅茶{ENDQUOTES} +STR_1622 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一個漏斗蛋糕{ENDQUOTES} +STR_1623 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一副太陽眼鏡{ENDQUOTES} +STR_1624 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一份牛肉麵{ENDQUOTES} +STR_1625 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一份炒米粉{ENDQUOTES} +STR_1626 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一客湯雲吞{ENDQUOTES} +STR_1627 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一客肉丸湯{ENDQUOTES} +STR_1628 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一杯果汁{ENDQUOTES} +STR_1629 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一杯豆漿{ENDQUOTES} +STR_1630 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一杯水正果{ENDQUOTES} +STR_1631 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一件潛艇三文治{ENDQUOTES} +STR_1632 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{STRINGID}購買一件曲奇{ENDQUOTES} +STR_1633 : +STR_1634 : +STR_1635 : +STR_1636 :{SMALLFONT}{OPENQUOTES}我不會花這麼多錢在{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}救命! 放我下去!{ENDQUOTES} +STR_1649 :{SMALLFONT}{OPENQUOTES}我花光了我身上的錢了!{ENDQUOTES} +STR_1650 :{SMALLFONT}{OPENQUOTES}嘩! 嶄新的遊樂設施在建造中呢!{ENDQUOTES} +STR_1651 :{SMALLFONT}{OPENQUOTES}這個遊樂設施不錯喔! 只是比起Phoneix還是差一截呢...{ENDQUOTES} +STR_1652 :{SMALLFONT}{OPENQUOTES}我好興奮 - 因為這是Intamin創造的遊樂設施!{ENDQUOTES} +STR_1653 :{SMALLFONT}{OPENQUOTES}...然而, 現在我們已經在{STRINGID}之上!{ENDQUOTES} +STR_1654 :{WINDOW_COLOUR_2}最近的想法: +STR_1655 :{SMALLFONT}{BLACK}在地上建造道路 +STR_1656 :{SMALLFONT}{BLACK}建造橋樑或隧道 +STR_1657 :{WINDOW_COLOUR_2}遊樂設施偏好 +STR_1658 :{WINDOW_COLOUR_2}刺激度: {BLACK}少於{COMMA16} +STR_1659 :{WINDOW_COLOUR_2}刺激度: {BLACK}介乎{COMMA16}及{COMMA16}之間 +STR_1660 :{WINDOW_COLOUR_2}刺激度: {BLACK}高於{COMMA16} +STR_1661 :{WINDOW_COLOUR_2}噁心忍受程度: {BLACK}{STRINGID} +STR_1662 :{WINDOW_COLOUR_2}快樂度: +STR_1663 :{WINDOW_COLOUR_2}噁心度: +STR_1664 :{WINDOW_COLOUR_2}體力: +STR_1665 :{WINDOW_COLOUR_2}飢餓度: +STR_1666 :{WINDOW_COLOUR_2}口渴度: +STR_1667 :{WINDOW_COLOUR_2}如廁度: +STR_1668 :{WINDOW_COLOUR_2}滿意度: {BLACK}未知 +STR_1669 :{WINDOW_COLOUR_2}滿意度: {BLACK}{COMMA16}% +STR_1670 :{WINDOW_COLOUR_2}總乘客數: {BLACK}{COMMA32} +STR_1671 :{WINDOW_COLOUR_2}總利潤: {BLACK}{CURRENCY2DP} +STR_1672 :煞車裝置 +STR_1673 :控制旋轉開/關軌道 +STR_1674 :煞車速度 +STR_1675 :{POP16}{VELOCITY} +STR_1676 :{SMALLFONT}{BLACK}設置煞車速度限制 +STR_1677 :{WINDOW_COLOUR_2}受歡迎度: {BLACK}未知 +STR_1678 :{WINDOW_COLOUR_2}受歡迎度: {BLACK}{COMMA16}% +STR_1679 :向上盤旋 (向左) +STR_1680 :向上盤旋 (向右) +STR_1681 :向下盤旋 (向左) +STR_1682 :向下盤旋 (向右) +STR_1683 :2 x 2地基 +STR_1684 :4 x 4地基 +STR_1685 :2 x 4地基 +STR_1686 :5 x 1地基 +STR_1687 :水濺軌道 +STR_1688 :4 x 1地基 +STR_1689 :區域煞車裝置 +STR_1690 :{WINDOW_COLOUR_2}{STRINGID}{NEWLINE}{BLACK}{STRINGID} +STR_1691 :{WINDOW_COLOUR_2} 費用: {BLACK}{CURRENCY} +STR_1692 :{WINDOW_COLOUR_2} 費用: {BLACK}{CURRENCY}起 +STR_1693 :{SMALLFONT}{BLACK}遊客 +STR_1694 :{SMALLFONT}{BLACK}員工 +STR_1695 :{SMALLFONT}{BLACK}收入和支出 +STR_1696 :{SMALLFONT}{BLACK}顧客資訊 +STR_1697 :不能在輪侯區放置此物件 +STR_1698 :只能在輪侯區放置此物件 +STR_1699 :遊戲中已有太多人物 +STR_1700 :僱用新的清潔工人 +STR_1701 :僱用新的維修人員 +STR_1702 :僱用新的安全警衛 +STR_1703 :僱用新的表演人員 +STR_1704 :不能僱用新員工... +STR_1705 :{SMALLFONT}{BLACK}解僱這位員工 +STR_1706 :{SMALLFONT}{BLACK}移動這個人物到新的位置 +STR_1707 :遊戲中已有太多員工 +STR_1708 :{SMALLFONT}{BLACK}設置這位員工的巡邏位置 +STR_1709 :解僱員工 +STR_1710 :確定 +STR_1711 :{WINDOW_COLOUR_1}你確定要解僱{STRINGID}嗎? +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_1716 :不適合的樂園名稱 +STR_1717 :不能重命名樂園... +STR_1718 :樂園名稱 +STR_1719 :請輸入樂園名稱: +STR_1720 :{SMALLFONT}{BLACK}命名樂園 +STR_1721 :樂園已關閉 +STR_1722 :樂園開放中 +STR_1723 :不能開放樂園... +STR_1724 :不能關閉樂園... +STR_1725 :不能購買土地... +STR_1726 :土地不供購買! +STR_1727 :建造權不供購買! +STR_1728 :不能在此購買建造權... +STR_1729 :土地並非由樂園所擁有! +STR_1730 :{RED}已關閉 - - +STR_1731 :{WHITE}{STRINGID} - - +STR_1732 :建造 +STR_1733 :模式 +STR_1734 :{WINDOW_COLOUR_2}圈數: +STR_1735 :{SMALLFONT}{BLACK}每次循環的圈數 +STR_1736 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1737 :{COMMA16} +STR_1738 :不能改變圈數... +STR_1739 :此賽事由遊客{INT32}勝出 +STR_1740 :此賽事由{STRINGID}勝出 +STR_1741 :尚未建造! +STR_1742 :{WINDOW_COLOUR_2}設施的最大載客量: +STR_1743 :{SMALLFONT}{BLACK}同時間遊樂設施上最多可接受的乘客數量 +STR_1744 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1745 :{COMMA16} +STR_1746 :不能改變... +STR_1747 :{WINDOW_COLOUR_2}遊玩時間限制: +STR_1748 :{SMALLFONT}{BLACK}此遊樂設施的遊玩時間限制 +STR_1749 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{DURATION} +STR_1750 :{DURATION} +STR_1751 :不能改變此遊樂設施的遊玩時間限制... +STR_1752 :{SMALLFONT}{BLACK}列出樂園內每個遊客 +STR_1753 :{SMALLFONT}{BLACK}列出樂園內遊客的總匯 +STR_1754 :{BLACK}{COMMA16}名遊客 +STR_1755 :{BLACK}{COMMA16}名遊客 +STR_1756 :{WINDOW_COLOUR_2}門票價格: +STR_1757 :{WINDOW_COLOUR_2}可靠度: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1758 :{SMALLFONT}{BLACK}建造模式 +STR_1759 :{SMALLFONT}{BLACK}移動模式 +STR_1760 :{SMALLFONT}{BLACK}填補模式 +STR_1761 :{SMALLFONT}{BLACK}以此方向建造迷宮 +STR_1762 :瀑布 +STR_1763 :急流 +STR_1764 :漩渦 +STR_1765 :即時拍照區域 +STR_1766 :倒轉轉木裝置 +STR_1767 :不斷旋轉的隧道 +STR_1768 :不能改變搖擺次數... +STR_1769 :{WINDOW_COLOUR_2}搖擺次數: +STR_1770 :{SMALLFONT}{BLACK}完全搖擺的次數 +STR_1771 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1772 :{COMMA16} +STR_1773 :每個遊樂設施只可建造一個即時照相區域 +STR_1774 :每個遊樂設施只可建造一個纜索坡道 +STR_1775 :關閉 +STR_1776 :開啟 +STR_1777 :{WINDOW_COLOUR_2}音樂 +STR_1778 :{STRINGID} - - +STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} 熊貓服裝 +STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} 老虎服裝 +STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} 大象服裝 +STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} 羅馬服裝 +STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} 哥斯拉服裝 +STR_1784 :{INLINE_SPRITE}{03}{20}{00}{00} 雪人服裝 +STR_1785 :{INLINE_SPRITE}{04}{20}{00}{00} 騎士服裝 +STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} 太空人服裝 +STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} 土匪服裝 +STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} 警長服裝 +STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} 海盜服裝 +STR_1790 :{SMALLFONT}{BLACK}選擇這種員工的制服顏色 +STR_1791 :{WINDOW_COLOUR_2}制服的顏色: +STR_1792 :回應{STRINGID}的故障呼叫中 +STR_1793 :前往到{STRINGID}作出檢查中 +STR_1794 :修理{STRINGID}中 +STR_1795 :回應電台呼叫中 +STR_1796 :已經故障並需要修復 +STR_1797 :不能在這個遊樂設施中更改這個選項 +STR_1798 :漩渦 +STR_1799 :{POP16}{POP16}{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1800 :保險裝置跳掣 +STR_1801 :保護裝置卡住不能開啟 +STR_1802 :保護裝置卡住不能關閉 +STR_1803 :車門卡住不能開啟 +STR_1804 :車門卡住不能關閉 +STR_1805 :車輛失靈 +STR_1806 :煞車裝置故障 +STR_1807 :控制裝置故障 +STR_1808 :{WINDOW_COLOUR_2}上次故障原因: {BLACK}{STRINGID} +STR_1809 :{WINDOW_COLOUR_2}今次故障原因: {OUTLINE}{RED}{STRINGID} +STR_1810 :{WINDOW_COLOUR_2}攜帶中: +STR_1811 :不能建造於此... +STR_1812 :{SMALLFONT}{BLACK}{STRINGID} +STR_1813 :其他物件 +STR_1814 :動作 +STR_1815 :想法 +STR_1816 :{SMALLFONT}{BLACK}選擇遊客列表中要顯示的資訊類別 +STR_1817 :({COMMA16}) +STR_1818 :{WINDOW_COLOUR_2}所有遊客 +STR_1819 :{WINDOW_COLOUR_2}所有遊客 (總匯) +STR_1820 :{WINDOW_COLOUR_2}{STRINGID}的遊客 +STR_1821 :{WINDOW_COLOUR_2}在想{STRINGID}的遊客 +STR_1822 :{WINDOW_COLOUR_2}在想{POP16}{STRINGID}的遊客 +STR_1823 :{SMALLFONT}{BLACK}顯示遊客對此遊樂設施/店面的想法 +STR_1824 :{SMALLFONT}{BLACK}顯示在使用此遊樂設施/店面的遊客 +STR_1825 :{SMALLFONT}{BLACK}顯示在輪候此遊樂設施/店面的遊客 +STR_1826 :狀態 +STR_1827 :人氣度 +STR_1828 :滿意度 +STR_1829 :利潤 +STR_1830 :輪候隊列長度 +STR_1831 :輪候時間 +STR_1832 :可靠度 +STR_1833 :故障度 +STR_1834 :遊客最愛的遊樂設施 +STR_1835 :人氣度: 未知 +STR_1836 :人氣度: {COMMA16}% +STR_1837 :滿意度: 未知 +STR_1838 :滿意度: {COMMA16}% +STR_1839 :可靠度: {COMMA16}% +STR_1840 :故障度: {COMMA16}% +STR_1841 :利潤: 每小時{CURRENCY2DP} +STR_1842 :{COMMA16}遊客最愛的遊樂設施 +STR_1843 :{COMMA16}遊客最愛的遊樂設施 +STR_1844 :{SMALLFONT}{BLACK}選擇要在遊樂設施/店面列表中顯示的資訊類別 +STR_1845 :{MONTHYEAR} +STR_1846 :{COMMA16}遊客 +STR_1847 :{INLINE_SPRITE}{11}{20}{00}{00}{COMMA16}遊客 +STR_1848 :{INLINE_SPRITE}{10}{20}{00}{00}{COMMA16}遊客 +STR_1849 :{WINDOW_COLOUR_2}播放音樂 +STR_1850 :{SMALLFONT}{BLACK}選擇此遊樂設施播放音樂與否 +STR_1851 :{WINDOW_COLOUR_2}運作成本: {BLACK}每小時{CURRENCY2DP} +STR_1852 :{WINDOW_COLOUR_2}運作成本: {BLACK}未知 +STR_1853 :{WINDOW_COLOUR_2}落成年份: {BLACK}今年 +STR_1854 :{WINDOW_COLOUR_2}落成年份: {BLACK}去年 +STR_1855 :{WINDOW_COLOUR_2}落成年份: {BLACK}{COMMA16}年前 +STR_1856 :{WINDOW_COLOUR_2}每件產品售出的利潤: {BLACK}{CURRENCY2DP} +STR_1857 :{WINDOW_COLOUR_2}每件產品售出的虧損: {BLACK}{CURRENCY2DP} +STR_1858 :{WINDOW_COLOUR_2}成本: {BLACK}每個月{CURRENCY2DP} +STR_1859 :個清潔工人 +STR_1860 :個維修人員 +STR_1861 :個安全警衛 +STR_1862 :個表演人員 +STR_1863 :個清潔工人 +STR_1864 :個維修人員 +STR_1865 :個安全警衛 +STR_1866 :個表演人員 +STR_1867 :{BLACK}{COMMA16} {STRINGID} +STR_1868 :不能改變旋轉次數... +STR_1869 :{WINDOW_COLOUR_2}旋轉次數: +STR_1870 :{SMALLFONT}{BLACK}完整旋轉次數 +STR_1871 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1872 :{COMMA16} +STR_1873 :{WINDOW_COLOUR_2}收入: {BLACK}每小時{CURRENCY2DP} +STR_1874 :{WINDOW_COLOUR_2}營利: {BLACK}每小時{CURRENCY2DP} +STR_1875 :{BLACK} {SPRITE}{BLACK} {STRINGID} +STR_1876 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{251}{19}{00}{00}檢查遊樂設施 +STR_1877 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{252}{19}{00}{00}修理遊樂設施 +STR_1878 :{WINDOW_COLOUR_2}檢查時距: +STR_1879 :每10分鐘 +STR_1880 :每20分鐘 +STR_1881 :每30分鐘 +STR_1882 :每45分鐘 +STR_1883 :每小時 +STR_1884 :每2小時 +STR_1885 :從不 +STR_1886 :檢查{STRINGID}中 +STR_1887 :{WINDOW_COLOUR_2}上次檢查時間: {BLACK}{COMMA16}分鐘前 +STR_1888 :{WINDOW_COLOUR_2}上次檢查時間: {BLACK}多於4小時 +STR_1889 :{WINDOW_COLOUR_2}故障度: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1890 :{SMALLFONT}{BLACK}選擇維修人員檢查此遊樂設施的時距 +STR_1891 :在樂園裡暫未有{STRINGID}! +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 : +STR_1893 : +STR_1894 :{WINDOW_COLOUR_2}售出{STRINGID}: {BLACK}{COMMA32} +STR_1895 :{SMALLFONT}{BLACK}建造新的遊樂設施/店鋪 +STR_1896 :{WINDOW_COLOUR_2}支出/收入 +STR_1897 :{WINDOW_COLOUR_2}建造遊樂設施 +STR_1898 :{WINDOW_COLOUR_2}運行遊樂設施費用 +STR_1899 :{WINDOW_COLOUR_2}購買土地 +STR_1900 :{WINDOW_COLOUR_2}調整地形 +STR_1901 :{WINDOW_COLOUR_2}樂園入場門票 +STR_1902 :{WINDOW_COLOUR_2}遊樂設施門票 +STR_1903 :{WINDOW_COLOUR_2}其他商品銷售額 +STR_1904 :{WINDOW_COLOUR_2}其他商品進貨 +STR_1905 :{WINDOW_COLOUR_2}食物/飲料銷售額 +STR_1906 :{WINDOW_COLOUR_2}食物/飲料進貨 +STR_1907 :{WINDOW_COLOUR_2}員工薪金 +STR_1908 :{WINDOW_COLOUR_2}營銷費用 +STR_1909 :{WINDOW_COLOUR_2}研發費用 +STR_1910 :{WINDOW_COLOUR_2}貸款利息 +STR_1911 :{BLACK} 每年{COMMA16}% +STR_1912 :{MONTH} +STR_1913 :{BLACK}+{CURRENCY2DP} +STR_1914 :{BLACK}{CURRENCY2DP} +STR_1915 :{RED}{CURRENCY2DP} +STR_1916 :{WINDOW_COLOUR_2}貸款: +STR_1917 :{POP16}{POP16}{POP16}{CURRENCY} +STR_1918 :不能再借貸更多錢! +STR_1919 :沒有足夠的現金! +STR_1920 :不能償還貸款! +STR_1921 :{SMALLFONT}{BLACK}開新遊戲 +STR_1922 :{SMALLFONT}{BLACK}繼續遊玩存檔 +STR_1923 :{SMALLFONT}{BLACK}開始教學 +STR_1924 :{SMALLFONT}{BLACK}退出遊戲 +STR_1925 :不能放置人物於此... +STR_1926 :{SMALLFONT} +STR_1927 :{YELLOW}{STRINGID}發生故障了 +STR_1928 :{RED}{STRINGID}毀壞了! +STR_1929 :{RED}{STRINGID}依然未修復好{NEWLINE}請檢查維修人員位置所在, 或考慮以更好的方法管理他們 +STR_1930 :{SMALLFONT}{BLACK}開啟/關閉這位遊客的追蹤資訊 - (假若開啟追蹤, 這位遊客的行動將會報告於最近消息裡) +STR_1931 :{STRINGID}已在輪候{STRINGID} +STR_1932 :{STRINGID}已在{STRINGID}上 +STR_1933 :{STRINGID}已在{STRINGID}中 +STR_1934 :{STRINGID}已離開{STRINGID} +STR_1935 :{STRINGID}已離開樂園 +STR_1936 :{STRINGID}已購買{STRINGID} +STR_1937 :{SMALLFONT}{BLACK}顯示關於這個訊息標題的資訊 +STR_1938 :{SMALLFONT}{BLACK}顯示遊客所視 +STR_1939 :{SMALLFONT}{BLACK}顯示員工所視 +STR_1940 :{SMALLFONT}{BLACK}顯示這位遊客的快樂度, 體力, 飢餓度等指標 +STR_1941 :{SMALLFONT}{BLACK}顯示這位遊客乘坐了甚麼遊樂設施 +STR_1942 :{SMALLFONT}{BLACK}顯示這位遊客的財政狀況 +STR_1943 :{SMALLFONT}{BLACK}顯示這位遊客的最近想法 +STR_1944 :{SMALLFONT}{BLACK}顯示這位遊客攜帶中的物件 +STR_1945 :{SMALLFONT}{BLACK}顯示有關這位員工的排序及選項 +STR_1946 :{SMALLFONT}{BLACK}選擇這位表演人員的服裝 +STR_1947 :{SMALLFONT}{BLACK}顯示已分配被巡邏的區域, 以及將最近的員工定位 +STR_1948 :{SMALLFONT}{BLACK}僱用這個類別的新員工 +STR_1949 :財政概要 +STR_1950 :財政圖表 +STR_1951 :樂園價值圖表 +STR_1952 :營利圖表 +STR_1953 :營銷計劃 +STR_1954 :研發資金 +STR_1955 :{WINDOW_COLOUR_2}圈數: +STR_1956 :{SMALLFONT}{BLACK}每次運轉遊樂設施的圈數 +STR_1957 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1958 :{COMMA16} +STR_1959 :不能改變圈數... +STR_1960 :{WINDOW_COLOUR_2}氣球價格: +STR_1961 :{WINDOW_COLOUR_2}毛公仔價格: +STR_1962 :{WINDOW_COLOUR_2}樂園地圖價格: +STR_1963 :{WINDOW_COLOUR_2}即時照片價格: +STR_1964 :{WINDOW_COLOUR_2}雨傘價格: +STR_1965 :{WINDOW_COLOUR_2}飲料價格: +STR_1966 :{WINDOW_COLOUR_2}漢堡價格: +STR_1967 :{WINDOW_COLOUR_2}薯條價格: +STR_1968 :{WINDOW_COLOUR_2}冰淇淋價格: +STR_1969 :{WINDOW_COLOUR_2}棉花糖價格: +STR_1970 :{WINDOW_COLOUR_2} +STR_1971 :{WINDOW_COLOUR_2} +STR_1972 :{WINDOW_COLOUR_2} +STR_1973 :{WINDOW_COLOUR_2}批薩價格: +STR_1974 :{WINDOW_COLOUR_2} +STR_1975 :{WINDOW_COLOUR_2}爆米花價格: +STR_1976 :{WINDOW_COLOUR_2}熱狗價格: +STR_1977 :{WINDOW_COLOUR_2}觸手價格: +STR_1978 :{WINDOW_COLOUR_2}帽子價格: +STR_1979 :{WINDOW_COLOUR_2}太妃蘋果糖價格: +STR_1980 :{WINDOW_COLOUR_2}T-Shirt價格: +STR_1981 :{WINDOW_COLOUR_2}甜甜圈價格: +STR_1982 :{WINDOW_COLOUR_2}咖啡價格: +STR_1983 :{WINDOW_COLOUR_2} +STR_1984 :{WINDOW_COLOUR_2}炸雞價格: +STR_1985 :{WINDOW_COLOUR_2}檸檬水價格: +STR_1986 :{WINDOW_COLOUR_2} +STR_1987 :{WINDOW_COLOUR_2} +STR_1988 :氣球 +STR_1989 :毛公仔 +STR_1990 :樂園地圖 +STR_1991 :即時照片 +STR_1992 :雨傘 +STR_1993 :飲料 +STR_1994 :漢堡 +STR_1995 :薯條 +STR_1996 :冰淇淋 +STR_1997 :棉花糖 +STR_1998 :空罐子 +STR_1999 :垃圾 +STR_2000 :空漢堡盒子 +STR_2001 :批薩 +STR_2002 :優惠卷 +STR_2003 :爆米花 +STR_2004 :熱狗 +STR_2005 :觸手 +STR_2006 :帽子 +STR_2007 :太妃蘋果糖 +STR_2008 :T-Shirt +STR_2009 :甜甜圈 +STR_2010 :咖啡 +STR_2011 :空杯子 +STR_2012 :炸雞 +STR_2013 :檸檬水 +STR_2014 :空盒子 +STR_2015 :空瓶子 +STR_2016 :氣球 +STR_2017 :毛公仔 +STR_2018 :樂園地圖 +STR_2019 :即時照片 +STR_2020 :雨傘 +STR_2021 :飲料 +STR_2022 :漢堡 +STR_2023 :薯條 +STR_2024 :冰淇淋 +STR_2025 :棉花糖 +STR_2026 :空罐子 +STR_2027 :垃圾 +STR_2028 :空漢堡盒子 +STR_2029 :批薩 +STR_2030 :優惠卷 +STR_2031 :爆米花 +STR_2032 :熱狗 +STR_2033 :觸手 +STR_2034 :帽子 +STR_2035 :太妃蘋果糖 +STR_2036 :T-Shirt +STR_2037 :甜甜圈 +STR_2038 :咖啡 +STR_2039 :空杯子 +STR_2040 :炸雞 +STR_2041 :檸檬水 +STR_2042 :空盒子 +STR_2043 :空瓶子 +STR_2044 :一個氣球 +STR_2045 :一隻毛公仔 +STR_2046 :一份樂園地圖 +STR_2047 :一張即時照片 +STR_2048 :一把雨傘 +STR_2049 :一杯飲料 +STR_2050 :一個漢堡 +STR_2051 :一客薯條 +STR_2052 :一個冰淇淋 +STR_2053 :一球棉花糖 +STR_2054 :一個空罐子 +STR_2055 :一些垃圾 +STR_2056 :一個空漢堡盒子 +STR_2057 :一件批薩 +STR_2058 :一張優惠卷 +STR_2059 :一客爆米花 +STR_2060 :一隻熱狗 +STR_2061 :一隻觸手 +STR_2062 :一頂帽子 +STR_2063 :一個太妃蘋果糖 +STR_2064 :一件T-shirt +STR_2065 :一件甜甜圈 +STR_2066 :一杯咖啡 +STR_2067 :一個空杯子 +STR_2068 :一客炸雞 +STR_2069 :一杯檸檬水 +STR_2070 :一個空盒子 +STR_2071 :一個空瓶子 +STR_2072 :{OPENQUOTES}{STRINGID}{ENDQUOTES}氣球 +STR_2073 :{OPENQUOTES}{STRINGID}{ENDQUOTES}毛公仔 +STR_2074 :{STRINGID}的地圖 +STR_2075 :{STRINGID}的即時照片 +STR_2076 :{OPENQUOTES}{STRINGID}{ENDQUOTES}雨傘 +STR_2077 :飲料 +STR_2078 :漢堡 +STR_2079 :薯條 +STR_2080 :冰淇淋 +STR_2081 :棉花糖 +STR_2082 :空罐子 +STR_2083 :垃圾 +STR_2084 :空漢堡盒子 +STR_2085 :批薩 +STR_2086 :{STRINGID}的優惠卷 +STR_2087 :爆米花 +STR_2088 :熱狗 +STR_2089 :觸手 +STR_2090 :{OPENQUOTES}{STRINGID}{ENDQUOTES}帽子 +STR_2091 :太妃蘋果糖 +STR_2092 :{OPENQUOTES}{STRINGID}{ENDQUOTES} T-Shirt +STR_2093 :甜甜圈 +STR_2094 :咖啡 +STR_2095 :空杯子 +STR_2096 :炸雞 +STR_2097 :檸檬水 +STR_2098 :空盒子 +STR_2099 :空瓶子 +STR_2100 :{WINDOW_COLOUR_2}即時照片價格: +STR_2101 :{WINDOW_COLOUR_2}即時照片價格: +STR_2102 :{WINDOW_COLOUR_2}即時照片價格: +STR_2103 :{WINDOW_COLOUR_2}椒鹽卷餅價格: +STR_2104 :{WINDOW_COLOUR_2}熱巧克力價格: +STR_2105 :{WINDOW_COLOUR_2}冰紅茶價格: +STR_2106 :{WINDOW_COLOUR_2}漏斗蛋糕價格: +STR_2107 :{WINDOW_COLOUR_2}太陽眼鏡價格: +STR_2108 :{WINDOW_COLOUR_2}牛肉麵價格: +STR_2109 :{WINDOW_COLOUR_2}炒米粉價格: +STR_2110 :{WINDOW_COLOUR_2}湯雲吞價格: +STR_2111 :{WINDOW_COLOUR_2}肉丸湯價格: +STR_2112 :{WINDOW_COLOUR_2}果汁價格: +STR_2113 :{WINDOW_COLOUR_2}豆漿價格: +STR_2114 :{WINDOW_COLOUR_2}水正果價格: +STR_2115 :{WINDOW_COLOUR_2}潛艇三文治價格: +STR_2116 :{WINDOW_COLOUR_2}曲奇價格: +STR_2117 :{WINDOW_COLOUR_2} +STR_2118 :{WINDOW_COLOUR_2} +STR_2119 :{WINDOW_COLOUR_2} +STR_2120 :{WINDOW_COLOUR_2}烤香腸價格: +STR_2121 :{WINDOW_COLOUR_2} +STR_2122 :即時照片 +STR_2123 :即時照片 +STR_2124 :即時照片 +STR_2125 :椒鹽卷餅 +STR_2126 :熱巧克力 +STR_2127 :冰紅茶 +STR_2128 :漏斗蛋糕 +STR_2129 :太陽眼鏡 +STR_2130 :牛肉麵 +STR_2131 :炒米粉 +STR_2132 :湯雲吞 +STR_2133 :肉丸湯 +STR_2134 :果汁 +STR_2135 :豆漿 +STR_2136 :水正果 +STR_2137 :潛艇三文治 +STR_2138 :曲奇 +STR_2139 :空碗子 +STR_2140 :空的飲品紙包裝 +STR_2141 :空果汁杯子 +STR_2142 :烤香腸 +STR_2143 :空碗子 +STR_2144 :即時照片 +STR_2145 :即時照片 +STR_2146 :即時照片 +STR_2147 :椒鹽卷餅 +STR_2148 :熱巧克力 +STR_2149 :冰紅茶 +STR_2150 :漏斗蛋糕 +STR_2151 :太陽眼鏡 +STR_2152 :牛肉麵 +STR_2153 :炒米粉 +STR_2154 :湯雲吞 +STR_2155 :肉丸湯 +STR_2156 :果汁 +STR_2157 :豆漿 +STR_2158 :水正果 +STR_2159 :潛艇三文治 +STR_2160 :曲奇 +STR_2161 :空碗子 +STR_2162 :空的飲品紙包裝 +STR_2163 :空果汁杯子 +STR_2164 :烤香腸 +STR_2165 :空碗子 +STR_2166 :一張即時照片 +STR_2167 :一張即時照片 +STR_2168 :一張即時照片 +STR_2169 :一件椒鹽卷餅 +STR_2170 :一杯熱巧克力 +STR_2171 :一杯冰紅茶 +STR_2172 :一個漏斗蛋糕 +STR_2173 :一副太陽眼鏡 +STR_2174 :一份牛肉麵 +STR_2175 :一份炒米粉 +STR_2176 :一客湯雲吞 +STR_2177 :一客肉丸湯 +STR_2178 :一杯果汁 +STR_2179 :一杯豆漿 +STR_2180 :一杯水正果 +STR_2181 :一件潛艇三文治 +STR_2182 :一件曲奇 +STR_2183 :一個空碗子 +STR_2184 :一盒空的飲品紙包裝 +STR_2185 :一個空果汁杯子 +STR_2186 :一條烤香腸 +STR_2187 :一個空碗子 +STR_2188 :{STRINGID}的即時照片 +STR_2189 :{STRINGID}的即時照片 +STR_2190 :{STRINGID}的即時照片 +STR_2191 :椒鹽卷餅 +STR_2192 :熱巧克力 +STR_2193 :冰紅茶 +STR_2194 :漏斗蛋糕 +STR_2195 :太陽眼鏡 +STR_2196 :牛肉麵 +STR_2197 :炒米粉 +STR_2198 :湯雲吞 +STR_2199 :肉丸湯 +STR_2200 :果汁 +STR_2201 :豆漿 +STR_2202 :水正果 +STR_2203 :潛艇三文治 +STR_2204 :曲奇 +STR_2205 :空碗子 +STR_2206 :空的飲品紙包裝 +STR_2207 :空果汁杯子 +STR_2208 :烤香腸 +STR_2209 :空碗子 +STR_2210 :{SMALLFONT}{BLACK}列出樂園內的清潔工人 +STR_2211 :{SMALLFONT}{BLACK}列出樂園內的維修人員 +STR_2212 :{SMALLFONT}{BLACK}列出樂園內的安全警衛 +STR_2213 :{SMALLFONT}{BLACK}列出樂園內的表演人員 +STR_2214 :遊戲暫停時無法建造任何物件! +STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) +STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F +STR_2218 :{RED}{STRINGID}, {STRINGID}的一部份, 尚未返回到{STRINGID}!{NEWLINE}檢查是否被卡住或被停止了 +STR_2219 :{RED}{COMMA16}人已喪生於{STRINGID}的意外中 +STR_2220 :{WINDOW_COLOUR_2}樂園評價: {BLACK}{COMMA16} +STR_2221 :{SMALLFONT}{BLACK}樂園評價: {COMMA16} +STR_2222 :{SMALLFONT}{BLACK}{STRINGID} +STR_2223 :{WINDOW_COLOUR_2}園內遊客: {BLACK}{COMMA16} +STR_2224 :{WINDOW_COLOUR_2}現金: {BLACK}{CURRENCY2DP} +STR_2225 :{WINDOW_COLOUR_2}現金: {RED}{CURRENCY2DP} +STR_2226 :{WINDOW_COLOUR_2}樂園價值: {BLACK}{CURRENCY} +STR_2227 :{WINDOW_COLOUR_2}公司價值: {BLACK}{CURRENCY} +STR_2228 :{WINDOW_COLOUR_2}上個月來自食物/飲料以及{NEWLINE}其他商品的銷售額: {BLACK}{CURRENCY} +STR_2229 :上坡到垂直的過渡軌道 +STR_2230 :垂直軌道 +STR_2231 :下落煞車裝置 +STR_2232 :纜索坡道 +STR_2233 :{SMALLFONT}{BLACK}樂園資料 +STR_2234 :最近訊息 +STR_2235 :{SMALLFONT}{STRINGID} {STRINGID} +STR_2236 :1月 +STR_2237 :2月 +STR_2238 :3月 +STR_2239 :4月 +STR_2240 :5月 +STR_2241 :6月 +STR_2242 :7月 +STR_2243 :8月 +STR_2244 :9月 +STR_2245 :10月 +STR_2246 :11月 +STR_2247 :12月 +STR_2248 :不能移除遊樂設施/店鋪... +STR_2249 :{BABYBLUE}全新遊樂設施/店鋪可供使用:{NEWLINE}{STRINGID} +STR_2250 :{BABYBLUE}全新景物/主題景物可供使用:{NEWLINE}{STRINGID} +STR_2251 :只可以在道路上建造! +STR_2252 :只可以橫過道路建造! +STR_2253 :運輸類遊樂設施 +STR_2254 :溫和類遊樂設施 +STR_2255 :雲霄飛車 +STR_2256 :剌激類遊樂設施 +STR_2257 :水文類遊樂設施 +STR_2258 :商店及攤販 +STR_2259 :景物及主題景物 +STR_2260 :無資金 +STR_2261 :最少資金 +STR_2262 :普通資金 +STR_2263 :最多資金 +STR_2264 :研發資金分配 +STR_2265 :{WINDOW_COLOUR_2}費用: {BLACK}每個月{CURRENCY} +STR_2266 :研發優先項目 +STR_2267 :目前研發項目 +STR_2268 :上次研發項目 +STR_2269 :{WINDOW_COLOUR_2}類別: {BLACK}{STRINGID} +STR_2270 :{WINDOW_COLOUR_2}進度: {BLACK}{STRINGID} +STR_2271 :{WINDOW_COLOUR_2}預計完工日期: {BLACK}{STRINGID} +STR_2272 :{WINDOW_COLOUR_2}遊樂設施/店鋪:{NEWLINE}{BLACK}{STRINGID} +STR_2273 :{WINDOW_COLOUR_2}景物/主題景物:{NEWLINE}{BLACK}{STRINGID} +STR_2274 :{SMALLFONT}{BLACK}顯示此研發項目的詳細資料 +STR_2275 :{SMALLFONT}{BLACK}顯示研發的資金分配及選項 +STR_2276 :{SMALLFONT}{BLACK}顯示研發項目進度 +STR_2277 :未知 +STR_2278 :運輸類遊樂設施 +STR_2279 :溫和類遊樂設施 +STR_2280 :雲霄飛車 +STR_2281 :剌激類遊樂設施 +STR_2282 :水文類遊樂設施 +STR_2283 :商店及攤販 +STR_2284 :景物及主題景物 +STR_2285 :初始研發 +STR_2286 :設計中 +STR_2287 :完成設計中 +STR_2288 :未知 +STR_2289 :{STRINGID} {STRINGID} +STR_2290 : +STR_2291 :選擇新遊戲的劇情 +STR_2292 :{WINDOW_COLOUR_2}乘坐過的遊樂設施: +STR_2293 :{BLACK}無 +STR_2294 :{SMALLFONT}{BLACK}更改基礎土地樣式 +STR_2295 :{SMALLFONT}{BLACK}更改土地的垂直邊界 +STR_2296 :{WINDOW_COLOUR_2}付了{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}進入樂園 +STR_2297 :{WINDOW_COLOUR_2}付了{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}乘坐{BLACK}{COMMA16}個遊樂設施 +STR_2298 :{WINDOW_COLOUR_2}付了{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}乘坐{BLACK}{COMMA16}個遊樂設施 +STR_2299 :{WINDOW_COLOUR_2}付了{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}享用{BLACK}{COMMA16}款食物 +STR_2300 :{WINDOW_COLOUR_2}付了{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}享用{BLACK}{COMMA16}款食物 +STR_2301 :{WINDOW_COLOUR_2}付了{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}享用{BLACK}{COMMA16}款飲料 +STR_2302 :{WINDOW_COLOUR_2}付了{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}享用{BLACK}{COMMA16}款飲料 +STR_2303 :{WINDOW_COLOUR_2}付了{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}購買{BLACK}{COMMA16}個記念品 +STR_2304 :{WINDOW_COLOUR_2}付了{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}購買{BLACK}{COMMA16}個記念品 +STR_2305 :軌道設計檔案 +STR_2306 :儲存軌道設計 +STR_2307 :選擇{STRINGID}的設計 +STR_2308 :{STRINGID}的設計檔案 +STR_2309 :安裝新的軌道設計 +STR_2310 :建造自訂設計 +STR_2311 :{WINDOW_COLOUR_2}興奮度: {BLACK}{COMMA2DP32} (approx.) +STR_2312 :{WINDOW_COLOUR_2}刺激度: {BLACK}{COMMA2DP32} (approx.) +STR_2313 :{WINDOW_COLOUR_2}噁心度: {BLACK}{COMMA2DP32} (approx.) +STR_2314 :{WINDOW_COLOUR_2}軌道長度: {BLACK}{STRINGID} +STR_2315 :{WINDOW_COLOUR_2}建造費用: {BLACK}約{CURRENCY} +STR_2316 :{WINDOW_COLOUR_2}需要空間: {BLACK}{COMMA16} x {COMMA16}格 +STR_2317 : +STR_2318 : +STR_2319 : +STR_2320 : +STR_2321 :{WINDOW_COLOUR_2}遊樂設施/店鋪數目: {BLACK}{COMMA16} +STR_2322 :{WINDOW_COLOUR_2}員工數目: {BLACK}{COMMA16} +STR_2323 :{WINDOW_COLOUR_2}樂園大小: {BLACK}{COMMA32}m{SQUARED} +STR_2324 :{WINDOW_COLOUR_2}樂園大小: {BLACK}{COMMA32}sq.ft. +STR_2325 :{SMALLFONT}{BLACK}購買土地來擴展樂園 +STR_2326 :{SMALLFONT}{BLACK}購買建造權來准許在樂園範圍外的空中或地底建造物件 +STR_2327 :選項 +STR_2328 :{WINDOW_COLOUR_2}貨幣單位: +STR_2329 :{WINDOW_COLOUR_2}距離及速度單位: +STR_2330 :{WINDOW_COLOUR_2}溫度單位: +STR_2331 :{WINDOW_COLOUR_2}高度標記單位: +STR_2332 :單位 +STR_2333 :聲效 +STR_2334 :英鎊 ({POUND}) +STR_2335 :美金 ($) +STR_2336 :法郎 (F) +STR_2337 :馬克 (DM) +STR_2338 :日元 ({YEN}) +STR_2339 :比塞塔 (Pts) +STR_2340 :裡拉 (L) +STR_2341 :荷蘭盾 (fl.) +STR_2342 :克朗 (kr) +STR_2343 :歐元 ({EURO}) +STR_2344 :英制 +STR_2345 :公制 +STR_2346 :顯示 +STR_2347 :{RED}{STRINGID}已被溺死! +STR_2348 :{SMALLFONT}{BLACK}顯示這位員工的統計資料 +STR_2349 :{WINDOW_COLOUR_2}工資: {BLACK}每個月{CURRENCY} +STR_2350 :{WINDOW_COLOUR_2}僱用日期: {BLACK}{MONTHYEAR} +STR_2351 :{WINDOW_COLOUR_2}除草次數: {BLACK}{COMMA16} +STR_2352 :{WINDOW_COLOUR_2}灌溉次數: {BLACK}{COMMA16} +STR_2353 :{WINDOW_COLOUR_2}掃地次數: {BLACK}{COMMA16} +STR_2354 :{WINDOW_COLOUR_2}清空拉坡筒次數: {BLACK}{COMMA16} +STR_2355 :{WINDOW_COLOUR_2}修理遊樂設施次數: {BLACK}{COMMA16} +STR_2356 :{WINDOW_COLOUR_2}檢驗遊樂設施次數: {BLACK}{COMMA16} +STR_2357 :房屋 +STR_2358 :單位 +STR_2359 :真實數值 +STR_2360 :{WINDOW_COLOUR_2}屏幕解析度: +STR_2361 :土地邊緣平滑化 +STR_2362 :{SMALLFONT}{BLACK}開啟/關閉土地邊緣平滑化 +STR_2363 :土地上的網格 +STR_2364 :{SMALLFONT}{BLACK}開啟/關閉土地上的網格 +STR_2365 :銀行拒絕增加你的貸款額! +STR_2366 :攝氏 ({DEGREE}C) +STR_2367 :華氏 ({DEGREE}F) +STR_2368 :無 +STR_2369 :低 +STR_2370 :普通 +STR_2371 :高 +STR_2372 :低 +STR_2373 :中 +STR_2374 :高 +STR_2375 :很高 +STR_2376 :極端 +STR_2377 :超極端 +STR_2378 :{SMALLFONT}{BLACK}調整較小的土地區域 +STR_2379 :{SMALLFONT}{BLACK}調整較大的土地區域 +STR_2380 :{SMALLFONT}{BLACK}調整較小的水塘區域 +STR_2381 :{SMALLFONT}{BLACK}調整較大的水塘區域 +STR_2382 :土地 +STR_2383 :水塘 +STR_2384 :{WINDOW_COLOUR_2}你的目標: +STR_2385 :{BLACK}無 +STR_2386 :{BLACK}在{POP16}{MONTHYEAR}尾之前, 樂園裡至少有{PUSH16}{PUSH16}{COMMA16}個遊客, 而且樂園評價並不低於600 +STR_2387 :{BLACK}在{POP16}{MONTHYEAR}尾之前, 樂園價值必需達到{CURRENCY} +STR_2388 :{BLACK}盡情玩吧! +STR_2389 :{BLACK}建造你的最佳{STRINGID}吧! +STR_2390 :{BLACK}樂園必需建造十種不同種類的雲霄飛車, 而且每座的興奮度不低於6.00 +STR_2391 :{BLACK}樂園裡至少有{COMMA16}個遊客. 任何時間下, 你並不可以令樂園評價跌至700以下! +STR_2392 :{BLACK}遊樂設施的門票收入至少要達到每月{POP16}{POP16}{CURRENCY} +STR_2393 :{BLACK}樂園必需建造十種不同種類的雲霄飛車, 每座的長度至少需要{LENGTH}, 而且興奮度都不低於7.00 +STR_2394 :{BLACK}建造好五座未完成的雲霄飛車, 將他們每座設計成興奮度至少達到{POP16}{POP16}{COMMA2DP32} +STR_2395 :{BLACK}還清樂園的貸款, 並令其價值至少達到{POP16}{POP16}{CURRENCY} +STR_2396 :{BLACK}食物, 飲料及記念品的銷售收入至少要達到每月{POP16}{POP16}{CURRENCY} +STR_2397 :無 +STR_2398 :指定日期要達到的遊客數量 +STR_2399 :指定日期要達到的樂園評價 +STR_2400 :盡情玩吧 +STR_2401 :建造你的最佳遊樂設施 +STR_2402 :建造十座雲霄飛車 +STR_2403 :樂園內遊客數量 +STR_2404 :遊樂設施門票的每月收入 +STR_2405 :建造十座指定長度的雲霄飛車 +STR_2406 :完成建造五座雲霄飛車 +STR_2407 :付清貸款及達到指定樂園評價 +STR_2408 :食物/飲料或其他商品的每月收入 +STR_2409 :{WINDOW_COLOUR_2}實行中的營銷計劃 +STR_2410 :{BLACK}無 +STR_2411 :{WINDOW_COLOUR_2}可以實行的營銷計劃 +STR_2412 :{SMALLFONT}{BLACK}開始實行這個營銷計劃 +STR_2413 :{BLACK}(每週{CURRENCY2DP}) +STR_2414 :(尚未選擇) +STR_2415 :{WINDOW_COLOUR_2}遊樂設施: +STR_2416 :{WINDOW_COLOUR_2}物品: +STR_2417 :{WINDOW_COLOUR_2}時長: +STR_2418 :免費進入{STRINGID} +STR_2419 :免費乘坐{STRINGID} +STR_2420 :半價進入{STRINGID} +STR_2421 :免費{STRINGID} +STR_2422 :{STRINGID}的推廣計劃 +STR_2423 :{STRINGID}的推廣計劃 +STR_2424 :{WINDOW_COLOUR_2}發放免費進入樂園卷 +STR_2425 :{WINDOW_COLOUR_2}發放免費乘坐個別遊樂設施卷 +STR_2426 :{WINDOW_COLOUR_2}發放半價進入樂園卷 +STR_2427 :{WINDOW_COLOUR_2}發放免費進入食物或飲料樂園卷 +STR_2428 :{WINDOW_COLOUR_2}開始針對樂園的推廣計劃 +STR_2429 :{WINDOW_COLOUR_2}開始針對個別遊樂設施的推廣計劃 +STR_2430 :{BLACK}免費進入{STRINGID}的優惠卷 +STR_2431 :{BLACK}免費乘坐{STRINGID}的優惠卷 +STR_2432 :{BLACK}半價進入{STRINGID}的優惠卷 +STR_2433 :{BLACK}免費{STRINGID}的優惠卷 +STR_2434 :{BLACK}{STRINGID}的推廣計劃 +STR_2435 :{BLACK}{STRINGID}的推廣計劃 +STR_2436 : +STR_2437 : +STR_2438 : +STR_2439 : +STR_2440 : +STR_2441 : +STR_2442 : +STR_2443 :{WINDOW_COLOUR_2}每週費用: {BLACK}{CURRENCY2DP} +STR_2444 :{WINDOW_COLOUR_2}總費用: {BLACK}{CURRENCY2DP} +STR_2445 :開始實行此營銷計劃 +STR_2446 :{YELLOW}你舉行的行銷計劃 - 免費進入樂園營銷計劃現已結束 +STR_2447 :{YELLOW}你舉行的行銷計劃 - 免費乘坐遊樂設施{STRINGID}現已結束 +STR_2448 :{YELLOW}你舉行的行銷計劃 - 半價進入樂園現已結束 +STR_2449 :{YELLOW}你舉行的行銷計劃 - 免費{STRINGID}現已結束 +STR_2450 :{YELLOW}你針對樂園的推廣計劃現已結束 +STR_2451 :{YELLOW}你針對{STRINGID}的推廣計劃現已結束 +STR_2452 :{WINDOW_COLOUR_2}現金 (減去貸款): {BLACK}{CURRENCY2DP} +STR_2453 :{WINDOW_COLOUR_2}現金 (減去貸款): {RED}{CURRENCY2DP} +STR_2454 :{SMALLFONT}{BLACK}{CURRENCY2DP} - +STR_2455 :{SMALLFONT}{BLACK}+{CURRENCY2DP} - +STR_2456 :{SMALLFONT}{BLACK}{CURRENCY2DP} - +STR_2457 :{SMALLFONT}{BLACK}顯示財政報表 +STR_2458 :{SMALLFONT}{BLACK}以圖表顯示過往到現在的凈現金 +STR_2459 :{SMALLFONT}{BLACK}以圖表顯示過往到現在的樂園價格 +STR_2460 :{SMALLFONT}{BLACK}以圖表顯示過往到現在的每週營利 +STR_2461 :{SMALLFONT}{BLACK}顯示營銷計劃詳情 +STR_2462 :{SMALLFONT}{BLACK}顯示樂園入口的視點 +STR_2463 :{SMALLFONT}{BLACK}以圖表顯示過往到現在的樂園評價 +STR_2464 :{SMALLFONT}{BLACK}以圖表顯示過往到現在的遊客人員 +STR_2465 :{SMALLFONT}{BLACK}顯示樂園門票價格以及其資訊 +STR_2466 :{SMALLFONT}{BLACK}顯示樂園的統計資料 +STR_2467 :{SMALLFONT}{BLACK}顯示是次遊戲的目標 +STR_2468 :{SMALLFONT}{BLACK}顯示這個樂園最近獲得的獎項 +STR_2469 :{SMALLFONT}{BLACK}選擇投放多少資金到研發當中 +STR_2470 :{SMALLFONT}{BLACK}研發新的運輸類遊樂設施 +STR_2471 :{SMALLFONT}{BLACK}研發新的溫和類遊樂設施 +STR_2472 :{SMALLFONT}{BLACK}研發新的雲霄飛車 +STR_2473 :{SMALLFONT}{BLACK}研發新的剌激類遊樂設施 +STR_2474 :{SMALLFONT}{BLACK}研發新的水文類遊樂設施 +STR_2475 :{SMALLFONT}{BLACK}研發新的商店及攤販 +STR_2476 :{SMALLFONT}{BLACK}研發新的景物及主題景物 +STR_2477 :{SMALLFONT}{BLACK}選擇這個遊樂設施的運作模式 +STR_2478 :{SMALLFONT}{BLACK}以圖表顯示速度與運作時間的關係 +STR_2479 :{SMALLFONT}{BLACK}以圖表顯示高度與運作時間的關係 +STR_2480 :{SMALLFONT}{BLACK}以圖表顯示垂直加速與運作時間的關係 +STR_2481 :{SMALLFONT}{BLACK}以圖表顯示橫向加速與運作時間的關係 +STR_2482 :{SMALLFONT}{BLACK}營利: 每週{CURRENCY}, 樂園價值: {CURRENCY} +STR_2483 :{WINDOW_COLOUR_2}每週營利: {BLACK}+{CURRENCY2DP} +STR_2484 :{WINDOW_COLOUR_2}每週營利: {RED}{CURRENCY2DP} +STR_2485 :控制 +STR_2486 :基本 +STR_2487 :顯示遊客的'真實'姓名 +STR_2488 :{SMALLFONT}{BLACK}設定顯示遊客的'真實'名字或顯示遊客名字為數字 +STR_2489 :快捷鍵... +STR_2490 :鍵盤快捷鍵 +STR_2491 :重設快捷鍵 +STR_2492 :{SMALLFONT}{BLACK}初始化所有快捷鍵設定 +STR_2493 :關閉最頂層的視窗 +STR_2494 :關閉所有視窗 +STR_2495 :退出建造模式 +STR_2496 :暫停遊戲 +STR_2497 :縮小檢視範圍 +STR_2498 :放大檢視範圍 +STR_2499 :順時針旋轉檢視範圍 +STR_2500 :旋轉要建造的物件 +STR_2501 :開關地底檢視模式 +STR_2502 :開關’移除地表’選項 +STR_2503 :開關’移除垂直表面’選項 +STR_2504 :開關’略過遊樂設施’選項 +STR_2505 :開關’略過景物’選項 +STR_2506 :開關’透明化支撐’選項 +STR_2507 :開關’透明化遊客’選項 +STR_2508 :開關’在土地上標記高度’選項 +STR_2509 :開關’在設施軌道上標記高度’選項 +STR_2510 :開關’在道路上標記高度’選項 +STR_2511 :調整土地 +STR_2512 :調整水面 +STR_2513 :建造景物 +STR_2514 :建造道路 +STR_2515 :建造新的遊樂設施 +STR_2516 :顯示財政狀況 +STR_2517 :顯示研發狀況 +STR_2518 :顯示遊樂設施/店面列表 +STR_2519 :顯示樂園狀況 +STR_2520 :顯示遊客列表 +STR_2521 :顯示員工列表 +STR_2522 :顯示最近訊息 +STR_2523 :顯示地圖 +STR_2524 :截圖 +### The following need to be reordered to match SDL_keycode layout. +STR_2525 :??? +STR_2526 :??? +STR_2527 :??? +STR_2528 :??? +STR_2529 :??? +STR_2530 :??? +STR_2531 :??? +STR_2532 :??? +STR_2533 :Backspace +STR_2534 :Tab +STR_2535 :??? +STR_2536 :??? +STR_2537 :Clear +STR_2538 :Return +STR_2539 :??? +STR_2540 :??? +STR_2541 :??? +STR_2542 :??? +STR_2543 :Alt/Menu +STR_2544 :Pause +STR_2545 :Caps +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 :Spacebar +STR_2558 :PgUp +STR_2559 :PgDn +STR_2560 :End +STR_2561 :Home +STR_2562 :Left +STR_2563 :Up +STR_2564 :Right +STR_2565 :Down +STR_2566 :Select +STR_2567 :Print +STR_2568 :Execute +STR_2569 :Snapshot +STR_2570 :Insert +STR_2571 :Delete +STR_2572 :Help +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 :NumPad 0 +STR_2622 :NumPad 1 +STR_2623 :NumPad 2 +STR_2624 :NumPad 3 +STR_2625 :NumPad 4 +STR_2626 :NumPad 5 +STR_2627 :NumPad 6 +STR_2628 :NumPad 7 +STR_2629 :NumPad 8 +STR_2630 :NumPad 9 +STR_2631 :NumPad * +STR_2632 :NumPad + +STR_2633 :??? +STR_2634 :NumPad - +STR_2635 :NumPad . +STR_2636 :NumPad / +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 :NumLock +STR_2670 :Scroll +STR_2671 :??? +STR_2672 :??? +STR_2673 :??? +STR_2674 :??? +STR_2675 :??? +STR_2676 :??? +STR_2677 :??? +STR_2678 :??? +STR_2679 :??? +STR_2680 :所有研發項目都已完成 +STR_2681 :{MEDIUMFONT}{BLACK}增加{CURRENCY}到你的金錢裡 +STR_2682 : +STR_2683 : +STR_2684 :{SMALLFONT}{BLACK}一大群遊客到訪 +STR_2685 :簡單雜噪參數 +STR_2686 :{WINDOW_COLOUR_2}最低值: +STR_2687 :{WINDOW_COLOUR_2}最高值: +STR_2688 :{WINDOW_COLOUR_2}基本頻律: +STR_2689 :{WINDOW_COLOUR_2}八度: +STR_2690 :生成地圖 +STR_2691 :{WINDOW_COLOUR_2}土地基本高度: +STR_2692 :{WINDOW_COLOUR_2}水面高度: +STR_2693 :{WINDOW_COLOUR_2}地質: +STR_2694 :生成 +STR_2695 :隨機地質 +STR_2696 :放置樹木 +STR_2697 :??? +STR_2698 :??? +STR_2699 :??? +STR_2700 :自動儲存的頻率: +STR_2701 :每分鐘 +STR_2702 :每5分鐘 +STR_2703 :每15分鐘 +STR_2704 :每30分鐘 +STR_2705 :每小時 +STR_2706 :從不 +STR_2707 :使用操作系統的對話框 +STR_2708 :{WINDOW_COLOUR_1}你確定要覆蓋存檔{STRINGID}? +STR_2709 :覆蓋 +STR_2710 :請輸入存檔名稱: +STR_2711 :; +STR_2712 := +STR_2713 :, +STR_2714 :- +STR_2715 :. +STR_2716 :/ +STR_2717 :' +STR_2718 :往上層目錄 +STR_2719 :建立新檔案 +STR_2720 :{UINT16}秒 +STR_2721 :{UINT16}秒 +STR_2722 :{UINT16}分:{UINT16}秒 +STR_2723 :{UINT16}分:{UINT16}秒 +STR_2724 :{UINT16}分:{UINT16}秒 +STR_2725 :{UINT16}分:{UINT16}秒 +STR_2726 :{UINT16}分 +STR_2727 :{UINT16}分 +STR_2728 :{UINT16}小時:{UINT16}分 +STR_2729 :{UINT16}小時:{UINT16}分 +STR_2730 :{UINT16}小時:{UINT16}分 +STR_2731 :{UINT16}小時:{UINT16}分 +STR_2732 :{COMMA16}ft +STR_2733 :{COMMA16}m +STR_2734 :{COMMA16}mph +STR_2735 :{COMMA16}km/h +STR_2736 :第{POP16}{COMMA16}年, {PUSH16}{PUSH16}{MONTH} +STR_2737 :{STRINGID} {MONTH}, 第{COMMA16}年 +STR_2738 :主選單音樂: +STR_2739 :無 +STR_2740 :夢幻遊樂園 (RCT1) +STR_2741 :模擬樂園 (RCT2) +STR_2742 :找不到css50.dat +STR_2743 :複製夢幻遊樂園(RCT1)文件夾中的'data\css17.dat'到模擬樂園(RCT2)的文件夾, 並重新命名為'data\css50.dat'. +STR_2744 :[ +STR_2745 :\ +STR_2746 :] +STR_2747 :{ENDQUOTES} +STR_2748 :列 +STR_2749 :我的新劇情 +# New strings used in the cheats window previously these were ??? +STR_2750 :移到所有物件至最頂部 +STR_2751 :移到所有物件至最底部 +STR_2752 :無雜草的草地 +STR_2753 :除好草的草地 +STR_2754 :灌溉花圃 +STR_2755 :修復被毀壞的物件 +STR_2756 :移除垃圾 +STR_2757 :強制晴天 +STR_2758 :強制雷暴 +STR_2759 :無'擋在路上'檢查 +STR_2760 :+{CURRENCY} +STR_2761 : +STR_2762 : +STR_2763 :??? +STR_2764 : +STR_2765 :添加超多遊客到訪 +STR_2766 :贏得此劇情 +STR_2767 :靜止氣候 +STR_2768 :不再靜止氣候 +STR_2769 :開放樂園 +STR_2770 :關閉樂園 +STR_2771 :減慢遊戲速度 +STR_2772 :加快遊戲速度 +STR_2773 :視窗化 +STR_2774 :全螢幕 +STR_2775 :全螢幕 (桌面尺寸) +STR_2776 :語言: +STR_2777 :{MOVE_X}{SMALLFONT}{STRING} +STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} +STR_2779 :額外檢視視窗#{COMMA16} +STR_2780 :新的額外檢視視窗 +# End of new strings +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} +STR_2782 :SHIFT + +STR_2783 :CTRL + +STR_2784 :更改鍵盤快捷鍵 +STR_2785 :{WINDOW_COLOUR_2}請按下屬於下列快捷鍵的新鍵位:{NEWLINE}{OPENQUOTES}{STRINGID}{ENDQUOTES} +STR_2786 :{SMALLFONT}{BLACK}按一下快捷鍵的描述來選擇新的鍵位 +STR_2787 :{WINDOW_COLOUR_2}樂園價值: {BLACK}{CURRENCY} +STR_2788 :{WINDOW_COLOUR_2}恭喜您!{NEWLINE}{BLACK}你已經達到你的目標, 並令公司價值增至 {CURRENCY} ! +STR_2789 :{WINDOW_COLOUR_2}你未能達到目標! +STR_2790 :請輸入你要在劇情列表顯示的名字 +STR_2791 :輸入名字 +STR_2792 :請輸入你要在劇情列表顯示的名字: +STR_2793 :{SMALLFONT}(已由{STRINGID}完成) +STR_2794 :{WINDOW_COLOUR_2}完成目標者: {BLACK}{STRINGID}{NEWLINE}{WINDOW_COLOUR_2} 令公司價值增至: {BLACK}{CURRENCY} +STR_2795 :排序 +STR_2796 :{SMALLFONT}{BLACK}將遊樂設施以不同類別列出 +STR_2797 :當滑鼠遊標放置於邊緣時, 捲動檢視範圍 +STR_2798 :{SMALLFONT}{BLACK}選擇到底當滑鼠游標放置於邊緣時, 捲動檢視範圍 +STR_2799 :{SMALLFONT}{BLACK}檢視或改變控制按鍵佈局 +STR_2800 :{WINDOW_COLOUR_2}總進園人數: {BLACK}{COMMA32} +STR_2801 :{WINDOW_COLOUR_2}樂園門票所得收入: {BLACK}{CURRENCY2DP} +STR_2802 :地圖 +STR_2803 :{SMALLFONT}{BLACK}將這些遊客高亮顯示於地圖中 +STR_2804 :{SMALLFONT}{BLACK}將這些員工高亮顯示於地圖中 +STR_2805 :{SMALLFONT}{BLACK}顯示樂園地圖 +STR_2806 :{RED}遊客都在投訴樂園裡的道路十分骯髒{NEWLINE}請檢查你的清潔工人位置所在, 並考慮以更好的方法管理他們 +STR_2807 :{RED}遊客都在投訴樂園裡隨地拋棄的垃圾十分多{NEWLINE}請檢查你的清潔工人位置所在, 並考慮以更好的方法管理他們 +STR_2808 :{RED}遊客都在投訴樂園裡的公物被毀壞{NEWLINE}請檢查你的安全警衛位置所在, 並考慮以更好的方法管理他們 +STR_2809 :{RED}遊客都餓了, 但他們找不到賣食物的店舖 +STR_2810 :{RED}遊客都渴了, 但他們找不到賣飲料的店舖 +STR_2811 :{RED}因為遊客都找不到樂園裡有廁所, 所以他們抱怨了 +STR_2812 :{RED}遊客都被卡住或迷失了{NEWLINE}請檢查樂園的道路設計是否需要改善, 以便遊客找到出路 +STR_2813 :{RED}你的樂園入場費太貴了!{NEWLINE}減低入場費或增加樂團價值來吸引更多遊客來訪 +STR_2814 :{WINDOW_COLOUR_2}最骯髒樂園獎 +STR_2815 :{WINDOW_COLOUR_2}最整潔樂園獎 +STR_2816 :{WINDOW_COLOUR_2}擁有最佳雲霄飛車獎 +STR_2817 :{WINDOW_COLOUR_2}最佳價值樂園獎 +STR_2818 :{WINDOW_COLOUR_2}最漂亮樂園獎 +STR_2819 :{WINDOW_COLOUR_2}最差價值樂園獎 +STR_2820 :{WINDOW_COLOUR_2}最安全樂園獎 +STR_2821 :{WINDOW_COLOUR_2}擁有最佳員工獎 +STR_2822 :{WINDOW_COLOUR_2}擁有最佳食物獎 +STR_2823 :{WINDOW_COLOUR_2}擁有最差食物獎 +STR_2824 :{WINDOW_COLOUR_2}擁有最佳廁所獎 +STR_2825 :{WINDOW_COLOUR_2}最令人失望樂園獎 +STR_2826 :{WINDOW_COLOUR_2}擁有最佳水文類遊樂設施獎 +STR_2827 :{WINDOW_COLOUR_2}擁有最佳自定設計的遊樂設施獎 +STR_2828 :{WINDOW_COLOUR_2}擁有最大膽的色彩選配獎 +STR_2829 :{WINDOW_COLOUR_2}擁有最令人迷失的道路獎 +STR_2830 :{WINDOW_COLOUR_2}擁有最佳溫和類遊樂設施獎 +STR_2831 :{TOPAZ}你的樂園剛獲得了'全國最骯髒樂園獎'! +STR_2832 :{TOPAZ}你的樂園剛獲得了'全國最整潔樂園獎'! +STR_2833 :{TOPAZ}你的樂園剛獲得了'擁有最佳雲霄飛車的樂園獎'! +STR_2834 :{TOPAZ}你的樂園剛獲得了'全國最佳價值樂園獎'! +STR_2835 :{TOPAZ}你的樂園剛獲得了'全國最漂亮樂園獎'! +STR_2836 :{TOPAZ}你的樂園剛獲得了'全國最差價值樂園獎'! +STR_2837 :{TOPAZ}你的樂園剛獲得了'全國最安全樂園獎'! +STR_2838 :{TOPAZ}你的樂園剛獲得了'擁有最佳員工的樂園獎'! +STR_2839 :{TOPAZ}你的樂園剛獲得了'擁有最佳食物的樂園獎'! +STR_2840 :{TOPAZ}你的樂園剛獲得了'擁有最差食物的樂園獎'! +STR_2841 :{TOPAZ}你的樂園剛獲得了'擁有最佳廁所的樂園獎'! +STR_2842 :{TOPAZ}你的樂園剛獲得了'全國最令人失望的樂園獎'! +STR_2843 :{TOPAZ}你的樂園剛獲得了'擁有最佳水文類遊樂設施的樂園獎'! +STR_2844 :{TOPAZ}你的樂園剛獲得了'擁有最佳自定設計的遊樂設施的樂園獎'! +STR_2845 :{TOPAZ}你的樂園剛獲得了'擁有最大膽的色彩選配的樂園獎'! +STR_2846 :{TOPAZ}你的樂園剛獲得了'擁有最令人迷失的道路的樂園獎'! +STR_2847 :{TOPAZ}你的樂園剛獲得了'擁有最佳溫和類遊樂設施的樂園獎'! +STR_2848 :{WINDOW_COLOUR_2}暫無獲得任何獎項 +STR_2849 :成功安裝新劇情 +STR_2850 :成功安裝新軌道設計 +STR_2851 :劇情已曾安裝 +STR_2852 :軌道設計已曾安裝 +STR_2853 :被當地政府禁止! +STR_2854 :{RED}遊客都不能走到去{STRINGID}的入口!{NEWLINE}請建造道路連接入口 +STR_2855 :{RED}{STRINGID}的出口並沒有道路連接!{NEWLINE}請建造道路連接出口 +STR_2856 :{WINDOW_COLOUR_2}教學 +STR_2857 :{WINDOW_COLOUR_2}(按下任意鍵來獲取控制) +STR_2858 :不能開始實行營銷計劃... +STR_2859 :另外一個OpenRCT2程序已在運行中 +STR_2860 :Infogrames Interactive credits... +STR_2861 :{WINDOW_COLOUR_2}Licensed to Infogrames Interactive Inc. +STR_2862 :音樂鳴謝列表... +STR_2863 :音樂鳴謝列表 +STR_2864 :{WINDOW_COLOUR_2}March - Children of the Regiment: (Fucik) 無版權 +STR_2865 :{WINDOW_COLOUR_2}Heyken's Serenade: (J.Heyken) British Standard Music Coy; GEMA, BRITICO +STR_2866 :{WINDOW_COLOUR_2}In Continental Mood: (Composer unknown) 版權被受控制 +STR_2867 :{WINDOW_COLOUR_2}Wedding Journey: (Traditional) +STR_2868 :{WINDOW_COLOUR_2}Tales from the Vienna Woods: (Johann Strauss) 無版權 +STR_2869 :{WINDOW_COLOUR_2}Slavonic Dance: (Traditional) +STR_2870 :{WINDOW_COLOUR_2}Das Alpenhorn: (Traditional) +STR_2871 :{WINDOW_COLOUR_2}The Blond Sailor: (Traditional) +STR_2872 :{WINDOW_COLOUR_2}Overture - Poet and Peasant: (Suppe) 無版權 +STR_2873 :{WINDOW_COLOUR_2}Waltz Medley: (Johann Strauss) 無版權 +STR_2874 :{WINDOW_COLOUR_2}Bella Bella Bimba: (Traditional) +STR_2875 :{WINDOW_COLOUR_2}Original recordings (P) 1976 C.J.Mears Organization, used with consent +STR_2876 :{WINDOW_COLOUR_2}RollerCoaster Tycoon 2 Title Music: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2877 :{WINDOW_COLOUR_2}Dodgems Beat: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2878 :{WINDOW_COLOUR_2}Mid Summer's Heat: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2879 :{WINDOW_COLOUR_2}Pharaoh's Tomb: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2880 :{WINDOW_COLOUR_2}Caesar's March: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2881 :{WINDOW_COLOUR_2}Drifting To Heaven: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2882 :{WINDOW_COLOUR_2}Invaders: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2883 :{WINDOW_COLOUR_2}Eternal Toybox: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2884 :{WINDOW_COLOUR_2}Jungle Juice: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2885 :{WINDOW_COLOUR_2}Ninja's Noodles: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2886 :{WINDOW_COLOUR_2}Voyage to Andromeda: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2887 :{WINDOW_COLOUR_2}Brimble's Beat: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2888 :{WINDOW_COLOUR_2}Atlantis: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2889 :{WINDOW_COLOUR_2}Wild West Kid: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2890 :{WINDOW_COLOUR_2}Vampire's Lair: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2891 :{WINDOW_COLOUR_2}Blockbuster: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2892 :{WINDOW_COLOUR_2}Airtime Rock: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2893 :{WINDOW_COLOUR_2}Searchlight Rag: (Scott Joplin/Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2894 :{WINDOW_COLOUR_2}Flight of Fantasy: (Steve Blenkinsopp) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2895 :{WINDOW_COLOUR_2}Big Rock: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2896 :{WINDOW_COLOUR_2}Hypothermia: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2897 :{WINDOW_COLOUR_2}Last Sleigh Ride: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2898 :{WINDOW_COLOUR_2}Pipes of Glencairn: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2899 :{WINDOW_COLOUR_2}Traffic Jam: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2900 :{WINDOW_COLOUR_2} +STR_2901 :{WINDOW_COLOUR_2}(音樂採樣承蒙Spectrasonics {ENDQUOTES}Liquid Grooves{ENDQUOTES}) +STR_2902 :{WINDOW_COLOUR_2}Toccata: (C.M.Widor, played by Peter James Adcock) recording {COPYRIGHT} Chris Sawyer 版權所有 +STR_2903 :{WINDOW_COLOUR_2}Space Rock: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2904 :{WINDOW_COLOUR_2}Manic Mechanic: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2905 :{WINDOW_COLOUR_2}Techno Torture: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2906 :{WINDOW_COLOUR_2}Sweat Dreams: (Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2907 :{WINDOW_COLOUR_2}What shall we do with the Drunken Sailor: (Anon/Allister Brimble) {COPYRIGHT} Chris Sawyer 版權所有 +STR_2908 :{WINDOW_COLOUR_2}Infogrames Interactive +STR_2909 :{WINDOW_COLOUR_2}Senior Producer: Thomas J. Zahorik +STR_2910 :{WINDOW_COLOUR_2}Executive Producer: Bill Levay +STR_2911 :{WINDOW_COLOUR_2}Senior Marketing Product Manager: Scott Triola +STR_2912 :{WINDOW_COLOUR_2}V.P. of Product Development: Scott Walker +STR_2913 :{WINDOW_COLOUR_2}General Manager: John Hurlbut +STR_2914 :{WINDOW_COLOUR_2}Director of Quality Assurance: Michael Craighead +STR_2915 :{WINDOW_COLOUR_2}Q.A. Certification Manager: Kurt Boutin +STR_2916 :{WINDOW_COLOUR_2}Q.A. Certification Lead: Mark Huggins +STR_2917 :{WINDOW_COLOUR_2}Testers: Dena Irene Fitzgerald, Scott Rollins, Christopher McPhail +STR_2918 :{WINDOW_COLOUR_2}Clif McClure, Erik Maramaldi, Erik Jeffery +STR_2919 :{WINDOW_COLOUR_2}Director of Marketing: Ann Marie Bland +STR_2920 :{WINDOW_COLOUR_2}Manager of Creative Services: Steve Martin +STR_2921 :{WINDOW_COLOUR_2}Manager of Editorial & Documentation Services: Elizabeth Mackney +STR_2922 :{WINDOW_COLOUR_2}Graphic Designer: Paul Anselmi +STR_2923 :{WINDOW_COLOUR_2}Copywriter: Kurt Carlson +STR_2924 :{WINDOW_COLOUR_2}Special Thanks to: Peter Matiss +STR_2925 :{WINDOW_COLOUR_2}Engineering Specialist: Ken Edwards +STR_2926 :{WINDOW_COLOUR_2}Engineering Services Manager: Luis Rivas +STR_2927 :{WINDOW_COLOUR_2}Lead Compatibility Analyst: Geoffrey Smith +STR_2928 :{WINDOW_COLOUR_2}Compatibility Analysts: Jason Cordero, Burke McQuinn, Kim Jardin +STR_2929 :{WINDOW_COLOUR_2}Lead Tester: Daniel Frisoli +STR_2930 :{WINDOW_COLOUR_2}Senior Tester: 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 : +STR_2970 : +STR_2971 :主要色彩選配 +STR_2972 :額外色彩選配1 +STR_2973 :額外色彩選配2 +STR_2974 :額外色彩選配3 +STR_2975 :{SMALLFONT}{BLACK}選取遊樂設施的色彩選配來修改 +STR_2976 :{SMALLFONT}{BLACK}將目前指定的色彩選配塗上遊樂設施的指定區域 +STR_2977 :員工命名 +STR_2978 :請輸入這位員工的新姓名: +STR_2979 :不能命名這位員工... +STR_2980 :遊戲中太多橫額 +STR_2981 :{RED}閒人止步 - - +STR_2982 :橫額文字 +STR_2983 :請輸入橫額中的文字: +STR_2984 :不能設定橫額中的文字... +STR_2985 :橫額 +STR_2986 :{SMALLFONT}{BLACK}修改橫額中的文字 +STR_2987 :{SMALLFONT}{BLACK}將此橫額顯示為'遊客止步' +STR_2988 :{SMALLFONT}{BLACK}拆除這個橫額 +STR_2989 :{SMALLFONT}{BLACK}選擇橫額顏色 +STR_2990 :{SMALLFONT}{BLACK}選擇文字顏色 +STR_2991 :招牌 +STR_2992 :修改招牌中的文字 +STR_2993 :請輸入招牌中的文字: +STR_2994 :{SMALLFONT}{BLACK}修改招牌中的文字 +STR_2995 :{SMALLFONT}{BLACK}拆除這個招牌 +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 :無法載入檔案... +STR_3011 :檔案中含有非法資料 +STR_3012 :碰碰車節奏風格 +STR_3013 :遊樂場風琴風格 +STR_3014 :羅馬號角風格 +STR_3015 :東方風格 +STR_3016 :火星風格 +STR_3017 :叢林敲擊風格 +STR_3018 :埃及風格 +STR_3019 :童真風格 +STR_3020 : +STR_3021 :太空風格 +STR_3022 :恐怖風格 +STR_3023 :電子風格 +STR_3024 :溫和風格 +STR_3025 :夏日風格 +STR_3026 :水文風格 +STR_3027 :美國西部風格 +STR_3028 :侏儸紀風格 +STR_3029 :搖滾風格 +STR_3030 :雷格泰姆音樂風格 +STR_3031 :夢幻風格 +STR_3032 :搖滾風格2 +STR_3033 :冰封風格 +STR_3034 :雪地風格 +STR_3035 :自訂音樂1 +STR_3036 :自訂音樂2 +STR_3037 :中世紀風格 +STR_3038 :都市風格 +STR_3039 :風琴風格 +STR_3040 :機械風格 +STR_3041 :摩登風格 +STR_3042 :海盜風格 +STR_3043 :搖滾風格3 +STR_3044 :糖果風格 +STR_3045 :{SMALLFONT}{BLACK}選擇要播放的音樂風格: +STR_3046 :此遊樂設施不能被修改 +STR_3047 :當地政府禁止拆除或修改此遊樂設施 +STR_3048 :當地政府禁止所有推廣計劃進行 +STR_3049 :哥爾夫球洞A +STR_3050 :哥爾夫球洞B +STR_3051 :哥爾夫球洞C +STR_3052 :哥爾夫球洞D +STR_3053 :哥爾夫球洞E +STR_3054 :載入中... +STR_3055 :白色 +STR_3056 :透明 +STR_3057 :{WINDOW_COLOUR_2}建造標記: +STR_3058 :磚牆 +STR_3059 :樹籬 +STR_3060 :冰磚牆 +STR_3061 :木柵欄 +STR_3062 :{SMALLFONT}{BLACK}標準雲霄飛車軌道 +STR_3063 :{SMALLFONT}{BLACK}水濺軌道 (軌道半浸於水中) +STR_3064 :新手級樂園 +STR_3065 :挑戰級樂園 +STR_3066 :專家級樂園 +STR_3067 :{OPENQUOTES}真實{ENDQUOTES}樂園 +STR_3068 :其他樂園 +STR_3069 :最上的區域 +STR_3070 :斜坡至平面 +STR_3071 :{WINDOW_COLOUR_2}劃一樂園內的價格 +STR_3072 :{SMALLFONT}{BLACK}選擇是否以此價格為劃一價格 +STR_3073 :{RED}警告: 你的樂園評價已跌至低於700!{NEWLINE}如果你在4週內尚未改善樂園評價, 你的樂園將會被強制關閉 +STR_3074 :{RED}警告: 你的樂園評價仍然低於700!{NEWLINE}你還有3週去改善評價 +STR_3075 :{RED}警告: 你的樂園評價仍然低於700!{NEWLINE}你還有2週去改善評價, 否則你的樂園將會被強制關閉 +STR_3076 :{RED}最後通諜: 你的樂園評價仍然低於700!{NEWLINE}7日之內你的樂園將會被強制關閉, 除非你能改善樂園評價 +STR_3077 :{RED}關閉告示: 你的樂園已被強制關閉! +STR_3078 :普通入口 +STR_3079 :木製入口 +STR_3080 :帆布帳幕式入口 +STR_3081 :城堡主題入口 (灰) +STR_3082 :城堡主題入口 (啡) +STR_3083 :叢林主題入口 +STR_3084 :木屋式入口 +STR_3085 :古羅馬主題入口 +STR_3086 :抽象主題入口 +STR_3087 :冰雪主題入口 +STR_3088 :寶塔式入口 +STR_3089 :太空主題入口 +STR_3090 :{SMALLFONT}{BLACK}選擇入口, 出口以及車站的風格 +STR_3091 :你無法刪除此軌道! +STR_3092 :你無法移動或修改這個遊樂設施的車站! +STR_3093 :{WINDOW_COLOUR_2}最愛: {BLACK}{STRINGID} +STR_3094 :N/A +STR_3095 :{WINDOW_COLOUR_2}鏈條坡道的鏈條速度: +STR_3096 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} +STR_3097 :{SMALLFONT}{BLACK}選擇鏈條坡道的鏈條上拉速度 +STR_3098 :不能更改鏈條坡道的鏈條速度... +STR_3099 :{SMALLFONT}{BLACK}選擇顏色 +STR_3100 :{SMALLFONT}{BLACK}選擇第二顏色 +STR_3101 :{SMALLFONT}{BLACK}選擇第三顏色 +STR_3102 :{SMALLFONT}{BLACK}將地形的景物重新上色 +STR_3103 :不能重新上色這個物件... +STR_3104 :{SMALLFONT}{BLACK}列出遊樂設施 +STR_3105 :{SMALLFONT}{BLACK}列出商店及攤販 +STR_3106 :{SMALLFONT}{BLACK}列出訪客資訊中心或其他遊客設施 +STR_3107 :關閉 +STR_3108 :測試 +STR_3109 :開啟 +STR_3110 :{WINDOW_COLOUR_2}煞車區間: {BLACK}{COMMA16} +STR_3111 :{SMALLFONT}{BLACK}點擊建造設計 +STR_3112 :{SMALLFONT}{BLACK}點擊刪除或重命名設計 +STR_3113 :選擇另一個設計 +STR_3114 :{SMALLFONT}{BLACK}返回選擇設計視窗 +STR_3115 :{SMALLFONT}{BLACK}儲存軌道設計 +STR_3116 :{SMALLFONT}{BLACK}儲存軌道設計 (在測試完結及測試資料生成完畢前不可用) +STR_3117 :{BLACK}呼叫維修人員中... +STR_3118 :{BLACK}{STRINGID}正在前往到這個遊樂設施 +STR_3119 :{BLACK}{STRINGID}正在修復這個遊樂設施 +STR_3120 :{SMALLFONT}{BLACK}將最鄰近, 或在維修此遊樂設施的維修人員定位 +STR_3121 :無法將維修人員定位, 或者附近的維修人員都在工作中 +STR_3122 :{WINDOW_COLOUR_2}遊客的最愛: {BLACK}{COMMA16}位遊客 +STR_3123 :{WINDOW_COLOUR_2}遊客的最愛: {BLACK}{COMMA16}位遊客 +STR_3124 :故障的{STRINGID} +STR_3125 :{WINDOW_COLOUR_2}興奮度加成: {BLACK}+{COMMA16}% +STR_3126 :{WINDOW_COLOUR_2}刺激度加成: {BLACK}+{COMMA16}% +STR_3127 :{WINDOW_COLOUR_2}噁心度加成: {BLACK}+{COMMA16}% +STR_3128 :儲存軌道設計 +STR_3129 :儲存軌道設計及周邊景物 +STR_3130 :儲存 +STR_3131 :取消 +STR_3132 :{BLACK}點擊選擇景物, 以便儲存於軌道設計內... +STR_3133 :無法於斜坡上建造此物件 +STR_3134 :{RED}(設計中含有不可用的景物) +STR_3135 :{RED}(車輛款式不可用 - 遊樂設施的性能可能會有影響) +STR_3136 :警告: 此設計會使用另一款車輛, 它的運作可能會跟預期有落差 +STR_3137 :選擇鄰近景物 +STR_3138 :重新選擇 +STR_3139 :纜道坡道不能在這個運作模式運作 +STR_3140 :纜道坡道需要連接至車站 +STR_3141 :纜道坡道並不適合於單次多圈數的遊樂設施 +STR_3142 :{WINDOW_COLOUR_2}載客量: {BLACK}{STRINGID} +STR_3143 :{SMALLFONT}{BLACK}在地圖上顯示所有人物 +STR_3144 :{SMALLFONT}{BLACK}在地圖上顯示所有遊樂設施及店鋪 +STR_3145 :{SMALLFONT}{BLACK}向左捲動{STRINGID} +STR_3146 :{SMALLFONT}{BLACK}向右捲動{STRINGID} +STR_3147 :{SMALLFONT}{BLACK}快速向左捲動{STRINGID} +STR_3148 :{SMALLFONT}{BLACK}快速向右捲動{STRINGID} +STR_3149 :{SMALLFONT}{BLACK}向左/向右捲動{STRINGID} +STR_3150 :{SMALLFONT}{BLACK}向上捲動{STRINGID} +STR_3151 :{SMALLFONT}{BLACK}向下捲動{STRINGID} +STR_3152 :{SMALLFONT}{BLACK}快速向上捲動{STRINGID} +STR_3153 :{SMALLFONT}{BLACK}快速向下捲動{STRINGID} +STR_3154 :{SMALLFONT}{BLACK}向上/向下捲動{STRINGID} +STR_3155 : +STR_3156 : +STR_3157 :地圖 +STR_3158 :圖表 +STR_3159 :列表 +STR_3160 : +STR_3161 : +STR_3162 :無法分配足夠的記憶體 +STR_3163 :安裝新資料檔中: +STR_3164 :{BLACK}已選擇{COMMA16}項 (最多{COMMA16}項) +STR_3165 : +STR_3166 :{BLACK}(ID: +STR_3167 :{WINDOW_COLOUR_2}包含: {BLACK}{COMMA16}項物件 +STR_3168 :{WINDOW_COLOUR_2}文字: {BLACK}{STRINGID} +STR_3169 :找不到以下物件的資料: +STR_3170 :沒有空間繪製圖像 +STR_3171 :選擇了太多此類型的物件 +STR_3172 :必需要先選擇以下的物件: {STRING} +STR_3173 :這個物件目前被使用中 +STR_3174 :其他物件需要這個物件 +STR_3175 :這個物件是必需的 +STR_3176 :無法選擇這個物件 +STR_3177 :無法取消選擇這個物件 +STR_3178 :至少需要選擇一項道路款式 +STR_3179 :至少需要選擇一項遊樂設施/店鋪 +STR_3180 :不合適的物件選擇 +STR_3181 :物件選擇 - {STRINGID} +STR_3182 :必須選擇樂園入口類別 +STR_3183 :必須選擇水塘類別 +STR_3184 :遊樂設施/其車輛 +STR_3185 :小型景物 +STR_3186 :大型景物 +STR_3187 :牆壁/柵欄 +STR_3188 :道路指示牌 +STR_3189 :道路 +STR_3190 :額外的道路物件 +STR_3191 :景物組別 +STR_3192 :樂園入口 +STR_3193 :水塘 +STR_3194 :劇情簡介 +STR_3195 :研發列表 +STR_3196 :{WINDOW_COLOUR_2}研發組別: {BLACK}{STRINGID} +STR_3197 :{WINDOW_COLOUR_2}遊戲開始時已研發好的項目: +STR_3198 :{WINDOW_COLOUR_2}需要在遊戲中研發的項目: +STR_3199 :隨機分配 +STR_3200 :{SMALLFONT}{BLACK}將需要在遊戲中研發的項目隨機分配 +STR_3201 :選取物件 +STR_3202 :編輯地勢 +STR_3203 :設定研發清單 +STR_3204 :選取選項 +STR_3205 :選取目標 +STR_3206 :儲存劇情 +STR_3207 :雲霄飛車設計工具 +STR_3208 :軌道設計管理工具 +STR_3209 :上一步: +STR_3210 :下一步: +STR_3211 :{WINDOW_COLOUR_2}地圖大小: +STR_3212 :{POP16}{COMMA16} x {PUSH16}{COMMA16} +STR_3213 :不能再縮小地圖 +STR_3214 :不能再擴大地圖 +STR_3215 :太接近地圖的邊緣 +STR_3216 :{SMALLFONT}{BLACK}選擇樂園擁有的土地及其他選項 +STR_3217 :已擁有的土地 +STR_3218 :已擁有建造權的土地 +STR_3219 :可供購買的土地 +STR_3220 :可供購買建造權的土地 +STR_3221 :{SMALLFONT}{BLACK}將樂園設置成為土地的擁有者 +STR_3222 :{SMALLFONT}{BLACK}尤樂園擁有土地的建造權 +STR_3223 :{SMALLFONT}{BLACK}將土地設置成為可供樂園購買 +STR_3224 :{SMALLFONT}{BLACK}將土地的建造權設置成為可供樂園購買 +STR_3225 :{SMALLFONT}{BLACK}設置是否在選中的位置中建造一些隨機物件 +STR_3226 :{SMALLFONT}{BLACK}建造樂園入口 +STR_3227 :太多樂園入口! +STR_3228 :{SMALLFONT}{BLACK}設置遊客的開始步行位置 +STR_3229 :區域煞車不能建造在車站之後 +STR_3230 :區域煞車不能建造在自己之後 +STR_3231 :區域煞車不能建造在這個鏈條坡道的頂部之後 +STR_3232 :選項 - 財政 +STR_3233 :選項 - 遊客 +STR_3234 :選項 - 樂園 +STR_3235 :{SMALLFONT}{BLACK}顯示財政選項 +STR_3236 :{SMALLFONT}{BLACK}顯示遊客選項 +STR_3237 :{SMALLFONT}{BLACK}顯示樂園選項 +STR_3238 :無金錢限制 +STR_3239 :{SMALLFONT}{BLACK}將這個樂園設定為無金錢限制的樂園 +STR_3240 :{WINDOW_COLOUR_2}初始現金: +STR_3241 :{WINDOW_COLOUR_2}初始貸款額: +STR_3242 :{WINDOW_COLOUR_2}最高貸款額: +STR_3243 :{WINDOW_COLOUR_2}貸款年利率: +STR_3244 :禁止營銷計劃 +STR_3245 :{SMALLFONT}{BLACK}禁止推銷, 推廣計劃以及其他營銷計劃 +STR_3246 :{WINDOW_COLOUR_2}{CURRENCY} +STR_3247 :{WINDOW_COLOUR_2}{COMMA16}% +STR_3248 :不能再增加初始現金! +STR_3249 :不能再減少初始現金! +STR_3250 :不能再增加初始貸款額! +STR_3251 :不能再減少初始貸款額! +STR_3252 :不能再增加最高貸款額! +STR_3253 :不能再減少最高貸款額! +STR_3254 :不能再增加貸款利率! +STR_3255 :不能再減少貸款利率! +STR_3256 :遊客喜歡較溫和的遊樂設施 +STR_3257 :{SMALLFONT}{BLACK}選擇普遍遊客是否只喜歡較溫和的遊樂設施 +STR_3258 :遊客喜歡較刺激的遊樂設施 +STR_3259 :{SMALLFONT}{BLACK}選擇普遍遊客是否只喜歡較刺激的遊樂設施 +STR_3260 :{WINDOW_COLOUR_2}遊客身上現金 (平均值): +STR_3261 :{WINDOW_COLOUR_2}遊客初始快樂度: +STR_3262 :{WINDOW_COLOUR_2}遊客初始飢餓度: +STR_3263 :{WINDOW_COLOUR_2}遊客初始口渴度: +STR_3264 :不能再增加這個選項! +STR_3265 :不能再減少這個選項! +STR_3266 :{SMALLFONT}{BLACK}選擇這個樂園的收費策略 +STR_3267 :禁止移除樹木 +STR_3268 :{SMALLFONT}{BLACK}禁止移除高壯的樹木 +STR_3269 :禁止調整地形 +STR_3270 :{SMALLFONT}{BLACK}禁止對地形作任何調整 +STR_3271 :禁止高空建造 +STR_3272 :{SMALLFONT}{BLACK}禁止任何高空發展 +STR_3273 :較高難度的樂園評價公式 +STR_3274 :{SMALLFONT}{BLACK}使增加樂園評價更加有挑戰性 +STR_3275 :較難生成遊客 +STR_3276 :{SMALLFONT}{BLACK}使吸引遊客更加有挑戰性 +STR_3277 :{WINDOW_COLOUR_2}購買土地的費用: +STR_3278 :{WINDOW_COLOUR_2}購買建造權利的費用: +STR_3279 :免費進入樂園 / 需費乘搭遊樂設施 +STR_3280 :需費進入樂園 / 免費乘搭遊樂設施 +STR_3281 :{WINDOW_COLOUR_2}樂園門票價格: +STR_3282 :{SMALLFONT}{BLACK}選擇目標及樂園名稱 +STR_3283 :{SMALLFONT}{BLACK}選擇要保留的遊樂設施/店鋪 +STR_3284 :選取目標 +STR_3285 :保留遊樂設施/店鋪 +STR_3286 :{SMALLFONT}{BLACK}選擇此劇情的目標 +STR_3287 :{WINDOW_COLOUR_2}目標: +STR_3288 :{SMALLFONT}{BLACK}選擇氣候 +STR_3289 :{WINDOW_COLOUR_2}氣候: +STR_3290 :又冷又潮濕 +STR_3291 :溫暖 +STR_3292 :又熱又乾燥 +STR_3293 :寒冷 +STR_3294 :更改... +STR_3295 :{SMALLFONT}{BLACK}更改樂園名稱 +STR_3296 :{SMALLFONT}{BLACK}更改劇情名稱 +STR_3297 :{SMALLFONT}{BLACK}更改樂園/劇情的簡介 +STR_3298 :{WINDOW_COLOUR_2}樂園名稱: {BLACK}{STRINGID} +STR_3299 :{WINDOW_COLOUR_2}樂園/劇情的簡介: +STR_3300 :{WINDOW_COLOUR_2}劇情名稱: {BLACK}{STRINGID} +STR_3301 :{WINDOW_COLOUR_2}達成目標的日期: +STR_3302 :{WINDOW_COLOUR_2}{MONTHYEAR} +STR_3303 :{WINDOW_COLOUR_2}遊客數量: +STR_3304 :{WINDOW_COLOUR_2}樂園評價: +STR_3305 :{WINDOW_COLOUR_2}每月收入: +STR_3306 :{WINDOW_COLOUR_2}每月利潤: +STR_3307 :{WINDOW_COLOUR_2}最少長度: +STR_3308 :{WINDOW_COLOUR_2}興奮度: +STR_3309 :{WINDOW_COLOUR_2}{COMMA16} +STR_3310 :{WINDOW_COLOUR_2}{LENGTH} +STR_3311 :{WINDOW_COLOUR_2}{COMMA2DP32} +STR_3312 :{WINDOW_COLOUR_2}請選取要保留的遊樂設施/店鋪: +STR_3313 :劇情名稱 +STR_3314 :請輸入這個劇情的名稱: +STR_3315 :樂園/劇情的簡介 +STR_3316 :請輸入這個樂園/劇情的簡介: +STR_3317 :暫無簡介 +STR_3318 :{SMALLFONT}{BLACK}選擇這個劇情要在哪個組別中顯示 +STR_3319 :{WINDOW_COLOUR_2}劇情組別: +STR_3320 :無法儲存劇情檔案... +STR_3321 :成功安裝新物件 +STR_3322 :{WINDOW_COLOUR_2}目標: {BLACK}{STRINGID} +STR_3323 :缺少物件資料, ID為: +STR_3324 :需要資料片: +STR_3325 :需要一隻資料片 +STR_3326 :{WINDOW_COLOUR_2}(暫無圖片) +STR_3327 :尚未設定遊客的開始步行位置 +STR_3328 :不能進行下一步編輯... +STR_3329 :尚未建造樂園入口 +STR_3330 :樂園必需有一些己擁有的土地 +STR_3331 :由地圖邊緣到樂園入口的道路尚未連接好, 或者太複雜 - 這些道路必需是一格寬度, 並以越少交界及彎位越好 +STR_3332 :樂園入口倒轉了, 或沒有道路連接至地圖邊緣 +STR_3333 :在存檔中導出附加物件 +STR_3334 :{SMALLFONT}{BLACK}選擇是否儲存附加物件(額外加入的附加物件)到存檔, 以便存檔給沒有那些附加物件的人載入 +STR_3335 :雲霄飛車設計工具 - 選擇要設計的雲霄飛車的類型及車輛種類 +STR_3336 :軌道設計管理工具 - 選擇要管理的遊樂設施的類型 +STR_3337 : +STR_3338 :{BLACK}自訂設計 +STR_3339 :{BLACK}可選{COMMA16}項預設計, 或可自訂設計 +STR_3340 :{BLACK}可選{COMMA16}項預設計, 或可自訂設計 +STR_3341 :{SMALLFONT}{BLACK}遊戲工具 +STR_3342 :劇情修改工具 +STR_3343 :將存檔轉換成劇情 +STR_3344 :雲霄飛車設計工具 +STR_3345 :軌道設計管理工具 +STR_3346 :無法儲存軌道設計... +STR_3347 :遊樂設施太巨型, 含有太多物件, 或景物分佈太散亂 +STR_3348 :重命名 +STR_3349 :刪除 +STR_3350 :軌道設計名稱 +STR_3351 :請輸入這個軌道設計的新名稱: +STR_3352 :不能重命名這個軌道設計... +STR_3353 :新名稱含有不適合的字符 +STR_3354 :已有另外一個檔案為相同名稱, 或檔案被寫入保護 +STR_3355 :檔案被寫入保護或被鎖定 +STR_3356 :刪除檔案 +STR_3357 :{WINDOW_COLOUR_2}你確定要永久刪除{STRINGID} ? +STR_3358 :不能刪除軌道設計... +STR_3359 :{BLACK}這類遊樂設施沒有已設計好的軌道設計 +STR_3360 :警告! +STR_3361 :這種遊樂設施擁有太多軌道設計 - 將不會列出某些軌道設計. +STR_3362 : +STR_3363 : +STR_3364 :進階 +STR_3365 :{SMALLFONT}{BLACK}在選擇景物組別之外, 允許選擇單項景物 +STR_3366 :{BLACK}= 遊樂設施 +STR_3367 :{BLACK}= 食物店鋪 +STR_3368 :{BLACK}= 飲料店鋪 +STR_3369 :{BLACK}= 記念品店鋪 +STR_3370 :{BLACK}= 訪客資訊中心 +STR_3371 :{BLACK}= 急救室 +STR_3372 :{BLACK}= 提款機 +STR_3373 :{BLACK}= 廁所 +STR_3374 :警告: 選取了太多物件! +STR_3375 :不是在此景觀組別中的所有物件都能夠選取 +STR_3376 :安裝新的軌道設計... +STR_3377 :{SMALLFONT}{BLACK}安裝新的軌道設計檔案 +STR_3378 :安裝 +STR_3379 :取消 +STR_3380 :無法安裝這個軌道設計 +STR_3381 :不兼容的檔案或含有非法資料 +STR_3382 :複製檔案失敗 +STR_3383 :輸入這個軌道設計的新名稱 +STR_3384 :已有相同名稱的軌道設計 - 請輸入這個軌道設計的新名稱: +STR_3385 :新手入門教學 +STR_3386 :自訂遊樂設施教學 +STR_3387 :雲霄飛車建造教學 +STR_3388 :無法切換至已選擇的模式 +STR_3389 :無法選擇額外的景觀物件... +STR_3390 :選取了太多物件 +# Start of tutorial strings. Not used at the moment, so not necessary to translate. +STR_3391 :{SMALLFONT}{BLACK}這個就是我們的樂園 - 先瞧瞧周邊的環境吧... +STR_3392 :{SMALLFONT}{BLACK}最簡單的方法就是按住滑鼠右鍵, 然後拖曳來移動檢視範圍... +STR_3393 :{SMALLFONT}{BLACK}如果要觀看更多樂園的部份, 你可以按最上工具列中的縮小檢視圖標來縮小檢視... +STR_3394 :{SMALLFONT}{BLACK}你亦可以旋轉90度來檢視... +STR_3395 :{SMALLFONT}{BLACK}這樣的比例下建造東西實在太困難了, 所以我們先還原基本步... +STR_3396 :{SMALLFONT}{BLACK}讓我們一起建造一個簡單的遊樂設施來開放這個樂園吧... +STR_3397 :{SMALLFONT}{BLACK}白色的'鬼影'顯示著建造遊樂設施的地方. 我們移動滑鼠到一個位置, 然後按下左鍵即可建造該遊樂設施... +STR_3398 :{SMALLFONT}{BLACK}遊樂設施需要一個入口及出口. 我們移動滑鼠到一個鄰近遊樂設施的方格, 然後按下左鍵即可建造入口, 然後重覆步驟建造出口... +STR_3399 :{SMALLFONT}{BLACK}為了遊客能享用我們新落成的遊樂設施, 我們需要建造道路連接出入口... +STR_3400 :{SMALLFONT}{BLACK}入口的道路我們可以使用特別的'輪候區'道路... +STR_3401 :{SMALLFONT}{BLACK}至於離開道路, 任何'普通'道路皆可... +STR_3402 :{SMALLFONT}{BLACK}大功告成, 我們可以開啟此遊樂設施了! 要開啟此遊樂設施, 我們需在遊樂設施視窗中按下旗幟圖標, 然後選擇'開啟'... +STR_3403 :{SMALLFONT}{BLACK}但遊客們在哪? +STR_3404 :{SMALLFONT}{BLACK}噢 - 樂園依然是關閉中! 好吧 - 我們去開放樂園... +STR_3405 :{SMALLFONT}{BLACK}當我們等待第一批進入樂園的遊客之時, 先建造一些景物吧... +STR_3406 :{SMALLFONT}{BLACK}又回到初學者教學中那個空空如也的樂園了. 我們將會建造一個簡單的自訂設計遊樂設施... +STR_3407 :{SMALLFONT}{BLACK}首先, 我們需要選擇一個開始的位置... +STR_3408 :{SMALLFONT}{BLACK}剛剛建好的軌道部份為'車站月台', 顧名思義, 即是給遊客上落車的地方... +STR_3409 :{SMALLFONT}{BLACK}我們會加多一點車站月台, 以便擴展月台... +STR_3410 :{SMALLFONT}{BLACK}你可以選擇在建造視窗上方的圖標來建造不同的軌道組合... +STR_3411 :{SMALLFONT}{BLACK}我們會選擇左彎道... +STR_3412 :{SMALLFONT}{BLACK}這個彎道尚未建好, 但白色的鬼影會顯示它建成的位置. 按下在建造視窗的巨型"建造此"按鈕便可建造這個彎道... +STR_3413 :{SMALLFONT}{BLACK}現在我們要建造直向前的軌道, 所以我們就點直向前軌道的圖標... +STR_3414 :{SMALLFONT}{BLACK}現在整個環形軌道就完成了, 我們要建造入口及出口... +STR_3415 :{SMALLFONT}{BLACK}讓我們測試一下這個設施, 看看他能不能運作... +STR_3416 :{SMALLFONT}{BLACK}在它測試的途中, 我們去建造輪候區及連結出口的道路吧... +STR_3417 :{SMALLFONT}{BLACK}OK - 讓我們開放樂園, 同時開放設施吧... +STR_3418 :{SMALLFONT}{BLACK}我們的新遊樂設施好像不會令人太過興奮 - 不如我們來添加點景物吧? +STR_3419 :{SMALLFONT}{BLACK}要在高空中建造景物, 按下SHIFT鍵, 然後移動滑鼠來選擇高度... +STR_3420 :{SMALLFONT}{BLACK}有些景物建造後是可以修改顏色的... +STR_3421 :{SMALLFONT}{BLACK}最後, 我們一起設置這個設施播放音樂吧... +STR_3422 :{SMALLFONT}{BLACK}這次, 讓我們建造一座雲霄飛車! +STR_3423 :{SMALLFONT}{BLACK}這裡有挺多預先設計好的雲霄飛車, 但是我們要建造獨一無二的自訂設計... +STR_3424 :{SMALLFONT}{BLACK}剛剛我們建好了車站月台, 現在我們要建造帶有鏈條的坡道... +STR_3425 :{SMALLFONT}{BLACK}雲霄飛車沒有任何驅動力, 所以'帶有鏈條的坡道'就是用來拉雲霄飛車上第一個斜坡... +STR_3426 :{SMALLFONT}{BLACK}帶有鏈條的坡道建好了 - 現在要建造第一個下坡... +STR_3427 :{SMALLFONT}{BLACK}建造這些彎道是個壞主意 - 當列車急速穿過彎道時, 乘客會被垂直G力所猛推到兩側... +STR_3428 :{SMALLFONT}{BLACK}大幅改善的方法就是傾斜這些彎道 - 橫向G力現在會推乘客到他們的座位, 而不是推到兩側... +STR_3429 :{SMALLFONT}{BLACK}不 - 這不行! 看看高度標記 - 第二個坡現在比第一個高... +STR_3430 :{SMALLFONT}{BLACK}為了確保列車能返回車站, 每個坡都要比上一個矮... +STR_3431 :{SMALLFONT}{BLACK}這樣就好了 - 我們的雲霄飛車應該可以攀上這個坡了! 我們現在試試一些更曲折的軌道吧... +STR_3432 :{SMALLFONT}{BLACK}我們需要在列車進入最後一個彎道及車站前減慢列車, 所以我們要建造一些制動器... +STR_3433 :{SMALLFONT}{BLACK}最後, 我們要建造一些'區間制動器', 以便兩組列車在設施上運行得更安全... +STR_3434 :{SMALLFONT}{BLACK}我們測試一下新的雲霄飛車, 看看它能不能運作吧! +STR_3435 :{SMALLFONT}{BLACK}太好了 - 一切順利! 現在又要做一些熟悉的動作: 建造道路, 然後讓遊客乘坐這座嶄新的雲霄飛車... +STR_3436 :{SMALLFONT}{BLACK}在它迎來第一個乘客的途中, 我們可以自訂化一下這座雲霄飛車... +# End of tutorial strings +STR_3437 :{SMALLFONT}{BLACK}在地形中清理某些大範圍內的景物 +STR_3438 :無法移除這裡所有的景物... +STR_3439 :移除景物 +STR_3440 :頁1 +STR_3441 :頁2 +STR_3442 :頁3 +STR_3443 :頁4 +STR_3444 :頁5 +STR_3445 :設置巡邏區域 +STR_3446 :取得巡邏區域 + +# New strings, cleaner +STR_5120 :財政 +STR_5121 :研發 +STR_5122 :(像RCT1一樣)以軌道類型選擇遊樂設施 +STR_5123 :翻新遊樂設施 +STR_5124 : +STR_5125 :全可拆卸 +STR_5126 :隨機播放主題曲 +STR_5127 :{SMALLFONT}{BLACK}禁止調整地勢 +STR_5128 :選擇大小 +STR_5129 :請輸入介於{COMMA16}及{COMMA16}的選擇大小 +STR_5130 :地圖大小 +STR_5131 :請輸入介於{COMMA16}及{COMMA16}的地圖大小 +STR_5132 :修理好所有遊樂設施 +STR_5133 :{SMALLFONT}{BLACK}選擇較小的土地範圍 +STR_5134 :{SMALLFONT}{BLACK}選擇較大的土地範圍 +STR_5135 :{SMALLFONT}{BLACK}購買土地擁有權或建造權 +STR_5136 :土地擁有權 +STR_5137 :允許鏈條上拉及發車速度高至{VELOCITY} +STR_5138 :{SMALLFONT}{WINDOW_COLOUR_2}{STRINGID} +STR_5139 :{WHITE}{STRINGID} +STR_5140 :去除煞車組件故障 +STR_5141 :去除所有故障機會 +STR_5142 :正常速度 +STR_5143 :快速速度 +STR_5144 :加快速度 +STR_5145 :更快速度 +STR_5146 :超快速度 +STR_5147 :密技 +STR_5148 :{SMALLFONT}{BLACK}改變遊戲速度 +STR_5149 :{SMALLFONT}{BLACK}顯示密技選項 +STR_5150 :啟用除錯工具 +STR_5151 :, +STR_5152 :. +STR_5153 :編輯配色主題... +STR_5154 :使用硬體渲染 +STR_5155 :容許測試未建造好的軌道設計 +STR_5156 :{SMALLFONT}{BLACK}容許測試大部份軌道設計, 即使未建造好的也可以. 但不能適用於區域煞車模式 +STR_5157 :允許設置進入樂園及乘坐遊樂設施的價格 +STR_5158 :回到主選單 +STR_5159 :離開OpenRCT2 +STR_5160 :{POP16}{MONTH} {PUSH16}{PUSH16}{STRINGID}, {POP16}第{COMMA16}年 +STR_5161 :日期格式: +STR_5162 :日/月/年 +STR_5163 :月/日/年 +STR_5164 :Twitch頻道名稱 +STR_5165 :以追隨者的用戶名命名遊客 +STR_5166 :{SMALLFONT}{BLACK}會以Twitch頻道的追隨者命名遊客 +STR_5167 :追蹤'追隨者'遊客 +STR_5168 :{SMALLFONT}{BLACK}會將追隨者用戶名的遊客開啟追蹤資訊 +STR_5169 :以聊天室用戶的名字命名遊客 +STR_5170 :{SMALLFONT}{BLACK}會以Twitch頻道的聊天室用戶的名字命名遊客 +STR_5171 :追蹤'聊天室用戶'遊客 +STR_5172 :{SMALLFONT}{BLACK}會將聊天室用戶名的遊客開啟追蹤資訊 +STR_5173 :將Twitch聊天室的內容推送為新聞 +STR_5174 :{SMALLFONT}{BLACK}會將Twitch聊天室所有標'!news'的內容以最近消息顯示於遊戲內 +STR_5175 :請輸入你的Twitch頻道名稱 +STR_5176 :准許Twitch頻道融合於遊戲之中 +STR_5177 :全屏幕模式: +STR_5178 :{SMALLFONT}{BLACK}顯示用於財政的密技 +STR_5179 :{SMALLFONT}{BLACK}顯示用於遊客的密技 +STR_5180 :{SMALLFONT}{BLACK}顯示用於樂園的密技 +STR_5181 :{SMALLFONT}{BLACK}顯示用於設施的密技 +STR_5182 :{INT32} +STR_5183 :地面高度 +STR_5184 :靖輸入介乎{COMMA16}及{COMMA16}的地面高度 +STR_5185 :水面高度 +STR_5186 :靖輸入介乎{COMMA16}及{COMMA16}的水面高度 +STR_5187 :財政 +STR_5188 :新的營銷計劃 +STR_5189 :研發 +STR_5190 :地圖 +STR_5191 :額外檢視視窗 +STR_5192 :最近消息 +STR_5193 :土地 +STR_5194 :水塘 +STR_5195 :清除景物 +STR_5196 :土地擁有權 +STR_5197 :景物 +STR_5198 :道路 +STR_5199 :建造遊樂設施 +STR_5200 :放置軌道設計 +STR_5201 :新的遊樂設施 +STR_5202 :選擇軌道設計 +STR_5203 :遊樂設施 +STR_5204 :遊樂設施列表 +STR_5205 :遊客 +STR_5206 :遊客列表 +STR_5207 :員工 +STR_5208 :員工列表 +STR_5209 :橫額 +STR_5210 :選取物件 +STR_5211 :研發列表 +STR_5212 :劇情選項 +STR_5213 :目標選項 +STR_5214 :生成地圖 +STR_5215 :軌道設計管理工具 +STR_5216 :軌道設計管理工具列表 +STR_5217 :密技 +STR_5218 :主題 +STR_5219 :選項 +STR_5220 :鍵盤快捷鍵 +STR_5221 :更改鍵盤快捷鍵 +STR_5222 :載入/儲存 +STR_5223 :儲存對話框 +STR_5224 :拆除遊樂設施對話框 +STR_5225 :解僱員工對話框 +STR_5226 :刪除軌道設計對話框 +STR_5227 :覆蓋存檔對話框 +STR_5228 :{SMALLFONT}{BLACK}主界面 +STR_5229 :{SMALLFONT}{BLACK}樂園 +STR_5230 :{SMALLFONT}{BLACK}工具 +STR_5231 :{SMALLFONT}{BLACK}遊樂設施及遊客 +STR_5232 :{SMALLFONT}{BLACK}編輯工具 +STR_5233 :{SMALLFONT}{BLACK}其他 +STR_5234 :{SMALLFONT}{BLACK}彈出視窗 +STR_5235 :{SMALLFONT}{BLACK}設定 +STR_5236 :主題: +STR_5237 :調色盤: +STR_5238 :目前主題: +STR_5239 :複製 +STR_5240 :請輸入這個主題的名稱 +STR_5241 :不能改變這個主題 +STR_5242 :主題名稱已經存在 +STR_5243 :使用了不適合的字符 +STR_5244 :主題 +STR_5245 :頂部工具列 +STR_5246 :底部工具列 +STR_5247 :雲霄飛車設計工具的底部工具列 +STR_5248 :劇情編輯工具的底部工具列 +STR_5249 :主選單的選單按鈕 +STR_5250 :主選單的'離開遊戲'按鈕 +STR_5251 :主選單的'選項'按鈕 +STR_5252 :主選單的'劇情選擇'視窗 +STR_5253 :樂園資訊 +STR_5254 :建立 +STR_5255 :{SMALLFONT}{BLACK}建立全新的主選單動畫 +STR_5256 :建立新的主題, 並作出更改 +STR_5257 :{SMALLFONT}{BLACK}以這個主題作為基礎, 建立新的主題 +STR_5258 :{SMALLFONT}{BLACK}刪除這個主題 +STR_5259 :{SMALLFONT}{BLACK}重命名這個主題 +STR_5260 :巨型截圖 +STR_5261 :過濾 +STR_5262 :瘋狂世界 (WW) +STR_5263 :時空歷險 (TT) +STR_5264 :自訂 +STR_5265 :{SMALLFONT}{BLACK}選擇哪些內容來源的物件為可視 +STR_5266 :{SMALLFONT}{BLACK}顯示 +STR_5267 :{SMALLFONT}{BLACK}語言及單位 +STR_5268 :{SMALLFONT}{BLACK}音效 +STR_5269 :{SMALLFONT}{BLACK}控制及界面 +STR_5270 :{SMALLFONT}{BLACK}其他 +STR_5271 :{SMALLFONT}{BLACK}Twitch +STR_5272 :{SMALLFONT}{BLACK}小型景物 +STR_5273 :{SMALLFONT}{BLACK}大型景物 +STR_5274 :{SMALLFONT}{BLACK}道路 +STR_5275 :搜尋物件 +STR_5276 :請輸入你要搜尋的物件名稱 +STR_5277 :清除 +STR_5278 :沙盒模式 +STR_5279 :沙盒模式關閉 +STR_5280 :{SMALLFONT}{BLACK}允許從地圖視窗中修改土地擁有權, 以及其他平常只適用於劇情編輯工具的選項 +STR_5281 :{SMALLFONT}{BLACK}功能 +STR_5282 :夢幻遊樂場 (RCT1)遊樂設施開關燈號 +STR_5283 :夢幻遊樂場 (RCT1)樂園開關燈號 +STR_5284 :夢幻遊樂場 (RCT1)選擇劇情字體 +STR_5285 :人肉炸彈!!! +STR_5286 :{SMALLFONT}{BLACK}將某些遊客爆炸,嘻嘻! +STR_5287 :遊樂設施已經故障了 +STR_5288 :遊樂設施已關閉了 +STR_5289 :沒有故障可適用於此遊樂設施 +STR_5290 :修復遊樂設施 +STR_5291 :不能強制令遊樂設施故障 +STR_5292 :{SMALLFONT}{BLACK}強制故障 +STR_5293 :{SMALLFONT}{BLACK}關閉遊樂設施/店鋪 +STR_5294 :{SMALLFONT}{BLACK}測試遊樂設施 +STR_5295 :{SMALLFONT}{BLACK}開啟遊樂設施/店鋪 +STR_5296 :{SMALLFONT}{BLACK}關閉樂園 +STR_5297 :{SMALLFONT}{BLACK}開放樂園 +STR_5298 :{RED}{STRINGID} +STR_5299 :{LIGHTPINK}{STRINGID} +STR_5300 :{SMALLFONT}{BLACK}一鍵解僱員工 +STR_5301 :{MEDIUMFONT}{BLACK}付清你的貸款 +STR_5302 :付清貸款 +STR_5303 :暫停時可以建造物件 +STR_5304 :主畫面動畫: +STR_5305 :夢幻遊樂場 (RCT1) +STR_5306 :夢幻遊樂場 (RCT1) (+資料片1 - AA) +STR_5307 :夢幻遊樂場 (RCT1) (+資料片1&2 - AA+LL) +STR_5308 :模擬樂園2 +STR_5309 :OpenRCT2 +STR_5310 :隨機 +STR_5311 :{SMALLFONT}{BLACK}除錯工具 +STR_5312 :顯示命名行 +STR_5313 :顯示地圖網格檢查工具 +STR_5314 :地圖網格檢查工具 +STR_5315 :草地 +STR_5316 :沙地 +STR_5317 :泥地 +STR_5318 :石地 +STR_5319 :火星 +STR_5320 :棋盤 +STR_5321 :雜草叢生草地 +STR_5322 :雪地 +STR_5323 :網格 (紅色) +STR_5324 :網格 (黃色) +STR_5325 :網格 (藍色) +STR_5326 :網格 (綠色) +STR_5327 :沙地 (較暗) +STR_5328 :沙地 (較淺) +STR_5329 :棋盤 (反轉) +STR_5330 :地底檢視模式 +STR_5330 :地底檢視模式 +STR_5331 :石地 +STR_5332 :木地 (紅色) +STR_5333 :木地 (黑色) +STR_5334 :雪地 +STR_5335 :遊樂設施入口 +STR_5336 :遊樂設施出口 +STR_5337 :樂園入口 +STR_5338 :元素類別 +STR_5339 :地面高度 +STR_5340 :清理高度 +STR_5341 :標記 +STR_5342 :請選擇地圖網格 +STR_5343 :自動放置員工 +STR_5344 :更新日誌 +STR_5345 :用於財政的密技 +STR_5346 :用於遊客的密技 +STR_5347 :用於樂園的密技 +STR_5348 :用於設施的密技 +STR_5349 :{SMALLFONT}{BLACK}所有遊樂設施 +STR_5350 :最高 +STR_5351 :最低 +STR_5352 :{BLACK}快樂度: +STR_5353 :{BLACK}體力: +STR_5354 :{BLACK}飢餓度: +STR_5355 :{BLACK}口渴度: +STR_5356 :{BLACK}噁心度: +STR_5357 :{BLACK}噁心忍受程度: +STR_5358 :{BLACK}如廁度: +STR_5359 :移除遊客 +STR_5360 :{SMALLFONT}{BLACK}移除地圖上所有遊客 +STR_5361 :給予全部遊客: +STR_5362 :{BLACK}設置所有遊客對遊樂設施的偏好刺激度為: +STR_5363 :高於1 +STR_5364 :低於15 +STR_5365 :{BLACK}員工行走速度: +STR_5366 :正常 +STR_5367 :快速 +STR_5368 :重設毀壞狀態 +STR_5369 :樂園參數... +STR_5370 :{SMALLFONT}{BLACK}按此來修改樂園參數{NEWLINE}例如關於限制, 生成遊客{NEWLINE}及金錢的選項 +STR_5371 :選取物件 +STR_5372 :滑鼠左鍵拖拉 +STR_5373 :名稱 {STRINGID} +STR_5374 :日期 {STRINGID} +STR_5375 :{UP} +STR_5376 :{DOWN} +STR_5377 :{SMALLFONT}{BLACK}儲存 +STR_5378 :{SMALLFONT}{BLACK}主選單動畫劇本 +STR_5379 :{SMALLFONT}{BLACK}跳至下一個等待(Wait)命令 +STR_5380 :{SMALLFONT}{BLACK}開始播放此選單動畫 +STR_5381 :{SMALLFONT}{BLACK}停止播放此主選單動畫 +STR_5382 :{SMALLFONT}{BLACK}重新開始播放此主選單動畫 +STR_5383 :{SMALLFONT}{BLACK}以這個主選單動畫作為基礎, 建立新的主選單動畫 +STR_5384 :{SMALLFONT}{BLACK}刪除這個主選單動畫 +STR_5385 :{SMALLFONT}{BLACK}重命名這個主選單動畫 +STR_5386 :{SMALLFONT}{BLACK}插入新的命令 +STR_5387 :{SMALLFONT}{BLACK}編輯選中的命令 +STR_5388 :{SMALLFONT}{BLACK}刪除選中的命令 +STR_5389 :{SMALLFONT}{BLACK}將播放中的主選單動畫跳至選中的命令 +STR_5390 :{SMALLFONT}{BLACK}將選中的命令移到下方 +STR_5391 :{SMALLFONT}{BLACK}將選中的命令移到上方 +STR_5392 :{SMALLFONT}{BLACK}添加存檔到此主選單動畫 +STR_5393 :{SMALLFONT}{BLACK}從此主選單動畫中移除選中的存檔 +STR_5394 :{SMALLFONT}{BLACK}重命名選中的存檔 +STR_5395 :{SMALLFONT}{BLACK}載入選中的存檔 +STR_5396 :{SMALLFONT}{BLACK}重新載入此主選單動畫劇本, 以便顯示在遊戲外作出的改變 +STR_5397 :只可以用於主選單中 +STR_5398 :不能在主選單動畫時編輯其劇本 +STR_5399 :按'暫停'按鈕繼續編輯 +STR_5400 :不能更改此主選單動畫 +STR_5401 :建立新的主選單動畫, 並作出更改 +STR_5402 :載入主選單動畫失敗 +STR_5403 :非法的存檔或沒有'Load'或'Wait'指令 +STR_5404 :名稱已經存在 +STR_5405 :請輸入存檔名稱 +STR_5406 :請輸入主選單動畫存檔名稱 +STR_5407 :增加 +STR_5408 :移除 +STR_5409 :插入 +STR_5410 :編輯 +STR_5411 :重新載入 +STR_5412 :跳至 +STR_5413 :載入 +STR_5414 :載入{MOVE_X}{87}Six Flags Magic Mountain.SC6 +STR_5415 :載入{MOVE_X}{87}{STRING} +STR_5416 :載入{MOVE_X}{87}無存檔被選中 +STR_5417 :定位 +STR_5418 :定位{MOVE_X}{87}{COMMA16} {COMMA16} +STR_5419 :旋轉 +STR_5420 :旋轉{MOVE_X}{87}{COMMA16} +STR_5421 :放大 +STR_5422 :放大{MOVE_X}{87}{COMMA16} +STR_5423 :等候 +STR_5424 :等候{MOVE_X}{87}{COMMA16} +STR_5425 :重新開始 +STR_5426 :結束 +STR_5427 :座標: +STR_5428 :逆時計轉動次數: +STR_5429 :放大等級: +STR_5430 :等待秒數: +STR_5431 :要載入的存檔: +STR_5432 :命令: +STR_5433 :主選單動畫 +STR_5434 :命令編輯工具 +STR_5435 :重命名存檔 +STR_5436 :修改主選單動畫... +STR_5437 :暫無存檔被選中 +STR_5438 :當命令編輯工具開啟不能作出改變 +STR_5439 :4秒以上的等待(Wait)命令需要加上重新開始(Restart)命令 +STR_5440 :當焦點失去時最小化全螢幕的遊戲 +STR_5441 :{SMALLFONT}{BLACK}以軌道類別分別遊樂設施,{NEWLINE}令到車輔風格可以在建造後更改,{NEWLINE}就像夢幻遊樂園1(RCT1)一樣. +STR_5442 :固定樂園評價: +STR_5443 :速度{MOVE_X}{87}{STRINGID} +STR_5444 :速度: +STR_5445 :速度 +STR_5446 :獲取 +STR_5447 :類別 {STRINGID} +STR_5448 :遊樂設施/車輛 {STRINGID} +STR_5449 :減慢遊戲速度 +STR_5450 :增快遊戲速度 +STR_5451 :開啟密技視窗 +STR_5452 :調整工具列的可視度 +STR_5453 :選擇另一類遊樂設施 +STR_5454 :去除FPS上限 +STR_5455 :啟用沙盒模式 +STR_5456 :去除阻礙檢查 +STR_5457 :去除支撐限制 +STR_5458 :順時計旋轉 +STR_5459 :逆時計旋轉 +STR_5460 :逆時針旋轉檢視範圍 +STR_5461 :設置遊客的屬性 +STR_5462 :{CURRENCY} +STR_5463 :目標: 盡情玩吧! +STR_5464 :一般 +STR_5465 :氣候 +STR_5466 :員工 +STR_5467 :ALT + +STR_5468 :最近消息 +STR_5469 :向上捲動地圖 +STR_5470 :向左捲動地圖 +STR_5471 :向下捲動地圖 +STR_5472 :向右捲動地圖 +STR_5473 :循環日與夜 +STR_5474 :於橫額中顯示全大寫英文 +STR_5475 :{COMMA16}週 +STR_5476 :硬件 +STR_5477 :地圖顯示 +STR_5478 :控制 +STR_5479 :工具列 +STR_5480 :顯示工具列按鈕: +STR_5481 :主題 +STR_5482 :{WINDOW_COLOUR_2}上次檢查時間: {BLACK} 1分鐘前 +STR_5483 :{BLACK}(還剩{COMMA16}週結束) +STR_5484 :{BLACK}(還剩{COMMA16}週結束) +STR_5485 :{SMALLFONT}{STRING} +STR_5486 :{BLACK}{COMMA16} +STR_5487 :{SMALLFONT}{BLACK}顯示最近消息 +STR_5488 :隱藏入口 (只適用於OpenRCT2!) +STR_5489 :{SMALLFONT}{BLACK}只顯示追蹤中的遊客 +STR_5490 :失去焦點時靜音 +STR_5491 :研發列表 +STR_5492 :劇情選項 +STR_5493 :發送訊息 +STR_5494 : +STR_5495 :玩家列表 +STR_5496 :玩家: +STR_5497 :延遲值 (Ping): +STR_5498 :伺服器列表 +STR_5499 :玩家名稱: +STR_5500 :新增伺服器 +STR_5501 :開始伺服器 +STR_5502 :多人連線模式 +STR_5503 :請輸入主機名稱或IP地址: +STR_5504 :{SMALLFONT}{BLACK}顯示多人連線狀態 +STR_5505 :無法連接至伺服器. +STR_5506 :遊客無視設施的刺激度 +STR_5507 :預設清潔工人會修剪草皮 +STR_5508 :允許載入校驗失敗的檔案 +STR_5509 :{SMALLFONT}{BLACK}允許載入校驗失敗的劇情及存檔, 例如試玩版的劇情或已損壞的存檔. +STR_5510 :預設聲效裝置 +STR_5511 :(未知) +STR_5512 :另存遊戲 +STR_5513 :(快速)儲存遊戲 +STR_5514 :禁止設施被刻意毀壞 +STR_5515 :{SMALLFONT}{BLACK}禁止遊客憤怒時刻意毀壞公眾物件的行為 +STR_5516 :{SMALLFONT}{BLACK}黑色 +STR_5517 :{SMALLFONT}{BLACK}白色 +STR_5518 :{SMALLFONT}{BLACK}灰色 +STR_5519 :{SMALLFONT}{BLACK}暗紫色 +STR_5520 :{SMALLFONT}{BLACK}淺紫色 +STR_5521 :{SMALLFONT}{BLACK}明紫色 +STR_5522 :{SMALLFONT}{BLACK}暗藍色 +STR_5523 :{SMALLFONT}{BLACK}淺藍色 +STR_5524 :{SMALLFONT}{BLACK}冰藍色 +STR_5525 :{SMALLFONT}{BLACK}深水配色 +STR_5526 :{SMALLFONT}{BLACK}淺水配色 +STR_5527 :{SMALLFONT}{BLACK}深綠色 +STR_5528 :{SMALLFONT}{BLACK}暗綠色 +STR_5529 :{SMALLFONT}{BLACK}苔蘚綠色 +STR_5530 :{SMALLFONT}{BLACK}明綠色 +STR_5531 :{SMALLFONT}{BLACK}橄欖綠色 +STR_5532 :{SMALLFONT}{BLACK}暗橄欖綠色 +STR_5533 :{SMALLFONT}{BLACK}明黃色 +STR_5534 :{SMALLFONT}{BLACK}黃色 +STR_5535 :{SMALLFONT}{BLACK}暗黃色 +STR_5536 :{SMALLFONT}{BLACK}淺橙色 +STR_5537 :{SMALLFONT}{BLACK}暗橙色 +STR_5538 :{SMALLFONT}{BLACK}淺啡色 +STR_5539 :{SMALLFONT}{BLACK}深啡色 +STR_5540 :{SMALLFONT}{BLACK}暗啡色 +STR_5541 :{SMALLFONT}{BLACK}淺鮭紅色 +STR_5542 :{SMALLFONT}{BLACK}紅酒色 +STR_5543 :{SMALLFONT}{BLACK}深紅色 +STR_5544 :{SMALLFONT}{BLACK}明紅色 +STR_5545 :{SMALLFONT}{BLACK}暗粉紅色 +STR_5546 :{SMALLFONT}{BLACK}明粉紅色 +STR_5547 :{SMALLFONT}{BLACK}淺粉紅色 +STR_5548 :顯示所有運作模式 +STR_5549 :年/月/日 +STR_5550 :{POP16}{POP16}第{COMMA16}年, {PUSH16}{PUSH16}{MONTH} {PUSH16}{PUSH16}{STRINGID} +STR_5551 :年/日/月 +STR_5552 :{POP16}{POP16}第{COMMA16}年, {PUSH16}{PUSH16}{PUSH16}{STRINGID} {MONTH} +STR_5553 :當Steam overlay開啟時暫停遊戲 +STR_5554 :{SMALLFONT}{BLACK}啟用山丘工具 +STR_5555 :顯示來自其他類型軌道的車輛種類 +STR_5556 :踢走玩家 +STR_5557 :多人遊戲不同步時依然保持連線 +STR_5558 :此設定會於重啟遊戲後生效 +STR_5559 :檢查時距為10分鐘 +STR_5560 :將所有遊樂設施的檢查時距設定為'每10分鐘' +STR_5561 :載入語言失敗 +STR_5562 :警告! +STR_5563 :此功能暫未穩定地使用, 請多加留意. +STR_5564 :插入已損壞元素 +STR_5565 :{SMALLFONT}{BLACK}在一個網格的最上插入一個已損壞的地圖元素. 此插入會隱藏其他元素. +STR_5566 :密碼: +STR_5567 :推廣 +STR_5568 :輸入密碼 +STR_5569 :此伺服器被密碼保護 +STR_5570 :索取伺服器 +STR_5571 :加入遊戲 +STR_5572 :加入最愛 +STR_5573 :由最愛中移除 +STR_5574 :伺服器名稱: +STR_5575 :最多玩家數: +STR_5576 :連接埠: +STR_5577 :南韓園 (₩) +STR_5578 :俄羅斯盧布 (R) +STR_5579 :顥示縮放因子: +STR_5580 :捷克克朗 (Kc) + + +##################### +# Rides/attractions # +##################### +############################################################################### +## RCT2 Objects +############################################################################### +[AML1] +STR_NAME :美式蒸氣火車 +STR_DESC :配備著復刻蒸氣火車頭及煤水車的小型蒸氣火車, 拉著帶有帆布車頂的木製車廂 +STR_CPTY :每車廂6個乘客 + +[CLIFT1] +STR_NAME :纜車車卡 +STR_DESC :供纜車使用的開放式車卡 +STR_CPTY :每車卡2個乘客 + +[CLIFT2] +STR_NAME :登頂滑雪纜車車椅 +STR_DESC :供纜車使用的開放式車卡 +STR_CPTY :每車卡2個乘客 + +[LIFT1] +STR_NAME :升降機 +STR_DESC :遊客乘搭升降機上下穿梭於垂直的管道中, 並借此訪問另一層 +STR_CPTY :16個乘客 + +[MONO1] +STR_NAME :流線型單軌電車 +STR_DESC :大載客量的單軌電車, 車頭車尾都配備著流線型設計 +STR_CPTY :每車卡5或10個乘客 + +[MONO2] +STR_NAME :小型單軌電車 +STR_DESC :附有開放式側邊的小型單軌電車 +STR_CPTY :每車卡4個乘客 + +[MONO3] +STR_NAME :懷舊風格單軌電車 +STR_DESC :使用開放式設計車廂的單軌電車 +STR_CPTY :每車卡4個乘客 + +[NRL] +STR_NAME :蒸氣火車 +STR_DESC :配備著復刻蒸氣火車頭及煤水車的小型蒸氣火車, 拉著開放式的木製車廂 +STR_CPTY :每車廂6個乘客 + +[NRL2] +STR_NAME :有蓋蒸氣火車 +STR_DESC :配備著復刻蒸氣火車頭及煤水車的小型蒸氣火車, 拉著帶有織布車頂的木製車廂 +STR_CPTY :每車廂6個乘客 + +[SMONO] +STR_NAME :懸掛式單軌電車 +STR_DESC :大載客量的單軌電車 +STR_CPTY :每車卡8個乘客 + +[TRAM1] +STR_NAME :電車 +STR_DESC :復刻的懷舊電車 +STR_CPTY :每車卡10個乘客 + +[4X4] +STR_NAME :怪獸卡車 +STR_DESC :能爬上陡斜坡道, 而且帶有動力的巨型4 x 4卡車 +STR_CPTY :每卡車2個乘客 + +[CHBUILD] +STR_NAME :古怪屋 +STR_DESC :一座建築物, 含有扭曲房間及傾斜走道使人於行走中失去方向感 +STR_CPTY :5個遊客 + +[CIRCUS1] +STR_NAME :馬戲團 +STR_DESC :於大型帳幕內進行動物馬戲團表演 +STR_CPTY :30個遊客 + +[CTCAR] +STR_NAME :笑臉貓遊 +STR_DESC :帶有動力的貓班車輛跟隨著軌道的路線遊覽周邊 +STR_CPTY :每輛車2個乘客 + +[DODG1] +STR_NAME :碰碰車 +STR_DESC :自助駕駛的電力碰碰車 +STR_CPTY :每車輛1個乘客 + +[FSAUC] +STR_NAME :碰碰飛碟 +STR_DESC :自助駕駛的飛碟型車輛 +STR_CPTY :每飛碟1個乘客 + +[FWH1] +STR_NAME :摩天輪 +STR_DESC :不斷旋轉, 附有露天座椅的巨大輪環 +STR_CPTY :32乘客 + +[GOLF1] +STR_NAME :迷你高爾夫 +STR_DESC :一個溫和的迷你高爾夫遊戲 +STR_CPTY : + +#WW +[CONDORRD] +STR_NAME :神鷹暢遊 +STR_DESC :乘客乘坐於軌道下的神鷹造型列車上, 將會於飛馳中體驗飛一般的快感 +STR_CPTY :每車卡4個乘客 diff --git a/data/language/czech.txt b/data/language/czech.txt new file mode 100644 index 0000000000..36d9d08486 --- /dev/null +++ b/data/language/czech.txt @@ -0,0 +1,3929 @@ +# 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 :Spirálová horská dráha +STR_0003 :Horská dráha ve stoje +STR_0004 :Závěsná houpající se horská dráha +STR_0005 :Obrácená horská dráha +STR_0006 :Dorostenecká horská dráha +STR_0007 :Miniaturní železnice +STR_0008 :Vysutá jednokolejka +STR_0009 :Malá zavěsná dráha +STR_0010 :Lodní dráha +STR_0011 :Divoká myš +STR_0012 :Překážkový dostih +STR_0013 :Automobilová dráha +STR_0014 :Vystřelovaný volný pád +STR_0015 :Bobová dráha +STR_0016 :Vyhlídková věž +STR_0017 :Smyčkující horská dráha +STR_0018 :Sjezd na člunech +STR_0019 :Dráha důlního vlaku +STR_0020 :Lanovka +STR_0021 :Vývrtková horská dráha +STR_0022 :Bludiště +STR_0023 :Točitá skluzavka +STR_0024 :Motokáry +STR_0025 :Žlab s kládamy +STR_0026 :Říční peřeje +STR_0027 :Autodrom +STR_0028 :Pirátská loď +STR_0029 :Houpací obracecí loď +STR_0030 :Stánek s jídlem +STR_0031 :Neznámý obchod (1D) +STR_0032 :Stánek s pitím +STR_0033 :Neznámý obchod (1F) +STR_0034 :Obchod +STR_0035 :Merry-Go-Round +STR_0036 :Neznámý obchod (22) +STR_0037 :Informačí kiosek +STR_0038 :Toalety +STR_0039 :Ruské kolo +STR_0040 :Simulátor pohybu +STR_0041 :3D Kino +STR_0042 :Top Spin +STR_0043 :Space Rings +STR_0044 :Reverse Freefall Coaster +STR_0045 :Výtah +STR_0046 :Vertical Drop Roller Coaster +STR_0047 :Bankomat +STR_0048 :Twist +STR_0049 :Strašidelný dům +STR_0050 :První pomoc +STR_0051 :Cirkus +STR_0052 :Vlak duchů +STR_0053 :Steel Twister Roller Coaster +STR_0054 :Dřevěná horská dráha +STR_0055 :Side-Friction Roller Coaster +STR_0056 :Divoká myš +STR_0057 :Mnohorozměrná horská dráha +STR_0058 :Neznámá atrakce (38) +STR_0059 :Létající horská dráha +STR_0060 :Neznámá atrakce (3A) +STR_0061 :VIrginský moták +STR_0062 :Cákající lodě +STR_0063 :Mini helikoptéra +STR_0064 :HOrská dráha v leže +STR_0065 :Vysutá jednokolejka +STR_0066 :Neznámá atrakce (40) +STR_0067 :Obrácená horská dráha +STR_0068 :Heartline Twister Coaster +STR_0069 :Mini Golf +STR_0070 :Obří dráha +STR_0071 :Roto-Drop +STR_0072 :Létající talíř +STR_0073 :Křivý dům +STR_0074 :Jenostopá kola +STR_0075 :Compact Inverted Coaster +STR_0076 :Vodní dráha +STR_0077 :Air Powered Vertical Coaster +STR_0078 :Inverted Hairpin Coaster +STR_0079 :Kouzelný koberec +STR_0080 :Podmořská jízda +STR_0081 :Rafty +STR_0082 :Neznámá atrakce (50) +STR_0083 :Enterprise +STR_0084 :Neznámá atrakce (52) +STR_0085 :Neznámá atrakce (53) +STR_0086 :Neznámá atrakce (54) +STR_0087 :Neznámá atrakce (55) +STR_0088 :Inverted Impulse Coaster +STR_0089 :Malá horská dráha +STR_0090 :Mini dráha +STR_0091 :Neznámá atrakce (59) +STR_0092 :LIM Launched Roller Coaster +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 :A compact roller coaster with a spiral lift hill and smooth, twisting drops. +STR_0513 :Horská dráha se smyčkami na které se jezdí ve stoje +STR_0514 :Vlaky zavješené pod kolejí se v zatáčkách houpají do stran +STR_0515 :Ocelová horská dráha s vlaky držícími zespod tratí, s mnoha složitími a otáčivímy prvky +STR_0516 :Pozvolná horská dráha pro ty kdo se zatím neodvažují na větší dráhy +STR_0517 :Pasažeři jedou v miniaturních vlacích po úzkorozchodné koleji. +STR_0518 :Cestujíci jedou v elektických vlacích po vysuté jednokolejné dráze. +STR_0519 :Cestujíci jedou zavěšení pod jednou kolejí v malích kabinách, volně se houpajících ze strany na stranu +STR_0520 :Přístavní molo kde hosté mohou řídit osobní plavidlo na vodní hladině +STR_0521 :Rychlá a mrštná horská dráha s ostrými zákrutami a strmími svahy. Dráha je předurčená k vysoké intensitě. +STR_0522 :Menší horská dráha na které hosté sedí nad dráhou bez kabiny kolem sebe +STR_0523 :Hosté jedou pomalu v hnaných vozidlech po určené trati. +STR_0524 :Kabina Freefall je pneumaticky vstřelena nahorů po vysoké ocelové věži a pak padá zpět volným pádem +STR_0525 :Riders career down a twisting track guided only by the curvature and banking of the semi-circular track +STR_0526 :Pasažéři jsou v otáčející se rozhledně která vyjede na vysokou věž +STR_0527 :Plynulá ocelová pásová horská dráha schopná vertikálních smyček +STR_0528 :Hosté sjíždí v nafukovacích člunech zatáčejícím korytem nebo uzavřenou trubicí +STR_0529 :Ocelová horská dráha ve stylu důlního vlaku s věrnými důlními kolejemi. +STR_0530 :Kabiny vysí na ocelovém laně které nepřetržitě jede z jednoho konce na druhý a zpět +STR_0531 :Kompaktní ocelová horská dráha na které vlak projíždí smyčky a vývrtky +STR_0532 : +STR_0533 : +STR_0534 :Hosté sami řídí benzínové motokáry +STR_0535 :Lodě ve tvaru klády jedou po vodní kanále, splavujíse se po strmích kopcích. Žádny host nezůstane suchý. +STR_0536 :Loď pluje po šírokých maeandrech, přes stříkající vodpoády a po vzrušujících pěnících přejích +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 :The car is accelerated out of the station along a long level track using Linear Induction Motors, then heads straight up a vertical spike of track, freefalling back down to return to the station +STR_0555 :Hosté jedou ve výtahu nahoů nebo dolů ve svislé věži aby se dostaly z jedné výsky do jiné +STR_0556 :Extra široké vozy se vrhaji střemhlav dolů za zážitky úplného volného pádu na horské dráze +STR_0557 : +STR_0558 : +STR_0559 : +STR_0560 : +STR_0561 : +STR_0562 :Hnané vozy jedou po několika-patrové dráze plné strašidelných kulis a speciálních efektů +STR_0563 :Sitting in comfortable trains with only simple lap restraints riders enjoy giant smooth drops and twisting track as well as plenty of 'air time' over the hills +STR_0564 :Při jízdou po dřevěné dráze je tato horská dráha rychlá, drsná, hlučná a poskytuje pocit „vymuknutí řízení“ s mnoha „pocity beztíže“ +STR_0565 :Jednoduchá dřevěná horská tráha schopná jen mírných kopců a zatáček, na které je vůz držen jen bočnímy kolečky a gravitací +STR_0566 :Individual roller coaster cars zip around a tight zig-zag layout of track with sharp corners and short sharp drops +STR_0567 :Sitting in seats suspended either side of the track, riders are pitched head-over-heels while they plunge down steep drops and travel through various inversions +STR_0568 : +STR_0569 :Jíza ve speciálních postrojích zavěšených pod tratí, poskytuje pocit letu, jako když se vrhnete do prázdna +STR_0570 : +STR_0571 :Kulaté vozy se otáčeí dokola tím jak projíždějí dřevěnou klikatou tratí +STR_0572 :Lodě s velkou kapacitou jedou po širokém vodním kanále, vzhůru poháněné bežícím pásem, zrychlují z prudkých svahů aby obrovským šplouchnutím namočili všechny hosty +STR_0573 :Hnané vozy ve tvaru helikoptér jedou na ocelové trati +STR_0574 :Hosté ve speciálních postrojích zavěšení v leže pod tratí, jedou přes zákruty a obraty pozadu nebo čelem k zemi +STR_0575 :Poháněné vlaky vysící pod vysuto kolejí převážejí lidi po parku +STR_0576 : +STR_0577 :Vozy s dvěma podvozky jedou po dřevěné trati, otáčející se dokola na speciálních místech +STR_0578 :Cars run along track enclosed by circular hoops, traversing steep drops and heartline twists +STR_0579 : +STR_0580 :Obrovská ocelová horská dráha s hladkými obraty a svahy přes 90 metrů +STR_0581 :Kruh sedadel je za pomalého otáčení vyzdvyhnut na vrchol věže, poté se vrátí volným pádem a postupně zastaví ve stanici pomocí magnetických brzd +STR_0582 : +STR_0583 : +STR_0584 :Speciální kola jezdí po ocelové koleji, poháněná šlapáním jezdců +STR_0585 :Riders sit in pairs of seats suspended beneath the track as they loop and twist through tight inversions +STR_0586 :Boat shaped cars run on roller coaster track to allow twisting curves and steep drops, splashing down into sections of water for gentle river sections +STR_0587 :After an exhilarating air-powered launch, the train speeds up a vertical track, over the top, and vertically down the other side to return to the station +STR_0588 :Individual cars run beneath a zig-zagging track with hairpin turns and sharp drops +STR_0589 : +STR_0590 :Riders ride in a submerged submarine through an underwater course +STR_0591 :Raft-shaped boats gently meander around a river track +STR_0592 : +STR_0593 : +STR_0594 : +STR_0595 : +STR_0596 : +STR_0597 : +STR_0598 :Inverted roller coaster trains are accelerated out of the station to travel up a vertical spike of track, then reverse back through the station to travel backwards up another vertical spike of track +STR_0599 :A compact roller coaster with individual cars and smooth twisting drops +STR_0600 :Powered mine trains career along a smooth and twisted track layout +STR_0601 : +STR_0602 :Roller coaster trains are accelerated out of the station by linear induction motors to speed through twisting inversions +STR_0603 :Host {INT32} +STR_0604 :Host {INT32} +STR_0605 :Host {INT32} +STR_0606 :Host {INT32} +STR_0607 :Host {INT32} +STR_0608 :Host {INT32} +STR_0609 :Host {INT32} +STR_0610 :Host {INT32} +STR_0611 :Host {INT32} +STR_0612 :Host {INT32} +STR_0613 :Host {INT32} +STR_0614 :Host {INT32} +STR_0615 :Host {INT32} +STR_0616 :Host {INT32} +STR_0617 :Host {INT32} +STR_0618 :Host {INT32} +STR_0619 :Host {INT32} +STR_0620 :Host {INT32} +STR_0621 :Host {INT32} +STR_0622 :Host {INT32} +STR_0623 :Host {INT32} +STR_0624 :Host {INT32} +STR_0625 :Host {INT32} +STR_0626 :Host {INT32} +STR_0627 :Host {INT32} +STR_0628 :Host {INT32} +STR_0629 :Host {INT32} +STR_0630 :Host {INT32} +STR_0631 :Host {INT32} +STR_0632 :Host {INT32} +STR_0633 :Host {INT32} +STR_0634 :Host {INT32} +STR_0635 :Host {INT32} +STR_0636 :Host {INT32} +STR_0637 :Host {INT32} +STR_0638 :Host {INT32} +STR_0639 :Host {INT32} +STR_0640 :Host {INT32} +STR_0641 :Host {INT32} +STR_0642 :Host {INT32} +STR_0643 :Host {INT32} +STR_0644 :Host {INT32} +STR_0645 :Host {INT32} +STR_0646 :Host {INT32} +STR_0647 :Host {INT32} +STR_0648 :Host {INT32} +STR_0649 :Host {INT32} +STR_0650 :Host {INT32} +STR_0651 :Host {INT32} +STR_0652 :Host {INT32} +STR_0653 :Host {INT32} +STR_0654 :Host {INT32} +STR_0655 :Host {INT32} +STR_0656 :Host {INT32} +STR_0657 :Host {INT32} +STR_0658 :Host {INT32} +STR_0659 :Host {INT32} +STR_0660 :Host {INT32} +STR_0661 :Host {INT32} +STR_0662 :Host {INT32} +STR_0663 :Host {INT32} +STR_0664 :Host {INT32} +STR_0665 :Host {INT32} +STR_0666 :Host {INT32} +STR_0667 :Host {INT32} +STR_0668 :Host {INT32} +STR_0669 :Host {INT32} +STR_0670 :Host {INT32} +STR_0671 :Host {INT32} +STR_0672 :Host {INT32} +STR_0673 :Host {INT32} +STR_0674 :Host {INT32} +STR_0675 :Host {INT32} +STR_0676 :Host {INT32} +STR_0677 :Host {INT32} +STR_0678 :Host {INT32} +STR_0679 :Host {INT32} +STR_0680 :Host {INT32} +STR_0681 :Host {INT32} +STR_0682 :Host {INT32} +STR_0683 :Host {INT32} +STR_0684 :Host {INT32} +STR_0685 :Host {INT32} +STR_0686 :Host {INT32} +STR_0687 :Host {INT32} +STR_0688 :Host {INT32} +STR_0689 :Host {INT32} +STR_0690 :Host {INT32} +STR_0691 :Host {INT32} +STR_0692 :Host {INT32} +STR_0693 :Host {INT32} +STR_0694 :Host {INT32} +STR_0695 :Host {INT32} +STR_0696 :Host {INT32} +STR_0697 :Host {INT32} +STR_0698 :Host {INT32} +STR_0699 :Host {INT32} +STR_0700 :Host {INT32} +STR_0701 :Host {INT32} +STR_0702 :Host {INT32} +STR_0703 :Host {INT32} +STR_0704 :Host {INT32} +STR_0705 :Host {INT32} +STR_0706 :Host {INT32} +STR_0707 :Host {INT32} +STR_0708 :Host {INT32} +STR_0709 :Host {INT32} +STR_0710 :Host {INT32} +STR_0711 :Host {INT32} +STR_0712 :Host {INT32} +STR_0713 :Host {INT32} +STR_0714 :Host {INT32} +STR_0715 :Host {INT32} +STR_0716 :Host {INT32} +STR_0717 :Host {INT32} +STR_0718 :Host {INT32} +STR_0719 :Host {INT32} +STR_0720 :Host {INT32} +STR_0721 :Host {INT32} +STR_0722 :Host {INT32} +STR_0723 :Host {INT32} +STR_0724 :Host {INT32} +STR_0725 :Host {INT32} +STR_0726 :Host {INT32} +STR_0727 :Host {INT32} +STR_0728 :Host {INT32} +STR_0729 :Host {INT32} +STR_0730 :Host {INT32} +STR_0731 :Host {INT32} +STR_0732 :Host {INT32} +STR_0733 :Host {INT32} +STR_0734 :Host {INT32} +STR_0735 :Host {INT32} +STR_0736 :Host {INT32} +STR_0737 :Host {INT32} +STR_0738 :Host {INT32} +STR_0739 :Host {INT32} +STR_0740 :Host {INT32} +STR_0741 :Host {INT32} +STR_0742 :Host {INT32} +STR_0743 :Host {INT32} +STR_0744 :Host {INT32} +STR_0745 :Host {INT32} +STR_0746 :Host {INT32} +STR_0747 :Host {INT32} +STR_0748 :Host {INT32} +STR_0749 :Host {INT32} +STR_0750 :Host {INT32} +STR_0751 :Host {INT32} +STR_0752 :Host {INT32} +STR_0753 :Host {INT32} +STR_0754 :Host {INT32} +STR_0755 :Host {INT32} +STR_0756 :Host {INT32} +STR_0757 :Host {INT32} +STR_0758 :Host {INT32} +STR_0759 :Host {INT32} +STR_0760 :Host {INT32} +STR_0761 :Host {INT32} +STR_0762 :Host {INT32} +STR_0763 :Host {INT32} +STR_0764 :Host {INT32} +STR_0765 :Host {INT32} +STR_0766 :Host {INT32} +STR_0767 :Host {INT32} +STR_0768 :Uklizeč {INT32} +STR_0769 :Technik {INT32} +STR_0770 :Hlídač {INT32} +STR_0771 :Bavič {INT32} +STR_0772 :Nepojmenovaný park{POP16}{POP16} +STR_0773 :Nepojmenovaný park{POP16}{POP16} +STR_0774 :Nepojmenovaný park{POP16}{POP16} +STR_0775 :Nepojmenovaný park{POP16}{POP16} +STR_0776 :Nepojmenovaný park{POP16}{POP16} +STR_0777 :Nepojmenovaný park{POP16}{POP16} +STR_0778 :Nápis +STR_0779 :1. +STR_0780 :2. +STR_0781 :3. +STR_0782 :4. +STR_0783 :5. +STR_0784 :6. +STR_0785 :7. +STR_0786 :8. +STR_0787 :9. +STR_0788 :10. +STR_0789 :11. +STR_0790 :12. +STR_0791 :13. +STR_0792 :14. +STR_0793 :15. +STR_0794 :16. +STR_0795 :17. +STR_0796 :18. +STR_0797 :19. +STR_0798 :20. +STR_0799 :21. +STR_0800 :22. +STR_0801 :23. +STR_0802 :24. +STR_0803 :25. +STR_0804 :26. +STR_0805 :27. +STR_0806 :28. +STR_0807 :29. +STR_0808 :30. +STR_0809 :31. +STR_0810 :Jan +STR_0811 :Feb +STR_0812 :Mar +STR_0813 :Apr +STR_0814 :May +STR_0815 :Jun +STR_0816 :Jul +STR_0817 :Aug +STR_0818 :Sep +STR_0819 :Oct +STR_0820 :Nov +STR_0821 :Dec +STR_0822 :Nedostupný grafický soubor +STR_0823 :Chybějicí nebo nedostupný soubor +STR_0824 :{BLACK}{CROSS} +STR_0825 :Zvolené jméno je již používáno +STR_0826 :Definováno příliš mnoho jmen +STR_0827 :Nedostatek financí - potřeba {CURRENCY2DP} +STR_0828 :{SMALLFONT}{BLACK}Zavřít okno +STR_0829 :{SMALLFONT}{BLACK}Window title - Drag this to move window +STR_0830 :{SMALLFONT}{BLACK}Přiblížit pohled +STR_0831 :{SMALLFONT}{BLACK}ZOddálit pohled +STR_0832 :{SMALLFONT}{BLACK}Otočit o 90{DEGREE} po směru hodinových ručiček +STR_0833 :{SMALLFONT}{BLACK}Pozastavit hru +STR_0834 :{SMALLFONT}{BLACK}Disk and game options +STR_0835 :Game initialisation failed +STR_0836 :Nelze spustit hru minimalizovanou. +STR_0837 :Unable to initialise graphics system +STR_0838 : +STR_0839 :{UINT16} x {UINT16} +STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +STR_0847 :O 'OpenRCT2' +STR_0848 :RollerCoaster Tycoon 2 +STR_0849 :{WINDOW_COLOUR_2}Verze 2.01.028 +STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, všechna práva vyhrazena +STR_0851 :{WINDOW_COLOUR_2}Design a programování - Chris Sawyer +STR_0852 :{WINDOW_COLOUR_2}Grafika - Simon Foster +STR_0853 :{WINDOW_COLOUR_2}Zvuky a hudba - Allister Brimble +STR_0854 :{WINDOW_COLOUR_2}Další zvukové nahrávky - David Ellis +STR_0855 :{WINDOW_COLOUR_2}Representation by Jacqui Lyons at Marjacq Ltd. +STR_0856 :{WINDOW_COLOUR_2}Poděkování: +STR_0857 :{WINDOW_COLOUR_2}Peter James Adcock, Joe Booth, a 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 :Příliš nízko! ! +STR_0878 :Moc vysoko! ! +STR_0879 :Tady nelze zemi snížit... +STR_0880 :Tady nelze zemi zvíšit... +STR_0881 :Předmět v cestě +STR_0882 :Nahrát hru +STR_0883 :Uložit hru +STR_0884 :Nahrát krajinu +STR_0885 :Uložit krajinu +STR_0886 :Ukončit hru +STR_0887 :Ukončit Scenario Editor +STR_0888 :Ukončit Roller Coaster Designer +STR_0889 :Ukončit Track Designs Manager +STR_0890 :SCR{COMMA16}.BMP +STR_0891 :Snímek obrazovky +STR_0892 :Snímek obrazovky byl uložen jako '{STRINGID}' +STR_0893 :Snímaní obrazovky selhalo ! +STR_0894 :Landscape data area full ! +STR_0895 :Nelze stavět částečně pod a nad zemí +STR_0896 :{POP16}{POP16}{STRINGID} Construction +STR_0897 :Direction +STR_0898 :{SMALLFONT}{BLACK}Zatáčka vlevo +STR_0899 :{SMALLFONT}{BLACK}Zatáčka vpravo +STR_0900 :{SMALLFONT}{BLACK}Zatáčka vlevo (malý poloměr) +STR_0901 :{SMALLFONT}{BLACK}Zatáčka vpravo (malý poloměr) +STR_0902 :{SMALLFONT}{BLACK}Zatáčka vlevo (velmi malý poloměr) +STR_0903 :{SMALLFONT}{BLACK}Zatáčka vpravo (velmi malý poloměr) +STR_0904 :{SMALLFONT}{BLACK}Zatáčka vlevo (velký poloměr) +STR_0905 :{SMALLFONT}{BLACK}Zatáčka vpravo (velký poloměr) +STR_0906 :{SMALLFONT}{BLACK}Rovinka +STR_0907 :Svah +STR_0908 :Roll/Banking +STR_0909 :Otáčení sedadel +STR_0910 :{SMALLFONT}{BLACK}Roll for left-hand curve +STR_0911 :{SMALLFONT}{BLACK}Roll for right-hand curve +STR_0912 :{SMALLFONT}{BLACK}No roll +STR_0913 :{SMALLFONT}{BLACK}Posunout na předchozí část +STR_0914 :{SMALLFONT}{BLACK}Posunout na následující část +STR_0915 :{SMALLFONT}{BLACK}Postavit vybranou část +STR_0916 :{SMALLFONT}{BLACK}Odstranit vybranou část +STR_0917 :{SMALLFONT}{BLACK}Kolmo dolů +STR_0918 :{SMALLFONT}{BLACK}Strmý svah dolů +STR_0919 :{SMALLFONT}{BLACK}Svah dolů +STR_0920 :{SMALLFONT}{BLACK}Vodorovně +STR_0921 :{SMALLFONT}{BLACK}Svah vzhůtu +STR_0922 :{SMALLFONT}{BLACK}Prudce vzhůru +STR_0923 :{SMALLFONT}{BLACK}Kolmo nahorů +STR_0924 :{SMALLFONT}{BLACK}Šroubovice dolů +STR_0925 :{SMALLFONT}{BLACK}Šroubovice vzhůru +STR_0926 :Tohle nelze odstranit... +STR_0927 :Tohle zde nejde postavit... +STR_0928 :{SMALLFONT}{BLACK}Řetězový vlek, pro pohon vozů do svahu +STR_0929 :'S' Ohyb (levý) +STR_0930 :'S' Ohyb (pravý) +STR_0931 :Svislá Smyčka (levá) +STR_0932 :Svislá Smyčka (pravá) +STR_0933 :Nejdříve zvyš nebo sniž povrch +STR_0934 :Vstup na atrakci v cestě +STR_0935 :Výtup z atrakce v cestě +STR_0936 :Vchod do parku v cestě +STR_0937 :{SMALLFONT}{BLACK}View options +STR_0938 :{SMALLFONT}{BLACK}Adjust land height and slope +STR_0939 :POdzemní/Vnitří pohled +STR_0940 :Remove Base Land +STR_0941 :Remove Vertical Faces +STR_0942 :Průhledné atrakce +STR_0943 :Průhledná výzdoba +STR_0944 :Uložit +STR_0945 :Neukládat +STR_0946 :Zrušit +STR_0947 :Uložit před zavřením ? +STR_0948 :Uložit před ukončením ? +STR_0949 :Uložit před ukončením ? +STR_0950 :Nahrát hru +STR_0951 :Ukončit hru +STR_0952 :Ukončit hru +STR_0953 :Nahrát krajinu +STR_0954 : +STR_0955 :{SMALLFONT}{BLACK}Vyberte úhel otočení sedadel pro tuto část trati +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 :Zrušit +STR_0973 :OK +STR_0974 :Atrakce +STR_0975 :Obchody a stánky +STR_0976 :Toalety a Informační kiosky +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_0984 :{WINDOW_COLOUR_2}{UP}{BLACK} {CURRENCY2DP} +STR_0985 :{WINDOW_COLOUR_2}{DOWN}{BLACK} {CURRENCY2DP} +STR_0986 :{BLACK}{CURRENCY2DP} +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 +STR_0998 :Na této trati nelze postavit více nástupišť +STR_0999 :Vyžaduje nástupiště +STR_1000 :Trať není uzavřený okruh. +STR_1001 :Track unsuitable for type of train +STR_1002 :Can't open {POP16}{POP16}{POP16}{STRINGID}... +STR_1003 :Can't test {POP16}{POP16}{POP16}{STRINGID}... +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 :Zvařít vše +STR_1012 :Otevřít vše +STR_1013 :Zvařít park +STR_1014 :Otevřít park +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... +STR_1018 :Can't make changes... +STR_1019 :Can't make changes... +STR_1020 :Can't make changes... +STR_1021 :{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_1022 :{POP16}{POP16}{POP16}{COMMA16} vagon na vlak +STR_1023 :{POP16}{POP16}{POP16}{COMMA16} vagónů na vlak +STR_1024 :{COMMA16} vagon na vlak +STR_1025 :{COMMA16} vagónů na vlak +STR_1026 :Nástupiště je příliš dlouhé! +STR_1027 :{SMALLFONT}{BLACK}Locate this on Main View +STR_1028 :Off edge of map! +STR_1029 :Cannot build partly above and partly below water! +STR_1030 :Tohle lze stavět jen pod vodou! +STR_1031 :Tohle nejde stavět pod vodou! +STR_1032 :Tohle jde stavět jen na hladině! +STR_1033 :Tohle jde stavět jen nad zemí! +STR_1034 :Tohle jde stavět jen na povrchu! +STR_1035 :Local authority won't allow construction above tree-height! +STR_1036 :Nahrát hru +STR_1037 :Nahrát krajinu +STR_1038 :Convert saved game to scenario +STR_1039 :Install new track design +STR_1040 :Uložit hru +STR_1041 :Uložit Scenario +STR_1042 :Uložit krajinu +STR_1043 :Uložená hra OpenRCT2 +STR_1044 :Soubor scénáře OpenRCT2 +STR_1045 :Soubor krajiny OpenRCT2 +STR_1046 :Soubor designu dráhy OpenRCT2 +STR_1047 :Uložení hry selhalo! +STR_1048 :Scenario save failed! +STR_1049 :Landscape save failed! +STR_1050 :Failed to load...{NEWLINE}File contains invalid data! +STR_1051 :Nevyditelné podpěry +STR_1052 :Nevyditelní lidé +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 +STR_1057 :Ride/attraction name +STR_1058 :Enter new name for this ride/attraction: +STR_1059 :Can't rename ride/attraction... +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 (passing station) +STR_1065 :Shuttle mode +STR_1066 :Boat hire mode +STR_1067 :Upward launch +STR_1068 :Rotating lift mode +STR_1069 :Station to station mode +STR_1070 :Single ride per admission +STR_1071 :Unlimited rides per admission +STR_1072 :Maze mode +STR_1073 :Race mode +STR_1074 :Bumper-car mode +STR_1075 :Swing mode +STR_1076 :Shop stall mode +STR_1077 :Rotation mode +STR_1078 :Forward rotation +STR_1079 :Backward rotation +STR_1080 :Film: {ENDQUOTES}Avenging aviators{ENDQUOTES} +STR_1081 :3D film: {ENDQUOTES}Mouse tails{ENDQUOTES} +STR_1082 :Space rings mode +STR_1083 :Beginners mode +STR_1084 :LIM-powered launch +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 mode +STR_1089 :Berserk mode +STR_1090 :Haunted house mode +STR_1091 :Circus show mode +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 (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} +STR_1100 :Waiting to depart {POP16}{STRINGID} +STR_1101 :Departing {POP16}{STRINGID} +STR_1102 :Travelling at {VELOCITY} +STR_1103 :Arriving at {POP16}{STRINGID} +STR_1104 :Unloading passengers at {POP16}{STRINGID} +STR_1105 :Travelling at {VELOCITY} +STR_1106 :Crashing! +STR_1107 :Crashed! +STR_1108 :Travelling at {VELOCITY} +STR_1109 :Swinging +STR_1110 :Rotating +STR_1111 :Rotating +STR_1112 :Operating +STR_1113 :Showing film +STR_1114 :Rotating +STR_1115 :Operating +STR_1116 :Operating +STR_1117 :Doing circus show +STR_1118 :Operating +STR_1119 :Waiting for cable lift +STR_1120 :Travelling at {VELOCITY} +STR_1121 :Stopping +STR_1122 :Waiting for passengers +STR_1123 :Waiting to start +STR_1124 :Starting +STR_1125 :Operating +STR_1126 :Stopping +STR_1127 :Unloading passengers +STR_1128 :Stopped by block brakes +STR_1129 :All vehicles in same colours +STR_1130 :Different colours per {STRINGID} +STR_1131 :Different colours per vehicle +STR_1132 :Vehicle {POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1133 :Vehicle {POP16}{COMMA16} +STR_1134 :{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} {COMMA16} +STR_1135 :{STRINGID} {COMMA16} +STR_1136 :{SMALLFONT}{BLACK}Vybrat hlavní barvy +STR_1137 :{SMALLFONT}{BLACK}Vybrat doplňkové barvy 1 +STR_1138 :{SMALLFONT}{BLACK}Vybrat doplňkové barvy 2 +STR_1139 :{SMALLFONT}{BLACK}Vybrat barvu podpěr +STR_1140 :{SMALLFONT}{BLACK}Vybrat barevné schéma vozidel +STR_1141 :{SMALLFONT}{BLACK}Select which vehicle/train to modify +STR_1142 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1143 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRINGID} +STR_1144 :Can't build/move entrance for this ride/attraction... +STR_1145 :Can't build/move exit for this ride/attraction... +STR_1146 :Vstup ještě není postaven +STR_1147 :Výstup ještě není postaven +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 +STR_1156 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1157 :{TICK}{MOVE_X}{SMALLFONT}{STRINGID} +STR_1158 :Tohle nelze odstranit... +STR_1159 :{SMALLFONT}{BLACK}Place scenery, gardens, and other accessories +STR_1160 :{SMALLFONT}{BLACK}Create/adjust lakes & water +STR_1161 :Tohle tafy nemůže být... +STR_1162 :{OUTLINE}{TOPAZ}{STRINGID} +STR_1163 :{STRINGID}{NEWLINE}(Right-Click to Modify) +STR_1164 :{STRINGID}{NEWLINE}(Right-Click to Remove) +STR_1165 :{STRINGID} - {STRINGID} {COMMA16} +STR_1166 :Tady nelze snížit hladinu vody... +STR_1167 :Tady nelze zvýšit hladinu vody... +STR_1168 :Nastavení +STR_1169 :(None) +STR_1170 :{STRING} +STR_1171 :{RED}Zavřeno - - +STR_1172 :{YELLOW}{STRINGID} - - +STR_1173 :{SMALLFONT}{BLACK}Build footpaths and queue lines +STR_1174 :Banner sign in the way +STR_1175 :Can't build this on sloped footpath +STR_1176 :Can't build footpath here... +STR_1177 :Can't remove footpath from here... +STR_1178 :Land slope unsuitable +STR_1179 :Footpath in the way +STR_1180 :Can't build this underwater! +STR_1181 :Cesty +STR_1182 :Druh +STR_1183 :Směr +STR_1184 :Slope +STR_1185 :{SMALLFONT}{BLACK}Směr +STR_1186 :{SMALLFONT}{BLACK}Slope down +STR_1187 :{SMALLFONT}{BLACK}Level +STR_1188 :{SMALLFONT}{BLACK}Slope up +STR_1189 :{SMALLFONT}{BLACK}Construct the selected footpath section +STR_1190 :{SMALLFONT}{BLACK}Remove previous footpath section +STR_1191 :{BLACK}{STRINGID} +STR_1192 :{OUTLINE}{RED}{STRINGID} +STR_1193 :{WINDOW_COLOUR_2}{STRINGID} +STR_1194 :Zavřeno +STR_1195 :Testovací kolo +STR_1196 :Otevřeno +STR_1197 :Porucha +STR_1198 :Nehoda! +STR_1199 :{COMMA16} person on ride +STR_1200 :{COMMA16} people on ride +STR_1201 :Nobody in queue line +STR_1202 :1 person in queue line +STR_1203 :{COMMA16} people in queue line +STR_1204 :{COMMA16} minute queue time +STR_1205 :{COMMA16} minutes queue time +STR_1206 :{WINDOW_COLOUR_2}Čekat na: +STR_1207 :{WINDOW_COLOUR_2}Vyjet když jiný vlak přijede do stanice +STR_1208 :{WINDOW_COLOUR_2}Vyplout když jiná loď přijede do přístavu +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}Čekat nejméně: +STR_1212 :{WINDOW_COLOUR_2}Čekat nejdéle: +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}Synchronise with adjacent stations +STR_1216 :{SMALLFONT}{BLACK}Select whether to synchronise departure with all adjacent stations (for 'racing') +STR_1217 :{COMMA16} sekund +STR_1218 :{BLACK}{SMALLUP} +STR_1219 :{BLACK}{SMALLDOWN} +STR_1220 :Jen východ +STR_1221 :Nemá vchod +STR_1222 :Chybí východ +STR_1223 :{SMALLFONT}{BLACK}Transport rides +STR_1224 :{SMALLFONT}{BLACK}Gentle rides +STR_1225 :{SMALLFONT}{BLACK}Roller coasters +STR_1226 :{SMALLFONT}{BLACK}Thrill rides +STR_1227 :{SMALLFONT}{BLACK}Water rides +STR_1228 :{SMALLFONT}{BLACK}Shops & stalls +STR_1229 :vlak +STR_1230 :vlaky +STR_1231 :Vlak +STR_1232 :Vlaky +STR_1233 :{COMMA16} vlak +STR_1234 :{COMMA16} Vlaky +STR_1235 :Vlak {COMMA16} +STR_1236 :loď +STR_1237 :loďe +STR_1238 :Loď +STR_1239 :Loďe +STR_1240 :{COMMA16} loď +STR_1241 :{COMMA16} loďe +STR_1242 :Loď {COMMA16} +STR_1243 :dráha +STR_1244 :dráhy +STR_1245 :Dráha +STR_1246 :Dráhy +STR_1247 :{COMMA16} dráha +STR_1248 :{COMMA16} dráhy +STR_1249 :Dráha {COMMA16} +STR_1250 :docking platform +STR_1251 :docking platforms +STR_1252 :Docking platform +STR_1253 :Docking platforms +STR_1254 :{COMMA16} docking platform +STR_1255 :{COMMA16} docking platforms +STR_1256 :Docking platform {COMMA16} +STR_1257 :station +STR_1258 :stations +STR_1259 :Station +STR_1260 :Stations +STR_1261 :{COMMA16} station +STR_1262 :{COMMA16} stations +STR_1263 :Station {COMMA16} +STR_1264 :car +STR_1265 :cars +STR_1266 :Car +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_1278 :structure +STR_1279 :structures +STR_1280 :Structure +STR_1281 :Structures +STR_1282 :{COMMA16} structure +STR_1283 :{COMMA16} structures +STR_1284 :Structure {COMMA16} +STR_1285 :loď +STR_1286 :lodě +STR_1287 :Loď +STR_1288 :Lodě +STR_1289 :{COMMA16} loď +STR_1290 :{COMMA16} lodě +STR_1291 :Loď {COMMA16} +STR_1292 :kabina +STR_1293 :kabiny +STR_1294 :Kabina +STR_1295 :Kabiny +STR_1296 :{COMMA16} kabina +STR_1297 :{COMMA16} kabin +STR_1298 :Kabina {COMMA16} +STR_1299 :kolo +STR_1300 :kol +STR_1301 :Kolo +STR_1302 :Kol +STR_1303 :{COMMA16} kolo +STR_1304 :{COMMA16} kol +STR_1305 :Kolo {COMMA16} +STR_1306 :ring +STR_1307 :rings +STR_1308 :Ring +STR_1309 :Rings +STR_1310 :{COMMA16} ring +STR_1311 :{COMMA16} rings +STR_1312 :Ring {COMMA16} +STR_1313 :hráč +STR_1314 :hráči +STR_1315 :Hráč +STR_1316 :Hráči +STR_1317 :{COMMA16} hráč +STR_1318 :{COMMA16} hráči +STR_1319 :Hráč {COMMA16} +STR_1320 :course +STR_1321 :courses +STR_1322 :Course +STR_1323 :Courses +STR_1324 :{COMMA16} course +STR_1325 :{COMMA16} courses +STR_1326 :Course {COMMA16} +STR_1327 :{SMALLFONT}{BLACK}Rotate objects by 90{DEGREE} +STR_1328 :Level land required +STR_1329 :{WINDOW_COLOUR_2}Launch speed: +STR_1330 :{SMALLFONT}{BLACK}Maximum speed when leaving station +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} - Entrance{POP16}{POP16} +STR_1336 :{STRINGID} - Station {POP16}{COMMA16} Entrance +STR_1337 :{STRINGID} - Exit{POP16}{POP16} +STR_1338 :{STRINGID} - Station {POP16}{COMMA16} Exit +STR_1339 :{BLACK}V7sledky testů nejsou hotovy... +STR_1340 :{WINDOW_COLOUR_2}Max. rychlost: {BLACK}{VELOCITY} +STR_1341 :{WINDOW_COLOUR_2}Ride time: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1342 :{DURATION} +STR_1343 :{DURATION} / +STR_1344 :{WINDOW_COLOUR_2}Ride length: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1345 :{LENGTH} +STR_1346 :{LENGTH} / +STR_1347 :{WINDOW_COLOUR_2}Průměrná rychlost: {BLACK}{VELOCITY} +STR_1348 :{WINDOW_COLOUR_2}Max. positive vertical G's: {BLACK}{COMMA2DP32}g +STR_1349 :{WINDOW_COLOUR_2}Max. positive vertical G's: {OUTLINE}{RED}{COMMA2DP32}g +STR_1350 :{WINDOW_COLOUR_2}Max. negative vertical G's: {BLACK}{COMMA2DP32}g +STR_1351 :{WINDOW_COLOUR_2}Max. negative vertical G's: {OUTLINE}{RED}{COMMA2DP32}g +STR_1352 :{WINDOW_COLOUR_2}Max. lateral G's: {BLACK}{COMMA2DP32}g +STR_1353 :{WINDOW_COLOUR_2}Max. lateral G's: {OUTLINE}{RED}{COMMA2DP32}g +STR_1354 :{WINDOW_COLOUR_2}Nejvyšší pád: {BLACK}{LENGTH} +STR_1355 :{WINDOW_COLOUR_2}Pádů: {BLACK}{COMMA16} +STR_1356 :{WINDOW_COLOUR_2}Obratů: {BLACK}{COMMA16} +STR_1357 :{WINDOW_COLOUR_2}Holes: {BLACK}{COMMA16} +STR_1358 :{WINDOW_COLOUR_2}Celkem ve stav beztíže: {BLACK}{COMMA2DP32}sekund +STR_1359 :{WINDOW_COLOUR_2}Queue time: {BLACK}{COMMA16} minute +STR_1360 :{WINDOW_COLOUR_2}Queue time: {BLACK}{COMMA16} minutes +STR_1361 :Can't change speed... +STR_1362 :Can't change launch speed... +STR_1363 :Too high for supports! +STR_1364 :Supports for track above can't be extended any further! +STR_1365 :Otočka kolem trati (levá) +STR_1366 :Otočka kolem trati (pravá) +STR_1367 :Poloviční smyčka +STR_1368 :Poloviční Vývrtka (levá) +STR_1369 :Poloviční Vývrtka (pravá) +STR_1370 :Sudový výkrut (levý) +STR_1371 :Sudový výkrut (pravý) +STR_1372 :Launched Lift Hill +STR_1373 :Velká Poloviční Vývrtka (levá) +STR_1374 :Velká Poloviční Vývrtka (pravá) +STR_1375 :Přechod vzhůru +STR_1376 :Přechod dolů +STR_1377 :Otočka kolem těla (levá) +STR_1378 :Otočka kolem těla (pravá) +STR_1379 :Obrat (levý) +STR_1380 :Obrat (Pravy) +STR_1381 :Zahnutý vlečný svah (vlevo) +STR_1382 :Zahnutý vlečný svah (vpravo) +STR_1383 :Čtvrt smyčky +STR_1384 :{YELLOW}{STRINGID} +STR_1385 :{SMALLFONT}{BLACK}Other track configurations +STR_1386 :Zvláštní... +STR_1387 :Can't change land type... +STR_1388 :{OUTLINE}{GREEN}+ {CURRENCY} +STR_1389 :{OUTLINE}{RED}- {CURRENCY} +STR_1390 :{CURRENCY2DP} +STR_1391 :{RED}{CURRENCY2DP} +STR_1392 :{SMALLFONT}{BLACK}View of ride/attraction +STR_1393 :{SMALLFONT}{BLACK}Vehicle details and options +STR_1394 :{SMALLFONT}{BLACK}Operating options +STR_1395 :{SMALLFONT}{BLACK}Maintenance options +STR_1396 :{SMALLFONT}{BLACK}Colour scheme options +STR_1397 :{SMALLFONT}{BLACK}Sound & music options +STR_1398 :{SMALLFONT}{BLACK}Measurements and test data +STR_1399 :{SMALLFONT}{BLACK}Graphs +STR_1400 :Vchod +STR_1401 :Východ +STR_1402 :{SMALLFONT}{BLACK}Build or move entrance to ride/attraction +STR_1403 :{SMALLFONT}{BLACK}Build or move exit from ride/attraction +STR_1404 :{SMALLFONT}{BLACK}Otočit o 90{DEGREE} +STR_1405 :{SMALLFONT}{BLACK}Zrcadlový obraz +STR_1406 :{SMALLFONT}{BLACK}Toggle scenery on/off (if available for this design) +STR_1407 :{WINDOW_COLOUR_2}Build this... +STR_1408 :{WINDOW_COLOUR_2}Cena: {BLACK}{CURRENCY} +STR_1409 :Entry/Exit Platform +STR_1410 :Svislá věž +STR_1411 :{STRINGID} v cestě +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}Rychlost +STR_1416 :{WINDOW_COLOUR_2}Výška +STR_1417 :{WINDOW_COLOUR_2}Vert.G's +STR_1418 :{WINDOW_COLOUR_2}Lat.G's +STR_1419 :{SMALLFONT}{BLACK}{VELOCITY} +STR_1420 :{SMALLFONT}{BLACK}{LENGTH} +STR_1421 :{SMALLFONT}{BLACK}{COMMA16}g +STR_1422 :{SMALLFONT}{BLACK}Logging data from {POP16}{STRINGID} +STR_1423 :{SMALLFONT}{BLACK}Queue line path +STR_1424 :{SMALLFONT}{BLACK}Footpath +STR_1425 :Footpath +STR_1426 :Queue Line +STR_1427 :{WINDOW_COLOUR_2}Customers: {BLACK}{COMMA32} per hour +STR_1428 :{WINDOW_COLOUR_2}Admission price: +STR_1429 :{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1430 :Free +STR_1431 :Walking +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_1438 :Sitting +STR_1439 :(select location) +STR_1440 :Seká trávu +STR_1441 :Zametá cestu +STR_1442 :Vynáši odpadkový koš +STR_1443 :Zalévá záhon +STR_1444 :Sleduje {STRINGID} +STR_1445 :Sleduje vystavbu {STRINGID} +STR_1446 :Prohlíží si prostředí +STR_1447 :Opouští park +STR_1448 :Sleduje výstavbu nové trti +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 :Jméno hosta +STR_1453 :Vložte jméno tohoto hosta: +STR_1454 :Nelze pojmenovat hosta... +STR_1455 :Neplatné jméno pro hosta +STR_1456 :{WINDOW_COLOUR_2}Utracených peněz: {BLACK}{CURRENCY2DP} +STR_1457 :{WINDOW_COLOUR_2}Peněz v kapse: {BLACK}{CURRENCY2DP} +STR_1458 :{WINDOW_COLOUR_2}Čas strávený v parku: {BLACK}{REALTIME} +STR_1459 :Track style +STR_1460 :{SMALLFONT}{BLACK}otevřená trať ve tvaru 'U' +STR_1461 :{SMALLFONT}{BLACK}uzavřená trať ve tvaru 'O' +STR_1462 :Svah je pro vlečení příliš strmí +STR_1463 :Hostů +STR_1464 :Šroubovice vzhůru (small) +STR_1465 :Šroubovice vzhůru (large) +STR_1466 :Šroubovice dolů (small) +STR_1467 :Šroubovice dolů (large) +STR_1468 :Personál +STR_1469 :Dráha musí začínat a končit stanicí +STR_1470 :Stanice není dost dlouhá +STR_1471 :{WINDOW_COLOUR_2}Rychlost: +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 +STR_1475 :{WINDOW_COLOUR_2}Intensity rating: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1476 :{WINDOW_COLOUR_2}Intensity rating: {BLACK}Not yet available +STR_1477 :{WINDOW_COLOUR_2}Intensity rating: {OUTLINE}{RED}{COMMA2DP32} ({STRINGID}) +STR_1478 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1479 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}Not yet available +STR_1480 :{SMALLFONT}{OPENQUOTES}Nemohu si dovolit {STRINGID}{ENDQUOTES} +STR_1481 :{SMALLFONT}{OPENQUOTES}Utratil jsem všechny své peníze{ENDQUOTES} +STR_1482 :{SMALLFONT}{OPENQUOTES}Je my špatně{ENDQUOTES} +STR_1483 :{SMALLFONT}{OPENQUOTES}Je my hrozně špatně{ENDQUOTES} +STR_1484 :{SMALLFONT}{OPENQUOTES}I want to go on something more thrilling than {STRINGID}{ENDQUOTES} +STR_1485 :{SMALLFONT}{OPENQUOTES}{STRINGID} na mě vypadá moc intenzivně{ENDQUOTES} +STR_1486 :{SMALLFONT}{OPENQUOTES}I haven't finished my {STRINGID} yet{ENDQUOTES} +STR_1487 :{SMALLFONT}{OPENQUOTES}Jen ze sledování {STRINGID} se my dělá zle{ENDQUOTES} +STR_1488 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za vstup na {STRINGID}{ENDQUOTES} +STR_1489 :{SMALLFONT}{OPENQUOTES}Chci jít domů{ENDQUOTES} +STR_1490 :{SMALLFONT}{OPENQUOTES}{STRINGID} is really good value{ENDQUOTES} +STR_1491 :{SMALLFONT}{OPENQUOTES}Už mám {STRINGID}{ENDQUOTES} +STR_1492 :{SMALLFONT}{OPENQUOTES}Nemohu si dovolit {STRINGID}{ENDQUOTES} +STR_1493 :{SMALLFONT}{OPENQUOTES}Nejdem hladový{ENDQUOTES} +STR_1494 :{SMALLFONT}{OPENQUOTES}Nemám žízeň{ENDQUOTES} +STR_1495 :{SMALLFONT}{OPENQUOTES}Pomóc! Topím se!{ENDQUOTES} +STR_1496 :{SMALLFONT}{OPENQUOTES}Ztratil jsem se!{ENDQUOTES} +STR_1497 :{SMALLFONT}{OPENQUOTES}Na {STRINGID} to bylo super{ENDQUOTES} +STR_1498 :{SMALLFONT}{OPENQUOTES}4ekám v řadě na {STRINGID} už věky{ENDQUOTES} +STR_1499 :{SMALLFONT}{OPENQUOTES}Jsem unavený{ENDQUOTES} +STR_1500 :{SMALLFONT}{OPENQUOTES}Mám hlad{ENDQUOTES} +STR_1501 :{SMALLFONT}{OPENQUOTES}Jsem žíznivý{ENDQUOTES} +STR_1502 :{SMALLFONT}{OPENQUOTES}Potřebuji jít na toaletu{ENDQUOTES} +STR_1503 :{SMALLFONT}{OPENQUOTES}Nemůžu najít {STRINGID}{ENDQUOTES} +STR_1504 :{SMALLFONT}{OPENQUOTES}I'm not paying that much to use {STRINGID}{ENDQUOTES} +STR_1505 :{SMALLFONT}{OPENQUOTES}I'm not going on {STRINGID} while it's raining{ENDQUOTES} +STR_1506 :{SMALLFONT}{OPENQUOTES}Je tu hrozný nepořádek{ENDQUOTES} +STR_1507 :{SMALLFONT}{OPENQUOTES}Nemůžu najít východ z praku{ENDQUOTES} +STR_1508 :{SMALLFONT}{OPENQUOTES}I want to get off {STRINGID}{ENDQUOTES} +STR_1509 :{SMALLFONT}{OPENQUOTES}I want to get out of {STRINGID}{ENDQUOTES} +STR_1510 :{SMALLFONT}{OPENQUOTES}I'm not going on {STRINGID} - It isn't safe{ENDQUOTES} +STR_1511 :{SMALLFONT}{OPENQUOTES}This path is disgusting{ENDQUOTES} +STR_1512 :{SMALLFONT}{OPENQUOTES}Je to tady hrozně přelidněné{ENDQUOTES} +STR_1513 :{SMALLFONT}{OPENQUOTES}The vandalism here is really bad{ENDQUOTES} +STR_1514 :{SMALLFONT}{OPENQUOTES}Krásné prostředí!{ENDQUOTES} +STR_1515 :{SMALLFONT}{OPENQUOTES}This park is really clean and tidy{ENDQUOTES} +STR_1516 :{SMALLFONT}{OPENQUOTES}The jumping fountains are great{ENDQUOTES} +STR_1517 :{SMALLFONT}{OPENQUOTES}The music is nice here{ENDQUOTES} +STR_1518 :{SMALLFONT}{OPENQUOTES}This balloon from {STRINGID} is really good value{ENDQUOTES} +STR_1519 :{SMALLFONT}{OPENQUOTES}This cuddly toy from {STRINGID} is really good value{ENDQUOTES} +STR_1520 :{SMALLFONT}{OPENQUOTES}This park map from {STRINGID} is really good value{ENDQUOTES} +STR_1521 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} +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 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 candyfloss from {STRINGID} is really good value{ENDQUOTES} +STR_1528 : +STR_1529 : +STR_1530 : +STR_1531 :{SMALLFONT}{OPENQUOTES}This pizza from {STRINGID} is really good value{ENDQUOTES} +STR_1532 : +STR_1533 :{SMALLFONT}{OPENQUOTES}This popcorn from {STRINGID} is really good value{ENDQUOTES} +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 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} +STR_1541 : +STR_1542 :{SMALLFONT}{OPENQUOTES}This fried chicken from {STRINGID} is really good value{ENDQUOTES} +STR_1543 :{SMALLFONT}{OPENQUOTES}This lemonade from {STRINGID} is really good value{ENDQUOTES} +STR_1544 : +STR_1545 : +STR_1546 : +STR_1547 : +STR_1548 : +STR_1549 : +STR_1550 :{SMALLFONT}{OPENQUOTES}Wow!{ENDQUOTES} +STR_1551 :{SMALLFONT}{OPENQUOTES}I have the strangest feeling someone is watching me{ENDQUOTES} +STR_1552 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za a balloon from {STRINGID}{ENDQUOTES} +STR_1553 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za a cuddly toy from {STRINGID}{ENDQUOTES} +STR_1554 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za a park map from {STRINGID}{ENDQUOTES} +STR_1555 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za an on-ride photo from {STRINGID}{ENDQUOTES} +STR_1556 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za an umbrella from {STRINGID}{ENDQUOTES} +STR_1557 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za a drink from {STRINGID}{ENDQUOTES} +STR_1558 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za a burger from {STRINGID}{ENDQUOTES} +STR_1559 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za chips from {STRINGID}{ENDQUOTES} +STR_1560 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za an ice cream from {STRINGID}{ENDQUOTES} +STR_1561 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za candyfloss from {STRINGID}{ENDQUOTES} +STR_1562 : +STR_1563 : +STR_1564 : +STR_1565 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za pizza from {STRINGID}{ENDQUOTES} +STR_1566 : +STR_1567 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za popcorn from {STRINGID}{ENDQUOTES} +STR_1568 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za a hot dog from {STRINGID}{ENDQUOTES} +STR_1569 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za tentacle from {STRINGID}{ENDQUOTES} +STR_1570 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za a hat from {STRINGID}{ENDQUOTES} +STR_1571 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za a toffee apple from {STRINGID}{ENDQUOTES} +STR_1572 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za a T-shirt from {STRINGID}{ENDQUOTES} +STR_1573 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za a doughnut from {STRINGID}{ENDQUOTES} +STR_1574 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za coffee from {STRINGID}{ENDQUOTES} +STR_1575 : +STR_1576 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za fried chicken from {STRINGID}{ENDQUOTES} +STR_1577 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za lemonade from {STRINGID}{ENDQUOTES} +STR_1578 : +STR_1579 : +STR_1580 : +STR_1581 : +STR_1582 : +STR_1583 : +STR_1584 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} +STR_1585 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} +STR_1586 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} +STR_1587 :{SMALLFONT}{OPENQUOTES}This pretzel from {STRINGID} is really good value{ENDQUOTES} +STR_1588 :{SMALLFONT}{OPENQUOTES}This hot chocolate from {STRINGID} is really good value{ENDQUOTES} +STR_1589 :{SMALLFONT}{OPENQUOTES}This iced tea from {STRINGID} is really good value{ENDQUOTES} +STR_1590 :{SMALLFONT}{OPENQUOTES}This funnel cake from {STRINGID} is really good value{ENDQUOTES} +STR_1591 :{SMALLFONT}{OPENQUOTES}These sunglasses from {STRINGID} are really good value{ENDQUOTES} +STR_1592 :{SMALLFONT}{OPENQUOTES}These beef noodles from {STRINGID} are really good value{ENDQUOTES} +STR_1593 :{SMALLFONT}{OPENQUOTES}These fried rice noodles from {STRINGID} are really good value{ENDQUOTES} +STR_1594 :{SMALLFONT}{OPENQUOTES}This wonton soup from {STRINGID} is really good value{ENDQUOTES} +STR_1595 :{SMALLFONT}{OPENQUOTES}This meatball soup from {STRINGID} is really good value{ENDQUOTES} +STR_1596 :{SMALLFONT}{OPENQUOTES}This fruit juice from {STRINGID} is really good value{ENDQUOTES} +STR_1597 :{SMALLFONT}{OPENQUOTES}This soybean milk from {STRINGID} is really good value{ENDQUOTES} +STR_1598 :{SMALLFONT}{OPENQUOTES}This sujongkwa from {STRINGID} is really good value{ENDQUOTES} +STR_1599 :{SMALLFONT}{OPENQUOTES}This sub sandwich from {STRINGID} is really good value{ENDQUOTES} +STR_1600 :{SMALLFONT}{OPENQUOTES}This cookie from {STRINGID} is really good value{ENDQUOTES} +STR_1601 : +STR_1602 : +STR_1603 : +STR_1604 :{SMALLFONT}{OPENQUOTES}This roast sausage from {STRINGID} are really good value{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}Nezaplatím tak moc za on-ride photo from {STRINGID}{ENDQUOTES} +STR_1617 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za an on-ride photo from {STRINGID}{ENDQUOTES} +STR_1618 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za an on-ride photo from {STRINGID}{ENDQUOTES} +STR_1619 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za a pretzel from {STRINGID}{ENDQUOTES} +STR_1620 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za hot chocolate from {STRINGID}{ENDQUOTES} +STR_1621 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za iced tea from {STRINGID}{ENDQUOTES} +STR_1622 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za a funnel cake from {STRINGID}{ENDQUOTES} +STR_1623 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za sunglasses from {STRINGID}{ENDQUOTES} +STR_1624 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za beef noodles from {STRINGID}{ENDQUOTES} +STR_1625 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za fried rice noodles from {STRINGID}{ENDQUOTES} +STR_1626 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za wonton soup from {STRINGID}{ENDQUOTES} +STR_1627 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za for meatball soup from {STRINGID}{ENDQUOTES} +STR_1628 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za fruit juice from {STRINGID}{ENDQUOTES} +STR_1629 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za soybean milk from {STRINGID}{ENDQUOTES} +STR_1630 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za for sujongkwa from {STRINGID}{ENDQUOTES} +STR_1631 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za a sub sandwich from {STRINGID}{ENDQUOTES} +STR_1632 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za a cookie from {STRINGID}{ENDQUOTES} +STR_1633 : +STR_1634 : +STR_1635 : +STR_1636 :{SMALLFONT}{OPENQUOTES}Nezaplatím tak moc za a roast sausage from {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}Pomóc! Polož mě dolů!{ENDQUOTES} +STR_1649 :{SMALLFONT}{OPENQUOTES}Dochází my hotovost!{ENDQUOTES} +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}intenzita: {BLACK}méně než {COMMA16} +STR_1659 :{WINDOW_COLOUR_2}intenzita: {BLACK}mezi {COMMA16} a {COMMA16} +STR_1660 :{WINDOW_COLOUR_2}intenzita: {BLACK}víc než {COMMA16} +STR_1661 :{WINDOW_COLOUR_2}Odolnost nevolnosti: {BLACK}{STRINGID} +STR_1662 :{WINDOW_COLOUR_2}Nálada: +STR_1663 :{WINDOW_COLOUR_2}Nevolnost: +STR_1664 :{WINDOW_COLOUR_2}Energie: +STR_1665 :{WINDOW_COLOUR_2}Hlad: +STR_1666 :{WINDOW_COLOUR_2}Žízeň: +STR_1667 :{WINDOW_COLOUR_2}Toalety: +STR_1668 :{WINDOW_COLOUR_2}Uspokojení: {BLACK}neznámé +STR_1669 :{WINDOW_COLOUR_2}Uspokojení: {BLACK}{COMMA16}% +STR_1670 :{WINDOW_COLOUR_2}Hostů celkem: {BLACK}{COMMA32} +STR_1671 :{WINDOW_COLOUR_2}Výdělek celkem: {BLACK}{CURRENCY2DP} +STR_1672 :Brakes +STR_1673 :Spinning Control Toggle Track +STR_1674 :Brake speed +STR_1675 :{POP16}{VELOCITY} +STR_1676 :{SMALLFONT}{BLACK}Set speed limit for brakes +STR_1677 :{WINDOW_COLOUR_2}Popularita: {BLACK}Neznámá +STR_1678 :{WINDOW_COLOUR_2}Popularita: {BLACK}{COMMA16}% +STR_1679 :Helix up (left) +STR_1680 :Helix up (right) +STR_1681 :Helix down (left) +STR_1682 :Helix down (right) +STR_1683 :Base size 2 x 2 +STR_1684 :Base size 4 x 4 +STR_1685 :Base size 2 x 4 +STR_1686 :Base size 5 x 1 +STR_1687 :Water splash +STR_1688 :Base size 4 x 1 +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_1694 :{SMALLFONT}{BLACK}Staff +STR_1695 :{SMALLFONT}{BLACK}Income and costs +STR_1696 :{SMALLFONT}{BLACK}Customer information +STR_1697 :Cannot place these on queue line area +STR_1698 :Can only place these on queue area +STR_1699 :Too many people in game +STR_1700 :Hire new Handyman +STR_1701 :Hire new Mechanic +STR_1702 :Hire new Security Guard +STR_1703 :Hire new Entertainer +STR_1704 :Can't hire new staff... +STR_1705 :{SMALLFONT}{BLACK}Sack this staff member +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_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 +STR_1714 :{INLINE_SPRITE}{249}{19}{00}{00}{WINDOW_COLOUR_2}Empty litter bins +STR_1715 :{INLINE_SPRITE}{250}{19}{00}{00}{WINDOW_COLOUR_2}Mow grass +STR_1716 :Invalid name for park +STR_1717 :Can't rename park... +STR_1718 :Park Name +STR_1719 :Enter name for park: +STR_1720 :{SMALLFONT}{BLACK}Name park +STR_1721 :Park closed +STR_1722 :Park open +STR_1723 :Can't open park... +STR_1724 :Can't close park... +STR_1725 :Can't buy land... +STR_1726 :Land not for sale! +STR_1727 :Construction rights not for sale! +STR_1728 :Can't buy construction rights here... +STR_1729 :Land not owned by park! +STR_1730 :{RED}Closed - - +STR_1731 :{WHITE}{STRINGID} - - +STR_1732 :Build +STR_1733 :Mode +STR_1734 :{WINDOW_COLOUR_2}Number of laps: +STR_1735 :{SMALLFONT}{BLACK}Number of laps of circuit +STR_1736 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1737 :{COMMA16} +STR_1738 :Can't change number of laps... +STR_1739 :Race won by guest {INT32} +STR_1740 :Race won by {STRINGID} +STR_1741 :Not yet constructed ! +STR_1742 :{WINDOW_COLOUR_2}Max. people on ride: +STR_1743 :{SMALLFONT}{BLACK}Maximum number of people allowed on this ride at one time +STR_1744 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1745 :{COMMA16} +STR_1746 :Can't change this... +STR_1747 :{WINDOW_COLOUR_2}Time limit: +STR_1748 :{SMALLFONT}{BLACK}Time limit for ride +STR_1749 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{DURATION} +STR_1750 :{DURATION} +STR_1751 :Can't change time limit for ride... +STR_1752 :{SMALLFONT}{BLACK}Show list of individual guests in park +STR_1753 :{SMALLFONT}{BLACK}Show summarised list of guests in park +STR_1754 :{BLACK}{COMMA16} guests +STR_1755 :{BLACK}{COMMA16} guest +STR_1756 :{WINDOW_COLOUR_2}Admission price: +STR_1757 :{WINDOW_COLOUR_2}Reliability: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1758 :{SMALLFONT}{BLACK}Build mode +STR_1759 :{SMALLFONT}{BLACK}Move mode +STR_1760 :{SMALLFONT}{BLACK}Fill-in mode +STR_1761 :{SMALLFONT}{BLACK}Build maze in this direction +STR_1762 :Waterfalls +STR_1763 :Rapids +STR_1764 :Log Bumps +STR_1765 :On-ride photo section +STR_1766 :Reverser turntable +STR_1767 :Spinning tunnel +STR_1768 :Can't change number of swings... +STR_1769 :{WINDOW_COLOUR_2}Number of swings: +STR_1770 :{SMALLFONT}{BLACK}Number of complete swings +STR_1771 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1772 :{COMMA16} +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_1778 :{STRINGID} - - +STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Panda costume +STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tiger costume +STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} Elephant costume +STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} Roman costume +STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} Gorilla costume +STR_1784 :{INLINE_SPRITE}{03}{20}{00}{00} Snowman costume +STR_1785 :{INLINE_SPRITE}{04}{20}{00}{00} Knight costume +STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} Astronaut costume +STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} Bandit costume +STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} Sheriff costume +STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} Pirate costume +STR_1790 :{SMALLFONT}{BLACK}Select uniform colour for this type of staff +STR_1791 :{WINDOW_COLOUR_2}Uniform colour: +STR_1792 :Responding to {STRINGID} breakdown call +STR_1793 :Heading to {STRINGID} for an inspection +STR_1794 :Fixing {STRINGID} +STR_1795 :Answering radio call +STR_1796 :Has broken down and requires fixing +STR_1797 :This option cannot be changed for this ride +STR_1798 :Whirlpool +STR_1799 :{POP16}{POP16}{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1800 :Safety cut-out +STR_1801 :Restraints stuck closed +STR_1802 :Restraints stuck open +STR_1803 :Doors stuck closed +STR_1804 :Doors stuck open +STR_1805 :Vehicle malfunction +STR_1806 :Brakes failure +STR_1807 :Control failure +STR_1808 :{WINDOW_COLOUR_2}Last breakdown: {BLACK}{STRINGID} +STR_1809 :{WINDOW_COLOUR_2}Current breakdown: {OUTLINE}{RED}{STRINGID} +STR_1810 :{WINDOW_COLOUR_2}Carrying: +STR_1811 :Can't build this here... +STR_1812 :{SMALLFONT}{BLACK}{STRINGID} +STR_1813 :Miscellaneous Objects +STR_1814 :Actions +STR_1815 :Thoughts +STR_1816 :{SMALLFONT}{BLACK}Select information type to show in guest list +STR_1817 :({COMMA16}) +STR_1818 :{WINDOW_COLOUR_2}All guests +STR_1819 :{WINDOW_COLOUR_2}All guests (summarised) +STR_1820 :{WINDOW_COLOUR_2}Guests {STRINGID} +STR_1821 :{WINDOW_COLOUR_2}Guests thinking {STRINGID} +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 :Stav +STR_1827 :Popularita +STR_1828 :Spokojenost +STR_1829 :Výdělečnost +STR_1830 :Délka řady +STR_1831 :Doba čekání +STR_1832 :Reliability +STR_1833 :Přerušní provozu +STR_1834 :Guests favourite +STR_1835 :Popularita: Neznámá +STR_1836 :Popularita: {COMMA16}% +STR_1837 :Spokojenost: Neznámá +STR_1838 :Spokojenost: {COMMA16}% +STR_1839 :Reliability: {COMMA16}% +STR_1840 :Přerušní provozu: {COMMA16}% +STR_1841 :Výdělečnost: {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 +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}Vyber jaká hudba se bude hrát +STR_1851 :{WINDOW_COLOUR_2}Cena provozu: {BLACK}{CURRENCY2DP} za hodinu +STR_1852 :{WINDOW_COLOUR_2}Cena provozu: {BLACK}Unknown +STR_1853 :{WINDOW_COLOUR_2}Postaveno: {BLACK}Letos +STR_1854 :{WINDOW_COLOUR_2}Postaveno: {BLACK}Minulí rok +STR_1855 :{WINDOW_COLOUR_2}Postaveno: {BLACK}Před {COMMA16} lety +STR_1856 :{WINDOW_COLOUR_2}Zisk za prodaný předmět: {BLACK}{CURRENCY2DP} +STR_1857 :{WINDOW_COLOUR_2}Ztráta na prodaný předmět: {BLACK}{CURRENCY2DP} +STR_1858 :{WINDOW_COLOUR_2}Cost: {BLACK}{CURRENCY2DP} per month +STR_1859 :Uklízeč +STR_1860 :Technik +STR_1861 :Hlídač +STR_1862 :Bavič +STR_1863 :Uklízeč +STR_1864 :Technik +STR_1865 :Hlídač +STR_1866 :Bavič +STR_1867 :{BLACK}{COMMA16} {STRINGID} +STR_1868 :Can't change number of rotations... +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}{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 +STR_1878 :{WINDOW_COLOUR_2}Inspection: +STR_1879 :Every 10 minutes +STR_1880 :Every 20 minutes +STR_1881 :Every 30 minutes +STR_1882 :Every 45 minutes +STR_1883 :Every hour +STR_1884 :Every 2 hours +STR_1885 :Never +STR_1886 :Inspecting {STRINGID} +STR_1887 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}{COMMA16} minutes +STR_1888 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}more than 4 hours +STR_1889 :{WINDOW_COLOUR_2}Down-Time: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1890 :{SMALLFONT}{BLACK}Select how often a mechanic should check this ride +STR_1891 :No {STRINGID} in park yet! +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 : +STR_1893 : +STR_1894 :{WINDOW_COLOUR_2}{STRINGID} sold: {BLACK}{COMMA32} +STR_1895 :{SMALLFONT}{BLACK}Postavit novou atrakci +STR_1896 :{WINDOW_COLOUR_2}Expenditure/Income +STR_1897 :{WINDOW_COLOUR_2}Ride construction +STR_1898 :{WINDOW_COLOUR_2}Ride running costs +STR_1899 :{WINDOW_COLOUR_2}Land purchase +STR_1900 :{WINDOW_COLOUR_2}Landscaping +STR_1901 :{WINDOW_COLOUR_2}Park entrance tickets +STR_1902 :{WINDOW_COLOUR_2}Ride tickets +STR_1903 :{WINDOW_COLOUR_2}Shop sales +STR_1904 :{WINDOW_COLOUR_2}Shop stock +STR_1905 :{WINDOW_COLOUR_2}Food/drink sales +STR_1906 :{WINDOW_COLOUR_2}Food/drink stock +STR_1907 :{WINDOW_COLOUR_2}Staff wages +STR_1908 :{WINDOW_COLOUR_2}Marketing +STR_1909 :{WINDOW_COLOUR_2}Research +STR_1910 :{WINDOW_COLOUR_2}Loan interest +STR_1911 :{BLACK} at {COMMA16}% per year +STR_1912 :{MONTH} +STR_1913 :{BLACK}+{CURRENCY2DP} +STR_1914 :{BLACK}{CURRENCY2DP} +STR_1915 :{RED}{CURRENCY2DP} +STR_1916 :{WINDOW_COLOUR_2}Loan: +STR_1917 :{POP16}{POP16}{POP16}{CURRENCY} +STR_1918 :Can't borrow any more money! +STR_1919 :Not enough cash available! +STR_1920 :Can't pay back loan! +STR_1921 :{SMALLFONT}{BLACK}Start a new game +STR_1922 :{SMALLFONT}{BLACK}Continue playing a saved game +STR_1923 :{SMALLFONT}{BLACK}Show tutorial +STR_1924 :{SMALLFONT}{BLACK}Exit +STR_1925 :Can't place person here... +STR_1926 :{SMALLFONT} +STR_1927 :{YELLOW}{STRINGID} has broken down +STR_1928 :{RED}{STRINGID} has crashed! +STR_1929 :{RED}{STRINGID} still hasn't been fixed{NEWLINE}Check where your mechanics are and consider organizing them better +STR_1930 :{SMALLFONT}{BLACK}Turn on/off tracking information for this guest - (If tracking is on, guest's movements will be reported in the message area) +STR_1931 :{STRINGID} has joined the queue line for {STRINGID} +STR_1932 :{STRINGID} is on {STRINGID} +STR_1933 :{STRINGID} is in {STRINGID} +STR_1934 :{STRINGID} has left {STRINGID} +STR_1935 :{STRINGID} has left the park +STR_1936 :{STRINGID} has bought {STRINGID} +STR_1937 :{SMALLFONT}{BLACK}Show information about the subject of this message +STR_1938 :{SMALLFONT}{BLACK}Show view of guest +STR_1939 :{SMALLFONT}{BLACK}Show view of staff member +STR_1940 :{SMALLFONT}{BLACK}Show happiness, energy, hunger etc. for this guest +STR_1941 :{SMALLFONT}{BLACK}Show which rides this guest has been on +STR_1942 :{SMALLFONT}{BLACK}Show financial information about this guest +STR_1943 :{SMALLFONT}{BLACK}Show guest's recent thoughts +STR_1944 :{SMALLFONT}{BLACK}Show items guest is carrying +STR_1945 :{SMALLFONT}{BLACK}Show orders and options for this staff member +STR_1946 :{SMALLFONT}{BLACK}Select costume for this entertainer +STR_1947 :{SMALLFONT}{BLACK}Show areas patrolled by selected staff type, and locate the nearest staff member +STR_1948 :{SMALLFONT}{BLACK}Hire a new staff member of the selected type +STR_1949 :Financial Summary +STR_1950 :Financial Graph +STR_1951 :Park Value Graph +STR_1952 :Profit Graph +STR_1953 :Marketing +STR_1954 :Research Funding +STR_1955 :{WINDOW_COLOUR_2}Number of circuits: +STR_1956 :{SMALLFONT}{BLACK}Number of circuits of track per ride +STR_1957 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1958 :{COMMA16} +STR_1959 :Can't change number of circuits... +STR_1960 :{WINDOW_COLOUR_2}Balloon price: +STR_1961 :{WINDOW_COLOUR_2}Cuddly Toy price: +STR_1962 :{WINDOW_COLOUR_2}Park Map price: +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}Chips price: +STR_1968 :{WINDOW_COLOUR_2}Ice Cream price: +STR_1969 :{WINDOW_COLOUR_2}Candyfloss price: +STR_1970 :{WINDOW_COLOUR_2} +STR_1971 :{WINDOW_COLOUR_2} +STR_1972 :{WINDOW_COLOUR_2} +STR_1973 :{WINDOW_COLOUR_2}Pizza price: +STR_1974 :{WINDOW_COLOUR_2} +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}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: +STR_1983 :{WINDOW_COLOUR_2} +STR_1984 :{WINDOW_COLOUR_2}Fried Chicken price: +STR_1985 :{WINDOW_COLOUR_2}Lemonade price: +STR_1986 :{WINDOW_COLOUR_2} +STR_1987 :{WINDOW_COLOUR_2} +STR_1988 :Balónek +STR_1989 :Plyšová Hračka +STR_1990 :Mapa +STR_1991 :Fotka z atrakce +STR_1992 :Deštník +STR_1993 :Pití +STR_1994 :Burger +STR_1995 :Lupínky +STR_1996 :Zmrzlina +STR_1997 :Cukrová vata +STR_1998 :Prázdná plechovka +STR_1999 :Odpadky +STR_2000 :Prázdná obal od burgeru +STR_2001 :Pizza +STR_2002 :Poukaz +STR_2003 :Popcorn +STR_2004 :Hot Dog +STR_2005 :Tentacle +STR_2006 :Čepice +STR_2007 :Karamelové jablko +STR_2008 :Tričko +STR_2009 :Kobliha +STR_2010 :Káva +STR_2011 :Prázdná kelímek +STR_2012 :Smažené Kuře +STR_2013 :Limonáda +STR_2014 :Prázdná krabička +STR_2015 :Prázdná láhev +STR_2016 :Balónky +STR_2017 :Plyšové hračky +STR_2018 :Mapy +STR_2019 :On-Ride Photos +STR_2020 :Umbrellas +STR_2021 :Drinks +STR_2022 :Burgers +STR_2023 :Chips +STR_2024 :Ice Creams +STR_2025 :Candyfloss +STR_2026 :Empty Cans +STR_2027 :Rubbish +STR_2028 :Empty Burger Boxes +STR_2029 :Pizzas +STR_2030 :Vouchers +STR_2031 :Popcorn +STR_2032 :Hot Dogs +STR_2033 :Tentacles +STR_2034 :Hats +STR_2035 :Toffee Apples +STR_2036 :T-Shirts +STR_2037 :Doughnuts +STR_2038 :Coffees +STR_2039 :Empty Cups +STR_2040 :Fried Chicken +STR_2041 :Lemonade +STR_2042 :Empty Boxes +STR_2043 :Empty Bottles +STR_2044 :a Balloon +STR_2045 :a Cuddly Toy +STR_2046 :a Park Map +STR_2047 :an On-Ride Photo +STR_2048 :an Umbrella +STR_2049 :a Drink +STR_2050 :a Burger +STR_2051 :some Chips +STR_2052 :an Ice Cream +STR_2053 :some Candyfloss +STR_2054 :an Empty Can +STR_2055 :some Rubbish +STR_2056 :an Empty Burger Box +STR_2057 :a Pizza +STR_2058 :a Voucher +STR_2059 :some Popcorn +STR_2060 :a Hot Dog +STR_2061 :a Tentacle +STR_2062 :a Hat +STR_2063 :a Toffee Apple +STR_2064 :a T-Shirt +STR_2065 :a Doughnut +STR_2066 :a Coffee +STR_2067 :an Empty Cup +STR_2068 :some Fried Chicken +STR_2069 :some Lemonade +STR_2070 :an Empty Box +STR_2071 :an Empty Bottle +STR_2072 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Balloon +STR_2073 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Cuddly Toy +STR_2074 :Map of {STRINGID} +STR_2075 :On-Ride Photo of {STRINGID} +STR_2076 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Umbrella +STR_2077 :Drink +STR_2078 :Burger +STR_2079 :Chips +STR_2080 :Ice Cream +STR_2081 :Candyfloss +STR_2082 :Empty Can +STR_2083 :Rubbish +STR_2084 :Empty Burger Box +STR_2085 :Pizza +STR_2086 :Voucher for {STRINGID} +STR_2087 :Popcorn +STR_2088 :Hot Dog +STR_2089 :Tentacle +STR_2090 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Hat +STR_2091 :Toffee Apple +STR_2092 :{OPENQUOTES}{STRINGID}{ENDQUOTES} T-Shirt +STR_2093 :Doughnut +STR_2094 :Coffee +STR_2095 :Empty Cup +STR_2096 :Fried Chicken +STR_2097 :Lemonade +STR_2098 :Empty Box +STR_2099 :Empty Bottle +STR_2100 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_2101 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_2102 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_2103 :{WINDOW_COLOUR_2}Pretzel price: +STR_2104 :{WINDOW_COLOUR_2}Hot Chocolate price: +STR_2105 :{WINDOW_COLOUR_2}Iced Tea price: +STR_2106 :{WINDOW_COLOUR_2}Funnel Cake price: +STR_2107 :{WINDOW_COLOUR_2}Sunglasses price: +STR_2108 :{WINDOW_COLOUR_2}Beef Noodles price: +STR_2109 :{WINDOW_COLOUR_2}Fried Rice Noodles price: +STR_2110 :{WINDOW_COLOUR_2}Wonton Soup price: +STR_2111 :{WINDOW_COLOUR_2}Meatball Soup price: +STR_2112 :{WINDOW_COLOUR_2}Fruit Juice price: +STR_2113 :{WINDOW_COLOUR_2}Soybean Milk price: +STR_2114 :{WINDOW_COLOUR_2}Sujongkwa price: +STR_2115 :{WINDOW_COLOUR_2}Sub Sandwich price: +STR_2116 :{WINDOW_COLOUR_2}Cookie price: +STR_2117 :{WINDOW_COLOUR_2} +STR_2118 :{WINDOW_COLOUR_2} +STR_2119 :{WINDOW_COLOUR_2} +STR_2120 :{WINDOW_COLOUR_2}Roast Sausage price: +STR_2121 :{WINDOW_COLOUR_2} +STR_2122 :On-Ride Photo +STR_2123 :On-Ride Photo +STR_2124 :On-Ride Photo +STR_2125 :Pretzel +STR_2126 :Hot Chocolate +STR_2127 :Iced Tea +STR_2128 :Funnel Cake +STR_2129 :Sunglasses +STR_2130 :Beef Noodles +STR_2131 :Fried Rice Noodles +STR_2132 :Wonton Soup +STR_2133 :Meatball Soup +STR_2134 :Fruit Juice +STR_2135 :Soybean Milk +STR_2136 :Sujongkwa +STR_2137 :Sub Sandwich +STR_2138 :Cookie +STR_2139 :Empty Bowl +STR_2140 :Empty Drink Carton +STR_2141 :Empty Juice Cup +STR_2142 :Roast Sausage +STR_2143 :Empty Bowl +STR_2144 :On-Ride Photos +STR_2145 :On-Ride Photos +STR_2146 :On-Ride Photos +STR_2147 :Pretzels +STR_2148 :Hot Chocolates +STR_2149 :Iced Teas +STR_2150 :Funnel Cakes +STR_2151 :Sunglasses +STR_2152 :Beef Noodles +STR_2153 :Fried Rice Noodles +STR_2154 :Wonton Soups +STR_2155 :Meatball Soups +STR_2156 :Fruit Juices +STR_2157 :Soybean Milks +STR_2158 :Sujongkwa +STR_2159 :Sub Sandwiches +STR_2160 :Cookies +STR_2161 :Empty Bowls +STR_2162 :Empty Drink Cartons +STR_2163 :Empty Juice cups +STR_2164 :Roast Sausages +STR_2165 :Empty Bowls +STR_2166 :an On-Ride Photo +STR_2167 :an On-Ride Photo +STR_2168 :an On-Ride Photo +STR_2169 :a Pretzel +STR_2170 :a Hot Chocolate +STR_2171 :an Iced Tea +STR_2172 :a Funnel Cake +STR_2173 :a pair of Sunglasses +STR_2174 :some Beef Noodles +STR_2175 :some Fried Rice Noodles +STR_2176 :some Wonton Soup +STR_2177 :some Meatball Soup +STR_2178 :a Fruit Juice +STR_2179 :some Soybean Milk +STR_2180 :some Sujongkwa +STR_2181 :a Sub Sandwich +STR_2182 :a Cookie +STR_2183 :an Empty Bowl +STR_2184 :an Empty Drink Carton +STR_2185 :an Empty Juice Cup +STR_2186 :a Roast Sausage +STR_2187 :an Empty Bowl +STR_2188 :On-Ride Photo of {STRINGID} +STR_2189 :On-Ride Photo of {STRINGID} +STR_2190 :On-Ride Photo of {STRINGID} +STR_2191 :Pretzel +STR_2192 :Hot Chocolate +STR_2193 :Iced Tea +STR_2194 :Funnel Cake +STR_2195 :Sunglasses +STR_2196 :Beef Noodles +STR_2197 :Fried Rice Noodles +STR_2198 :Wonton Soup +STR_2199 :Meatball Soup +STR_2200 :Fruit Juice +STR_2201 :Soybean Milk +STR_2202 :Sujongkwa +STR_2203 :Sub Sandwich +STR_2204 :Cookie +STR_2205 :Empty Bowl +STR_2206 :Empty Drink Carton +STR_2207 :Empty Juice Cup +STR_2208 :Roast Sausage +STR_2209 :Empty Bowl +STR_2210 :{SMALLFONT}{BLACK}Show list of handymen in park +STR_2211 :{SMALLFONT}{BLACK}Show list of mechanics in park +STR_2212 :{SMALLFONT}{BLACK}Show list of security guards in park +STR_2213 :{SMALLFONT}{BLACK}Show list of entertainers in park +STR_2214 :Construction not possible while game is paused! +STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) +STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F +STR_2218 :{RED}{STRINGID} on {STRINGID} hasn't returned to the {STRINGID} yet!{NEWLINE}Check whether it is stuck or has stalled +STR_2219 :{RED}{COMMA16} people have died in an accident on {STRINGID} +STR_2220 :{WINDOW_COLOUR_2}Park Rating: {BLACK}{COMMA16} +STR_2221 :{SMALLFONT}{BLACK}Park Rating: {COMMA16} +STR_2222 :{SMALLFONT}{BLACK}{STRINGID} +STR_2223 :{WINDOW_COLOUR_2}Guests in park: {BLACK}{COMMA16} +STR_2224 :{WINDOW_COLOUR_2}Cash: {BLACK}{CURRENCY2DP} +STR_2225 :{WINDOW_COLOUR_2}Cash: {RED}{CURRENCY2DP} +STR_2226 :{WINDOW_COLOUR_2}Park value: {BLACK}{CURRENCY} +STR_2227 :{WINDOW_COLOUR_2}Company value: {BLACK}{CURRENCY} +STR_2228 :{WINDOW_COLOUR_2}Last month's profit from food/drink and{NEWLINE}merchandise sales: {BLACK}{CURRENCY} +STR_2229 :Slope up to vertical +STR_2230 :Vertical track +STR_2231 :Holding brake for drop +STR_2232 :Cable lift hill +STR_2233 :{SMALLFONT}{BLACK}Park information +STR_2234 :Recent Messages +STR_2235 :{SMALLFONT}{STRINGID} {STRINGID} +STR_2236 :Ledna +STR_2237 :Únorna +STR_2238 :Březena +STR_2239 :Dubna +STR_2240 :Května +STR_2241 :Června +STR_2242 :Červenece +STR_2243 :Srpena +STR_2244 :Září +STR_2245 :Říjena +STR_2246 :Listopadu +STR_2247 :Prosinece +STR_2248 :Can't demolish ride/attraction... +STR_2249 :{BABYBLUE}New ride/attraction now available:{NEWLINE}{STRINGID} +STR_2250 :{BABYBLUE}New scenery/themeing now available:{NEWLINE}{STRINGID} +STR_2251 :Can only be built on paths! +STR_2252 :Can only be built across paths! +STR_2253 :Transport Rides +STR_2254 :Gentle Rides +STR_2255 :Roller Coasters +STR_2256 :Thrill Rides +STR_2257 :Water Rides +STR_2258 :Shops & Stalls +STR_2259 :Scenery & Themeing +STR_2260 :No funding +STR_2261 :Minimum funding +STR_2262 :Normal funding +STR_2263 :Maximum funding +STR_2264 :Research funding +STR_2265 :{WINDOW_COLOUR_2}Cost: {BLACK}{CURRENCY} per month +STR_2266 :Research priorities +STR_2267 :Currently in development +STR_2268 :Last development +STR_2269 :{WINDOW_COLOUR_2}Type: {BLACK}{STRINGID} +STR_2270 :{WINDOW_COLOUR_2}Progress: {BLACK}{STRINGID} +STR_2271 :{WINDOW_COLOUR_2}Expected: {BLACK}{STRINGID} +STR_2272 :{WINDOW_COLOUR_2}Ride/attraction:{NEWLINE}{BLACK}{STRINGID} +STR_2273 :{WINDOW_COLOUR_2}Scenery/themeing:{NEWLINE}{BLACK}{STRINGID} +STR_2274 :{SMALLFONT}{BLACK}Show details of this invention or development +STR_2275 :{SMALLFONT}{BLACK}Show funding and options for research & development +STR_2276 :{SMALLFONT}{BLACK}Show research & development status +STR_2277 :Unknown +STR_2278 :Transport Ride +STR_2279 :Gentle Ride +STR_2280 :Roller Coaster +STR_2281 :Thrill Ride +STR_2282 :Water Ride +STR_2283 :Shop/Stall +STR_2284 :Scenery/Themeing +STR_2285 :Initial research +STR_2286 :Designing +STR_2287 :Completing design +STR_2288 :Unknown +STR_2289 :{STRINGID} {STRINGID} +STR_2290 :{SMALLFONT}{BLACK}{STRINGID} {STRINGID} +STR_2291 :Select scenario for new game +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 +STR_2305 :Track design files +STR_2306 :Save track design +STR_2307 :Select {STRINGID} design +STR_2308 :{STRINGID} Track Designs +STR_2309 :Install New Track Design +STR_2310 :Build custom design +STR_2311 :{WINDOW_COLOUR_2}Excitement rating: {BLACK}{COMMA2DP32} (approx.) +STR_2312 :{WINDOW_COLOUR_2}Intensity rating: {BLACK}{COMMA2DP32} (approx.) +STR_2313 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}{COMMA2DP32} (approx.) +STR_2314 :{WINDOW_COLOUR_2}Ride length: {BLACK}{STRINGID} +STR_2315 :{WINDOW_COLOUR_2}Cost: {BLACK}around {CURRENCY} +STR_2316 :{WINDOW_COLOUR_2}Space required: {BLACK}{COMMA16} x {COMMA16} blocks +STR_2317 : +STR_2318 : +STR_2319 : +STR_2320 : +STR_2321 :{WINDOW_COLOUR_2}Number of rides/attractions: {BLACK}{COMMA16} +STR_2322 :{WINDOW_COLOUR_2}Staff: {BLACK}{COMMA16} +STR_2323 :{WINDOW_COLOUR_2}Park size: {BLACK}{COMMA32}m{SQUARED} +STR_2324 :{WINDOW_COLOUR_2}Park size: {BLACK}{COMMA32}sq.ft. +STR_2325 :{SMALLFONT}{BLACK}Buy land to extend park +STR_2326 :{SMALLFONT}{BLACK}Buy construction rights to allow construction above or below land outside the park +STR_2327 :Options +STR_2328 :{WINDOW_COLOUR_2}Měna: +STR_2329 :{WINDOW_COLOUR_2}Délka a rychlost: +STR_2330 :{WINDOW_COLOUR_2}Teplota: +STR_2331 :{WINDOW_COLOUR_2}Výškové značky: +STR_2332 :Jednotky +STR_2333 :Sound +STR_2334 :Libry ({POUND}) +STR_2335 :Dolary ($) +STR_2336 :Franky (F) +STR_2337 :Marka (DM) +STR_2338 :Yeny ({YEN}) +STR_2339 :Pesos (Pts) +STR_2340 :Lira (L) +STR_2341 :Guldeny (fl.) +STR_2342 :Koruny (Kč) +STR_2343 :Euroa ({EURO}) +STR_2344 :Imperiální +STR_2345 :Metrické +STR_2346 :Display +STR_2347 :{RED}{STRINGID} has drowned! +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 +STR_2358 :Units +STR_2359 :Real Values +STR_2360 :{WINDOW_COLOUR_2}Display Resolution: +STR_2361 :Landscape Smoothing +STR_2362 :{SMALLFONT}{BLACK}Toggle landscape tile edge smoothing on/off +STR_2363 :Gridlines on Landscape +STR_2364 :{SMALLFONT}{BLACK}Toggle gridlines on landscape on/off +STR_2365 :The bank refuses to increase your loan! +STR_2366 :Celsius ({DEGREE}C) +STR_2367 :Fahrenheit ({DEGREE}F) +STR_2368 :None +STR_2369 :Low +STR_2370 :Average +STR_2371 :High +STR_2372 :Low +STR_2373 :Medium +STR_2374 :High +STR_2375 :Very high +STR_2376 :Extreme +STR_2377 :Ultra-Extreme +STR_2378 :{SMALLFONT}{BLACK}Adjust smaller area of land +STR_2379 :{SMALLFONT}{BLACK}Adjust larger area of land +STR_2380 :{SMALLFONT}{BLACK}Adjust smaller area of water +STR_2381 :{SMALLFONT}{BLACK}Adjust larger area of water +STR_2382 :Land +STR_2383 :Water +STR_2384 :{WINDOW_COLOUR_2}Tvůj úkol: +STR_2385 :{BLACK}žádný +STR_2386 :{BLACK}Mít v parku alespoň {COMMA16} hostů na konci {MONTHYEAR}, s hodnocením parku alespoň 600 +STR_2387 :{BLACK}Dosáhnout hodnoty parku alespoň {POP16}{POP16}{CURRENCY} na konci {PUSH16}{PUSH16}{PUSH16}{MONTHYEAR} +STR_2388 :{BLACK}Bav se! +STR_2389 :{BLACK}Build the best {STRINGID} you can! +STR_2390 :{BLACK}Mýt v parku 10 druhů kolotoču v provozu, každy s hodnotou zábavnosti alespoň 6.00 +STR_2391 :{BLACK}Mít v parku alespoň {COMMA16} hostů a zároveň nesmíš nikdy nechat hodnocení parku spadnout pod 700! +STR_2392 :{BLACK}Dosáhnout měsíčního příjmu z lístků na atrakce alespoň {POP16}{POP16}{CURRENCY} +STR_2393 :{BLACK}{BLACK}Mýt v parku 10 druhů kolotoču v provozu, každy s hodnotou zábavnosti alespoň 7.00 a délkou alespoň {LENGHT} +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}Vrátit půjčku a dosáhnout hodnoty parku alspoň {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 :Nic +STR_2398 :Počet hostů v daný čas +STR_2399 :Hodnotu praku v dané datum +STR_2400 :Volná zábava +STR_2401 :Postav nejlepší atrakci co dokážeš +STR_2402 :Postavit 10 kolotočů +STR_2403 :Počet hostů v parku +STR_2404 :Měsíční příjem z +STR_2405 :Postavit 10 drah zadané délky +STR_2406 :Dokončit stavbu 5 kolotočů +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 : +STR_2438 : +STR_2439 : +STR_2440 : +STR_2441 : +STR_2442 : +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 +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} - +STR_2455 :{SMALLFONT}{BLACK}+{CURRENCY2DP} - +STR_2456 :{SMALLFONT}{BLACK}{CURRENCY2DP} - +STR_2457 :{SMALLFONT}{BLACK}Show financial accounts +STR_2458 :{SMALLFONT}{BLACK}Show graph of cash (less loan) over time +STR_2459 :{SMALLFONT}{BLACK}Show graph of park value over time +STR_2460 :{SMALLFONT}{BLACK}Show graph of weekly profit +STR_2461 :{SMALLFONT}{BLACK}Show marketing campaigns +STR_2462 :{SMALLFONT}{BLACK}Show view of park entrance +STR_2463 :{SMALLFONT}{BLACK}Show graph of park ratings over time +STR_2464 :{SMALLFONT}{BLACK}Show graph of guest numbers over time +STR_2465 :{SMALLFONT}{BLACK}Show park entrance price and information +STR_2466 :{SMALLFONT}{BLACK}Show park statistics +STR_2467 :{SMALLFONT}{BLACK}Show objectives for this game +STR_2468 :{SMALLFONT}{BLACK}Show recent awards this park has received +STR_2469 :{SMALLFONT}{BLACK}Select level of research & development +STR_2470 :{SMALLFONT}{BLACK}Research new transport rides +STR_2471 :{SMALLFONT}{BLACK}Research new gentle rides +STR_2472 :{SMALLFONT}{BLACK}Research new roller coasters +STR_2473 :{SMALLFONT}{BLACK}Research new thrill rides +STR_2474 :{SMALLFONT}{BLACK}Research new water rides +STR_2475 :{SMALLFONT}{BLACK}Research new shops and stalls +STR_2476 :{SMALLFONT}{BLACK}Research new scenery and themeing +STR_2477 :{SMALLFONT}{BLACK}Select operating mode for this ride/attraction +STR_2478 :{SMALLFONT}{BLACK}Show graph of velocity against time +STR_2479 :{SMALLFONT}{BLACK}Show graph of altitude against time +STR_2480 :{SMALLFONT}{BLACK}Show graph of vertical acceleration against time +STR_2481 :{SMALLFONT}{BLACK}Show graph of lateral acceleration against time +STR_2482 :{SMALLFONT}{BLACK}Profit: {CURRENCY} per week, Park Value: {CURRENCY} +STR_2483 :{WINDOW_COLOUR_2}Weekly profit: {BLACK}+{CURRENCY2DP} +STR_2484 :{WINDOW_COLOUR_2}Weekly profit: {RED}{CURRENCY2DP} +STR_2485 :Controls +STR_2486 :General +STR_2487 :Show 'real' names of guests +STR_2488 :{SMALLFONT}{BLACK}Toggle between showing 'real' names of guests and guest numbers +STR_2489 :Shortcut keys... +STR_2490 :Keyboard shortcuts +STR_2491 :Reset keys +STR_2492 :{SMALLFONT}{BLACK}Set all keyboard shortcuts back to default settings +STR_2493 :Close top-most window +STR_2494 :Close all floating windows +STR_2495 :Cancel construction mode +STR_2496 :Pause game +STR_2497 :Zoom view out +STR_2498 :Zoom view in +STR_2499 :Rotate view clockwise +STR_2500 :Rotate construction object +STR_2501 :Underground view toggle +STR_2502 :Remove base land toggle +STR_2503 :Remove vertical land toggle +STR_2504 :See-through rides toggle +STR_2505 :See-through scenery toggle +STR_2506 :Invisible supports toggle +STR_2507 :Invisible people toggle +STR_2508 :Height marks on land toggle +STR_2509 :Height marks on ride tracks toggle +STR_2510 :Height marks on paths toggle +STR_2511 :Adjust land +STR_2512 :Adjust water +STR_2513 :Build scenery +STR_2514 :Build paths +STR_2515 :Build new ride +STR_2516 :Show financial information +STR_2517 :Show research information +STR_2518 :Show rides list +STR_2519 :Show park information +STR_2520 :Show guest list +STR_2521 :Show staff list +STR_2522 :Show recent messages +STR_2523 :Show map +STR_2524 :Screenshot +### The following need to be reordered to match SDL_keycode layout. +STR_2525 :??? +STR_2526 :??? +STR_2527 :??? +STR_2528 :??? +STR_2529 :??? +STR_2530 :??? +STR_2531 :??? +STR_2532 :??? +STR_2533 :Backspace +STR_2534 :Tab +STR_2535 :??? +STR_2536 :??? +STR_2537 :Clear +STR_2538 :Return +STR_2539 :??? +STR_2540 :??? +STR_2541 :??? +STR_2542 :??? +STR_2543 :Alt/Menu +STR_2544 :Pause +STR_2545 :Caps +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 :Spacebar +STR_2558 :PgUp +STR_2559 :PgDn +STR_2560 :End +STR_2561 :Home +STR_2562 :Left +STR_2563 :Up +STR_2564 :Right +STR_2565 :Down +STR_2566 :Select +STR_2567 :Print +STR_2568 :Execute +STR_2569 :Snapshot +STR_2570 :Insert +STR_2571 :Delete +STR_2572 :Help +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 :NumPad 0 +STR_2622 :NumPad 1 +STR_2623 :NumPad 2 +STR_2624 :NumPad 3 +STR_2625 :NumPad 4 +STR_2626 :NumPad 5 +STR_2627 :NumPad 6 +STR_2628 :NumPad 7 +STR_2629 :NumPad 8 +STR_2630 :NumPad 9 +STR_2631 :NumPad * +STR_2632 :NumPad + +STR_2633 :??? +STR_2634 :NumPad - +STR_2635 :NumPad . +STR_2636 :NumPad / +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 :NumLock +STR_2670 :Scroll +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 {CURRENCY} +STR_2682 : +STR_2683 : +STR_2684 :{SMALLFONT}{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 minute +STR_2702 :Every 5 minutes +STR_2703 :Every 15 minutes +STR_2704 :Every 30 minutes +STR_2705 :Every hour +STR_2706 :Never +STR_2707 :Use system dialog 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}, 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 :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 :+{CURRENCY} +STR_2761 : +STR_2762 : +STR_2763 :??? +STR_2764 : +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 +# End of new strings +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} +STR_2782 :SHIFT + +STR_2783 :CTRL + +STR_2784 :Change keyboard shortcut +STR_2785 :{WINDOW_COLOUR_2}Press new shortcut key for:{NEWLINE}{OPENQUOTES}{STRINGID}{ENDQUOTES} +STR_2786 :{SMALLFONT}{BLACK}Click on shortcut description to select new key +STR_2787 :{WINDOW_COLOUR_2}Park value: {BLACK}{CURRENCY} +STR_2788 :{WINDOW_COLOUR_2}Congratulations !{NEWLINE}{BLACK}You achieved your objective with a company value of {CURRENCY} ! +STR_2789 :{WINDOW_COLOUR_2}You have failed your objective ! +STR_2790 :Enter name into scenario chart +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_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_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 +STR_2806 :{RED}Guests are complaining about the disgusting state of the paths in your park{NEWLINE}Check where your handymen are and consider organising them better +STR_2807 :{RED}Guests are complaining about the amount of litter in your park{NEWLINE}Check where your handymen are and consider organising them better +STR_2808 :{RED}Guests are complaining about the vandalism in your park{NEWLINE}Check where your security guards are and consider organising 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 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 +STR_2815 :{WINDOW_COLOUR_2}Tidiest park award +STR_2816 :{WINDOW_COLOUR_2}Award for the park with the best roller coasters +STR_2817 :{WINDOW_COLOUR_2}Best value park award +STR_2818 :{WINDOW_COLOUR_2}Most beautiful park award +STR_2819 :{WINDOW_COLOUR_2}Worst value park award +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 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 +STR_2828 :{WINDOW_COLOUR_2}Most dazzling ride colour schemes award +STR_2829 :{WINDOW_COLOUR_2}Most confusing park layout award +STR_2830 :{WINDOW_COLOUR_2}Best gentle ride award +STR_2831 :{TOPAZ}Your park has received an award for being 'The most untidy park in the country'! +STR_2832 :{TOPAZ}Your park has received an award for being 'The tidiest park in the country'! +STR_2833 :{TOPAZ}Your park has received an award for being 'The park with the best roller coasters'! +STR_2834 :{TOPAZ}Your park has received an award for being 'The best value park in the country'! +STR_2835 :{TOPAZ}Your park has received an award for being 'The most beautiful park in the country'! +STR_2836 :{TOPAZ}Your park has received an award for being 'The worst value park in the country'! +STR_2837 :{TOPAZ}Your park has received an award for being 'The safest park in the country'! +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 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'! +STR_2845 :{TOPAZ}Your park has received an award for being 'The park with the most dazzling choice of colour schemes'! +STR_2846 :{TOPAZ}Your park has received an award for being 'The park with the most confusing layout'! +STR_2847 :{TOPAZ}Your park has received an award for being 'The park with the best gentle rides'! +STR_2848 :{WINDOW_COLOUR_2}No recent awards +STR_2849 :New scenario installed successfully +STR_2850 :New track design installed successfully +STR_2851 :Scenario already installed +STR_2852 :Track design already installed +STR_2853 :Forbidden by the local authority! +STR_2854 :{RED}Guests can't get to the entrance of {STRINGID} !{NEWLINE}Construct a path to the entrance +STR_2855 :{RED}{STRINGID} has no path leading from its exit !{NEWLINE}Construct a path from the ride exit +STR_2856 :{WINDOW_COLOUR_2}Tutorial +STR_2857 :{WINDOW_COLOUR_2}(Press a key or mouse button to take control) +STR_2858 :Can't start marketing campaign... +STR_2859 :Another instance of OpenRCT2 is already running +STR_2860 :Infogrames Interactive credits... +STR_2861 :{WINDOW_COLOUR_2}Licensed to Infogrames Interactive Inc. +STR_2862 :Music acknowledgements... +STR_2863 :Music acknowledgements +STR_2864 :{WINDOW_COLOUR_2}March - Children of the Regiment: (Fucik) non copyright +STR_2865 :{WINDOW_COLOUR_2}Heyken's Serenade: (J.Heyken) British Standard Music Coy; GEMA, BRITICO +STR_2866 :{WINDOW_COLOUR_2}In Continental Mood: (Composer unknown) Copyright Control +STR_2867 :{WINDOW_COLOUR_2}Wedding Journey: (Traditional) +STR_2868 :{WINDOW_COLOUR_2}Tales from the Vienna Woods: (Johann Strauss) non copyright +STR_2869 :{WINDOW_COLOUR_2}Slavonic Dance: (Traditional) +STR_2870 :{WINDOW_COLOUR_2}Das Alpenhorn: (Traditional) +STR_2871 :{WINDOW_COLOUR_2}The Blond Sailor: (Traditional) +STR_2872 :{WINDOW_COLOUR_2}Overture - Poet and Peasant: (Suppe) non copyright +STR_2873 :{WINDOW_COLOUR_2}Waltz Medley: (Johann Strauss) non copyright +STR_2874 :{WINDOW_COLOUR_2}Bella Bella Bimba: (Traditional) +STR_2875 :{WINDOW_COLOUR_2}Original recordings (P) 1976 C.J.Mears Organization, used with consent +STR_2876 :{WINDOW_COLOUR_2}RollerCoaster Tycoon 2 Title Music: (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, played by Peter James Adcock) recording {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}Senior Producer: Thomas J. Zahorik +STR_2910 :{WINDOW_COLOUR_2}Executive Producer: Bill Levay +STR_2911 :{WINDOW_COLOUR_2}Senior Marketing Product Manager: Scott Triola +STR_2912 :{WINDOW_COLOUR_2}V.P. of Product Development: Scott Walker +STR_2913 :{WINDOW_COLOUR_2}General Manager: John Hurlbut +STR_2914 :{WINDOW_COLOUR_2}Director of Quality Assurance: Michael Craighead +STR_2915 :{WINDOW_COLOUR_2}Q.A. Certification Manager: Kurt Boutin +STR_2916 :{WINDOW_COLOUR_2}Q.A. Certification Lead: Mark Huggins +STR_2917 :{WINDOW_COLOUR_2}Testers: Dena Irene Fitzgerald, Scott Rollins, Christopher McPhail +STR_2918 :{WINDOW_COLOUR_2}Clif McClure, Erik Maramaldi, Erik Jeffery +STR_2919 :{WINDOW_COLOUR_2}Director of Marketing: Ann Marie Bland +STR_2920 :{WINDOW_COLOUR_2}Manager of Creative Services: Steve Martin +STR_2921 :{WINDOW_COLOUR_2}Manager of Editorial & Documentation Services: Elizabeth Mackney +STR_2922 :{WINDOW_COLOUR_2}Graphic Designer: Paul Anselmi +STR_2923 :{WINDOW_COLOUR_2}Copywriter: Kurt Carlson +STR_2924 :{WINDOW_COLOUR_2}Special Thanks to: Peter Matiss +STR_2925 :{WINDOW_COLOUR_2}Engineering Specialist: Ken Edwards +STR_2926 :{WINDOW_COLOUR_2}Engineering Services Manager: Luis Rivas +STR_2927 :{WINDOW_COLOUR_2}Lead Compatibility Analyst: Geoffrey Smith +STR_2928 :{WINDOW_COLOUR_2}Compatibility Analysts: Jason Cordero, Burke McQuinn, Kim Jardin +STR_2929 :{WINDOW_COLOUR_2}Lead Tester: Daniel Frisoli +STR_2930 :{WINDOW_COLOUR_2}Senior Tester: 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 : +STR_2970 : +STR_2971 :Main colour scheme +STR_2972 :Alternative colour scheme 1 +STR_2973 :Alternative colour scheme 2 +STR_2974 :Alternative colour scheme 3 +STR_2975 :{SMALLFONT}{BLACK}Select which colour scheme to change, or paint ride with +STR_2976 :{SMALLFONT}{BLACK}Paint an individual area of this ride using the selected colour scheme +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_2982 :Banner text +STR_2983 :Enter new text for this banner: +STR_2984 :Can't set new text for banner... +STR_2985 :Banner +STR_2986 :{SMALLFONT}{BLACK}Change text on banner +STR_2987 :{SMALLFONT}{BLACK}Set this banner as a 'no-entry' sign for guests +STR_2988 :{SMALLFONT}{BLACK}Demolish this banner +STR_2989 :{SMALLFONT}{BLACK}Select main colour +STR_2990 :{SMALLFONT}{BLACK}Select text colour +STR_2991 :Sign +STR_2992 :Sign text +STR_2993 :Enter new text for this sign: +STR_2994 :{SMALLFONT}{BLACK}Change text on sign +STR_2995 :{SMALLFONT}{BLACK}Demolish this sign +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 :Unable to load file... +STR_3011 :File contains invalid data +STR_3012 :Dodgems beat style +STR_3013 :Fairground organ style +STR_3014 :Roman fanfare style +STR_3015 :Oriental style +STR_3016 :Martian style +STR_3017 :Jungle drums style +STR_3018 :Egyptian style +STR_3019 :Toyland style +STR_3020 : +STR_3021 :Space style +STR_3022 :Horror style +STR_3023 :Techno style +STR_3024 :Gentle style +STR_3025 :Summer style +STR_3026 :Water style +STR_3027 :Wild west style +STR_3028 :Jurassic style +STR_3029 :Rock style +STR_3030 :Ragtime style +STR_3031 :Fantasy style +STR_3032 :Rock style 2 +STR_3033 :Ice style +STR_3034 :Snow style +STR_3035 :Custom music 1 +STR_3036 :Custom music 2 +STR_3037 :Medieval style +STR_3038 :Urban style +STR_3039 :Organ style +STR_3040 :Mechanical style +STR_3041 :Modern style +STR_3042 :Pirates style +STR_3043 :Rock style 3 +STR_3044 :Candy style +STR_3045 :{SMALLFONT}{BLACK}Select style of music to play +STR_3046 :This ride cannot be modified +STR_3047 :Local authority forbids demolition or modifications to this ride +STR_3048 :Marketing campaigns forbidden by local authority +STR_3049 :Golf hole A +STR_3050 :Golf hole B +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_3057 :{WINDOW_COLOUR_2}Construction Marker: +STR_3058 :Brick walls +STR_3059 :Hedges +STR_3060 :Ice blocks +STR_3061 :Wooden fences +STR_3062 :{SMALLFONT}{BLACK}Standard roller coaster track +STR_3063 :{SMALLFONT}{BLACK}Water channel (track submerged) +STR_3064 :Beginner Parks +STR_3065 :Challenging Parks +STR_3066 :Expert Parks +STR_3067 :{OPENQUOTES}Real{ENDQUOTES} Parks +STR_3068 :Other Parks +STR_3069 :Top Section +STR_3070 :Slope to Level +STR_3071 :{WINDOW_COLOUR_2}Same price throughout park +STR_3072 :{SMALLFONT}{BLACK}Select whether this price is used throughout the entire park +STR_3073 :{RED}WARNING: Your park rating has dropped below 700 !{NEWLINE}If you haven't raised the park rating in 4 weeks, your park will be closed down +STR_3074 :{RED}WARNING: Your park rating is still below 700 !{NEWLINE}You have 3 weeks to raise the park rating +STR_3075 :{RED}WARNING: Your park rating is still below 700 !{NEWLINE}You have only 2 weeks to raise the park rating, or your park will be closed down +STR_3076 :{RED}FINAL WARNING: Your park rating is still below 700 !{NEWLINE}In just 7 days your park will be closed down unless you can raise the rating +STR_3077 :{RED}CLOSURE NOTICE: Your park has been closed down ! +STR_3078 :Plain entrance +STR_3079 :Wooden entrance +STR_3080 :Canvas tent entrance +STR_3081 :Castle entrance (grey) +STR_3082 :Castle entrance (brown) +STR_3083 :Jungle entrance +STR_3084 :Log cabin entrance +STR_3085 :Classical/Roman entrance +STR_3086 :Abstract entrance +STR_3087 :Snow/Ice entrance +STR_3088 :Pagoda entrance +STR_3089 :Space entrance +STR_3090 :{SMALLFONT}{BLACK}Select style of entrance, exit, and station +STR_3091 :You are not allowed to remove this section! +STR_3092 :You are not allowed to move or modify the station for this ride! +STR_3093 :{WINDOW_COLOUR_2}Favourite: {BLACK}{STRINGID} +STR_3094 :N/A +STR_3095 :{WINDOW_COLOUR_2}Lift hill chain speed: +STR_3096 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} +STR_3097 :{SMALLFONT}{BLACK}Select lift hill chain speed +STR_3098 :Can't change lift hill speed... +STR_3099 :{SMALLFONT}{BLACK}Select colour +STR_3100 :{SMALLFONT}{BLACK}Select second colour +STR_3101 :{SMALLFONT}{BLACK}Select third colour +STR_3102 :{SMALLFONT}{BLACK}Re-paint coloured scenery on landscape +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 +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 +STR_3113 :Select a different design +STR_3114 :{SMALLFONT}{BLACK}Go back to design selection window +STR_3115 :{SMALLFONT}{BLACK}Save track design +STR_3116 :{SMALLFONT}{BLACK}Save track design (Not possible until ride has been tested and statistics have been generated) +STR_3117 :{BLACK}Calling mechanic... +STR_3118 :{BLACK}{STRINGID} is heading for the ride +STR_3119 :{BLACK}{STRINGID} is fixing the ride +STR_3120 :{SMALLFONT}{BLACK}Locate nearest available mechanic, or mechanic fixing ride +STR_3121 :Unable to locate mechanic, or all nearby mechanics are busy +STR_3122 :{WINDOW_COLOUR_2}Favourite ride of: {BLACK}{COMMA16} guest +STR_3123 :{WINDOW_COLOUR_2}Favourite ride of: {BLACK}{COMMA16} guests +STR_3124 :Broken {STRINGID} +STR_3125 :{WINDOW_COLOUR_2}Excitement Factor: {BLACK}+{COMMA16}% +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_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) +STR_3135 :{RED}(Vehicle design unavailable - Ride performance may be affected) +STR_3136 :Warning: This design will be built with an alternative vehicle type and may not perform as expected +STR_3137 :Select Nearby Scenery +STR_3138 :Reset Selection +STR_3139 :Cable lift unable to work in this operating mode +STR_3140 :Cable lift hill must start immediately after station +STR_3141 :Multi-circuit per ride not possible with cable lift hill +STR_3142 :{WINDOW_COLOUR_2}Capacity: {BLACK}{STRINGID} +STR_3143 :{SMALLFONT}{BLACK}Show people on map +STR_3144 :{SMALLFONT}{BLACK}Show rides and stalls on map +STR_3145 :{SMALLFONT}{BLACK}Scroll {STRINGID} left +STR_3146 :{SMALLFONT}{BLACK}Scroll {STRINGID} right +STR_3147 :{SMALLFONT}{BLACK}Scroll {STRINGID} left fast +STR_3148 :{SMALLFONT}{BLACK}Scroll {STRINGID} right fast +STR_3149 :{SMALLFONT}{BLACK}Scroll {STRINGID} left/right +STR_3150 :{SMALLFONT}{BLACK}Scroll {STRINGID} up +STR_3151 :{SMALLFONT}{BLACK}Scroll {STRINGID} down +STR_3152 :{SMALLFONT}{BLACK}Scroll {STRINGID} up fast +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_3160 : +STR_3161 : +STR_3162 :Unable to allocate enough memory +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_3169 :Data for the following object not found: +STR_3170 :Not enough space for graphics +STR_3171 :Too many objects of this type selected +STR_3172 :The following object must be selected first: {STRING} +STR_3173 :This object is currently in use +STR_3174 :This object is required by another object +STR_3175 :This object is always required +STR_3176 :Unable to select this object +STR_3177 :Unable to de-select this object +STR_3178 :At least one path object must be selected +STR_3179 :At least one ride vehicle/attraction object must be selected +STR_3180 :Invalid selection of objects +STR_3181 :Object Selection - {STRINGID} +STR_3182 :Park entrance type must be selected +STR_3183 :Water type must be selected +STR_3184 :Ride Vehicles/Attractions +STR_3185 :Small Scenery +STR_3186 :Large Scenery +STR_3187 :Walls/Fences +STR_3188 :Path Signs +STR_3189 :Footpaths +STR_3190 :Path Extras +STR_3191 :Scenery Groups +STR_3192 :Park Entrance +STR_3193 :Water +STR_3194 :Scenario Description +STR_3195 :Invention List +STR_3196 :{WINDOW_COLOUR_2}Research Group: {BLACK}{STRINGID} +STR_3197 :{WINDOW_COLOUR_2}Items pre-invented at start of game: +STR_3198 :{WINDOW_COLOUR_2}Items to invent during game: +STR_3199 :Random Shuffle +STR_3200 :{SMALLFONT}{BLACK}Randomly shuffle the list of items to invent during the game +STR_3201 :Object Selection +STR_3202 :Landscape Editor +STR_3203 :Invention List Set Up +STR_3204 :Options Selection +STR_3205 :Objective Selection +STR_3206 :Save Scenario +STR_3207 :Roller Coaster Designer +STR_3208 :Track Designs Manager +STR_3209 :Back to Previous Step: +STR_3210 :Forward to Next Step: +STR_3211 :{WINDOW_COLOUR_2}Map size: +STR_3212 :{POP16}{COMMA16} x {PUSH16}{COMMA16} +STR_3213 :Can't decrease map size any further +STR_3214 :Can't increase map size any further +STR_3215 :Too close to edge of map +STR_3216 :{SMALLFONT}{BLACK}Select park-owned land etc. +STR_3217 :Land Owned +STR_3218 :Construction Rights Owned +STR_3219 :Land For Sale +STR_3220 :Construction Rights For Sale +STR_3221 :{SMALLFONT}{BLACK}Set land to be owned by the park +STR_3222 :{SMALLFONT}{BLACK}Set construction rights only to be owned by the park +STR_3223 :{SMALLFONT}{BLACK}Set land to be available to purchase by the park +STR_3224 :{SMALLFONT}{BLACK}Set construction rights to be available to purchase by the park +STR_3225 :{SMALLFONT}{BLACK}Toggle on/off building a random cluster of objects around the selected position +STR_3226 :{SMALLFONT}{BLACK}Build park entrance +STR_3227 :Too many park entrances! +STR_3228 :{SMALLFONT}{BLACK}Set starting positions for people +STR_3229 :Block Brakes cannot be used directly after station +STR_3230 :Block Brakes cannot be used directly after each other +STR_3231 :Block Brakes cannot be used directly after the top of this lift hill +STR_3232 :Options - Financial +STR_3233 :Options - Guests +STR_3234 :Options - Park +STR_3235 :{SMALLFONT}{BLACK}Show financial options +STR_3236 :{SMALLFONT}{BLACK}Show guest options +STR_3237 :{SMALLFONT}{BLACK}Show park options +STR_3238 :No Money +STR_3239 :{SMALLFONT}{BLACK}Make this park a 'no money' park with no financial restrictions +STR_3240 :{WINDOW_COLOUR_2}Initial cash: +STR_3241 :{WINDOW_COLOUR_2}Initial loan: +STR_3242 :{WINDOW_COLOUR_2}Maximum loan size: +STR_3243 :{WINDOW_COLOUR_2}Annual interest rate: +STR_3244 :Forbid marketing campaigns +STR_3245 :{SMALLFONT}{BLACK}Forbid advertising, promotional schemes, and other marketing campaigns +STR_3246 :{WINDOW_COLOUR_2}{CURRENCY} +STR_3247 :{WINDOW_COLOUR_2}{COMMA16}% +STR_3248 :Can't increase initial cash any further! +STR_3249 :Can't reduce initial cash any further! +STR_3250 :Can't increase initial loan any further! +STR_3251 :Can't reduce initial loan any further! +STR_3252 :Can't increase maximum loan size any further! +STR_3253 :Can't reduce maximum loan size any further! +STR_3254 :Can't increase interest rate any further! +STR_3255 :Can't reduce interest rate any further! +STR_3256 :Guests prefer less intense rides +STR_3257 :{SMALLFONT}{BLACK}Select whether guests should generally prefer less intense rides only +STR_3258 :Guests prefer more intense rides +STR_3259 :{SMALLFONT}{BLACK}Select whether guests should generally prefer more intense rides only +STR_3260 :{WINDOW_COLOUR_2}Cash per guest (average): +STR_3261 :{WINDOW_COLOUR_2}Guests initial happiness: +STR_3262 :{WINDOW_COLOUR_2}Guests initial hunger: +STR_3263 :{WINDOW_COLOUR_2}Guests initial thirst: +STR_3264 :Can't increase this any further! +STR_3265 :Can't reduce this any further! +STR_3266 :{SMALLFONT}{BLACK}Select how this park charges for entrance and rides +STR_3267 :Forbid tree removal +STR_3268 :{SMALLFONT}{BLACK}Forbid tall trees being removed +STR_3269 :Forbid landscape changes +STR_3270 :{SMALLFONT}{BLACK}Forbid any changes to the landscape +STR_3271 :Forbid high construction +STR_3272 :{SMALLFONT}{BLACK}Forbid any tall construction +STR_3273 :Park rating higher difficult level +STR_3274 :{SMALLFONT}{BLACK}Make the park rating value more challenging +STR_3275 :Guest generation higher difficult level +STR_3276 :{SMALLFONT}{BLACK}Make it more difficult to attract guests to the park +STR_3277 :{WINDOW_COLOUR_2}Cost to buy land: +STR_3278 :{WINDOW_COLOUR_2}Cost to buy construction rights: +STR_3279 :Free park entry / Pay per ride +STR_3280 :Pay to enter park / Free rides +STR_3281 :{WINDOW_COLOUR_2}Entry price: +STR_3282 :{SMALLFONT}{BLACK}Select objective and park name +STR_3283 :{SMALLFONT}{BLACK}Select rides to be preserved +STR_3284 :Objective Selection +STR_3285 :Preserved Rides +STR_3286 :{SMALLFONT}{BLACK}Select objective for this scenario +STR_3287 :{WINDOW_COLOUR_2}Objective: +STR_3288 :{SMALLFONT}{BLACK}Select climate +STR_3289 :{WINDOW_COLOUR_2}Climate: +STR_3290 :Cool and wet +STR_3291 :Warm +STR_3292 :Hot and dry +STR_3293 :Cold +STR_3294 :Change... +STR_3295 :{SMALLFONT}{BLACK}Change name of park +STR_3296 :{SMALLFONT}{BLACK}Change name of scenario +STR_3297 :{SMALLFONT}{BLACK}Change detail notes about park / scenario +STR_3298 :{WINDOW_COLOUR_2}Park Name: {BLACK}{STRINGID} +STR_3299 :{WINDOW_COLOUR_2}Park/Scenario Details: +STR_3300 :{WINDOW_COLOUR_2}Scenario Name: {BLACK}{STRINGID} +STR_3301 :{WINDOW_COLOUR_2}Objective Date: +STR_3302 :{WINDOW_COLOUR_2}{MONTHYEAR} +STR_3303 :{WINDOW_COLOUR_2}Number of guests: +STR_3304 :{WINDOW_COLOUR_2}Park value: +STR_3305 :{WINDOW_COLOUR_2}Monthly income: +STR_3306 :{WINDOW_COLOUR_2}Monthly profit: +STR_3307 :{WINDOW_COLOUR_2}Minimum length: +STR_3308 :{WINDOW_COLOUR_2}Excitement rating: +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_3314 :Enter name for scenario: +STR_3315 :Park/Scenario Details +STR_3316 :Enter description of this scenario: +STR_3317 :No details yet +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_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_3327 :Starting positions for people not set +STR_3328 :Can't advance to next editor stage... +STR_3329 :Park entrance not yet built +STR_3330 :Park must own some land +STR_3331 :Path from park entrance to map edge either not complete or too complex - Path must be single-width with as few junctions and corners as possible +STR_3332 :Park entrance is the wrong way round or has no path leading to the map edge +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 : +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_3341 :{SMALLFONT}{BLACK}Game tools +STR_3342 :Scenario Editor +STR_3343 :Convert Saved Game to Scenario +STR_3344 :Roller Coaster Designer +STR_3345 :Track Designs Manager +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 : +STR_3363 : +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}= 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... +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_3385 :Beginners Tutorial +STR_3386 :Custom Rides Tutorial +STR_3387 :Roller Coaster Building Tutorial +STR_3388 :Unable to switch to selected mode +STR_3389 :Unable to select additional item of scenery... +STR_3390 :Too many items selected +# Start of tutorial strings. Not used at the moment, so not necessary to translate. +STR_3391 :{SMALLFONT}{BLACK}Here is our park - Let's have a quick look around... +STR_3392 :{SMALLFONT}{BLACK}Holding down the RIGHT mouse button and moving the mouse is the quickest way to move the view... +STR_3393 :{SMALLFONT}{BLACK}To view more of the park, you can zoom the view out using the icon at the top of the screen... +STR_3394 :{SMALLFONT}{BLACK}You can also rotate the view in 90 degree steps... +STR_3395 :{SMALLFONT}{BLACK}Building anything at this scale is a bit difficult, so let's zoom the view back in again... +STR_3396 :{SMALLFONT}{BLACK}Let's build a simple ride to get the park started... +STR_3397 :{SMALLFONT}{BLACK}The white 'ghost' image shows where the ride will be built. We'll move the pointer to select the position then click to build it... +STR_3398 :{SMALLFONT}{BLACK}Rides need an entrance and an exit. We'll move the pointer to a square on the edge of the ride and then click to build first the entrance and then the exit... +STR_3399 :{SMALLFONT}{BLACK}We need to build footpaths to allow guests to reach our new ride... +STR_3400 :{SMALLFONT}{BLACK}For the path to the ride entrance we'll use a special 'queue line' path... +STR_3401 :{SMALLFONT}{BLACK}For the exit path, just an 'ordinary' path will do... +STR_3402 :{SMALLFONT}{BLACK}Right, lets open the ride! To open the ride we click the flag icon on the ride window and select 'open'... +STR_3403 :{SMALLFONT}{BLACK}But where are the guests? +STR_3404 :{SMALLFONT}{BLACK}Oh - The park is still closed! Right - Let's open it... +STR_3405 :{SMALLFONT}{BLACK}While we're waiting for our first guests, let's build some scenery... +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 customise the ride a bit... +# End of tutorial strings +STR_3437 :{SMALLFONT}{BLACK}Clear large areas of scenery from landscape +STR_3438 :Unable to remove all scenery from here... +STR_3439 :Clear Scenery +STR_3440 :Strana 1 +STR_3441 :Strana 2 +STR_3442 :Strana 3 +STR_3443 :Strana 4 +STR_3444 :Strana 5 +STR_3445 :Set Patrol Area +STR_3446 :Cancel Patrol Area + +# New strings, cleaner +STR_5120 :Finances +STR_5121 :Research +STR_5122 :Select rides by track type (like in RCT1) +STR_5123 :Renew rides +STR_5124 : +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 :Normální rychlost +STR_5143 :Quick Speed +STR_5144 :Fast Speed +STR_5145 :Turbo Speed +STR_5146 :Hyper Speed +STR_5147 :Cheats +STR_5148 :{SMALLFONT}{BLACK}Change the game speed +STR_5149 :{SMALLFONT}{BLACK}Show cheat options +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 :{POP16}{MONTH} {PUSH16}{PUSH16}{STRINGID}, Year {POP16}{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 :Výzkum +STR_5190 :Mapa +STR_5191 :Viewport +STR_5192 :Poslední novinky +STR_5193 :Pozemky +STR_5194 :Voda +STR_5195 :Vyčistit scénář +STR_5196 :Pozemková práva +STR_5197 :Scenery +STR_5198 :Cesta +STR_5199 :Ride Construction +STR_5200 :Track Design Place +STR_5201 :New Ride +STR_5202 :Track Design Selection +STR_5203 :Atrakce +STR_5204 :Seznam atrakcí +STR_5205 :Host +STR_5206 :Seznam hostů +STR_5207 :Zaměstnanci +STR_5208 :seznam zaměstnanců +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 :Nastavení +STR_5220 :Klávesové zkratky +STR_5221 :Změnit klávesové zkratky +STR_5222 :Načíst/uložit +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}Hlavní UI +STR_5229 :{SMALLFONT}{BLACK}Park +STR_5230 :{SMALLFONT}{BLACK}Nástroje +STR_5231 :{SMALLFONT}{BLACK}Rides and Peeps +STR_5232 :{SMALLFONT}{BLACK}Editory +STR_5233 :{SMALLFONT}{BLACK}Ostatní +STR_5234 :{SMALLFONT}{BLACK}Prompts +STR_5235 :{SMALLFONT}{BLACK}Nastavení +STR_5236 :Okno: +STR_5237 :Paleta: +STR_5238 :Current Theme: +STR_5239 :Duplikovat +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 :Create +STR_5255 :{SMALLFONT}{BLACK}Create a new title sequence from scratch +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 and interface +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 :{SMALLFONT}{BLACK}Makes some 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 :Park cheats +STR_5348 :Ride cheats +STR_5349 :{SMALLFONT}{BLACK}All Rides +STR_5350 :Max +STR_5351 :Min +STR_5352 :{BLACK}Happiness: +STR_5353 :{BLACK}Energy: +STR_5354 :{BLACK}Hunger: +STR_5355 :{BLACK}Thirst: +STR_5356 :{BLACK}Nausea: +STR_5357 :{BLACK}Nausea tolerance: +STR_5358 :{BLACK}Bathroom: +STR_5359 :Remove guests +STR_5360 :{SMALLFONT}{BLACK}Removes all guests from the map +STR_5361 :Give all guests: +STR_5362 :{BLACK}Set all guests' preferred ride intensity to: +STR_5363 :More than 1 +STR_5364 :Less than 15 +STR_5365 :{BLACK}Staff speed: +STR_5366 :Normal +STR_5367 :Fast +STR_5368 :Reset crash status +STR_5369 :Park parameters... +STR_5370 :{SMALLFONT}{BLACK}Click this button to modify park{NEWLINE}parameters like restrictions,{NEWLINE}guest generation and money. +STR_5371 :Object Selection +STR_5372 :Invert right mouse dragging +STR_5373 :Name {STRINGID} +STR_5374 :Date {STRINGID} +STR_5375 :{UP} +STR_5376 :{DOWN} +STR_5377 :{SMALLFONT}{BLACK}Saves +STR_5378 :{SMALLFONT}{BLACK}Script +STR_5379 :{SMALLFONT}{BLACK}Skip to next wait command +STR_5380 :{SMALLFONT}{BLACK}Start playing title sequence +STR_5381 :{SMALLFONT}{BLACK}Stop playing title sequence +STR_5382 :{SMALLFONT}{BLACK}Restart title sequence +STR_5383 :{SMALLFONT}{BLACK}Create a new title sequence based on the current one +STR_5384 :{SMALLFONT}{BLACK}Delete the current title sequence +STR_5385 :{SMALLFONT}{BLACK}Rename the current title sequence +STR_5386 :{SMALLFONT}{BLACK}Insert a new command +STR_5387 :{SMALLFONT}{BLACK}Edit the selected command +STR_5388 :{SMALLFONT}{BLACK}Delete the selected command +STR_5389 :{SMALLFONT}{BLACK}Skip to the selected command in the title sequence +STR_5390 :{SMALLFONT}{BLACK}Move the selected command down +STR_5391 :{SMALLFONT}{BLACK}Move the selected command up +STR_5392 :{SMALLFONT}{BLACK}Add a save to the title sequence +STR_5393 :{SMALLFONT}{BLACK}Remove the selected save from the title sequence +STR_5394 :{SMALLFONT}{BLACK}Rename the selected save +STR_5395 :{SMALLFONT}{BLACK}Load the selected save in game +STR_5396 :{SMALLFONT}{BLACK}Reload the title sequence if changes have been made to it outside of the game +STR_5397 :Can only be used on the title screen +STR_5398 :Cannot edit title sequence while it's playing +STR_5399 :Press the stop button to continue editing +STR_5400 :Can't change this title sequence +STR_5401 :Create a new title sequence to make changes to +STR_5402 :Failed to load title sequence +STR_5403 :There may be no Load or Wait command or a save may be invalid +STR_5404 :Name already exists +STR_5405 :Enter a name for the save +STR_5406 :Enter a name for the title sequence +STR_5407 :Add +STR_5408 :Remove +STR_5409 :Insert +STR_5410 :Edit +STR_5411 :Reload +STR_5412 :Skip to +STR_5413 :Load +STR_5414 :Load{MOVE_X}{87}Six Flags Magic Mountain.SC6 +STR_5415 :Load{MOVE_X}{87}{STRING} +STR_5416 :Load{MOVE_X}{87}No save selected +STR_5417 :Location +STR_5418 :Location{MOVE_X}{87}{COMMA16} {COMMA16} +STR_5419 :Rotate +STR_5420 :Rotate{MOVE_X}{87}{COMMA16} +STR_5421 :Zoom +STR_5422 :Zoom{MOVE_X}{87}{COMMA16} +STR_5423 :Wait +STR_5424 :Wait{MOVE_X}{87}{COMMA16} +STR_5425 :Restart +STR_5426 :End +STR_5427 :Coordinates: +STR_5428 :Anticlockwise rotations: +STR_5429 :Zoom level: +STR_5430 :Seconds to wait: +STR_5431 :Save to load: +STR_5432 :Command: +STR_5433 :Title Sequences +STR_5434 :Command Editor +STR_5435 :Rename save +STR_5436 :Edit Title Sequences... +STR_5437 :No save selected +STR_5438 :Can't make changes while command editor is open +STR_5439 :A wait command with at least 4 seconds is required with a restart command +STR_5440 :Minimise fullscreen on focus loss +STR_5441 :{SMALLFONT}{BLACK}Identifies rides by track type,{NEWLINE}so vehicles can be changed{NEWLINE}afterwards, like in RCT1. +STR_5442 :Force park rating: +STR_5443 :Speed{MOVE_X}{87}{STRINGID} +STR_5444 :Speed: +STR_5445 :Speed +STR_5446 :Get +STR_5447 :Type {STRINGID} +STR_5448 :Ride / Vehicle {STRINGID} +STR_5449 :Reduce game speed +STR_5450 :Increase game speed +STR_5451 :Open cheats window +STR_5452 :Toggle visibility of toolbars +STR_5453 :Select another ride +STR_5454 :Uncap FPS +STR_5455 :Enable sandbox mode +STR_5456 :Disable clearance checks +STR_5457 :Disable support limits +STR_5458 :Rotate clockwise +STR_5459 :Rotate anti-clockwise +STR_5460 :Rotate view anti-clockwise +STR_5461 :Set guests' parameters +STR_5462 :{CURRENCY} +STR_5463 :Goal: Have fun! +STR_5464 :General +STR_5465 :Climate +STR_5466 :Staff +STR_5467 :ALT + +STR_5468 :Recent messages +STR_5469 :Scroll map up +STR_5470 :Scroll map left +STR_5471 :Scroll map down +STR_5472 :Scroll map right +STR_5473 :Cycle day / night +STR_5474 :Display text on banners in upper case +STR_5475 :{COMMA16} weeks +STR_5476 :Hardware +STR_5477 :Map rendering +STR_5478 :Controls +STR_5479 :Toolbar +STR_5480 :Show toolbar buttons for: +STR_5481 :Themes +STR_5482 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}1 minute +STR_5483 :{BLACK}({COMMA16} weeks remaining) +STR_5484 :{BLACK}({COMMA16} week remaining) +STR_5485 :{SMALLFONT}{STRING} +STR_5486 :{BLACK}{COMMA16} +STR_5487 :{SMALLFONT}{BLACK}Show recent messages +STR_5488 :No entrance (OpenRCT2 only!) +STR_5489 :{SMALLFONT}{BLACK}Show only tracked guests +STR_5490 :Disable audio on focus loss +STR_5491 :Seznam vynálezů +STR_5492 :Nastavení scénáře +STR_5493 :Poslat zprávu +STR_5494 : +STR_5495 :Seznam hráčů +STR_5496 :Hráč: +STR_5497 :Ping: +STR_5498 :Seznam Serverů +STR_5499 :Jméno hráče: +STR_5500 :Přidat Server +STR_5501 :Spustit Server +STR_5502 :Hra více hráčů +STR_5503 :Enter hostname or IP address: +STR_5504 :{SMALLFONT}{BLACK}Show multiplayer status +STR_5505 :Nelze se připojit k serveru. +STR_5506 :Hosté ingnorují intensitu +STR_5507 :Handymen mow grass by default +STR_5508 :APovolit nahrávat soubory s chybným kontrolním součtem +STR_5509 :{SMALLFONT}{BLACK}Allows loading scenarios and saves that have an incorrect checksum, like the scenarios from the demo or damaged saves. +STR_5510 :Default sound device +STR_5511 :(UNKNOWN) +STR_5512 :Uložit hru jako +STR_5513 :(Rychle) uložit hru +STR_5514 :Vypnout vandalismus +STR_5515 :{SMALLFONT}{BLACK}Zastaví vandalismus naštvaných hostů +STR_5516 :{SMALLFONT}{BLACK}Černá +STR_5517 :{SMALLFONT}{BLACK}Šedá +STR_5518 :{SMALLFONT}{BLACK}Bílá +STR_5519 :{SMALLFONT}{BLACK}Tmavě fialová +STR_5520 :{SMALLFONT}{BLACK}Světle fialová +STR_5521 :{SMALLFONT}{BLACK}Jasně fialová +STR_5522 :{SMALLFONT}{BLACK}Tmavě modrá +STR_5523 :{SMALLFONT}{BLACK}Světle modrá +STR_5524 :{SMALLFONT}{BLACK}Ledové modrá +STR_5525 :{SMALLFONT}{BLACK}Temná voda +STR_5526 :{SMALLFONT}{BLACK}Světlá voda +STR_5527 :{SMALLFONT}{BLACK}Sytě zelená +STR_5528 :{SMALLFONT}{BLACK}Tmavě zelená +STR_5529 :{SMALLFONT}{BLACK}Brčálově zelená +STR_5530 :{SMALLFONT}{BLACK}Jasně zelená +STR_5531 :{SMALLFONT}{BLACK}Olivově zelená +STR_5532 :{SMALLFONT}{BLACK}Tavá olivová zelená +STR_5533 :{SMALLFONT}{BLACK}Jasně žlutá +STR_5534 :{SMALLFONT}{BLACK}Žlutá +STR_5535 :{SMALLFONT}{BLACK}Temně žlutá +STR_5536 :{SMALLFONT}{BLACK}Světle oranžová +STR_5537 :{SMALLFONT}{BLACK}Temně oranžová +STR_5538 :{SMALLFONT}{BLACK}Světle hnědá +STR_5539 :{SMALLFONT}{BLACK}Sytě hnědá +STR_5540 :{SMALLFONT}{BLACK}Temně hnědá +STR_5541 :{SMALLFONT}{BLACK}Lososová +STR_5542 :{SMALLFONT}{BLACK}Bordeaux +STR_5543 :{SMALLFONT}{BLACK}Sytě červená +STR_5544 :{SMALLFONT}{BLACK}Jasně červená +STR_5545 :{SMALLFONT}{BLACK}Temně růžová +STR_5546 :{SMALLFONT}{BLACK}Jasně růžová +STR_5547 :{SMALLFONT}{BLACK}Světle +STR_5548 :Show all operating modes +STR_5549 :Rok/Měsíc/Den +STR_5550 :{POP16}{POP16}Rok {COMMA16}, {PUSH16}{PUSH16}{MONTH} {PUSH16}{PUSH16}{STRINGID} +STR_5551 :Rok/Den/Měsíc +STR_5552 :{POP16}{POP16}Rok {COMMA16}, {PUSH16}{PUSH16}{PUSH16}{STRINGID} {MONTH} +STR_5553 :Pause game when Steam overlay is open +STR_5554 :{SMALLFONT}{BLACK}Enable mountain tool +STR_5555 :Show vehicles from other track types +STR_5556 :Vyhodit hráče +STR_5557 :Zůstat připojen při desynchronizaci (Hra více hráčů) +STR_5558 :Změna tohoto nastavení vyžaduje restart +STR_5559 :10 min. inspections +STR_5560 :{SMALLFONT}{BLACK}Sets the inspection time to 'Every 10 minutes' on all rides +STR_5561 :Nahrání souborů jazyka selhalo +STR_5562 :POZOR! +STR_5563 :This feature is currently unstable, take extra caution. +STR_5564 :Insert Corrupt Element +STR_5565 :{SMALLFONT}{BLACK}Inserts a corrupt map element at top of tile. This will hide any element above the corrupt element. +STR_5566 :Heslo: +STR_5567 :Propagovat +STR_5568 :Vyžadovat heslo +STR_5569 :Tento server vyžaduje heslo +STR_5570 :Hledat servery +STR_5571 :Připojit se ke hře +STR_5572 :Přída k oblíbeným +STR_5573 :Odstranit z oblíbených +STR_5574 :Jméno serveru: +STR_5575 :Hráčů maximálně: +STR_5576 :Port: +STR_5577 :Jiho-Korejský Won (W) +STR_5578 :Ruský Rubl (R) + +##################### +# Rides/attractions # +##################### + +#WW +[CONDORRD] +STR_NAME :Condor Ride +STR_DESC :Riding in special harnesses below the track, riders experience the feeling of flight as they swoop through the air in Condor-shaped trains +STR_CPTY :4 passengers per car diff --git a/data/language/dutch.txt b/data/language/dutch.txt index db170d4a2b..cf42a3debb 100644 --- a/data/language/dutch.txt +++ b/data/language/dutch.txt @@ -22,7 +22,7 @@ STR_0020 :Kabelbaan STR_0021 :Stalen schroefachtbaan STR_0022 :Doolhof STR_0023 :Spiraalglijbaan -STR_0024 :Go Karts +STR_0024 :Go-karts STR_0025 :Boomstamattractie STR_0026 :Wildwaterbaan STR_0027 :Botsauto's @@ -42,7 +42,7 @@ STR_0040 :Bewegingssimulator STR_0041 :3D-bioscoop STR_0042 :Topspin STR_0043 :Ruimteringen -STR_0044 :Omgekeerde vrijevalachtbaan +STR_0044 :Achterwaartsevrijevalachtbaan STR_0045 :Lift STR_0046 :Verticale achtbaan STR_0047 :Geldautomaat @@ -51,17 +51,17 @@ STR_0049 :Spookhuis STR_0050 :Eerste hulp STR_0051 :Circus STR_0052 :Spooktrein -STR_0053 :Hyper-twisterachtbaan +STR_0053 :Stalen twisterachtbaan STR_0054 :Houten achtbaan STR_0055 :Zijfrictie-achtbaan STR_0056 :Wilde muis STR_0057 :Multidimensie-achtbaan STR_0058 :Onbekende attractie (38) -STR_0059 :Omgekeerde luchtachtbaan +STR_0059 :Vliegachtbaan STR_0060 :Onbekende attractie (3A) STR_0061 :Virginia Reel STR_0062 :Plonsboten -STR_0063 :Minihelikopters +STR_0063 :Minihelicopters STR_0064 :Liggende achtbaan STR_0065 :Omgekeerde monorail STR_0066 :Onbekende attractie (40) @@ -88,7 +88,7 @@ STR_0086 :Onbekende attractie (54) STR_0087 :Onbekende attractie (55) STR_0088 :Omgekeerde Impulse-achtbaan STR_0089 :Mini-achtbaan -STR_0090 :Aandreven mijntrein +STR_0090 :Aangedreven mijntrein STR_0091 :Onbekende attractie (59) STR_0092 :LIM-lanceringsachtbaan STR_0093 : @@ -510,31 +510,31 @@ STR_0508 : STR_0509 : STR_0510 : STR_0511 : -STR_0512 : -STR_0513 : -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 -STR_0518 :Passagiers rijden in elektrische treinen over een monorailbaan -STR_0519 :Passagiers zitten in kleine karretjes die onder een enkele rail hangen en naar buiten zwaaien in de bochten -STR_0520 : -STR_0521 : -STR_0522 : -STR_0523 :Bezoekers rijden langzaam over een baan in aangedreven karretjes -STR_0524 : -STR_0525 : -STR_0526 : -STR_0527 :Een soepele stalen achtbaan die verticale loopings kan maken -STR_0528 : -STR_0529 : -STR_0530 :Stoeltjes hangen aan een continu draaiende stalen kabel die van het ene uiteinde van de baan naar het andere loopt, en daarna weer terug -STR_0531 : +STR_0512 :Een compacte achtbaan met een spiraalvormige kettingheuvel en soepele, kronkelende afdalingen. +STR_0513 :Een achtbaan met loopings waar de passagiers in de karretjes staan. +STR_0514 :Treinen hangen onder de baan en zwaaien naar buiten in de bochten. +STR_0515 :Een stalen achtbaan met treinen die onder de baan hangen, met veel complexe en kronkelende baanelementen. +STR_0516 :Een rustige achtbaan voor bezoekers die nog niet in engere attracties durven. +STR_0517 :Passagiers rijden in miniatuurtreinen over een smalspoorweg. +STR_0518 :Passagiers rijden in elektrische treinen over een monorailbaan. +STR_0519 :Passagiers zitten in kleine karretjes die onder een enkele rail hangen en naar buiten zwaaien in de bochten. +STR_0520 :Een aanlegsteiger waar bezoekers in een bootje kunnen gaan om over het water te varen. +STR_0521 :Een intense, snelle en kronkelende achtbaan met scherpe bochten en afdalingen. +STR_0522 :Een kleinere achtbaan waar de passagiers boven de baan en op het karretje zitten. +STR_0523 :Bezoekers rijden langzaam over een baan in aangedreven karretjes. +STR_0524 :Een vrijevalwagen wordt pneumatisch langs een hoge stalen toren gelanceerd en gaat daarna in een vrije val weer naar beneden. +STR_0525 :Passagiers rijden over een kronkelende baan, waarbij ze enkel worden geleid door de ronding en banking van de halfronde baan. +STR_0526 :Bezoekers gaan in een roterende observatiecabine langs een toren omhoog +STR_0527 :Een soepele stalen achtbaan die verticale loopings kan maken. +STR_0528 :Passagiers glijden in opblaasboten door een kronkelende halfopen of compleet gesloten glijbaan. +STR_0529 :Achtbaantreinen in de vorm van een mijntrein razen over stalen achtbaanrails die er uitziet als een oude spoorbaan. +STR_0530 :Stoeltjes hangen aan een continu draaiende stalen kabel die van het ene uiteinde van de baan naar het andere loopt, en daarna weer terug. +STR_0531 :Een compacte stalen achtbaan waar de trein door schroeven en loopings gaat. STR_0532 : STR_0533 : -STR_0534 : -STR_0535 : -STR_0536 : +STR_0534 :Go-karts met benzinemotor die de passagiers zelf besturen. +STR_0535 :Boten in de vorm van een boomstam varen door een waterbak, waarbij ze van steile hellingen afdalen om de passagiers te doorweken. +STR_0536 :Ronde boten varen door een brede waterbak, waarbij ze de passagiers opwinden door watervallen en schuimende stroomversnellingen. STR_0537 : STR_0538 : STR_0539 : @@ -552,55 +552,55 @@ STR_0550 : STR_0551 : STR_0552 : STR_0553 : -STR_0554 :Het karretje wordt het station uitgelanceerd over een lange rechte baan door middel van lineaire inductiemotoren, om daarna recht omhoog te gaan en weer terug te vallen richting het station -STR_0555 : -STR_0556 : +STR_0554 :Het karretje wordt het station uitgelanceerd over een lange rechte baan door middel van lineaire inductiemotoren, om daarna recht omhoog te gaan en weer terug te vallen richting het station. +STR_0555 :Bezoekers gaan in een lift in een toren omhoog of omlaag om naar een ander hoogteniveau te komen. +STR_0556 :Extra brede karretjes rijden over een compleet verticale baan voor de ultieme vrijevalbeleving. STR_0557 : STR_0558 : STR_0559 : STR_0560 : STR_0561 : -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 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_0562 :Aangedreven karretjes rijden langs eng decor en special effects over een baan met hoogteverschillen. +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 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 hangen in treinen onder de baan met enkel schouderbeugels 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 : -STR_0573 : -STR_0574 : -STR_0575 :Aangedreven treinen hangen aan een enkele rail en vervoeren mensen door het park heen +STR_0571 :Ronde karretjes gaan over een zigzaggende houten baan en draaien daarbij rond. +STR_0572 :Boten met een hoge capaciteit varen door een brede waterbak, worden naar boven vervoerd door een lopende band, en gaan met hoge snelheid steile heuvels af om met een grote plons de passagiers te doorweken. +STR_0573 :Aangedreven karretjes in de vorm van een helicopter rijden over een stalen baan, bestuurd door het trappen van de passagiers. +STR_0574 :Passagiers worden door middel van een speciale beugel in een liggende positie vastgehouden, waarna ze op hun rug of met hun gezicht naar de grond door kronkelende stukken baan en omkeringen heen gaan. +STR_0575 :Aangedreven treinen hangen aan een enkele rail en vervoeren mensen door het park heen. STR_0576 : -STR_0577 : -STR_0578 :Karretjes rijden in een baan omgeven door hoepels en gaan door steile afdalingen en heartline-twists +STR_0577 :Karretjes met draaistellen rijden op een houten baan en kunnen omkeren op speciale stukken baan. +STR_0578 :Karretjes rijden in een baan omgeven door hoepels en gaan door steile afdalingen en heartline-twists. STR_0579 : -STR_0580 : -STR_0581 : +STR_0580 :Een gigantische stalen achtbaan die in staat is tot soepele afdalingen en heuvels die hoger zijn dan 90 meter. +STR_0581 :Een ring van stoelen wordt naar de bovenkant van een hoge toren getrokken terwijl hij rustig ronddraait, waarna hij losgelaten wordt in een vrije val, waarna hij beneden rustig wordt afgeremd door middel van magnetische remmen. STR_0582 : STR_0583 : -STR_0584 : -STR_0585 : -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_0584 :Speciale fietsen rijden over een stalen monorail, voortbewogen door het trappen van de passagiers. +STR_0585 :Passagiers zitten in stoelparen die onder de baan hangen terwijl ze door kronkelende en scherpe omkeringen gaan. +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 :Na een enerverende pneumatische lancering rijdt de trein met hogere snelheid over een verticale baan, over de top, en vervolgens over de andere kant weer naar beneden om terug te keren naar het station. +STR_0588 :Losse karretjes hangen onder een zigzaggende baan met haarspeldbochten en scherpe afdalingen. STR_0589 : -STR_0590 : -STR_0591 : +STR_0590 :Passagiers rijden over een onderwaterparcours in onderzeeërs. +STR_0591 :Boten in de vorm van een vlot varen rustig door een waterbak. STR_0592 : STR_0593 : STR_0594 : STR_0595 : STR_0596 : STR_0597 : -STR_0598 : -STR_0599 :Een compacte achtbaan met individuele karretjes en steile, kronkelende afdalingen -STR_0600 : +STR_0598 :Een omgekeerde achtbaantrein wordt het station uit gelanceerd en gaat een verticale kronkelende baan op, waarna deze terugzakt, door het station heengaat en achteruit een ander stuk verticale baan opgaat. +STR_0599 :Een compacte achtbaan met individuele karretjes en steile, kronkelende afdalingen. +STR_0600 :Aangedreven mijntreinen rijden over een soepele en kronkelende baan. STR_0601 : -STR_0602 : +STR_0602 :Achtbaantreinen worden door lineaire inductiemotoren het station uit gelanceerd en razen door een kronkelende baan die vaak over de kop gaat. STR_0603 :Bezoeker {INT32} STR_0604 :Bezoeker {INT32} STR_0605 :Bezoeker {INT32} @@ -836,16 +836,17 @@ STR_0834 :{SMALLFONT}{BLACK}Schijf- en spelopties STR_0835 :Kan het spel niet initialiseren STR_0836 :Kan het spel niet in geminimaliseerde toestand starten STR_0837 :Kan het grafisch systeem niet starten -STR_0838 :CD-code {INT32} is niet geldig voor deze CD van RollerCoaster Tycoon 2!{WINDOW_COLOUR_1}{WINDOW_COLOUR_1}Deïnstalleer RollerCoaster Tycoon 2% en installeer het opnieuw met de correcte CD-code +STR_0838 : STR_0839 :{UINT16} x {UINT16} STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} -STR_0841 :Bureaubladvenster -STR_0842 :640x480 (volledig scherm) -STR_0843 :800x600 (volledig scherm) -STR_0844 :1024x768 (volledig scherm) -STR_0845 :1152x864 (volledig scherm) -STR_0846 :1280x1024 (volledig scherm) -STR_0847 :Over 'RollerCoaster Tycoon 2' +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +STR_0847 :Over 'OpenRCT2' STR_0848 :RollerCoaster Tycoon 2 STR_0849 :{WINDOW_COLOUR_2}Versie 2.01.028 STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, alle rechten voorbehouden @@ -894,7 +895,7 @@ STR_0892 :Screenshot opgeslagen als '{STRINGID}' STR_0893 :Screenshot maken mislukt! STR_0894 :"Landscape data area" zit vol! STR_0895 :Kan niet gedeeltelijk onder en boven de grond bouwen -STR_0896 :{POP16}{POP16}{STRINGID} Constructie +STR_0896 :{POP16}{POP16}Constructie {STRINGID} STR_0897 :Richting STR_0898 :{SMALLFONT}{BLACK}Bocht naar links STR_0899 :{SMALLFONT}{BLACK}Bocht naar rechts @@ -903,7 +904,7 @@ STR_0901 :{SMALLFONT}{BLACK}Bocht naar rechts (kleine straal) STR_0902 :{SMALLFONT}{BLACK}Bocht naar links (zeer kleine straal) STR_0903 :{SMALLFONT}{BLACK}Bocht naar rechts (zeer kleine straal) STR_0904 :{SMALLFONT}{BLACK}Bocht naar links (grote straal) -STR_0905 :{SMALLFONT}{BLACK}Bocht naar rechts (straal) +STR_0905 :{SMALLFONT}{BLACK}Bocht naar rechts (grote straal) STR_0906 :{SMALLFONT}{BLACK}Recht stuk STR_0907 :Helling STR_0908 :Roll/Banking @@ -1041,10 +1042,10 @@ STR_1039 :Nieuw baanontwerp installeren STR_1040 :Spel opslaan STR_1041 :Scenario opslaan STR_1042 :Landschap opslaan -STR_1043 :Opgeslagen spel van RollerCoaster Tycoon 2 -STR_1044 :Scenario voor RollerCoaster Tycoon 2 -STR_1045 :Landschap voor RollerCoaster Tycoon 2 -STR_1046 :Baanontwerp voor RollerCoaster Tycoon 2 +STR_1043 :Opgeslagen spel van OpenRCT2 +STR_1044 :Scenario voor OpenRCT2 +STR_1045 :Landschap voor OpenRCT2 +STR_1046 :Baanontwerp voor OpenRCT2 STR_1047 :Spel opslaan mislukt! STR_1048 :Scenario opslaan mislukt! STR_1049 :Landschap opslaan mislukt! @@ -1170,7 +1171,7 @@ STR_1168 :Opties STR_1169 :(Geen) STR_1170 :{STRING} STR_1171 :{RED}Gesloten - - -STR_1172 :{YELLLOW}{STRINGID} - - +STR_1172 :{YELLOW}{STRINGID} - - STR_1173 :{SMALLFONT}{BLACK}Voetpaden en wachtrijen aanleggen STR_1174 :Lichtkrant in de weg STR_1175 :Kan dit niet op hellend voetpad neerzetten @@ -1535,7 +1536,7 @@ STR_1533 :{SMALLFONT}{OPENQUOTES}Deze popcorn van {STRINGID} is erg goedkoop{ STR_1534 :{SMALLFONT}{OPENQUOTES}Deze hotdog van {STRINGID} is erg goedkoop{ENDQUOTES} STR_1535 :{SMALLFONT}{OPENQUOTES}Deze tentakel van {STRINGID} is erg goedkoop{ENDQUOTES} STR_1536 :{SMALLFONT}{OPENQUOTES}Deze hoed van {STRINGID} is erg goedkoop{ENDQUOTES} -STR_1537 :{SMALLFONT}{OPENQUOTES}Deze toffeeappel van {STRINGID} is erg goedkoop{ENDQUOTES} +STR_1537 :{SMALLFONT}{OPENQUOTES}Deze gevulde appel van {STRINGID} is erg goedkoop{ENDQUOTES} STR_1538 :{SMALLFONT}{OPENQUOTES}Dit T-shirt van {STRINGID} is erg goedkoop{ENDQUOTES} STR_1539 :{SMALLFONT}{OPENQUOTES}Deze donut van {STRINGID} is erg goedkoop{ENDQUOTES} STR_1540 :{SMALLFONT}{OPENQUOTES}Deze koffie van {STRINGID} is erg goedkoop{ENDQUOTES} @@ -1569,7 +1570,7 @@ STR_1567 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor popcorn van {STRI STR_1568 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor een hotdog van {STRINGID}{ENDQUOTES} STR_1569 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor een tentakel van {STRINGID}{ENDQUOTES} STR_1570 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor een hoed van {STRINGID}{ENDQUOTES} -STR_1571 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor een toffeeappel van {STRINGID}{ENDQUOTES} +STR_1571 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor een gevulde appel van {STRINGID}{ENDQUOTES} STR_1572 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor een T-shirt van {STRINGID}{ENDQUOTES} STR_1573 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor een donut van {STRINGID}{ENDQUOTES} STR_1574 :{SMALLFONT}{OPENQUOTES}Zoveel betaal ik niet voor koffie van {STRINGID}{ENDQUOTES} @@ -1890,8 +1891,10 @@ STR_1888 :{WINDOW_COLOUR_2}Tijd sinds laatste inspectie: {BLACK}meer dan 4 uu STR_1889 :{WINDOW_COLOUR_2}Stilstandtijd: {MOVE_X}{255}{BLACK}{COMMA16}% STR_1890 :{SMALLFONT}{BLACK}Selecteer hoe vaak een monteur deze attractie moet inspecteren STR_1891 :Nog geen {STRINGID} in het park! -STR_1892 :RollerCoaster Tycoon 2 -STR_1893 :Voer je CD van RollerCoaster Tycoon 2 in het volgende station in: +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 : +STR_1893 : STR_1894 :{WINDOW_COLOUR_2}{STRINGID} verkocht: {BLACK}{COMMA32} STR_1895 :{SMALLFONT}{BLACK}Nieuwe attractie bouwen STR_1896 :{WINDOW_COLOUR_2}Uitgaven/Inkomsten @@ -1977,7 +1980,7 @@ STR_1975 :{WINDOW_COLOUR_2}Prijs popcorn: STR_1976 :{WINDOW_COLOUR_2}Prijs hotdog: STR_1977 :{WINDOW_COLOUR_2}Prijs tentakel: STR_1978 :{WINDOW_COLOUR_2}Prijs hoed: -STR_1979 :{WINDOW_COLOUR_2}Prijs toffeeappel: +STR_1979 :{WINDOW_COLOUR_2}Prijs gevulde appel: STR_1980 :{WINDOW_COLOUR_2}Prijs T-shirt: STR_1981 :{WINDOW_COLOUR_2}Prijs donut: STR_1982 :{WINDOW_COLOUR_2}Prijs koffie: @@ -2005,7 +2008,7 @@ STR_2003 :Popcorn STR_2004 :Hotdog STR_2005 :Tentakel STR_2006 :Hoed -STR_2007 :Toffeeappel +STR_2007 :Gevulde appel STR_2008 :T-shirt STR_2009 :Donut STR_2010 :Koffie @@ -2033,7 +2036,7 @@ STR_2031 :Bakjes popcorn STR_2032 :Hotdogs STR_2033 :Tentakels STR_2034 :Hoeden -STR_2035 :Toffeeappels +STR_2035 :Gevulde appels STR_2036 :T-shirts STR_2037 :Donuts STR_2038 :Kopjes koffie @@ -2061,7 +2064,7 @@ STR_2059 :popcorn STR_2060 :een hotdog STR_2061 :een tentakel STR_2062 :een hoed -STR_2063 :een toffeeappel +STR_2063 :een gevulde appel STR_2064 :een T-shirt STR_2065 :een donut STR_2066 :een kop koffie @@ -2089,7 +2092,7 @@ STR_2087 :Popcorn STR_2088 :Hotdog STR_2089 :Tentakel STR_2090 :Hoed van {OPENQUOTES}{STRINGID}{ENDQUOTES} -STR_2091 :Toffeeappel +STR_2091 :Gevulde appel STR_2092 :T-shirt van {OPENQUOTES}{STRINGID}{ENDQUOTES} STR_2093 :Donut STR_2094 :Koffie @@ -2215,7 +2218,7 @@ STR_2213 :{SMALLFONT}{BLACK}Toon lijst van entertainers in het park STR_2214 :Bouwen is niet mogelijk wanneer het spel is gepauzeerd! STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C -STR_2217 :{WINDOW_COLOUR_2}{COMMA16}F +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F STR_2218 :{RED}{STRINGID} van {STRINGID} is nog niet teruggekeerd naar de opstapplaats ({STRINGID})!{NEWLINE}Controleer of het is vastgelopen of stil komen te staan STR_2219 :{RED}{COMMA16} personen zijn om het leven gekomen bij een ongeluk in {STRINGID} STR_2220 :{WINDOW_COLOUR_2}Parkwaardering: {BLACK}{COMMA16} @@ -2288,10 +2291,10 @@ STR_2286 :Ontwerpen STR_2287 :Ontwerp voltooien STR_2288 :Onbekend STR_2289 :{STRINGID} {STRINGID} -STR_2290 :{SMALLFONT}{BLACK}{STRINGID} {STRINGID} +STR_2290 : STR_2291 :Selecteer een scenario voor een nieuw spel STR_2292 :{WINDOW_COLOUR_2}Bezochte attracties: -STR_2293 :{BLACK} Geen +STR_2293 :{BLACK} Niets STR_2294 :{SMALLFONT}{BLACK}Bovenkant land aanpassen STR_2295 :{SMALLFONT}{BLACK}Zijkant land aanpassen STR_2296 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} betaald voor entree @@ -2315,10 +2318,10 @@ STR_2313 :{WINDOW_COLOUR_2}Misselijkheidswaarde: {BLACK}{COMMA2DP32} (ongevee 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 -STR_2317 :{WINDOW_COLOUR_2}Geluidskwaliteit: -STR_2318 :Laag -STR_2319 :Gemiddeld -STR_2320 :Hoog +STR_2317 : +STR_2318 : +STR_2319 : +STR_2320 : STR_2321 :{WINDOW_COLOUR_2}Aantal attracties: {BLACK}{COMMA16} STR_2322 :{WINDOW_COLOUR_2}Werknemers: {BLACK}{COMMA16} STR_2323 :{WINDOW_COLOUR_2}Parkgrootte: {BLACK}{COMMA32}m{SQUARED} @@ -2365,7 +2368,7 @@ 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! STR_2366 :Celsius ({DEGREE}C) -STR_2367 :Fahrenheit (F) +STR_2367 :Fahrenheit ({DEGREE}F) STR_2368 :Geen STR_2369 :Laag STR_2370 :Gemiddeld @@ -2434,13 +2437,13 @@ STR_2432 :{BLACK}Bonnen voor 50% korting op entree voor {STRINGID} STR_2433 :{BLACK}Bonnen voor gratis {STRINGID} STR_2434 :{BLACK}Advertentiecampagne voor {STRINGID} STR_2435 :{BLACK}Advertentiecampagne voor {STRINGID} -STR_2436 :1 week -STR_2437 :2 weken -STR_2438 :3 weken -STR_2439 :4 weken -STR_2440 :5 weken -STR_2441 :6 weken -STR_2442 :{BLACK}({STRINGID} resterend) +STR_2436 : +STR_2437 : +STR_2438 : +STR_2439 : +STR_2440 : +STR_2441 : +STR_2442 : STR_2443 :{WINDOW_COLOUR_2}Kosten per week: {BLACK}{CURRENCY2DP} STR_2444 :{WINDOW_COLOUR_2}Totale kosten: {BLACK}{CURRENCY2DP} STR_2445 :Start deze marketingcampagne @@ -2679,10 +2682,10 @@ STR_2677 :??? STR_2678 :??? STR_2679 :??? 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_2681 :{MEDIUMFONT}{BLACK}Verhoog je saldo met {CURRENCY} +STR_2682 : +STR_2683 : +STR_2684 :{SMALLFONT}{BLACK}Er arriveert een grote groep bezoekers STR_2685 :Parameters voor Simplex noise STR_2686 :Minimum: STR_2687 :Maximum: @@ -2699,11 +2702,11 @@ STR_2697 :??? STR_2698 :??? STR_2699 :??? 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_2701 :Elke minuut +STR_2702 :Elke 5 minuten +STR_2703 :Elke 15 minuten +STR_2704 :Elke 30 minuten +STR_2705 :Elk uur STR_2706 :Nooit STR_2707 :Open nieuw scherm STR_2708 :{WINDOW_COLOUR_1}Weet je zeker dat je {STRINGID} wilt vervangen? @@ -2716,8 +2719,8 @@ STR_2714 :- STR_2715 :. STR_2716 :/ STR_2717 :' -STR_2718 :(één map omhoog) -STR_2719 :(nieuw bestand) +STR_2718 :Eén map omhoog +STR_2719 :Nieuw bestand STR_2720 :{UINT16}s STR_2721 :{UINT16}s STR_2722 :{UINT16}m {UINT16}s @@ -2754,15 +2757,15 @@ STR_2752 :Onkruid weg STR_2753 :Gras maaien STR_2754 :Bloemen water geven STR_2755 :Vandalisme repareren -STR_2756 :Afval op paden weghalen +STR_2756 :Afval verwijderen STR_2757 :Mooi weer STR_2758 :Regen STR_2759 :Hoogtes op nul -STR_2760 :+5000 geld -STR_2761 :Betaalde entree -STR_2762 :Betalen per rit +STR_2760 :+{CURRENCY} +STR_2761 : +STR_2762 : STR_2763 :??? -STR_2764 :Tevreden gasten +STR_2764 : STR_2765 :Grote groep STR_2766 :Win scenario STR_2767 :Weer vastzetten @@ -2779,7 +2782,7 @@ STR_2777 :{MOVE_X}{SMALLFONT}{STRING} STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} STR_2779 :Kijkvenster {COMMA16} STR_2780 :Extra kijkvenster -STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} STR_2782 :SHIFT + STR_2783 :CTRL + STR_2784 :Sneltoets wijzigen @@ -2857,7 +2860,7 @@ STR_2855 :{RED}{STRINGID} heeft geen pad vanaf de uitgang!{NEWLINE}Bouw een p STR_2856 :{WINDOW_COLOUR_2}Tutorial STR_2857 :{WINDOW_COLOUR_2}(Druk op een toets of muisknop om de controle over te nemen) STR_2858 :Kan marketingcampagne niet starten... -STR_2859 :RollerCoaster Tycoon 2 draait al +STR_2859 :OpenRCT2 draait al STR_2860 :Credits voor Infogrames Interactive... STR_2861 :{WINDOW_COLOUR_2}In licentie geven aan Infogrames Interactive Inc. STR_2862 :Muziekdankwoord... @@ -2967,8 +2970,8 @@ STR_2965 :{WINDOW_COLOUR_2} STR_2966 : STR_2967 : STR_2968 : -STR_2969 :Het gebruik van dit product is onderhevig aan de bepalingen in de gebruikersovereenkomst -STR_2970 :die te raadplegen is in de {OPENQUOTES}ReadMe{ENDQUOTES} of de handleiding. +STR_2969 : +STR_2970 : STR_2971 :Standaard kleurenschema STR_2972 :Alternatief kleurenschema 1 STR_2973 :Alternatief kleurenschema 2 @@ -3158,8 +3161,8 @@ STR_3156 : STR_3157 :kaart STR_3158 :grafiek STR_3159 :lijst -STR_3160 :RollerCoaster Tycoon 2: Eerste start... -STR_3161 :RollerCoaster Tycoon 2: Objectbestanden controleren... +STR_3160 : +STR_3161 : STR_3162 :Kan niet voldoende geheugen toewijzen STR_3163 :Nieuwe data installeren: STR_3164 :{BLACK}{COMMA16} geselecteerd (maximum: {COMMA16}) @@ -3168,25 +3171,25 @@ STR_3166 :{BLACK}(ID: STR_3167 :{WINDOW_COLOUR_2}Bevat {BLACK}{COMMA16} objecten STR_3168 :{WINDOW_COLOUR_2}Tekst: {BLACK}{STRINGID} STR_3169 :Data voor de volgende objecten niet gevonden: -STR_3170 :Niet genoeg ruimte voor graphics -STR_3171 :Te veel objecten van dit type geselecteerd +STR_3170 :Niet genoeg ruimte voor graphics. +STR_3171 :er zijn teveel objecten van dit type geselecteerd. STR_3172 :De volgende objecten moeten eerst geselecteerd worden: -STR_3173 :Dit object is momenteel in gebruik -STR_3174 :Een ander object is afhankelijk van dit object -STR_3175 :Dit object is altijd benodigd -STR_3176 :Kan object niet selecteren -STR_3177 :Kan object niet deselecteren -STR_3178 :Er moet minstens één voetpad worden geselecteerd -STR_3179 :Er moet minstens één attractie worden geselecteerd -STR_3180 :Ongeldige selectie van objecten +STR_3173 :dit object is momenteel in gebruik. +STR_3174 :een ander object is afhankelijk van dit object. +STR_3175 :dit object is altijd benodigd. +STR_3176 :Kan object niet selecteren: +STR_3177 :Kan object niet deselecteren: +STR_3178 :er moet minstens één voetpad worden geselecteerd. +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 watertype worden geselecteerd +STR_3182 :er moet een parkingang worden geselecteerd. +STR_3183 :er moet een watertype worden geselecteerd. STR_3184 :Attracties/voertuigen STR_3185 :Klein decor STR_3186 :Groot decor STR_3187 :Muren/hekken -STR_3188 :Borden voor paden +STR_3188 :Lichtkranten STR_3189 :Voetpaden STR_3190 :Extra's voor paden STR_3191 :Decorgroepen @@ -3335,7 +3338,7 @@ 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 STR_3336 :Baanontwerpbeheer - Attractietype selecteren -STR_3337 :Six Flags-park +STR_3337 : STR_3338 :{BLACK}Eigen ontwerp STR_3339 :{BLACK}{COMMA16} ontwerp beschikbaar, of maak een eigen ontwerp STR_3340 :{BLACK}{COMMA16} ontwerpen beschikbaar, of maak een eigen ontwerp @@ -3346,7 +3349,7 @@ STR_3344 :Achtbaanontwerper STR_3345 :Baanontwerpbeheer STR_3346 :Kan baanontwerp niet opslaan STR_3347 :Attractie is te groot, bevat teveel elementen of het decor is te ver verspreid -STR_3348 :Naam wijzigen +STR_3348 :Hernoemen STR_3349 :Verwijderen STR_3350 :Naam baanontwerp STR_3351 :Voer een nieuwe naam in voor dit baanontwerp: @@ -3360,8 +3363,8 @@ 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 :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_3362 : +STR_3363 : STR_3364 :Meer opties STR_3365 :{SMALLFONT}{BLACK}Maakt naast selectie van decorgroepen ook selectie van losse items mogelijk STR_3366 :{BLACK}= Attractie @@ -3447,11 +3450,11 @@ 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_5120 :Financiën +STR_5121 :Onderzoek +STR_5122 :Attracties op baantype sorteren STR_5123 :Attr. vernieuwen -STR_5124 :Six Flags weg +STR_5124 : STR_5125 :Afbreekbaar maken STR_5126 :Willekeurige titelmuziek STR_5127 :{SMALLFONT}{BLACK}Landtype i.p.v. landhoogte aanpassen bij slepen @@ -3474,7 +3477,7 @@ STR_5143 :Vlot STR_5144 :Hard STR_5145 :Turbo STR_5146 :Nitro -STR_5147 :'Cheats'-knop in de werkbalk tonen +STR_5147 :Cheats STR_5148 :{SMALLFONT}{BLACK}Spelsnelheid veranderen STR_5149 :{SMALLFONT}{BLACK}Het cheatsvenster openen STR_5150 :Debugging-hulpmiddelen inschakelen @@ -3489,33 +3492,33 @@ STR_5156 :{SMALLFONT}{BLACK}Maakt het mogelijk om de meeste attractietypes te STR_5157 :Alle prijzen ontgrendelen STR_5158 :Terug naar het hoofdmenu STR_5159 :OpenRCT2 afsluiten -STR_5160 :{MONTH} {STRINGID}, jaar {COMMA16} +STR_5160 :{POP16}{MONTH} {PUSH16}{PUSH16}{STRINGID}, jaar {POP16}{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_5166 :{SMALLFONT}{BLACK}Geeft bezoekers namen van gebruikers die het Twitch-kanaal volgen. +STR_5167 :Bez. met Twitch-volgersnamen volgen in berichtengeb. +STR_5168 :{SMALLFONT}{BLACK}Zet het bezoekersvolgsysteem aan voor bezoekers die naar Twitch-volgers zijn genoemd. +STR_5169 :Bez. namen van gebruikers in de Twitch-chat geven +STR_5170 :{SMALLFONT}{BLACK}Geeft bezoekers namen van gebruikers in de Twitch-chat. +STR_5171 :Bez. met Twitch-chatnamen volgen in berichtengebied +STR_5172 :{SMALLFONT}{BLACK}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_5174 :{SMALLFONT}{BLACK}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_5178 :{SMALLFONT}{BLACK}Cheats voor financiën +STR_5179 :{SMALLFONT}{BLACK}Cheats voor gasten +STR_5180 :{SMALLFONT}{BLACK}Cheats voor park +STR_5181 :{SMALLFONT}{BLACK}Cheats voor attracties STR_5182 :{INT32} STR_5183 :Basishoogte -STR_5184 :Enter base height between {COMMA16} and {COMMA16} +STR_5184 :Voer een basishoogte tussen {COMMA16} en {COMMA16} in STR_5185 :Waterniveau -STR_5186 :Enter water level between {COMMA16} and {COMMA16} +STR_5186 :Voer een waterniveau tussen {COMMA16} en {COMMA16} in STR_5187 :Financiën STR_5188 :Nieuwe advertentiecampagne STR_5189 :Onderzoek @@ -3570,9 +3573,9 @@ 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_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 @@ -3583,9 +3586,9 @@ 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_5254 :Aanmaken +STR_5255 :{SMALLFONT}{BLACK}Begint een nieuwe, lege titelpresentatie +STR_5256 :Maak een nieuw thema aan 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 @@ -3598,7 +3601,7 @@ STR_5265 :{SMALLFONT}{BLACK}Selecteer uit welke bronnen objecten zichtbaar zi STR_5266 :{SMALLFONT}{BLACK}Weergave STR_5267 :{SMALLFONT}{BLACK}Landinstellingen STR_5268 :{SMALLFONT}{BLACK}Audio -STR_5269 :{SMALLFONT}{BLACK}Bediening +STR_5269 :{SMALLFONT}{BLACK}Bediening en interface STR_5270 :{SMALLFONT}{BLACK}Overig STR_5271 :{SMALLFONT}{BLACK}Twitch STR_5272 :{SMALLFONT}{BLACK}Klein decor @@ -3615,7 +3618,7 @@ 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_5286 :{SMALLFONT}{BLACK}Laat sommige gasten exploderen STR_5287 :Attractie is al defect STR_5288 :Attractie is gesloten STR_5289 :Deze attractie kan niet defect raken @@ -3668,9 +3671,2347 @@ STR_5335 :Attractie-ingang STR_5336 :Attractie-uitgang STR_5337 :Parkingang STR_5338 :Elementtype -STR_5339 :Hoogte onderkant -STR_5340 :Hoogte bovenkant +STR_5339 :Hoogte onderk. +STR_5340 :Hoogte bovenk. STR_5341 :Eigenschappen STR_5342 :Kies een vakje op de kaart STR_5343 :Werknemers automatisch plaatsen STR_5344 :Wijzigingsoverzicht +STR_5345 :Cheats voor geld +STR_5346 :Cheats voor bezoekers +STR_5347 :Cheats voor het park +STR_5348 :Cheats voor attracties +STR_5349 :{SMALLFONT}{BLACK}Alle attracties +STR_5350 :Max +STR_5351 :Min +STR_5352 :{BLACK}Stemming: +STR_5353 :{BLACK}Energie: +STR_5354 :{BLACK}Honger: +STR_5355 :{BLACK}Dorst: +STR_5356 :{BLACK}Misselijkh.: +STR_5357 :{BLACK}Misselijkheidstol.: +STR_5358 :{BLACK}WC: +STR_5359 :Bez. verwijderen +STR_5360 :{SMALLFONT}{BLACK}Verwijdert alle bezoekers van de kaart +STR_5361 :Geef alle bez.: +STR_5362 :{BLACK}Zet de voorkeursintensiteit van alle bez. op: +STR_5363 :Meer dan 1 +STR_5364 :Minder dan 15 +STR_5365 :{BLACK}Snelheid werknemers: +STR_5366 :Normaal +STR_5367 :Snel +STR_5368 :Crashstatus weg +STR_5369 :Parkparameters... +STR_5370 :{SMALLFONT}{BLACK}Klik op deze knop om park-{NEWLINE}parameters zoals verboden,{NEWLINE}bezoekersgenerering en geld{NEWLINE}aan te passen. +STR_5371 :Objectselectie +STR_5372 :Sleeprichting van rechtermuisknop omkeren +STR_5373 :Naam {STRINGID} +STR_5374 :Datum {STRINGID} +STR_5375 :{UP} +STR_5376 :{DOWN} +STR_5377 :{SMALLFONT}{BLACK}Opgeslagen spellen +STR_5378 :{SMALLFONT}{BLACK}Script +STR_5379 :{SMALLFONT}{BLACK}Ga naar volgend Wacht-commando +STR_5380 :{SMALLFONT}{BLACK}Start het afspelen van de titelpresentatie +STR_5381 :{SMALLFONT}{BLACK}Stopt het afspelen van de titelpresentatie +STR_5382 :{SMALLFONT}{BLACK}Titelpresentatie herstarten +STR_5383 :{SMALLFONT}{BLACK}Een nieuwe titelpresentatie aanmaken die is gebaseerd op de huidige +STR_5384 :{SMALLFONT}{BLACK}Huidige titelpresentatie verwijderen +STR_5385 :{SMALLFONT}{BLACK}Huidige titelpresentatie hernoemen +STR_5386 :{SMALLFONT}{BLACK}Nieuw commando invoegen +STR_5387 :{SMALLFONT}{BLACK}Geselecteerd commando bewerken +STR_5388 :{SMALLFONT}{BLACK}Geselecteerd commando verwijderen +STR_5389 :{SMALLFONT}{BLACK}Naar geselecteerd commando titelpresentatie springen +STR_5390 :{SMALLFONT}{BLACK}Geselecteerd commando naar beneden verplaatsen +STR_5391 :{SMALLFONT}{BLACK}Geselecteerd commando naar boven verplaatsen +STR_5392 :{SMALLFONT}{BLACK}Opgeslagen spel aan titelpresentatie toevoegen +STR_5393 :{SMALLFONT}{BLACK}Geselecteerd opgeslagen spel uit titelpresentatie verwijderen +STR_5394 :{SMALLFONT}{BLACK}Opgeslagen spel hernoemen +STR_5395 :{SMALLFONT}{BLACK}Opgeslagen spel laden +STR_5396 :{SMALLFONT}{BLACK}Titelpresentatie herladen als ze buiten het spel om is aangepast +STR_5397 :Kan enkel in het titelscherm worden gebruikt +STR_5398 :Kan de titelpresentatie niet aanpassen wanneer deze wordt afgespeeld +STR_5399 :Klik op Stop om verder te gaan met aanpassen +STR_5400 :Kan deze titelpresentatie niet aanpassen +STR_5401 :Een nieuwe titelpresentatie aanmaken om wijzigingen aan te brengen +STR_5402 :Kan titelpresentatie niet laden +STR_5403 :Er is mogelijk geen Laad- or Wacht-commando of één van de opgeslagen spellen is mogelijk beschadigd +STR_5404 :Naam bestaat al +STR_5405 :Voer een naam in voor het opgeslagen spel +STR_5406 :Voer een naam in voor de titelpresentatie +STR_5407 :Toevoegen +STR_5408 :Verwijderen +STR_5409 :Invoegen +STR_5410 :Bewerken +STR_5411 :Herladen +STR_5412 :Spring naar +STR_5413 :Laad +STR_5414 :Laad{MOVE_X}{87}Six Flags Magic Mountain.SC6 +STR_5415 :Laad{MOVE_X}{87}{STRING} +STR_5416 :Laad{MOVE_X}{87}Geen opgeslagen spel geselecteerd +STR_5417 :Locatie +STR_5418 :Locatie{MOVE_X}{87}{COMMA16} {COMMA16} +STR_5419 :Draai +STR_5420 :Draai{MOVE_X}{87}{COMMA16} +STR_5421 :Zoom +STR_5422 :Zoom{MOVE_X}{87}{COMMA16} +STR_5423 :Wacht +STR_5424 :Wacht{MOVE_X}{87}{COMMA16} +STR_5425 :Herstarten +STR_5426 :Einde +STR_5427 :Coördinaten: +STR_5428 :Aant. draaiingen tegen de klok: +STR_5429 :Zoomniveau: +STR_5430 :Te wachten seconden: +STR_5431 :Te laden opgeslagen spel: +STR_5432 :Commando: +STR_5433 :Titelpresentaties +STR_5434 :Commandobewerker +STR_5435 :Opgeslagen spel hernoemen +STR_5436 :Titelpresentaties bewerken... +STR_5437 :Geen opgeslagen spel geselecteerd +STR_5438 :Kan geen wijzigingen aanbrengen wanneer de commandobewerker open is +STR_5439 :Een Herstart-commando moet worden voorafgegaan door een Wacht-commando van minstens vier seconden. +STR_5440 :Volledig scherm minimaliseren bij focusverlies +STR_5441 :{SMALLFONT}{BLACK}Sorteert attracties per baantype,{NEWLINE}zodat achteraf wisselen van treintypes mogelijk{NEWLINE}wordt, zoals in RCT1. +STR_5442 :Parkwaardering forc.: +STR_5443 :Snelheid{MOVE_X}{87}{STRINGID} +STR_5444 :Snelheid: +STR_5445 :Snelheid +STR_5446 :Ophalen +STR_5447 :Type {STRINGID} +STR_5448 :Attractie/voertuig {STRINGID} +STR_5449 :Spelsnelheid verlagen +STR_5450 :Spelsnelheid verhogen +STR_5451 :Cheatsvenster openen +STR_5452 :Zichtbaarheid werkbalken schakelen +STR_5453 :Andere attractie selecteren +STR_5454 :FPS-limiet opheffen +STR_5455 :Zandboxmodus inschakelen +STR_5456 :Hoogtecontroles uitschakelen +STR_5457 :Ondersteuningslimieten uitschakelen +STR_5458 :Met de klok mee draaien +STR_5459 :Tegen de klok in draaien +STR_5460 :Beeld tegen de klok in draaien +STR_5461 :Bezoekersparameters aanpassen +STR_5462 :{CURRENCY} +STR_5463 :Doel: Plezier hebben! +STR_5464 :Algemeen +STR_5465 :Weer +STR_5466 :Werknemers +STR_5467 :ALT + +STR_5468 :Recente berichten +STR_5469 :Kaart naar boven scrollen +STR_5470 :Kaart naar links scrollen +STR_5471 :Kaart naar beneden scrollen +STR_5472 :Kaart naar rechts scrollen +STR_5473 :Dag-nachtcyclus +STR_5474 :Teksten op lichtkranten in hoofdletters tonen +STR_5475 :{COMMA16} weken +STR_5476 :Hardware +STR_5477 :Kaartrendering +STR_5478 :Bediening +STR_5479 :Werkbalk +STR_5480 :Knoppen in de werkbalk tonen voor: +STR_5481 :Thema's +STR_5482 :{WINDOW_COLOUR_2}Tijd sinds laatste inspectie: {BLACK}1 minuut +STR_5483 :{BLACK}({COMMA16} weken resterend) +STR_5484 :{BLACK}({COMMA16} week resterend) +STR_5485 :{SMALLFONT}{STRING} +STR_5486 :{BLACK}{COMMA16} +STR_5487 :{SMALLFONT}{BLACK}Recente berichten tonen +STR_5488 :Geen ingang (alleen in OpenRCT2!) +STR_5489 :{SMALLFONT}{BLACK}Enkel bezoekers die gevolgd worden weergeven +STR_5490 :Geluid dempen bij focusverlies +STR_5491 :Uitvindingenlijst +STR_5492 :Scenario-opties +STR_5493 :Bericht verzenden +STR_5494 : +STR_5495 :Spelerslijst +STR_5496 :Speler: +STR_5497 :Ping: +STR_5498 :Serverlijst +STR_5499 :Spelersnaam: +STR_5500 :Server toevoegen +STR_5501 :Server starten +STR_5502 :Multiplayer +STR_5503 :Hostnaam of IP-adres invoeren: +STR_5504 :{SMALLFONT}{BLACK}Status multiplayer tonen +STR_5505 :Kan niet met de server verbinden. +STR_5506 :Bezoekers negeren intensiteit +STR_5507 :Klusjesmannen standaard gras laten maaien +STR_5508 :Bestanden met incorrecte checksum toch laden +STR_5509 :{SMALLFONT}{BLACK}Maakt het mogelijk om scenario's en opgeslagen spellen met een incorrecte checksum te laden, zoals scenario's uit de demo of beschadigde opgeslagen parken. +STR_5510 :Standaard geluidsapparaat +STR_5511 :(ONBEKEND) +STR_5512 :Spel opslaan als... +STR_5513 :Spel (snel) opslaan +STR_5514 :Vandalisme uitschakelen +STR_5515 :{SMALLFONT}{BLACK}Voorkomt dat bezoekers objecten in je park vernielen als ze kwaad zijn +STR_5516 :{SMALLFONT}{BLACK}Zwart +STR_5517 :{SMALLFONT}{BLACK}Grijs +STR_5518 :{SMALLFONT}{BLACK}Wit +STR_5519 :{SMALLFONT}{BLACK}Donkerpaars +STR_5520 :{SMALLFONT}{BLACK}Lichtpaars +STR_5521 :{SMALLFONT}{BLACK}Helder paars +STR_5522 :{SMALLFONT}{BLACK}Darkblauw +STR_5523 :{SMALLFONT}{BLACK}Lichtblauw +STR_5524 :{SMALLFONT}{BLACK}IJzig blauw +STR_5525 :{SMALLFONT}{BLACK}Donkere waterkleur +STR_5526 :{SMALLFONT}{BLACK}Lichte waterkleur +STR_5527 :{SMALLFONT}{BLACK}Verzadigd groen +STR_5528 :{SMALLFONT}{BLACK}Donkergroen +STR_5529 :{SMALLFONT}{BLACK}Mosgroen +STR_5530 :{SMALLFONT}{BLACK}Helder groen +STR_5531 :{SMALLFONT}{BLACK}Olijfgroen +STR_5532 :{SMALLFONT}{BLACK}Donker olijfgroen +STR_5533 :{SMALLFONT}{BLACK}Helder geel +STR_5534 :{SMALLFONT}{BLACK}Geel +STR_5535 :{SMALLFONT}{BLACK}Donkergeel +STR_5536 :{SMALLFONT}{BLACK}Lichtoranje +STR_5537 :{SMALLFONT}{BLACK}Donkeroranje +STR_5538 :{SMALLFONT}{BLACK}Lichtbruin +STR_5539 :{SMALLFONT}{BLACK}Verzadigd bruin +STR_5540 :{SMALLFONT}{BLACK}Donkerbruin +STR_5541 :{SMALLFONT}{BLACK}Zalmroze +STR_5542 :{SMALLFONT}{BLACK}Bordeauxrood +STR_5543 :{SMALLFONT}{BLACK}Verzadigd rood +STR_5544 :{SMALLFONT}{BLACK}Helder rood +STR_5545 :{SMALLFONT}{BLACK}Donkerroze +STR_5546 :{SMALLFONT}{BLACK}Helder roze +STR_5547 :{SMALLFONT}{BLACK}Lichtroze +STR_5548 :Alle bedrijfsmodi tonen +STR_5549 :Jaar/maand/dag +STR_5550 :{POP16}{POP16}Jaar {COMMA16}, {PUSH16}{PUSH16}{MONTH} {PUSH16}{PUSH16}{STRINGID} +STR_5551 :Jaar/dag/maand +STR_5552 :{POP16}{POP16}Jaar {COMMA16}, {PUSH16}{PUSH16}{PUSH16}{STRINGID} {MONTH} +STR_5553 :Spel pauzeren als de Steam-overlay open staat +STR_5554 :{SMALLFONT}{BLACK}Overgangen met omringend land gladstrijken +STR_5555 :Voertuigen van andere baantypen tonen +STR_5556 :Speler verwijderen +STR_5557 :Verbinding behouden na desynchronisatie (multiplayer) +STR_5558 :Om deze instelling van kracht te laten worden is een herstart vereist. +STR_5559 :Elke 10 min. inspect. +STR_5560 :{SMALLFONT}{BLACK}Stelt het inspectieinterval van alle attracties in op 'Elke 10 minuten'. +STR_5561 :Kon taal niet laden +STR_5562 :WAARSCHUWING: +STR_5563 :Deze functie is momenteel niet helemaal stabiel, wees voorzichtig. +STR_5564 :Ongeldig element invoegen +STR_5565 :{SMALLFONT}{BLACK}Plaatst een ongeldig element boven de andere elementen van dit vakje. Alle elementen die boven dit ongeldige element worden geplaatst worden onzichtbaar. +STR_5566 :Wachtwoord: +STR_5567 :Bekendmaken +STR_5568 :Wachtwoord vereist +STR_5569 :Deze server vereist een wachtwoord. +STR_5570 :Lijst verversen +STR_5571 :Meedoen +STR_5572 :Toev. aan favorieten +STR_5573 :Verw. uit favorieten +STR_5574 :Servernaam: +STR_5575 :Max. aant. spelers: +STR_5576 :Poort: +STR_5577 :Zuid-Koreaanse won (W) +STR_5578 :Russische roebel (R) +STR_5579 :Vergrotingsfactor: +STR_5580 :Tsjechische kroon (Kc) + +############# +# Scenarios # +############# + +## RCT2 Original + +STR_SCNR :Alpine Adventures +STR_PARK :Alpine Adventures +STR_DTLS :Maak van een klein skistation in de bergen een amusementspark met een sneeuwthema. + + +STR_SCNR :Amity Airfield +STR_PARK :Amity Airfield +STR_DTLS :Bouw een amusementspark met een luchtvaartthema op dit verlaten vliegveld. + + +STR_SCNR :Botany Breakers +STR_PARK :Botany Breakers +STR_DTLS :Het is je uitdaging om een zeer winstgevend park te bouwen op dit paradijselijke eiland. + + +STR_SCNR :Bumbly Bazaar +STR_PARK :Bumbly Bazaar +STR_DTLS :Beginnend met een klein marktkraampje, is het je uitdaging om de winst van winkels en kraampjes te vergroten door attracties en achtbanen te bouwen en zo meer klanten te trekken. + + +STR_SCNR :Crazy Castle +STR_PARK :Crazy Castle +STR_DTLS :Je hebt een groot kasteel geërfd - het is je opdracht er een klein themapark van te maken. + + +STR_SCNR :Dusty Greens +STR_PARK :Dusty Greens +STR_DTLS :Dusty Greens ligt aan een snelwegknooppunt in de woestijn, en is een gelegenheid om van een kleine golfbaan een succesvol themapark te maken. + + +STR_SCNR :Electric Fields +STR_PARK :Electric Fields +STR_DTLS :Je hebt een kleine boerderij geërfd, en het is je uitdaging een klein themapark tussen de velden en de boerderijen te bouwen. + + +STR_SCNR :Extreme Heights +STR_PARK :Extreme Heights +STR_DTLS :Vrij van financiële beperkingen, is het je uitdaging om dit woestijnpark uit te breiden om mensen te trekken die de extreemste sensaties zoeken. + + +STR_SCNR :Factory Capers +STR_PARK :Factory Capers +STR_DTLS :Een verlaten fabriekscomplex is een gelegenheid om een amusementspark met een mechanisch thema te bouwen. + + +STR_SCNR :Fungus Woods +STR_PARK :Fungus Woods +STR_DTLS :Beperkt tot uitsluitend de ouderwetse houten attracties, is het je uitdaging om een succesvol themapark in Fungus Woods te bouwen. + + +STR_SCNR :Ghost Town +STR_PARK :Ghost Town +STR_DTLS :Je wordt aangenomen door een grote keten van amusementsparken en het is je taak een gigantisch park met achtbanen te bouwen rond een verlaten mijnstadje. + + +STR_SCNR :Gravity Gardens +STR_PARK :Gravity Gardens +STR_DTLS :Het is je uitdaging een park met achtbanen in de prachtige Gravity Gardens te bouwen... geen andere attracties, alleen maar achtbanen! + + +STR_SCNR :Infernal Views +STR_PARK :Infernal Views +STR_DTLS :Een park dat op een hachelijke plaats is gevestigd: op een vulkaanse, naast stromende lava. + + +STR_SCNR :Lucky Lake +STR_PARK :Lucky Lake +STR_DTLS :Met een onbeperkt budget, maar gesitueerd op een veeleisende locatie is het een uitdaging dit park uit te breiden en te beheren. + + +STR_SCNR :Rainbow Summit +STR_PARK :Rainbow Summit +STR_DTLS :In dit park, gelegen op een heuvel, zijn hoge bouwwerken verboden. Kun je het park uitbreiden en het succesvol maken? + + +STR_SCNR :Six Flags Belgium +STR_PARK :Six Flags Belgium +STR_DTLS :Probeer dit Six Flags-park op je eigen manier te beheren en te verbeteren. + + +STR_SCNR :Six Flags Great Adventure +STR_PARK :Six Flags Great Adventure +STR_DTLS :Bouw de ontbrekende Six Flags-attracties, of maak je eigen ontwerpen om het park te verbeteren! Maar vergeet je uiteindelijke doel niet: meer bezoekers naar het park halen! + + +STR_SCNR :Six Flags Holland +STR_PARK :Six Flags Holland +STR_DTLS :Probeer dit Six Flags-park op je eigen manier te beheren en te verbeteren. + + +STR_SCNR :Six Flags Magic Mountain +STR_PARK :Six Flags Magic Mountain +STR_DTLS :Bouw de ontbrekende Six Flags-attracties, of maak je eigen ontwerpen om het park te verbeteren! Maar vergeet je uiteindelijke doel niet: je lening terugbetalen terwijl je de waarde van je park laat stijgen! + + +STR_SCNR :Six Flags over Texas +STR_PARK :Six Flags over Texas +STR_DTLS :Bouw de ontbrekende Six Flags-attracties, of maak je eigen ontwerpen om het park te verbeteren! Maar vergeet je uiteindelijke doel niet: meer bezoekers naar het park halen! + + +STR_SCNR :Bouw je eigen Six Flags Belgium +STR_PARK :Six Flags Belgium +STR_DTLS :Bouw je eigen versie van dit Europese Six Flags-park. + + +STR_SCNR :Bouw je eigen Six Flags Great Adventure +STR_PARK :Six Flags Great Adventure +STR_DTLS :Gebruik je ontwerpvaardigheden om dit Six Flags-park opnieuw te maken. + + +STR_SCNR :Bouw je eigen Six Flags Holland +STR_PARK :Six Flags Holland +STR_DTLS :Bouw je eigen versie van dit Europese Six Flags-park. + + +STR_SCNR :Bouw je eigen Six Flags Magic Mountain +STR_PARK :Six Flags Magic Mountain +STR_DTLS :Maak je eigen versie van dit enorme Six Flags-park. + + +STR_SCNR :Bouw je eigen Six Flags over Texas +STR_PARK :Six Flags over Texas +STR_DTLS :Maak je eigen versie van dit Six Flags-park. + + +STR_SCNR :Bouw je eigen Six Flags-park +STR_PARK :Six Flags +STR_DTLS :Maak je eigen Six Flags-park, door gebruik te maken van attracties uit andere Six Flags-parken of door zelf nieuwe attracties te ontwerpen. + +#TT + +STR_SCNR : Mythologie - Animatronic-filmset +STR_PARK :Animatronic Antics +STR_DTLS :Je moet een bestaand pretpark, gebouwd op een oude filmset, beheren en verbeteren. Bouw een eerbetoon aan de pioniers van de stop-motionanimatie, die de wezens uit de mythologie tot leven brachten op het witte doek. + +################################## +# Rides/attractions / Attracties # +################################## + +# 3D Cinema / 3d-bioscoop +[C3D] +STR_NAME :3D-bioscoop +STR_DESC :Bioscoop in een bolvormig gebouw waarin 3D-films worden getoond. +STR_CPTY :20 passagiers +# End of 3D Cinema / 3d-bioscoop + +# Mine Ride / Aangedreven mijntrein +[PMT1] +STR_NAME :Aangedreven mijntrein +STR_DESC :Aangedreven mijntreinen rijden over een soepele en kronkelende baan. +STR_CPTY :4 passagiers per karretje (voorste karretje 2) +# End of Mine Ride / Aangedreven mijntrein + +# Reverse Freefall Coaster / Achterwaartsevrijevalachtbaan +[REVF1] +STR_NAME :Wagen voor achterwaartse vrije val +STR_DESC :Grote wagen voor de achterwaartstevrijevalachtbaan. +STR_CPTY :8 passagiers + +#WW +[KOLARIDE] +STR_NAME :Koalabaan +STR_DESC :Grote wagen voor de achterwaartstevrijevalachtbaan. +STR_CPTY :8 passagiers + +#TT +[JETPACKX] +STR_NAME :Jetpack-booster +STR_DESC :Passagiers zitten in een voertuig dat gelanceerd wordt over een verticale baan. +STR_CPTY :8 passagiers +# End of Reverse Freefall Coaster / Achterwaartsevrijevalachtbaan + +# Car Ride / Autorondrit +[TRUCK1] +STR_NAME :Pickuptrucks +STR_DESC :Elektrische voertuigen in de vorm van een pickuptruck. +STR_CPTY :1 passagier per truck + +[RCR] +STR_NAME :Raceauto's +STR_DESC :Elektrische voertuigen in de vorm van een raceauto. +STR_CPTY :1 passagier per karretje + +[SPCAR] +STR_NAME :Sportauto's +STR_DESC :Elektrische voertuigen in de vorm van een sportauto. +STR_CPTY :1 passagier per karretje + +[VCR] +STR_NAME :Oldtimers +STR_DESC :Elektrische voertuigen in de vorm van een oldtimer. +STR_CPTY :1 passagier per karretje + +[CTCAR] +STR_NAME :Cheshire Cats +STR_DESC :Elektrische voertuigen in de vorm van een kat. +STR_CPTY :1 passagier per karretje + +[4X4] +STR_NAME :Monstertrucks +STR_DESC :Gigantische elektrische 4x4-trucks die steile hellingen kunnen nemen. +STR_CPTY :2 passagiers per truck + +#WW +[CRNVBFLY] +STR_NAME :Vlinderwagentjes +STR_DESC :Elektrische carnivalsoptochtwagentjes in de vorm van een vlinder. +STR_CPTY :2 passagiers per karretje + +#WW +[CRNVFROG] +STR_NAME :Kikkerwagentjes +STR_DESC :Elektrische carnivalsoptochtwagentjes in de vorm van een kikker. +STR_CPTY :2 passagiers per karretje + +#WW +[CRNVLZRD] +STR_NAME :Hagediswagentjes +STR_DESC :Elektrische carnivalsoptochtwagentjes in de vorm van een hagedis. +STR_CPTY :2 passagiers per karretje + +#WW +[BLACKCAB] +STR_NAME :Londonse taxi's +STR_DESC :Elektrische voertuigen in de vorm van een Londense taxi. +STR_CPTY :2 passagiers per karretje + +#WW +[HUSKIE] +STR_NAME :Huskiewagentjes +STR_DESC :Elektrische voertuigen in de vorm van een huskieslee. +STR_CPTY :2 passagiers per karretje + +#TT +[PEGASUSX] +STR_NAME :Pegasuskarretjes +STR_DESC :Elektrische voertuigen in de vorm van een kar die wordt voortgetrokken door Pegasus. +STR_CPTY :2 passagiers per karretje + +#TT +[HOVERCAR] +STR_NAME :Zweefwagens +STR_DESC :Door middel van maglev-technologie wordt de illusie van futuristische zweefwagens gecreëerd. +STR_CPTY :2 passagiers per karretje +# End of Car Ride / Autorondrit + +# Motion Simulator / Bewegingssimulator +[SIMPOD] +STR_NAME :Bewegingssimulator +STR_DESC :Passagiers bekijken een film in de cabine van een bewegingssimulator die wordt gedraaid en bewogen door een hydraulische arm. +STR_CPTY :8 passagiers + +#TT +[MICROBUS] +STR_NAME :Hippiebus +STR_DESC :Passagiers bekijken een film in de cabine van een bewegingssimulator die wordt gedraaid en bewogen door een hydraulische arm. +STR_CPTY :8 passagiers +# End of Motion Simulator / Bewegingssimulator + +# Bobsleigh Coaster / Bobslee-achtbaan +[BOB1] +STR_NAME :Bobslee-achtbaan +STR_DESC :Passagiers rijden over een kronkelende baan, waarbij ze enkel worden geleid door de ronding en banking van de halfronde baan. +STR_CPTY :2 passagiers per karretje + +[INTBOB] +STR_NAME :Zespersoonsbob +STR_DESC :Passagiers rijden over een kronkelende baan, waarbij ze enkel worden geleid door de ronding en banking van de halfronde baan. +STR_CPTY :6 passagiers per bob + +#WW +[PENGUINB] +STR_NAME :Pinguïnbobslee +STR_DESC :Passagiers rijden over een kronkelende baan, waarbij ze enkel worden geleid door de ronding en banking van de halfronde baan. +STR_CPTY :2 passagiers per karretje + +#TT +[BLCKDETH] +STR_NAME :Zwartedoodbobslee +STR_DESC :Passagiers rijden over een kronkelende baan in ratvormige karretjes, waarbij ze enkel worden geleid door de ronding en banking van de halfronde baan. +STR_CPTY :2 passagiers per karretje +# End of Bobsleigh Coaster / Bobslee-achtbaan + +# Log Flume / Boomstamattractie +[LFB1] +STR_NAME :Boomstamattractie +STR_DESC :Boten in de vorm van een boomstam varen door een waterbak, waarbij ze van steile hellingen afdalen om de passagiers te doorweken. +STR_CPTY :4 passagiers per boot + +#WW +[CROCFLUM] +STR_NAME :Krokillenrivier +STR_DESC :Boten in de vorm van een krokodil varen door een waterbak, waarbij ze van steile hellingen afdalen om de passagiers te doorweken. +STR_CPTY :4 passagiers per boot +# End of Log Flume / Boomstamattractie + +# Boat Ride / Bootverhuur +[RBOAT] +STR_NAME :Roeiboten +STR_DESC :Boten waarin passagiers zelf roeien. +STR_CPTY :2 passagiers per boot + +[BBOAT] +STR_NAME :Botsboten +STR_DESC :Kleine ronde bootjes, aangedreven door een centrale motor en bestuurd door de passagiers. +STR_CPTY :2 passagiers per boot + +[JSKI] +STR_NAME :Jetski's +STR_DESC :Eénpersoons jetski's die de bezoekers zelf kunnen besturen. +STR_CPTY :1 persoon per jetski + +[CBOAT] +STR_NAME :Kano's +STR_DESC :Lange kano's waarin de passagiers zelf roeien. +STR_CPTY :2 passagiers per kano + +[TRIKE] +STR_NAME :Waterfietsen +STR_DESC :Driewielige waterfietsen met grote raderwielen. +STR_CPTY :2 passagiers per waterfiets + +[SWANS] +STR_NAME :Zwanenbootjes +STR_DESC :Boten in de vorm van een zwaan, voortgestuwd door het trappen van de passagiers op de eerste rij. +STR_CPTY :4 passagiers per boot + +#WW +[DOLPHINR] +STR_NAME :Dolfijnenbootjes +STR_DESC :Eénpersoonsvoertuigen in de vorm van een dolfijn die de bezoekers zelf kunnen besturen. +STR_CPTY :1 persoon per voertuig + +#WW +[OUTRIGGR] +STR_NAME :Outriggerkano's +STR_DESC :Lange kano's waarin de passagiers zelf roeien. +STR_CPTY :2 passagiers per kano + +#WW +[TUTLBOAT] +STR_NAME :Schildpadbootjes +STR_DESC :Kleine ronde opblaasbootjes, aangedreven door een centrale motor en bestuurd door de passagiers. +STR_CPTY :2 passagiers per boot + +#WW +[MANDARIN] +STR_NAME :Mandarijneendbootjes +STR_DESC :Boot in de vorm van een mandarijneend, die wordt voortbewogen door het trappen van de passagiers op de eerste rij. +STR_CPTY :4 passagiers per boot + +#WW +[DHOWWATR] +STR_NAME :Dhowbootjes +STR_DESC :Decoratieve visserboot waarbij de passagiers zelf trappen. +STR_CPTY :2 passagiers per boot + +#CC +[AE-SWIM] +STR_NAME :Zwembad +STR_DESC :Een steiger waarvan gasten het water in kunnen om een stukje te zwemmen. Door "The Amazing Earl". +STR_CPTY :1 bezoeker per "boot" +# End of Boat Ride / Bootverhuur + +# Dodgems / Botsauto's +[DODG1] +STR_NAME :Botsauto's +STR_DESC :Elektrische wagentjes die de passagiers zelf besturen. +STR_CPTY :1 passagier per botsauto + +#TT +[TRICATOP] +STR_NAME :Triceratopsbotsauto's +STR_DESC :De passagiers vatten elkaar bij de horens in triceratopsvormige botsauto's. +STR_CPTY :1 passagier per botsauto + +#TT +[FIGTKNIT] +STR_NAME :Riddergevecht-botsauto's +STR_DESC :De passagiers strijden om de eer in paardvormige botsauto's. +STR_CPTY :1 passagier per botsauto +# End of Dodgems / Botsauto's + +# Circus +[CIRCUS1] +STR_NAME :Circus +STR_DESC :Een dierennummer in een circustent. +STR_CPTY :30 bezoekers +# End of Circus + +# Compact Inverted Coaster / Compacte omgekeerde achtbaan +[SLCT] +STR_NAME :Compacte omgekeerde achtbaan +STR_DESC :Passagiers zitten in stoelparen die onder de baan hangen terwijl ze door kronkelende en scherpe omkeringen gaan. +STR_CPTY :2 passagiers per karretje + +[VEKDV] +STR_NAME :Omgekeerde verticale shuttle +STR_DESC :Passagiers zitten in karretjes die onder de baan hangen, worden achteruit een verticale baan opgetrokken en vervolgens losgelaten, waarna ze door kronkelende en scherpe omkeringen gaan. +STR_CPTY :4 passagiers per karretje + +[SLCFO] +STR_NAME :Omgekeerde shuttle +STR_DESC :Passagiers zitten in stoelparen die onder de baan hangen terwijl ze door kronkelende en scherpe omkeringen gaan. +STR_CPTY :4 passagiers per karretje + +#WW +[POLARBER] +STR_NAME :IJsbeerachtbaan +STR_DESC :Passagiers zitten in paren, met het gezicht naar voren of achteren, en gaan door scherpe omkeringen. +STR_CPTY :4 passagiers per karretje +# End of Compact Inverted Coaster / Compacte omgekeerde achtbaan + +# Crooked House +[CHBUILD] +STR_NAME :Crooked House +STR_DESC :Gebouw met scheve kamers en gangen die de bezoekers desoriënteren. +STR_CPTY :5 bezoekers + +#TT +[FUNHOUSE] +STR_NAME :Fun House +STR_DESC :Gebouw met bewegende muren en vloeren om de bezoekers te desoriënteren. +STR_CPTY :5 bezoekers + +#TT +[HALOFMRS] +STR_NAME :Spiegelpaleis +STR_DESC :Gebouw met gebogen spiegels die de weerspiegeling van de bezoekers vervormen. +STR_CPTY :5 bezoekers + +#TT +[SPOKPRSN] +STR_NAME :Spookgevangenis +STR_DESC :Gebouw met kerkers en poppen van opgesloten mensen, om de bezoekers die er doorheen lopen angst aan te jagen. +STR_CPTY :5 bezoekers +# End of Crooked House + +# Maze / Doolhof +[HMAZE] +STR_NAME :Doolhof +STR_DESC :Bezoekers lopen door een doolhof van 1,8m hoge heggen of muren, en kunnen er pas uit wanneer ze de uitgang vinden. +# End of Maze / Doolhof + +# Merry-go-round / Draaimolen +[MGR1] +STR_NAME :Draaimolen +STR_DESC :Traditionele draaimolen met uit hout gesneden paarden. +STR_CPTY :16 passagiers + +#TT +[MGR2] +STR_NAME :Dubbeldekscarrousel +STR_DESC :Traditionele overdekte dubbeldekscarrousel met uit hout gesneden paarden. +STR_CPTY :32 passagiers +# End of Merry-go-round / Draaimolen + +# Enterprise +[ENTERP] +STR_NAME :Enterprise +STR_DESC :Draaiend wiel met hangende passagierscabines, dat eerst gaat draaien en vervolgens wordt opgetild door een steunarm. +STR_CPTY :16 passagiers + +#WW +[FIRECRAK] +STR_NAME :Voetzoekerenterprise +STR_DESC :Draaiend wiel met hangende passagierscabines, dat eerst gaat draaien en vervolgens wordt opgetild door een steunarm. +STR_CPTY :16 passagiers +# End of Enterprise + +# Monorail Cycles / Fietsbaan +[MONBK] +STR_NAME :Fietsbaan +STR_DESC :Speciale fietsen rijden over een stalen monorail, voortbewogen door het trappen van de passagiers. +STR_CPTY :1 persoon per fiets +# End of Monorail Cycles / Fietsbaan + +# Launched Freefall / Gelanceerde vrije val +[SSC1] +STR_NAME :Gelanceerde vrije val +STR_DESC :Een vrijevalwagen wordt pneumatisch langs een hoge stalen toren gelanceerd en gaat daarna in een vrije val weer naar beneden. +STR_CPTY :8 passagiers +# End of Launched Freefall / Gelanceerde vrije val + +# Giga Coaster / Giga-achtbaan +[INTST] +STR_NAME :Giga-achtbaan +STR_DESC :Een gigantische stalen achtbaan die in staat is tot soepele afdalingen en heuvels die hoger zijn dan 90 meter. +STR_CPTY :4 passagiers per karretje + +#WW +[TAXICSTR] +STR_NAME :Taxi-achtbaan +STR_DESC :Een gigantische stalen achtbaan met treinen in de vorm van een taxi die in staat is tot soepele afdalingen en heuvels die hoger zijn dan 90 meter. +STR_CPTY :4 passagiers per karretje +# End of Giga Coaster / Giga-achtbaan + +# Go-karts +[KART1] +STR_NAME :Go-karts +STR_DESC :Go-karts met benzinemotor die de passagiers zelf besturen. +STR_CPTY :1 persoon per kart + +#TT +[CAVMNCAR] +STR_NAME :Holbewoners-go-karts +STR_DESC :Passagiers racen in go-karts met een steentijdthema. +STR_CPTY :1 persoon per kart + +#TT +[1920RACR] +STR_NAME :Jarentwintig-raceauto's +STR_DESC :Passagiers racen in go-karts die er uitzien als raceauto's uit de jaren '20. +STR_CPTY :1 persoon per kart +# End of Go-karts + +# Heartline Twister +[UTCAR] +STR_NAME :Twisterkarretjes +STR_DESC :Achtbaankarretjes die geschikt zijn voor heartline twists. +STR_CPTY :4 passagiers per karretje + +[UTCARR] +STR_NAME :Twisterkarretjes (achterstevoren starten) +STR_DESC :Achtbaankarretjes die geschikt zijn voor heartline twists. +STR_CPTY :4 passagiers per karretje + +#WW +[TIGRTWST] +STR_NAME :Bengaalsetijgerkarretjes +STR_DESC :Achtbaankarretjes die geschikt zijn voor heartline twists. +STR_CPTY :4 passagiers per karretje +# End of Heartline Twister + +# Wooden Roller Coaster / Houten achtbaan +[PTCT1] +STR_NAME :Houten achtbaantrein +STR_DESC :Houten achtbaantrein met gevoerde zittingen en schootbeugels. +STR_CPTY :4 passagiers per karretje + +[PTCT2] +STR_NAME :Houten achtbaantrein (zespersoons) +STR_DESC :Houten achtbaantrein met gevoerde zittingen en schootbeugels. +STR_CPTY :6 passagiers per karretje + +[PTCT2R] +STR_NAME :Houten achtbaantrein (zespersoons, achteruit) +STR_DESC :Houten achtbaantrein met gevoerde zittingen en schootbeugels, die rijdt met de zittingen naar achteren. +STR_CPTY :6 passagiers per karretje + +[MFT] +STR_NAME :Gelede achtbaantrein +STR_DESC :Achtbaantrein met korte karretjes van één rij en een open voorkant. +STR_CPTY :2 passagiers per karretje + +#WW +[MINECART] +STR_NAME :Mijnkarretjes +STR_DESC :Houten achtbaantrein met gevoerde zittingen en schootbeugels. +STR_CPTY :4 passagiers per karretje + +#WW +[STGCCSTR] +STR_NAME :Postkoetsen +STR_DESC :Houten achtbaantrein met gevoerde zittingen en schootbeugels. +STR_CPTY :4 passagiers per karretje +# End of Wooden Roller Coaster / Houten achtbaan + +# Reverser Roller Coaster / Houten achteruitachtbaan +[REVCAR] +STR_NAME :Houten achteruitachtbaan +STR_DESC :Karretjes met draaistellen rijden op een houten baan en kunnen omkeren op speciale stukken baan. +STR_CPTY :6 passagiers per karretje + +#TT +[POLICECR] +STR_NAME :Politieautobaan +STR_DESC :Karretjes die er uitzien als een Amerikaanse politieauto uit de jaren '60 rijden op een houten baan en kunnen omkeren op speciale stukken baan. +STR_CPTY :6 passagiers per karretje +# End of Reverser Roller Coaster / Houten achteruitachtbaan + +# Wooden Wild Mouse / Houten wildemuisachtbaan +[WMMINE] +STR_NAME :Houten wildemijnachtbaan +STR_DESC :Kleine mijnkarretjes rijden op een zigzaggende baan en hellen gevaarlijk over in de haarspeldbochten en scherpe afdalingen. +STR_CPTY :2 passagiers per karretje + +[WMOUSE] +STR_NAME :Houten wildemuisachtbaan +STR_DESC :Kleine muisvormige karretjes rijden op een zigzaggende baan en hellen gevaarlijk over in de haarspeldbochten en scherpe afdalingen. +STR_CPTY :2 passagiers per karretje +# End of Wooden Wild Mouse / Houten wildemuisachtbaan + +# Junior Roller Coaster / Juniorachtbaan +[ZLDB] +STR_NAME :Lieveheersbeestjestreinen +STR_DESC :Achtbaantrein met kleine karretjes in de vorm van een lieveheersbeestje. +STR_CPTY :2 passagiers per karretje + +[ZLOG] +STR_NAME :Boomstronktreinen +STR_DESC :Achtbaantrein met kleine karretjes in de vorm van een boomstronk. +STR_CPTY :2 passagiers per karretje + +#WW +[WHICGRUB] +STR_NAME :Rupstreinen +STR_DESC :Achtbaantrein met kleine karretjes in de vorm van een grote rups. +STR_CPTY :2 passagiers per karretje + +#OCC +[ZPANDA] +STR_NAME :Pandatreinen +STR_DESC :Achtbaantrein met kleine karretjes in de vorm van een panda. +STR_CPTY :1 passagier per karretje +# End of Junior Roller Coaster / Juniorachtbaan + +# Chairlift / Kabelbaan +[CLIFT1] +STR_NAME :Stoeltjesliftkarretjes +STR_DESC :Open stoeltjesliftkarretjes. +STR_CPTY :2 passagiers per karretje + +[CLIFT2] +STR_NAME :Skiliftkarretjes +STR_DESC :Open karretjes in skiliftstijl. +STR_CPTY :2 passagiers per karretje +# End of Chairlift / Kabelbaan + +# LIM Launched RC / LIM-lanceringsachtbaan +[PREMT1] +STR_NAME :LIM-lanceringsachtbaan +STR_DESC :Achtbaantreinen worden door lineaire inductiemotoren het station uit gelanceerd en razen door een kronkelende baan die vaak over de kop gaat. +STR_CPTY :4 passagiers per karretje + +#WW +[TGVTRAIN] +STR_NAME :TGV-achtbaan +STR_DESC :Achtbaantreinen worden door lineaire inductiemotoren het station uit gelanceerd en razen door een kronkelende baan die vaak over de kop gaat. +STR_CPTY :4 passagiers per karretje + +#TT +[GANSTRCR] +STR_NAME :Gangsterauto-achtbaan +STR_DESC :Achtbaantreinen in de stijl van een gansterauto uit de jaren '20 worden door lineaire inductiemotoren het station uit gelanceerd en razen door een kronkelende baan die vaak over de kop gaat. +STR_CPTY :4 passagiers per karretje +# End of LIM Launched RC / LIM-lanceringsachtbaan + +# Lift +[LIFT1] +STR_NAME :Lift +STR_DESC :Bezoekers gaan in een lift in een toren omhoog of omlaag om naar een ander hoogteniveau te komen. +STR_CPTY :16 passagiers + +#WW +[MINELIFT] +STR_NAME :Mijnlift +STR_DESC :Bezoekers gaan in een lift in een toren omhoog of omlaag om naar een ander hoogteniveau te komen. +STR_CPTY :16 passagiers + +#TT +[TELEPTER] +STR_NAME :Teleporter +STR_DESC :Bezoekers gaan in een lift in een toren omhoog of omlaag om naar een ander hoogteniveau te komen. +STR_CPTY :16 passagiers +# End of Lift + +# Lay-down RC / Liggende achtbaan +[VEKST] +STR_NAME :Liggende achtbaan +STR_DESC :Passagiers worden door middel van een speciale beugel in een liggende positie vastgehouden, waarna ze op hun rug of met hun gezicht naar de grond door kronkelende stukken baan en omkeringen heen gaan. +STR_CPTY :4 passagiers per karretje + +#TT +[HARPIESX] +STR_NAME :Harpijenbaan +STR_DESC :Passagiers worden door middel van een speciale beugel in een liggende positie vastgehouden, waarna ze op hun rug of met hun gezicht naar de grond door kronkelende stukken baan en omkeringen heen gaan. +STR_CPTY :4 passagiers per karretje +# End of Lay-down RC / Liggende achtbaan + +# Air powered vertical RC / Luchtaangedreven verticale achtbaan +[THCAR] +STR_NAME :Luchtaangedreven verticale achtbaan +STR_DESC :Na een enerverende pneumatische lancering rijdt de trein met hogere snelheid over een verticale baan, over de top, en vervolgens over de andere kant weer naar beneden om terug te keren naar het station. +STR_CPTY :2 passagiers per karretje + +#WW +[BOMERANG] +STR_NAME :Boemerangachtbaan +STR_DESC :Na een enerverende pneumatische lancering rijdt de trein met hogere snelheid over een verticale baan, over de top, en vervolgens over de andere kant weer naar beneden om terug te keren naar het station. +STR_CPTY :2 passagiers per karretje + +#TT +[HOTRODXX] +STR_NAME :Hotrod-achtbaan +STR_DESC :Na een enerverende pneumatische lancering rijdt de trein met hogere snelheid over een verticale baan, over de top, en vervolgens over de andere kant weer naar beneden om terug te keren naar het station. +STR_CPTY :2 passagiers per karretje +# End of Air powered vertical RC / Luchtaangedreven verticale achtbaan + +# Mine train RC / Mijntreinachtbaan +[AMT1] +STR_NAME :Mijntreinachtbaan +STR_DESC :Achtbaantreinen in de vorm van een mijntrein razen over stalen achtbaanrails die er uitziet als een oude spoorbaan. +STR_CPTY :4 passagiers per karretje (voorste karretje 2) +# End of Mine train RC / Mijntreinachtbaan + +# Mini RC / Mini-achtbaan +[WCATC] +STR_NAME :Autokarretjes +STR_DESC :Achtbaankarretjes in de vorm van een auto. +STR_CPTY :4 passagiers per karretje + +[RCKC] +STR_NAME :Raketkarretjes +STR_DESC :Achtbaankarretjes in de vorm van een raket. +STR_CPTY :4 passagiers per karretje + +[JSTAR1] +STR_NAME :Rodelsleekarretjes +STR_DESC :Achtbaankarretjes in de vorm van een rodelslee, waarin de passagiers achter elkaar zitten. +STR_CPTY :4 passagiers per karretje + +#WW +[JAGUARRD] +STR_NAME :Jaguarkarretjes +STR_DESC :Achtbaankarretjes in de vorm van een jaguar. +STR_CPTY 4 passagiers per karretje + +#WW +[LIONRIDE] +STR_NAME :Leeuwenkarretjes +STR_DESC :Achtbaankarretjes in de vorm van een leeuw. +STR_CPTY :4 passagiers per karretje + +#WW +[RSSNCRRD] +STR_NAME :Russische auto's +STR_DESC :Achtbaankarretjes in de vorm van een Russische auto. +STR_CPTY :4 passagiers per auto + +#TT +[JETPLANE] +STR_NAME :Straalvliegtuigachtbaan +STR_DESC :Een compacte achtbaan met individuele karretjes en steile, kronkelende afdalingen. +STR_CPTY :4 passagiers per karretje +# End of Mini RC / Mini-achtbaan + +# Miniature railway / Miniatuurspoorweg +[NRL] +STR_NAME :Stoomtrein +STR_DESC :Miniatuurstroomtrein bestaande uit een replicastoomlocomotief en tender, die open houten wagons voorttrekt. +STR_CPTY :6 passagiers per wagon + +[NRL2] +STR_NAME :Stroomtrein met overdekte wagons +STR_DESC :Miniatuurstroomtrein bestaande uit een replicastoomlocomotief en tender, die wagons met stoffen overdekking voorttrekt. +STR_CPTY :6 passagiers per wagon + +[AML1] +STR_NAME :Amerikaanse stoomtrein +STR_DESC :Miniatuurstroomtrein bestaande uit een replicastoomlocomotief en tender, die wagons met stoffen overdekking voorttrekt. +STR_CPTY :6 passagiers per wagon + +[TRAM1] +STR_NAME :Trams +STR_DESC :Replica's van oude trams +STR_CPTY :10 passagiers per tram + +#WW +[LONDONBS] +STR_NAME :Londense bus +STR_DESC :Replica van de beroemde Londense Routemasters. +STR_CPTY :10 passagiers per bus + +#WW +[STEAMTRN] +STR_NAME :Maharadja-stoomtrein +STR_DESC :Miniatuurstroomtrein bestaande uit een replicastoomlocomotief en tender, die dichte houten wagons voorttrekt. +STR_CPTY :6 passagiers per wagon + +#WW +[SANFTRAM] +STR_NAME :Trams uit San Francisco +STR_DESC :Replica's van oude trams uit San Francisco +STR_CPTY :10 passagiers per tram + +#TT +[SCHOOLBS] +STR_NAME :Schoolbussen +STR_DESC :Replica's van Amerikaanse gele schoolbussen. +STR_CPTY :10 passagiers per bus +# End of Miniature railway / Miniatuurspoorweg + +# Mini Golf / Minigolf +[GOLF1] +STR_NAME :Miniholf +STR_DESC :Een rustig spelletje minigolf. +# End of Mini Golf / Minigolf + +# Mini Helicopters / Minihelicopters +[HELICAR] +STR_NAME :Minihelicopters +STR_DESC :Aangedreven karretjes in de vorm van een helicopter rijden over een stalen baan, bestuurd door het trappen van de passagiers. +STR_CPTY :2 passagiers per karretje +# End of Mini Helicopters / Minihelicopters + +# Monorail +[MONO1] +STR_NAME :Gestroomlijnde monorailtrein +STR_DESC :Monorailtrein met gestroomlijnde voor- en achterkant en een hoge capaciteit. +STR_CPTY :10 passagiers per karretje (voor en achter 5) + +[MONO2] +STR_NAME :Kleine monorailkarretjes +STR_DESC :Kleine monorailkarretjes met open zijkanten. +STR_CPTY :4 passagiers per karretje + +[MONO3] +STR_NAME :Retro-monorailtreinen +STR_DESC :Monorailtreinen met open karretjes. +STR_CPTY :4 passagiers per karretje +# End of Monorail + +# Multi-dimension RC / Multidimensieachtbaan +[ARRX] +STR_NAME :Multidimensieachtbaantrein +STR_DESC :Karretjes met stoelen die de passagiers halsoverkop kunnen laten tollen. +STR_CPTY :4 passagiers per karretje +# End of Multi-dimension RC / Multidimensieachtbaan + +# Observation Tower / Observatietoren +[OBS1] +STR_NAME :Observatietoren +STR_DESC :Draaiende observatiecabine die langs een verticale toren omhoog gaat. +STR_CPTY :20 passagiers + +[OBS2] +STR_NAME :Dubbelsdeks observatietoren +STR_DESC :Draaiende observatiecabine met twee dekken die langs een verticale toren omhoog gaat. +STR_CPTY :32 passagiers + +#TT +[BMVOCTPS] +STR_NAME :Klodder uit de ruimte +STR_DESC :Draaiende gethematiseerde observatiecabine die langs een verticale toren omhoog gaat. +STR_CPTY :20 passagiers +# End of Observation Tower / Observatietoren + +# Inverted Impulse RC / Omgekeerde Impulse-achtbaan +[INTINV] +STR_NAME :Omgekeerde Impulse-achtbaan +STR_DESC :Een omgekeerde achtbaantrein wordt het station uit gelanceerd en gaat een verticale kronkelende baan op, waarna deze terugzakt, door het station heengaat en achteruit een ander stuk verticale baan opgaat. +STR_CPTY :4 passagiers per karretje + +#TT +[BARNSTRM] +STR_NAME :Stuntvliegersachtbaan +STR_DESC :Een omgekeerde achtbaantrein wordt het station uit gelanceerd en gaat een verticale kronkelende baan op, waarna deze terugzakt, door het station heengaat en achteruit een ander stuk verticale baan opgaat. +STR_CPTY :4 passagiers per karretje +# End of Inverted Impulse RC / Omgekeerde Impulse-achtbaan + +# Inverted RC / Omgekeerde achtbaan +[NEMT] +STR_NAME :Omgekeerde achtbaan +STR_DESC :Passagiers zitten in stoelen die onder de baan hangen terwijl ze door grote loopings, twists en grote adembenemende afdelingen gaan. +STR_CPTY :4 passagiers per karretje +# End of Inverted RC / Omgekeerde achtbaan + +# Inverted Hairpin RC / Omgekeerde haarspeldachtbaan +[IVMC1] +STR_NAME :Omgekeerde haarspeldachtbaan +STR_DESC :Losse karretjes hangen onder een zigzaggende baan met haarspeldbochten en scherpe afdalingen. +STR_CPTY :4 passagiers per karretje +# End of Inverted Hairpin RC / Omgekeerde haarspeldachtbaan + +# Flying RC / Vliegachtbaan +[BMAIR] +STR_NAME :Vliegachtbaan +STR_DESC :Bezoekers hangen in treinen onder de baan met enkel schouderbeugels en krijgen zo de ervaring dat ze vliegen. +STR_CPTY :4 passagiers per karretje + +#WW +[CONDORRD] +STR_NAME :Condorbaan +STR_DESC :Bezoekers hangen in Condorvormige treinen onder de baan met enkel schouderbeugels en krijgen zo de ervaring dat ze vliegen. +STR_CPTY :4 passagiers per karretje + +#TT +[PTERODAC] +STR_NAME :Pterodactyl Coaster +STR_DESC :Bezoekers hangen in confortabele treinen onder de baan met enkel schouderbeugels en krijgen zo de ultieme prehistorische vliegervaring. +STR_CPTY :4 passagiers per karretje +# End of Flying RC / Vliegachtbaan + +# Inverted Mini RC / Omgekeerde mini-achtbaan +[BATFL] +STR_NAME :Schommelkarretjes +STR_DESC :Kleine karretjes die aan de rail erboven schommelen. +STR_CPTY :2 passagiers per karretje + +[SKYTR] +STR_NAME :Omgekeerde mini-achtbaan +STR_DESC :Passagiers zitten in kleine karretjes die onder een enkele rail hangen en naar buiten zwaaien in de bochten. +STR_CPTY :1 passagier per karretje + +#WW +[SPUTNIKR] +STR_NAME :Spoetnikbaan +STR_DESC :Passagiers zitten in karretjes in de vorm van de Spoetnik, die onder een enkele rail hangen en naar buiten zwaaien in de bochten. +STR_CPTY :2 passagiers per karretje + +#TT +[DRAGNFLY] +STR_NAME :Libellenbaan +STR_DESC :Passagiers zitten in kleine karretjes die onder een enkele rail hangen en naar buiten zwaaien in de bochten. +STR_CPTY :2 passagiers per karretje + +#TT +[HOVRBORD] +STR_NAME :Hoverboard Coaster +STR_DESC :Passagiers zitten op een futurisch hoverboard die onder een enkele rail hangt en naar buiten zwaait in de bochten. +STR_CPTY :2 passagiers per karretje +# End of Inverted Mini RC / Omgekeerde mini-achtbaan + +# Suspended monorail / Omgekeerde monorail +[SMONO] +STR_NAME :Hangende monorailtreinen +STR_DESC :Monorailtreinen met een hoge capaciteit. +STR_CPTY :8 passagiers per karretje + +#TT +[ZEPLELIN] +STR_NAME :Zeppelin +STR_DESC :Monorailtreinen met een hoge capaciteit. +STR_CPTY :8 passagiers per karretje +# End of Suspended monorail / Omgekeerde monorail + +# Suspended Swinging Coaster / Omgekeerde schommelachtbaan +[ARRSW1] +STR_NAME :Normale karretjes +STR_DESC :Omgekeerde achtbaantrein bestaande uit karretjes die vrijuit kunnen schommelen als de trein door een bocht gaat. +STR_CPTY :4 passagiers per karretje + +[ARRSW2] +STR_NAME :Vliegtuigkarretjes +STR_DESC :Omgekeerde achtbaantrein bestaande uit karretjes in de vorm van een vliegtuig, die vrijuit kunnen schommelen als de trein door een bocht gaat. +STR_CPTY :4 passagiers per karretje + +[VEKVAMP] +STR_NAME :Karretjes zonder bodem +STR_DESC :Omgekeerde achtbaantrein bestaande uit stoeltjesliftachtige karretjes die vrijuit kunnen schommelen als de trein door een bocht gaat. +STR_CPTY :2 passagiers per karretje + +#WW +[ROCKET] +STR_NAME :Raketten uit de jaren '50 +STR_DESC :Omgekeerde achtbaantrein bestaande uit karretjes in de vorm van een raket uit de jaren '50, die vrijuit kunnen schommelen als de trein door een bocht gaat. +STR_CPTY :4 passagiers per karretje + +#WW +[GORILLA] +STR_NAME :Gorillakarretjes +STR_DESC :Omgekeerde achtbaantrein bestaande uit karretjes in de vorm van een gorilla, die vrijuit kunnen schommelen als de trein door een bocht gaat. +STR_CPTY :4 passagiers per karretje + +#WW +[SLOTH] +STR_NAME :Luiaardkarretjes +STR_DESC :Omgekeerde achtbaantrein bestaande uit karretjes in de vorm van een luiaard, die vrijuit kunnen schommelen als de trein door een bocht gaat. +STR_CPTY :4 passagiers per karretje + +#WW +[FOOTBALL] +STR_NAME :Voetbalkarretjes +STR_DESC :Omgekeerde achtbaantrein bestaande uit karretjes in de vorm van een enorme voetbal, die vrijuit kunnen schommelen als de trein door een bocht gaat. +STR_CPTY :4 passagiers per karretje + +#TT +[SEAPLANE] +STR_NAME :Watervliegtuigbaan +STR_DESC :Omgekeerde achtbaantrein bestaande uit karretjes die vrijuit kunnen schommelen als de trein door een bocht gaat. +STR_CPTY :4 passagiers per karretje +# End of Suspended Swinging Coaster / Omgekeerde schommelachtbaan + +# Submarine ride / Onderzeeërattractie +[SUBMAR] +STR_NAME :Onderzeeërattractie +STR_DESC :Passagiers rijden over een onderwaterparcours in onderzeeërs. +STR_CPTY :4 passagiers per onderzeeër + +#WW +[HIPPORID] +STR_NAME :Nijlpaardonderzeeërs +STR_DESC :Passagiers rijden over een onderwaterparcours in onderzeeërs. +STR_CPTY :5 passagiers per onderzeeër + +#WW +[KILLWHAL] +STR_NAME :Orka-onderzeeërs +STR_DESC :Passagiers rijden over een onderwaterparcours in onderzeeërs. +STR_CPTY :5 passagiers per onderzeeër +# End of Submarine ride / Onderzeeërattractie + +# Splash boats / Plonsboten +[SPBOAT] +STR_NAME :Plonsboten +STR_DESC :Boten met een hoge capaciteit varen door een brede waterbak, worden naar boven vervoerd door een lopende band, en gaan met hoge snelheid steile heuvels af om met een grote plons de passagiers te doorweken. +STR_CPTY :16 passagiers per boot +# End of Splash boats / Plonsboten + +# Ferris Wheel / Reuzenrad +[FWH1] +STR_NAME :Reuzenrad +STR_DESC :Groot draaiend rad met open stoeltjes. +STR_CPTY :32 passagiers +# End of Ferris Wheel / Reuzenrad + +# River Rafts / Riviertocht +[RFTBOAT] +STR_NAME :Riviertocht +STR_DESC :Boten in de vorm van een vlot varen rustig door een waterbak. +STR_CPTY :4 passagiers per vlot + +#TT +[RIVRSTYX] +STR_NAME :De Styx +STR_DESC :Bezoekers varen in het bootje van Charon door een waterbak. +STR_CPTY :4 passagiers per bootje +# End of River Rafts / Riviertocht + +# Roto-drop +[GDROP1] +STR_NAME :Roto-drop +STR_DESC :Een ring van stoelen wordt naar de bovenkant van een hoge toren getrokken terwijl hij rustig ronddraait, waarna hij losgelaten wordt in een vrije val, waarna hij beneden rustig wordt afgeremd door middel van magnetische remmen. +STR_CPTY :16 passagiers +# End of Roto-drop + +# Space rings / Ruimteringen +[SRINGS] +STR_NAME :Ruimteringen +STR_DESC :Concentrische draaiende ringen waarmee de passagiers vrij kunnen draaien in alle richtingen. +STR_CPTY :1 bezoeker per ring + +#TT +[FLALMACE] +STR_NAME :Goedendags +STR_DESC :Passagiers zitten op stoel in de vorm van een goedendag die ronddraait aan een paal. +STR_CPTY :1 bezoeker per stoel + +#TT +[TIMEMACH] +STR_NAME :Tijdmachine +STR_DESC :Bezoekers zitten in een speciaal ontwerpen bol en krijgen de illusie dat ze door de tijd reizen. +STR_CPTY :1 bezoeker per tijdmachine + +#CC +[RIDE7MKY] +STR_NAME :Springkussens +STR_DESC :Bezoekers springen op en neer op met lucht gevulde kussens. +STR_CPTY :1 bezoeker per kussen +# End of Space rings / Ruimteringen + +# Swinging ship / Schommelschip +[SWSH1] +STR_NAME :Schommelschip +STR_DESC :Groot schommelend piratenschip +STR_CPTY :16 passagiers +# End of Swinging ship / Schommelschip + +# Swinging Inverter Ship / Schommelschip dat over de kop gaat +[SWSH2] +STR_NAME :Schommelschip dat over de kop gaat +STR_DESC :Schip dat is bevestigd aan een arm met een contragewicht, en 360 graden kan draaien. +STR_CPTY :12 passagiers + +#WW +[JUNKSWNG] +STR_NAME :Chinese jonk +STR_DESC :Chinese jonk die is bevestigd aan een arm met een contragewicht, en 360 graden kan draaien. +STR_CPTY :12 passagiers +# End of Swinging Inverter Ship / Schommelschip dat over de kop gaat + +# Spiral RC / Spiraalachtbaan +[SPDRCR] +STR_NAME :Spiraalachtbaan +STR_DESC :Een compacte achtbaan met een spiraalvormige kettingheuvel en karretjes waarin de passagiers achter elkaar zitten. +STR_CPTY :6 passagiers per karretje + +#WW +[RHINORID] +STR_NAME :Neushoornbaan +STR_DESC :Een compacte achtbaan met een spiraalvormige kettingheuvel en karretjes waarin de passagiers achter elkaar zitten. +STR_CPTY :6 passagiers per karretje + +#TT +[BATTRRAM] +STR_NAME :Stormrambaan +STR_DESC :Een compacte achtbaan met een spiraalvormige kettingheuvel en karretjes waarin de passagiers achter elkaar zitten. +STR_CPTY :6 passagiers per karretje +# End of Spiral RC / Spiraalachtbaan + +# Spiral Slide / Spiraalglijbaan +[HSKELT] +STR_NAME :Spiraalglijbaan +STR_DESC :Houten gebouw met van binnen een trap en van buiten een spiraalglijbaan voor glijmatten. +# End of Spiral Slide / Spiraalglijbaan + +# Haunted House / Spookhuis +[HHBUILD] +STR_NAME :Spookhuis +STR_DESC :Groot gethematiseerd gebouw met enge gangen en spookachtige kamers. +STR_CPTY :15 bezoekers +# End of Haunted House / Spookhuis + +# Ghost train / Spooktrein +[GTC] +STR_NAME :Spooktrein +STR_DESC :Aangedreven monstervormige karretjes rijden over een baan, die over meerdere hoogteniveau loopt, langs spookachtig decor en special effects. +STR_CPTY :2 passagiers per karretje + +[HMCAR] +STR_NAME :Spookachtig landhuis +STR_DESC :Aangedreven karretjes rijden over een baan, die over meerdere hoogteniveau loopt, langs decor en special effects. +STR_CPTY :2 passagiers per karretje +# End of Ghost train / Spooktrein + +# Stand-Up RC / Staande achtbaan +[TOGST] +STR_NAME :Staande achtbaan +STR_DESC :Een achtbaan met loopings waar de passagiers in de karretjes staan. +STR_CPTY :4 passagiers per karretje + +#WW +[OSTRICH] +STR_NAME :Struisvogelbaan +STR_DESC :Een achtbaan met loopings waar de passagiers in de karretjes staan. +STR_CPTY :4 passagiers per karretje +# End of Stand-Up RC / Staande achtbaan + +# Looping RC / Stalen achtbaan +[SCHT1] +STR_NAME :Achtbaantrein +STR_DESC :Achtbaantrein met schootbeugels, die door loopings kan rijden. +STR_CPTY :4 passagiers per karretje + +#TT +[POLCHASE] +STR_NAME :Politieachtervolging +STR_DESC :Achtbaantrein met schootbeugels, die door loopings kan rijden. +STR_CPTY :4 passagiers per karretje + +#CC +[AE-MTRHN] +STR_NAME :Matterhorntrein +STR_DESC :Achtbaantrein in de stijl van de beroemde Matterhorn voor de 50e verjaardag van Disneyland. Door "The Amazing Earl". +STR_CPTY :4 passagiers per karretje +# End of Looping RC / Stalen achtbaan + +# Corkscrew RC / Stalen schroefachtbaan +[ARRT1] +STR_NAME :Stalen schroefachtbaan +STR_DESC :Een compacte stalen achtbaan waar de trein door schroeven en loopings gaat. +STR_CPTY :4 passagiers per karretje + +[ARRT2] +STR_NAME :Hypercoaster +STR_DESC :Een achtbaan zonder omkeringen met grote heuvels, een hoge snelheid, en comfortabele treinen met enkel schootbeugels. +STR_CPTY :6 passagiers per karretje + +#WW +[ANACONDA] +STR_NAME :Anacondabaan +STR_DESC :Een achtbaan zonder omkeringen met grote heuvels, een hoge snelheid, en comfortabele treinen met enkel schootbeugels. +STR_CPTY :6 passagiers per karretje + +#WW +[GRATWHTE] +STR_NAME :Grote-witte-haaibaan +STR_DESC :Een achtbaan zonder omkeringen met grote heuvels, een hoge snelheid, en comfortabele treinen met enkel schootbeugels. +STR_CPTY :4 passagiers per karretje + +#WW +[CONGAEEL] +STR_NAME :Palingbaan +STR_DESC :Een compacte stalen achtbaan waar de palingvormige trein door schroeven en loopings gaat. +STR_CPTY :4 passagiers per karretje + +#WW +[BULLET] +STR_NAME :Shinkansenbaan +STR_DESC :Achtbaan met treinen in de vorm van de Japanse Shinkansen (kogeltrein). +STR_CPTY :4 passagiers per karretje + +#WW +[CADDILAC] +STR_NAME :Limousinebaan +STR_DESC :Achtbaan met treinen in de vorm van een limousine +STR_CPTY :4 passagiers per karretje + +#WW +[SEALS] +STR_NAME :Zeehondenbaan +STR_DESC :Een compacte stalen achtbaan waar de trein door schroeven en loopings gaat. +STR_CPTY :4 passagiers per karretje +# End of Corkscrew RC / Stalen schroefachtbaan + +# Steel Twister RC / Stalen twisterachtbaan +[BMSD] +STR_NAME :Twisterachtbaan +STR_DESC :Brede achtbaantrein die langs de soepele stalen baan glijdt en door diverse soorten omkeringen gaat. +STR_CPTY :4 passagiers per karretje + +[BMSU] +STR_NAME :Staande twisterachtbaan +STR_DESC :Passagiers staan in de brede achtbaantrein met speciaal ontworpen beugels terwijl ze door soepele afdalingen en meerdere omkeringen razen. +STR_CPTY :4 passagiers per karretje + +[BMFL] +STR_NAME :Achtbaan zonder bodem +STR_DESC :Brede achtbaantreinen zonder bodem, die de passagiers het gevoel geeft in de open lucht te zijn terwijl ze langs de kronkelende baan en door meerdere omkeringen glijden. +STR_CPTY :4 passagiers per karretje + +[GOLTR] +STR_NAME :Hyper-twistertreinen +STR_DESC :Ruime treinen met eenvoudige schootbeugels. +STR_CPTY :6 passagiers per karretje + +[BMRB] +STR_NAME :Hyper-twistertreinen (brede karretjes) +STR_DESC :Brede karretjes met vier verhoogde stoelen naast elkaar en eenvoudige schootbeugels. +STR_CPTY :4 passagiers per karretje + +#WW +[SURFBRDC] +STR_NAME :Surfbaan +STR_DESC :Passagiers staan in de brede achtbaantrein met speciaal ontworpen beugels terwijl ze door soepele afdalingen en meerdere omkeringen razen. +STR_CPTY :4 passagiers per karretje + +#TT +[CERBERUS] +STR_NAME :Cerberusbaan +STR_DESC :Bezoekers zitten in comfortabele treinen met enkel eenvoudige schootbeugels terwijl ze door door soepele afdalingen gaan. +STR_CPTY :4 passagiers per karretje +# End of Steel Twister RC / Stalen twisterachtbaan + +# Steeplechase (Singel Rail RC) +[STEEP1] +STR_NAME :Steeplechase +STR_DESC :Passagiers zitten op paardvormige voertuigen die over een enkele rail lopen. +STR_CPTY :2 passagiers per paard + +[STEEP2] +STR_NAME :Motorfietsrace +STR_DESC :Passagiers zitten op voertuigen in de vorm van een motorgiets die over een enkele rail lopen. +STR_CPTY :2 rassagiers per motorfiets + +[SBOX] +STR_NAME :Zeepkistenrace +STR_DESC :Passagiers zitten in voertuigen in de vorm van een zeepkist die over een enkele rail lopen. +STR_CPTY :4 passagiers per zeepkist + +#TT +[JOUSTING] +STR_NAME :Duellerende ridders +STR_DESC :Passagiers zitten op paardvormige voertuigen die over een enkele rail lopen. +STR_CPTY :2 passagiers per paard + +#TT +[RAPTORXX] +STR_NAME :Velociraptorrace +STR_DESC :Passagiers zitten op velociraptorvormige voertuigen die over een enkele rail lopen. +STR_CPTY :2 passagiers per velociraptor + +#TT +[HOVERBKE] +STR_NAME :Zweeffietsen +STR_DESC :Passagiers zitten op futuristische fietsvormige voertuigen die over een enkele rail lopen. +STR_CPTY :2 passagiers per zweeffiets + +#CC +[AE-REIND] +STR_NAME :Runaway Reindeer +STR_DESC :Passagiers zitten in paren op rendiervormige karretjes - compleet met knipperende rode neuzen. Door "The Amazing Earl". +STR_CPTY :2 passagiers per rendier +# End of Steeplechase (Singel Rail RC) + +# Topspin +[TOPSP1] +STR_NAME :Topspin +STR_DESC :Passagiers zitten in een gondel die is opgehangen aan grote roterende armen, en worden halsoverkop vooruit en achteruit gedraaid. +STR_CPTY :8 passagiers + +#TT +[TREBUCHT] +STR_NAME :Trebuchet-topspin +STR_DESC :Passagiers zitten in een gondel die is opgehangen aan grote roterende armen, gebaseerd op een middeleeuws belegeringswapen. +STR_CPTY :8 passagiers +# End of Topspin + +# Twist +[TWIST1] +STR_NAME :Twist +STR_DESC :Passagiers zitten per twee in stoelen die ronddraaien aan de uiteinden van drie lange draaiarmen. +STR_CPTY :18 passagiers + +[TWIST2] +STR_NAME :Sneeuwkopjes +STR_DESC :Passagiers zitten per twee in stoelen die om een sneeuwpop heendraaien. +STR_CPTY :18 passagiers + +#WW +[FABERGE] +STR_NAME :Fabergé-twist +STR_DESC :Passagiers zitten per twee in stoelen die ronddraaien aan de uiteinden van drie lange draaiarmen. +STR_CPTY :18 passagiers + +#WW +[DIAMONDR] +STR_NAME :Diamant-twist +STR_DESC :Passagiers zitten per twee in stoelen die ronddraaien aan de uiteinden van drie lange draaiarmen. +STR_CPTY :18 passagiers + +#WW +[ITALYPOR] +STR_NAME :Carabinieri-twist +STR_DESC :Passagiers zitten per twee in stoelen die ronddraaien aan de uiteinden van drie lange draaiarmen. +STR_CPTY :18 passagiers + +#WW +[COFFEECU] +STR_NAME :Koffiepot-twist +STR_DESC :Passagiers zitten per twee in stoelen die ronddraaien aan de uiteinden van drie lange draaiarmen. +STR_CPTY :18 passagiers + +#WW +[FIGHTKIT] +STR_NAME :Havik-twist +STR_DESC :Passagiers zitten per twee in stoelen die ronddraaien aan de uiteinden van drie lange draaiarmen. +STR_CPTY :18 passagiers + +#TT +[GINTSPDR] +STR_NAME :B-filmspin-twist +STR_DESC :Passagiers zitten per twee in stoelen die rond een reuzenspin uit een B-film draaien. +STR_CPTY :18 passagiers + +#TT +[DINOEGGS] +STR_NAME :Dinosaurei-twist +STR_DESC :Passagiers zitten per twee in stoelen die rond een bewegende moederdinosaurus draaien. +STR_CPTY :18 passagiers + +#TT +[NEPTUNEX] +STR_NAME :Neptunus-twist +STR_DESC :Passagiers zitten per twee in stoelen die rond een bewegend standbeeld van Neptunus draaien. +STR_CPTY :18 passagiers + +#TT +[TOMMYGUN] +STR_NAME :Tommygun-twist +STR_DESC :Passagiers zitten per twee in stoelen die rond een grote replica van een 'Tommy gun' draaien. +STR_CPTY :18 passagiers + +#CC +[RIDE4MKY] +STR_NAME :Zweefmolen +STR_DESC :Passagiers zitten in stoeltjes die onder een molen hangen en naar buiten vliegen als deze gaat draaien. +STR_CPTY :18 passagiers + +#CC +[AE-SWING] +STR_NAME :Zweefmolen +STR_DESC :Passagiers zitten in stoeltjes die onder een molen hangen en naar buiten vliegen als deze gaat draaien. Door "The Amazing Earl". +STR_CPTY :18 passagiers +# End of Twist + +# Vertical drop RC / Verticale achtbaan +[BMVD] +STR_NAME :Verticale achtbaan +STR_DESC :Extra brede karretjes rijden over een compleet verticale baan voor de ultieme vrijevalbeleving. +STR_CPTY :6 passagiers per karretje + +#TT +[VALKYRIE] +STR_NAME :Walkürenbaan +STR_DESC :Extra brede karretjes rijden over een compleet verticale baan voor de ultieme vrijevalbeleving. +STR_CPTY :6 passagiers per karretje +# End of Vertical drop RC / Verticale achtbaan + +# Virginia Reel +[VREEL] +STR_NAME :Virginia Reel +STR_DESC :Ronde karretjes gaan over een zigzaggende houten baan en draaien daarbij rond. +STR_CPTY :4 passagiers per karretje +# End of Virginia Reel + +# Magic Carpet / Vliegend tapijt +[MCARPET1] +STR_NAME :Vliegend tapijt +STR_DESC :Een grote wagen in de vorm van een vliegend tapijt draait rond aan de uiteinden van vier draaiarmen. +STR_CPTY :12 passagiers +# End of Magic Carpet / Vliegend tapijt + +# Flying saucers / Vliegende schotels +[FSAUC] +STR_NAME :Vliegende schotels +STR_DESC :Vliegende schotels die de passagiers zelf besturen +STR_CPTY :1 passagier per karretje + +#WW +[DRAGDODG] +STR_NAME :Chinese drakenkoppen +STR_DESC :Vliegende schotels die de passagiers zelf besturen +STR_CPTY :1 passagier per karretje + +#WW +[SKIDOO] +STR_NAME :Sneeuwscooters +STR_DESC :Elektrische sneeuwscooters die de passagiers zelf besturen +STR_CPTY :1 passagier per karretje + +#TT +[CYCLOPSX] +STR_NAME :Cyclopenogen +STR_DESC :Passagiers rijden in het oog van een grote cycloop. +STR_CPTY :1 passagier per karretje + +#TT +[FLWRPOWR] +STR_NAME :Flowerpower-schotels +STR_DESC :Vliegende schotels in de vorm van een bloem die de passagiers zelf besturen +STR_CPTY :1 passagier per karretje +# End of Flying saucers / Vliegende schotels + +# Water Coaster / Waterachtbaan +[CSTBOAT] +STR_NAME :Boten +STR_DESC :Achtbaankarretjes in de vorm van een boot. +STR_CPTY :6 passagiers per boot + +#WW +[MANTARAY] +STR_NAME :Manta's +STR_DESC :Achtbaankarretjes in de vorm van een manta (adelaarsrog). +STR_CPTY :6 passagiers per boot + +#TT +[TRILOBTE] +STR_NAME :Trilobietenbaan +STR_DESC :Bootvormige karretjes in de vorm van trilobiet 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_CPTY :6 passagiers per boot + +#TT +[FLYGBOAT] +STR_NAME :Vliegende boten +STR_DESC :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_CPTY :6 passagiers per boot +# End of Water Coaster / Waterachtbaan + +# Dinghy Slide / Waterglijbaan +[DING1] +STR_NAME :Waterglijbaan +STR_DESC :Passagiers glijden in opblaasboten door een kronkelende halfopen of compleet gesloten glijbaan. +STR_CPTY :2 passagiers per bootje +# End of Dinghy Slide / Waterglijbaan + +# (Steel) Wild Mouse / (Stalen) Wilde muis +[SMC1] +STR_NAME :Muiskarretjes +STR_DESC :Losse karretjes in de vorm van een muis. +STR_CPTY :4 passagiers per karretje + +[SMC2] +STR_NAME :Mijnkarretjes +STR_DESC :Losse karretjes in de vorm van een houten mijnkarretje. +STR_CPTY :4 passagiers per karretje + +[WMSPIN] +STR_NAME :Draaiende wilde muis +STR_DESC :Muisvormige karretjes rijden snel door scherpe bochten en korte afdalingen, en draaien daarbij zachtjes rond om de passagiers te desoriënteren. +STR_CPTY :4 passagiers per karretje +# End of (Steel) Wild Mouse / (Stalen) Wilde muis + +# River Rapids / Wildwaterbaan +[RAPBOAT] +STR_NAME :Wildwaterbaan +STR_DESC :Ronde boten varen door een brede waterbak, waarbij ze de passagiers opwinden door watervallen en schuimende stroomversnellingen. +STR_CPTY :8 passagiers per boot + +#TT +[OAKBAREL] +STR_NAME :Eikenvatwildwaterbaan +STR_DESC :Eikenhouten vaten varen door een brede waterbak, waarbij ze de passagiers opwinden door watervallen en schuimende stroomversnellingen. +STR_CPTY :8 passagiers per boot +# End of River Rapids / Wildwaterbaan + +# Side-Friction RC / Zijfrictieachtbaan +[SFRIC1] +STR_NAME :Houten zijfrictiekarretjes +STR_DESC :Eenvoudige karretjes voor de zijfrictieachtbaan. +STR_CPTY :4 passagiers per karretjes +# End of Side-Friction RC / Zijfrictieachtbaan + +#################################### +# Shops/stalls / Winkels/kraampjes # +#################################### + +# Food stalls +[BURGB] +STR_NAME :Hamburgerbar +STR_DESC :Een hamburgervormig gebouw dat hamburgers verkoopt. + +[COOKST] +STR_NAME :Koekwinkel +STR_DESC :Een kraam waar grote koeken worden verkocht. + +[RSAUS] +STR_NAME :Gebradenworstkraam +STR_DESC :Een kraam waar Chinese gebraden worst wordt verkocht. + +[CHKNUG] +STR_NAME :Kipnuggetskraam +STR_DESC :Een kraam waar kipnuggets worden verkocht. + +[FRNOOD] +STR_NAME :Rijstnoedelkraam +STR_DESC :Een kraam waar Chinese gebakken rijstnoedels worden verkocht. + +[BNOODLES] +STR_NAME :Rundernoedelkraam +STR_DESC :Een kraam waar Chinese rundernoedels worden verkocht. + +[CHCKS] +STR_NAME :Gebakkenkipkraam +STR_DESC :Een kraam waar bakjes gebakken kip worden verkocht. + +[HOTDS] +STR_NAME :Hotdogkraam +STR_DESC :Een kraam waar hotdogs worden verkocht. + +[PIZZS] +STR_NAME :Pizzakraam +STR_DESC :Een kraam waar stukken pizza worden verkocht. + +[SUBSTL] +STR_NAME :Broodjeskraam +STR_DESC :Een kraam waar broodjes worden verkocht. + +[ICECR1] +STR_NAME :Vruchtenijskraam +STR_DESC :Een gethematiseerde kraam waar vruchtenijs wordt verkocht. + +[ICECR2] +STR_NAME :Roomijskraam +STR_DESC :Een kraam waar roomijs wordt verkocht. + +[SQDST] +STR_NAME :Zeevruchtenkraam +STR_DESC :Een kraam waar gebakken tentakel wordt verkocht. + +[WONTON] +STR_NAME :Wantansoepkraam +STR_DESC :Een kraam waar wantansoep wordt verkocht. + +[PRETST] +STR_NAME :Krakelingenkraam +STR_DESC :Een kraam waar knapperige zoute krakelingen worden verkocht. + +[TOFFS] +STR_NAME :Kraam met gevulde appels +STR_DESC :Een appelvormige kraam waar gevulde appels op een stokje worden verkocht. + +[CHPSH] +STR_NAME :Frietkot +STR_DESC :Een kraam waar friet wordt verkocht. + +[CHPSH2] +STR_NAME :Frietkraam +STR_DESC :Een kraam waar friet wordt verkocht. + +[CNDYF] +STR_NAME :Suikerspinkraam +STR_DESC :Een suikerspinvormige kraam waar roze suikerspinnen worden verkocht. + +[MBSOUP] +STR_NAME :Soep-met-balletjeskraam +STR_DESC :Een kraam waar Chinese soep met balletjes wordt verkocht. + +[FUNCAKE] +STR_NAME :Oliebollenkraam +STR_DESC :Een kraam waar oliebollen worden verkocht. + +[DOUGH] +STR_NAME :Donutkraam +STR_DESC :Een kraam waar donuts worden verkocht. + +[POPCS] +STR_NAME :Popcornkraam +STR_DESC :Een kraam waar grote emmers popcorn worden verkocht. + +#TT +[1920SAND] +STR_NAME :Artdeco-kraam +STR_DESC :Een kraam waar noedels en frisse limonade worden verkocht. + +#TT +[MEDISOUP] +STR_NAME :Heksensoep +STR_DESC :Een kraam waar dikke gebonden soep wordt verkocht. + +#TT +[MKTSTAL1] +STR_NAME :Marktkraam met gevulde appels +STR_DESC :Een marktkraam waar gevulde appels worden verkocht. + +#TT +[MYTHOSEA] +STR_NAME :Neptunus' zeevruchtenkraam +STR_DESC :Een kraam met Neptunus' zoute lekkernijen. +# End of Food stalls + +# Drink stalls +[COFFS] +STR_NAME :Koffiewinkel +STR_DESC :Een winkel in art-decostijl waar kopjes koffie worden verkocht. + +[CINDR] +STR_NAME :Sujeonggwakraam +STR_DESC :Een kraam waar Koreaanse sujeonggwa-drankjes worden verkocht. + +[HCHOC] +STR_NAME :Warmechocolademelkkraam +STR_DESC :Een kraam waar warme chocolademelk wordt verkocht. + +[DRNKS] +STR_NAME :Frisdrankkraam +STR_DESC :Een kraam in de vorm van vier blikjes waar frisdrank wordt verkocht. + +[ICETST] +STR_NAME :IJstheekraam +STR_DESC :Een kraam waar ijsthee wordt verkocht. + +[LEMST] +STR_NAME :Limonadekraam +STR_DESC :Een kraam waar verfrissende limonade wordt verkocht. + +[SOYBEAN] +STR_NAME :Sojamelkkraam +STR_DESC :Een kraam waar pakjes sojamelk worden verkocht. + +[STARFRDR] +STR_NAME :Vruchtendrankkraam +STR_DESC :Een kraam waar vruchtendrankjes worden verkocht. + +#TT +[MKTSTAL2] +STR_NAME :Marktkraam met limonade +STR_DESC :Een marktkraam waar ouderwetse, frisse limonade wordt verkocht. + +#TT +[MOONJUCE] +STR_NAME :Maansap +STR_DESC :Een waar de nieuwste soorten frisdrank worden verkocht. +# End of Drink stalls + +# Shops +[BALLN] +STR_NAME :Ballonnenkraam +STR_DESC :Een souvenirkraam waar met helium gevulde ballonnen worden verkocht. + +[HATST] +STR_NAME :Hoedenkraam +STR_DESC :Een souvenirkraam waar grote piepschuimen hoeden worden verkocht. + +[TSHRT] +STR_NAME :T-shirtkraam +STR_DESC :Een souvenirkraam waar T-shirts worden verkocht. + +[SUNGST] +STR_NAME :Zonnebrillenkraam +STR_DESC :Een kraam waar allerlei soorten zonnebrillen worden verkocht. + +[SOUVS] +STR_NAME :Souvenirkraam +STR_DESC :Een souvenirkraam waar knuffels en paraplu's worden verkocht. + +#TT +[SOFTOYST] +STR_NAME :Knuffelkraam +STR_DESC :Een kraam waar schattige zachtige dinosaurusknuffels worden verkocht. + +#TT +[1960TSRT] +STR_NAME :'Flower Power'-t-shirtkraam +STR_DESC :Een kraam waar t-shirts met bloemmotief worden verkocht. +# End of Shops + +# Toilets +[TLT1] +STR_NAME :Toiletten +STR_DESC :Eenvoudige toiletten in een prefab betonnen gebouw. + +[TLT2] +STR_NAME :Toiletten +STR_DESC :Toiletten in een gebouw in blokhutstijl. +# End of Toilets + +# Information Kiosks +[INFOK] +STR_NAME :Informatiekiosk +STR_DESC :Een kiosk waar gasten kaarten van het park en paraplu's kunnen kopen. + +#CC +[INFO1MKY] +STR_NAME :Informatiekiosk +STR_DESC :Een kiosk waar gasten kaarten van het park en paraplu's kunnen kopen. + +# End of Information Kiosks + +# Cash Machines +[ATM1] +STR_NAME :Geldautomaat +STR_DESC :Een geldautomaat die de bezoekers kunnen gebruiken als ze bijna door hun contante geld heen zijn. +# End of Cash Machines + +# First Aid +[FAID1] +STR_NAME :Eerste hulp +STR_DESC :Een gebouw waar misselijke gasten sneller kunnen opknappen. +# End of First Aid + +################################# +# Park Entrances / Parkingangen # +################################# + +[PKENT1] +STR_NAME :Traditionele parkingang + +[PKEMM] +STR_NAME :Parkingang met ijzeren poorten + +[PKESFH] +STR_NAME :Parkingang met gebouw + +#WW +[AFRICENT] +STR_NAME :Parkingang in Afrikaanse stijl + +#WW +[EUROENT] +STR_NAME :Parkingang in Europese stijl + +#WW +[ICEENT] +STR_NAME :Parkingang in ijsstijl + +#WW +[JAPENT] +STR_NAME :Parkingang in Japanse stijl + +#WW +[NAENT] +STR_NAME :Parkingang in Noord-Amerikaanse stijl + +#WW +[OZENTRAN] +STR_NAME :Parkingang in Australische stijl + +#WW +[SAMERENT] +STR_NAME :Parkingang in Zuid-Amerikaanse stijl + +#TT +[1920SENT] +STR_NAME :Parkingang in 'Roaring Twenties'-stijl + +#TT +[FUTURENT] +STR_NAME :Futuristische parkingang + +#TT +[GLDYRENT] +STR_NAME :Parkingang in 'rock 'n' roll'-stijl + +#TT +[JURASENT] +STR_NAME :Parkingang in prehistorische stijl + +#TT +[MEDIENTR] +STR_NAME :Parkingang in middeleeuwse stijl + +#TT +[MYTHENTR] +STR_NAME :Parkingang in mythologische stijl +######### +# Water # +######### + +[WTRCYAN] +STR_NAME :Natuurlijk water + +[WTRGREEN] +STR_NAME :Gifgroen water + +[WTRGRN] +STR_NAME :Groen water + +[WTRORNG] +STR_NAME :Oranje water + +#OCC +[WTRPINK] +STR_NAME :Roze water + +################# +# Paths / Paden # +################# + +[PATHASH] +STR_NAME :Voetpad met aslaag + +[PATHCRZY] +STR_NAME :Voetpad met onregelmatig plaveisel + +[PATHDIRT] +STR_NAME :Onverhard voetpad + +[PATHSPCE] +STR_NAME :Voetpad in ruimtestijl + +[ROAD] +STR_NAME :Weg + +[TARMAC] +STR_NAME :Voetpad van asfalt + +[TARMACB] +STR_NAME :Voetpad van bruin asfalt + +[TARMACG] +STR_NAME :Voetpad van groen asfalt + +#TT +[1920PATH] +STR_NAME :Stoep + +#TT +[FUTRPAT2] +STR_NAME :Printplaat-voetpad zonder leuningen + +#TT +[FUTRPATH] +STR_NAME :Printplaat-voetpad + +#TT +[JURRPATH] +STR_NAME :Rotsachtig voetpad + +#TT +[MEDIPATH] +STR_NAME :Houten voetpad + +#TT +[MYTHPATH] +STR_NAME :Mozaiek-voetpad + +#TT +[RANBPATH] +STR_NAME :Regenboogvoetpad + +################################# +# Scenery groups / Decorgroepen # +################################# + +[SCGABSTR] +STR_NAME :Abstract thema + +[SCGCANDY] +STR_NAME :Gigantisch-snoep-thema + +[SCGCLASS] +STR_NAME :Klassiek/Romeins thema + +[SCGEGYPT] +STR_NAME :Egyptisch thema + +[SCGFENCE] +STR_NAME :Hekken en muren + +[SCGGARDN] +STR_NAME :Bloemen + +[SCGGIANT] +STR_NAME :Gigantische-tuin-thema + +[SCGHALLO] +STR_NAME :Eng thema + +[SCGINDUS] +STR_NAME :Mechanisch thema + +[SCGJUNGL] +STR_NAME :Junglethema + +[SCGJURAS] +STR_NAME :Jurassisch thema + +[SCGMART] +STR_NAME :Marsthema + +[SCGMEDIE] +STR_NAME :Middeleeuws thema + +[SCGMINE] +STR_NAME :Mijnthema + +[SCGORIEN] +STR_NAME :Pagodethema + +[SCGPATHX] +STR_NAME :Borden en onderdelen voor voetpaden + +[SCGPIRAT] +STR_NAME :Piratenthema + +[SCGSHRUB] +STR_NAME :Struiken en ornamenten + +[SCGSIXFL] +STR_NAME :Six Flags-thema + +[SCGSNOW] +STR_NAME :Sneeuw- en ijsthema + +[SCGSPACE] +STR_NAME :Ruimtethema + +[SCGSPOOK] +STR_NAME :Spookthema + +[SCGSPORT] +STR_NAME :Sportthema + +[SCGTREES] +STR_NAME :Bomen + +[SCGURBAN] +STR_NAME :Stadsthema + +[SCGWALLS] +STR_NAME :Muren en daken + +[SCGWATER] +STR_NAME :Waterthema + +[SCGWOND] +STR_NAME :Wonderlandthema + +[SCGWWEST] +STR_NAME :Wildwestthema + +#WW +[SCGAFRIC] +STR_NAME : Afrikaans thema + +#WW +[SCGARTIC] +STR_NAME : Antarcticathema + +#WW +[SCGASIA] +STR_NAME : Aziatisch thema + +#WW +[SCGAUSTR] +STR_NAME : Australisch thema + +#WW +[SCGEUROP] +STR_NAME : Europees thema + +#WW +[SCGNAMRC] +STR_NAME : Noord-Amerikaans thema + +#WW +[SCGSAMER] +STR_NAME : Zuid-Amerikaans thema + +#TT +[SCG1920S] +STR_NAME : 'Roaring Twenties'-thema + +#TT +[SCG1920W] +STR_NAME : 'Roaring Twenties'-muren + +#TT +[SCG1960S] +STR_NAME : 'Rock 'n' roll'-thema + +#TT +[SCGFUTUR] +STR_NAME : Toekomstthema + +#TT +[SCGJURRA] +STR_NAME : Prehistorisch thema + +#TT +[SCGMEDIV] +STR_NAME : 'Donkere eeuwen'-thema + +#TT +[SCGMYTHO] +STR_NAME : Mythologisch thema + +################# +# Large objects # +################# +[GLTHENT] +STR_NAME :'Goliath'-bord + +[MDSAENT] +STR_NAME :'Medusa'-bord + +[NITROENT] +STR_NAME :'Nitro'-bord + +[SHS1] +STR_NAME :Rijtjeshuis + +######### +# Walls # +######### +[WALLTXGT] +STR_NAME :'Texas Giant'-bord + +################## +# Path additions # +################## +[BENCHPL] +STR_NAME :Stadionstoeltjes + +[BENCHSTN] +STR_NAME :Stenen bank + +[JUMPSNW1] +STR_NAME :Springende sneeuwballen + +[LAMPDSY] +STR_NAME :Lamp in madeliefjesvorm + +[QTV1] +STR_NAME :Wachtrij-tv + +#TT +[MEDBENCH] +STR_NAME :Krukjes + +#OCC +[LITTERPA] +STR_NAME :Vuilnisbak in pandavorm + +########### +# Banners # +########### +[BN1] +STR_NAME :Lichtkrant + +[BN2] +STR_NAME :Lichtkrant in junglestijl + +[BN3] +STR_NAME :Lichtkrant in Romeinse stijl + +[BN4] +STR_NAME :Lichtkrant in Egyptische stijl + +[BN5] +STR_NAME :Lichtkrant in mijnstijl + +[BN6] +STR_NAME :Lichtkrant in Jurastijl + +[BN7] +STR_NAME :Lichtkrant in pagodestijl + +[BN8] +STR_NAME :Besneeuwde lichtkrant + +[BN9] +STR_NAME :Lichtkrant in ruimtestijl diff --git a/data/language/english_uk.txt b/data/language/english_uk.txt index 379cf6b46c..1c03cb38e3 100644 --- a/data/language/english_uk.txt +++ b/data/language/english_uk.txt @@ -54,7 +54,7 @@ STR_0049 :Haunted House STR_0050 :First Aid Room STR_0051 :Circus Show STR_0052 :Ghost Train -STR_0053 :Twister Roller Coaster +STR_0053 :Steel Twister Roller Coaster STR_0054 :Wooden Roller Coaster STR_0055 :Side-Friction Roller Coaster STR_0056 :Wild Mouse @@ -513,31 +513,31 @@ STR_0508 : STR_0509 : STR_0510 : STR_0511 : -STR_0512 : -STR_0513 : +STR_0512 :A compact roller coaster with a spiral lift hill and smooth, twisting drops. +STR_0513 :A looping roller coaster where the riders ride in a standing position STR_0514 :Trains suspended beneath the roller coaster track swing out to the side around corners -STR_0515 : +STR_0515 :A steel roller coaster with trains that are held beneath the track, with many complex and twisting track elements STR_0516 :A gentle roller coaster for people who haven't yet got the courage to face the larger rides STR_0517 :Passengers ride in miniature trains along a narrow-gauge railway track STR_0518 :Passengers travel in electric trains along a monorail track STR_0519 :Passengers ride in small cars hanging beneath the single-rail track, swinging freely from side to side around corners -STR_0520 : -STR_0521 : -STR_0522 : +STR_0520 :A dock platform where guests can drive/row personal watercraft on a body of water +STR_0521 :A fast and twisting roller coaster with tight turns and steep drops. Intensity is bound to be high. +STR_0522 :A smaller roller coaster where the riders sit above the track with no car around them STR_0523 :Riders travel slowly in powered vehicles along a track-based route -STR_0524 : -STR_0525 : -STR_0526 : +STR_0524 :Freefall car is pneumatically launched up a tall steel tower and then allowed to freefall down +STR_0525 :Riders career down a twisting track guided only by the curvature and banking of the semi-circular track +STR_0526 :Passengers travel in a rotating observation cabin which travels up a tall tower STR_0527 :A smooth steel-tracked roller coaster capable of vertical loops -STR_0528 : -STR_0529 : +STR_0528 :Riders travel in inflatable dinghies down a twisting semi-circular or completely enclosed tube track +STR_0529 :Mine train themed roller coaster trains career along steel roller coaster track made to look like old railway track STR_0530 :Cars hang from a steel cable which runs continuously from one end of the ride to the other and back again -STR_0531 : +STR_0531 :A compact steel-tracked roller coaster where the train travels through corkscrews and loops STR_0532 : STR_0533 : -STR_0534 : -STR_0535 : -STR_0536 : +STR_0534 :Self-drive petrol-engined go karts +STR_0535 :Log-shaped boats travel along a water channel, splashing down steep slopes to soak the riders +STR_0536 :Circular boats meander along a wide water channel, splashing through waterfalls and thrilling riders through foaming rapids STR_0537 : STR_0538 : STR_0539 : @@ -556,14 +556,14 @@ STR_0551 : STR_0552 : STR_0553 : STR_0554 :The car is accelerated out of the station along a long level track using Linear Induction Motors, then heads straight up a vertical spike of track, freefalling back down to return to the station -STR_0555 : -STR_0556 : +STR_0555 :Guests ride in an elevator up or down a vertical tower to get from one level to another +STR_0556 :Extra-wide cars descend completely vertical sloped track for the ultimate freefall roller coaster experience STR_0557 : STR_0558 : STR_0559 : STR_0560 : STR_0561 : -STR_0562 : +STR_0562 :Powered cars travel along a multi-level track past spooky scenery and special effects STR_0563 :Sitting in comfortable trains with only simple lap restraints riders enjoy giant smooth drops and twisting track as well as plenty of 'air time' over the hills STR_0564 :Running on wooden track, this coaster is fast, rough, noisy, and gives an 'out of control' riding experience with plenty of 'air time' STR_0565 :A simple wooden roller coaster capable of only gentle slopes and turns, where the cars are only kept on the track by side friction wheels and gravity @@ -572,38 +572,38 @@ STR_0567 :Sitting in seats suspended either side of the track, riders are pit STR_0568 : STR_0569 :Riding in special harnesses below the track, riders experience the feeling of flight as they swoop through the air STR_0570 : -STR_0571 : -STR_0572 : -STR_0573 : -STR_0574 : +STR_0571 :Circular cars spin around as they travel along the zig-zagging wooden track +STR_0572 :Large capacity boats travel along a wide water channel, propelled up slopes by a conveyer belt, accelerating down steep slopes to soak the riders with a gaint splash +STR_0573 :Powered helicoper shaped cars running on a steel track, controlled by the pedalling of the riders +STR_0574 :Riders are held in special harnesses in a lying-down position, travlling through twisted track and inversions either on their backs or facing the ground STR_0575 :Powered trains hanging from a single rail transport people around the park STR_0576 : -STR_0577 : +STR_0577 :Bogied cars run on wooden tracks, turning around on special reversing sections STR_0578 :Cars run along track enclosed by circular hoops, traversing steep drops and heartline twists STR_0579 : -STR_0580 : -STR_0581 : +STR_0580 :A giant steel roller coaster capable of smooth drops and hills of over 300ft +STR_0581 :A ring of seats is pulled to the top of a tall tower while gently rotating, then allowed to free-fall down, stopping gently at the bottom using magnetic brakes STR_0582 : STR_0583 : -STR_0584 : -STR_0585 : +STR_0584 :Special bicycles run on a steel monorail track, propelled by the pedalling of the riders +STR_0585 :Riders sit in pairs of seats suspended beneath the track as they loop and twist through tight inversions STR_0586 :Boat shaped cars run on roller coaster track to allow twisting curves and steep drops, splashing down into sections of water for gentle river sections -STR_0587 : -STR_0588 : +STR_0587 :After an exhilarating air-powered launch, the train speeds up a vertical track, over the top, and vertically down the other side to return to the station +STR_0588 :Individual cars run beneath a zig-zagging track with hairpin turns and sharp drops STR_0589 : -STR_0590 : -STR_0591 : +STR_0590 :Riders ride in a submerged submarine through an underwater course +STR_0591 :Raft-shaped boats gently meander around a river track STR_0592 : STR_0593 : STR_0594 : STR_0595 : STR_0596 : STR_0597 : -STR_0598 : +STR_0598 :Inverted roller coaster trains are accelerated out of the station to travel up a vertical spike of track, then reverse back through the station to travel backwards up another vertical spike of track STR_0599 :A compact roller coaster with individual cars and smooth twisting drops -STR_0600 : +STR_0600 :Powered mine trains career along a smooth and twisted track layout STR_0601 : -STR_0602 : +STR_0602 :Roller coaster trains are accelerated out of the station by linear induction motors to speed through twisting inversions STR_0603 :Guest {INT32} STR_0604 :Guest {INT32} STR_0605 :Guest {INT32} @@ -836,19 +836,20 @@ STR_0831 :{SMALLFONT}{BLACK}Zoom view out STR_0832 :{SMALLFONT}{BLACK}Rotate view 90{DEGREE} clockwise STR_0833 :{SMALLFONT}{BLACK}Pause game STR_0834 :{SMALLFONT}{BLACK}Disk and game options -STR_0835 :Game initialization failed +STR_0835 :Game initialisation failed STR_0836 :Unable to start game in a minimised state STR_0837 :Unable to initialise 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_0838 : STR_0839 :{UINT16} x {UINT16} STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} -STR_0841 :Desktop window -STR_0842 :640x480 full screen -STR_0843 :800x600 full screen -STR_0844 :1024x768 full screen -STR_0845 :1152x864 full screen -STR_0846 :1280x1024 full screen -STR_0847 :About 'RollerCoaster Tycoon 2' +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +STR_0847 :About 'OpenRCT2' STR_0848 :RollerCoaster Tycoon 2 STR_0849 :{WINDOW_COLOUR_2}Version 2.01.028 STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, all rights reserved @@ -1044,10 +1045,10 @@ 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_1043 :OpenRCT2 Saved Game +STR_1044 :OpenRCT2 Scenario File +STR_1045 :OpenRCT2 Landscape File +STR_1046 :OpenRCT2 Track Design File STR_1047 :Game save failed! STR_1048 :Scenario save failed! STR_1049 :Landscape save failed! @@ -1781,7 +1782,7 @@ STR_1776 :On 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 +STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tiger costume STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} Elephant costume STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} Roman costume STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} Gorilla costume @@ -1893,8 +1894,10 @@ STR_1888 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}more than 4 hou STR_1889 :{WINDOW_COLOUR_2}Down-Time: {MOVE_X}{255}{BLACK}{COMMA16}% STR_1890 :{SMALLFONT}{BLACK}Select how often a mechanic should check this ride STR_1891 :No {STRINGID} in park yet! -STR_1892 :RollerCoaster Tycoon 2 -STR_1893 :Please insert your RollerCoaster Tycoon 2 CD in the following drive: +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 : +STR_1893 : STR_1894 :{WINDOW_COLOUR_2}{STRINGID} sold: {BLACK}{COMMA32} STR_1895 :{SMALLFONT}{BLACK}Build new ride/attraction STR_1896 :{WINDOW_COLOUR_2}Expenditure/Income @@ -2218,7 +2221,7 @@ STR_2213 :{SMALLFONT}{BLACK}Show list of entertainers in park STR_2214 :Construction not possible while game is paused! STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C -STR_2217 :{WINDOW_COLOUR_2}{COMMA16}F +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F STR_2218 :{RED}{STRINGID} on {STRINGID} hasn't returned to the {STRINGID} yet!{NEWLINE}Check whether it is stuck or has stalled STR_2219 :{RED}{COMMA16} people have died in an accident on {STRINGID} STR_2220 :{WINDOW_COLOUR_2}Park Rating: {BLACK}{COMMA16} @@ -2291,7 +2294,7 @@ STR_2286 :Designing STR_2287 :Completing design STR_2288 :Unknown STR_2289 :{STRINGID} {STRINGID} -STR_2290 :{SMALLFONT}{BLACK}{STRINGID} {STRINGID} +STR_2290 : STR_2291 :Select scenario for new game STR_2292 :{WINDOW_COLOUR_2}Rides been on: STR_2293 :{BLACK} Nothing @@ -2318,10 +2321,10 @@ STR_2313 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}{COMMA2DP32} (approx.) STR_2314 :{WINDOW_COLOUR_2}Ride length: {BLACK}{STRINGID} STR_2315 :{WINDOW_COLOUR_2}Cost: {BLACK}around {CURRENCY} STR_2316 :{WINDOW_COLOUR_2}Space required: {BLACK}{COMMA16} x {COMMA16} blocks -STR_2317 :{WINDOW_COLOUR_2}Sound Quality: -STR_2318 :Low -STR_2319 :Medium -STR_2320 :High +STR_2317 : +STR_2318 : +STR_2319 : +STR_2320 : STR_2321 :{WINDOW_COLOUR_2}Number of rides/attractions: {BLACK}{COMMA16} STR_2322 :{WINDOW_COLOUR_2}Staff: {BLACK}{COMMA16} STR_2323 :{WINDOW_COLOUR_2}Park size: {BLACK}{COMMA32}m{SQUARED} @@ -2368,7 +2371,7 @@ STR_2363 :Gridlines on Landscape STR_2364 :{SMALLFONT}{BLACK}Toggle gridlines on landscape on/off STR_2365 :The bank refuses to increase your loan! STR_2366 :Celsius ({DEGREE}C) -STR_2367 :Fahrenheit (F) +STR_2367 :Fahrenheit ({DEGREE}F) STR_2368 :None STR_2369 :Low STR_2370 :Average @@ -2438,12 +2441,12 @@ 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_2437 : +STR_2438 : +STR_2439 : +STR_2440 : +STR_2441 : +STR_2442 : 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 @@ -2500,7 +2503,7 @@ STR_2495 :Cancel construction mode STR_2496 :Pause game STR_2497 :Zoom view out STR_2498 :Zoom view in -STR_2499 :Rotate view +STR_2499 :Rotate view clockwise STR_2500 :Rotate construction object STR_2501 :Underground view toggle STR_2502 :Remove base land toggle @@ -2683,10 +2686,10 @@ 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_2681 :{MEDIUMFONT}{BLACK}Increases your money by {CURRENCY} +STR_2682 : +STR_2683 : +STR_2684 :{SMALLFONT}{BLACK}Large group of peeps arrive STR_2685 :Simplex Noise Parameters STR_2686 :{WINDOW_COLOUR_2}Low: STR_2687 :{WINDOW_COLOUR_2}High: @@ -2703,13 +2706,13 @@ 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_2701 :Every minute +STR_2702 :Every 5 minutes +STR_2703 :Every 15 minutes +STR_2704 :Every 30 minutes +STR_2705 :Every hour STR_2706 :Never -STR_2707 :Open new window +STR_2707 :Use system dialog 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. @@ -2720,8 +2723,8 @@ STR_2714 :- STR_2715 :. STR_2716 :/ STR_2717 :' -STR_2718 :(up) -STR_2719 :(new file) +STR_2718 :Up +STR_2719 :New file STR_2720 :{UINT16}sec STR_2721 :{UINT16}secs STR_2722 :{UINT16}min:{UINT16}sec @@ -2763,11 +2766,11 @@ 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_2760 :+{CURRENCY} +STR_2761 : +STR_2762 : STR_2763 :??? -STR_2764 :Happy Guests +STR_2764 : STR_2765 :Large Tram STR_2766 :Win scenario STR_2767 :Freeze Climate @@ -2785,7 +2788,7 @@ STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} STR_2779 :Viewport #{COMMA16} STR_2780 :Extra viewport # End of new strings -STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} STR_2782 :SHIFT + STR_2783 :CTRL + STR_2784 :Change keyboard shortcut @@ -2810,9 +2813,9 @@ STR_2802 :Map 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 -STR_2806 :{RED}Guests are complaining about the disgusting state of the paths in your park{NEWLINE}Check where your handymen are and consider organizing them better -STR_2807 :{RED}Guests are complaining about the amount of litter in your park{NEWLINE}Check where your handymen are and consider organizing them better -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_2806 :{RED}Guests are complaining about the disgusting state of the paths in your park{NEWLINE}Check where your handymen are and consider organising them better +STR_2807 :{RED}Guests are complaining about the amount of litter in your park{NEWLINE}Check where your handymen are and consider organising them better +STR_2808 :{RED}Guests are complaining about the vandalism in your park{NEWLINE}Check where your security guards are and consider organising 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 toilets in your park @@ -2863,7 +2866,7 @@ STR_2855 :{RED}{STRINGID} has no path leading from its exit !{NEWLINE}Constru STR_2856 :{WINDOW_COLOUR_2}Tutorial STR_2857 :{WINDOW_COLOUR_2}(Press a key or mouse button to take control) STR_2858 :Can't start marketing campaign... -STR_2859 :Another instance of RollerCoaster Tycoon 2 is already running +STR_2859 :Another instance of OpenRCT2 is already running STR_2860 :Infogrames Interactive credits... STR_2861 :{WINDOW_COLOUR_2}Licensed to Infogrames Interactive Inc. STR_2862 :Music acknowledgements... @@ -2973,8 +2976,8 @@ STR_2965 :{WINDOW_COLOUR_2} STR_2966 : STR_2967 : STR_2968 : -STR_2969 :Use of this product is subject to the terms of a licence agreement -STR_2970 :found in the product's {OPENQUOTES}ReadMe{ENDQUOTES} file and in the manual +STR_2969 : +STR_2970 : STR_2971 :Main colour scheme STR_2972 :Alternative colour scheme 1 STR_2973 :Alternative colour scheme 2 @@ -3164,8 +3167,8 @@ STR_3156 : STR_3157 :map STR_3158 :graph STR_3159 :list -STR_3160 :RollerCoaster Tycoon 2: Starting for the first time... -STR_3161 :RollerCoaster Tycoon 2: Checking object files... +STR_3160 : +STR_3161 : STR_3162 :Unable to allocate enough memory STR_3163 :Installing new data: STR_3164 :{BLACK}{COMMA16} selected (maximum {COMMA16}) @@ -3176,7 +3179,7 @@ STR_3168 :{WINDOW_COLOUR_2}Text: {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 -STR_3172 :The following object must be selected first: +STR_3172 :The following object must be selected first: {STRING} STR_3173 :This object is currently in use STR_3174 :This object is required by another object STR_3175 :This object is always required @@ -3341,7 +3344,7 @@ 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_3337 : 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 @@ -3366,8 +3369,8 @@ 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_3362 : +STR_3363 : STR_3364 :Advanced STR_3365 :{SMALLFONT}{BLACK}Allow selection of individual items of scenery in addition to scenery groups STR_3366 :{BLACK}= Ride @@ -3395,6 +3398,7 @@ STR_3387 :Roller Coaster Building Tutorial STR_3388 :Unable to switch to selected mode STR_3389 :Unable to select additional item of scenery... STR_3390 :Too many items selected +# Start of tutorial strings. Not used at the moment, so not necessary to translate. STR_3391 :{SMALLFONT}{BLACK}Here is our park - Let's have a quick look around... STR_3392 :{SMALLFONT}{BLACK}Holding down the RIGHT mouse button and moving the mouse is the quickest way to move the view... STR_3393 :{SMALLFONT}{BLACK}To view more of the park, you can zoom the view out using the icon at the top of the screen... @@ -3441,6 +3445,7 @@ STR_3433 :{SMALLFONT}{BLACK}And finally we'll add 'block brakes', which allow 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 customise the ride a bit... +# End of tutorial strings STR_3437 :{SMALLFONT}{BLACK}Clear large areas of scenery from landscape STR_3438 :Unable to remove all scenery from here... STR_3439 :Clear Scenery @@ -3453,11 +3458,11 @@ 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_5120 :Finances +STR_5121 :Research +STR_5122 :Select rides by track type (like in RCT1) STR_5123 :Renew rides -STR_5124 :No Six Flags +STR_5124 : STR_5125 :All destructable STR_5126 :Random title music STR_5127 :{SMALLFONT}{BLACK}Disable land elevation @@ -3480,9 +3485,9 @@ STR_5143 :Quick Speed STR_5144 :Fast Speed STR_5145 :Turbo Speed STR_5146 :Hyper Speed -STR_5147 :Show cheats button on toolbar +STR_5147 :Cheats STR_5148 :{SMALLFONT}{BLACK}Change the game speed -STR_5149 :{SMALLFONT}{BLACK}Open the cheats window +STR_5149 :{SMALLFONT}{BLACK}Show cheat options STR_5150 :Enable debugging tools STR_5151 :, STR_5152 :. @@ -3493,7 +3498,7 @@ STR_5156 :{SMALLFONT}{BLACK}Allows testing of most ride types even when the t STR_5157 :Unlock all prices STR_5158 :Quit to menu STR_5159 :Exit OpenRCT2 -STR_5160 :{MONTH} {STRINGID}, Year {COMMA16} +STR_5160 :{POP16}{MONTH} {PUSH16}{PUSH16}{STRINGID}, Year {POP16}{COMMA16} STR_5161 :Date Format: STR_5162 :Day/Month/Year STR_5163 :Month/Day/Year @@ -3587,8 +3592,8 @@ 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_5254 :Create +STR_5255 :{SMALLFONT}{BLACK}Create a new title sequence from scratch 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 @@ -3602,7 +3607,7 @@ 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_5269 :{SMALLFONT}{BLACK}Controls and interface STR_5270 :{SMALLFONT}{BLACK}Miscellaneous STR_5271 :{SMALLFONT}{BLACK}Twitch STR_5272 :{SMALLFONT}{BLACK}Small Scenery @@ -3619,7 +3624,7 @@ 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_5286 :{SMALLFONT}{BLACK}Makes some guests explode STR_5287 :Ride is already broken down STR_5288 :Ride is closed STR_5289 :No breakdowns available for this ride @@ -3680,6 +3685,247 @@ 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 +STR_5347 :Park cheats +STR_5348 :Ride cheats +STR_5349 :{SMALLFONT}{BLACK}All Rides +STR_5350 :Max +STR_5351 :Min +STR_5352 :{BLACK}Happiness: +STR_5353 :{BLACK}Energy: +STR_5354 :{BLACK}Hunger: +STR_5355 :{BLACK}Thirst: +STR_5356 :{BLACK}Nausea: +STR_5357 :{BLACK}Nausea tolerance: +STR_5358 :{BLACK}Bathroom: +STR_5359 :Remove guests +STR_5360 :{SMALLFONT}{BLACK}Removes all guests from the map +STR_5361 :Give all guests: +STR_5362 :{BLACK}Set all guests' preferred ride intensity to: +STR_5363 :More than 1 +STR_5364 :Less than 15 +STR_5365 :{BLACK}Staff speed: +STR_5366 :Normal +STR_5367 :Fast +STR_5368 :Reset crash status +STR_5369 :Park parameters... +STR_5370 :{SMALLFONT}{BLACK}Click this button to modify park{NEWLINE}parameters like restrictions,{NEWLINE}guest generation and money. +STR_5371 :Object Selection +STR_5372 :Invert right mouse dragging +STR_5373 :Name {STRINGID} +STR_5374 :Date {STRINGID} +STR_5375 :{UP} +STR_5376 :{DOWN} +STR_5377 :{SMALLFONT}{BLACK}Saves +STR_5378 :{SMALLFONT}{BLACK}Script +STR_5379 :{SMALLFONT}{BLACK}Skip to next wait command +STR_5380 :{SMALLFONT}{BLACK}Start playing title sequence +STR_5381 :{SMALLFONT}{BLACK}Stop playing title sequence +STR_5382 :{SMALLFONT}{BLACK}Restart title sequence +STR_5383 :{SMALLFONT}{BLACK}Create a new title sequence based on the current one +STR_5384 :{SMALLFONT}{BLACK}Delete the current title sequence +STR_5385 :{SMALLFONT}{BLACK}Rename the current title sequence +STR_5386 :{SMALLFONT}{BLACK}Insert a new command +STR_5387 :{SMALLFONT}{BLACK}Edit the selected command +STR_5388 :{SMALLFONT}{BLACK}Delete the selected command +STR_5389 :{SMALLFONT}{BLACK}Skip to the selected command in the title sequence +STR_5390 :{SMALLFONT}{BLACK}Move the selected command down +STR_5391 :{SMALLFONT}{BLACK}Move the selected command up +STR_5392 :{SMALLFONT}{BLACK}Add a save to the title sequence +STR_5393 :{SMALLFONT}{BLACK}Remove the selected save from the title sequence +STR_5394 :{SMALLFONT}{BLACK}Rename the selected save +STR_5395 :{SMALLFONT}{BLACK}Load the selected save in game +STR_5396 :{SMALLFONT}{BLACK}Reload the title sequence if changes have been made to it outside of the game +STR_5397 :Can only be used on the title screen +STR_5398 :Cannot edit title sequence while it's playing +STR_5399 :Press the stop button to continue editing +STR_5400 :Can't change this title sequence +STR_5401 :Create a new title sequence to make changes to +STR_5402 :Failed to load title sequence +STR_5403 :There may be no Load or Wait command or a save may be invalid +STR_5404 :Name already exists +STR_5405 :Enter a name for the save +STR_5406 :Enter a name for the title sequence +STR_5407 :Add +STR_5408 :Remove +STR_5409 :Insert +STR_5410 :Edit +STR_5411 :Reload +STR_5412 :Skip to +STR_5413 :Load +STR_5414 :Load{MOVE_X}{87}Six Flags Magic Mountain.SC6 +STR_5415 :Load{MOVE_X}{87}{STRING} +STR_5416 :Load{MOVE_X}{87}No save selected +STR_5417 :Location +STR_5418 :Location{MOVE_X}{87}{COMMA16} {COMMA16} +STR_5419 :Rotate +STR_5420 :Rotate{MOVE_X}{87}{COMMA16} +STR_5421 :Zoom +STR_5422 :Zoom{MOVE_X}{87}{COMMA16} +STR_5423 :Wait +STR_5424 :Wait{MOVE_X}{87}{COMMA16} +STR_5425 :Restart +STR_5426 :End +STR_5427 :Coordinates: +STR_5428 :Anticlockwise rotations: +STR_5429 :Zoom level: +STR_5430 :Seconds to wait: +STR_5431 :Save to load: +STR_5432 :Command: +STR_5433 :Title Sequences +STR_5434 :Command Editor +STR_5435 :Rename save +STR_5436 :Edit Title Sequences... +STR_5437 :No save selected +STR_5438 :Can't make changes while command editor is open +STR_5439 :A wait command with at least 4 seconds is required with a restart command +STR_5440 :Minimise fullscreen on focus loss +STR_5441 :{SMALLFONT}{BLACK}Identifies rides by track type,{NEWLINE}so vehicles can be changed{NEWLINE}afterwards, like in RCT1. +STR_5442 :Force park rating: +STR_5443 :Speed{MOVE_X}{87}{STRINGID} +STR_5444 :Speed: +STR_5445 :Speed +STR_5446 :Get +STR_5447 :Type {STRINGID} +STR_5448 :Ride / Vehicle {STRINGID} +STR_5449 :Reduce game speed +STR_5450 :Increase game speed +STR_5451 :Open cheats window +STR_5452 :Toggle visibility of toolbars +STR_5453 :Select another ride +STR_5454 :Uncap FPS +STR_5455 :Enable sandbox mode +STR_5456 :Disable clearance checks +STR_5457 :Disable support limits +STR_5458 :Rotate clockwise +STR_5459 :Rotate anti-clockwise +STR_5460 :Rotate view anti-clockwise +STR_5461 :Set guests' parameters +STR_5462 :{CURRENCY} +STR_5463 :Goal: Have fun! +STR_5464 :General +STR_5465 :Climate +STR_5466 :Staff +STR_5467 :ALT + +STR_5468 :Recent messages +STR_5469 :Scroll map up +STR_5470 :Scroll map left +STR_5471 :Scroll map down +STR_5472 :Scroll map right +STR_5473 :Cycle day / night +STR_5474 :Display text on banners in upper case +STR_5475 :{COMMA16} weeks +STR_5476 :Hardware +STR_5477 :Map rendering +STR_5478 :Controls +STR_5479 :Toolbar +STR_5480 :Show toolbar buttons for: +STR_5481 :Themes +STR_5482 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}1 minute +STR_5483 :{BLACK}({COMMA16} weeks remaining) +STR_5484 :{BLACK}({COMMA16} week remaining) +STR_5485 :{SMALLFONT}{STRING} +STR_5486 :{BLACK}{COMMA16} +STR_5487 :{SMALLFONT}{BLACK}Show recent messages +STR_5488 :No entrance (OpenRCT2 only!) +STR_5489 :{SMALLFONT}{BLACK}Show only tracked guests +STR_5490 :Disable audio on focus loss +STR_5491 :Inventions list +STR_5492 :Scenario options +STR_5493 :Send Message +STR_5494 : +STR_5495 :Player List +STR_5496 :Player: +STR_5497 :Ping: +STR_5498 :Server List +STR_5499 :Player Name: +STR_5500 :Add Server +STR_5501 :Start Server +STR_5502 :Multiplayer +STR_5503 :Enter hostname or IP address: +STR_5504 :{SMALLFONT}{BLACK}Show multiplayer status +STR_5505 :Unable to connect to server. +STR_5506 :Guests ignore intensities +STR_5507 :Handymen mow grass by default +STR_5508 :Allow loading files with incorrect checksums +STR_5509 :{SMALLFONT}{BLACK}Allows loading scenarios and saves that have an incorrect checksum, like the scenarios from the demo or damaged saves. +STR_5510 :Default sound device +STR_5511 :(UNKNOWN) +STR_5512 :Save Game As +STR_5513 :(Quick) save game +STR_5514 :Disable vandalism +STR_5515 :{SMALLFONT}{BLACK}Stops guests from vandalising your park when they're angry +STR_5516 :{SMALLFONT}{BLACK}Black +STR_5517 :{SMALLFONT}{BLACK}Grey +STR_5518 :{SMALLFONT}{BLACK}White +STR_5519 :{SMALLFONT}{BLACK}Dark purple +STR_5520 :{SMALLFONT}{BLACK}Light purple +STR_5521 :{SMALLFONT}{BLACK}Bright purple +STR_5522 :{SMALLFONT}{BLACK}Dark blue +STR_5523 :{SMALLFONT}{BLACK}Light blue +STR_5524 :{SMALLFONT}{BLACK}Icy blue +STR_5525 :{SMALLFONT}{BLACK}Dark water +STR_5526 :{SMALLFONT}{BLACK}Light water +STR_5527 :{SMALLFONT}{BLACK}Saturated green +STR_5528 :{SMALLFONT}{BLACK}Dark green +STR_5529 :{SMALLFONT}{BLACK}Moss green +STR_5530 :{SMALLFONT}{BLACK}Bright green +STR_5531 :{SMALLFONT}{BLACK}Olive green +STR_5532 :{SMALLFONT}{BLACK}Dark olive green +STR_5533 :{SMALLFONT}{BLACK}Bright yellow +STR_5534 :{SMALLFONT}{BLACK}Yellow +STR_5535 :{SMALLFONT}{BLACK}Dark yellow +STR_5536 :{SMALLFONT}{BLACK}Light orange +STR_5537 :{SMALLFONT}{BLACK}Dark orange +STR_5538 :{SMALLFONT}{BLACK}Light brown +STR_5539 :{SMALLFONT}{BLACK}Saturated brown +STR_5540 :{SMALLFONT}{BLACK}Dark brown +STR_5541 :{SMALLFONT}{BLACK}Salmon pink +STR_5542 :{SMALLFONT}{BLACK}Bordeaux red +STR_5543 :{SMALLFONT}{BLACK}Saturated red +STR_5544 :{SMALLFONT}{BLACK}Bright red +STR_5545 :{SMALLFONT}{BLACK}Dark pink +STR_5546 :{SMALLFONT}{BLACK}Bright pink +STR_5547 :{SMALLFONT}{BLACK}Light pink +STR_5548 :Show all operating modes +STR_5549 :Year/Month/Day +STR_5550 :{POP16}{POP16}Year {COMMA16}, {PUSH16}{PUSH16}{MONTH} {PUSH16}{PUSH16}{STRINGID} +STR_5551 :Year/Day/Month +STR_5552 :{POP16}{POP16}Year {COMMA16}, {PUSH16}{PUSH16}{PUSH16}{STRINGID} {MONTH} +STR_5553 :Pause game when Steam overlay is open +STR_5554 :{SMALLFONT}{BLACK}Enable mountain tool +STR_5555 :Show vehicles from other track types +STR_5556 :Kick Player +STR_5557 :Stay connected after desynchronisation (Multiplayer) +STR_5558 :A restart is required for this setting to take effect +STR_5559 :10 min. inspections +STR_5560 :{SMALLFONT}{BLACK}Sets the inspection time to 'Every 10 minutes' on all rides +STR_5561 :Failed to load language +STR_5562 :WARNING! +STR_5563 :This feature is currently unstable, take extra caution. +STR_5564 :Insert Corrupt Element +STR_5565 :{SMALLFONT}{BLACK}Inserts a corrupt map element at top of tile. This will hide any element above the corrupt element. +STR_5566 :Password: +STR_5567 :Advertise +STR_5568 :Password Required +STR_5569 :This server requires a password +STR_5570 :Fetch Servers +STR_5571 :Join Game +STR_5572 :Add To Favourites +STR_5573 :Remove From Favourites +STR_5574 :Server Name: +STR_5575 :Max Players: +STR_5576 :Port: +STR_5577 :South Korean Won (W) +STR_5578 :Russian Rouble (R) +STR_5579 :Window scale factor: +STR_5580 :Czech koruna (Kc) + +##################### +# Rides/attractions # +##################### + +#WW +[CONDORRD] +STR_NAME :Condor Ride +STR_DESC :Riding in special harnesses below the track, riders experience the feeling of flight as they swoop through the air in Condor-shaped trains +STR_CPTY :4 passengers per car diff --git a/data/language/english_us.txt b/data/language/english_us.txt index f5ecc67ee3..5e25bea092 100644 --- a/data/language/english_us.txt +++ b/data/language/english_us.txt @@ -54,7 +54,7 @@ STR_0049 :Haunted House STR_0050 :First Aid Room STR_0051 :Circus Show STR_0052 :Tunnel Of Horror -STR_0053 :Twister Roller Coaster +STR_0053 :Steel Twister Roller Coaster STR_0054 :Wooden Roller Coaster STR_0055 :Side-Friction Roller Coaster STR_0056 :Wild Mouse @@ -513,31 +513,31 @@ STR_0508 : STR_0509 : STR_0510 : STR_0511 : -STR_0512 : -STR_0513 : +STR_0512 :A compact roller coaster with a spiral lift hill and smooth, twisting drops. +STR_0513 :A looping roller coaster where the riders ride in a standing position STR_0514 :Trains suspended beneath the roller coaster track swing out to the side around corners -STR_0515 : +STR_0515 :A steel roller coaster with trains that are held beneath the track, with many complex and twisting track elements STR_0516 :A gentle roller coaster for people who haven't yet got the courage to face the larger rides STR_0517 :Passengers ride in miniature trains along a narrow-gauge railway track STR_0518 :Passengers travel in electric trains along a monorail track STR_0519 :Passengers ride in small cars hanging beneath the single-rail track, swinging freely from side to side around corners -STR_0520 : -STR_0521 : -STR_0522 : +STR_0520 :A dock platform where guests can drive/row personal watercraft on a body of water +STR_0521 :A fast and twisting roller coaster with tight turns and steep drops. Intensity is bound to be high. +STR_0522 :A smaller roller coaster where the riders sit above the track with no car around them STR_0523 :Riders travel slowly in powered vehicles along a track-based route -STR_0524 : -STR_0525 : -STR_0526 : +STR_0524 :Freefall car is pneumatically launched up a tall steel tower and then allowed to freefall down +STR_0525 :Riders career down a twisting track guided only by the curvature and banking of the semi-circular track +STR_0526 :Passengers travel in a rotating observation cabin which travels up a tall tower STR_0527 :A smooth steel-tracked roller coaster capable of vertical loops -STR_0528 : -STR_0529 : +STR_0528 :Riders travel in inflatable dinghies down a twisting semi-circular or completely enclosed tube track +STR_0529 :Mine train themed roller coaster trains career along steel roller coaster track made to look like old railway track STR_0530 :Cars hang from a steel cable which runs continuously from one end of the ride to the other and back again -STR_0531 : +STR_0531 :A compact steel-tracked roller coaster where the train travels through corkscrews and loops STR_0532 : STR_0533 : -STR_0534 : -STR_0535 : -STR_0536 : +STR_0534 :Self-drive petrol-engined go karts +STR_0535 :Log-shaped boats travel along a water channel, splashing down steep slopes to soak the riders +STR_0536 :Circular boats meander along a wide water channel, splashing through waterfalls and thrilling riders through foaming rapids STR_0537 : STR_0538 : STR_0539 : @@ -556,14 +556,14 @@ STR_0551 : STR_0552 : STR_0553 : STR_0554 :The car is accelerated out of the station along a long level track using Linear Induction Motors, then heads straight up a vertical spike of track, freefalling back down to return to the station -STR_0555 : -STR_0556 : +STR_0555 :Guests ride in an elevator up or down a vertical tower to get from one level to another +STR_0556 :Extra-wide cars descend completely vertical sloped track for the ultimate freefall roller coaster experience STR_0557 : STR_0558 : STR_0559 : STR_0560 : STR_0561 : -STR_0562 : +STR_0562 :Powered cars travel along a multi-level track past spooky scenery and special effects STR_0563 :Sitting in comfortable trains with only simple lap restraints riders enjoy giant smooth drops and twisting track as well as plenty of 'air time' over the hills STR_0564 :Running on wooden track, this coaster is fast, rough, noisy, and gives an 'out of control' riding experience with plenty of 'air time' STR_0565 :A simple wooden roller coaster capable of only gentle slopes and turns, where the cars are only kept on the track by side friction wheels and gravity @@ -572,38 +572,38 @@ STR_0567 :Sitting in seats suspended either side of the track, riders are pit STR_0568 : STR_0569 :Riding in special harnesses below the track, riders experience the feeling of flight as they swoop through the air STR_0570 : -STR_0571 : -STR_0572 : -STR_0573 : -STR_0574 : +STR_0571 :Circular cars spin around as they travel along the zig-zagging wooden track +STR_0572 :Large capacity boats travel along a wide water channel, propelled up slopes by a conveyer belt, accelerating down steep slopes to soak the riders with a gaint splash +STR_0573 :Powered helicoper shaped cars running on a steel track, controlled by the pedalling of the riders +STR_0574 :Riders are held in special harnesses in a lying-down position, travlling through twisted track and inversions either on their backs or facing the ground STR_0575 :Powered trains hanging from a single rail transport people around the park STR_0576 : -STR_0577 : +STR_0577 :Bogied cars run on wooden tracks, turning around on special reversing sections STR_0578 :Cars run along track enclosed by circular hoops, traversing steep drops and heartline twists STR_0579 : -STR_0580 : -STR_0581 : +STR_0580 :A giant steel roller coaster capable of smooth drops and hills of over 300ft +STR_0581 :A ring of seats is pulled to the top of a tall tower while gently rotating, then allowed to free-fall down, stopping gently at the bottom using magnetic brakes STR_0582 : STR_0583 : -STR_0584 : -STR_0585 : +STR_0584 :Special bicycles run on a steel monorail track, propelled by the pedalling of the riders +STR_0585 :Riders sit in pairs of seats suspended beneath the track as they loop and twist through tight inversions STR_0586 :Boat shaped cars run on roller coaster track to allow twisting curves and steep drops, splashing down into sections of water for gentle river sections -STR_0587 : -STR_0588 : +STR_0587 :After an exhilarating air-powered launch, the train speeds up a vertical track, over the top, and vertically down the other side to return to the station +STR_0588 :Individual cars run beneath a zig-zagging track with hairpin turns and sharp drops STR_0589 : -STR_0590 : -STR_0591 : +STR_0590 :Riders ride in a submerged submarine through an underwater course +STR_0591 :Raft-shaped boats gently meander around a river track STR_0592 : STR_0593 : STR_0594 : STR_0595 : STR_0596 : STR_0597 : -STR_0598 : +STR_0598 :Inverted roller coaster trains are accelerated out of the station to travel up a vertical spike of track, then reverse back through the station to travel backwards up another vertical spike of track STR_0599 :A compact roller coaster with individual cars and smooth twisting drops -STR_0600 : +STR_0600 :Powered mine trains career along a smooth and twisted track layout STR_0601 : -STR_0602 : +STR_0602 :Roller coaster trains are accelerated out of the station by linear induction motors to speed through twisting inversions STR_0603 :Guest {INT32} STR_0604 :Guest {INT32} STR_0605 :Guest {INT32} @@ -839,16 +839,17 @@ STR_0834 :{SMALLFONT}{BLACK}Disk and game options STR_0835 :Game initialization failed STR_0836 :Unable to start game in a minimized state 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_0838 : STR_0839 :{UINT16} x {UINT16} STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} -STR_0841 :Desktop window -STR_0842 :640x480 full screen -STR_0843 :800x600 full screen -STR_0844 :1024x768 full screen -STR_0845 :1152x864 full screen -STR_0846 :1280x1024 full screen -STR_0847 :About 'RollerCoaster Tycoon 2' +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +STR_0847 :About 'OpenRCT2' STR_0848 :RollerCoaster Tycoon 2 STR_0849 :{WINDOW_COLOUR_2}Version 2.01.028 STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, all rights reserved @@ -1044,10 +1045,10 @@ 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_1043 :OpenRCT2 Saved Game +STR_1044 :OpenRCT2 Scenario File +STR_1045 :OpenRCT2 Landscape File +STR_1046 :OpenRCT2 Track Design File STR_1047 :Game save failed! STR_1048 :Scenario save failed! STR_1049 :Landscape save failed! @@ -1781,7 +1782,7 @@ STR_1776 :On 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 +STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tiger costume STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} Elephant costume STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} Roman costume STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} Gorilla costume @@ -1893,8 +1894,10 @@ STR_1888 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}more than 4 hou STR_1889 :{WINDOW_COLOUR_2}Down-Time: {MOVE_X}{255}{BLACK}{COMMA16}% STR_1890 :{SMALLFONT}{BLACK}Select how often a mechanic should check this ride STR_1891 :No {STRINGID} in park yet! -STR_1892 :RollerCoaster Tycoon 2 -STR_1893 :Please insert your RollerCoaster Tycoon 2 CD in the following drive: +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 : +STR_1893 : STR_1894 :{WINDOW_COLOUR_2}{STRINGID} sold: {BLACK}{COMMA32} STR_1895 :{SMALLFONT}{BLACK}Build new ride/attraction STR_1896 :{WINDOW_COLOUR_2}Expenditure/Income @@ -2218,7 +2221,7 @@ STR_2213 :{SMALLFONT}{BLACK}Show list of entertainers in park STR_2214 :Construction not possible while game is paused! STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C -STR_2217 :{WINDOW_COLOUR_2}{COMMA16}F +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F STR_2218 :{RED}{STRINGID} on {STRINGID} hasn't returned to the {STRINGID} yet!{NEWLINE}Check whether it is stuck or has stalled STR_2219 :{RED}{COMMA16} people have died in an accident on {STRINGID} STR_2220 :{WINDOW_COLOUR_2}Park Rating: {BLACK}{COMMA16} @@ -2291,7 +2294,7 @@ STR_2286 :Designing STR_2287 :Completing design STR_2288 :Unknown STR_2289 :{STRINGID} {STRINGID} -STR_2290 :{SMALLFONT}{BLACK}{STRINGID} {STRINGID} +STR_2290 : STR_2291 :Select scenario for new game STR_2292 :{WINDOW_COLOUR_2}Rides been on: STR_2293 :{BLACK} Nothing @@ -2318,10 +2321,10 @@ STR_2313 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}{COMMA2DP32} (approx.) STR_2314 :{WINDOW_COLOUR_2}Ride length: {BLACK}{STRINGID} STR_2315 :{WINDOW_COLOUR_2}Cost: {BLACK}around {CURRENCY} STR_2316 :{WINDOW_COLOUR_2}Space required: {BLACK}{COMMA16} x {COMMA16} blocks -STR_2317 :{WINDOW_COLOUR_2}Sound Quality: -STR_2318 :Low -STR_2319 :Medium -STR_2320 :High +STR_2317 : +STR_2318 : +STR_2319 : +STR_2320 : STR_2321 :{WINDOW_COLOUR_2}Number of rides/attractions: {BLACK}{COMMA16} STR_2322 :{WINDOW_COLOUR_2}Staff: {BLACK}{COMMA16} STR_2323 :{WINDOW_COLOUR_2}Park size: {BLACK}{COMMA32}m{SQUARED} @@ -2368,7 +2371,7 @@ STR_2363 :Gridlines on Landscape STR_2364 :{SMALLFONT}{BLACK}Toggle gridlines on landscape on/off STR_2365 :The bank refuses to increase your loan! STR_2366 :Celsius ({DEGREE}C) -STR_2367 :Fahrenheit (F) +STR_2367 :Fahrenheit ({DEGREE}F) STR_2368 :None STR_2369 :Low STR_2370 :Average @@ -2438,12 +2441,12 @@ 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_2437 : +STR_2438 : +STR_2439 : +STR_2440 : +STR_2441 : +STR_2442 : 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 @@ -2683,10 +2686,10 @@ 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_2681 :{MEDIUMFONT}{BLACK}Increases your money by {CURRENCY} +STR_2682 : +STR_2683 : +STR_2684 :{SMALLFONT}{BLACK}Large group of peeps arrive STR_2685 :Simplex Noise Parameters STR_2686 :{WINDOW_COLOUR_2}Low: STR_2687 :{WINDOW_COLOUR_2}High: @@ -2703,13 +2706,13 @@ 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_2701 :Every minute +STR_2702 :Every 5 minutes +STR_2703 :Every 15 minutes +STR_2704 :Every 30 minutes +STR_2705 :Every hour STR_2706 :Never -STR_2707 :Open new window +STR_2707 :Use system dialog 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. @@ -2720,8 +2723,8 @@ STR_2714 :- STR_2715 :. STR_2716 :/ STR_2717 :' -STR_2718 :(up) -STR_2719 :(new file) +STR_2718 :Up +STR_2719 :New file STR_2720 :{UINT16}sec STR_2721 :{UINT16}secs STR_2722 :{UINT16}min:{UINT16}sec @@ -2764,11 +2767,11 @@ 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_2760 :+{CURRENCY} +STR_2761 : +STR_2762 : STR_2763 :??? -STR_2764 :Happy Guests +STR_2764 : STR_2765 :Large Tram STR_2766 :Win scenario STR_2767 :Freeze Climate @@ -2787,8 +2790,7 @@ STR_2779 :Viewport #{COMMA16} STR_2780 :Extra viewport # End of new strings - -STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} STR_2782 :SHIFT + STR_2783 :CTRL + STR_2784 :Change keyboard shortcut @@ -2866,7 +2868,7 @@ STR_2855 :{RED}{STRINGID} has no path leading from its exit !{NEWLINE}Constru STR_2856 :{WINDOW_COLOUR_2}Tutorial STR_2857 :{WINDOW_COLOUR_2}(Press a key or mouse button to take control) STR_2858 :Can't start marketing campaign... -STR_2859 :Another instance of RollerCoaster Tycoon 2 is already running +STR_2859 :Another instance of OpenRCT2 is already running STR_2860 :Infogrames Interactive credits... STR_2861 :{WINDOW_COLOUR_2}Licensed to Infogrames Interactive Inc. STR_2862 :Music acknowledgements... @@ -2976,8 +2978,8 @@ STR_2965 :{WINDOW_COLOUR_2} STR_2966 : STR_2967 : STR_2968 : -STR_2969 :Use of this product is subject to the terms of a license agreement -STR_2970 :found in the product's {OPENQUOTES}ReadMe{ENDQUOTES} file and in the manual +STR_2969 : +STR_2970 : STR_2971 :Main color scheme STR_2972 :Alternative color scheme 1 STR_2973 :Alternative color scheme 2 @@ -3167,8 +3169,8 @@ STR_3156 : STR_3157 :map STR_3158 :graph STR_3159 :list -STR_3160 :RollerCoaster Tycoon 2: Starting for the first time... -STR_3161 :RollerCoaster Tycoon 2: Checking object files... +STR_3160 : +STR_3161 : STR_3162 :Unable to allocate enough memory STR_3163 :Installing new data: STR_3164 :{BLACK}{COMMA16} selected (maximum {COMMA16}) @@ -3179,7 +3181,7 @@ STR_3168 :{WINDOW_COLOUR_2}Text: {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 -STR_3172 :The following object must be selected first: +STR_3172 :The following object must be selected first: {STRING} STR_3173 :This object is currently in use STR_3174 :This object is required by another object STR_3175 :This object is always required @@ -3344,7 +3346,7 @@ 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_3337 : 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 @@ -3369,8 +3371,8 @@ 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_3362 : +STR_3363 : STR_3364 :Advanced STR_3365 :{SMALLFONT}{BLACK}Allow selection of individual items of scenery in addition to scenery groups STR_3366 :{BLACK}= Ride @@ -3456,11 +3458,11 @@ 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_5120 :Finances +STR_5121 :Research +STR_5122 :Select rides by track type (like in RCT1) STR_5123 :Renew rides -STR_5124 :No Six Flags +STR_5124 : STR_5125 :All destructable STR_5126 :Random title music STR_5127 :{SMALLFONT}{BLACK}Disable land elevation @@ -3483,7 +3485,7 @@ STR_5143 :Quick Speed STR_5144 :Fast Speed STR_5145 :Turbo Speed STR_5146 :Hyper Speed -STR_5147 :Show cheats button on toolbar +STR_5147 :Cheats STR_5148 :{SMALLFONT}{BLACK}Change the game speed STR_5149 :{SMALLFONT}{BLACK}Open the cheats window STR_5150 :Enable debugging tools @@ -3491,14 +3493,14 @@ STR_5150 :Enable debugging tools STR_5151 :, #Decimals separator STR_5152 :. -STR_5153 :Color schemes... +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_5160 :{POP16}{MONTH} {PUSH16}{PUSH16}{STRINGID}, Year {POP16}{COMMA16} STR_5161 :Date Format: STR_5162 :Day/Month/Year STR_5163 :Month/Day/Year @@ -3592,8 +3594,8 @@ 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_5254 :Create +STR_5255 :{SMALLFONT}{BLACK}Create a new title sequence from scratch 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 @@ -3607,7 +3609,7 @@ 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_5269 :{SMALLFONT}{BLACK}Controls and interface STR_5270 :{SMALLFONT}{BLACK}Miscellaneous STR_5271 :{SMALLFONT}{BLACK}Twitch STR_5272 :{SMALLFONT}{BLACK}Small Scenery @@ -3624,7 +3626,7 @@ 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_5286 :{SMALLFONT}{BLACK}Makes some guests explode STR_5287 :Ride is already broken down STR_5288 :Ride is closed STR_5289 :No breakdowns available for this ride @@ -3683,3 +3685,249 @@ 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 :Park cheats +STR_5348 :Ride cheats +STR_5349 :{SMALLFONT}{BLACK}All Rides +STR_5350 :Max +STR_5351 :Min +STR_5352 :{BLACK}Happiness: +STR_5353 :{BLACK}Energy: +STR_5354 :{BLACK}Hunger: +STR_5355 :{BLACK}Thirst: +STR_5356 :{BLACK}Nausea: +STR_5357 :{BLACK}Nausea tolerance: +STR_5358 :{BLACK}Bathroom: +STR_5359 :Remove guests +STR_5360 :{SMALLFONT}{BLACK}Removes all guests from the map +STR_5361 :Give all guests: +STR_5362 :{BLACK}Set all guests' preferred ride intensity to: +STR_5363 :More than 1 +STR_5364 :Less than 15 +STR_5365 :{BLACK}Staff speed: +STR_5366 :Normal +STR_5367 :Fast +STR_5368 :Reset crash status +STR_5369 :Park parameters... +STR_5370 :{SMALLFONT}{BLACK}Click this button to modify park{NEWLINE}parameters like restrictions,{NEWLINE}guest generation and money. +STR_5371 :Object Selection +STR_5372 :Invert right mouse dragging +STR_5373 :Name {STRINGID} +STR_5374 :Date {STRINGID} +STR_5375 :{UP} +STR_5376 :{DOWN} +STR_5377 :{SMALLFONT}{BLACK}Saves +STR_5378 :{SMALLFONT}{BLACK}Script +STR_5379 :{SMALLFONT}{BLACK}Skip to next wait command +STR_5380 :{SMALLFONT}{BLACK}Start playing title sequence +STR_5381 :{SMALLFONT}{BLACK}Stop playing title sequence +STR_5382 :{SMALLFONT}{BLACK}Restart title sequence +STR_5383 :{SMALLFONT}{BLACK}Create a new title sequence based on the current one +STR_5384 :{SMALLFONT}{BLACK}Delete the current title sequence +STR_5385 :{SMALLFONT}{BLACK}Rename the current title sequence +STR_5386 :{SMALLFONT}{BLACK}Insert a new command +STR_5387 :{SMALLFONT}{BLACK}Edit the selected command +STR_5388 :{SMALLFONT}{BLACK}Delete the selected command +STR_5389 :{SMALLFONT}{BLACK}Skip to the selected command in the title sequence +STR_5390 :{SMALLFONT}{BLACK}Move the selected command down +STR_5391 :{SMALLFONT}{BLACK}Move the selected command up +STR_5392 :{SMALLFONT}{BLACK}Add a save to the title sequence +STR_5393 :{SMALLFONT}{BLACK}Remove the selected save from the title sequence +STR_5394 :{SMALLFONT}{BLACK}Rename the selected save +STR_5395 :{SMALLFONT}{BLACK}Load the selected save in game +STR_5396 :{SMALLFONT}{BLACK}Reload the title sequence if changes have been made to it outside of the game +STR_5397 :Can only be used on the title screen +STR_5398 :Cannot edit title sequence while it's playing +STR_5399 :Press the stop button to continue editing +STR_5400 :Can't change this title sequence +STR_5401 :Create a new title sequence to make changes to +STR_5402 :Failed to load title sequence +STR_5403 :There may be no Load or Wait command or a save may be invalid +STR_5404 :Name already exists +STR_5405 :Enter a name for the save +STR_5406 :Enter a name for the title sequence +STR_5407 :Add +STR_5408 :Remove +STR_5409 :Insert +STR_5410 :Edit +STR_5411 :Reload +STR_5412 :Skip to +STR_5413 :Load +STR_5414 :Load{MOVE_X}{87}Six Flags Magic Mountain.SC6 +STR_5415 :Load{MOVE_X}{87}{STRING} +STR_5416 :Load{MOVE_X}{87}No save selected +STR_5417 :Location +STR_5418 :Location{MOVE_X}{87}{COMMA16} {COMMA16} +STR_5419 :Rotate +STR_5420 :Rotate{MOVE_X}{87}{COMMA16} +STR_5421 :Zoom +STR_5422 :Zoom{MOVE_X}{87}{COMMA16} +STR_5423 :Wait +STR_5424 :Wait{MOVE_X}{87}{COMMA16} +STR_5425 :Restart +STR_5426 :End +STR_5427 :Coordinates: +STR_5428 :Counter-clockwise rotations: +STR_5429 :Zoom level: +STR_5430 :Seconds to wait: +STR_5431 :Save to load: +STR_5432 :Command: +STR_5433 :Title Sequences +STR_5434 :Command Editor +STR_5435 :Rename save +STR_5436 :Edit Title Sequences... +STR_5437 :No save selected +STR_5438 :Can't make changes while command editor is open +STR_5439 :A wait command with at least 4 seconds is required with a restart command +STR_5440 :Minimize fullscreen on focus loss +STR_5441 :{SMALLFONT}{BLACK}Identifies rides by track type,{NEWLINE}so vehicles can be changed{NEWLINE}afterwards, like in RCT1. +STR_5442 :Force park rating: +STR_5443 :Speed{MOVE_X}{87}{STRINGID} +STR_5444 :Speed: +STR_5445 :Speed +STR_5446 :Get +STR_5447 :Type {STRINGID} +STR_5448 :Ride / Vehicle {STRINGID} +STR_5449 :Reduce game speed +STR_5450 :Increase game speed +STR_5451 :Open cheats window +STR_5452 :Toggle visibility of toolbars +STR_5453 :Select another ride +STR_5454 :Uncap FPS +STR_5455 :Enable sandbox mode +STR_5456 :Disable clearance checks +STR_5457 :Disable support limits +STR_5458 :Rotate clockwise +STR_5459 :Rotate counterclockwise +STR_5460 :Rotate view counterclockwise +STR_5461 :Set guests' parameters +STR_5462 :{CURRENCY} +STR_5463 :Goal: Have fun! +STR_5464 :General +STR_5465 :Climate +STR_5466 :Staff +STR_5467 :ALT + +STR_5468 :Recent messages +STR_5469 :Scroll map up +STR_5470 :Scroll map left +STR_5471 :Scroll map down +STR_5472 :Scroll map right +STR_5473 :Cycle day / night +STR_5474 :Display text on banners in upper case +STR_5475 :{COMMA16} weeks +STR_5476 :Hardware +STR_5477 :Map rendering +STR_5478 :Controls +STR_5479 :Toolbar +STR_5480 :Show toolbar buttons for: +STR_5481 :Themes +STR_5482 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}1 minute +STR_5483 :{BLACK}({COMMA16} weeks remaining) +STR_5484 :{BLACK}({COMMA16} week remaining) +STR_5485 :{SMALLFONT}{STRING} +STR_5486 :{BLACK}{COMMA16} +STR_5487 :{SMALLFONT}{BLACK}Show recent messages +STR_5488 :No entrance (OpenRCT2 only!) +STR_5489 :{SMALLFONT}{BLACK}Show only tracked guests +STR_5490 :Disable audio on focus loss +STR_5491 :Inventions list +STR_5492 :Scenario options +STR_5493 :Send Message +STR_5494 : +STR_5495 :Player List +STR_5496 :Player: +STR_5497 :Ping: +STR_5498 :Server List +STR_5499 :Player Name: +STR_5500 :Add Server +STR_5501 :Start Server +STR_5502 :Multiplayer +STR_5503 :Enter hostname or IP address: +STR_5504 :{SMALLFONT}{BLACK}Show multiplayer status +STR_5505 :Unable to connect to server. +STR_5506 :Guests ignore intensities +STR_5507 :Handymen mow grass by default +STR_5508 :Allow loading files with incorrect checksums +STR_5509 :{SMALLFONT}{BLACK}Allows loading scenarios and saves that have an incorrect checksum, like the scenarios from the demo or damaged saves. +STR_5510 :Default sound device +STR_5511 :(UNKNOWN) +STR_5512 :Save Game As +STR_5513 :(Quick) save game +STR_5514 :Disable vandalism +STR_5515 :{SMALLFONT}{BLACK}Stops guests from vandalizing your park when they're angry +STR_5516 :{SMALLFONT}{BLACK}Black +STR_5517 :{SMALLFONT}{BLACK}Gray +STR_5518 :{SMALLFONT}{BLACK}White +STR_5519 :{SMALLFONT}{BLACK}Dark purple +STR_5520 :{SMALLFONT}{BLACK}Light purple +STR_5521 :{SMALLFONT}{BLACK}Bright purple +STR_5522 :{SMALLFONT}{BLACK}Dark blue +STR_5523 :{SMALLFONT}{BLACK}Light blue +STR_5524 :{SMALLFONT}{BLACK}Icy blue +STR_5525 :{SMALLFONT}{BLACK}Dark water +STR_5526 :{SMALLFONT}{BLACK}Light water +STR_5527 :{SMALLFONT}{BLACK}Saturated green +STR_5528 :{SMALLFONT}{BLACK}Dark green +STR_5529 :{SMALLFONT}{BLACK}Moss green +STR_5530 :{SMALLFONT}{BLACK}Bright green +STR_5531 :{SMALLFONT}{BLACK}Olive green +STR_5532 :{SMALLFONT}{BLACK}Dark olive green +STR_5533 :{SMALLFONT}{BLACK}Bright yellow +STR_5534 :{SMALLFONT}{BLACK}Yellow +STR_5535 :{SMALLFONT}{BLACK}Dark yellow +STR_5536 :{SMALLFONT}{BLACK}Light orange +STR_5537 :{SMALLFONT}{BLACK}Dark orange +STR_5538 :{SMALLFONT}{BLACK}Light brown +STR_5539 :{SMALLFONT}{BLACK}Saturated brown +STR_5540 :{SMALLFONT}{BLACK}Dark brown +STR_5541 :{SMALLFONT}{BLACK}Salmon pink +STR_5542 :{SMALLFONT}{BLACK}Bordeaux red +STR_5543 :{SMALLFONT}{BLACK}Saturated red +STR_5544 :{SMALLFONT}{BLACK}Bright red +STR_5545 :{SMALLFONT}{BLACK}Dark pink +STR_5546 :{SMALLFONT}{BLACK}Bright pink +STR_5547 :{SMALLFONT}{BLACK}Light pink +STR_5548 :Show all operating modes +STR_5549 :Year/Month/Day +STR_5550 :{POP16}{POP16}Year {COMMA16}, {PUSH16}{PUSH16}{MONTH} {PUSH16}{PUSH16}{STRINGID} +STR_5551 :Year/Day/Month +STR_5552 :{POP16}{POP16}Year {COMMA16}, {PUSH16}{PUSH16}{PUSH16}{STRINGID} {MONTH} +STR_5553 :Pause game when Steam overlay is open +STR_5554 :{SMALLFONT}{BLACK}Enable mountain tool +STR_5555 :Show vehicles from other track types +STR_5556 :Kick Player +STR_5557 :Stay connected after desynchronization (Multiplayer) +STR_5558 :A restart is required for this setting to take effect +STR_5559 :10 min. inspections +STR_5560 :{SMALLFONT}{BLACK}Sets the inspection time to 'Every 10 minutes' on all rides +STR_5561 :Failed to load language +STR_5562 :WARNING! +STR_5563 :This feature is currently unstable, take extra caution. +STR_5564 :Insert Corrupt Element +STR_5565 :{SMALLFONT}{BLACK}Inserts a corrupt map element at top of tile. This will hide any element above the corrupt element. +STR_5566 :Password: +STR_5567 :Advertise +STR_5568 :Password Required +STR_5569 :This server requires a password +STR_5570 :Fetch Servers +STR_5571 :Join Game +STR_5572 :Add To Favorites +STR_5573 :Remove From Favorites +STR_5574 :Server Name: +STR_5575 :Max Players: +STR_5576 :Port: +STR_5577 :South Korean Won (W) +STR_5578 :Russian Ruble (R) +STR_5579 :Window scale factor: +STR_5580 :Czech koruna (Kc) + +######### +# Rides # +######### + +#WW +[CONDORRD] +STR_NAME :Condor Ride +STR_DESC :Riding in special harnesses below the track, riders experience the feeling of flight as they swoop through the air in Condor-shaped trains +STR_CPTY :4 passengers per car diff --git a/data/language/finnish.txt b/data/language/finnish.txt new file mode 100644 index 0000000000..f36f052215 --- /dev/null +++ b/data/language/finnish.txt @@ -0,0 +1,3904 @@ +# 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 :Kierrevuoristorata +STR_0003 :Seisomavuoristorata +STR_0004 :Riippukeinuvuoristorata +STR_0005 :Käänteinen vuoristorata +STR_0006 :Juniorivuoristorata +STR_0007 :Pienoisrautatie +STR_0008 :Yksiraiteinen rautatie +STR_0009 :Pieni riippuva vuoristorata +STR_0010 :Veneajelu +STR_0011 :Puinen villihiiri +STR_0012 :Estejuoksu +STR_0013 :Autoajelu +STR_0014 :Laukaistu vapaapudotus +STR_0015 :Rattikelkkarata +STR_0016 :Näköalatorni +STR_0017 :Silmukkavuoristorata +STR_0018 :Veneliukumäki +STR_0019 :Kaivosjunarata +STR_0020 :Tuolihissi +STR_0021 :Korkkiruuvivuoristorata +STR_0022 :Labyrintti +STR_0023 :Kierreliukumäki +STR_0024 :Mikroautot +STR_0025 :Tukkijoki +STR_0026 :Koskiseikkailu +STR_0027 :Törmäysautot +STR_0028 :Merirosvolaiva +STR_0029 :Keinuva käänteinen laiva +STR_0030 :Ruokakoju +STR_0031 :Tuntematon koju (1D) +STR_0032 :Juomakoju +STR_0033 :Tuntematon koju (1F) +STR_0034 :Kauppa +STR_0035 :Karuselli +STR_0036 :Tuntematon koju (22) +STR_0037 :Infokioski +STR_0038 :Vessa +STR_0039 :Maailmanpyörä +STR_0040 :Liikesimulaattori +STR_0041 :3D-teatteri +STR_0042 :Yläpyörähdys +STR_0043 :Avaruusrenkaat +STR_0044 :Päinvastainen vapaapudotusrata +STR_0045 :Hissi +STR_0046 :Pystysuora tiputusvuoristorata +STR_0047 :Pankkiautomaatti +STR_0048 :Vääntely +STR_0049 :Kummitustalo +STR_0050 :Ensiapuhuone +STR_0051 :Sirkusesitys +STR_0052 :Kummitusjuna +STR_0053 :Teräskiehkuravuoristorata +STR_0054 :Puinen vuoristorata +STR_0055 :Sivukitkavuoristorata +STR_0056 :Villihiiri +STR_0057 :Moniulottuvuusvuoristorata +STR_0058 :Tuntematon laite (38) +STR_0059 :Lentävä vuoristorata +STR_0060 :Tuntematon laite (3A) +STR_0061 :Virginian kela +STR_0062 :Roiskahdusveneet +STR_0063 :Minihelikopterit +STR_0064 :Makuuvuoristorata +STR_0065 :Riippuva yksiraiteinen rautatie +STR_0066 :Tuntematon laite (40) +STR_0067 :Päinvastainen vuoristorata +STR_0068 :Sydänviivakiehkurarata +STR_0069 :Minigolffi +STR_0070 :Jättirata +STR_0071 :Pyörivä tiputus +STR_0072 :Lentävät lautaset +STR_0073 :Kiero talo +STR_0074 :Yksiraiteinen rautatiekierto +STR_0075 :Tiivis käänteinen rata +STR_0076 :Vesirata +STR_0077 :Ilmakäyttöinen pystysuora rata +STR_0078 :Kääteinenhiusneularata +STR_0079 :Taikamatto +STR_0080 :Sukellusveneajelu +STR_0081 :Jokilautat +STR_0082 :Tuntematon laite (50) +# 0083 is a name, and can't be translated. The ride itself was named after USS Enterprise from star trek, see wikipedia. +STR_0083 :Enterprise +STR_0084 :Tuntematon laite (52) +STR_0085 :Tuntematon laite (53) +STR_0086 :Tuntematon laite (54) +STR_0087 :Tuntematon laite (55) +STR_0088 :Käänteinen impulssirata +STR_0089 :Minivuoristorata +STR_0090 :Kaivosajelu +STR_0091 :Tuntematon laite (59) +STR_0092 :Induktiomoottorilaukaisuvuoristorata +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 :A compact roller coaster with a spiral lift hill and smooth, twisting drops. +STR_0513 :A looping roller coaster where the riders ride in a standing position +STR_0514 :Trains suspended beneath the roller coaster track swing out to the side around corners +STR_0515 :A steel roller coaster with trains that are held beneath the track, with many complex and twisting track elements +STR_0516 :A gentle roller coaster for people who haven't yet got the courage to face the larger rides +STR_0517 :Passengers ride in miniature trains along a narrow-gauge railway track +STR_0518 :Matkustajat kulkevat sähköisillä junilla yksittäisellä raiteella +STR_0519 :Passengers ride in small cars hanging beneath the single-rail track, swinging freely from side to side around corners +STR_0520 :A dock platform where guests can drive/row personal watercraft on a body of water +STR_0521 :A fast and twisting roller coaster with tight turns and steep drops. Intensity is bound to be high. +STR_0522 :A smaller roller coaster where the riders sit above the track with no car around them +STR_0523 :Riders travel slowly in powered vehicles along a track-based route +STR_0524 :Freefall car is pneumatically launched up a tall steel tower and then allowed to freefall down +STR_0525 :Riders career down a twisting track guided only by the curvature and banking of the semi-circular track +STR_0526 :Passengers travel in a rotating observation cabin which travels up a tall tower +STR_0527 :A smooth steel-tracked roller coaster capable of vertical loops +STR_0528 :Riders travel in inflatable dinghies down a twisting semi-circular or completely enclosed tube track +STR_0529 :Mine train themed roller coaster trains career along steel roller coaster track made to look like old railway track +STR_0530 :Cars hang from a steel cable which runs continuously from one end of the ride to the other and back again +STR_0531 :A compact steel-tracked roller coaster where the train travels through corkscrews and loops +STR_0532 : +STR_0533 : +STR_0534 :Itsestään ajavat bensalla kulkevat mikroautot +STR_0535 :Log-shaped boats travel along a water channel, splashing down steep slopes to soak the riders +STR_0536 :Circular boats meander along a wide water channel, splashing through waterfalls and thrilling riders through foaming rapids +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 :The car is accelerated out of the station along a long level track using Linear Induction Motors, then heads straight up a vertical spike of track, freefalling back down to return to the station +STR_0555 :Guests ride in an elevator up or down a vertical tower to get from one level to another +STR_0556 :Extra-wide cars descend completely vertical sloped track for the ultimate freefall roller coaster experience +STR_0557 : +STR_0558 : +STR_0559 : +STR_0560 : +STR_0561 : +STR_0562 :Powered cars travel along a multi-level track past spooky scenery and special effects +STR_0563 :Sitting in comfortable trains with only simple lap restraints riders enjoy giant smooth drops and twisting track as well as plenty of 'air time' over the hills +STR_0564 :Running on wooden track, this coaster is fast, rough, noisy, and gives an 'out of control' riding experience with plenty of 'air time' +STR_0565 :A simple wooden roller coaster capable of only gentle slopes and turns, where the cars are only kept on the track by side friction wheels and gravity +STR_0566 :Individual roller coaster cars zip around a tight zig-zag layout of track with sharp corners and short sharp drops +STR_0567 :Sitting in seats suspended either side of the track, riders are pitched head-over-heels while they plunge down steep drops and travel through various inversions +STR_0568 : +STR_0569 :Riding in special harnesses below the track, riders experience the feeling of flight as they swoop through the air +STR_0570 : +STR_0571 :Circular cars spin around as they travel along the zig-zagging wooden track +STR_0572 :Large capacity boats travel along a wide water channel, propelled up slopes by a conveyer belt, accelerating down steep slopes to soak the riders with a gaint splash +STR_0573 :Powered helicoper shaped cars running on a steel track, controlled by the pedalling of the riders +STR_0574 :Riders are held in special harnesses in a lying-down position, travlling through twisted track and inversions either on their backs or facing the ground +STR_0575 :Powered trains hanging from a single rail transport people around the park +STR_0576 : +STR_0577 :Bogied cars run on wooden tracks, turning around on special reversing sections +STR_0578 :Cars run along track enclosed by circular hoops, traversing steep drops and heartline twists +STR_0579 : +STR_0580 :A giant steel roller coaster capable of smooth drops and hills of over 300ft +STR_0581 :A ring of seats is pulled to the top of a tall tower while gently rotating, then allowed to free-fall down, stopping gently at the bottom using magnetic brakes +STR_0582 : +STR_0583 : +STR_0584 :Special bicycles run on a steel monorail track, propelled by the pedalling of the riders +STR_0585 :Riders sit in pairs of seats suspended beneath the track as they loop and twist through tight inversions +STR_0586 :Boat shaped cars run on roller coaster track to allow twisting curves and steep drops, splashing down into sections of water for gentle river sections +STR_0587 :After an exhilarating air-powered launch, the train speeds up a vertical track, over the top, and vertically down the other side to return to the station +STR_0588 :Individual cars run beneath a zig-zagging track with hairpin turns and sharp drops +STR_0589 : +STR_0590 :Riders ride in a submerged submarine through an underwater course +STR_0591 :Raft-shaped boats gently meander around a river track +STR_0592 : +STR_0593 : +STR_0594 : +STR_0595 : +STR_0596 : +STR_0597 : +STR_0598 :Inverted roller coaster trains are accelerated out of the station to travel up a vertical spike of track, then reverse back through the station to travel backwards up another vertical spike of track +STR_0599 :A compact roller coaster with individual cars and smooth twisting drops +STR_0600 :Powered mine trains career along a smooth and twisted track layout +STR_0601 : +STR_0602 :Roller coaster trains are accelerated out of the station by linear induction motors to speed through twisting inversions +STR_0603 :Vieras {INT32} +STR_0604 :Vieras {INT32} +STR_0605 :Vieras {INT32} +STR_0606 :Vieras {INT32} +STR_0607 :Vieras {INT32} +STR_0608 :Vieras {INT32} +STR_0609 :Vieras {INT32} +STR_0610 :Vieras {INT32} +STR_0611 :Vieras {INT32} +STR_0612 :Vieras {INT32} +STR_0613 :Vieras {INT32} +STR_0614 :Vieras {INT32} +STR_0615 :Vieras {INT32} +STR_0616 :Vieras {INT32} +STR_0617 :Vieras {INT32} +STR_0618 :Vieras {INT32} +STR_0619 :Vieras {INT32} +STR_0620 :Vieras {INT32} +STR_0621 :Vieras {INT32} +STR_0622 :Vieras {INT32} +STR_0623 :Vieras {INT32} +STR_0624 :Vieras {INT32} +STR_0625 :Vieras {INT32} +STR_0626 :Vieras {INT32} +STR_0627 :Vieras {INT32} +STR_0628 :Vieras {INT32} +STR_0629 :Vieras {INT32} +STR_0630 :Vieras {INT32} +STR_0631 :Vieras {INT32} +STR_0632 :Vieras {INT32} +STR_0633 :Vieras {INT32} +STR_0634 :Vieras {INT32} +STR_0635 :Vieras {INT32} +STR_0636 :Vieras {INT32} +STR_0637 :Vieras {INT32} +STR_0638 :Vieras {INT32} +STR_0639 :Vieras {INT32} +STR_0640 :Vieras {INT32} +STR_0641 :Vieras {INT32} +STR_0642 :Vieras {INT32} +STR_0643 :Vieras {INT32} +STR_0644 :Vieras {INT32} +STR_0645 :Vieras {INT32} +STR_0646 :Vieras {INT32} +STR_0647 :Vieras {INT32} +STR_0648 :Vieras {INT32} +STR_0649 :Vieras {INT32} +STR_0650 :Vieras {INT32} +STR_0651 :Vieras {INT32} +STR_0652 :Vieras {INT32} +STR_0653 :Vieras {INT32} +STR_0654 :Vieras {INT32} +STR_0655 :Vieras {INT32} +STR_0656 :Vieras {INT32} +STR_0657 :Vieras {INT32} +STR_0658 :Vieras {INT32} +STR_0659 :Vieras {INT32} +STR_0660 :Vieras {INT32} +STR_0661 :Vieras {INT32} +STR_0662 :Vieras {INT32} +STR_0663 :Vieras {INT32} +STR_0664 :Vieras {INT32} +STR_0665 :Vieras {INT32} +STR_0666 :Vieras {INT32} +STR_0667 :Vieras {INT32} +STR_0668 :Vieras {INT32} +STR_0669 :Vieras {INT32} +STR_0670 :Vieras {INT32} +STR_0671 :Vieras {INT32} +STR_0672 :Vieras {INT32} +STR_0673 :Vieras {INT32} +STR_0674 :Vieras {INT32} +STR_0675 :Vieras {INT32} +STR_0676 :Vieras {INT32} +STR_0677 :Vieras {INT32} +STR_0678 :Vieras {INT32} +STR_0679 :Vieras {INT32} +STR_0680 :Vieras {INT32} +STR_0681 :Vieras {INT32} +STR_0682 :Vieras {INT32} +STR_0683 :Vieras {INT32} +STR_0684 :Vieras {INT32} +STR_0685 :Vieras {INT32} +STR_0686 :Vieras {INT32} +STR_0687 :Vieras {INT32} +STR_0688 :Vieras {INT32} +STR_0689 :Vieras {INT32} +STR_0690 :Vieras {INT32} +STR_0691 :Vieras {INT32} +STR_0692 :Vieras {INT32} +STR_0693 :Vieras {INT32} +STR_0694 :Vieras {INT32} +STR_0695 :Vieras {INT32} +STR_0696 :Vieras {INT32} +STR_0697 :Vieras {INT32} +STR_0698 :Vieras {INT32} +STR_0699 :Vieras {INT32} +STR_0700 :Vieras {INT32} +STR_0701 :Vieras {INT32} +STR_0702 :Vieras {INT32} +STR_0703 :Vieras {INT32} +STR_0704 :Vieras {INT32} +STR_0705 :Vieras {INT32} +STR_0706 :Vieras {INT32} +STR_0707 :Vieras {INT32} +STR_0708 :Vieras {INT32} +STR_0709 :Vieras {INT32} +STR_0710 :Vieras {INT32} +STR_0711 :Vieras {INT32} +STR_0712 :Vieras {INT32} +STR_0713 :Vieras {INT32} +STR_0714 :Vieras {INT32} +STR_0715 :Vieras {INT32} +STR_0716 :Vieras {INT32} +STR_0717 :Vieras {INT32} +STR_0718 :Vieras {INT32} +STR_0719 :Vieras {INT32} +STR_0720 :Vieras {INT32} +STR_0721 :Vieras {INT32} +STR_0722 :Vieras {INT32} +STR_0723 :Vieras {INT32} +STR_0724 :Vieras {INT32} +STR_0725 :Vieras {INT32} +STR_0726 :Vieras {INT32} +STR_0727 :Vieras {INT32} +STR_0728 :Vieras {INT32} +STR_0729 :Vieras {INT32} +STR_0730 :Vieras {INT32} +STR_0731 :Vieras {INT32} +STR_0732 :Vieras {INT32} +STR_0733 :Vieras {INT32} +STR_0734 :Vieras {INT32} +STR_0735 :Vieras {INT32} +STR_0736 :Vieras {INT32} +STR_0737 :Vieras {INT32} +STR_0738 :Vieras {INT32} +STR_0739 :Vieras {INT32} +STR_0740 :Vieras {INT32} +STR_0741 :Vieras {INT32} +STR_0742 :Vieras {INT32} +STR_0743 :Vieras {INT32} +STR_0744 :Vieras {INT32} +STR_0745 :Vieras {INT32} +STR_0746 :Vieras {INT32} +STR_0747 :Vieras {INT32} +STR_0748 :Vieras {INT32} +STR_0749 :Vieras {INT32} +STR_0750 :Vieras {INT32} +STR_0751 :Vieras {INT32} +STR_0752 :Vieras {INT32} +STR_0753 :Vieras {INT32} +STR_0754 :Vieras {INT32} +STR_0755 :Vieras {INT32} +STR_0756 :Vieras {INT32} +STR_0757 :Vieras {INT32} +STR_0758 :Vieras {INT32} +STR_0759 :Vieras {INT32} +STR_0760 :Vieras {INT32} +STR_0761 :Vieras {INT32} +STR_0762 :Vieras {INT32} +STR_0763 :Vieras {INT32} +STR_0764 :Vieras {INT32} +STR_0765 :Vieras {INT32} +STR_0766 :Vieras {INT32} +STR_0767 :Vieras {INT32} +STR_0768 :Yleismies {INT32} +STR_0769 :Mekaanikko {INT32} +STR_0770 :Vartija {INT32} +STR_0771 :Viihdyttjäjä {INT32} +STR_0772 :Nimetön puisto{POP16}{POP16} +STR_0773 :Nimetön puisto{POP16}{POP16} +STR_0774 :Nimetön puisto{POP16}{POP16} +STR_0775 :Nimetön puisto{POP16}{POP16} +STR_0776 :Nimetön puisto{POP16}{POP16} +STR_0777 :Nimetön puisto{POP16}{POP16} +STR_0778 :Kyltti +STR_0779 :1. +STR_0780 :2. +STR_0781 :3. +STR_0782 :4. +STR_0783 :5. +STR_0784 :6. +STR_0785 :7. +STR_0786 :8. +STR_0787 :9. +STR_0788 :10. +STR_0789 :11. +STR_0790 :12. +STR_0791 :13. +STR_0792 :14. +STR_0793 :15. +STR_0794 :16. +STR_0795 :17. +STR_0796 :18. +STR_0797 :19. +STR_0798 :20. +STR_0799 :21. +STR_0800 :22. +STR_0801 :23. +STR_0802 :24. +STR_0803 :25. +STR_0804 :26. +STR_0805 :27. +STR_0806 :28. +STR_0807 :29. +STR_0808 :30. +STR_0809 :31. +STR_0810 :Tammi +STR_0811 :Helmi +STR_0812 :Maalis +STR_0813 :Huhti +STR_0814 :Touko +STR_0815 :Kesä +STR_0816 :Heinä +STR_0817 :Elo +STR_0818 :Syys +STR_0819 :Loka +STR_0820 :Marras +STR_0821 :Joulu +STR_0822 :Kykenemätön avaamaan grafiikkadatatiedostoa +STR_0823 :Puuttuva tai käyttökelvoton datatiedosto +STR_0824 :{BLACK}{CROSS} +STR_0825 :Nimi on jo käytössä +STR_0826 :Liian monta nimeä määritetty +STR_0827 :Rahaa ei ole tarpeeksi - tarvitaan {CURRENCY2DP} +STR_0828 :{SMALLFONT}{BLACK}Sulje ikkuna +STR_0829 :{SMALLFONT}{BLACK}Ikkunan otsikko - Vedä tätä liikuttaakseen ikkunaa +STR_0830 :{SMALLFONT}{BLACK}Suurenna +STR_0831 :{SMALLFONT}{BLACK}Pienennä +STR_0832 :{SMALLFONT}{BLACK}Käännä 90{DEGREE} myötäpäivään +STR_0833 :{SMALLFONT}{BLACK}Pysäytä peli +STR_0834 :{SMALLFONT}{BLACK}Levy- ja peliasetukset +STR_0835 :Pelin alustus epäonnistui +STR_0836 :Kykenemätön aloittamaan peliä pienennetyssä tilassa +STR_0837 :Kykenemätön alustamaan grafiikkajärjestelmää +STR_0838 : +STR_0839 :{UINT16} x {UINT16} +STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +STR_0847 :Lisätietoja 'OpenRCT2' +STR_0848 :RollerCoaster Tycoon 2 +STR_0849 :{WINDOW_COLOUR_2}Versio 2.01.028 +STR_0850 :{WINDOW_COLOUR_2}Tekijänoikeus {COPYRIGHT} 2002 Chris Sawyer, kaikki oikeudet pidetään +STR_0851 :{WINDOW_COLOUR_2}Suunnitellut ja ohjelmoinut Chris Sawyer +STR_0852 :{WINDOW_COLOUR_2}Grafiikka Simon Foster +STR_0853 :{WINDOW_COLOUR_2}Äänet ja musiikki Allister Brimble +STR_0854 :{WINDOW_COLOUR_2}Lisä-äänet nauhoittanut David Ellis +STR_0855 :{WINDOW_COLOUR_2}Edustaja Jacqui Lyons at Marjacq Ltd. +STR_0856 :{WINDOW_COLOUR_2}Kiitoksia: +STR_0857 :{WINDOW_COLOUR_2}Peter James Adcock, Joe Booth, ja 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 :Liian matala ! +STR_0878 :Liian korkea ! +STR_0879 :Maata ei voi alentaa tästä... +STR_0880 :Maata ei voi nostaa tästä... +STR_0881 :Esine on tiellä +STR_0882 :Lataa peli +STR_0883 :Tallenna peli +STR_0884 :Lataa maisema +STR_0885 :Tallenna maisema +STR_0886 :Lopeta peli +STR_0887 :Lopeta skenaariomuokkaaja +STR_0888 :Lopeta vuoristoratasuunnittelija +STR_0889 :Lopeta ratasuunnitelmahallinta +STR_0890 :Kuva{COMMA16}.BMP +STR_0891 :Kuvankaappaus +STR_0892 :Kuvankaappaus tallennettu levylle nimellä '{STRINGID}' +STR_0893 :Kuvankaappaus epäonnistui ! +STR_0894 :Maisematietoalue on täynnä ! +STR_0895 :Ei voi rakentaa osittain maan ylle ja alle +STR_0896 :{POP16}{POP16}{STRINGID} Rakenne +STR_0897 :Suunta +STR_0898 :{SMALLFONT}{BLACK}Vasemman käden kaarre +STR_0899 :{SMALLFONT}{BLACK}Oikean käden kaarre +STR_0900 :{SMALLFONT}{BLACK}Vasemman käden kaarre (pieni säde) +STR_0901 :{SMALLFONT}{BLACK}Oikean käden kaarre (pieni säde) +STR_0902 :{SMALLFONT}{BLACK}Vasemman käden kaarre (todella pieni säde) +STR_0903 :{SMALLFONT}{BLACK}Oikean käden kaarre (todella pieni säde) +STR_0904 :{SMALLFONT}{BLACK}Vasemman käden kaarre (iso säde) +STR_0905 :{SMALLFONT}{BLACK}Oikean käden kaarre (iso säde) +STR_0906 :{SMALLFONT}{BLACK}Suora +STR_0907 :Rinne +STR_0908 :Kallistus +STR_0909 :Istuimen kierto +STR_0910 :{SMALLFONT}{BLACK}Vasemmalle kaartava kallistus +STR_0911 :{SMALLFONT}{BLACK}Oikealle kaartava kallistus +STR_0912 :{SMALLFONT}{BLACK}Ei kallistusta +STR_0913 :{SMALLFONT}{BLACK}Siirry edelliseen osaan +STR_0914 :{SMALLFONT}{BLACK}Siirry seuraavaan osaan +STR_0915 :{SMALLFONT}{BLACK}Rakenna valittu osio +STR_0916 :{SMALLFONT}{BLACK}Poista valittu osio +STR_0917 :{SMALLFONT}{BLACK}Pystypudotus +STR_0918 :{SMALLFONT}{BLACK}Jyrkkä mäki alas +STR_0919 :{SMALLFONT}{BLACK}Mäki alas +STR_0920 :{SMALLFONT}{BLACK}Tasanne +STR_0921 :{SMALLFONT}{BLACK}Mäki ylös +STR_0922 :{SMALLFONT}{BLACK}Jyrkkä mäki ylös +STR_0923 :{SMALLFONT}{BLACK}Pystynousu +STR_0924 :{SMALLFONT}{BLACK}Ruuvikierre alas +STR_0925 :{SMALLFONT}{BLACK}Ruuvikierre ylös +STR_0926 :Tämän poistaminen ei onnistu... +STR_0927 :Tämän rakentaminen tähän ei onnistu... +STR_0928 :{SMALLFONT}{BLACK}Ketjumäki, vaunujen vetämistä varten mäissä. +STR_0929 :'S' mutka (vasen) +STR_0930 :'S' mutka (oikea) +STR_0931 :Pystysuora kierukka (vasen) +STR_0932 :Pystysuora kierukka (oikea) +STR_0933 :Nosta tai laske maata ensin +STR_0934 :Laitteen sisäänkäynti edessä +STR_0935 :Laitteen uloskäynti edessä +STR_0936 :Puiston sisäänkäynti edessä +STR_0937 :{SMALLFONT}{BLACK}Näkymäasetukset +STR_0938 :{SMALLFONT}{BLACK}Muokkaa maan korkeutta ja jyrkkyyttä +STR_0939 :Maanalainen näkymä +STR_0940 :Poista pohjamaa +STR_0941 :Poista pystysuorat pinnat +STR_0942 :Näe laitteiden läpi +STR_0943 :Näe maiseman läpi +STR_0944 :Tallenna +STR_0945 :Älä tallenna +STR_0946 :Peruuta +STR_0947 :Tallenna ennen lataamista ? +STR_0948 :Tallenna ennen lopettamista ? +STR_0949 :Tallenna ennen lopettamista ? +STR_0950 :Lataa peli +STR_0951 :Lopeta peli +STR_0952 :Lopeta peli +STR_0953 :Lataa maisema +STR_0954 : +STR_0955 :{SMALLFONT}{BLACK}Valitse istuimen kiertokulma tämän radan osioon +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 :Peruuta +STR_0973 :OK +STR_0974 :Laitteet +STR_0975 :Kaupat ja kojut +STR_0976 :Vessat ja infokioskit +STR_0977 :Uusia kuljetuslaitteita +STR_0978 :Uusia lempeitä laitteita +STR_0979 :Uusia vuoristoratoja +STR_0980 :Uusia jännittäviä laitteita +STR_0981 :Uusia vesilaitteita +STR_0982 :Uusia kauppoja ja kojuja +STR_0983 :Tutkimustyö & kehittely +STR_0984 :{WINDOW_COLOUR_2}{UP}{BLACK} {CURRENCY2DP} +STR_0985 :{WINDOW_COLOUR_2}{DOWN}{BLACK} {CURRENCY2DP} +STR_0986 :{BLACK}{CURRENCY2DP} +STR_0987 :Liian monta laitetta/kohdetta +STR_0988 :Ei pysty luomaan uutta laitetta/kohdetta... +STR_0989 :{STRINGID} +STR_0990 :{SMALLFONT}{BLACK}Rakennus +STR_0991 :Asematasanne +STR_0992 :{SMALLFONT}{BLACK}Romuta koko laite/kohde +STR_0993 :Romuta laite/nähtävyys +STR_0994 :Romuta +STR_0995 :{WINDOW_COLOUR_1}Oletko varma että haluat tuhota {STRINGID}:n? +STR_0996 :Kokonaisnäkymä +STR_0997 :{SMALLFONT}{BLACK}Näe valinta +STR_0998 :Ei lisää asemia sallittu tälle laitteelle +STR_0999 :Vaatii asematasanteen +STR_1000 :Rata ei tee täydellistä kierrosta +STR_1001 :Rata ei sovi kyseiselle junalajille +STR_1002 :Avaaminen ei onnistu laitteessa {POP16}{POP16}{POP16}{STRINGID}... +STR_1003 :Testiajo ei onnistu laitteessa {POP16}{POP16}{POP16}{STRINGID}... +STR_1004 :Sulkeminen ei onnistu laitteessa {POP16}{POP16}{POP16}{STRINGID}... +STR_1005 :Rakentaminen ei onnistu laitteessa {POP16}{POP16}{POP16}{STRINGID}... +STR_1006 :Täytyy ensin sulkea +STR_1007 :Kykenemätön luomaan tarpeeksi kulkuneuvoja +STR_1008 :{SMALLFONT}{BLACK}Avaa, sulje tai testaa laitetta/kohdetta +STR_1009 :{SMALLFONT}{BLACK}Avaa tai sulje kaikki laitteet/kohteet +STR_1010 :{SMALLFONT}{BLACK}Avaa tai sulje puisto +STR_1011 :Sulje kaikki +STR_1012 :Avaa kaikki +STR_1013 :Sulje puisto +STR_1014 :Avaa puisto +STR_1015 :Kykenemätön toimimaan useamman asematasanteen kanssa tässä toimintatilassa +STR_1016 :Kykenemätön toimimaan vähemmän kuin kahden asematasanteen kanssa tässä toimintatilassa +STR_1017 :Ei pysty vaihtaamaan toimintatilaa... +STR_1018 :Muutoksien teko ei onnistu... +STR_1019 :Muutoksien teko ei onnistu... +STR_1020 :Muutoksien teko ei onnistu... +STR_1021 :{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_1022 :{POP16}{POP16}{POP16}{COMMA16} auto per juna +STR_1023 :{POP16}{POP16}{POP16}{COMMA16} autoa per juna +STR_1024 :{COMMA16} auto per juna +STR_1025 :{COMMA16} autoa per juna +STR_1026 :Asematasanne on liian pitkä! +STR_1027 :{SMALLFONT}{BLACK}Paikanna tämä päänäkymässä +STR_1028 :Kentän laidan yli! +STR_1029 :Ei voi rakentaa osittain veden pinnan ylle ja alle! +STR_1030 :Tämän voi ainoastaan rakentaa veden alle! +STR_1031 :Tätä ei voi rakentaa veden alle! +STR_1032 :Tämän voi ainoastaan rakentaa veteen! +STR_1033 :Tämän voi ainoastaan rakentaa maanpinnan ylle! +STR_1034 :Tämän voi ainoastaan rakentaa maanpinnalle! +STR_1035 :Paikallinen virkavalta ei salli rakentaa puiden latvoja korkeammalle! +STR_1036 :Lataa peli +STR_1037 :Lataa maisema +STR_1038 :Muunna tallennettu peli skenaarioksi +STR_1039 :Asenna uusi ratasuunnitelma +STR_1040 :Tallenna peli +STR_1041 :Tallenna skenaario +STR_1042 :Tallenna maisema +STR_1043 :OpenRCT2 Tallennettu peli +STR_1044 :OpenRCT2 Skenaariotiedosto +STR_1045 :OpenRCT2 Maisematiedosto +STR_1046 :OpenRCT2 Ratasuunitelmatiedosto +STR_1047 :Pelin tallennus epäonnistui! +STR_1048 :Skenaarion tallennus epäonnistui! +STR_1049 :Maisematiedoston tallennus epäonnistui! +STR_1050 :Avaaminen epäonnistui...{NEWLINE}Tiedosto sisältää virheellistä tietoa! +STR_1051 :Näkymättömät tuet +STR_1052 :Näkymättömät ihmiset +STR_1053 :{SMALLFONT}{BLACK}Laitteet/kohteet puistossa +STR_1054 :{SMALLFONT}{BLACK}Nimeä laite/kohde +STR_1055 :{SMALLFONT}{BLACK}Nimeä henkilö +STR_1056 :{SMALLFONT}{BLACK}Nimeä henkilöstön jäsen +STR_1057 :Laitteen/kohteen nimi +STR_1058 :Kirjoita uusi nimi tälle laitteelle/kohteelle: +STR_1059 :Ei pysty uudelleennimeämään laitetta/kohdetta... +STR_1060 :Virheellinen laitteen/kohteen nimi +STR_1061 :Normaali toimintatila +STR_1062 :Toistuva kierros toimintatila +STR_1063 :Käänteinen-kallistus laukaistu sukkula toimintatila +STR_1064 :Voimalaukaisu (aseman ohimennen) +STR_1065 :Sukkulatoimintatila +STR_1066 :Veneajelutoimintatila +STR_1067 :Ylöspäin laukaisu +STR_1068 :Pyörivä hissi -toimintatila +STR_1069 :Asemalta asemalle toimintatila +STR_1070 :Yksi kyyti per sisäänpääsy +STR_1071 :Loputtomat kyydit per sisäänpääsy +STR_1072 :Labyrinttitoimintatila +STR_1073 :Kilpailutoimintatila +STR_1074 :Törmäysautotoimintatila +STR_1075 :Keinutoimintatila +STR_1076 :Kojutoimintatila +STR_1077 :Pyörimistoimintatila +STR_1078 :Eteenpäin pyöriminen +STR_1079 :Taaksepäin pyöriminen +STR_1080 :Elokuva: {ENDQUOTES}Kostavat lentäjät{ENDQUOTES} +STR_1081 :3D-elokuva: {ENDQUOTES}Hiiren hännät{ENDQUOTES} +STR_1082 :Avaruusrenkaat toimintatila +STR_1083 :Aloittelijoille toimintatila +STR_1084 :Induktiomoottorilaukaisu +STR_1085 :Elokuva: {ENDQUOTES}Jännityksen ratsastajat{ENDQUOTES} +STR_1086 :3D-elokuva: {ENDQUOTES}Myrskyn jahtaajat{ENDQUOTES} +STR_1087 :3D-elokuva: {ENDQUOTES}Avaruusryöstäjät{ENDQUOTES} +STR_1088 :Intensiivinen toimintatila +STR_1089 :Hullu toimintatila +STR_1090 :Kummitustalo toimintatila +STR_1091 :Sirkusesitys toimintatila +STR_1092 :Alaspäin laukaisu +STR_1093 :Kiero talo toimintatila +STR_1094 :Vapaapudotustoimintatila +STR_1095 :Toistuva kierros lohkojarrutuksella toiminatila +STR_1096 :Voimalaukaisu (ilman aseman ohimenemistä) +STR_1097 :Voimalaukaisu lohkojarrutuksella toimintatila +STR_1098 :Matkustetaan {POP16}{STRINGID} loppuun +STR_1099 :Odoitetaan matkustajia {POP16}{STRINGID} +STR_1100 :Odoitetaan lähtöä {POP16}{STRINGID} +STR_1101 :Lähtemässä {POP16}{STRINGID} +STR_1102 :Nopeus {VELOCITY} +STR_1103 :Saapumassa {POP16}{STRINGID} +STR_1104 :Matkustajia puretaan {POP16}{STRINGID} +STR_1105 :Nopeus {VELOCITY} +STR_1106 :Sortuu! +STR_1107 :Sortunut! +STR_1108 :Nopeus {VELOCITY} +STR_1109 :Keinuu +STR_1110 :Pyörii +STR_1111 :Pyörii +STR_1112 :Käynnissä +STR_1113 :Ohjelma pyörii +STR_1114 :Pyörii +STR_1115 :Käynnissä +STR_1116 :Käynnissä +STR_1117 :Sirkusesitys menossa +STR_1118 :Käynnissä +STR_1119 :Odotetaan kaapelihissiä +STR_1120 :Nopeus {VELOCITY} +STR_1121 :Pysäytetään +STR_1122 :Odotetaan matkustajia +STR_1123 :Odotetaan käynnistämistä +STR_1124 :Käynnistetään +STR_1125 :Käynnissä +STR_1126 :Pysäytetään +STR_1127 :Matkustajia puretaan +STR_1128 :Pysähtynyt lohkojarruihin. +STR_1129 :Kaikki ajoneuvot saman värisiä +STR_1130 :Eri värit per {STRINGID} +STR_1131 :Eri värit per ajoneuvo +STR_1132 :Ajoneuvo {POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1133 :Ajoneuvo {POP16}{COMMA16} +STR_1134 :{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} {COMMA16} +STR_1135 :{STRINGID} {COMMA16} +STR_1136 :{SMALLFONT}{BLACK}Valitse pääväri +STR_1137 :{SMALLFONT}{BLACK}Valitse valinnainen väri 1 +STR_1138 :{SMALLFONT}{BLACK}Valitse valinnainen väri 2 +STR_1139 :{SMALLFONT}{BLACK}Valitse tukirakenteiden väri +STR_1140 :{SMALLFONT}{BLACK}Valitse ajoneuvon väriteemava +STR_1141 :{SMALLFONT}{BLACK}Valitse mitä ajoneuvoa/junaa muuttaa +STR_1142 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1143 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRINGID} +STR_1144 :Ei pysty rakentamaan/siirtämään tämän laitteen/kohteen sisäänkäyntiä... +STR_1145 :Ei pysty rakentamaan/siirtämään tämän laitteen/kohteen uloskäyntiä... +STR_1146 :Sisäänkäyntiä ei ole vielä rakennettu +STR_1147 :Uloskäyntiä ei ole vielä rakennettu +STR_1148 :Neljännes kuorma +STR_1149 :Puolikas kuorma +STR_1150 :Kolmeneljäsosaa kuorma +STR_1151 :Täysi kuorma +STR_1152 :Mikä tahansa kuorma +STR_1153 :Korkeusmerkinnät laitteiden radoissa +STR_1154 :Korkeusmerkinnät maanpinnassa +STR_1155 :Korkeusmerkinnät poluissa +STR_1156 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1157 :{TICK}{MOVE_X}{SMALLFONT}{STRINGID} +STR_1158 :Tämän poistaminen ei onnistu... +STR_1159 :{SMALLFONT}{BLACK}Aseta maisemaa, puutarhoja, ja muita tilpehöörejä. +STR_1160 :{SMALLFONT}{BLACK}Luo/säädä järviä ja vettä +STR_1161 :Tätä ei voi asettaa tähän... +STR_1162 :{OUTLINE}{TOPAZ}{STRINGID} +STR_1163 :{STRINGID}{NEWLINE}(Oikea klikkaus muokkaa) +STR_1164 :{STRINGID}{NEWLINE}(Oikea klikkaus poistaa) +STR_1165 :{STRINGID} - {STRINGID} {COMMA16} +STR_1166 :Veden tasoa ei voi laskea tässä... +STR_1167 :Veden tasoa ei voi nostaa tässä... +STR_1168 :Asetukset +STR_1169 :(Ei mitään) +STR_1170 :{STRING} +STR_1171 :{RED}Suljettu - - +STR_1172 :{YELLOW}{STRINGID} - - +STR_1173 :{SMALLFONT}{BLACK}Rakenna jalkakäytäviä ja jonotuslinjoja +STR_1174 :Mainoskyltti on tiellä +STR_1175 :Tätä ei voi rakentaa kaltevalle jalkakäytävälle +STR_1176 :Jalkakäytävää ei voi rakentaa tähän... +STR_1177 :Jalkakäytävää ei voi poistaa tästä... +STR_1178 :Maan kaltevuus epäsopiva +STR_1179 :Jalkakäytävä on tiellä +STR_1180 :Tätä ei voi rakentaa veden alle! +STR_1181 :Jalkakäytävät +STR_1182 :Tyyppi +STR_1183 :Suunta +STR_1184 :Mäki +STR_1185 :{SMALLFONT}{BLACK}Suunta +STR_1186 :{SMALLFONT}{BLACK}Mäki alas +STR_1187 :{SMALLFONT}{BLACK}Tasanne +STR_1188 :{SMALLFONT}{BLACK}Mäki ylös +STR_1189 :{SMALLFONT}{BLACK}Rakenna valittu jalkakäytävän osio +STR_1190 :{SMALLFONT}{BLACK}Poista valittu jalkakäytävän osio +STR_1191 :{BLACK}{STRINGID} +STR_1192 :{OUTLINE}{RED}{STRINGID} +STR_1193 :{WINDOW_COLOUR_2}{STRINGID} +STR_1194 :Suljettu +STR_1195 :Testiajo +STR_1196 :Auki +STR_1197 :Rikki +STR_1198 :Sortunut! +STR_1199 :{COMMA16} henkilö laitteessa +STR_1200 :{COMMA16} henkilöä laitteessa +STR_1201 :Ei ketään jonossa +STR_1202 :1 henkilö jonossa +STR_1203 :{COMMA16} henkilöä jonossa +STR_1204 :{COMMA16} minuutin jonotusaika +STR_1205 :{COMMA16} minuutin jonotusaika +STR_1206 :{WINDOW_COLOUR_2}Odota: +STR_1207 :{WINDOW_COLOUR_2}Lähde jos toinen juna saapuu asemalle +STR_1208 :{WINDOW_COLOUR_2}Lähde jos toinen vene saapuu asemalle +STR_1209 :{SMALLFONT}{BLACK}Valitse pitäisikö odottaa matkustajia ennen lähtöä +STR_1210 :{SMALLFONT}{BLACK}Valitse pitäisikö lähteä jos toinen vaunu saapuu samalle asemalle +STR_1211 :{WINDOW_COLOUR_2}Vähimmäisodotusaika: +STR_1212 :{WINDOW_COLOUR_2}Enimmäisodotusaika: +STR_1213 :{SMALLFONT}{BLACK}Valitse vähimmäisodotusaika ennen lähtöä +STR_1214 :{SMALLFONT}{BLACK}Valitse enimmäisodotusaika ennen lähtöä +STR_1215 :{WINDOW_COLOUR_2}Synkronoi rinnakkaisasemien kanssa +STR_1216 :{SMALLFONT}{BLACK}Valitse pitäisikö synkronoida lähtö kaikkien rinnakkaisasemien kanssa ('kilpailua' varten) +STR_1217 :{COMMA16} sekuntia +STR_1218 :{BLACK}{SMALLUP} +STR_1219 :{BLACK}{SMALLDOWN} +STR_1220 :Vain uloskäynti +STR_1221 :Ei sisäänkäyntiä +STR_1222 :Ei uloskäyntiä +STR_1223 :{SMALLFONT}{BLACK}Kuljetuslaitteet +STR_1224 :{SMALLFONT}{BLACK}Lempeät laitteet +STR_1225 :{SMALLFONT}{BLACK}Vuoristoradat +STR_1226 :{SMALLFONT}{BLACK}Jännittävät radat +STR_1227 :{SMALLFONT}{BLACK}Vesilaitteet +STR_1228 :{SMALLFONT}{BLACK}Kaupat ja kojut +STR_1229 :juna +STR_1230 :junaa +STR_1231 :Juna +STR_1232 :junaa +STR_1233 :{COMMA16} juna +STR_1234 :{COMMA16} junaa +STR_1235 :Juna {COMMA16} +STR_1236 :vene +STR_1237 :venettä +STR_1238 :Vene +STR_1239 :Venettä +STR_1240 :{COMMA16} vene +STR_1241 :{COMMA16} venettä +STR_1242 :Vene {COMMA16} +STR_1243 :rata +STR_1244 :rataa +STR_1245 :Rata +STR_1246 :Rataa +STR_1247 :{COMMA16} rata +STR_1248 :{COMMA16} rataa +STR_1249 :Rata {COMMA16} +STR_1250 :telakointitasanne +STR_1251 :telakointitasanteita +STR_1252 :Telakointitasanne +STR_1253 :Telakointitasanteita +STR_1254 :{COMMA16} telakointitasanne +STR_1255 :{COMMA16} telakointitasanteita +STR_1256 :Telakointitasanne {COMMA16} +STR_1257 :asema +STR_1258 :asemaa +STR_1259 :Asema +STR_1260 :Asemaa +STR_1261 :{COMMA16} asema +STR_1262 :{COMMA16} asemaa +STR_1263 :Asema {COMMA16} +STR_1264 :auto +STR_1265 :autoa +STR_1266 :Auto +STR_1267 :Autoa +STR_1268 :{COMMA16} auto +STR_1269 :{COMMA16} autoa +STR_1270 :Auto {COMMA16} +STR_1271 :rakennus +STR_1272 :rakennusta +STR_1273 :Rakennus +STR_1274 :Rakennusta +STR_1275 :{COMMA16} rakennus +STR_1276 :{COMMA16} rakennusta +STR_1277 :Rakennus {COMMA16} +STR_1278 :rakennelma +STR_1279 :rakennelmia +STR_1280 :Rakennelma +STR_1281 :Rakennelmia +STR_1282 :{COMMA16} rakennelma +STR_1283 :{COMMA16} rakennelmaa +STR_1284 :Rakennelma {COMMA16} +STR_1285 :laiva +STR_1286 :laivaa +STR_1287 :Laiva +STR_1288 :Laivaa +STR_1289 :{COMMA16} laiva +STR_1290 :{COMMA16} laivaa +STR_1291 :Laiva {COMMA16} +STR_1292 :koju +STR_1293 :kojua +STR_1294 :Koju +STR_1295 :Kojua +STR_1296 :{COMMA16} koju +STR_1297 :{COMMA16} kojua +STR_1298 :Koju {COMMA16} +STR_1299 :pyörä +STR_1300 :pyörää +STR_1301 :Pyörä +STR_1302 :Pyörää +STR_1303 :{COMMA16} pyörä +STR_1304 :{COMMA16} pyörää +STR_1305 :Pyörä {COMMA16} +STR_1306 :rengas +STR_1307 :rengasta +STR_1308 :Rengas +STR_1309 :Rengasta +STR_1310 :{COMMA16} rengas +STR_1311 :{COMMA16} rengasta +STR_1312 :Rengas {COMMA16} +STR_1313 :pelaaja +STR_1314 :pelaajaa +STR_1315 :Pelaaja +STR_1316 :Pelaajaa +STR_1317 :{COMMA16} pelaaja +STR_1318 :{COMMA16} pelaajaa +STR_1319 :Pelaaja {COMMA16} +STR_1320 :rata +STR_1321 :rataa +STR_1322 :Rata +STR_1323 :Rataa +STR_1324 :{COMMA16} rata +STR_1325 :{COMMA16} rataa +STR_1326 :Rata {COMMA16} +STR_1327 :{SMALLFONT}{BLACK}Käännä esineitä 90{DEGREE} +STR_1328 :Vaatii tasaisen maan +STR_1329 :{WINDOW_COLOUR_2}Lähtönopeus: +STR_1330 :{SMALLFONT}{BLACK}Enimmäisnopeus kun lähdetään asemalta +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} - Sisäänkäynti{POP16}{POP16} +STR_1336 :{STRINGID} - Asema {POP16}{COMMA16} Sisäänkäynti +STR_1337 :{STRINGID} - Uloskäynti{POP16}{POP16} +STR_1338 :{STRINGID} - Asema {POP16}{COMMA16} Uloskäynti +STR_1339 :{BLACK}Testituloksia ei ole vielä saatavilla... +STR_1340 :{WINDOW_COLOUR_2}Suurin nopeus: {BLACK}{VELOCITY} +STR_1341 :{WINDOW_COLOUR_2}Ajelun kesto: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1342 :{DURATION} +STR_1343 :{DURATION} / +STR_1344 :{WINDOW_COLOUR_2}Radan pituus: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1345 :{LENGTH} +STR_1346 :{LENGTH} / +STR_1347 :{WINDOW_COLOUR_2}Keskinopeus: {BLACK}{VELOCITY} +STR_1348 :{WINDOW_COLOUR_2}Suurin positiivinen vertikaalinen G-voima: {BLACK}{COMMA2DP32}g +STR_1349 :{WINDOW_COLOUR_2}Suurin positiivinen vertikaalinen G-voima: {OUTLINE}{RED}{COMMA2DP32}g +STR_1350 :{WINDOW_COLOUR_2}Suurin negatiivinen vertikaalinen G-voima: {BLACK}{COMMA2DP32}g +STR_1351 :{WINDOW_COLOUR_2}Suurin negatiivinen vertikaalinen G-voima: {OUTLINE}{RED}{COMMA2DP32}g +STR_1352 :{WINDOW_COLOUR_2}Suurin sivuttainen G-voima: {BLACK}{COMMA2DP32}g +STR_1353 :{WINDOW_COLOUR_2}Suurin sivuttainen G-voima: {OUTLINE}{RED}{COMMA2DP32}g +STR_1354 :{WINDOW_COLOUR_2}Korkein pudotuskorkeus: {BLACK}{LENGTH} +STR_1355 :{WINDOW_COLOUR_2}Pudotuksia: {BLACK}{COMMA16} +STR_1356 :{WINDOW_COLOUR_2}Käänteitä: {BLACK}{COMMA16} +STR_1357 :{WINDOW_COLOUR_2}Reikää: {BLACK}{COMMA16} +STR_1358 :{WINDOW_COLOUR_2}ilma-aika' yhteensä: {BLACK}{COMMA2DP32}secs +STR_1359 :{WINDOW_COLOUR_2}Jonotusaika: {BLACK}{COMMA16} minuutti +STR_1360 :{WINDOW_COLOUR_2}Jonotusaika: {BLACK}{COMMA16} minuuttia +STR_1361 :Nopeuden muuttaminen ei onnistu... +STR_1362 :Lähtönopeuden muuttaminen ei onnistu... +STR_1363 :Liian korkealla tukia varten! +STR_1364 :Ylemmän laitteen tukia ei voida laajentaa pidemmälle! +STR_1365 :Hallittava kierre (vasen) +STR_1366 :Hallittava kierre (oikea) +STR_1367 :Puolikas silmukka +STR_1368 :Puolikas korkkiruuvi (vasen) +STR_1369 :Puolikas korkkiruuvi (oikea) +STR_1370 :Tynnyrivierre (vasen) +STR_1371 :Tynnyrivierre (oikea) +STR_1372 :Laukaistu nostomäki +STR_1373 :Iso puolikas silmukka (vasen) +STR_1374 :Iso puolikas silmukka (oikea) +STR_1375 :Ylempi siirto +STR_1376 :Alempi siirto +STR_1377 :Sydämen viiva vierähdys (vasen) +STR_1378 :Sydämen viiva vierähdys (oikea) +STR_1379 :Käännin (vasen) +STR_1380 :Käännin (oikea) +STR_1381 :Kaareva nostomäki (vasen) +STR_1382 :Kaareva nostomäki (oikea) +STR_1383 :Neljännesosa silmukka +STR_1384 :{YELLOW}{STRINGID} +STR_1385 :{SMALLFONT}{BLACK}Muut radan asetukset +STR_1386 :Erikoinen... +STR_1387 :Maan tyyppiä ei voida muuttaa... +STR_1388 :{OUTLINE}{GREEN}+ {CURRENCY} +STR_1389 :{OUTLINE}{RED}- {CURRENCY} +STR_1390 :{CURRENCY2DP} +STR_1391 :{RED}{CURRENCY2DP} +STR_1392 :{SMALLFONT}{BLACK}Näkymä laitteesta/kohteesta +STR_1393 :{SMALLFONT}{BLACK}Kulkuneuvon yksitoiskohdat ja asetukset +STR_1394 :{SMALLFONT}{BLACK}Toiminta-asetukset +STR_1395 :{SMALLFONT}{BLACK}Huoltoasetukset +STR_1396 :{SMALLFONT}{BLACK}Värityylin asetukset +STR_1397 :{SMALLFONT}{BLACK}Ääni- ja musiikkiasetukset +STR_1398 :{SMALLFONT}{BLACK}Mitat- ja testitiedot +STR_1399 :{SMALLFONT}{BLACK}Kaaviokuvat +STR_1400 :Sisäänkäynti +STR_1401 :Uloskäynti +STR_1402 :{SMALLFONT}{BLACK}Rakenna tai siirrä sisäänkäynti laitteesta/kohteesta +STR_1403 :{SMALLFONT}{BLACK}Rakenna tai siirrä uloskäynti laitteesta/kohteesta +STR_1404 :{SMALLFONT}{BLACK}Käännä 90{DEGREE} +STR_1405 :{SMALLFONT}{BLACK}Peilaa kuva +STR_1406 :{SMALLFONT}{BLACK}Vaihda maisema päälle/pois (vain jos saatavilla tälle suunnitelmalle) +STR_1407 :{WINDOW_COLOUR_2}Rakenna tämä... +STR_1408 :{WINDOW_COLOUR_2}Kustannus: {BLACK}{CURRENCY} +STR_1409 :Sisään-/uloskäyntitasanne +STR_1410 :Pystysuora torni +STR_1411 :{STRINGID} tiellä +STR_1412 :{WINDOW_COLOUR_3}Tietojen keruu ei ole saatavilla tämäntyyppiselle laitteelle +STR_1413 :{WINDOW_COLOUR_3}Tietojen keruu alkaa kun seuraava {STRINGID} lähtee {STRINGID} +STR_1414 :{SMALLFONT}{BLACK}{DURATION} +STR_1415 :{WINDOW_COLOUR_2}Nopeus +STR_1416 :{WINDOW_COLOUR_2}Korkeus +STR_1417 :{WINDOW_COLOUR_2}Vert. G-voima +STR_1418 :{WINDOW_COLOUR_2}Sivut. G-voima +STR_1419 :{SMALLFONT}{BLACK}{VELOCITY} +STR_1420 :{SMALLFONT}{BLACK}{LENGTH} +STR_1421 :{SMALLFONT}{BLACK}{COMMA16}g +STR_1422 :{SMALLFONT}{BLACK}Kerätään tietoja {POP16}{STRINGID} +STR_1423 :{SMALLFONT}{BLACK}Jonolinjaston tie +STR_1424 :{SMALLFONT}{BLACK}Jalkakäytävä +STR_1425 :Jalkakäytävä +STR_1426 :Jonolinjasto +STR_1427 :{WINDOW_COLOUR_2}Asiakkaita: {BLACK}{COMMA32} per tunti +STR_1428 :{WINDOW_COLOUR_2}Sisäänpääsymaksu: +STR_1429 :{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1430 :Ilmainen +STR_1431 :Kävelee +STR_1432 :Menossa kohti {STRINGID} +STR_1433 :Jonottaa {STRINGID} +STR_1434 :Hukkuu +#these following 3 would require extra coding, so i will leave them default for now +STR_1435 :On {STRINGID} +STR_1436 :In {STRINGID} +STR_1437 :At {STRINGID} +STR_1438 :Istuu +STR_1439 :(valitse sijainti) +STR_1440 :Leikkaa ruohoa +STR_1441 :Harjaa jalkakäytävää +STR_1442 :Tyhjentää roskakoria +STR_1443 :Kastelee puutarhoja +STR_1444 :Katsoo {STRINGID} +STR_1445 :Katsoo {STRINGID}:n rakentamista +STR_1446 :Katselee maisemia +STR_1447 :Lähdössä puistosta +STR_1448 :Katsoo uuden laitteen rakentamista +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 :Vieraan nimi +STR_1453 :Kirjoita nimi vieraalle: +STR_1454 :Vieraan nimeäminen ei onnistu... +STR_1455 :Virheellinen nimi vieraalle +STR_1456 :{WINDOW_COLOUR_2}Rahaa käytetty: {BLACK}{CURRENCY2DP} +STR_1457 :{WINDOW_COLOUR_2}Rahaa taskussa: {BLACK}{CURRENCY2DP} +STR_1458 :{WINDOW_COLOUR_2}Aikaa kulutettu puistossa: {BLACK}{REALTIME} +STR_1459 :Radan tyyli +STR_1460 :{SMALLFONT}{BLACK}'U':n muotoinen avoin rata +STR_1461 :{SMALLFONT}{BLACK}'O':n muotoinen ympäröity rata +STR_1462 :Liian jyrkkä nostomäkeä varten +STR_1463 :Vieraat +STR_1464 :Ruuvikierre ylös (pieni) +STR_1465 :Ruuvikierre ylös (iso) +STR_1466 :Ruuvikierre alas (pieni) +STR_1467 :Ruuvikierre alas (iso) +STR_1468 :Henkilökunta +STR_1469 :Laitteen pitää alkaa ja loppua asemilla +STR_1470 :Asema ei ole tarpeeksi pitkä +STR_1471 :{WINDOW_COLOUR_2}Nopeus: +STR_1472 :{SMALLFONT}{BLACK}Tämän laitteen nopeus +STR_1473 :{WINDOW_COLOUR_2}Jännityksen arvosana: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1474 :{WINDOW_COLOUR_2}Jännityksen arvosana: {BLACK}Ei viellä saatavilla +STR_1475 :{WINDOW_COLOUR_2}Intensiteettiarvosana: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1476 :{WINDOW_COLOUR_2}Intensiteettiarvosana: {BLACK}Ei viellä saatavilla +STR_1477 :{WINDOW_COLOUR_2}Intensiteettiarvosana: {OUTLINE}{RED}{COMMA2DP32} ({STRINGID}) +STR_1478 :{WINDOW_COLOUR_2}Pahoinvoinnin arvosana: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1479 :{WINDOW_COLOUR_2}Pahoinvoinnin arvosana: {BLACK}Ei viellä saatavilla +STR_1480 :{SMALLFONT}{OPENQUOTES}Minulla ei ole varaa mennä {STRINGID}{ENDQUOTES} +STR_1481 :{SMALLFONT}{OPENQUOTES}Kulutin kaikki rahani{ENDQUOTES} +STR_1482 :{SMALLFONT}{OPENQUOTES}Tunnen oloni kamalaksi{ENDQUOTES} +STR_1483 :{SMALLFONT}{OPENQUOTES}Tunnen oloni todella kamalaksi{ENDQUOTES} +STR_1484 :{SMALLFONT}{OPENQUOTES}Tahdon mennä johonkin jännittävämpään kuin {STRINGID}{ENDQUOTES} +STR_1485 :{SMALLFONT}{OPENQUOTES}{STRINGID} näyttää liian hurjalta minulle{ENDQUOTES} +STR_1486 :{SMALLFONT}{OPENQUOTES}En ole syönyt/juonut {STRINGID} loppuun vielä{ENDQUOTES} +STR_1487 :{SMALLFONT}{OPENQUOTES}Pelkästään {STRINGID} katsominen saa minut tuntemaan oloni kamalaksi{ENDQUOTES} +STR_1488 :{SMALLFONT}{OPENQUOTES}En aio maksaa noin paljon päästäkseni {STRINGID}{ENDQUOTES} +STR_1489 :{SMALLFONT}{OPENQUOTES}Haluan kotiin{ENDQUOTES} +STR_1490 :{SMALLFONT}{OPENQUOTES}{STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1491 :{SMALLFONT}{OPENQUOTES}Minulla on jo {STRINGID}{ENDQUOTES} +STR_1492 :{SMALLFONT}{OPENQUOTES}Minulla ei ole varaa ostaa {STRINGID}{ENDQUOTES} +STR_1493 :{SMALLFONT}{OPENQUOTES}Minulla ei ole nälkä{ENDQUOTES} +STR_1494 :{SMALLFONT}{OPENQUOTES}Minulla ei ole jano{ENDQUOTES} +STR_1495 :{SMALLFONT}{OPENQUOTES}Apua! Hukun!{ENDQUOTES} +STR_1496 :{SMALLFONT}{OPENQUOTES}Olen eksynyt!{ENDQUOTES} +STR_1497 :{SMALLFONT}{OPENQUOTES}{STRINGID} oli mahtava{ENDQUOTES} +STR_1498 :{SMALLFONT}{OPENQUOTES}Olen jonottanut ikuisuuden kohteeseen {STRINGID}{ENDQUOTES} +STR_1499 :{SMALLFONT}{OPENQUOTES}Olen väsynyt{ENDQUOTES} +STR_1500 :{SMALLFONT}{OPENQUOTES}Minulla on nälkä{ENDQUOTES} +STR_1501 :{SMALLFONT}{OPENQUOTES}Minulla on jano{ENDQUOTES} +STR_1502 :{SMALLFONT}{OPENQUOTES}Minun tarvitsee käydä vessassa{ENDQUOTES} +STR_1503 :{SMALLFONT}{OPENQUOTES}En löydä {STRINGID}{ENDQUOTES} +STR_1504 :{SMALLFONT}{OPENQUOTES}En aio maksaa noin paljon käyttääkseni {STRINGID}{ENDQUOTES} +STR_1505 :{SMALLFONT}{OPENQUOTES}Täällä sataa, en halua mennä kohteeseen {STRINGID}{ENDQUOTES} +STR_1506 :{SMALLFONT}{OPENQUOTES}Täällä on todella paljon roskaa{ENDQUOTES} +STR_1507 :{SMALLFONT}{OPENQUOTES}En löydä puiston uloskäyntiä{ENDQUOTES} +STR_1508 :{SMALLFONT}{OPENQUOTES}Tahdon pois kohteesta {STRINGID}{ENDQUOTES} +STR_1509 :{SMALLFONT}{OPENQUOTES}Tahdon ulos kohteesta {STRINGID}{ENDQUOTES} +STR_1510 :{SMALLFONT}{OPENQUOTES}En mene kohteeseen {STRINGID} - Se ei ole turvallinen{ENDQUOTES} +STR_1511 :{SMALLFONT}{OPENQUOTES}Tämä tie on kuvottava{ENDQUOTES} +STR_1512 :{SMALLFONT}{OPENQUOTES}Täällä on liikaa tungosta{ENDQUOTES} +STR_1513 :{SMALLFONT}{OPENQUOTES}Täällä on todella paljon ilkivaltaa{ENDQUOTES} +STR_1514 :{SMALLFONT}{OPENQUOTES}Mahtava maisema!{ENDQUOTES} +STR_1515 :{SMALLFONT}{OPENQUOTES}Tämä puisto on todella puhdas ja siisti{ENDQUOTES} +STR_1516 :{SMALLFONT}{OPENQUOTES}Hyppivät suihkulähteet ovat todella mahtavia!{ENDQUOTES} +STR_1517 :{SMALLFONT}{OPENQUOTES}Täällä oleva musiikki on hienoa{ENDQUOTES} +STR_1518 :{SMALLFONT}{OPENQUOTES}Tämä ilmapallo kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1519 :{SMALLFONT}{OPENQUOTES}Tämä pehmolelu kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1520 :{SMALLFONT}{OPENQUOTES}Tämä puiston kartta kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1521 :{SMALLFONT}{OPENQUOTES}Tämä kuva kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1522 :{SMALLFONT}{OPENQUOTES}Tämä sateenvarjo kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1523 :{SMALLFONT}{OPENQUOTES}Tämä juoma kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1524 :{SMALLFONT}{OPENQUOTES}Tämä hampurilainen kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1525 :{SMALLFONT}{OPENQUOTES}Nämä ranskalaiset kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1526 :{SMALLFONT}{OPENQUOTES}Tämä jäätelö kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1527 :{SMALLFONT}{OPENQUOTES}Tämä hattara kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1528 : +STR_1529 : +STR_1530 : +STR_1531 :{SMALLFONT}{OPENQUOTES}Tämä pitsa kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1532 : +STR_1533 :{SMALLFONT}{OPENQUOTES}Tämä popcorn kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1534 :{SMALLFONT}{OPENQUOTES}Tämä nakkisämpylä kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1535 :{SMALLFONT}{OPENQUOTES}Tämä lonkero kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1536 :{SMALLFONT}{OPENQUOTES}Tämä hattu kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1537 :{SMALLFONT}{OPENQUOTES}Tämä toffeeomena kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1538 :{SMALLFONT}{OPENQUOTES}Tämä t-paita kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1539 :{SMALLFONT}{OPENQUOTES}Tämä donitsi kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1540 :{SMALLFONT}{OPENQUOTES}Tämä kahvi kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1541 : +STR_1542 :{SMALLFONT}{OPENQUOTES}Tämä friteerattu kana kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1543 :{SMALLFONT}{OPENQUOTES}Tämä limonaati {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1544 : +STR_1545 : +STR_1546 : +STR_1547 : +STR_1548 : +STR_1549 : +STR_1550 :{SMALLFONT}{OPENQUOTES}Vau!{ENDQUOTES} +STR_1551 :{SMALLFONT}{OPENQUOTES}Minulla on outo fiilis että joku katselee minua{ENDQUOTES} +STR_1552 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon ilmapallosta kojussa {STRINGID}{ENDQUOTES} +STR_1553 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon pehmolelusta kojussa {STRINGID}{ENDQUOTES} +STR_1554 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon puiston kartasta kojussa {STRINGID}{ENDQUOTES} +STR_1555 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon kuvasta kojussa {STRINGID}{ENDQUOTES} +STR_1556 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon sateenvarjosta kojussa {STRINGID}{ENDQUOTES} +STR_1557 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon juomasta kojussa {STRINGID}{ENDQUOTES} +STR_1558 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon hampurilaisesta kojussa {STRINGID}{ENDQUOTES} +STR_1559 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon ranskalaisista kojussa {STRINGID}{ENDQUOTES} +STR_1560 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon jäätelöstä kojussa {STRINGID}{ENDQUOTES} +STR_1561 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon hattarasta kojussa {STRINGID}{ENDQUOTES} +STR_1562 : +STR_1563 : +STR_1564 : +STR_1565 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon hattarasta kojussa {STRINGID}{ENDQUOTES} +STR_1566 : +STR_1567 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon popcornista kojussa {STRINGID}{ENDQUOTES} +STR_1568 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon nakkisämpylästä kojussa {STRINGID}{ENDQUOTES} +STR_1569 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon lonkerosta kojussa {STRINGID}{ENDQUOTES} +STR_1570 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon hatusta kojussa {STRINGID}{ENDQUOTES} +STR_1571 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon toffeeomenasta kojussa {STRINGID}{ENDQUOTES} +STR_1572 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon t-paidasta kojussa {STRINGID}{ENDQUOTES} +STR_1573 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon donitsista kojussa {STRINGID}{ENDQUOTES} +STR_1574 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon kahvista kojussa {STRINGID}{ENDQUOTES} +STR_1575 : +STR_1576 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon friteeratusta kanasta kojussa {STRINGID}{ENDQUOTES} +STR_1577 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon limonaatista kojussa {STRINGID}{ENDQUOTES} +STR_1578 : +STR_1579 : +STR_1580 : +STR_1581 : +STR_1582 : +STR_1583 : +STR_1584 :{SMALLFONT}{OPENQUOTES}Tämä kuva kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1585 :{SMALLFONT}{OPENQUOTES}Tämä kuva kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1586 :{SMALLFONT}{OPENQUOTES}Tämä kuva kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1587 :{SMALLFONT}{OPENQUOTES}Tämä viipurinrinkeli kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1588 :{SMALLFONT}{OPENQUOTES}Tämä kuuma kaakao kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1589 :{SMALLFONT}{OPENQUOTES}Tämä jäätee kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1590 :{SMALLFONT}{OPENQUOTES}Tämä tippaleipä kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1591 :{SMALLFONT}{OPENQUOTES}TNämä aurinkolasit kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1592 :{SMALLFONT}{OPENQUOTES}Nämä häränlihanuudelit kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1593 :{SMALLFONT}{OPENQUOTES}Nämä paistetut riisinuudelit kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1594 :{SMALLFONT}{OPENQUOTES}Tämä wontonkeitto kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1595 :{SMALLFONT}{OPENQUOTES}Tämä lihapullakeitto kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1596 :{SMALLFONT}{OPENQUOTES}Tämä hedelmämehu kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1597 :{SMALLFONT}{OPENQUOTES}Tämä soijamaito kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1598 :{SMALLFONT}{OPENQUOTES}Tämä sujongkwa kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1599 :{SMALLFONT}{OPENQUOTES}Tämä pantonki kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1600 :{SMALLFONT}{OPENQUOTES}Tämä keksi kojusta {STRINGID} on todella hyvän arvoinen{ENDQUOTES} +STR_1601 : +STR_1602 : +STR_1603 : +STR_1604 :{SMALLFONT}{OPENQUOTES}Tämä grillattu makkara kojusta {STRINGID} on todella hyvän arvoinen{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}En maksa noin paljon kuvasta kojussa {STRINGID}{ENDQUOTES} +STR_1617 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon kuvasta kojussa {STRINGID}{ENDQUOTES} +STR_1618 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon kuvasta kojussa {STRINGID}{ENDQUOTES} +STR_1619 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon viipurinrinkelistä kojussa {STRINGID}{ENDQUOTES} +STR_1620 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon kaakaosta kojussa {STRINGID}{ENDQUOTES} +STR_1621 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon jääteestä kojussa {STRINGID}{ENDQUOTES} +STR_1622 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon tippaleivästä kojussa {STRINGID}{ENDQUOTES} +STR_1623 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon aurinkolaseista kojussa {STRINGID}{ENDQUOTES} +STR_1624 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon härkänuudeleista kojussa {STRINGID}{ENDQUOTES} +STR_1625 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon paistetusta riisinuudeleista kojussa {STRINGID}{ENDQUOTES} +STR_1626 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon wontonkeitosta kojussa {STRINGID}{ENDQUOTES} +STR_1627 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon lihapullakeitosta kojussa {STRINGID}{ENDQUOTES} +STR_1628 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon hedelmämehusta kojussa {STRINGID}{ENDQUOTES} +STR_1629 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon soijamaidosta kojussa {STRINGID}{ENDQUOTES} +STR_1630 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon sujongkwasta kojussa {STRINGID}{ENDQUOTES} +STR_1631 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon patongista kojussa {STRINGID}{ENDQUOTES} +STR_1632 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon keksistä kojussa {STRINGID}{ENDQUOTES} +STR_1633 : +STR_1634 : +STR_1635 : +STR_1636 :{SMALLFONT}{OPENQUOTES}En maksa noin paljon grillatusta makkarasta kojussa {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}Auta! Laske minut alas!{ENDQUOTES} +STR_1649 :{SMALLFONT}{OPENQUOTES}Rahat ovat loppumassa!{ENDQUOTES} +STR_1650 :{SMALLFONT}{OPENQUOTES}Vau! Uutta laitetta rakennetaan!{ENDQUOTES} +STR_1651 :{SMALLFONT}{OPENQUOTES}Hieno laite! Mutta se ei ole yhtä hyvä kuin Phoenix...{ENDQUOTES} +STR_1652 :{SMALLFONT}{OPENQUOTES}Olen niin innoissani - se on Intaminlaite!{ENDQUOTES} +STR_1653 :{SMALLFONT}{OPENQUOTES}...ja tässä me olemme {STRINGID}!{ENDQUOTES} +STR_1654 :{WINDOW_COLOUR_2}Viimeisimmät ajatukset: +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}Onnellisuus: +STR_1663 :{WINDOW_COLOUR_2}Nausea: +STR_1664 :{WINDOW_COLOUR_2}Energia: +STR_1665 :{WINDOW_COLOUR_2}Nälkä: +STR_1666 :{WINDOW_COLOUR_2}Jano: +STR_1667 :{WINDOW_COLOUR_2}Vessa: +STR_1668 :{WINDOW_COLOUR_2}Tyytyväisyys: {BLACK}Tuntematon +STR_1669 :{WINDOW_COLOUR_2}Tyytyväisyys: {BLACK}{COMMA16}% +STR_1670 :{WINDOW_COLOUR_2}Asiakkaiden määrä: {BLACK}{COMMA32} +STR_1671 :{WINDOW_COLOUR_2}Kokonaistuotanto: {BLACK}{CURRENCY2DP} +STR_1672 :Jarrut +STR_1673 :Spinning Control Toggle Track +STR_1674 :Jarrutusnopeus +STR_1675 :{POP16}{VELOCITY} +STR_1676 :{SMALLFONT}{BLACK}Set speed limit for brakes +STR_1677 :{WINDOW_COLOUR_2}Suosio: {BLACK}Tuntematon +STR_1678 :{WINDOW_COLOUR_2}Suosio: {BLACK}{COMMA16}% +STR_1679 :Helix up (left) +STR_1680 :Helix up (right) +STR_1681 :Helix down (left) +STR_1682 :Helix down (right) +STR_1683 :Base size 2 x 2 +STR_1684 :Base size 4 x 4 +STR_1685 :Base size 2 x 4 +STR_1686 :Base size 5 x 1 +STR_1687 :Water splash +STR_1688 :Base size 4 x 1 +STR_1689 :Block brakes +STR_1690 :{WINDOW_COLOUR_2}{STRINGID}{NEWLINE}{BLACK}{STRINGID} +STR_1691 :{WINDOW_COLOUR_2} Hinta: {BLACK}{CURRENCY} +STR_1692 :{WINDOW_COLOUR_2} Cost: {BLACK}from {CURRENCY} +STR_1693 :{SMALLFONT}{BLACK}Vieraat +STR_1694 :{SMALLFONT}{BLACK}Henkilökunta +STR_1695 :{SMALLFONT}{BLACK}Tulot ja kulut +STR_1696 :{SMALLFONT}{BLACK}Asiakkaan tiedot +STR_1697 :Cannot place these on queue line area +STR_1698 :Can only place these on queue area +STR_1699 :Liikaa henkilöitä pelissä +STR_1700 :Palkkaa uusi yleismies +STR_1701 :Palkkaa uusi mekaanikko +STR_1702 :Palkkaa uusi vartija +STR_1703 :Palkkaa uusi viihdyttäjä +STR_1704 :Henkilökunnan palkkaaminen ei onnistu... +STR_1705 :{SMALLFONT}{BLACK}Irtisano tämä henkilökunnan jäsen +STR_1706 :{SMALLFONT}{BLACK}Siirrä tämä henkilö uuteen sijaintiin +STR_1707 :Liikaa henkilökuntaa pelissä +STR_1708 :{SMALLFONT}{BLACK}Set patrol area for this staff member +STR_1709 :Irtisano henkilökunta +STR_1710 :Kyllä +STR_1711 :{WINDOW_COLOUR_1}Are you sure you want to sack {STRINGID}? +STR_1712 :{INLINE_SPRITE}{247}{19}{00}{00}{WINDOW_COLOUR_2}Harjaa jalkakäytävät +STR_1713 :{INLINE_SPRITE}{248}{19}{00}{00}{WINDOW_COLOUR_2}Kastele puutarhat +STR_1714 :{INLINE_SPRITE}{249}{19}{00}{00}{WINDOW_COLOUR_2}Tyhjennä roskakorit +STR_1715 :{INLINE_SPRITE}{250}{19}{00}{00}{WINDOW_COLOUR_2}Leikkaa ruohoa +STR_1716 :Virheellinen nimi puistolle +STR_1717 :Puiston nimeäminen ei onnistunut... +STR_1718 :Puiston nimi +STR_1719 :Anna nimi puistolle: +STR_1720 :{SMALLFONT}{BLACK}Nimeä puisto +STR_1721 :Puisto suljettu +STR_1722 :Puisto auki +STR_1723 :Puiston avaus ei onnistunut... +STR_1724 :Puiston sulkeminen ei onnistunut... +STR_1725 :Maan ostaminen ei onnistunut... +STR_1726 :Maa ei ole myytävänä! +STR_1727 :Rakennusoikeudet eivät ole myytävänä! +STR_1728 :Rakennusoikeuksia ei voi ostaa tähän... +STR_1729 :Maa ei ole puiston omistuksessa! +STR_1730 :{RED}Suljettu - - +STR_1731 :{WHITE}{STRINGID} - - +STR_1732 :Build +STR_1733 :Mode +STR_1734 :{WINDOW_COLOUR_2}Kierroston määrä: +STR_1735 :{SMALLFONT}{BLACK}Kierrosten määrä radalla +STR_1736 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1737 :{COMMA16} +STR_1738 :Kierrosten määrää ei voitu muuttaa... +STR_1739 :Kisan voitti vieras {INT32} +STR_1740 :Kisan voitti {STRINGID} +STR_1741 :Ei ole vielä rakennettu ! +STR_1742 :{WINDOW_COLOUR_2}Max. people on ride: +STR_1743 :{SMALLFONT}{BLACK}Maximum number of people allowed on this ride at one time +STR_1744 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1745 :{COMMA16} +STR_1746 :Tätä ei voitu muuttaa... +STR_1747 :{WINDOW_COLOUR_2}Aikarajoitus: +STR_1748 :{SMALLFONT}{BLACK}Aikarajoitus ajelulle +STR_1749 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{DURATION} +STR_1750 :{DURATION} +STR_1751 :Aikarajoitusta ajelulle ei voitu muuttaa... +STR_1752 :{SMALLFONT}{BLACK}Näytä puiston yksittäiset vieraat +STR_1753 :{SMALLFONT}{BLACK}Näytä puiston vieraat yhteenvetona +STR_1754 :{BLACK}{COMMA16} vieraat +STR_1755 :{BLACK}{COMMA16} vieras +STR_1756 :{WINDOW_COLOUR_2}Sisäänpääsymaksu: +STR_1757 :{WINDOW_COLOUR_2}Luotettavuus: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1758 :{SMALLFONT}{BLACK}Build mode +STR_1759 :{SMALLFONT}{BLACK}Move mode +STR_1760 :{SMALLFONT}{BLACK}Fill-in mode +STR_1761 :{SMALLFONT}{BLACK}Rakenna labyrinttia tähän suuntaan +STR_1762 :Vesiputoukset +STR_1763 :Kosket +STR_1764 :Log Bumps +STR_1765 :On-ride photo section +STR_1766 :Reverser turntable +STR_1767 :Pyörivä tunneli +STR_1768 :Heilahdusten määrää ei voitu muuttaa... +STR_1769 :{WINDOW_COLOUR_2}Heilahdusten määrä: +STR_1770 :{SMALLFONT}{BLACK}Kokonaisten heilahdusten määrä +STR_1771 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1772 :{COMMA16} +STR_1773 :Only one on-ride photo section allowed per ride +STR_1774 :Only one cable lift hill allowed per ride +STR_1775 :Pois päältä +STR_1776 :Päällä +STR_1777 :{WINDOW_COLOUR_2}Musiikki +STR_1778 :{STRINGID} - - +STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Pandapuku +STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tiikeripuku +STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} Norsupuku +STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} Roomalainenpuku +STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} Gorillapuku +STR_1784 :{INLINE_SPRITE}{03}{20}{00}{00} Lumimiespuku +STR_1785 :{INLINE_SPRITE}{04}{20}{00}{00} Ritaripuku +STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} Astronauttipuku +STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} Rosvopuku +STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} Seriffipuku +STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} Merirosvopuku +STR_1790 :{SMALLFONT}{BLACK}Valitse virka-asun väri tämän tyyppisille henkilökunnille +STR_1791 :{WINDOW_COLOUR_2}Virka-asun väri: +STR_1792 :Responding to {STRINGID} breakdown call +STR_1793 :Heading to {STRINGID} for an inspection +STR_1794 :Korjataan {STRINGID} +STR_1795 :Vastataan radiopuheluun +STR_1796 :Has broken down and requires fixing +STR_1797 :This option cannot be changed for this ride +STR_1798 :Whirlpool +STR_1799 :{POP16}{POP16}{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1800 :Safety cut-out +STR_1801 :Restraints stuck closed +STR_1802 :Restraints stuck open +STR_1803 :Doors stuck closed +STR_1804 :Doors stuck open +STR_1805 :Ajoneuvotoimintahäiriö +STR_1806 :Jarruvirhe +STR_1807 :Ohjausvirhe +STR_1808 :{WINDOW_COLOUR_2}Last breakdown: {BLACK}{STRINGID} +STR_1809 :{WINDOW_COLOUR_2}Current breakdown: {OUTLINE}{RED}{STRINGID} +STR_1810 :{WINDOW_COLOUR_2}Carrying: +STR_1811 :Tätä ei voi rakentaa tähän... +STR_1812 :{SMALLFONT}{BLACK}{STRINGID} +STR_1813 :Miscellaneous Objects +STR_1814 :Toiminnat +STR_1815 :Ajatukset +STR_1816 :{SMALLFONT}{BLACK}Valitse näytettävä tietotyyppi vieras listalle +STR_1817 :({COMMA16}) +STR_1818 :{WINDOW_COLOUR_2}Kaikki vieraat +STR_1819 :{WINDOW_COLOUR_2}Kaikki vieraat (yhteenvetona) +STR_1820 :{WINDOW_COLOUR_2}Vieraat {STRINGID} +STR_1821 :{WINDOW_COLOUR_2}Vieraat ajattelevat {STRINGID} +STR_1822 :{WINDOW_COLOUR_2}Vieraat ajattelevat {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 :Tilanne +STR_1827 :Suosio +STR_1828 :Tyytyväisyys +STR_1829 :Tuotto +STR_1830 :Jonon pituus +STR_1831 :Jonotusaika +STR_1832 :Luotettavuus +STR_1833 :Keskeytysaika +STR_1834 :Vieraiden suosikki +STR_1835 :Suosio: Tuntematon +STR_1836 :Suosio: {COMMA16}% +STR_1837 :Tyytyväisyys: Tuntematon +STR_1838 :Tyytyväisyys: {COMMA16}% +STR_1839 :Luotettavuus: {COMMA16}% +STR_1840 :Keskeytysaika: {COMMA16}% +STR_1841 :Tuotto: {CURRENCY2DP} per tunti +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 +STR_1845 :{MONTHYEAR} +STR_1846 :{COMMA16} vierasta +STR_1847 :{INLINE_SPRITE}{11}{20}{00}{00}{COMMA16} vierasta +STR_1848 :{INLINE_SPRITE}{10}{20}{00}{00}{COMMA16} vierasta +STR_1849 :{WINDOW_COLOUR_2}Toista musiikkia +STR_1850 :{SMALLFONT}{BLACK}Valitse mitä musiikkia toistetaan tälle ajelulle +STR_1851 :{WINDOW_COLOUR_2}Käyttökustannus: {BLACK}{CURRENCY2DP} per tunti +STR_1852 :{WINDOW_COLOUR_2}Käyttökustannus: {BLACK}Tuntematon +STR_1853 :{WINDOW_COLOUR_2}Rakennettu: {BLACK}Tämä vuosi +STR_1854 :{WINDOW_COLOUR_2}Rakennettu: {BLACK}Viime vuonna +STR_1855 :{WINDOW_COLOUR_2}Rakennettu: {BLACK}{COMMA16} vuotta sitten +STR_1856 :{WINDOW_COLOUR_2}Tuottoa per myyty esine: {BLACK}{CURRENCY2DP} +STR_1857 :{WINDOW_COLOUR_2}Tappiota per myyty esine: {BLACK}{CURRENCY2DP} +STR_1858 :{WINDOW_COLOUR_2}Kustannus: {BLACK}{CURRENCY2DP} per kuukausi +STR_1859 :Yleismies +STR_1860 :Mekaanikko +STR_1861 :Vartija +STR_1862 :Viihdyttäjä +STR_1863 :Yleismies +STR_1864 :Mekaanikko +STR_1865 :Vartija +STR_1866 :Viihdyttäjä +STR_1867 :{BLACK}{COMMA16} {STRINGID} +STR_1868 :Can't change number of rotations... +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}Tulo: {BLACK}{CURRENCY2DP} per tunti +STR_1874 :{WINDOW_COLOUR_2}Tuotto: {BLACK}{CURRENCY2DP} per tunti +STR_1875 :{BLACK} {SPRITE}{BLACK} {STRINGID} +STR_1876 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{251}{19}{00}{00}Tarkista ajelut +STR_1877 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{252}{19}{00}{00}Korjaa ajelut +STR_1878 :{WINDOW_COLOUR_2}Tarkistus: +STR_1879 :10 min välein +STR_1880 :20 min välein +STR_1881 :30 min välein +STR_1882 :45 min välein +STR_1883 :Tunnin välein +STR_1884 :2 tunnin välein +STR_1885 :Ei koskaan +STR_1886 :Tarkistetaan {STRINGID} +STR_1887 :{WINDOW_COLOUR_2}Viimeinen tarkastus: {BLACK}{COMMA16} minuuttia sitten +STR_1888 :{WINDOW_COLOUR_2}Viimeinen tarkistus: {BLACK}yli 4 tuntia sitten +STR_1889 :{WINDOW_COLOUR_2}Keskeytysaika: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1890 :{SMALLFONT}{BLACK}Valitse kuinka usein mekaanikko tarkistaa tämän ajelun +STR_1891 :No {STRINGID} in park yet! +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 : +STR_1893 : +STR_1894 :{WINDOW_COLOUR_2}{STRINGID} myyty: {BLACK}{COMMA32} +STR_1895 :{SMALLFONT}{BLACK}Build new ride/attraction +STR_1896 :{WINDOW_COLOUR_2}Expenditure/Income +STR_1897 :{WINDOW_COLOUR_2}Ride construction +STR_1898 :{WINDOW_COLOUR_2}Ajelun käyttökulut +STR_1899 :{WINDOW_COLOUR_2}Maahankinnat +STR_1900 :{WINDOW_COLOUR_2}Maisemointi +STR_1901 :{WINDOW_COLOUR_2}Puiston sisäänpääsyliput +STR_1902 :{WINDOW_COLOUR_2}Ajeluliput +STR_1903 :{WINDOW_COLOUR_2}Kojujen myynnit +STR_1904 :{WINDOW_COLOUR_2}Shop stock +STR_1905 :{WINDOW_COLOUR_2}Ruoka-/juomamyynnit +STR_1906 :{WINDOW_COLOUR_2}Food/drink stock +STR_1907 :{WINDOW_COLOUR_2}Henkilökunnan palkat +STR_1908 :{WINDOW_COLOUR_2}Markkinointi +STR_1909 :{WINDOW_COLOUR_2}Tutkimustyö +STR_1910 :{WINDOW_COLOUR_2}Lainan korko +STR_1911 :{BLACK} at {COMMA16}% per year +STR_1912 :{MONTH} +STR_1913 :{BLACK}+{CURRENCY2DP} +STR_1914 :{BLACK}{CURRENCY2DP} +STR_1915 :{RED}{CURRENCY2DP} +STR_1916 :{WINDOW_COLOUR_2}Laina: +STR_1917 :{POP16}{POP16}{POP16}{CURRENCY} +STR_1918 :Ei voi enempää lainata rahaa! +STR_1919 :Rahaa ei ole tarpeeksi! +STR_1920 :Lainan takaisin maksaminen ei onnistunut! +STR_1921 :{SMALLFONT}{BLACK}Aloita uusi peli +STR_1922 :{SMALLFONT}{BLACK}Jatka tallennetun pelin pelaamista +STR_1923 :{SMALLFONT}{BLACK}Show tutorial +STR_1924 :{SMALLFONT}{BLACK}Lopeta +STR_1925 :Henkilöä ei voi sijoittaa tähän... +STR_1926 :{SMALLFONT} +STR_1927 :{YELLOW}{STRINGID} on hajonnut +STR_1928 :{RED}{STRINGID} on hajonnut! +STR_1929 :{RED}{STRINGID} still hasn't been fixed{NEWLINE}Check where your mechanics are and consider organizing them better +STR_1930 :{SMALLFONT}{BLACK}Turn on/off tracking information for this guest - (If tracking is on, guest's movements will be reported in the message area) +STR_1931 :{STRINGID} has joined the queue line for {STRINGID} +STR_1932 :{STRINGID} is on {STRINGID} +STR_1933 :{STRINGID} is in {STRINGID} +STR_1934 :{STRINGID} has left {STRINGID} +STR_1935 :{STRINGID} on lähtenyt puistosta +STR_1936 :{STRINGID} has bought {STRINGID} +STR_1937 :{SMALLFONT}{BLACK}Show information about the subject of this message +STR_1938 :{SMALLFONT}{BLACK}Näytä vierasnäkymä +STR_1939 :{SMALLFONT}{BLACK}Näytä henkilöstönäkymä +STR_1940 :{SMALLFONT}{BLACK}Show happiness, energy, hunger etc. for this guest +STR_1941 :{SMALLFONT}{BLACK}Show which rides this guest has been on +STR_1942 :{SMALLFONT}{BLACK}Näytä vieraan taloustiedot +STR_1943 :{SMALLFONT}{BLACK}Näytä vieraan viimeiset ajatukset +STR_1944 :{SMALLFONT}{BLACK}Näytä mitä esineitä vieras kantaa +STR_1945 :{SMALLFONT}{BLACK}Show orders and options for this staff member +STR_1946 :{SMALLFONT}{BLACK}Valitse puku viihdyttäjälle +STR_1947 :{SMALLFONT}{BLACK}Show areas patrolled by selected staff type, and locate the nearest staff member +STR_1948 :{SMALLFONT}{BLACK}Palkkaa uusi tietyn tyyppinen henkilöstön jäsen +STR_1949 :Taloudellinen yhteenveto +STR_1950 :Talouskuvaaja +STR_1951 :Puiston arvokuvaaja +STR_1952 :Tuottokuvaaja +STR_1953 :Markkinointi +STR_1954 :Tutkimustyön rahoitus +STR_1955 :{WINDOW_COLOUR_2}Number of circuits: +STR_1956 :{SMALLFONT}{BLACK}Number of circuits of track per ride +STR_1957 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1958 :{COMMA16} +STR_1959 :Can't change number of circuits... +STR_1960 :{WINDOW_COLOUR_2}Ilmapallon hinta: +STR_1961 :{WINDOW_COLOUR_2}Pehmolelun hinta: +STR_1962 :{WINDOW_COLOUR_2}Puiston kartan hinta: +STR_1963 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_1964 :{WINDOW_COLOUR_2}Sateenvarjon hinta: +STR_1965 :{WINDOW_COLOUR_2}Juoman hinta: +STR_1966 :{WINDOW_COLOUR_2}Hampurilaisen hinta: +STR_1967 :{WINDOW_COLOUR_2}Sipsien hinta: +STR_1968 :{WINDOW_COLOUR_2}Jäätelön hinta: +STR_1969 :{WINDOW_COLOUR_2}Hattaran hinta: +STR_1970 :{WINDOW_COLOUR_2} +STR_1971 :{WINDOW_COLOUR_2} +STR_1972 :{WINDOW_COLOUR_2} +STR_1973 :{WINDOW_COLOUR_2}Pizzan hinta: +STR_1974 :{WINDOW_COLOUR_2} +STR_1975 :{WINDOW_COLOUR_2}Popcornin hinta: +STR_1976 :{WINDOW_COLOUR_2}Hot Dogin hinta: +STR_1977 :{WINDOW_COLOUR_2}Lonkeron hinta: +STR_1978 :{WINDOW_COLOUR_2}Hatun hinta: +STR_1979 :{WINDOW_COLOUR_2}Toffeeomenan hinta: +STR_1980 :{WINDOW_COLOUR_2}T-paidan hinta: +STR_1981 :{WINDOW_COLOUR_2}Donitsin hinta: +STR_1982 :{WINDOW_COLOUR_2}Kahvin hinta: +STR_1983 :{WINDOW_COLOUR_2} +STR_1984 :{WINDOW_COLOUR_2}Paistetun kanan hinta: +STR_1985 :{WINDOW_COLOUR_2}Limonaadin hinta: +STR_1986 :{WINDOW_COLOUR_2} +STR_1987 :{WINDOW_COLOUR_2} +STR_1988 :Ilmapallo +STR_1989 :Pehmolelu +STR_1990 :Puiston kartta +STR_1991 :On-Ride Photo +STR_1992 :Sateenvarjo +STR_1993 :Juoma +STR_1994 :Hampurilainen +STR_1995 :Sipsit +STR_1996 :Jäätelö +STR_1997 :Hattara +STR_1998 :Tyhjä tölkki +STR_1999 :Roska +STR_2000 :Tyhjä hampurilaisrasia +STR_2001 :Pizza +STR_2002 :Etuseteli +STR_2003 :Popcorn +STR_2004 :Hot Dog +STR_2005 :Lonkero +STR_2006 :Hattu +STR_2007 :Toffeeomena +STR_2008 :T-paita +STR_2009 :Donitsi +STR_2010 :Kahvi +STR_2011 :Tyhjä kuppi +STR_2012 :Paistettu kana +STR_2013 :Limonaadi +STR_2014 :Tyhjä rasia +STR_2015 :Tyhjä pullo +STR_2016 :Ilmapalloja +STR_2017 :Pehmoleluja +STR_2018 :Puistokarttoja +STR_2019 :On-Ride Photos +STR_2020 :Sateenvarjoja +STR_2021 :Juomia +STR_2022 :Hampurilaisia +STR_2023 :Sipsejä +STR_2024 :Jäätelöä +STR_2025 :Hattara +STR_2026 :Tyhjiä tölkkejä +STR_2027 :Roska +STR_2028 :Tyhjiä hampurilaisrasioita +STR_2029 :Pizzoja +STR_2030 :Etuseteleitä +STR_2031 :Popcorn +STR_2032 :Hot Dogeja +STR_2033 :Lonkeroita +STR_2034 :Hattuja +STR_2035 :Toffeeomenoita +STR_2036 :T-paitoja +STR_2037 :Donitseja +STR_2038 :Kahvia +STR_2039 :Tyhjiä tölkkejä +STR_2040 :Paistettu kana +STR_2041 :Limonaadi +STR_2042 :Tyhjiä rasiota +STR_2043 :Tyhjiä pulloja +STR_2044 :Ilmapallo +STR_2045 :Pehmolelu +STR_2046 :Puiston kartta +STR_2047 :an On-Ride Photo +STR_2048 :Sateenvarjo +STR_2049 :Juoma +STR_2050 :Hampurilainen +STR_2051 :Sipsejä +STR_2052 :Jäätelö +STR_2053 :Hattaraa +STR_2054 :Tyhjä tölkki +STR_2055 :Roskaa +STR_2056 :Tyhjä hampurilaisrasia +STR_2057 :Pizza +STR_2058 :Etuseteli +STR_2059 :Popcornia +STR_2060 :Hot Dog +STR_2061 :Lonkero +STR_2062 :Hattu +STR_2063 :Toffeeomena +STR_2064 :T-paita +STR_2065 :Donitsi +STR_2066 :Kahvi +STR_2067 :Tyhjä tölkki +STR_2068 :Paistettua kanaa +STR_2069 :Limonaadia +STR_2070 :Tyhjä rasia +STR_2071 :Tyhjä pullo +STR_2072 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Ilmapallo +STR_2073 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Pehmolelu +STR_2074 :Map of {STRINGID} +STR_2075 :On-Ride Photo of {STRINGID} +STR_2076 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Sateenvarjo +STR_2077 :Juoma +STR_2078 :Hampurilainen +STR_2079 :Sipsejä +STR_2080 :Jäätelö +STR_2081 :Hattara +STR_2082 :Tyhjä tölkki +STR_2083 :Roska +STR_2084 :Tyhjä hampurilaisrasia +STR_2085 :Pizza +STR_2086 :Voucher for {STRINGID} +STR_2087 :Popcorn +STR_2088 :Hot Dog +STR_2089 :Lonkero +STR_2090 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Hattu +STR_2091 :Toffeeomena +STR_2092 :{OPENQUOTES}{STRINGID}{ENDQUOTES} T-paita +STR_2093 :Donitsi +STR_2094 :Kahvi +STR_2095 :Tyhjä tölkki +STR_2096 :Paistettu kana +STR_2097 :Limonaadi +STR_2098 :Tyhjä tölkki +STR_2099 :Tyhjä pullo +STR_2100 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_2101 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_2102 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_2103 :{WINDOW_COLOUR_2}Rinkelin hinta: +STR_2104 :{WINDOW_COLOUR_2}Kaakaon hinta: +STR_2105 :{WINDOW_COLOUR_2}Jääteen hinta: +STR_2106 :{WINDOW_COLOUR_2}Tippaleivän hinta: +STR_2107 :{WINDOW_COLOUR_2}Aurinkolasien hinta: +STR_2108 :{WINDOW_COLOUR_2}Häränlihanuudelien hinta: +STR_2109 :{WINDOW_COLOUR_2}Paistettu riisinuudelien hinta: +STR_2110 :{WINDOW_COLOUR_2}Wontonkeiton hinta: +STR_2111 :{WINDOW_COLOUR_2}Lihapullakeiton hinta: +STR_2112 :{WINDOW_COLOUR_2}Hedelmämehun hinta: +STR_2113 :{WINDOW_COLOUR_2}Soijapapumaidon hinta: +STR_2114 :{WINDOW_COLOUR_2}Sujongkwan hinta: +STR_2115 :{WINDOW_COLOUR_2}Patongin hinta: +STR_2116 :{WINDOW_COLOUR_2}Piparin hinta: +STR_2117 :{WINDOW_COLOUR_2} +STR_2118 :{WINDOW_COLOUR_2} +STR_2119 :{WINDOW_COLOUR_2} +STR_2120 :{WINDOW_COLOUR_2}Paahdetun makkaran hinta: +STR_2121 :{WINDOW_COLOUR_2} +STR_2122 :On-Ride Photo +STR_2123 :On-Ride Photo +STR_2124 :On-Ride Photo +STR_2125 :Rinkeli +STR_2126 :Kaakao +STR_2127 :Jäätee +STR_2128 :Tippaleipä +STR_2129 :Aurinkolasit +STR_2130 :Häränlihanuudelit +STR_2131 :Paistettu riisinuudelit +STR_2132 :Wontonkeitto +STR_2133 :Lihapullakeitto +STR_2134 :Hedelmämehu +STR_2135 :Soijapapumaito +STR_2136 :Sujongkwa +STR_2137 :Patonki +STR_2138 :Pipari +STR_2139 :Tyhjä kulho +STR_2140 :Tyhjä juomatölkki +STR_2141 :Tyhjä mehukuppi +STR_2142 :Paahdettu makkara +STR_2143 :Tyhjä kulho +STR_2144 :On-Ride Photos +STR_2145 :On-Ride Photos +STR_2146 :On-Ride Photos +STR_2147 :Rinkelit +STR_2148 :Kaakaot +STR_2149 :Jääteet +STR_2150 :Tippaleivät +STR_2151 :Aurinkolasit +STR_2152 :Häränlihanuudelit +STR_2153 :Paistettu riisinuudelit +STR_2154 :Wontonkeitot +STR_2155 :Lihapullokeitot +STR_2156 :Hedelmämehut +STR_2157 :Soijapapumaidot +STR_2158 :Sujongkwa +STR_2159 :Patongit +STR_2160 :Piparit +STR_2161 :Tyhjiä kulhoja +STR_2162 :Tyhjiä juomatölkkejä +STR_2163 :Tyhjiä mehukuppeja +STR_2164 :Paahdetut makkarat +STR_2165 :Tyhjiä kulhoja +STR_2166 :an On-Ride Photo +STR_2167 :an On-Ride Photo +STR_2168 :an On-Ride Photo +STR_2169 :Rinkeli +STR_2170 :Kaakao +STR_2171 :Jäätee +STR_2172 :Tippaleipä +STR_2173 :Aurinkolasipari +STR_2174 :Häränlihanuudeleita +STR_2175 :Paistettuja riisinuudeleita +STR_2176 :Wontonkeittoa +STR_2177 :Lihapullakeittoa +STR_2178 :Hedelmämehua +STR_2179 :Soijapapumaitoa +STR_2180 :Sujongkwaa +STR_2181 :Patonki +STR_2182 :Pipari +STR_2183 :Tyhjä kulho +STR_2184 :Tyhjä juomatölkki +STR_2185 :Tyhjä mehukuppi +STR_2186 :Paahdettu makkara +STR_2187 :Tyhjä kulho +STR_2188 :On-Ride Photo of {STRINGID} +STR_2189 :On-Ride Photo of {STRINGID} +STR_2190 :On-Ride Photo of {STRINGID} +STR_2191 :Rinkeli +STR_2192 :Kaakao +STR_2193 :Jäätee +STR_2194 :Tippaleipä +STR_2195 :Aurinkolasit +STR_2196 :Häränlihanuudelit +STR_2197 :Paistettuja riisinuudeleita +STR_2198 :Wontonkeitto +STR_2199 :Lihapullakeitto +STR_2200 :Hedelmämehu +STR_2201 :Soijapapumaito +STR_2202 :Sujongkwa +STR_2203 :Patonki +STR_2204 :Pipari +STR_2205 :Tyhjä kulho +STR_2206 :Tyhjä juomatölkki +STR_2207 :Tyhjä mehukuppi +STR_2208 :Paahdettu makkara +STR_2209 :Tyhjä kulho +STR_2210 :{SMALLFONT}{BLACK}Näytä puiston yleismiehet +STR_2211 :{SMALLFONT}{BLACK}Näytä puiston mekaanikot +STR_2212 :{SMALLFONT}{BLACK}Näytä puiston vartijat +STR_2213 :{SMALLFONT}{BLACK}Näytä puiston viihdyttäjät +STR_2214 :Rakentaminen ei ole mahdollista pelin ollessa pysäytettynä! +STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) +STR_2216 :{WINDOW_COLOU1R_2}{COMMA16}{DEGREE}C +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F +STR_2218 :{RED}{STRINGID} on {STRINGID} hasn't returned to the {STRINGID} yet!{NEWLINE}Check whether it is stuck or has stalled +STR_2219 :{RED}{COMMA16} people have died in an accident on {STRINGID} +STR_2220 :{WINDOW_COLOUR_2}Puiston luokitus: {BLACK}{COMMA16} +STR_2221 :{SMALLFONT}{BLACK}Puiston luokitus: {COMMA16} +STR_2222 :{SMALLFONT}{BLACK}{STRINGID} +STR_2223 :{WINDOW_COLOUR_2}Vieraiden määrä: {BLACK}{COMMA16} +STR_2224 :{WINDOW_COLOUR_2}Kassa: {BLACK}{CURRENCY2DP} +STR_2225 :{WINDOW_COLOUR_2}Kassa: {RED}{CURRENCY2DP} +STR_2226 :{WINDOW_COLOUR_2}Puiston arvo: {BLACK}{CURRENCY} +STR_2227 :{WINDOW_COLOUR_2}Yrityksen arvo: {BLACK}{CURRENCY} +STR_2228 :{WINDOW_COLOUR_2}Last month's profit from food/drink and{NEWLINE}merchandise sales: {BLACK}{CURRENCY} +STR_2229 :Slope up to vertical +STR_2230 :Vertical track +STR_2231 :Holding brake for drop +STR_2232 :Cable lift hill +STR_2233 :{SMALLFONT}{BLACK}Puiston tiedot +STR_2234 :Viimeiset viestit +STR_2235 :{SMALLFONT}{STRINGID} {STRINGID} +STR_2236 :Tammikuu +STR_2237 :Helmikuu +STR_2238 :Maaliskuu +STR_2239 :Huhtikuu +STR_2240 :Toukokuu +STR_2241 :Kesäkuu +STR_2242 :Heinäkuu +STR_2243 :Elokuu +STR_2244 :Syyskuu +STR_2245 :Lokakuu +STR_2246 :Marraskuu +STR_2247 :Joulukuu +STR_2248 :Can't demolish ride/attraction... +STR_2249 :{BABYBLUE}New ride/attraction now available:{NEWLINE}{STRINGID} +STR_2250 :{BABYBLUE}New scenery/themeing now available:{NEWLINE}{STRINGID} +STR_2251 :Can only be built on paths! +STR_2252 :Can only be built across paths! +STR_2253 :Transport Rides +STR_2254 :Gentle Rides +STR_2255 :Vuoristoradat +STR_2256 :Thrill Rides +STR_2257 :Vesiajelut +STR_2258 :Shops & Stalls +STR_2259 :Scenery & Themeing +STR_2260 :Ei rahoitusta +STR_2261 :Vähimmäisrahoitus +STR_2262 :Normaali rahoitus +STR_2263 :Täysrahoitus +STR_2264 :Tutkimustyön rahoitus +STR_2265 :{WINDOW_COLOUR_2}Kustannus: {BLACK}{CURRENCY} kuukaudessa +STR_2266 :Tutkimustyön tärkeysjärjestykset +STR_2267 :Paraikaa suunnitteilla +STR_2268 :Last development +STR_2269 :{WINDOW_COLOUR_2}Tyyppi: {BLACK}{STRINGID} +STR_2270 :{WINDOW_COLOUR_2}Edistys: {BLACK}{STRINGID} +STR_2271 :{WINDOW_COLOUR_2}Odotettavista: {BLACK}{STRINGID} +STR_2272 :{WINDOW_COLOUR_2}Ride/attraction:{NEWLINE}{BLACK}{STRINGID} +STR_2273 :{WINDOW_COLOUR_2}Scenery/themeing:{NEWLINE}{BLACK}{STRINGID} +STR_2274 :{SMALLFONT}{BLACK}Show details of this invention or development +STR_2275 :{SMALLFONT}{BLACK}Show funding and options for research & development +STR_2276 :{SMALLFONT}{BLACK}Show research & development status +STR_2277 :Tuntematon +STR_2278 :Transport Ride +STR_2279 :Gentle Ride +STR_2280 :Roller Coaster +STR_2281 :Thrill Ride +STR_2282 :Vesiajelu +STR_2283 :Shop/Stall +STR_2284 :Scenery/Themeing +STR_2285 :Initial research +STR_2286 :Suunnitellaan +STR_2287 :Completing design +STR_2288 :Tuntematon +STR_2289 :{STRINGID} {STRINGID} +STR_2290 :{SMALLFONT}{BLACK}{STRINGID} {STRINGID} +STR_2291 :Select scenario for new game +STR_2292 :{WINDOW_COLOUR_2}Rides been on: +STR_2293 :{BLACK} Ei mitään +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 +STR_2305 :Track design files +STR_2306 :Save track design +STR_2307 :Select {STRINGID} design +STR_2308 :{STRINGID} Track Designs +STR_2309 :Install New Track Design +STR_2310 :Build custom design +STR_2311 :{WINDOW_COLOUR_2}Excitement rating: {BLACK}{COMMA2DP32} (approx.) +STR_2312 :{WINDOW_COLOUR_2}Intensity rating: {BLACK}{COMMA2DP32} (approx.) +STR_2313 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}{COMMA2DP32} (approx.) +STR_2314 :{WINDOW_COLOUR_2}Ajelun pituus: {BLACK}{STRINGID} +STR_2315 :{WINDOW_COLOUR_2}Kustannus: {BLACK}noin {CURRENCY} +STR_2316 :{WINDOW_COLOUR_2}Tilaa tarvitaan: {BLACK}{COMMA16} x {COMMA16} neliöä +STR_2317 : +STR_2318 : +STR_2319 : +STR_2320 : +STR_2321 :{WINDOW_COLOUR_2}Number of rides/attractions: {BLACK}{COMMA16} +STR_2322 :{WINDOW_COLOUR_2}Henkilökunta: {BLACK}{COMMA16} +STR_2323 :{WINDOW_COLOUR_2}Puiston koko: {BLACK}{COMMA32}m{SQUARED} +STR_2324 :{WINDOW_COLOUR_2}Puiston koko: {BLACK}{COMMA32}sq.ft. +STR_2325 :{SMALLFONT}{BLACK}Osta maata laajentaakseen puistoa +STR_2326 :{SMALLFONT}{BLACK}Buy construction rights to allow construction above or below land outside the park +STR_2327 :Asetukset +STR_2328 :{WINDOW_COLOUR_2}Valuutta: +STR_2329 :{WINDOW_COLOUR_2}Etäisyys ja nopeus: +STR_2330 :{WINDOW_COLOUR_2}Lämpötila: +STR_2331 :{WINDOW_COLOUR_2}Korkeusmerkinnät: +STR_2332 :Yksikkö +STR_2333 :Ääni +STR_2334 :Punta ({POUND}) +STR_2335 :Dollari ($) +STR_2336 :Frangi (F) +STR_2337 :Saksanmarkka (DM) +STR_2338 :Jen ({YEN}) +STR_2339 :Peseta (Pts) +STR_2340 :Liira (L) +STR_2341 :Guldeni (fl.) +STR_2342 :Kruunu (kr) +STR_2343 :Euro ({EURO}) +STR_2344 :Brittiläinen +STR_2345 :Metrinen +STR_2346 :Näytä +STR_2347 :{RED}{STRINGID} on hukkunut! +STR_2348 :{SMALLFONT}{BLACK}Show statistics for this staff member +STR_2349 :{WINDOW_COLOUR_2}Palkat: {BLACK}{CURRENCY} per kuukausi +STR_2350 :{WINDOW_COLOUR_2}Työllistetty: {BLACK}{MONTHYEAR} +STR_2351 :{WINDOW_COLOUR_2}Nurmikkoa ajettu: {BLACK}{COMMA16} +STR_2352 :{WINDOW_COLOUR_2}Puutarhaa kasteltu: {BLACK}{COMMA16} +STR_2353 :{WINDOW_COLOUR_2}Törkyä harjattu: {BLACK}{COMMA16} +STR_2354 :{WINDOW_COLOUR_2}Roskakoria tyhjennetty: {BLACK}{COMMA16} +STR_2355 :{WINDOW_COLOUR_2}Ajelua korjattu: {BLACK}{COMMA16} +STR_2356 :{WINDOW_COLOUR_2}Ajelua tarkistettu: {BLACK}{COMMA16} +STR_2357 :Talo +STR_2358 :Yksiköt +STR_2359 :Oikeat arvot +STR_2360 :{WINDOW_COLOUR_2}Näytön tarkkuus +STR_2361 :Landscape Smoothing +STR_2362 :{SMALLFONT}{BLACK}Toggle landscape tile edge smoothing on/off +STR_2363 :Gridlines on Landscape +STR_2364 :{SMALLFONT}{BLACK}Toggle gridlines on landscape on/off +STR_2365 :Pankki ei suostu korottamaan lainaasi! +STR_2366 :Celsius ({DEGREE}C) +STR_2367 :Fahrenheit ({DEGREE}F) +STR_2368 :Ei mitään +STR_2369 :Matala +STR_2370 :Tyydyttävä +STR_2371 :Korkea +STR_2372 :Matala +STR_2373 :Keski +STR_2374 :Korkea +STR_2375 :Todella korkea +STR_2376 :Extreme +STR_2377 :Ultra-Extreme +STR_2378 :{SMALLFONT}{BLACK}Säädä pienempi alue maata +STR_2379 :{SMALLFONT}{BLACK}Säädä suurempi alue maata +STR_2380 :{SMALLFONT}{BLACK}Säädä pienempi alue vettä +STR_2381 :{SMALLFONT}{BLACK}Säädä suurempi alue vettä +STR_2382 :Maa +STR_2383 :Vesi +STR_2384 :{WINDOW_COLOUR_2}Tavoitteesi: +STR_2385 :{BLACK}Ei mitään +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}Pidä hauskaa! +STR_2389 :{BLACK}Rakenna paras {STRINGID} kuin voit! +STR_2390 :{BLACK}To have 10 different types of roller coasters operating in your park, each with an excitement value of at least 6.00 +STR_2391 :{BLACK}To have at least {COMMA16} guests in your park. You must not let the park rating drop below 700 at any time! +STR_2392 :{BLACK}To achieve a monthly income from ride tickets of at least {POP16}{POP16}{CURRENCY} +STR_2393 :{BLACK}To have 10 different types of roller coasters operating in your park, each with a minimum length of {LENGTH}, and an excitement rating of at least 7.00 +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 :Ei mitään +STR_2398 :Vieraiden määrä tiettynä päivänä +STR_2399 :Puiston arvo tiettynä päivänä +STR_2400 :Pidä hauskaa +STR_2401 :Rakenna parhaat ajelut joita voit +STR_2402 :Rakenna 10 vuoristorataa +STR_2403 :Vieraiden määrä puistossa +STR_2404 :Kuukausittainen tulo ajelujen tuloista +STR_2405 :Rakenna 10 vuoristorataa tietyssä ajassa +STR_2406 :Rakenna valmiiksi 5 vuoristorataa +STR_2407 :Maksa laina pois ja saavuta tietty puiston arvo +STR_2408 :Monthly profit from food/merchandise +STR_2409 :{WINDOW_COLOUR_2}Markkinointikampanjoja käynnissä +STR_2410 :{BLACK}Ei mitään +STR_2411 :{WINDOW_COLOUR_2}Markkinointikampanjoja saatavilla +STR_2412 :{SMALLFONT}{BLACK}Aloita tämä markkinointikampanja +STR_2413 :{BLACK}({CURRENCY2DP} viikossa) +STR_2414 :(Ei valittu) +STR_2415 :{WINDOW_COLOUR_2}Ajelu: +STR_2416 :{WINDOW_COLOUR_2}Esine: +STR_2417 :{WINDOW_COLOUR_2}Kesto: +STR_2418 :Free entry to {STRINGID} +STR_2419 :Free ride on {STRINGID} +STR_2420 :Half-price entry to {STRINGID} +STR_2421 :Ilmainen {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}Mainoskampanja puistollesi +STR_2429 :{WINDOW_COLOUR_2}Mainoskampanja tietylle ajelulle +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 viikko +STR_2437 : +STR_2438 : +STR_2439 : +STR_2440 : +STR_2441 : +STR_2442 : +STR_2443 :{WINDOW_COLOUR_2}Viikottainen kustannus: {BLACK}{CURRENCY2DP} +STR_2444 :{WINDOW_COLOUR_2}Kokonaiskustannus: {BLACK}{CURRENCY2DP} +STR_2445 :Aloita tämä markkinointikampanja +STR_2446 :{YELLOW}Markkinointikampanja ilmaisille sisäänpääsyille puistossasi on loppunut +STR_2447 :{YELLOW}Your marketing campaign for free rides on {STRINGID} has finished +STR_2448 :{YELLOW}Markkinointikampanja sisäänpääsy puoleen hintaan puistoosi on loppunut +STR_2449 :{YELLOW}Your marketing campaign for free {STRINGID} has finished +STR_2450 :{YELLOW}Mainoskampanjasi puistolle on loppunut +STR_2451 :{YELLOW}Your advertising campaign for {STRINGID} has finished +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} - +STR_2455 :{SMALLFONT}{BLACK}+{CURRENCY2DP} - +STR_2456 :{SMALLFONT}{BLACK}{CURRENCY2DP} - +STR_2457 :{SMALLFONT}{BLACK}Show financial accounts +STR_2458 :{SMALLFONT}{BLACK}Show graph of cash (less loan) over time +STR_2459 :{SMALLFONT}{BLACK}Näytä kuvaaja puiston arvosta +STR_2460 :{SMALLFONT}{BLACK}Näytä kuvaaja viikottaisesta tuotosta +STR_2461 :{SMALLFONT}{BLACK}Näytä markkinointikampanjat +STR_2462 :{SMALLFONT}{BLACK}Näytä puiston sisäänkäynti +STR_2463 :{SMALLFONT}{BLACK}Show graph of park ratings over time +STR_2464 :{SMALLFONT}{BLACK}Show graph of guest numbers over time +STR_2465 :{SMALLFONT}{BLACK}Näytä sisäänpääsyhinta ja -tiedot +STR_2466 :{SMALLFONT}{BLACK}Näytä puiston tilastot +STR_2467 :{SMALLFONT}{BLACK}Näytä pelin tavoitteet +STR_2468 :{SMALLFONT}{BLACK}Näytä viimeiset palkinnot mitä tämä puisto on saanut +STR_2469 :{SMALLFONT}{BLACK}Select level of research & development +STR_2470 :{SMALLFONT}{BLACK}Research new transport rides +STR_2471 :{SMALLFONT}{BLACK}Research new gentle rides +STR_2472 :{SMALLFONT}{BLACK}Research new roller coasters +STR_2473 :{SMALLFONT}{BLACK}Research new thrill rides +STR_2474 :{SMALLFONT}{BLACK}Tutki uusia vesiajeluja +STR_2475 :{SMALLFONT}{BLACK}Research new shops and stalls +STR_2476 :{SMALLFONT}{BLACK}Research new scenery and themeing +STR_2477 :{SMALLFONT}{BLACK}Select operating mode for this ride/attraction +STR_2478 :{SMALLFONT}{BLACK}Show graph of velocity against time +STR_2479 :{SMALLFONT}{BLACK}Show graph of altitude against time +STR_2480 :{SMALLFONT}{BLACK}Show graph of vertical acceleration against time +STR_2481 :{SMALLFONT}{BLACK}Show graph of lateral acceleration against time +STR_2482 :{SMALLFONT}{BLACK}Tuotte: {CURRENCY} viikossa, puiston arvo: {CURRENCY} +STR_2483 :{WINDOW_COLOUR_2}Viikottainen tuotto: {BLACK}+{CURRENCY2DP} +STR_2484 :{WINDOW_COLOUR_2}Viikottainen tuotto: {RED}{CURRENCY2DP} +STR_2485 :Ohjaimet +STR_2486 :Yleiset +STR_2487 :Näytä vieraiden 'oikeat' nimet +STR_2488 :{SMALLFONT}{BLACK}Toggle between showing 'real' names of guests and guest numbers +STR_2489 :Pikanäppäimet... +STR_2490 :Näppäimistön pikanäppäimet +STR_2491 :Reset keys +STR_2492 :{SMALLFONT}{BLACK}Set all keyboard shortcuts back to default settings +STR_2493 :Close top-most window +STR_2494 :Close all floating windows +STR_2495 :Cancel construction mode +STR_2496 :Pysäytä peli +STR_2497 :Zoom view out +STR_2498 :Zoom view in +STR_2499 :Rotate view clockwise +STR_2500 :Rotate construction object +STR_2501 :Underground view toggle +STR_2502 :Remove base land toggle +STR_2503 :Remove vertical land toggle +STR_2504 :See-through rides toggle +STR_2505 :See-through scenery toggle +STR_2506 :Invisible supports toggle +STR_2507 :Invisible people toggle +STR_2508 :Height marks on land toggle +STR_2509 :Height marks on ride tracks toggle +STR_2510 :Height marks on paths toggle +STR_2511 :Säädä maata +STR_2512 :Säädä vettä +STR_2513 :Build scenery +STR_2514 :Build paths +STR_2515 :Rakenna uusi ajelu +STR_2516 :Näytä taloustiedot +STR_2517 :Näytä tutkimustyötiedot +STR_2518 :Näytä ajelulista +STR_2519 :Näytä puiston tiedot +STR_2520 :Näytä vieraslista +STR_2521 :Näytä henkilöstölista +STR_2522 :Näytä viimeiset viestit +STR_2523 :Näytä kartta +STR_2524 :Kuvankaappaus +### The following need to be reordered to match SDL_keycode layout. +STR_2525 :??? +STR_2526 :??? +STR_2527 :??? +STR_2528 :??? +STR_2529 :??? +STR_2530 :??? +STR_2531 :??? +STR_2532 :??? +STR_2533 :Askelpalautin +STR_2534 :Tab +STR_2535 :??? +STR_2536 :??? +STR_2537 :Clear +STR_2538 :Return +STR_2539 :??? +STR_2540 :??? +STR_2541 :??? +STR_2542 :??? +STR_2543 :Alt/Menu +STR_2544 :Pysäytä +STR_2545 :Caps +STR_2546 :??? +STR_2547 :??? +STR_2548 :??? +STR_2549 :??? +STR_2550 :??? +STR_2551 :??? +STR_2552 :Esc-näppäin +STR_2553 :??? +STR_2554 :??? +STR_2555 :??? +STR_2556 :??? +STR_2557 :Välilyönti +STR_2558 :PgUp +STR_2559 :PgDn +STR_2560 :End +STR_2561 :Home +STR_2562 :Vasen +STR_2563 :Ylös +STR_2564 :Oikea +STR_2565 :Alas +STR_2566 :Select +STR_2567 :Print +STR_2568 :Execute +STR_2569 :Ruudunkaappaus +STR_2570 :Insert +STR_2571 :Delete +STR_2572 :Ohje +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 :Valikko +STR_2619 :??? +STR_2620 :??? +STR_2621 :NumPad 0 +STR_2622 :NumPad 1 +STR_2623 :NumPad 2 +STR_2624 :NumPad 3 +STR_2625 :NumPad 4 +STR_2626 :NumPad 5 +STR_2627 :NumPad 6 +STR_2628 :NumPad 7 +STR_2629 :NumPad 8 +STR_2630 :NumPad 9 +STR_2631 :NumPad * +STR_2632 :NumPad + +STR_2633 :??? +STR_2634 :NumPad - +STR_2635 :NumPad . +STR_2636 :NumPad / +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 :NumLock +STR_2670 :Scroll +STR_2671 :??? +STR_2672 :??? +STR_2673 :??? +STR_2674 :??? +STR_2675 :??? +STR_2676 :??? +STR_2677 :??? +STR_2678 :??? +STR_2679 :??? +STR_2680 :Kaikki tutkimustyö on tehty +STR_2681 :{MEDIUMFONT}{BLACK}Increases your money by {CURRENCY} +STR_2682 : +STR_2683 : +STR_2684 :{SMALLFONT}{BLACK}Large group of peeps arrive +STR_2685 :Simplex Noise Parameters +STR_2686 :{WINDOW_COLOUR_2}Matala: +STR_2687 :{WINDOW_COLOUR_2}Korkea: +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}Vedentaso: +STR_2693 :{WINDOW_COLOUR_2}Ympäristö: +STR_2694 :Luo +STR_2695 :Satunnainen ympäristö +STR_2696 :Aseta puita +STR_2697 :??? +STR_2698 :??? +STR_2699 :??? +STR_2700 :Automaattisen tallennuksen tiheys: +STR_2701 :1 min välein +STR_2702 :5 min välein +STR_2703 :15 min välein +STR_2704 :30 min välein +STR_2705 :Tunnin välein +STR_2706 :Ei koskaan +STR_2707 :Avaa uusi ikkuna +STR_2708 :{WINDOW_COLOUR_1}Oletko varma, että haluat korvata tiedoston {STRINGID}? +STR_2709 :Korvaa +STR_2710 :Kirjoita tiedoston nimi. +STR_2711 :; +STR_2712 := +STR_2713 :, +STR_2714 :- +STR_2715 :. +STR_2716 :/ +STR_2717 :' +STR_2718 :(ylös) +STR_2719 :(uusi tiedosto) +STR_2720 :{UINT16}sek +STR_2721 :{UINT16}sekuntia +STR_2722 :{UINT16}min:{UINT16}sek +STR_2723 :{UINT16}min:{UINT16}sekuntia +STR_2724 :{UINT16}minuuttia:{UINT16}sek +STR_2725 :{UINT16}minuuttia:{UINT16}sekuntia +STR_2726 :{UINT16}min +STR_2727 :{UINT16}minuuttia +STR_2728 :{UINT16}tunti:{UINT16}min +STR_2729 :{UINT16}tunti:{UINT16}minuuttia +STR_2730 :{UINT16}tuntia:{UINT16}min +STR_2731 :{UINT16}tuntia:{UINT16}minuuttias +STR_2732 :{COMMA16}jalka +STR_2733 :{COMMA16}m +STR_2734 :{COMMA16}mph +STR_2735 :{COMMA16}km/h +STR_2736 :{MONTH}, Vuosi {COMMA16} +STR_2737 :{STRINGID} {MONTH}, Vuosi {COMMA16} +STR_2738 :Otsikkoruudun musiikki: +STR_2739 :Ei mitään +STR_2740 :RollerCoaster Tycoon 1 +STR_2741 :RollerCoaster Tycoon 2 +STR_2742 :css50.dat ei löydy +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 :My new scenario +# New strings used in the cheats window previously these were ??? +STR_2750 :Siirrä kaikki esineet ylös +STR_2751 :Siirrä kaikki esineet alas +STR_2752 :Clear grass +STR_2753 :Leikattu ruoho +STR_2754 :Kastele kasvit +STR_2755 :Korjaa tärvelöinti +STR_2756 :Poista roskat +STR_2757 :Pakota aurinko +STR_2758 :Pakota ukkonen +STR_2759 :Zero Clearance +STR_2760 :+{CURRENCY} +STR_2761 : +STR_2762 : +STR_2763 :??? +STR_2764 : +STR_2765 :Large Tram +STR_2766 :Win scenario +STR_2767 :Jäädytä ilmasto +STR_2768 :Unfreeze Climate +STR_2769 :Avaa puisto +STR_2770 :Sulje puisto +STR_2771 :Hitaampi pelinopeus +STR_2772 :Nopeampi pelinopeus +STR_2773 :Ikkunoitu +STR_2774 :Koko näyttö +STR_2775 :Koko näyttö (työpöytä) +STR_2776 :Kieli: +STR_2777 :{MOVE_X}{SMALLFONT}{STRING} +STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} +STR_2779 :Ikkuna #{COMMA16} +STR_2780 :Ylimääräinen ikkuna +# End of new strings +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} +STR_2782 :SHIFT + +STR_2783 :CTRL + +STR_2784 :Muuta näppäimistön pikanäppäintä +STR_2785 :{WINDOW_COLOUR_2}Press new shortcut key for:{NEWLINE}{OPENQUOTES}{STRINGID}{ENDQUOTES} +STR_2786 :{SMALLFONT}{BLACK}Click on shortcut description to select new key +STR_2787 :{WINDOW_COLOUR_2}Puiston arvo: {BLACK}{CURRENCY} +STR_2788 :{WINDOW_COLOUR_2}Congratulations !{NEWLINE}{BLACK}You achieved your objective with a company value of {CURRENCY} ! +STR_2789 :{WINDOW_COLOUR_2}Epäonnistuit tavoitteessasi ! +STR_2790 :Enter name into scenario chart +STR_2791 :Anna nimi +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 :Järjestä +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}Sisäänpääsyt: {BLACK}{COMMA32} +STR_2801 :{WINDOW_COLOUR_2}Tulot sisäänpääsyistä: {BLACK}{CURRENCY2DP} +STR_2802 :Kartta +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}Näytä puiston kartta +STR_2806 :{RED}Guests are complaining about the disgusting state of the paths in your park{NEWLINE}Check where your handymen are and consider organising them better +STR_2807 :{RED}Guests are complaining about the amount of litter in your park{NEWLINE}Check where your handymen are and consider organising them better +STR_2808 :{RED}Guests are complaining about the vandalism in your park{NEWLINE}Check where your security guards are and consider organising them better +STR_2809 :{RED}Vieraat ovat nälkäisiä eivätkä löydä paikkaa mistä saisi ruokaa +STR_2810 :{RED}Vieraat ovat janoisia eivätkä löydä paikkaa josta saisi juotavaa +STR_2811 :{RED}Vieraat valittavat etteivät löydä vessaa puistostasi +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}Sotkuisin puisto -palkinto +STR_2815 :{WINDOW_COLOUR_2}Siistein puisto -palkinto +STR_2816 :{WINDOW_COLOUR_2}Award for the park with the best roller coasters +STR_2817 :{WINDOW_COLOUR_2}Best value park award +STR_2818 :{WINDOW_COLOUR_2}Kaunein puisto -palkinto +STR_2819 :{WINDOW_COLOUR_2}Worst value park award +STR_2820 :{WINDOW_COLOUR_2}Turvallisin puisto -palkinto +STR_2821 :{WINDOW_COLOUR_2}Paras henkilöstö -palkinto +STR_2822 :{WINDOW_COLOUR_2}Parhaat puistoruuat -palkinto +STR_2823 :{WINDOW_COLOUR_2}Huonoimmat puistoruuat -palkinto +STR_2824 :{WINDOW_COLOUR_2}Parhaat puistovessat -palkinto +STR_2825 :{WINDOW_COLOUR_2}Pettymyksellisin puisto -palkinto +STR_2826 :{WINDOW_COLOUR_2}Parhaat vesiajelut -palkinto +STR_2827 :{WINDOW_COLOUR_2}Best custom-designed rides award +STR_2828 :{WINDOW_COLOUR_2}Most dazzling ride colour schemes award +STR_2829 :{WINDOW_COLOUR_2}Most confusing park layout award +STR_2830 :{WINDOW_COLOUR_2}Best gentle ride award +STR_2831 :{TOPAZ}Puistosi sai 'Sotkuisin puisto maassa' -palkinnon! +STR_2832 :{TOPAZ}Puistosi sai 'Siistein puisto maassa' -palkinnon! +STR_2833 :{TOPAZ}Puistosi sai 'Puisto parhaimmilla vuoristoradoilla' -palkinnon! +STR_2834 :{TOPAZ}Your park has received an award for being 'The best value park in the country'! +STR_2835 :{TOPAZ}Puistosi sai 'Kaunein puisto maassa' -palkinnon! +STR_2836 :{TOPAZ}Your park has received an award for being 'The worst value park in the country'! +STR_2837 :{TOPAZ}Puistosi sai 'Turvallisin puisto maassa' -palkinnon! +STR_2838 :{TOPAZ}Puistosi sai 'Puisto parhaimmalla henkilöstöllä' -palkinnon! +STR_2839 :{TOPAZ}Puistosi sai 'Puisto parhaimmalla ruualla maassa' -palkinnon! +STR_2840 :{TOPAZ}Puisto sai 'Puisto huonoimmalla ruualla maassa' -palkinnon! +STR_2841 :{TOPAZ}Puistosi sai 'Puisto parhaimmilla vessatiloilla maassa' -palkinnon! +STR_2842 :{TOPAZ}Puistosi sai 'Pettymyksellisin puisto maassa' -palkinnon! +STR_2843 :{TOPAZ}Puistosi sai 'Parhaat vesiajelut maassa' -palkinnon! +STR_2844 :{TOPAZ}Your park has received an award for being 'The park with the best custom-designed rides'! +STR_2845 :{TOPAZ}Your park has received an award for being 'The park with the most dazzling choice of colour schemes'! +STR_2846 :{TOPAZ}Your park has received an award for being 'The park with the most confusing layout'! +STR_2847 :{TOPAZ}Your park has received an award for being 'The park with the best gentle rides'! +STR_2848 :{WINDOW_COLOUR_2}Ei tuoreita palkintoja +STR_2849 :Uusi skenaario asennettiin onnistuneesti +STR_2850 :New track design installed successfully +STR_2851 :Skenaario jo asennettu +STR_2852 :Track design already installed +STR_2853 :Kiellettyä paikallisten viranomaisten mukaan! +STR_2854 :{RED}Guests can't get to the entrance of {STRINGID} !{NEWLINE}Construct a path to the entrance +STR_2855 :{RED}{STRINGID} has no path leading from its exit !{NEWLINE}Construct a path from the ride exit +STR_2856 :{WINDOW_COLOUR_2}Tutorial +STR_2857 :{WINDOW_COLOUR_2}(Press a key or mouse button to take control) +STR_2858 :Markkinointikampanjaa ei voitu aloittaa... +STR_2859 :Another instance of OpenRCT2 is already running +STR_2860 :Infogrames Interactiven lopputekstit... +STR_2861 :{WINDOW_COLOUR_2}Lisensoinut Infogrames Interactive Inc. +STR_2862 :Music acknowledgements... +STR_2863 :Music acknowledgements +STR_2864 :{WINDOW_COLOUR_2}March - Children of the Regiment: (Fucik) non copyright +STR_2865 :{WINDOW_COLOUR_2}Heyken's Serenade: (J.Heyken) British Standard Music Coy; GEMA, BRITICO +STR_2866 :{WINDOW_COLOUR_2}In Continental Mood: (Composer unknown) Copyright Control +STR_2867 :{WINDOW_COLOUR_2}Wedding Journey: (Perinteinen) +STR_2868 :{WINDOW_COLOUR_2}Tales from the Vienna Woods: (Johann Strauss) non copyright +STR_2869 :{WINDOW_COLOUR_2}Slavonic Dance: (Perinteinen) +STR_2870 :{WINDOW_COLOUR_2}Das Alpenhorn: (Perinteinen) +STR_2871 :{WINDOW_COLOUR_2}The Blond Sailor: (Perinteinen) +STR_2872 :{WINDOW_COLOUR_2}Overture - Poet and Peasant: (Suppe) non copyright +STR_2873 :{WINDOW_COLOUR_2}Waltz Medley: (Johann Strauss) non copyright +STR_2874 :{WINDOW_COLOUR_2}Bella Bella Bimba: (Perinteinen) +STR_2875 :{WINDOW_COLOUR_2}Original recordings (P) 1976 C.J.Mears Organization, used with consent +STR_2876 :{WINDOW_COLOUR_2}RollerCoaster Tycoon 2 Title Music: (Allister Brimble) copyright {COPYRIGHT} Chris Sawyer +STR_2877 :{WINDOW_COLOUR_2}Dodgems Beat: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2878 :{WINDOW_COLOUR_2}Mid Summer's Heat: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2879 :{WINDOW_COLOUR_2}Pharaoh's Tomb: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2880 :{WINDOW_COLOUR_2}Caesar's March: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2881 :{WINDOW_COLOUR_2}Drifting To Heaven: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2882 :{WINDOW_COLOUR_2}Invaders: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2883 :{WINDOW_COLOUR_2}Eternal Toybox: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2884 :{WINDOW_COLOUR_2}Jungle Juice: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2885 :{WINDOW_COLOUR_2}Ninja's Noodles: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2886 :{WINDOW_COLOUR_2}Voyage to Andromeda: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2887 :{WINDOW_COLOUR_2}Brimble's Beat: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2888 :{WINDOW_COLOUR_2}Atlantis: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2889 :{WINDOW_COLOUR_2}Wild West Kid: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2890 :{WINDOW_COLOUR_2}Vampire's Lair: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2891 :{WINDOW_COLOUR_2}Blockbuster: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2892 :{WINDOW_COLOUR_2}Airtime Rock: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2893 :{WINDOW_COLOUR_2}Searchlight Rag: (Scott Joplin/Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2894 :{WINDOW_COLOUR_2}Flight of Fantasy: (Steve Blenkinsopp) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2895 :{WINDOW_COLOUR_2}Big Rock: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2896 :{WINDOW_COLOUR_2}Hypothermia: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2897 :{WINDOW_COLOUR_2}Last Sleigh Ride: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2898 :{WINDOW_COLOUR_2}Pipes of Glencairn: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2899 :{WINDOW_COLOUR_2}Traffic Jam: (Allister Brimble) tekijänoikeus {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, played by Peter James Adcock) recording {COPYRIGHT} Chris Sawyer +STR_2903 :{WINDOW_COLOUR_2}Space Rock: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2904 :{WINDOW_COLOUR_2}Manic Mechanic: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2905 :{WINDOW_COLOUR_2}Techno Torture: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2906 :{WINDOW_COLOUR_2}Sweat Dreams: (Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2907 :{WINDOW_COLOUR_2}What shall we do with the Drunken Sailor: (Anon/Allister Brimble) tekijänoikeus {COPYRIGHT} Chris Sawyer +STR_2908 :{WINDOW_COLOUR_2}Infogrames Interactive +STR_2909 :{WINDOW_COLOUR_2}Senior Producer: Thomas J. Zahorik +STR_2910 :{WINDOW_COLOUR_2}Executive Producer: Bill Levay +STR_2911 :{WINDOW_COLOUR_2}Senior Marketing Product Manager: Scott Triola +STR_2912 :{WINDOW_COLOUR_2}V.P. of Product Development: Scott Walker +STR_2913 :{WINDOW_COLOUR_2}General Manager: John Hurlbut +STR_2914 :{WINDOW_COLOUR_2}Director of Quality Assurance: Michael Craighead +STR_2915 :{WINDOW_COLOUR_2}Q.A. Certification Manager: Kurt Boutin +STR_2916 :{WINDOW_COLOUR_2}Q.A. Certification Lead: Mark Huggins +STR_2917 :{WINDOW_COLOUR_2}Testaajat: Dena Irene Fitzgerald, Scott Rollins, Christopher McPhail +STR_2918 :{WINDOW_COLOUR_2}Clif McClure, Erik Maramaldi, Erik Jeffery +STR_2919 :{WINDOW_COLOUR_2}Director of Marketing: Ann Marie Bland +STR_2920 :{WINDOW_COLOUR_2}Manager of Creative Services: Steve Martin +STR_2921 :{WINDOW_COLOUR_2}Manager of Editorial & Documentation Services: Elizabeth Mackney +STR_2922 :{WINDOW_COLOUR_2}Graphic Designer: Paul Anselmi +STR_2923 :{WINDOW_COLOUR_2}Copywriter: Kurt Carlson +STR_2924 :{WINDOW_COLOUR_2}Erikoiskiitokset: Peter Matiss +STR_2925 :{WINDOW_COLOUR_2}Engineering Specialist: Ken Edwards +STR_2926 :{WINDOW_COLOUR_2}Engineering Services Manager: Luis Rivas +STR_2927 :{WINDOW_COLOUR_2}Lead Compatibility Analyst: Geoffrey Smith +STR_2928 :{WINDOW_COLOUR_2}Compatibility Analysts: Jason Cordero, Burke McQuinn, Kim Jardin +STR_2929 :{WINDOW_COLOUR_2}Päätestaaja: Daniel Frisoli +STR_2930 :{WINDOW_COLOUR_2}Senior Tester: 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 : +STR_2970 : +STR_2971 :Main colour scheme +STR_2972 :Alternative colour scheme 1 +STR_2973 :Alternative colour scheme 2 +STR_2974 :Alternative colour scheme 3 +STR_2975 :{SMALLFONT}{BLACK}Select which colour scheme to change, or paint ride with +STR_2976 :{SMALLFONT}{BLACK}Paint an individual area of this ride using the selected colour scheme +STR_2977 :Henkilöstön jäsenen nimi +STR_2978 :Anna tälle henkilöstön jäsenelle nimi: +STR_2979 :Henkilöstön nimeäminen ei onnistu... +STR_2980 :Too many banners in game +STR_2981 :{RED}Ei sisäänkäyntiä - - +STR_2982 :Banner text +STR_2983 :Enter new text for this banner: +STR_2984 :Can't set new text for banner... +STR_2985 :Banner +STR_2986 :{SMALLFONT}{BLACK}Change text on banner +STR_2987 :{SMALLFONT}{BLACK}Set this banner as a 'no-entry' sign for guests +STR_2988 :{SMALLFONT}{BLACK}Demolish this banner +STR_2989 :{SMALLFONT}{BLACK}Valitse pääväri +STR_2990 :{SMALLFONT}{BLACK}Valitse tekstille väri +STR_2991 :Kyltti +STR_2992 :Tekstikyltti +STR_2993 :Anna teksti tälle kyltille: +STR_2994 :{SMALLFONT}{BLACK}Muuta teksti kyltille +STR_2995 :{SMALLFONT}{BLACK}Romuta tämä kyltti +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 :Tiedoston lataus ei onnistunut... +STR_3011 :Tiedosto sisältää virheellistä tietoa +STR_3012 :Dodgems beat style +STR_3013 :Fairground organ style +STR_3014 :Roman fanfare style +STR_3015 :Itämainen tyyli +STR_3016 :Marssilainen tyyli +STR_3017 :Viidakkorummut-tyyli +STR_3018 :Egyptiläinen tyyli +STR_3019 :Lelumaatyyli +STR_3020 : +STR_3021 :Avaruustyyli +STR_3022 :Kauhutyyli +STR_3023 :Teknotyyli +STR_3024 :Hempeätyyli +STR_3025 :Kesätyyli +STR_3026 :Vesityyli +STR_3027 :Villilänsityyli +STR_3028 :Jurassic style +STR_3029 :Kivityyli +STR_3030 :Ragtime style +STR_3031 :Fantasiatyyli +STR_3032 :Kivityyli 2 +STR_3033 :Jäätyyli +STR_3034 :Lumityyli +STR_3035 :Custom music 1 +STR_3036 :Custom music 2 +STR_3037 :Keskiaikainen tyyli +STR_3038 :Kaupunkimainen tyyli +STR_3039 :Organ style +STR_3040 :Mekaaninen tyyli +STR_3041 :Modernityyli +STR_3042 :Merirosvotyyli +STR_3043 :Kivityyli 3 +STR_3044 :Karkkityyli +STR_3045 :{SMALLFONT}{BLACK}Valitse toistettavan musiikin tyyli +STR_3046 :Tätä ajelua ei voi muokata +STR_3047 :Local authority forbids demolition or modifications to this ride +STR_3048 :Marketing campaigns forbidden by local authority +STR_3049 :Golf-reikä A +STR_3050 :Golf-reikä B +STR_3051 :Golf-reikä C +STR_3052 :Golf-reikä D +STR_3053 :Golf-reikä E +STR_3054 :Ladataan... +STR_3055 :Valkoinen +STR_3056 :Läpikuultava +STR_3057 :{WINDOW_COLOUR_2}Construction Marker: +STR_3058 :Tiiliseinät +STR_3059 :Pensasaidat +STR_3060 :Jääpalat +STR_3061 :Puiset aidat +STR_3062 :{SMALLFONT}{BLACK}Standard roller coaster track +STR_3063 :{SMALLFONT}{BLACK}Water channel (track submerged) +STR_3064 :Aloittajan puistot +STR_3065 :Haastavat puistot +STR_3066 :Asiantuntijan puistot +STR_3067 :{OPENQUOTES}Oikeat{ENDQUOTES} puistot +STR_3068 :Muut puistot +STR_3069 :Top Section +STR_3070 :Slope to Level +STR_3071 :{WINDOW_COLOUR_2}Sama hinta kaikkialla puistossa +STR_3072 :{SMALLFONT}{BLACK}Valitse käytetäänkö samaa hintaa kaikkialla puistossa +STR_3073 :{RED}WARNING: Your park rating has dropped below 700 !{NEWLINE}If you haven't raised the park rating in 4 weeks, your park will be closed down +STR_3074 :{RED}WARNING: Your park rating is still below 700 !{NEWLINE}You have 3 weeks to raise the park rating +STR_3075 :{RED}WARNING: Your park rating is still below 700 !{NEWLINE}You have only 2 weeks to raise the park rating, or your park will be closed down +STR_3076 :{RED}FINAL WARNING: Your park rating is still below 700 !{NEWLINE}In just 7 days your park will be closed down unless you can raise the rating +STR_3077 :{RED}LAKKAUTUSTIEDOTE: Puistosi on suljettu ! +STR_3078 :Tavallinen sisäänkäynti +STR_3079 :Puinen sisäänkäynti +STR_3080 :Kangastelttasisäänkäynti +STR_3081 :Linnan sisäänkäynti (harmaa) +STR_3082 :Linnan sisäänkäynti (ruskea) +STR_3083 :Viidakkosisäänkäynti +STR_3084 :Hirsimökkisisäänkäynti +STR_3085 :Klassinen/Roomalainen sisäänkäynti +STR_3086 :Abstrktisisäänkäynti +STR_3087 :Lumi-/Jääsisäänkäynti +STR_3088 :Pagodisisäänkäynti +STR_3089 :Avaruussisäänkäynti +STR_3090 :{SMALLFONT}{BLACK}Select style of entrance, exit, and station +STR_3091 :Ei ole sallittua poistaa tätä aluetta! +STR_3092 :You are not allowed to move or modify the station for this ride! +STR_3093 :{WINDOW_COLOUR_2}Suosikki: {BLACK}{STRINGID} +STR_3094 :Ei saatavilla +STR_3095 :{WINDOW_COLOUR_2}Lift hill chain speed: +STR_3096 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} +STR_3097 :{SMALLFONT}{BLACK}Select lift hill chain speed +STR_3098 :Can't change lift hill speed... +STR_3099 :{SMALLFONT}{BLACK}Valitse väri +STR_3100 :{SMALLFONT}{BLACK}Valitse toinen väri +STR_3101 :{SMALLFONT}{BLACK}Valitse kolmas väri +STR_3102 :{SMALLFONT}{BLACK}Re-paint coloured scenery on landscape +STR_3103 :Tämän uudelleenvärittäminen ei onnistunut... +STR_3104 :{SMALLFONT}{BLACK}Ajelulista +STR_3105 :{SMALLFONT}{BLACK}List shops and stalls +STR_3106 :{SMALLFONT}{BLACK}List information kiosks and other guest facilities +STR_3107 :Sulje +STR_3108 :Testi +STR_3109 :Avaa +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 +STR_3113 :Valitse toinen suunnitelma +STR_3114 :{SMALLFONT}{BLACK}Go back to design selection window +STR_3115 :{SMALLFONT}{BLACK}Save track design +STR_3116 :{SMALLFONT}{BLACK}Save track design (Not possible until ride has been tested and statistics have been generated) +STR_3117 :{BLACK}Kutsutaan mekaanikkoa... +STR_3118 :{BLACK}{STRINGID} menossa kohti ajelua +STR_3119 :{BLACK}{STRINGID} korjaamassa ajelua +STR_3120 :{SMALLFONT}{BLACK}Locate nearest available mechanic, or mechanic fixing ride +STR_3121 :Unable to locate mechanic, or all nearby mechanics are busy +STR_3122 :{WINDOW_COLOUR_2}Favourite ride of: {BLACK}{COMMA16} guest +STR_3123 :{WINDOW_COLOUR_2}Favourite ride of: {BLACK}{COMMA16} guests +STR_3124 :Hajonnut {STRINGID} +STR_3125 :{WINDOW_COLOUR_2}Excitement Factor: {BLACK}+{COMMA16}% +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 :Tallenna +STR_3131 :Peruuta +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) +STR_3135 :{RED}(Vehicle design unavailable - Ride performance may be affected) +STR_3136 :Warning: This design will be built with an alternative vehicle type and may not perform as expected +STR_3137 :Select Nearby Scenery +STR_3138 :Reset Selection +STR_3139 :Cable lift unable to work in this operating mode +STR_3140 :Cable lift hill must start immediately after station +STR_3141 :Multi-circuit per ride not possible with cable lift hill +STR_3142 :{WINDOW_COLOUR_2}Kapasiteetti: {BLACK}{STRINGID} +STR_3143 :{SMALLFONT}{BLACK}Näytä ihmiset kartalla +STR_3144 :{SMALLFONT}{BLACK}Show rides and stalls on map +STR_3145 :{SMALLFONT}{BLACK}Vieritä {STRINGID} vasemmalle +STR_3146 :{SMALLFONT}{BLACK}Vieritä {STRINGID} oikealle +STR_3147 :{SMALLFONT}{BLACK}Vieritä {STRINGID} vasemmalle nopeasti +STR_3148 :{SMALLFONT}{BLACK}Vieritä {STRINGID} oikealle nopeasti +STR_3149 :{SMALLFONT}{BLACK}Vieritä {STRINGID} vasemmalle/oikealle +STR_3150 :{SMALLFONT}{BLACK}Vieritä {STRINGID} ylös +STR_3151 :{SMALLFONT}{BLACK}Vieritä {STRINGID} alas +STR_3152 :{SMALLFONT}{BLACK}Vieritä {STRINGID} ylös nopeasti +STR_3153 :{SMALLFONT}{BLACK}Vieritä {STRINGID} alas nopeasti +STR_3154 :{SMALLFONT}{BLACK}Vieritä {STRINGID} ylös/alas +STR_3155 : +STR_3156 : +STR_3157 :kartta +STR_3158 :graph +STR_3159 :lista +STR_3160 : +STR_3161 : +STR_3162 :Unable to allocate enough memory +STR_3163 :Installing new data: +STR_3164 :{BLACK}{COMMA16} selected (maximum {COMMA16}) +STR_3165 : +STR_3166 :{BLACK}(ID: +STR_3167 :{WINDOW_COLOUR_2}Sisältää: {BLACK}{COMMA16} objektia +STR_3168 :{WINDOW_COLOUR_2}Teksti: {BLACK}{STRINGID} +STR_3169 :Tiedot seuraavalle objektille ei löydy: +STR_3170 :Tilaa ei ole tarpeeksi grafiikoille +STR_3171 :Liian montaa tämän tyyppistä objektia valittuna +STR_3172 :Tämä objekti pitää valita ensiksi: {STRING} +STR_3173 :Tämä objekti on käytössä +STR_3174 :Tätä objektia tarvitaan toisessa projektissa +STR_3175 :Tätä objektia aina tarvitaan +STR_3176 :Ei onnistunut valita tätä objektia +STR_3177 :Unable to de-select this object +STR_3178 :At least one path object must be selected +STR_3179 :At least one ride vehicle/attraction object must be selected +STR_3180 :Virheellinen objektien valinta +STR_3181 :Objektin valinta - {STRINGID} +STR_3182 :Puiston sisäänkäynnintyyli on valittava +STR_3183 :Veden tyyppi on valittava +STR_3184 :Ride Vehicles/Attractions +STR_3185 :Small Scenery +STR_3186 :Large Scenery +STR_3187 :Seinät/Aidat +STR_3188 :Path Signs +STR_3189 :Jalkakäytävät +STR_3190 :Path Extras +STR_3191 :Scenery Groups +STR_3192 :Puiston sisäänkäynti +STR_3193 :Vesi +STR_3194 :Scenario Description +STR_3195 :Keksintölista +STR_3196 :{WINDOW_COLOUR_2}Tutkimusryhmä: {BLACK}{STRINGID} +STR_3197 :{WINDOW_COLOUR_2}Items pre-invented at start of game: +STR_3198 :{WINDOW_COLOUR_2}Items to invent during game: +STR_3199 :Satunnainen sekoitus +STR_3200 :{SMALLFONT}{BLACK}Randomly shuffle the list of items to invent during the game +STR_3201 :Object Selection +STR_3202 :Landscape Editor +STR_3203 :Invention List Set Up +STR_3204 :Options Selection +STR_3205 :Tavoitteen valinta +STR_3206 :Save Scenario +STR_3207 :Roller Coaster Designer +STR_3208 :Track Designs Manager +STR_3209 :Takaisin edelliseen vaiheeseen: +STR_3210 :Siirry seuraavaan vaiheeseen: +STR_3211 :{WINDOW_COLOUR_2}Kartan koko: +STR_3212 :{POP16}{COMMA16} x {PUSH16}{COMMA16} +STR_3213 :Karttaa ei voi enempää pienentää +STR_3214 :Karttaa ei voi enempää suurentaa +STR_3215 :Liian lähellä kartan reunaa +STR_3216 :{SMALLFONT}{BLACK}Select park-owned land etc. +STR_3217 :Maan omistaa +STR_3218 :Rakennusoikeudet omistaa +STR_3219 :Maata myytävänä +STR_3220 :Rakennusoikeudet myytävänä +STR_3221 :{SMALLFONT}{BLACK}Set land to be owned by the park +STR_3222 :{SMALLFONT}{BLACK}Set construction rights only to be owned by the park +STR_3223 :{SMALLFONT}{BLACK}Set land to be available to purchase by the park +STR_3224 :{SMALLFONT}{BLACK}Set construction rights to be available to purchase by the park +STR_3225 :{SMALLFONT}{BLACK}Toggle on/off building a random cluster of objects around the selected position +STR_3226 :{SMALLFONT}{BLACK}Rakenna puistolle sisäänkäynti +STR_3227 :Liikaa sisäänkäyntejä puistolla! +STR_3228 :{SMALLFONT}{BLACK}Set starting positions for people +STR_3229 :Block Brakes cannot be used directly after station +STR_3230 :Block Brakes cannot be used directly after each other +STR_3231 :Block Brakes cannot be used directly after the top of this lift hill +STR_3232 :Asetukset - Talous +STR_3233 :Asetukset - Vieraat +STR_3234 :Asetukset - Puisto +STR_3235 :{SMALLFONT}{BLACK}Show financial options +STR_3236 :{SMALLFONT}{BLACK}Show guest options +STR_3237 :{SMALLFONT}{BLACK}Show park options +STR_3238 :Ei rahaa +STR_3239 :{SMALLFONT}{BLACK}Make this park a 'no money' park with no financial restrictions +STR_3240 :{WINDOW_COLOUR_2}Aloitusrahamäärä: +STR_3241 :{WINDOW_COLOUR_2}Aloituslaina: +STR_3242 :{WINDOW_COLOUR_2}Maximum loan size: +STR_3243 :{WINDOW_COLOUR_2}Annual interest rate: +STR_3244 :Kiellä markkinointikampanjat +STR_3245 :{SMALLFONT}{BLACK}Forbid advertising, promotional schemes, and other marketing campaigns +STR_3246 :{WINDOW_COLOUR_2}{CURRENCY} +STR_3247 :{WINDOW_COLOUR_2}{COMMA16}% +STR_3248 :Can't increase initial cash any further! +STR_3249 :Can't reduce initial cash any further! +STR_3250 :Can't increase initial loan any further! +STR_3251 :Can't reduce initial loan any further! +STR_3252 :Can't increase maximum loan size any further! +STR_3253 :Can't reduce maximum loan size any further! +STR_3254 :Can't increase interest rate any further! +STR_3255 :Can't reduce interest rate any further! +STR_3256 :Guests prefer less intense rides +STR_3257 :{SMALLFONT}{BLACK}Select whether guests should generally prefer less intense rides only +STR_3258 :Guests prefer more intense rides +STR_3259 :{SMALLFONT}{BLACK}Select whether guests should generally prefer more intense rides only +STR_3260 :{WINDOW_COLOUR_2}Cash per guest (average): +STR_3261 :{WINDOW_COLOUR_2}Guests initial happiness: +STR_3262 :{WINDOW_COLOUR_2}Guests initial hunger: +STR_3263 :{WINDOW_COLOUR_2}Guests initial thirst: +STR_3264 :Can't increase this any further! +STR_3265 :Can't reduce this any further! +STR_3266 :{SMALLFONT}{BLACK}Select how this park charges for entrance and rides +STR_3267 :Estä puiden poistaminen +STR_3268 :{SMALLFONT}{BLACK}Estä korkeiden puiden poistaminen +STR_3269 :Forbid landscape changes +STR_3270 :{SMALLFONT}{BLACK}Forbid any changes to the landscape +STR_3271 :Forbid high construction +STR_3272 :{SMALLFONT}{BLACK}Forbid any tall construction +STR_3273 :Park rating higher difficult level +STR_3274 :{SMALLFONT}{BLACK}Make the park rating value more challenging +STR_3275 :Guest generation higher difficult level +STR_3276 :{SMALLFONT}{BLACK}Make it more difficult to attract guests to the park +STR_3277 :{WINDOW_COLOUR_2}Cost to buy land: +STR_3278 :{WINDOW_COLOUR_2}Cost to buy construction rights: +STR_3279 :Free park entry / Pay per ride +STR_3280 :Pay to enter park / Free rides +STR_3281 :{WINDOW_COLOUR_2}Sisäänpääsyhinta: +STR_3282 :{SMALLFONT}{BLACK}Valitse tavoite ja puiston nimi +STR_3283 :{SMALLFONT}{BLACK}Select rides to be preserved +STR_3284 :Tavoitteen valinta +STR_3285 :Preserved Rides +STR_3286 :{SMALLFONT}{BLACK}Select objective for this scenario +STR_3287 :{WINDOW_COLOUR_2}Tavoite: +STR_3288 :{SMALLFONT}{BLACK}Valitse ilmasto +STR_3289 :{WINDOW_COLOUR_2}Ilmasto: +STR_3290 :Kylmä ja märkä +STR_3291 :Lämmin +STR_3292 :Kuuma ja kuiva +STR_3293 :Kylmä +STR_3294 :Muuta... +STR_3295 :{SMALLFONT}{BLACK}Vaihda puiston nimi +STR_3296 :{SMALLFONT}{BLACK}Change name of scenario +STR_3297 :{SMALLFONT}{BLACK}Change detail notes about park / scenario +STR_3298 :{WINDOW_COLOUR_2}Puiston nimi: {BLACK}{STRINGID} +STR_3299 :{WINDOW_COLOUR_2}Park/Scenario Details: +STR_3300 :{WINDOW_COLOUR_2}Scenario Name: {BLACK}{STRINGID} +STR_3301 :{WINDOW_COLOUR_2}Tavoitepäivä: +STR_3302 :{WINDOW_COLOUR_2}{MONTHYEAR} +STR_3303 :{WINDOW_COLOUR_2}Vieraiden määrä: +STR_3304 :{WINDOW_COLOUR_2}Puiston arvo: +STR_3305 :{WINDOW_COLOUR_2}Kuukausittainen tulo: +STR_3306 :{WINDOW_COLOUR_2}Kuukausittainen tuotto: +STR_3307 :{WINDOW_COLOUR_2}Minimum length: +STR_3308 :{WINDOW_COLOUR_2}Excitement rating: +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_3314 :Enter name for scenario: +STR_3315 :Park/Scenario Details +STR_3316 :Enter description of this scenario: +STR_3317 :Lisätietoja ei ole vielä saatavilla +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 :Uusia objekteja asennettu onnistuneesti +STR_3322 :{WINDOW_COLOUR_2}Tavoite: {BLACK}{STRINGID} +STR_3323 :Missing object data, ID: +STR_3324 :Tarvitsee lisäosapaketin: +STR_3325 :Tarvitsee lisäosapaketin +STR_3326 :{WINDOW_COLOUR_2}(ei kuvaa) +STR_3327 :Starting positions for people not set +STR_3328 :Can't advance to next editor stage... +STR_3329 :Puiston sisäänkäyntiä ei ole vielä rakennettu +STR_3330 :Puiston pitää omistaa edes jonkin verran maata +STR_3331 :Path from park entrance to map edge either not complete or too complex - Path must be single-width with as few junctions and corners as possible +STR_3332 :Park entrance is the wrong way round or has no path leading to the map edge +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 : +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_3341 :{SMALLFONT}{BLACK}Pelityökalut +STR_3342 :Scenario Editor +STR_3343 :Convert Saved Game to Scenario +STR_3344 :Roller Coaster Designer +STR_3345 :Track Designs Manager +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 :Uudelleennimeä +STR_3349 :Poista +STR_3350 :Track design name +STR_3351 :Enter new name for this track design: +STR_3352 :Can't rename track design... +STR_3353 :Uusi nimi sisältää virheellisiä merkkejä +STR_3354 :Toinen saman niminen tiedosto on jo olemassa tai tiedosto on kirjoitussuojattu +STR_3355 :Tiedosto on kirjoitussuojattu tai lukittu +STR_3356 :Poista tiedosto +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 :Varoitus! +STR_3361 :Too many track designs of this type - Some will not be listed. +STR_3362 : +STR_3363 : +STR_3364 :Edistynyt +STR_3365 :{SMALLFONT}{BLACK}Allow selection of individual items of scenery in addition to scenery groups +STR_3366 :{BLACK}= Ajelu +STR_3367 :{BLACK}= Ruokakoju +STR_3368 :{BLACK}= Juomakoju +STR_3369 :{BLACK}= Matkamuistokoju +STR_3370 :{BLACK}= Info. Kiosk +STR_3371 :{BLACK}= Ensiapu +STR_3372 :{BLACK}= Kassakone +STR_3373 :{BLACK}= Vessa +STR_3374 :Varoitus: Liian monta objektia valittuna! +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 :Asenna +STR_3379 :Peruuta +STR_3380 :Unable to install this track design... +STR_3381 :File is not compatible or contains invalid data +STR_3382 :Tiedoston kopio epäonnistui +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_3385 :Beginners Tutorial +STR_3386 :Custom Rides Tutorial +STR_3387 :Roller Coaster Building Tutorial +STR_3388 :Unable to switch to selected mode +STR_3389 :Unable to select additional item of scenery... +STR_3390 :Liian monta esinettä valittuna +STR_3391 :{SMALLFONT}{BLACK}Here is our park - Let's have a quick look around... +STR_3392 :{SMALLFONT}{BLACK}Holding down the RIGHT mouse button and moving the mouse is the quickest way to move the view... +STR_3393 :{SMALLFONT}{BLACK}To view more of the park, you can zoom the view out using the icon at the top of the screen... +STR_3394 :{SMALLFONT}{BLACK}You can also rotate the view in 90 degree steps... +STR_3395 :{SMALLFONT}{BLACK}Building anything at this scale is a bit difficult, so let's zoom the view back in again... +STR_3396 :{SMALLFONT}{BLACK}Let's build a simple ride to get the park started... +STR_3397 :{SMALLFONT}{BLACK}The white 'ghost' image shows where the ride will be built. We'll move the pointer to select the position then click to build it... +STR_3398 :{SMALLFONT}{BLACK}Rides need an entrance and an exit. We'll move the pointer to a square on the edge of the ride and then click to build first the entrance and then the exit... +STR_3399 :{SMALLFONT}{BLACK}We need to build footpaths to allow guests to reach our new ride... +STR_3400 :{SMALLFONT}{BLACK}For the path to the ride entrance we'll use a special 'queue line' path... +STR_3401 :{SMALLFONT}{BLACK}For the exit path, just an 'ordinary' path will do... +STR_3402 :{SMALLFONT}{BLACK}Right, lets open the ride! To open the ride we click the flag icon on the ride window and select 'open'... +STR_3403 :{SMALLFONT}{BLACK}Mutta missä ovat vieraat? +STR_3404 :{SMALLFONT}{BLACK}Oh - The park is still closed! Right - Let's open it... +STR_3405 :{SMALLFONT}{BLACK}While we're waiting for our first guests, let's build some scenery... +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}Lisätään jotain musiikkia ajeluun... +STR_3422 :{SMALLFONT}{BLACK}Rakennetaan vuoristorata! +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 customise 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_3439 :Tyhjennä maisema +STR_3440 :Sivu 1 +STR_3441 :Sivu 2 +STR_3442 :Sivu 3 +STR_3443 :Sivu 4 +STR_3444 :Sivu 5 +STR_3445 :Set Patrol Area +STR_3446 :Cancel Patrol Area + +# New strings, cleaner +STR_5120 :Talous +STR_5121 :Tutkimustyö +STR_5122 :Valitse ajelut radan tyypin mukaan (kuten RCT1:ssä) +STR_5123 :Uusi ajelut +STR_5124 : +STR_5125 :Kaikki tuhottavat +STR_5126 :Satunnainen otsikkomusiikki +STR_5127 :{SMALLFONT}{BLACK}Estä maan korkeuden muuttaminen +STR_5128 :Valinnan koko +STR_5129 :Enter selection size between {COMMA16} and {COMMA16} +STR_5130 :Kartan koko +STR_5131 :Enter map size between {COMMA16} and {COMMA16} +STR_5132 :Korjaa kaikki ajelut +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 :Maaoikeudet +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 :Normaalinopeus +STR_5143 :Pikanopeus +STR_5144 :Nopeanopeus +STR_5145 :Turbonopeus +STR_5146 :Hypernopeus +STR_5147 :Huijaukset +STR_5148 :{SMALLFONT}{BLACK}Muuta pelin nopeus +STR_5149 :{SMALLFONT}{BLACK}Avaa huijauksetikkuna +STR_5150 :Enable debugging tools +STR_5151 :, +STR_5152 :. +STR_5153 :Muuta teemoja... +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 :Lopeta valikkoon +STR_5159 :Lopeta OpenRCT2 +STR_5160 :{POP16}{MONTH} {PUSH16}{PUSH16}{STRINGID}, Vuosi {POP16}{COMMA16} +STR_5161 :Päiväyksen tyyli: +STR_5162 :Päivä/Kuukausi/Vuosi +STR_5163 :Kuukausi/Päivä/Vuosi +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}Näytä taloushuijaukset +STR_5179 :{SMALLFONT}{BLACK}Näytä vierashuijaukset +STR_5180 :{SMALLFONT}{BLACK}Näytä puistohuijaukset +STR_5181 :{SMALLFONT}{BLACK}Näytä ajeluhuijaukset +STR_5182 :{INT32} +STR_5183 :Base height +STR_5184 :Enter base height between {COMMA16} and {COMMA16} +STR_5185 :Veden taso +STR_5186 :Enter water level between {COMMA16} and {COMMA16} +STR_5187 :Talous +STR_5188 :Uusi kampanja +STR_5189 :Tutkimustyö +STR_5190 :Kartta +STR_5191 :Viewport +STR_5192 :Viimeiset uutiset +STR_5193 :Maa +STR_5194 :Vesi +STR_5195 :Clear Scenery +STR_5196 :Maaoikeudet +STR_5197 :Scenery +STR_5198 :Jalkakäytävä +STR_5199 :Ride Construction +STR_5200 :Track Design Place +STR_5201 :Uusi ajelu +STR_5202 :Track Design Selection +STR_5203 :Ajelu +STR_5204 :Ajelulista +STR_5205 :Vieras +STR_5206 :Vieraslista +STR_5207 :Henkilökunta +STR_5208 :Henkilökuntalista +STR_5209 :Banner +STR_5210 :Object Selection +STR_5211 :Keksintölista +STR_5212 :Scenario Options +STR_5213 :Tavoiteasetukset +STR_5214 :Map Generation +STR_5215 :Track Design Manager +STR_5216 :Track Design Manager List +STR_5217 :Huijaukset +STR_5218 :Teemat +STR_5219 :Asetukset +STR_5220 :Näppäimistön pikanäppäimet +STR_5221 :Muuta näppäimistön pikanäppäimiä +STR_5222 :Lataa/Tallenna +STR_5223 :Tallennuskehote +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}Puisto +STR_5230 :{SMALLFONT}{BLACK}Työkalut +STR_5231 :{SMALLFONT}{BLACK}Rides and Peeps +STR_5232 :{SMALLFONT}{BLACK}Editors +STR_5233 :{SMALLFONT}{BLACK}Sekalaiset +STR_5234 :{SMALLFONT}{BLACK}Kehotteet +STR_5235 :{SMALLFONT}{BLACK}Asetukset +STR_5236 :Ikkuna: +STR_5237 :Väripaletti: +STR_5238 :Nykyinen teema: +STR_5239 :Kopioi +STR_5240 :Anna nimi teemalle +STR_5241 :Nimen muuttaminen ei onnistunut +STR_5242 :Teeman nimi on jo olemassa +STR_5243 :Virheellisiä merkkejä käytetty +STR_5244 :Teemat +STR_5245 :Ylhäällä työkalupalkki +STR_5246 :Alhaalla työkalupalkki +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 :Puiston tiedot +STR_5254 :Luo +STR_5255 :{SMALLFONT}{BLACK}Create a new title sequence from scratch +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}Poista nykyinen teema +STR_5259 :{SMALLFONT}{BLACK}Uudelleennimeä nykyinen teema +STR_5260 :Jättimäinen ruudunkaappaus +STR_5261 :Suodatin +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}Näyttö +STR_5267 :{SMALLFONT}{BLACK}Kulttuuri ja yksiköt +STR_5268 :{SMALLFONT}{BLACK}Ääni +STR_5269 :{SMALLFONT}{BLACK}Controls and interface +STR_5270 :{SMALLFONT}{BLACK}Sekalaiset +# again, twitch is a name, and can't be translated +STR_5271 :{SMALLFONT}{BLACK}Twitch +STR_5272 :{SMALLFONT}{BLACK}Small Scenery +STR_5273 :{SMALLFONT}{BLACK}Large Scenery +STR_5274 :{SMALLFONT}{BLACK}Jalkakäytävä +STR_5275 :Search for Objects +STR_5276 :Enter the name of an object to search for +STR_5277 :Tyhjennä +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}Ominaisuuksia +STR_5282 :RCT1 Ajelu auki/suljettu -valot +STR_5283 :RCT1 Puisto auki/kiinni -valot +STR_5284 :RCT1 Scenario Selection Font +STR_5285 :RÄJÄHTÄÄ!!! +STR_5286 :{SMALLFONT}{BLACK}Saa jotkut vieraat räjähtämään +STR_5287 :Ajelu on jo hajonnut +STR_5288 :Ajelu on suljettu +STR_5289 :No breakdowns available for this ride +STR_5290 :Korjaa ajelu +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}Sulje puisto +STR_5297 :{SMALLFONT}{BLACK}Avaa puisto +STR_5298 :{RED}{STRINGID} +STR_5299 :{LIGHTPINK}{STRINGID} +STR_5300 :{SMALLFONT}{BLACK}Quick fire staff +STR_5301 :{MEDIUMFONT}{BLACK}Poista lainasi +STR_5302 :Poista laina +STR_5303 :Salli rakentelu pelin ollessa pysäytetty +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 :Satunnainen +STR_5311 :{SMALLFONT}{BLACK}Debug tools +STR_5312 :Näytä komentokehote +STR_5313 :Show tile inspector +STR_5314 :Tile inspector +STR_5315 :Nurmikko +STR_5316 :Hiekka +STR_5317 :Pöly +STR_5318 :Kallio +STR_5319 :Marssilainen +STR_5320 :Shakkilauta +STR_5321 :Ruohokasoja +STR_5322 :Jää +STR_5323 :Ruudukko (punainen) +STR_5324 :Ruudukko (keltainen) +STR_5325 :Ruudukko (sininen) +STR_5326 :Ruudukko (vihreä) +STR_5327 :Hiekka (tumma) +STR_5328 :Hiekka (vaalea) +STR_5329 :Shakkilauta (käänteinen) +STR_5330 :Maanalainen näkymä +STR_5331 :Kallio +STR_5332 :Puu (punainen) +STR_5333 :Puu (musta) +STR_5334 :Jää +STR_5335 :Ajelun sisäänkäynti +STR_5336 :Ajelun uloskäynti +STR_5337 :Puiston sisäänkäynti +STR_5338 :Element type +STR_5339 :Base height +STR_5340 :Clearance height +STR_5341 :Flags +STR_5342 :Choose a map tile +STR_5343 :Automaattisesti aseta henkilöstö +STR_5344 :Muutosloki +STR_5345 :Taloushuijaukset +STR_5346 :Vierashuijaukset +STR_5347 :Puiston huijaukset +STR_5348 :Ajelun huijaukset +STR_5349 :{SMALLFONT}{BLACK}Kaikki ajelut +STR_5350 :Max +STR_5351 :Min +STR_5352 :{BLACK}Onnellisuus: +STR_5353 :{BLACK}Energia: +STR_5354 :{BLACK}Nälkä: +STR_5355 :{BLACK}Jano: +STR_5356 :{BLACK}Pahoinvointi: +STR_5357 :{BLACK}Pahoinvoinnin sietoraja: +STR_5358 :{BLACK}Vessa: +STR_5359 :Poista vieraat +STR_5360 :{SMALLFONT}{BLACK}Poista kaikki vieraat kartalta +STR_5361 :Anna kaikille vieraille: +STR_5362 :{BLACK}Set all guests' preferred ride intensity to: +STR_5363 :Enemmän kuin 1 +STR_5364 :Vähemmän kuin 15 +STR_5365 :{BLACK}Henkilökunnan nopeus: +STR_5366 :Normaali +STR_5367 :Nopea +STR_5368 :Reset crash status +STR_5369 :Puiston määritteet... +STR_5370 :{SMALLFONT}{BLACK}Click this button to modify park{NEWLINE}parameters like restrictions,{NEWLINE}guest generation and money. +STR_5371 :Object Selection +STR_5372 :Invert right mouse dragging +STR_5373 :Nimi {STRINGID} +STR_5374 :Päiväys {STRINGID} +STR_5375 :{UP} +STR_5376 :{DOWN} +STR_5377 :{SMALLFONT}{BLACK}Tallenteet +STR_5378 :{SMALLFONT}{BLACK}Komentosarja +STR_5379 :{SMALLFONT}{BLACK}Skip to next wait command +STR_5380 :{SMALLFONT}{BLACK}Start playing title sequence +STR_5381 :{SMALLFONT}{BLACK}Stop playing title sequence +STR_5382 :{SMALLFONT}{BLACK}Restart title sequence +STR_5383 :{SMALLFONT}{BLACK}Create a new title sequence based on the current one +STR_5384 :{SMALLFONT}{BLACK}Delete the current title sequence +STR_5385 :{SMALLFONT}{BLACK}Rename the current title sequence +STR_5386 :{SMALLFONT}{BLACK}Lisää uusi komento +STR_5387 :{SMALLFONT}{BLACK}Muokkaa uusi komento +STR_5388 :{SMALLFONT}{BLACK}Poista valittu komento +STR_5389 :{SMALLFONT}{BLACK}Skip to the selected command in the title sequence +STR_5390 :{SMALLFONT}{BLACK}Siirrä valittu komento alas +STR_5391 :{SMALLFONT}{BLACK}Siirrä valittu komento ylös +STR_5392 :{SMALLFONT}{BLACK}Add a save to the title sequence +STR_5393 :{SMALLFONT}{BLACK}Remove the selected save from the title sequence +STR_5394 :{SMALLFONT}{BLACK}Uudelleennimeä valittu tallenne +STR_5395 :{SMALLFONT}{BLACK}Lataa valittu tallenne pelissä +STR_5396 :{SMALLFONT}{BLACK}Reload the title sequence if changes have been made to it outside of the game +STR_5397 :Voidaan käyttää ainoastaan otsikkoruudussa +STR_5398 :Cannot edit title sequence while it's playing +STR_5399 :Press the stop button to continue editing +STR_5400 :Can't change this title sequence +STR_5401 :Create a new title sequence to make changes to +STR_5402 :Failed to load title sequence +STR_5403 :There may be no Load or Wait command or a save may be invalid +STR_5404 :Nimi on jo olemassa +STR_5405 :Anna nimi tallenteelle +STR_5406 :Enter a name for the title sequence +STR_5407 :Lisää +STR_5408 :Poista +STR_5409 :Insert +STR_5410 :Muokkaa +STR_5411 :Lataa uudelleen +STR_5412 :Skip to +STR_5413 :Lataa +STR_5414 :Lataa{MOVE_X}{87}Six Flags Magic Mountain.SC6 +STR_5415 :Lataa{MOVE_X}{87}{STRING} +STR_5416 :Lataa{MOVE_X}{87}Tallennetta ei ole valittu +STR_5417 :Sijainti +STR_5418 :Sijainti{MOVE_X}{87}{COMMA16} {COMMA16} +STR_5419 :Käännä +STR_5420 :Käännä{MOVE_X}{87}{COMMA16} +STR_5421 :Zoom +STR_5422 :Zoom{MOVE_X}{87}{COMMA16} +STR_5423 :Odota +STR_5424 :Odota{MOVE_X}{87}{COMMA16} +STR_5425 :Uudelleen käynnistä +STR_5426 :Lopeta +STR_5427 :Koordinaatit: +STR_5428 :Vastapäivään käännökset: +STR_5429 :Suurennus: +STR_5430 :Sekuntia odottaa: +STR_5431 :Tallenna lataakseen: +STR_5432 :Komento: +STR_5433 :Title Sequences +STR_5434 :Komentojenmuokkain +STR_5435 :Uudelleen nimeä tallenne +STR_5436 :Edit Title Sequences... +STR_5437 :Tallennusta ei valittuna +STR_5438 :Muutosten teko ei onnistu komentojenmuokkaimen ollessa päällä +STR_5439 :A wait command with at least 4 seconds is required with a restart command +STR_5440 :Minimise fullscreen on focus loss +STR_5441 :{SMALLFONT}{BLACK}Identifies rides by track type,{NEWLINE}so vehicles can be changed{NEWLINE}afterwards, like in RCT1. +STR_5442 :Pakota puiston luokitus: +STR_5443 :Nopeus{MOVE_X}{87}{STRINGID} +STR_5444 :Nopeus: +STR_5445 :Nopeus +STR_5446 :Hanki +STR_5447 :Tyyppi {STRINGID} +STR_5448 :Ajelu / Ajoneuvo {STRINGID} +STR_5449 :Vähennä pelin nopeutta +STR_5450 :Lisää pelin nopeutta +STR_5451 :Avaa huijausikkuna +STR_5452 :Toggle visibility of toolbars +STR_5453 :Valitse toinen ajelu +STR_5454 :Älä rajoita FPS +STR_5455 :Enable sandbox mode +STR_5456 :Disable clearance checks +STR_5457 :Disable support limits +STR_5458 :Käännä myötäpäivään +STR_5459 :Käännä vastapäivään +STR_5460 :Käännä näkymää vastapäivään +STR_5461 :Määritä vieraiden määritteitä +STR_5462 :{CURRENCY} +STR_5463 :Tavoite: Pidä hauskaa! +STR_5464 :Yleiset +STR_5465 :Ilmasto +STR_5466 :Henkilökunta +STR_5467 :ALT + +STR_5468 :Viimeiset viestit +STR_5469 :Vieritä karttaa ylös +STR_5470 :Vieritä karttaa vasemmalle +STR_5471 :Vieritä karttaa alas +STR_5472 :Vieritä karttaa oikealle +STR_5473 :Cycle day / night +STR_5474 :Display text on banners in upper case +STR_5475 :{COMMA16} viikkoa +STR_5476 :Laitteisto +STR_5477 :Map rendering +STR_5478 :Ohjaimet +STR_5479 :Työkalupalkki +STR_5480 :Show toolbar buttons for: +STR_5481 :Teemat +STR_5482 :{WINDOW_COLOUR_2}Aikaa viime tarkistuksesta: {BLACK}1 minuutti +STR_5483 :{BLACK}({COMMA16} viikkoa jäljellä) +STR_5484 :{BLACK}({COMMA16} viikko jäljellä) +STR_5485 :{SMALLFONT}{STRING} +STR_5486 :{BLACK}{COMMA16} +STR_5487 :{SMALLFONT}{BLACK}Näytä viimeiset viestit +STR_5488 :Ei sisäänkäyntiä +STR_5489 :{SMALLFONT}{BLACK}Show only tracked guests +STR_5490 :Disable audio on focus loss +STR_5491 :Keksinnötlista +STR_5492 :Scenario options +STR_5493 :Lähetä viesti +STR_5494 : +STR_5495 :Pelaajalista +STR_5496 :Pelaaja: +STR_5497 :Ping: +STR_5498 :Palvelinlista +STR_5499 :Pelaajan nimi: +STR_5500 :Lisää palvelin +STR_5501 :Käynistä palvelin +STR_5502 :Moninpeli +STR_5503 :Anna isäntänimi tai IP-osoite: +STR_5504 :{SMALLFONT}{BLACK}Näytä moninpelin tilanne +STR_5505 :Yhdistäminen ei onnistunut. +STR_5506 :Guests ignore intensities +STR_5507 :Yleismiehet leikkaavat ruohoa oletuksena +STR_5508 :Allow loading files with incorrect checksums +STR_5509 :{SMALLFONT}{BLACK}Allows loading scenarios and saves that have an incorrect checksum, like the scenarios from the demo or damaged saves. +STR_5510 :Oletus äänilaite +STR_5511 :(TUNTEMATON) +STR_5512 :Tallenna peli nimellä +STR_5513 :(Pika) tallenna peli +STR_5514 :Disable vandalism +STR_5515 :{SMALLFONT}{BLACK}Estää vieraita tärvelemästä puistoasi heidän ollessa vihaisia +STR_5516 :{SMALLFONT}{BLACK}Musta +STR_5517 :{SMALLFONT}{BLACK}Harmaa +STR_5518 :{SMALLFONT}{BLACK}Valkoinen +STR_5519 :{SMALLFONT}{BLACK}Tummanvioletti +STR_5520 :{SMALLFONT}{BLACK}Vaaleanvioletti +STR_5521 :{SMALLFONT}{BLACK}Kirkkaanvioletti +STR_5522 :{SMALLFONT}{BLACK}Tummansininen +STR_5523 :{SMALLFONT}{BLACK}Vaaleansininen +STR_5524 :{SMALLFONT}{BLACK}Jäinensininen +STR_5525 :{SMALLFONT}{BLACK}Sinivihreä +STR_5526 :{SMALLFONT}{BLACK}Akvamariini +STR_5527 :{SMALLFONT}{BLACK}Kyllästettyvihreä +STR_5528 :{SMALLFONT}{BLACK}Tummanvihreä +STR_5529 :{SMALLFONT}{BLACK}Sammaleenvihreä +STR_5530 :{SMALLFONT}{BLACK}Kirkkaanvihreä +STR_5531 :{SMALLFONT}{BLACK}Oliivinvihreä +STR_5532 :{SMALLFONT}{BLACK}Tummanoliivinvihreä +STR_5533 :{SMALLFONT}{BLACK}Kirkkaankeltainen +STR_5534 :{SMALLFONT}{BLACK}Keltainen +STR_5535 :{SMALLFONT}{BLACK}Tummankeltainen +STR_5536 :{SMALLFONT}{BLACK}Vaaleanoranssi +STR_5537 :{SMALLFONT}{BLACK}Tummanoranssi +STR_5538 :{SMALLFONT}{BLACK}Vaaleanruskea +STR_5539 :{SMALLFONT}{BLACK}Kyllästettyruskea +STR_5540 :{SMALLFONT}{BLACK}Tummanruskea +STR_5541 :{SMALLFONT}{BLACK}Lohenvaaleanpunainen +STR_5542 :{SMALLFONT}{BLACK}Bordeauxinpunainen +STR_5543 :{SMALLFONT}{BLACK}Kyllästetynpunainen +STR_5544 :{SMALLFONT}{BLACK}Kirkkaanpunainen +STR_5545 :{SMALLFONT}{BLACK}Tummanvaaleanpunainen +STR_5546 :{SMALLFONT}{BLACK}Kirkasvaaleanpunainen +STR_5547 :{SMALLFONT}{BLACK}Vaaleanpunainen +STR_5548 :Show all operating modes +STR_5549 :Vuosi/Kuukausi/Päivä +STR_5550 :{POP16}{POP16}Vuosi {COMMA16}, {PUSH16}{PUSH16}{MONTH} {PUSH16}{PUSH16}{STRINGID} +STR_5551 :Vuosi/Päivä/Kuukausi +STR_5552 :{POP16}{POP16}Vuosi {COMMA16}, {PUSH16}{PUSH16}{PUSH16}{STRINGID} {MONTH} + +######### +# Rides # +######### + +#WW +[CONDORRD] +STR_NAME :Condor Ride +STR_DESC :Riding in special harnesses below the track, riders experience the feeling of flight as they swoop through the air in Condor-shaped trains +STR_CPTY :4 matkustajaa per auto diff --git a/data/language/french.txt b/data/language/french.txt index 3322f1656a..82aaa48471 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 :Attraction -STR_0003 :Attraction +STR_0002 :Montagnes russes en spirales +STR_0003 :Montagnes russes debout STR_0004 :Suspended Swinging Coaster -STR_0005 :Attraction -STR_0006 :Junior Roller Coaster -STR_0007 :Miniature Railway +STR_0005 :Montagnes russes inversées +STR_0006 :Montagnes russes junior +STR_0007 :Chemin de fer miniature STR_0008 :Monorail -STR_0009 :Mini Suspended Coaster -STR_0010 :Attraction -STR_0011 :Attraction -STR_0012 :Attraction -STR_0013 :Car Ride -STR_0014 :Attraction -STR_0015 :Attraction -STR_0016 :Attraction +STR_0009 :Mini montagnes russes suspendues +STR_0010 :Boat Hire +STR_0011 :Wooden Wild Mouse +STR_0012 :Steeplechase +STR_0013 :Balade en voiture +STR_0014 :Launched Freefall +STR_0015 :Bobsleigh Coaster +STR_0016 :Tour d'observation STR_0017 :Looping Roller Coaster -STR_0018 :Attraction -STR_0019 :Attraction +STR_0018 :Dinghy Slide +STR_0019 :Train de la mine STR_0020 :Chairlift -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 :Attraction -STR_0036 :Stall -STR_0037 :Kiosk +STR_0021 :Corkscrew Roller Coaster +STR_0022 :Labyrinthe +STR_0023 :Toboggan spiral +STR_0024 :Go Karts +STR_0025 :Log Flume +STR_0026 :River Rapids +STR_0027 :Dodgems +STR_0028 :Bateau pirate +STR_0029 :Swinging Inverter Ship +STR_0030 :Stand de nourriture +STR_0031 :Unknown Stall (1D) +STR_0032 :Stand de boissons +STR_0033 :Unknown Stall (1F) +STR_0034 :Boutique +STR_0035 :Manège +STR_0036 :Unknown Stall (22) +STR_0037 :Kiosque d'information STR_0038 :Toilettes -STR_0039 :Attraction -STR_0040 :Attraction -STR_0041 :Attraction -STR_0042 :Attraction -STR_0043 :Attraction +STR_0039 :Grande roue +STR_0040 :Simulateur de mouvements +STR_0041 :Cinéma 3D +STR_0042 :Top Spin +STR_0043 :Anneaux de l'espace STR_0044 :Reverse Freefall Coaster -STR_0045 :Lift -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_0045 :Ascenseur +STR_0046 :Vertical Drop Roller Coaster +STR_0047 :Distributeur de monnaie +STR_0048 :Twist +STR_0049 :Maison hantée +STR_0050 :Infirmerie +STR_0051 :Spectacle de cirque +STR_0052 :Train fantôme +STR_0053 :Steel Twister Roller Coaster +STR_0054 :Montagnes russes en bois STR_0055 :Side-Friction Roller Coaster -STR_0056 :Wild Mouse +STR_0056 :Souris sauvage STR_0057 :Multi-Dimension Roller Coaster -STR_0058 :Attraction -STR_0059 :Aerial Inverted Roller Coaster -STR_0060 :Attraction -STR_0061 :Attraction -STR_0062 :Attraction -STR_0063 :Attraction -STR_0064 :Attraction -STR_0065 :Suspended Monorail -STR_0066 :Attraction -STR_0067 :Attraction +STR_0058 :Unknown Ride (38) +STR_0059 :Montagnes russes volantes +STR_0060 :Unknown Ride (3A) +STR_0061 :Virginia Reel +STR_0062 :Splash Boats +STR_0063 :Mini hélicoptères +STR_0064 :Lay-down Roller Coaster +STR_0065 :Monorail suspendu +STR_0066 :Unknown Ride (40) +STR_0067 :Reverser Roller Coaster STR_0068 :Heartline Twister Coaster -STR_0069 :Attraction -STR_0070 :Attraction -STR_0071 :Attraction -STR_0072 :Attraction -STR_0073 :Attraction -STR_0074 :Attraction -STR_0075 :Attraction +STR_0069 :Mini-golf +STR_0070 :Giga Coaster +STR_0071 :Roto-Drop +STR_0072 :Flying Saucers +STR_0073 :Maison bizarre +STR_0074 :Monorail Cycles +STR_0075 :Compact Inverted Coaster STR_0076 :Water Coaster -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 :Attraction -STR_0091 :Attraction -STR_0092 :Attraction +STR_0077 :Air Powered Vertical Coaster +STR_0078 :Inverted Hairpin Coaster +STR_0079 :Tapis volant +STR_0080 :Balade sous-marine +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 montagnes russes +STR_0090 :Mine Ride +STR_0091 :Unknown Ride (59) +STR_0092 :LIM Launched Roller Coaster STR_0093 : STR_0094 : STR_0095 : @@ -513,31 +513,31 @@ STR_0508 : STR_0509 : STR_0510 : STR_0511 : -STR_0512 : -STR_0513 : +STR_0512 :A compact roller coaster with a spiral lift hill and smooth, twisting drops. +STR_0513 :A looping roller coaster where the riders ride in a standing position STR_0514 :Trains suspended beneath the roller coaster track swing out to the side around corners -STR_0515 : +STR_0515 :A steel roller coaster with trains that are held beneath the track, with many complex and twisting track elements STR_0516 :A gentle roller coaster for people who haven't yet got the courage to face the larger rides STR_0517 :Passengers ride in miniature trains along a narrow-gauge railway track STR_0518 :Passengers travel in electric trains along a monorail track STR_0519 :Passengers ride in small cars hanging beneath the single-rail track, swinging freely from side to side around corners -STR_0520 : -STR_0521 : -STR_0522 : +STR_0520 :A dock platform where guests can drive/row personal watercraft on a body of water +STR_0521 :A fast and twisting roller coaster with tight turns and steep drops. Intensity is bound to be high. +STR_0522 :A smaller roller coaster where the riders sit above the track with no car around them STR_0523 :Riders travel slowly in powered vehicles along a track-based route -STR_0524 : -STR_0525 : -STR_0526 : +STR_0524 :Freefall car is pneumatically launched up a tall steel tower and then allowed to freefall down +STR_0525 :Riders career down a twisting track guided only by the curvature and banking of the semi-circular track +STR_0526 :Passengers travel in a rotating observation cabin which travels up a tall tower STR_0527 :A smooth steel-tracked roller coaster capable of vertical loops -STR_0528 : -STR_0529 : +STR_0528 :Riders travel in inflatable dinghies down a twisting semi-circular or completely enclosed tube track +STR_0529 :Mine train themed roller coaster trains career along steel roller coaster track made to look like old railway track STR_0530 :Cars hang from a steel cable which runs continuously from one end of the ride to the other and back again -STR_0531 : +STR_0531 :A compact steel-tracked roller coaster where the train travels through corkscrews and loops STR_0532 : STR_0533 : -STR_0534 : -STR_0535 : -STR_0536 : +STR_0534 :Self-drive petrol-engined go karts +STR_0535 :Log-shaped boats travel along a water channel, splashing down steep slopes to soak the riders +STR_0536 :Circular boats meander along a wide water channel, splashing through waterfalls and thrilling riders through foaming rapids STR_0537 : STR_0538 : STR_0539 : @@ -556,14 +556,14 @@ STR_0551 : STR_0552 : STR_0553 : STR_0554 :The car is accelerated out of the station along a long level track using Linear Induction Motors, then heads straight up a vertical spike of track, freefalling back down to return to the station -STR_0555 : -STR_0556 : +STR_0555 :Guests ride in an elevator up or down a vertical tower to get from one level to another +STR_0556 :Extra-wide cars descend completely vertical sloped track for the ultimate freefall roller coaster experience STR_0557 : STR_0558 : STR_0559 : STR_0560 : STR_0561 : -STR_0562 : +STR_0562 :Powered cars travel along a multi-level track past spooky scenery and special effects STR_0563 :Sitting in comfortable trains with only simple lap restraints riders enjoy giant smooth drops and twisting track as well as plenty of 'air time' over the hills STR_0564 :Running on wooden track, this coaster is fast, rough, noisy, and gives an 'out of control' riding experience with plenty of 'air time' STR_0565 :A simple wooden roller coaster capable of only gentle slopes and turns, where the cars are only kept on the track by side friction wheels and gravity @@ -572,38 +572,38 @@ STR_0567 :Sitting in seats suspended either side of the track, riders are pit STR_0568 : STR_0569 :Riding in special harnesses below the track, riders experience the feeling of flight as they swoop through the air STR_0570 : -STR_0571 : -STR_0572 : -STR_0573 : -STR_0574 : +STR_0571 :Circular cars spin around as they travel along the zig-zagging wooden track +STR_0572 :Large capacity boats travel along a wide water channel, propelled up slopes by a conveyer belt, accelerating down steep slopes to soak the riders with a gaint splash +STR_0573 :Powered helicoper shaped cars running on a steel track, controlled by the pedalling of the riders +STR_0574 :Riders are held in special harnesses in a lying-down position, travlling through twisted track and inversions either on their backs or facing the ground STR_0575 :Powered trains hanging from a single rail transport people around the park STR_0576 : -STR_0577 : +STR_0577 :Bogied cars run on wooden tracks, turning around on special reversing sections STR_0578 :Cars run along track enclosed by circular hoops, traversing steep drops and heartline twists STR_0579 : STR_0580 : STR_0581 : STR_0582 : STR_0583 : -STR_0584 : -STR_0585 : +STR_0584 :Special bicycles run on a steel monorail track, propelled by the pedalling of the riders +STR_0585 :Riders sit in pairs of seats suspended beneath the track as they loop and twist through tight inversions STR_0586 :Boat shaped cars run on roller coaster track to allow twisting curves and steep drops, splashing down into sections of water for gentle river sections -STR_0587 : -STR_0588 : +STR_0587 :After an exhilarating air-powered launch, the train speeds up a vertical track, over the top, and vertically down the other side to return to the station +STR_0588 :Individual cars run beneath a zig-zagging track with hairpin turns and sharp drops STR_0589 : -STR_0590 : -STR_0591 : +STR_0590 :Riders ride in a submerged submarine through an underwater course +STR_0591 :Raft-shaped boats gently meander around a river track STR_0592 : STR_0593 : STR_0594 : STR_0595 : STR_0596 : STR_0597 : -STR_0598 : +STR_0598 :Inverted roller coaster trains are accelerated out of the station to travel up a vertical spike of track, then reverse back through the station to travel backwards up another vertical spike of track STR_0599 :A compact roller coaster with individual cars and smooth twisting drops -STR_0600 : +STR_0600 :Powered mine trains career along a smooth and twisted track layout STR_0601 : -STR_0602 : +STR_0602 :Roller coaster trains are accelerated out of the station by linear induction motors to speed through twisting inversions STR_0603 :Visiteur {INT32} STR_0604 :Visiteur {INT32} STR_0605 :Visiteur {INT32} @@ -823,32 +823,34 @@ STR_0818 :Sep STR_0819 :Oct STR_0820 :Nov STR_0821 :Déc -STR_0822 :Unable to access graphic data file -STR_0823 :Missing or inaccessible data file +STR_0822 :Impossible d'accéder au fichier de données graphiques +STR_0823 :Fichier de données manquant ou inaccessible STR_0824 :{BLACK}{CROSS} -STR_0825 :Chosen name in use already -STR_0826 :Too many names defined -STR_0827 :Not enough cash - requires {CURRENCY2DP} -STR_0828 :{SMALLFONT}{BLACK}Close window -STR_0829 :{SMALLFONT}{BLACK}Window title - Drag this to move window -STR_0830 :{SMALLFONT}{BLACK}Zoom view in -STR_0831 :{SMALLFONT}{BLACK}Zoom view out -STR_0832 :{SMALLFONT}{BLACK}Rotate view 90{DEGREE} clockwise -STR_0833 :{SMALLFONT}{BLACK}Pause game -STR_0834 :{SMALLFONT}{BLACK}Disk and game options -STR_0835 :Game initialization failed -STR_0836 :Unable to start game in a minimized state -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_0825 :Nom choisi déjà utilisé +STR_0826 :Trop de noms définis +STR_0827 :Pas assez d'argent - Nécessite {CURRENCY2DP} +STR_0828 :{SMALLFONT}{BLACK}Fermer la fenêtre +STR_0829 :{SMALLFONT}{BLACK}Titre de la fenêtre - Faites glisser ceci pour déplacer la fenêtre +STR_0830 :{SMALLFONT}{BLACK}Zoomer sur la vue +STR_0831 :{SMALLFONT}{BLACK}Dézoomer sur la vue +STR_0832 :{SMALLFONT}{BLACK}Tourner la vue de 90{DEGREE} dans le sens des aiguilles d'une montre +STR_0833 :{SMALLFONT}{BLACK}Mettre en pause le jeu +STR_0834 :{SMALLFONT}{BLACK}Options du jeu et du disque +STR_0835 :L'initialisation du jeu a échouée +STR_0836 :Impossible de démarrer le jeu minimisé +STR_0837 :Impossible d'initialiser le système de graphiques +STR_0838 : STR_0839 :{UINT16} x {UINT16} STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} -STR_0841 :En une fenêtre -STR_0842 :640x480 plein écran -STR_0843 :800x600 plein écran -STR_0844 :1024x768 plein écran -STR_0845 :1152x864 plein écran -STR_0846 :1280x1024 plein écran -STR_0847 :A propos 'RollerCoaster Tycoon 2' +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +#end +STR_0847 :A propos d'OpenRCT2 STR_0848 :RollerCoaster Tycoon 2 STR_0849 :{WINDOW_COLOUR_2}Version 2.01.028 STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, tous droits réservés @@ -878,67 +880,67 @@ 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 :Too low ! -STR_0878 :Too high ! -STR_0879 :Can't lower land here... -STR_0880 :Can't raise land here... -STR_0881 :Object in the way +STR_0877 :Trop bas! +STR_0878 :Trop haut! +STR_0879 :Impossible d'abaisser le terrain ici... +STR_0880 :Impossible de surélever le terrain ici... +STR_0881 :Objet dans le passage STR_0882 :Charger partie STR_0883 :Sauvegarder partie -STR_0884 :Load Landscape -STR_0885 :Save Landscape +STR_0884 :Charger paysage +STR_0885 :Sauvegarder paysage STR_0886 :Quitter la partie -STR_0887 :Quitter l'Editeur de scénario -STR_0888 :Quitter Roller Coaster Designer -STR_0889 :Quit Track Designs Manager +STR_0887 :Quitter l'Éditeur de scénario +STR_0888 :Quitter le concepteur de montagnes russes +STR_0889 :Quitter le gestionnaire des voies STR_0890 :SCR{COMMA16}.BMP STR_0891 :Capture d'écran -STR_0892 :Screenshot saved to disk as '{STRINGID}' -STR_0893 :Screenshot failed ! +STR_0892 :Capture d'écran sauvegardée en tant que '{STRINGID}' +STR_0893 :La capture d'écran a échouée! STR_0894 :Landscape data area full ! -STR_0895 :Can't build partly above and partly below ground +STR_0895 :Impossible de construire partiellement au dessus et partiellement en dessous du sol STR_0896 :{POP16}{POP16}{STRINGID} Construction STR_0897 :Direction -STR_0898 :{SMALLFONT}{BLACK}Left-hand curve -STR_0899 :{SMALLFONT}{BLACK}Right-hand curve -STR_0900 :{SMALLFONT}{BLACK}Left-hand curve (small radius) -STR_0901 :{SMALLFONT}{BLACK}Right-hand curve (small radius) -STR_0902 :{SMALLFONT}{BLACK}Left-hand curve (very small radius) -STR_0903 :{SMALLFONT}{BLACK}Right-hand curve (very small radius) -STR_0904 :{SMALLFONT}{BLACK}Left-hand curve (large radius) -STR_0905 :{SMALLFONT}{BLACK}Right-hand curve (large radius) -STR_0906 :{SMALLFONT}{BLACK}Straight -STR_0907 :Slope +STR_0898 :{SMALLFONT}{BLACK}Courbe à gauche +STR_0899 :{SMALLFONT}{BLACK}Courbe à droite +STR_0900 :{SMALLFONT}{BLACK}Courbe à gauche (petit rayon) +STR_0901 :{SMALLFONT}{BLACK}Courbe à droite (petit rayon) +STR_0902 :{SMALLFONT}{BLACK}Courbe à gauche (très petit rayon) +STR_0903 :{SMALLFONT}{BLACK}Courbe à droite (très petit rayon) +STR_0904 :{SMALLFONT}{BLACK}Courbe à gauche (grand rayon) +STR_0905 :{SMALLFONT}{BLACK}Courbe à droite (grand rayon) +STR_0906 :{SMALLFONT}{BLACK}Droit +STR_0907 :Pente STR_0908 :Roll/Banking -STR_0909 :Seat Rot. +STR_0909 :Rot. des sièges. STR_0910 :{SMALLFONT}{BLACK}Roll for left-hand curve STR_0911 :{SMALLFONT}{BLACK}Roll for right-hand curve STR_0912 :{SMALLFONT}{BLACK}No roll -STR_0913 :{SMALLFONT}{BLACK}Move to previous section -STR_0914 :{SMALLFONT}{BLACK}Move to next section +STR_0913 :{SMALLFONT}{BLACK}Aller à la section précédente +STR_0914 :{SMALLFONT}{BLACK}Aller à la section suivante STR_0915 :{SMALLFONT}{BLACK}Construct the selected section STR_0916 :{SMALLFONT}{BLACK}Remove the highlighted section -STR_0917 :{SMALLFONT}{BLACK}Vertical drop +STR_0917 :{SMALLFONT}{BLACK}Chute verticale STR_0918 :{SMALLFONT}{BLACK}Steep slope down STR_0919 :{SMALLFONT}{BLACK}Slope down -STR_0920 :{SMALLFONT}{BLACK}Level +STR_0920 :{SMALLFONT}{BLACK}Niveau STR_0921 :{SMALLFONT}{BLACK}Slope up STR_0922 :{SMALLFONT}{BLACK}Steep slope up STR_0923 :{SMALLFONT}{BLACK}Vertical rise -STR_0924 :{SMALLFONT}{BLACK}Helix down -STR_0925 :{SMALLFONT}{BLACK}Helix up -STR_0926 :Can't remove this... -STR_0927 :Can't construct this here... +STR_0924 :{SMALLFONT}{BLACK}Hélice descendante +STR_0925 :{SMALLFONT}{BLACK}Hélice montante +STR_0926 :Impossible de supprimer ceci... +STR_0927 :Impossible de construire ceci ici... STR_0928 :{SMALLFONT}{BLACK}Chain lift, to pull cars up slopes -STR_0929 :'S' Bend (left) -STR_0930 :'S' Bend (right) -STR_0931 :Vertical Loop (left) -STR_0932 :Vertical Loop (right) -STR_0933 :Raise or lower land first -STR_0934 :Ride entrance in the way -STR_0935 :Ride exit in the way -STR_0936 :Park entrance in the way -STR_0937 :{SMALLFONT}{BLACK}View options +STR_0929 :Courbe en 'S' (gauche) +STR_0930 :Courbe en 'S' (droite) +STR_0931 :Boucle verticale (gauche) +STR_0932 :Boucle verticale (droite) +STR_0933 :Surélevez ou abaissez le terrain d'abord +STR_0934 :Entrée de l'attraction dans le passage +STR_0935 :Sortie de l'attraction dans le passage +STR_0936 :Entrée du parc dans le passage +STR_0937 :{SMALLFONT}{BLACK}Voir les options STR_0938 :{SMALLFONT}{BLACK}Adjust land height and slope STR_0939 :Vue souterraine/intérieure STR_0940 :Supprimer surface de base @@ -948,15 +950,15 @@ STR_0943 :Décor transparent STR_0944 :Sauvegarder STR_0945 :Ne pas sauvegarder STR_0946 :Annuler -STR_0947 :Save this before loading ? -STR_0948 :Save this before quitting ? -STR_0949 :Save this before quitting ? +STR_0947 :Sauvegarder ceci avant de charger ? +STR_0948 :Sauvegarder ceci avant de quitter ? +STR_0949 :Sauvegarder ceci avant de quitter ? STR_0950 :Charger une partie STR_0951 :Quitter la partie STR_0952 :Quitter la partie -STR_0953 :Load Landscape +STR_0953 :Charger le paysage STR_0954 : -STR_0955 :{SMALLFONT}{BLACK}Select seat rotation angle for this track section +STR_0955 :{SMALLFONT}{BLACK}Sélectionnez l'angle de rotation des sièges pour cette section de voie STR_0956 :-180{DEGREE} STR_0957 :-135{DEGREE} STR_0958 :-90{DEGREE} @@ -975,223 +977,223 @@ STR_0970 :+450{DEGREE} STR_0971 :+495{DEGREE} STR_0972 :Annuler STR_0973 :OK -STR_0974 :Rides -STR_0975 :Shops and Stalls -STR_0976 :Restrooms and Information Kiosks -STR_0977 :New Transport Rides -STR_0978 :New Gentle Rides +STR_0974 :Attractions +STR_0975 :Magasins et stands +STR_0976 :Toilettes et kiosques d'information +STR_0977 :Nouveaux moyens de transport +STR_0978 :Nouvelles attractions calmes STR_0979 :Nouvelles montagnes russes -STR_0980 :New Thrill Rides -STR_0981 :New Water Rides -STR_0982 :New Shops & Stalls -STR_0983 :Research & Development +STR_0980 :Nouvelles attractions à frissons +STR_0981 :Nouvelles attractions aquatiques +STR_0982 :Nouveaux magasins et stands +STR_0983 :Recherche & Développement STR_0984 :{WINDOW_COLOUR_2}{UP}{BLACK} {CURRENCY2DP} STR_0985 :{WINDOW_COLOUR_2}{DOWN}{BLACK} {CURRENCY2DP} STR_0986 :{BLACK}{CURRENCY2DP} -STR_0987 :Too many rides/attractions -STR_0988 :Can't create new ride/attraction... +STR_0987 :Trop d'attractions +STR_0988 :Impossible de créer une nouvelle 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 -STR_0998 :No more stations allowed on this ride -STR_0999 :Requires a station platform -STR_1000 :Track is not a complete circuit -STR_1001 :Track unsuitable for type of train -STR_1002 :Can't open {POP16}{POP16}{POP16}{STRINGID}... -STR_1003 :Can't test {POP16}{POP16}{POP16}{STRINGID}... -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_0991 :Quai +STR_0992 :{SMALLFONT}{BLACK}Démolir toute l'attraction +STR_0993 :Démolir l'attraction +STR_0994 :Démolir +STR_0995 :{WINDOW_COLOUR_1}Êtes-vous vraiment sûr de vouloir démolir {STRINGID}? +STR_0996 :Vue générale +STR_0997 :{SMALLFONT}{BLACK}Vue sur la sélection +STR_0998 :Plus de stations autorisées sur cette attraction +STR_0999 :Nécessite un quai +STR_1000 :La voie n'est pas un circuit complet +STR_1001 :La voie est inadaptée à ce type de train +STR_1002 :Impossible d'ouvrir {POP16}{POP16}{POP16}{STRINGID}... +STR_1003 ::Impossible de tester {POP16}{POP16}{POP16}{STRINGID}... +STR_1004 ::Impossible de fermer {POP16}{POP16}{POP16}{STRINGID}... +STR_1005 ::Impossible de commencer la construction sur {POP16}{POP16}{POP16}{STRINGID}... +STR_1006 :Doit être fermé d'abord +STR_1007 :Impossible de créer suffisamment de véhicules +STR_1008 :{SMALLFONT}{BLACK}Ouvrir, fermer ou tester une attraction +STR_1009 :{SMALLFONT}{BLACK}Ouvrir, fermer ou tester toutes les attractions +STR_1010 :{SMALLFONT}{BLACK}Ouvrir ou fermer le parc STR_1011 :Tout fermer STR_1012 :Tout ouvrir STR_1013 :Fermer le parc STR_1014 :Ouvrir le parc -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... -STR_1018 :Can't make changes... -STR_1019 :Can't make changes... -STR_1020 :Can't make changes... +STR_1015 :Impossible de fonctionner avec plus d'une platforme de station dans ce mode +STR_1016 :Impossible de fonctionner avec moins de deux stations dans ce mode +STR_1017 :Impossible de changer le mode d'opération... +STR_1018 :Impossible d'appliquer les changements... +STR_1019 :Impossible d'appliquer les changements... +STR_1020 :Impossible d'appliquer les changements... STR_1021 :{POP16}{POP16}{POP16}{POP16}{STRINGID} -STR_1022 :{POP16}{POP16}{POP16}{COMMA16} car per train -STR_1023 :{POP16}{POP16}{POP16}{COMMA16} cars per train +STR_1022 :{POP16}{POP16}{POP16}{COMMA16} voiture par train +STR_1023 :{POP16}{POP16}{POP16}{COMMA16} voitures par trains STR_1024 :{COMMA16} voiture par train STR_1025 :{COMMA16} voitures par train -STR_1026 :Station platform too long! -STR_1027 :{SMALLFONT}{BLACK}Locate this on Main View -STR_1028 :Off edge of map! -STR_1029 :Cannot build partly above and partly below water! -STR_1030 :Can only build this underwater! -STR_1031 :Can't build this underwater! -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_1026 :Le quai est trop long! +STR_1027 :{SMALLFONT}{BLACK}Localiser sur la vue générale +STR_1028 :En dehors de la carte! +STR_1029 :Impossible de construire partiellement au dessus et partiellement en dessous de l'eau! +STR_1030 :Ne peut être construit que sous l'eau! +STR_1031 :Impossible de construire ceci sous l'eau! +STR_1032 :Ne peut être construit que sur l'eau! +STR_1033 :Ne peut être construit qu'au dessus du sol! +STR_1034 :Ne peut être construit que sur le sol! +STR_1035 :Les autorités locales n'autoriseront pas les constructions plus hautes qu'un arbre! STR_1036 :Charger une partie -STR_1037 :Load Landscape -STR_1038 :Convert saved game to scenario -STR_1039 :Install new track design +STR_1037 :Charger un paysage +STR_1038 :Convertir une partie sauvegardée en scénario +STR_1039 :Installer un nouveau modèle de voie STR_1040 :Sauvegarder la partie STR_1041 :Sauvegarder le scénario -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 -STR_1057 :Ride/attraction name -STR_1058 :Enter new name for this ride/attraction: -STR_1059 :Can't rename ride/attraction... -STR_1060 :Invalid ride/attraction name -STR_1061 :Normal mode -STR_1062 :Continuous circuit mode +STR_1042 :Sauvegarder le paysage +STR_1043 :Partie sauvegardée OpenRCT2 +STR_1044 :Fichier de scénario OpenRCT2 +STR_1045 :Fichier de paysage OpenRCT2 +STR_1046 :Modèle de voie OpenRCT2 +STR_1047 :La sauvegarde du jeu a échouée! +STR_1048 :La sauvegarde du scénario a échouée! +STR_1049 :La sauvegarde du paysage a échouée! +STR_1050 :Impossible de charger...{NEWLINE}Le fichier contient des données invalides! +STR_1051 :Supports invisibles +STR_1052 :Visiteurs invisibles +STR_1053 :{SMALLFONT}{BLACK}Attractions dans le parc +STR_1054 :{SMALLFONT}{BLACK}Nommer l'attraction +STR_1055 :{SMALLFONT}{BLACK}Nommer la personne +STR_1056 :{SMALLFONT}{BLACK}Nommer l'employé +STR_1057 :Nom de l'attraction +STR_1058 :Entrez un nom pour cette attraction : +STR_1059 :Impossible de renommer l'attraction... +STR_1060 :Nom d'attraction invalide +STR_1061 :Mode normal +STR_1062 :Mode circuit continu STR_1063 :Reverse-Incline launched shuttle mode STR_1064 :Lancement (avec passage de la station) STR_1065 :Shuttle mode STR_1066 :Boat hire mode STR_1067 :Upward launch -STR_1068 :Rotating lift mode -STR_1069 :Station to station mode -STR_1070 :Single ride per admission -STR_1071 :Unlimited rides per admission -STR_1072 :Maze mode -STR_1073 :Race mode -STR_1074 :Bumper-car mode +STR_1068 :Mode ascenseur en rotation +STR_1069 :Mode station à station +STR_1070 :Un seul tour par entrée +STR_1071 :Tours illimités par entrée +STR_1072 :Mode labyrinthe +STR_1073 :Mode course +STR_1074 :Mode auto-tamponneuses STR_1075 :Swing mode -STR_1076 :Shop stall mode -STR_1077 :Rotation mode -STR_1078 :Forward rotation -STR_1079 :Backward rotation -STR_1080 :Film: {ENDQUOTES}Avenging aviators{ENDQUOTES} -STR_1081 :3D film: {ENDQUOTES}Mouse tails{ENDQUOTES} -STR_1082 :Space rings mode -STR_1083 :Beginners mode +STR_1076 :Mode stand de boutique +STR_1077 :Mode rotation +STR_1078 :Rotation vers l'avant +STR_1079 :Rotation vers l'arrière +STR_1080 :Film: {ENDQUOTES}Les aviateurs vengeurs{ENDQUOTES} +STR_1081 :3D film: {ENDQUOTES}Queues de souris{ENDQUOTES} +STR_1082 :Mode anneaux de l'espace +STR_1083 :Mode débutants STR_1084 :LIM-powered launch -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 mode +STR_1085 :Film: {ENDQUOTES}Le grand frisson{ENDQUOTES} +STR_1086 :3D film: {ENDQUOTES}Chasseurs de tempêtes{ENDQUOTES} +STR_1087 :3D film: {ENDQUOTES}Commandos de l'espace{ENDQUOTES} +STR_1088 :Mode intense STR_1089 :Berserk mode -STR_1090 :Haunted house mode -STR_1091 :Circus show mode +STR_1090 :Mode maison hantée +STR_1091 :Mode spectacle de cirque STR_1092 :Downward launch -STR_1093 :Crooked house mode -STR_1094 :Freefall drop mode +STR_1093 :Mode maison biscornue +STR_1094 :Mode chute libre STR_1095 :Continuous circuit block sectioned mode 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} -STR_1100 :Waiting to depart {POP16}{STRINGID} -STR_1101 :Departing {POP16}{STRINGID} -STR_1102 :Traveling at {VELOCITY} -STR_1103 :Arriving at {POP16}{STRINGID} -STR_1104 :Unloading passengers at {POP16}{STRINGID} -STR_1105 :Traveling at {VELOCITY} -STR_1106 :Crashing! -STR_1107 :Crashed! -STR_1108 :Traveling at {VELOCITY} -STR_1109 :Swinging -STR_1110 :Rotating -STR_1111 :Rotating -STR_1112 :Operating -STR_1113 :Showing film -STR_1114 :Rotating -STR_1115 :Operating -STR_1116 :Operating -STR_1117 :Doing circus show -STR_1118 :Operating -STR_1119 :Waiting for cable lift -STR_1120 :Traveling at {VELOCITY} -STR_1121 :Stopping -STR_1122 :Waiting for passengers -STR_1123 :Waiting to start -STR_1124 :Starting -STR_1125 :Operating -STR_1126 :Stopping -STR_1127 :Unloading passengers -STR_1128 :Stopped by block brakes -STR_1129 :All vehicles in same colors -STR_1130 :Different colors per {STRINGID} -STR_1131 :Different colors per vehicle -STR_1132 :Vehicle {POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} -STR_1133 :Vehicle {POP16}{COMMA16} +STR_1098 :Se déplace vers la fin de {POP16}{STRINGID} +STR_1099 :Attend des passagers à {POP16}{STRINGID} +STR_1100 :Attend pour quitter {POP16}{STRINGID} +STR_1101 :Part de {POP16}{STRINGID} +STR_1102 :Voyage à {VELOCITY} +STR_1103 :Arrive à {POP16}{STRINGID} +STR_1104 :Dépose des passagers à {POP16}{STRINGID} +STR_1105 :Voyage à {VELOCITY} +STR_1106 :S'écrase! +STR_1107 :Écrasé! +STR_1108 :Voyage à {VELOCITY} +STR_1109 :Se balance +STR_1110 :Pivote +STR_1111 :Pivote +STR_1112 :Fonctionne +STR_1113 :Diffuse le film +STR_1114 :Pivote +STR_1115 :Fonctionne +STR_1116 :Fonctionne +STR_1117 :Spectacle de cirque en cours +STR_1118 :Fonctionne +STR_1119 :Attend la montée par câble +STR_1120 :Voyage à{VELOCITY} +STR_1121 :S'arrête +STR_1122 :Attend des passagers +STR_1123 :Attend le départ +STR_1124 :Démarre +STR_1125 :Fonctionne +STR_1126 :S'arrête +STR_1127 :Dépose des passagers +STR_1128 :Arrété par les blocs de freins +STR_1129 :Tous les véhicules de la même couleur +STR_1130 :Couleurs différentes par {STRINGID} +STR_1131 :Couleurs différentes par véhicule +STR_1132 :Véhicule {POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1133 :Véhicule {POP16}{COMMA16} STR_1134 :{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} {COMMA16} STR_1135 :{STRINGID} {COMMA16} -STR_1136 :{SMALLFONT}{BLACK}Select main color -STR_1137 :{SMALLFONT}{BLACK}Select additional color 1 -STR_1138 :{SMALLFONT}{BLACK}Select additional color 2 -STR_1139 :{SMALLFONT}{BLACK}Select support structure color -STR_1140 :{SMALLFONT}{BLACK}Select vehicle color scheme option -STR_1141 :{SMALLFONT}{BLACK}Select which vehicle/train to modify +STR_1136 :{SMALLFONT}{BLACK}Sélectionnez la couleur principale +STR_1137 :{SMALLFONT}{BLACK}Sélectionnez la couleur supplémentaire 1 +STR_1138 :{SMALLFONT}{BLACK}Sélectionnez la couleur supplémentaire 2 +STR_1139 :{SMALLFONT}{BLACK}Sélectionnez la couleur de la structure de support +STR_1140 :{SMALLFONT}{BLACK}Sélectionnez le motif de couleur du véhicule +STR_1141 :{SMALLFONT}{BLACK}Sélectionnez quel véhicule/train à modifier STR_1142 :{MOVE_X}{SMALLFONT}{STRINGID} STR_1143 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRINGID} -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 +STR_1144 :Impossible de construire/déplacer l'entrée de cette attraction... +STR_1145 :Impossible de construire/déplacer la sortie de cette attraction... +STR_1146 :Entrée pas encore construite +STR_1147 :Sortie pas encore construite +STR_1148 :Quart de la charge +STR_1149 :Moitiée de la charge +STR_1150 :Trois-quarts de la charge +STR_1151 :Charge totale +STR_1152 :N'importe quelle charge +STR_1153 :Niveau de hauteur sur les voies +STR_1154 :Niveau de hauteur sur le terrain +STR_1155 :Niveau de hauteur sur les chemins 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 :Impossible de supprimer ceci... +STR_1159 :{SMALLFONT}{BLACK}Placer le décor, les jardins, et autres accessoires +STR_1160 :{SMALLFONT}{BLACK}Créer/Adjuster les lacs et l'eau +STR_1161 :Impossible de positionner ceci ici... 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}(Clic-droit pour modifier) +STR_1164 :{STRINGID}{NEWLINE}(Clic-droit pour supprimer) STR_1165 :{STRINGID} - {STRINGID} {COMMA16} -STR_1166 :Can't lower water level here... -STR_1167 :Can't raise water level here... +STR_1166 :Impossible d'abaisser le niveau de l'eau ici... +STR_1167 :Impossible de surélever le niveau de l'eau ici... STR_1168 :Options STR_1169 :(None) STR_1170 :{STRING} -STR_1171 :{RED}Closed - - +STR_1171 :{RED}Fermé - - STR_1172 :{YELLOW}{STRINGID} - - -STR_1173 :{SMALLFONT}{BLACK}Build footpaths and queue lines -STR_1174 :Banner sign in the way -STR_1175 :Can't build this on sloped footpath -STR_1176 :Can't build footpath here... -STR_1177 :Can't remove footpath from here... -STR_1178 :Land slope unsuitable -STR_1179 :Footpath in the way -STR_1180 :Can't build this underwater! +STR_1173 :{SMALLFONT}{BLACK}Construire des chemins et des files d'attentes +STR_1174 :Panneau d'affichage sur le passage +STR_1175 :Impossible de construire ceci sur un chemin en pente +STR_1176 :Impossible de construire un chemin ici... +STR_1177 :Impossible de supprimer ce chemin... +STR_1178 :Terrain en pente inadapté +STR_1179 :Chemin sur le passage +STR_1180 :Impossible de construire ceci sous l'eau! STR_1181 :Allées STR_1182 :Type STR_1183 :Direction -STR_1184 :Direction +STR_1184 :Pente STR_1185 :{SMALLFONT}{BLACK}Direction -STR_1186 :{SMALLFONT}{BLACK}Slope down -STR_1187 :{SMALLFONT}{BLACK}Level -STR_1188 :{SMALLFONT}{BLACK}Slope up -STR_1189 :{SMALLFONT}{BLACK}Construct the selected footpath section -STR_1190 :{SMALLFONT}{BLACK}Remove previous footpath section +STR_1186 :{SMALLFONT}{BLACK}Pente descendante +STR_1187 :{SMALLFONT}{BLACK}Niveau +STR_1188 :{SMALLFONT}{BLACK}Pente montante +STR_1189 :{SMALLFONT}{BLACK}Construire la section de chemin sélectionnée +STR_1190 :{SMALLFONT}{BLACK}Supprimer la section de chemin précédente STR_1191 :{BLACK}{STRINGID} STR_1192 :{OUTLINE}{RED}{STRINGID} STR_1193 :{WINDOW_COLOUR_2}{STRINGID} @@ -1199,37 +1201,37 @@ STR_1194 :Fermé STR_1195 :En test STR_1196 :Ouvert STR_1197 :En panne -STR_1198 :Crashed! -STR_1199 :{COMMA16} person on ride -STR_1200 :{COMMA16} people on ride -STR_1201 :Nobody in queue line -STR_1202 :1 person in queue line -STR_1203 :{COMMA16} people in queue line -STR_1204 :{COMMA16} minute queue time -STR_1205 :{COMMA16} minutes queue time -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_1198 :Écrasé! +STR_1199 :{COMMA16} personne sur l'attraction +STR_1200 :{COMMA16} personnes sur l'attraction +STR_1201 :Personne dans la file d'attente +STR_1202 :Une personne dans la file d'attente +STR_1203 :{COMMA16} personnes dans la file d'attente +STR_1204 :{COMMA16} minute d'attente +STR_1205 :{COMMA16} minutes d'attente +STR_1206 :{WINDOW_COLOUR_2}Attendre: +STR_1207 :{WINDOW_COLOUR_2}Quitter si un autre train arrive à la station +STR_1208 :{WINDOW_COLOUR_2}Quitter si un autre bateau arrive à la station +STR_1209 :{SMALLFONT}{BLACK}Sélectionnez si il faut attendre des passagers avant de partir +STR_1210 :{SMALLFONT}{BLACK}Sélectionnez si il faut partir quand un autre véhicule arrive à la même station +STR_1211 :{WINDOW_COLOUR_2}Temps d'attente minimum: +STR_1212 :{WINDOW_COLOUR_2}Temps d'attente maximum: +STR_1213 :{SMALLFONT}{BLACK}Sélectionnez la durée minimum à attendre avant de partir +STR_1214 :{SMALLFONT}{BLACK}Sélectionnez la durée maximum à attendre avant de partir +STR_1215 :{WINDOW_COLOUR_2}Synchroniser avec les stations adjacentes +STR_1216 :{SMALLFONT}{BLACK}Sélectionnez si il faut synchroniser le départ avec toutes les stations adjacentes STR_1217 :{COMMA16} secondes STR_1218 :{BLACK}{SMALLUP} STR_1219 :{BLACK}{SMALLDOWN} -STR_1220 :Exit only -STR_1221 :No entrance -STR_1222 :No exit -STR_1223 :{SMALLFONT}{BLACK}Transport rides -STR_1224 :{SMALLFONT}{BLACK}Gentle rides -STR_1225 :{SMALLFONT}{BLACK}Roller coasters -STR_1226 :{SMALLFONT}{BLACK}Thrill rides -STR_1227 :{SMALLFONT}{BLACK}Water rides -STR_1228 :{SMALLFONT}{BLACK}Shops & stalls +STR_1220 :Sortie seulement +STR_1221 :Pas d'entrée +STR_1222 :Pas de sortie +STR_1223 :{SMALLFONT}{BLACK}Moyens de transports +STR_1224 :{SMALLFONT}{BLACK}Attractions calmes +STR_1225 :{SMALLFONT}{BLACK}Montagnes russes +STR_1226 :{SMALLFONT}{BLACK}Attractions à frissons +STR_1227 :{SMALLFONT}{BLACK}Attractions aquatiques +STR_1228 :{SMALLFONT}{BLACK}Magasins et stands STR_1229 :train STR_1230 :trains STR_1231 :Train @@ -1237,27 +1239,27 @@ STR_1232 :Trains STR_1233 :{COMMA16} train STR_1234 :{COMMA16} trains STR_1235 :Train {COMMA16} -STR_1236 :boat -STR_1237 :boats -STR_1238 :Boat -STR_1239 :Boats -STR_1240 :{COMMA16} boat -STR_1241 :{COMMA16} boats -STR_1242 :Boat {COMMA16} -STR_1243 :track -STR_1244 :tracks -STR_1245 :Track -STR_1246 :Tracks -STR_1247 :{COMMA16} track -STR_1248 :{COMMA16} tracks -STR_1249 :Track {COMMA16} -STR_1250 :docking platform -STR_1251 :docking platforms -STR_1252 :Docking platform -STR_1253 :Docking platforms -STR_1254 :{COMMA16} docking platform -STR_1255 :{COMMA16} docking platforms -STR_1256 :Docking platform {COMMA16} +STR_1236 :bateau +STR_1237 :bateaux +STR_1238 :Bateau +STR_1239 :Bateaux +STR_1240 :{COMMA16} bateau +STR_1241 :{COMMA16} bateaux +STR_1242 :Bateau {COMMA16} +STR_1243 :voie +STR_1244 :voies +STR_1245 :Voie +STR_1246 :Voies +STR_1247 :{COMMA16} voie +STR_1248 :{COMMA16} voies +STR_1249 :Voie {COMMA16} +STR_1250 :plateforme d'arrimage +STR_1251 :plateformes d'arrimage +STR_1252 :Plateforme d'arrimage +STR_1253 :Plateformes d'arrimage +STR_1254 :{COMMA16} plateforme d'arrimage +STR_1255 :{COMMA16} plateformes d'arrimage +STR_1256 :Plateforme d'arrimage {COMMA16} STR_1257 :station STR_1258 :stations STR_1259 :Station @@ -1265,13 +1267,13 @@ STR_1260 :Stations STR_1261 :{COMMA16} station STR_1262 :{COMMA16} stations STR_1263 :Station {COMMA16} -STR_1264 :car -STR_1265 :cars -STR_1266 :Car -STR_1267 :Cars -STR_1268 :{COMMA16} car -STR_1269 :{COMMA16} cars -STR_1270 :Car {COMMA16} +STR_1264 :voiture +STR_1265 :voitures +STR_1266 :Voiture +STR_1267 :Voitures +STR_1268 :{COMMA16} voiture +STR_1269 :{COMMA16} voitures +STR_1270 :Voiture {COMMA16} STR_1271 :bâtiment STR_1272 :bâtiments STR_1273 :Bâtiment @@ -1286,41 +1288,41 @@ STR_1281 :Structures STR_1282 :{COMMA16} structure STR_1283 :{COMMA16} structures STR_1284 :Structure {COMMA16} -STR_1285 :ship -STR_1286 :ships -STR_1287 :Ship -STR_1288 :Ships -STR_1289 :{COMMA16} ship -STR_1290 :{COMMA16} ships -STR_1291 :Ship {COMMA16} -STR_1292 :cabin -STR_1293 :cabins -STR_1294 :Cabin -STR_1295 :Cabins -STR_1296 :{COMMA16} cabin -STR_1297 :{COMMA16} cabins -STR_1298 :Cabin {COMMA16} -STR_1299 :wheel -STR_1300 :wheels -STR_1301 :Wheel -STR_1302 :Wheels -STR_1303 :{COMMA16} wheel -STR_1304 :{COMMA16} wheels -STR_1305 :Wheel {COMMA16} -STR_1306 :ring -STR_1307 :rings -STR_1308 :Ring -STR_1309 :Rings -STR_1310 :{COMMA16} ring -STR_1311 :{COMMA16} rings -STR_1312 :Ring {COMMA16} -STR_1313 :player -STR_1314 :players -STR_1315 :Player -STR_1316 :Players -STR_1317 :{COMMA16} player -STR_1318 :{COMMA16} players -STR_1319 :Player {COMMA16} +STR_1285 :navire +STR_1286 :navires +STR_1287 :Navire +STR_1288 :Navires +STR_1289 :{COMMA16} navire +STR_1290 :{COMMA16} Navires +STR_1291 :Navire {COMMA16} +STR_1292 :cabine +STR_1293 :cabines +STR_1294 :Cabine +STR_1295 :Cabines +STR_1296 :{COMMA16} cabine +STR_1297 :{COMMA16} cabines +STR_1298 :Cabine {COMMA16} +STR_1299 :roue +STR_1300 :roues +STR_1301 :Roue +STR_1302 :Roues +STR_1303 :{COMMA16} roue +STR_1304 :{COMMA16} roues +STR_1305 :Roue {COMMA16} +STR_1306 :anneau +STR_1307 :anneaux +STR_1308 :Anneau +STR_1309 :Anneaux +STR_1310 :{COMMA16} anneau +STR_1311 :{COMMA16} anneaux +STR_1312 :Anneau {COMMA16} +STR_1313 :joueur +STR_1314 :joueurs +STR_1315 :Joueur +STR_1316 :Joueurs +STR_1317 :{COMMA16} joueur +STR_1318 :{COMMA16} joueurs +STR_1319 :Joueur {COMMA16} STR_1320 :course STR_1321 :courses STR_1322 :Course @@ -1328,10 +1330,10 @@ STR_1323 :Courses STR_1324 :{COMMA16} course STR_1325 :{COMMA16} courses STR_1326 :Course {COMMA16} -STR_1327 :{SMALLFONT}{BLACK}Rotate objects by 90{DEGREE} -STR_1328 :Level land required -STR_1329 :{WINDOW_COLOUR_2}Launch speed: -STR_1330 :{SMALLFONT}{BLACK}Maximum speed when leaving station +STR_1327 :{SMALLFONT}{BLACK}Pivoter les objets de 90{DEGREE} +STR_1328 :Niveau de terrain requis +STR_1329 :{WINDOW_COLOUR_2}Vitesse de lancement: +STR_1330 :{SMALLFONT}{BLACK}Vitesse maximale en quittant la station STR_1331 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} STR_1332 :{VELOCITY} STR_1333 :{STRINGID} - {STRINGID}{POP16} @@ -1340,12 +1342,12 @@ 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} +STR_1339 :{BLACK}Pas encore de résultats de test... +STR_1340 :{WINDOW_COLOUR_2}Vitesse max.: {BLACK}{VELOCITY} +STR_1341 :{WINDOW_COLOUR_2}Durée de l'attraction: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} STR_1342 :{DURATION} STR_1343 :{DURATION} / -STR_1344 :{WINDOW_COLOUR_2}Ride length: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1344 :{WINDOW_COLOUR_2}Longueur de l'attraction: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} STR_1345 :{LENGTH} STR_1346 :{LENGTH} / STR_1347 :{WINDOW_COLOUR_2}Vitesse moyenne: {BLACK}{VELOCITY} @@ -1355,24 +1357,24 @@ STR_1350 :{WINDOW_COLOUR_2}Max. negative vertical G's: {BLACK}{COMMA2DP32}g STR_1351 :{WINDOW_COLOUR_2}Max. negative vertical G's: {OUTLINE}{RED}{COMMA2DP32}g STR_1352 :{WINDOW_COLOUR_2}Max. lateral G's: {BLACK}{COMMA2DP32}g STR_1353 :{WINDOW_COLOUR_2}Max. lateral G's: {OUTLINE}{RED}{COMMA2DP32}g -STR_1354 :{WINDOW_COLOUR_2}Highest drop height: {BLACK}{LENGTH} -STR_1355 :{WINDOW_COLOUR_2}Drops: {BLACK}{COMMA16} +STR_1354 :{WINDOW_COLOUR_2}Plus haute hauteur de chute: {BLACK}{LENGTH} +STR_1355 :{WINDOW_COLOUR_2}Chutes: {BLACK}{COMMA16} STR_1356 :{WINDOW_COLOUR_2}Inversions: {BLACK}{COMMA16} -STR_1357 :{WINDOW_COLOUR_2}Holes: {BLACK}{COMMA16} +STR_1357 :{WINDOW_COLOUR_2}Trous: {BLACK}{COMMA16} STR_1358 :{WINDOW_COLOUR_2}Total 'air' time: {BLACK}{COMMA2DP32}secs -STR_1359 :{WINDOW_COLOUR_2}Queue time: {BLACK}{COMMA16} minute -STR_1360 :{WINDOW_COLOUR_2}Queue time: {BLACK}{COMMA16} minutes -STR_1361 :Can't change speed... -STR_1362 :Can't change launch speed... -STR_1363 :Too high for supports! -STR_1364 :Supports for track above can't be extended any further! +STR_1359 :{WINDOW_COLOUR_2}Temps d'attente: {BLACK}{COMMA16} minute +STR_1360 :{WINDOW_COLOUR_2}Temps d'attente: {BLACK}{COMMA16} minutes +STR_1361 :Impossible de changer la vitesse... +STR_1362 :Impossidle de changer la vitesse de lancement... +STR_1363 :Trop haut pour les supports! +STR_1364 :Les supports pour la voie d'au dessus ne peuvent être plus étendus! STR_1365 :In-line Twist (left) STR_1366 :In-line Twist (right) -STR_1367 :Half Loop +STR_1367 :Demi boucle STR_1368 :Half Corkscrew (left) STR_1369 :Half Corkscrew (right) -STR_1370 :Barrel Roll (left) -STR_1371 :Barrel Roll (right) +STR_1370 :Tonneau (gauche) +STR_1371 :Tonneau (droite) STR_1372 :Launched Lift Hill STR_1373 :Large Half Loop (left) STR_1374 :Large Half Loop (right) @@ -1384,35 +1386,35 @@ STR_1379 :Reverser (left) STR_1380 :Reverser (right) STR_1381 :Curved Lift Hill (left) STR_1382 :Curved Lift Hill (right) -STR_1383 :Quarter Loop +STR_1383 :Quart de boucle STR_1384 :{YELLOW}{STRINGID} -STR_1385 :{SMALLFONT}{BLACK}Other track configurations -STR_1386 :Special... -STR_1387 :Can't change land type... +STR_1385 :{SMALLFONT}{BLACK}Autres configurations de voie +STR_1386 :Spécial... +STR_1387 :Impossible de changer le type de terrain... STR_1388 :{OUTLINE}{GREEN}+ {CURRENCY} STR_1389 :{OUTLINE}{RED}- {CURRENCY} STR_1390 :{CURRENCY2DP} STR_1391 :{RED}{CURRENCY2DP} -STR_1392 :{SMALLFONT}{BLACK}View of ride/attraction -STR_1393 :{SMALLFONT}{BLACK}Vehicle details and options -STR_1394 :{SMALLFONT}{BLACK}Operating options -STR_1395 :{SMALLFONT}{BLACK}Maintenance options -STR_1396 :{SMALLFONT}{BLACK}Color scheme options -STR_1397 :{SMALLFONT}{BLACK}Sound & music options -STR_1398 :{SMALLFONT}{BLACK}Measurements and test data -STR_1399 :{SMALLFONT}{BLACK}Graphs +STR_1392 :{SMALLFONT}{BLACK}Vue sur l'attraction +STR_1393 :{SMALLFONT}{BLACK}Détails des véhicules +STR_1394 :{SMALLFONT}{BLACK}Options d'opération +STR_1395 :{SMALLFONT}{BLACK}Options de maintenance +STR_1396 :{SMALLFONT}{BLACK}Options des couleurs +STR_1397 :{SMALLFONT}{BLACK}Options de son et musique +STR_1398 :{SMALLFONT}{BLACK}Données de test et mesures +STR_1399 :{SMALLFONT}{BLACK}Graphiques STR_1400 :Entrée STR_1401 :Sortie -STR_1402 :{SMALLFONT}{BLACK}Build or move entrance to ride/attraction -STR_1403 :{SMALLFONT}{BLACK}Build or move exit from ride/attraction -STR_1404 :{SMALLFONT}{BLACK}Rotate 90{DEGREE} -STR_1405 :{SMALLFONT}{BLACK}Mirror image -STR_1406 :{SMALLFONT}{BLACK}Toggle scenery on/off (if available for this design) -STR_1407 :{WINDOW_COLOUR_2}Build this... -STR_1408 :{WINDOW_COLOUR_2}Cost: {BLACK}{CURRENCY} -STR_1409 :Entry/Exit Platform -STR_1410 :Vertical Tower -STR_1411 :{STRINGID} in the way +STR_1402 :{SMALLFONT}{BLACK}Construire ou déplacer l'entrée de l'attraction +STR_1403 :{SMALLFONT}{BLACK}Construire ou déplacer la sortie de l'attraction +STR_1404 :{SMALLFONT}{BLACK}Rotation de 90{DEGREE} +STR_1405 :{SMALLFONT}{BLACK}Miroir +STR_1406 :{SMALLFONT}{BLACK}Activer/Désactiver le décor (si disponible pour ce modèle) +STR_1407 :{WINDOW_COLOUR_2}Construire ceci... +STR_1408 :{WINDOW_COLOUR_2}Prix : {BLACK}{CURRENCY} +STR_1409 :Plateforme d'entrée/sortie +STR_1410 :Tour verticale +STR_1411 :{STRINGID} dans le passage 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} @@ -1423,128 +1425,128 @@ STR_1418 :{WINDOW_COLOUR_2}Lat.G's STR_1419 :{SMALLFONT}{BLACK}{VELOCITY} STR_1420 :{SMALLFONT}{BLACK}{LENGTH} STR_1421 :{SMALLFONT}{BLACK}{COMMA16}g -STR_1422 :{SMALLFONT}{BLACK}Logging data from {POP16}{STRINGID} -STR_1423 :{SMALLFONT}{BLACK}Queue line path -STR_1424 :{SMALLFONT}{BLACK}Footpath -STR_1425 :Footpath -STR_1426 :Queue Line +STR_1422 :{SMALLFONT}{BLACK}Prise en note des données de {POP16}{STRINGID} +STR_1423 :{SMALLFONT}{BLACK}Chemin de la file d'attente +STR_1424 :{SMALLFONT}{BLACK}Chemin +STR_1425 :Chemin +STR_1426 :File d'attente STR_1427 :{WINDOW_COLOUR_2}Clients: {BLACK}{COMMA32} par heure -STR_1428 :{WINDOW_COLOUR_2}Admission price: +STR_1428 :{WINDOW_COLOUR_2}Prix d'entrée: STR_1429 :{POP16}{POP16}{POP16}{CURRENCY2DP} STR_1430 :Gratuit STR_1431 :Marche -STR_1432 :Heading for {STRINGID} -STR_1433 :Queuing for {STRINGID} -STR_1434 :Drowning +STR_1432 :Se dirige vers {STRINGID} +STR_1433 :Fait la queue pour {STRINGID} +STR_1434 :Se noie STR_1435 :En {STRINGID} STR_1436 :Dans {STRINGID} STR_1437 :A {STRINGID} -STR_1438 :Sitting +STR_1438 :Est assis STR_1439 :(select location) -STR_1440 :Mowing grass +STR_1440 :Tond le gazon STR_1441 :Balaye l'allée -STR_1442 :Emptying litter bin -STR_1443 :Watering gardens -STR_1444 :Watching {STRINGID} -STR_1445 :Watching construction of {STRINGID} -STR_1446 :Looking at scenery -STR_1447 :Leaving the park -STR_1448 :Watching new ride being constructed +STR_1442 :Vide la poubelle +STR_1443 :Arrose les jardins +STR_1444 :Regarde {STRINGID} +STR_1445 :Regarde la construction de {STRINGID} +STR_1446 :Regarde le décor +STR_1447 :Quitte le parc +STR_1448 :Regarde une nouvelle attraction en cours de construction 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 :Nom du visiteur -STR_1453 :Enter name for this guest: -STR_1454 :Can't name guest... -STR_1455 :Invalid name for guest -STR_1456 :{WINDOW_COLOUR_2}Cash spent: {BLACK}{CURRENCY2DP} -STR_1457 :{WINDOW_COLOUR_2}Cash in pocket: {BLACK}{CURRENCY2DP} +STR_1453 :Entrez un nom pour ce visiteur: +STR_1454 :Impossible de nommer le visiteur... +STR_1455 :Nom de visiteur invalide +STR_1456 :{WINDOW_COLOUR_2}Argent dépensé: {BLACK}{CURRENCY2DP} +STR_1457 :{WINDOW_COLOUR_2}Argent dans la poche: {BLACK}{CURRENCY2DP} STR_1458 :{WINDOW_COLOUR_2}Temps dans le parc: {BLACK}{REALTIME} -STR_1459 :Track style -STR_1460 :{SMALLFONT}{BLACK}'U' shaped open track -STR_1461 :{SMALLFONT}{BLACK}'O' shaped enclosed track +STR_1459 :Type de voie +STR_1460 :{SMALLFONT}{BLACK}Voie ouverte en forme de 'U' +STR_1461 :{SMALLFONT}{BLACK}Voie fermée en forme de 'O' STR_1462 :Too steep for lift hill STR_1463 :Visiteurs -STR_1464 :Helix up (small) -STR_1465 :Helix up (large) -STR_1466 :Helix down (small) -STR_1467 :Helix down (large) +STR_1464 :Hélice montante (petite) +STR_1465 :Hélice montante (grande) +STR_1466 :Hélice descendante (petite) +STR_1467 :Hélice descendante (grande) STR_1468 :Personnel -STR_1469 :Ride must start and end with stations -STR_1470 :Station not long enough +STR_1469 :L'attraction doit commencer et finir avec des stations +STR_1470 :Station pas assez longue 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 -STR_1475 :{WINDOW_COLOUR_2}Intensity rating: {BLACK}{COMMA2DP32} ({STRINGID}) -STR_1476 :{WINDOW_COLOUR_2}Intensity rating: {BLACK}Not yet available -STR_1477 :{WINDOW_COLOUR_2}Intensity rating: {OUTLINE}{RED}{COMMA2DP32} ({STRINGID}) -STR_1478 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}{COMMA2DP32} ({STRINGID}) -STR_1479 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}Not yet available -STR_1480 :{SMALLFONT}{OPENQUOTES}I can't afford {STRINGID}{ENDQUOTES} -STR_1481 :{SMALLFONT}{OPENQUOTES}I've spent all my money{ENDQUOTES} -STR_1482 :{SMALLFONT}{OPENQUOTES}I feel sick{ENDQUOTES} -STR_1483 :{SMALLFONT}{OPENQUOTES}I feel very sick{ENDQUOTES} -STR_1484 :{SMALLFONT}{OPENQUOTES}I want to go on something more thrilling than {STRINGID}{ENDQUOTES} -STR_1485 :{SMALLFONT}{OPENQUOTES}{STRINGID} looks too intense for me{ENDQUOTES} -STR_1486 :{SMALLFONT}{OPENQUOTES}I haven't finished my {STRINGID} yet{ENDQUOTES} -STR_1487 :{SMALLFONT}{OPENQUOTES}Just looking at {STRINGID} makes me feel sick{ENDQUOTES} -STR_1488 :{SMALLFONT}{OPENQUOTES}I'm not paying that much to go on {STRINGID}{ENDQUOTES} -STR_1489 :{SMALLFONT}{OPENQUOTES}I want to go home{ENDQUOTES} -STR_1490 :{SMALLFONT}{OPENQUOTES}{STRINGID} is really good value{ENDQUOTES} -STR_1491 :{SMALLFONT}{OPENQUOTES}I've already got {STRINGID}{ENDQUOTES} -STR_1492 :{SMALLFONT}{OPENQUOTES}I can't afford {STRINGID}{ENDQUOTES} -STR_1493 :{SMALLFONT}{OPENQUOTES}I'm not hungry{ENDQUOTES} -STR_1494 :{SMALLFONT}{OPENQUOTES}I'm not thirsty{ENDQUOTES} -STR_1495 :{SMALLFONT}{OPENQUOTES}Help! I'm drowning!{ENDQUOTES} -STR_1496 :{SMALLFONT}{OPENQUOTES}I'm lost!{ENDQUOTES} -STR_1497 :{SMALLFONT}{OPENQUOTES}{STRINGID} was great{ENDQUOTES} -STR_1498 :{SMALLFONT}{OPENQUOTES}I've been queuing for {STRINGID} for ages{ENDQUOTES} -STR_1499 :{SMALLFONT}{OPENQUOTES}I'm tired{ENDQUOTES} -STR_1500 :{SMALLFONT}{OPENQUOTES}I'm hungry{ENDQUOTES} -STR_1501 :{SMALLFONT}{OPENQUOTES}I'm thirsty{ENDQUOTES} -STR_1502 :{SMALLFONT}{OPENQUOTES}I need to go to the bathroom{ENDQUOTES} -STR_1503 :{SMALLFONT}{OPENQUOTES}I can't find {STRINGID}{ENDQUOTES} -STR_1504 :{SMALLFONT}{OPENQUOTES}I'm not paying that much to use {STRINGID}{ENDQUOTES} -STR_1505 :{SMALLFONT}{OPENQUOTES}I'm not going on {STRINGID} while it's raining{ENDQUOTES} -STR_1506 :{SMALLFONT}{OPENQUOTES}The litter here is really bad{ENDQUOTES} -STR_1507 :{SMALLFONT}{OPENQUOTES}I can't find the park exit{ENDQUOTES} -STR_1508 :{SMALLFONT}{OPENQUOTES}I want to get off {STRINGID}{ENDQUOTES} -STR_1509 :{SMALLFONT}{OPENQUOTES}I want to get out of {STRINGID}{ENDQUOTES} -STR_1510 :{SMALLFONT}{OPENQUOTES}I'm not going on {STRINGID} - It isn't safe{ENDQUOTES} -STR_1511 :{SMALLFONT}{OPENQUOTES}This path is disgusting{ENDQUOTES} -STR_1512 :{SMALLFONT}{OPENQUOTES}It's too crowded here{ENDQUOTES} -STR_1513 :{SMALLFONT}{OPENQUOTES}The vandalism here is really bad{ENDQUOTES} -STR_1514 :{SMALLFONT}{OPENQUOTES}Great scenery!{ENDQUOTES} -STR_1515 :{SMALLFONT}{OPENQUOTES}This park is really clean and tidy{ENDQUOTES} -STR_1516 :{SMALLFONT}{OPENQUOTES}The jumping fountains are great{ENDQUOTES} -STR_1517 :{SMALLFONT}{OPENQUOTES}The music is nice here{ENDQUOTES} -STR_1518 :{SMALLFONT}{OPENQUOTES}This balloon from {STRINGID} is really good value{ENDQUOTES} -STR_1519 :{SMALLFONT}{OPENQUOTES}This cuddly toy from {STRINGID} is really good value{ENDQUOTES} -STR_1520 :{SMALLFONT}{OPENQUOTES}This park map from {STRINGID} is really good value{ENDQUOTES} -STR_1521 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} -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_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_1472 :{SMALLFONT}{BLACK}Vitesse de cette attraction +STR_1473 :{WINDOW_COLOUR_2}Niveau d'excitation: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1474 :{WINDOW_COLOUR_2}Niveau d'excitation: {BLACK}Pas encore disponible +STR_1475 :{WINDOW_COLOUR_2}Niveau d'intensité: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1476 :{WINDOW_COLOUR_2}Niveau d'intensité: {BLACK}Pas encore disponible +STR_1477 :{WINDOW_COLOUR_2}Niveau d'intensité: {OUTLINE}{RED}{COMMA2DP32} ({STRINGID}) +STR_1478 :{WINDOW_COLOUR_2}Niveau de nausée: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1479 :{WINDOW_COLOUR_2}Niveau de nausée: {BLACK}Pas encore disponible +STR_1480 :{SMALLFONT}{OPENQUOTES}Je ne peux pas me payer{STRINGID}{ENDQUOTES} +STR_1481 :{SMALLFONT}{OPENQUOTES}J'ai dépensé tout mon argent{ENDQUOTES} +STR_1482 :{SMALLFONT}{OPENQUOTES}Je me sens malade{ENDQUOTES} +STR_1483 :{SMALLFONT}{OPENQUOTES}Je me sens très malade{ENDQUOTES} +STR_1484 :{SMALLFONT}{OPENQUOTES}Je veux aller sur quelque chose de plus excitant que {STRINGID}{ENDQUOTES} +STR_1485 :{SMALLFONT}{OPENQUOTES}{STRINGID} a l'air trop intense pour moi{ENDQUOTES} +STR_1486 :{SMALLFONT}{OPENQUOTES}Je n'ai pas encore fini mon {STRINGID} {ENDQUOTES} +STR_1487 :{SMALLFONT}{OPENQUOTES}Rien que le fait de regarder {STRINGID} me rend malade{ENDQUOTES} +STR_1488 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour aller sur {STRINGID}{ENDQUOTES} +STR_1489 :{SMALLFONT}{OPENQUOTES}Je veux rentrer chez moi{ENDQUOTES} +STR_1490 :{SMALLFONT}{OPENQUOTES}{STRINGID} est un très bon choix{ENDQUOTES} +STR_1491 :{SMALLFONT}{OPENQUOTES}J'ai déjà un {STRINGID}{ENDQUOTES} +STR_1492 :{SMALLFONT}{OPENQUOTES}Je ne peux pas me payer {STRINGID}{ENDQUOTES} +STR_1493 :{SMALLFONT}{OPENQUOTES}Je n'ai pas faim{ENDQUOTES} +STR_1494 :{SMALLFONT}{OPENQUOTES}Je n'ai pas soif{ENDQUOTES} +STR_1495 :{SMALLFONT}{OPENQUOTES}À l'aide! Je me noie!{ENDQUOTES} +STR_1496 :{SMALLFONT}{OPENQUOTES}Je suis perdu!{ENDQUOTES} +STR_1497 :{SMALLFONT}{OPENQUOTES}{STRINGID} était génial{ENDQUOTES} +STR_1498 :{SMALLFONT}{OPENQUOTES}Je fais la queue pour {STRINGID} depuis des années{ENDQUOTES} +STR_1499 :{SMALLFONT}{OPENQUOTES}Je suis fatigué{ENDQUOTES} +STR_1500 :{SMALLFONT}{OPENQUOTES}J'ai faim{ENDQUOTES} +STR_1501 :{SMALLFONT}{OPENQUOTES}J'ai soif{ENDQUOTES} +STR_1502 :{SMALLFONT}{OPENQUOTES}Je dois aller aux toilettes{ENDQUOTES} +STR_1503 :{SMALLFONT}{OPENQUOTES}Je ne peux pas trouver {STRINGID}{ENDQUOTES} +STR_1504 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour utiliser {STRINGID}{ENDQUOTES} +STR_1505 :{SMALLFONT}{OPENQUOTES}Je ne vais pas sur {STRINGID} pendant qu'il pleut{ENDQUOTES} +STR_1506 :{SMALLFONT}{OPENQUOTES}La poubelle est mauvaise ici{ENDQUOTES} +STR_1507 :{SMALLFONT}{OPENQUOTES}Je ne peux pas trouver la sortie du parc{ENDQUOTES} +STR_1508 :{SMALLFONT}{OPENQUOTES}Je veux descendre de {STRINGID}{ENDQUOTES} +STR_1509 :{SMALLFONT}{OPENQUOTES}Je veux sortir de {STRINGID}{ENDQUOTES} +STR_1510 :{SMALLFONT}{OPENQUOTES}Je ne vais pas sur {STRINGID} - Ce n'est pas sécurisé{ENDQUOTES} +STR_1511 :{SMALLFONT}{OPENQUOTES}Ce chemin me dégoûte{ENDQUOTES} +STR_1512 :{SMALLFONT}{OPENQUOTES}Il y a trop de monde ici{ENDQUOTES} +STR_1513 :{SMALLFONT}{OPENQUOTES}Le vandalisme ici est vraiment mauvais{ENDQUOTES} +STR_1514 :{SMALLFONT}{OPENQUOTES}Super décor!{ENDQUOTES} +STR_1515 :{SMALLFONT}{OPENQUOTES}Ce parc est très propre et organisé{ENDQUOTES} +STR_1516 :{SMALLFONT}{OPENQUOTES}Les jets d'eau sont super{ENDQUOTES} +STR_1517 :{SMALLFONT}{OPENQUOTES}La musique est sympa ici{ENDQUOTES} +STR_1518 :{SMALLFONT}{OPENQUOTES}Ce ballon de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1519 :{SMALLFONT}{OPENQUOTES}Cette peluche de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1520 :{SMALLFONT}{OPENQUOTES}Cette carte du parc de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1521 :{SMALLFONT}{OPENQUOTES}Cette photo sur le vif de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1522 :{SMALLFONT}{OPENQUOTES}Ce parapluie de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1523 :{SMALLFONT}{OPENQUOTES}Cette boisson de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1524 :{SMALLFONT}{OPENQUOTES}Ce burger de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1525 :{SMALLFONT}{OPENQUOTES}Ces frites de {STRINGID} sont un très bon choix{ENDQUOTES} +STR_1526 :{SMALLFONT}{OPENQUOTES}Cette glace de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1527 :{SMALLFONT}{OPENQUOTES}Cette barbe-à-papa de {STRINGID} est un très bon choix{ENDQUOTES} STR_1528 : STR_1529 : STR_1530 : -STR_1531 :{SMALLFONT}{OPENQUOTES}This pizza from {STRINGID} is really good value{ENDQUOTES} +STR_1531 :{SMALLFONT}{OPENQUOTES}Cette pizza de {STRINGID} est un très bon choix{ENDQUOTES} STR_1532 : -STR_1533 :{SMALLFONT}{OPENQUOTES}This popcorn from {STRINGID} is really good value{ENDQUOTES} -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_1538 :{SMALLFONT}{OPENQUOTES}This T-shirt from {STRINGID} is really good value{ENDQUOTES} -STR_1539 :{SMALLFONT}{OPENQUOTES}This donut from {STRINGID} is really good value{ENDQUOTES} -STR_1540 :{SMALLFONT}{OPENQUOTES}This coffee from {STRINGID} is really good value{ENDQUOTES} +STR_1533 :{SMALLFONT}{OPENQUOTES}Ce popcorn de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1534 :{SMALLFONT}{OPENQUOTES}Ce hot-dog de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1535 :{SMALLFONT}{OPENQUOTES}Ce poulpe de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1536 :{SMALLFONT}{OPENQUOTES}Ce chapeau de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1537 :{SMALLFONT}{OPENQUOTES}Cette pomme d'amour de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1538 :{SMALLFONT}{OPENQUOTES}Ce T-shirt de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1539 :{SMALLFONT}{OPENQUOTES}Ce donut de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1540 :{SMALLFONT}{OPENQUOTES}Ce café de {STRINGID} est un très bon choix{ENDQUOTES} STR_1541 : -STR_1542 :{SMALLFONT}{OPENQUOTES}This fried chicken from {STRINGID} is really good value{ENDQUOTES} -STR_1543 :{SMALLFONT}{OPENQUOTES}This lemonade from {STRINGID} is really good value{ENDQUOTES} +STR_1542 :{SMALLFONT}{OPENQUOTES}Ce poulet frit de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1543 :{SMALLFONT}{OPENQUOTES}Cette limonade de {STRINGID} est un très bon choix{ENDQUOTES} STR_1544 : STR_1545 : STR_1546 : @@ -1552,60 +1554,60 @@ STR_1547 : STR_1548 : STR_1549 : STR_1550 :{SMALLFONT}{OPENQUOTES}Wow!{ENDQUOTES} -STR_1551 :{SMALLFONT}{OPENQUOTES}I have the strangest feeling someone is watching me{ENDQUOTES} -STR_1552 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a balloon from {STRINGID}{ENDQUOTES} -STR_1553 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a cuddly toy from {STRINGID}{ENDQUOTES} -STR_1554 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a park map from {STRINGID}{ENDQUOTES} -STR_1555 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} -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_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_1551 :{SMALLFONT}{OPENQUOTES}J'ai l'étrange impression que quelqu'un me regarde{ENDQUOTES} +STR_1552 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un ballon de {STRINGID}{ENDQUOTES} +STR_1553 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour une peluche de {STRINGID}{ENDQUOTES} +STR_1554 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour une carte du parc de {STRINGID}{ENDQUOTES} +STR_1555 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour une photo sur le vif de {STRINGID}{ENDQUOTES} +STR_1556 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un parapluie de {STRINGID}{ENDQUOTES} +STR_1557 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour une boisson de {STRINGID}{ENDQUOTES} +STR_1558 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un burger de {STRINGID}{ENDQUOTES} +STR_1559 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour des frites de {STRINGID}{ENDQUOTES} +STR_1560 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour une glace de {STRINGID}{ENDQUOTES} +STR_1561 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour une barbe-à-papa de {STRINGID}{ENDQUOTES} STR_1562 : STR_1563 : STR_1564 : -STR_1565 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for pizza from {STRINGID}{ENDQUOTES} +STR_1565 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour une pizza de {STRINGID}{ENDQUOTES} STR_1566 : -STR_1567 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for popcorn from {STRINGID}{ENDQUOTES} -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_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 donut from {STRINGID}{ENDQUOTES} -STR_1574 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for coffee from {STRINGID}{ENDQUOTES} +STR_1567 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour du popcorn de {STRINGID}{ENDQUOTES} +STR_1568 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un hot dog de {STRINGID}{ENDQUOTES} +STR_1569 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour du poulpe de {STRINGID}{ENDQUOTES} +STR_1570 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un chapeau de {STRINGID}{ENDQUOTES} +STR_1571 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour une pomme d'amour de {STRINGID}{ENDQUOTES} +STR_1572 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un T-shirt de {STRINGID}{ENDQUOTES} +STR_1573 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un donut de {STRINGID}{ENDQUOTES} +STR_1574 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un café de {STRINGID}{ENDQUOTES} STR_1575 : -STR_1576 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fried chicken from {STRINGID}{ENDQUOTES} -STR_1577 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for lemonade from {STRINGID}{ENDQUOTES} +STR_1576 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour du poulet frit de {STRINGID}{ENDQUOTES} +STR_1577 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un limonade de {STRINGID}{ENDQUOTES} STR_1578 : STR_1579 : STR_1580 : STR_1581 : STR_1582 : STR_1583 : -STR_1584 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} -STR_1585 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} -STR_1586 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} -STR_1587 :{SMALLFONT}{OPENQUOTES}This pretzel from {STRINGID} is really good value{ENDQUOTES} -STR_1588 :{SMALLFONT}{OPENQUOTES}This hot chocolate from {STRINGID} is really good value{ENDQUOTES} -STR_1589 :{SMALLFONT}{OPENQUOTES}This iced tea from {STRINGID} is really good value{ENDQUOTES} -STR_1590 :{SMALLFONT}{OPENQUOTES}This funnel cake from {STRINGID} is really good value{ENDQUOTES} -STR_1591 :{SMALLFONT}{OPENQUOTES}These sunglasses from {STRINGID} are really good value{ENDQUOTES} -STR_1592 :{SMALLFONT}{OPENQUOTES}These beef noodles from {STRINGID} are really good value{ENDQUOTES} -STR_1593 :{SMALLFONT}{OPENQUOTES}These fried rice noodles from {STRINGID} are really good value{ENDQUOTES} -STR_1594 :{SMALLFONT}{OPENQUOTES}This wonton soup from {STRINGID} is really good value{ENDQUOTES} -STR_1595 :{SMALLFONT}{OPENQUOTES}This meatball soup from {STRINGID} is really good value{ENDQUOTES} -STR_1596 :{SMALLFONT}{OPENQUOTES}This fruit juice from {STRINGID} is really good value{ENDQUOTES} -STR_1597 :{SMALLFONT}{OPENQUOTES}This soybean milk from {STRINGID} is really good value{ENDQUOTES} -STR_1598 :{SMALLFONT}{OPENQUOTES}This sujongkwa from {STRINGID} is really good value{ENDQUOTES} -STR_1599 :{SMALLFONT}{OPENQUOTES}This sub sandwich from {STRINGID} is really good value{ENDQUOTES} -STR_1600 :{SMALLFONT}{OPENQUOTES}This cookie from {STRINGID} is really good value{ENDQUOTES} +STR_1584 :{SMALLFONT}{OPENQUOTES}Cette photo sur le vif de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1585 :{SMALLFONT}{OPENQUOTES}Cette photo sur le vif de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1586 :{SMALLFONT}{OPENQUOTES}Cette photo sur le vif de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1587 :{SMALLFONT}{OPENQUOTES}Ce bretzel de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1588 :{SMALLFONT}{OPENQUOTES}Ce chocolat chaud de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1589 :{SMALLFONT}{OPENQUOTES}Ce thé glacé de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1590 :{SMALLFONT}{OPENQUOTES}Ce funnel cake de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1591 :{SMALLFONT}{OPENQUOTES}Ces lunettes de soleil de {STRINGID} sont un très bon choix{ENDQUOTES} +STR_1592 :{SMALLFONT}{OPENQUOTES}Ces nouilles au boeuf de {STRINGID} sont un très bon choix{ENDQUOTES} +STR_1593 :{SMALLFONT}{OPENQUOTES}Ces nouilles au riz frit de {STRINGID} sont un très bon choix{ENDQUOTES} +STR_1594 :{SMALLFONT}{OPENQUOTES}Cette soupe aux raviolis de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1595 :{SMALLFONT}{OPENQUOTES}Cette soupe aux boulettes de viande de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1596 :{SMALLFONT}{OPENQUOTES}Ce jus de fruits de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1597 :{SMALLFONT}{OPENQUOTES}Ce lait de soja de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1598 :{SMALLFONT}{OPENQUOTES}Ce sujongkwa de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1599 :{SMALLFONT}{OPENQUOTES}Ce sub sandwich de {STRINGID} est un très bon choix{ENDQUOTES} +STR_1600 :{SMALLFONT}{OPENQUOTES}Ce cookie de {STRINGID} est un très bon choix{ENDQUOTES} STR_1601 : STR_1602 : STR_1603 : -STR_1604 :{SMALLFONT}{OPENQUOTES}This roast sausage from {STRINGID} are really good value{ENDQUOTES} +STR_1604 :{SMALLFONT}{OPENQUOTES}Cette saucisse grillée de {STRINGID} est un très bon choix{ENDQUOTES} STR_1605 : STR_1606 : STR_1607 : @@ -1617,27 +1619,27 @@ STR_1612 : STR_1613 : STR_1614 : STR_1615 : -STR_1616 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} -STR_1617 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} -STR_1618 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} -STR_1619 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a pretzel from {STRINGID}{ENDQUOTES} -STR_1620 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for hot chocolate from {STRINGID}{ENDQUOTES} -STR_1621 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for iced tea from {STRINGID}{ENDQUOTES} -STR_1622 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a funnel cake from {STRINGID}{ENDQUOTES} -STR_1623 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for sunglasses from {STRINGID}{ENDQUOTES} -STR_1624 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for beef noodles from {STRINGID}{ENDQUOTES} -STR_1625 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fried rice noodles from {STRINGID}{ENDQUOTES} -STR_1626 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for wonton soup from {STRINGID}{ENDQUOTES} -STR_1627 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for meatball soup from {STRINGID}{ENDQUOTES} -STR_1628 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fruit juice from {STRINGID}{ENDQUOTES} -STR_1629 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for soybean milk from {STRINGID}{ENDQUOTES} -STR_1630 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for sujongkwa from {STRINGID}{ENDQUOTES} -STR_1631 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a sub sandwich from {STRINGID}{ENDQUOTES} -STR_1632 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a cookie from {STRINGID}{ENDQUOTES} +STR_1616 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour une photo sur le vif de {STRINGID}{ENDQUOTES} +STR_1617 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour une photo sur le vif de {STRINGID}{ENDQUOTES} +STR_1618 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour une photo sur le vif de {STRINGID}{ENDQUOTES} +STR_1619 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un bretzel de {STRINGID}{ENDQUOTES} +STR_1620 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un chocolat chaud de {STRINGID}{ENDQUOTES} +STR_1621 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour du thé glacé de {STRINGID}{ENDQUOTES} +STR_1622 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un funnel cake de {STRINGID}{ENDQUOTES} +STR_1623 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour des lunettes de soleil de {STRINGID}{ENDQUOTES} +STR_1624 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour des nouilles au boeuf de {STRINGID}{ENDQUOTES} +STR_1625 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour des nouilles au riz frit de {STRINGID}{ENDQUOTES} +STR_1626 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour une soupe aux raviolis de {STRINGID}{ENDQUOTES} +STR_1627 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour une soupe aux boulettes de viandes de {STRINGID}{ENDQUOTES} +STR_1628 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un jus de fruits de {STRINGID}{ENDQUOTES} +STR_1629 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour du lait de soja de {STRINGID}{ENDQUOTES} +STR_1630 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un sujongkwa de {STRINGID}{ENDQUOTES} +STR_1631 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un sub sandwich de {STRINGID}{ENDQUOTES} +STR_1632 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour un cookie de {STRINGID}{ENDQUOTES} STR_1633 : STR_1634 : STR_1635 : -STR_1636 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a roast sausage from {STRINGID}{ENDQUOTES} +STR_1636 :{SMALLFONT}{OPENQUOTES}Je ne paierai pas autant pour une saucisse grillée de {STRINGID}{ENDQUOTES} STR_1637 : STR_1638 : STR_1639 : @@ -1649,124 +1651,124 @@ STR_1644 : STR_1645 : STR_1646 : STR_1647 : -STR_1648 :{SMALLFONT}{OPENQUOTES}Help! Put me down!{ENDQUOTES} -STR_1649 :{SMALLFONT}{OPENQUOTES}I'm running out of cash!{ENDQUOTES} -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_1648 :{SMALLFONT}{OPENQUOTES}À l'aide! Déposez-moi!{ENDQUOTES} +STR_1649 :{SMALLFONT}{OPENQUOTES}Je n'ai plus d'argent!{ENDQUOTES} +STR_1650 :{SMALLFONT}{OPENQUOTES}Wow! Une nouvelle attraction en cours de construction!{ENDQUOTES} +STR_1651 :{SMALLFONT}{OPENQUOTES}Super attraction! Mais pas aussi bien que le Phoenix...{ENDQUOTES} +STR_1652 :{SMALLFONT}{OPENQUOTES}Je suis tellement excité - C'est une attraction Intamin!{ENDQUOTES} +STR_1653 :{SMALLFONT}{OPENQUOTES}...et là nous sommes sur {STRINGID}!{ENDQUOTES} +STR_1654 :{WINDOW_COLOUR_2}Pensées récentes: +STR_1655 :{SMALLFONT}{BLACK}Construire un chemin sur le terrain +STR_1656 :{SMALLFONT}{BLACK}Construire un pont ou un tunnel STR_1657 :{WINDOW_COLOUR_2}Attraction favorite -STR_1658 :{WINDOW_COLOUR_2}intensity: {BLACK}less than {COMMA16} +STR_1658 :{WINDOW_COLOUR_2}intensité: {BLACK}moins de {COMMA16} STR_1659 :{WINDOW_COLOUR_2}intensité: {BLACK}entre {COMMA16} et {COMMA16} -STR_1660 :{WINDOW_COLOUR_2}intensity: {BLACK}more than {COMMA16} +STR_1660 :{WINDOW_COLOUR_2}intensité: {BLACK}plus de {COMMA16} STR_1661 :{WINDOW_COLOUR_2}Tolérance nausée: {BLACK}{STRINGID} STR_1662 :{WINDOW_COLOUR_2}Bonheur: STR_1663 :{WINDOW_COLOUR_2}Nausée: -STR_1664 :{WINDOW_COLOUR_2}Energie: +STR_1664 :{WINDOW_COLOUR_2}Énergie: STR_1665 :{WINDOW_COLOUR_2}Faim: STR_1666 :{WINDOW_COLOUR_2}Soif: STR_1667 :{WINDOW_COLOUR_2}Toilettes: -STR_1668 :{WINDOW_COLOUR_2}Satisfaction: {BLACK}Unknown +STR_1668 :{WINDOW_COLOUR_2}Satisfaction: {BLACK}Inconnue 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_1670 :{WINDOW_COLOUR_2}Total de clients: {BLACK}{COMMA32} +STR_1671 :{WINDOW_COLOUR_2}Profit total: {BLACK}{CURRENCY2DP} STR_1672 :Freins STR_1673 :Spinning Control Toggle Track -STR_1674 :Brake speed +STR_1674 :Vitesse des freins STR_1675 :{POP16}{VELOCITY} -STR_1676 :{SMALLFONT}{BLACK}Set speed limit for brakes -STR_1677 :{WINDOW_COLOUR_2}Popularity: {BLACK}Unknown -STR_1678 :{WINDOW_COLOUR_2}Popularity: {BLACK}{COMMA16}% -STR_1679 :Helix up (left) -STR_1680 :Helix up (right) -STR_1681 :Helix down (left) -STR_1682 :Helix down (right) +STR_1676 :{SMALLFONT}{BLACK}Définir la limite de vitesse pour les freins +STR_1677 :{WINDOW_COLOUR_2}Popularité: {BLACK}Inconnue +STR_1678 :{WINDOW_COLOUR_2}Popularité: {BLACK}{COMMA16}% +STR_1679 :Hélice montante (gauche) +STR_1680 :Hélice montante (droite) +STR_1681 :Hélice descendante (gauche) +STR_1682 :Hélice descendante (droite) STR_1683 :Base size 2 x 2 STR_1684 :Base size 4 x 4 STR_1685 :Base size 2 x 4 STR_1686 :Base size 5 x 1 STR_1687 :Water splash STR_1688 :Base size 4 x 1 -STR_1689 :Block brakes +STR_1689 :Blocs de freins 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_1691 :{WINDOW_COLOUR_2} Coût: {BLACK}{CURRENCY} +STR_1692 :{WINDOW_COLOUR_2} Coût: {BLACK}de {CURRENCY} STR_1693 :{SMALLFONT}{BLACK}Visiteurs -STR_1694 :{SMALLFONT}{BLACK}Staff -STR_1695 :{SMALLFONT}{BLACK}Income and costs -STR_1696 :{SMALLFONT}{BLACK}Customer information -STR_1697 :Cannot place these on queue line area -STR_1698 :Can only place these on queue area -STR_1699 :Too many people in game -STR_1700 :Hire new Handyman -STR_1701 :Hire new Mechanic -STR_1702 :Hire new Security Guard -STR_1703 :Hire new Entertainer -STR_1704 :Can't hire new staff... -STR_1705 :{SMALLFONT}{BLACK}Sack this staff member -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_1694 :{SMALLFONT}{BLACK}Personnel +STR_1695 :{SMALLFONT}{BLACK}Profit et coûts +STR_1696 :{SMALLFONT}{BLACK}Informations sur les clients +STR_1697 :Impossible de les placer sur une file d'attente +STR_1698 :Ne peut être placé que sur une file d'attente +STR_1699 :Trop de personnes en jeu +STR_1700 :Embaucher un nouvel homme de service +STR_1701 :Embaucher un nouveau mécanicien +STR_1702 :Embaucher un nouvel agent de sécurité +STR_1703 :Embaucher un nouvel animateur +STR_1704 :Impossible d'embaucher de nouveaux employés... +STR_1705 :{SMALLFONT}{BLACK}Licencier cet employé +STR_1706 :{SMALLFONT}{BLACK}Déplacer cette personne vers une nouvelle localisation +STR_1707 :Trop d'employés en jeu +STR_1708 :{SMALLFONT}{BLACK}Définir une zone de patrouille pour cet employé +STR_1709 :Licencier des employés 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 -STR_1714 :{INLINE_SPRITE}{249}{19}{00}{00}{WINDOW_COLOUR_2}Empty litter bins -STR_1715 :{INLINE_SPRITE}{250}{19}{00}{00}{WINDOW_COLOUR_2}Mow grass +STR_1711 :{WINDOW_COLOUR_1}Êtes-vous sûr de vouloir licencier {STRINGID}? +STR_1712 :{INLINE_SPRITE}{247}{19}{00}{00}{WINDOW_COLOUR_2}Balayer les chemins +STR_1713 :{INLINE_SPRITE}{248}{19}{00}{00}{WINDOW_COLOUR_2}Arroser les jardins +STR_1714 :{INLINE_SPRITE}{249}{19}{00}{00}{WINDOW_COLOUR_2}Vider les poubelles +STR_1715 :{INLINE_SPRITE}{250}{19}{00}{00}{WINDOW_COLOUR_2}Tondre le gazon STR_1716 :Nom du parc non valide STR_1717 :Impossible de renommer le parc... -STR_1718 :Nom dur parc +STR_1718 :Nom du parc STR_1719 :Saisir nom du parc: -STR_1720 :{SMALLFONT}{BLACK}Name park +STR_1720 :{SMALLFONT}{BLACK}Nommer le parc STR_1721 :Parc fermé STR_1722 :Parc ouvert -STR_1723 :Can't open park... -STR_1724 :Can't close park... -STR_1725 :Impossible d'acheter le terrain... +STR_1723 :Impossible d'ouvrir le parc... +STR_1724 :Impossible de fermer le parc... +STR_1725 :Impossible d'acheter ce terrain... STR_1726 :Ce terrain n'est pas a vendre! STR_1727 :Les droits de construction ne sont pas à vendre! -STR_1728 :Impossible d'acheter les droits de construction içi... -STR_1729 :Land not owned by park! -STR_1730 :{RED}Closed - - +STR_1728 :Impossible d'acheter les droits de construction ici... +STR_1729 :Ce terrain n'appartient pas au parc! +STR_1730 :{RED}Fermé - - STR_1731 :{WHITE}{STRINGID} - - -STR_1732 :Build +STR_1732 :Construire STR_1733 :Mode -STR_1734 :{WINDOW_COLOUR_2}Number of laps: -STR_1735 :{SMALLFONT}{BLACK}Number of laps of circuit +STR_1734 :{WINDOW_COLOUR_2}Nombre de tours: +STR_1735 :{SMALLFONT}{BLACK}Nombre de tours du circuit STR_1736 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} STR_1737 :{COMMA16} -STR_1738 :Can't change number of laps... -STR_1739 :Race won by guest {INT32} +STR_1738 :Impossible de changer le nombre de tours... +STR_1739 :Course gagnée par visiteur {INT32} STR_1740 :Course gagnée par {STRINGID} -STR_1741 :Not yet constructed ! -STR_1742 :{WINDOW_COLOUR_2}Max. people on ride: -STR_1743 :{SMALLFONT}{BLACK}Maximum number of people allowed on this ride at one time +STR_1741 :Pas encore construit! +STR_1742 :{WINDOW_COLOUR_2}Personnes max. sur l'attraction: +STR_1743 :{SMALLFONT}{BLACK}Nombre maximum de personnes autorisées sur cette attraction en même temps STR_1744 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} STR_1745 :{COMMA16} -STR_1746 :Can't change this... -STR_1747 :{WINDOW_COLOUR_2}Time limit: -STR_1748 :{SMALLFONT}{BLACK}Time limit for ride +STR_1746 :Impossible de changer ceci... +STR_1747 :{WINDOW_COLOUR_2}Limite de temps: +STR_1748 :{SMALLFONT}{BLACK}Limite de temps pour l'attraction STR_1749 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{DURATION} STR_1750 :{DURATION} -STR_1751 :Can't change time limit for ride... -STR_1752 :{SMALLFONT}{BLACK}Show list of individual guests in park -STR_1753 :{SMALLFONT}{BLACK}Show summarized list of guests in park -STR_1754 :{BLACK}{COMMA16} guests -STR_1755 :{BLACK}{COMMA16} guest -STR_1756 :{WINDOW_COLOUR_2}Admission price: -STR_1757 :{WINDOW_COLOUR_2}Reliability: {MOVE_X}{255}{BLACK}{COMMA16}% -STR_1758 :{SMALLFONT}{BLACK}Build mode -STR_1759 :{SMALLFONT}{BLACK}Move mode -STR_1760 :{SMALLFONT}{BLACK}Fill-in mode -STR_1761 :{SMALLFONT}{BLACK}Build maze in this direction -STR_1762 :Waterfalls -STR_1763 :Rapids -STR_1764 :Log Bumps -STR_1765 :On-ride photo section +STR_1751 :Impossible de changer la limite de temps pour l'attraction... +STR_1752 :{SMALLFONT}{BLACK}Afficher la liste de chaque visiteur dans le parc +STR_1753 :{SMALLFONT}{BLACK}Afficher la liste résumée des visiteurs dans le parc +STR_1754 :{BLACK}{COMMA16} visiteurs +STR_1755 :{BLACK}{COMMA16} visiteur +STR_1756 :{WINDOW_COLOUR_2}Prix d'entrée: +STR_1757 :{WINDOW_COLOUR_2}Fiabilité: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1758 :{SMALLFONT}{BLACK}Mode construction +STR_1759 :{SMALLFONT}{BLACK}Mode déplacement +STR_1760 :{SMALLFONT}{BLACK}Mode remplissage +STR_1761 :{SMALLFONT}{BLACK}Construire le labyrinthe dans cette direction +STR_1762 :Cascades +STR_1763 :Rapides +STR_1764 :Rondins de bois +STR_1765 :Section photo sur le vif STR_1766 :Reverser turntable STR_1767 :Spinning tunnel STR_1768 :Can't change number of swings... @@ -1774,56 +1776,56 @@ STR_1769 :{WINDOW_COLOUR_2}Number of swings: STR_1770 :{SMALLFONT}{BLACK}Number of complete swings STR_1771 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} STR_1772 :{COMMA16} -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_1773 :Seulement une section photo sur le vif autorisée par attraction +STR_1774 :Seulement une montée par câble autorisée par attraction +STR_1775 :Éteint +STR_1776 :Allumé +STR_1777 :{WINDOW_COLOUR_2}Musique STR_1778 :{STRINGID} - - -STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Panda costume -STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tigre costume -STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} Elephant costume -STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} Roman costume -STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} Gorilla costume -STR_1784 :{INLINE_SPRITE}{03}{20}{00}{00} Snowman costume -STR_1785 :{INLINE_SPRITE}{04}{20}{00}{00} Knight costume -STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} Astronaut costume -STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} Bandit costume -STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} Sheriff costume -STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} Pirate costume -STR_1790 :{SMALLFONT}{BLACK}Select uniform color for this type of staff -STR_1791 :{WINDOW_COLOUR_2}Uniform color: -STR_1792 :Responding to {STRINGID} breakdown call -STR_1793 :Heading to {STRINGID} for an inspection -STR_1794 :Fixing {STRINGID} -STR_1795 :Answering radio call -STR_1796 :Has broken down and requires fixing -STR_1797 :This option cannot be changed for this ride -STR_1798 :Whirlpool +STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Costume de panda +STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Costume de tigre +STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} Costume d'éléphant +STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} Costume romain +STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} Costume de gorille +STR_1784 :{INLINE_SPRITE}{03}{20}{00}{00} Costume de bonhomme de neige +STR_1785 :{INLINE_SPRITE}{04}{20}{00}{00} Costume de chevalier +STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} Costume d'astronaute +STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} Costume de bandit +STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} Costume de shérif +STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} Costume de pirate +STR_1790 :{SMALLFONT}{BLACK}Sélectionnez la couleur de l'uniforme pour ce type d'employé +STR_1791 :{WINDOW_COLOUR_2}Couleur d'uniforme: +STR_1792 :Répond à l'appel sur l'incident de {STRINGID} +STR_1793 :Se rend à {STRINGID} pour une inspection +STR_1794 :Répare {STRINGID} +STR_1795 :Répond à l'appel radio +STR_1796 :S'est cassé et nécessite une réparation +STR_1797 :Cette option ne peut être changée pour cette attraction +STR_1798 :Tourbillon STR_1799 :{POP16}{POP16}{POP16}{POP16}{POP16}{CURRENCY2DP} -STR_1800 :Safety cut-out +STR_1800 :Contour de sécurité STR_1801 :Restraints stuck closed STR_1802 :Restraints stuck open -STR_1803 :Doors stuck closed -STR_1804 :Doors stuck open -STR_1805 :Vehicle malfunction -STR_1806 :Brakes failure -STR_1807 :Control failure -STR_1808 :{WINDOW_COLOUR_2}Last breakdown: {BLACK}{STRINGID} -STR_1809 :{WINDOW_COLOUR_2}Current breakdown: {OUTLINE}{RED}{STRINGID} -STR_1810 :{WINDOW_COLOUR_2}Carrying: -STR_1811 :Can't build this here... +STR_1803 :Portes restent fermées +STR_1804 :Portes restent ouvertes +STR_1805 :Malfonction d'un véhicule +STR_1806 :Défaillance des freins +STR_1807 :Défaillance des contrôles +STR_1808 :{WINDOW_COLOUR_2}Dernier incident: {BLACK}{STRINGID} +STR_1809 :{WINDOW_COLOUR_2}Incident actuel: {OUTLINE}{RED}{STRINGID} +STR_1810 :{WINDOW_COLOUR_2}Porte: +STR_1811 :Impossible de construire ça ici... STR_1812 :{SMALLFONT}{BLACK}{STRINGID} -STR_1813 :Miscellaneous Objects +STR_1813 :Objets divers STR_1814 :Actions -STR_1815 :Thoughts +STR_1815 :Pensées STR_1816 :{SMALLFONT}{BLACK}Select information type to show in guest list STR_1817 :({COMMA16}) STR_1818 :{WINDOW_COLOUR_2}Tous les visiteurs STR_1819 :{WINDOW_COLOUR_2}Tous les visiteurs (résumé) STR_1820 :{WINDOW_COLOUR_2}Visiteurs {STRINGID} -STR_1821 :{WINDOW_COLOUR_2}Guests thinking {STRINGID} -STR_1822 :{WINDOW_COLOUR_2}Guests thinking about {POP16}{STRINGID} +STR_1821 :{WINDOW_COLOUR_2}Visiteurs pensant {STRINGID} +STR_1822 :{WINDOW_COLOUR_2}Visiteurs pensant à {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 @@ -1832,54 +1834,54 @@ STR_1827 :Popularité STR_1828 :Satisfaction STR_1829 :Bénéfice STR_1830 :Longueur file -STR_1831 :Temps attente +STR_1831 :Temps d'attente STR_1832 :Fiabilité STR_1833 :Immobilisation STR_1834 :Plébiscitée -STR_1835 :Popularity: Unknown -STR_1836 :Popularity: {COMMA16}% -STR_1837 :Satisfaction: Unknown -STR_1838 :Satisfaction: {COMMA16}% -STR_1839 :Fiabilité: {COMMA16}% +STR_1835 :Popularité : Inconnue +STR_1836 :Popularité : {COMMA16}% +STR_1837 :Satisfaction : Inconnue +STR_1838 :Satisfaction : {COMMA16}% +STR_1839 :Fiabilité : {COMMA16}% STR_1840 :Immobilisation: {COMMA16}% -STR_1841 :Revenu: {CURRENCY} par heure -STR_1842 :Attraction préférée de: {COMMA16} visiteur -STR_1843 :Attraction préférée de: {COMMA16} visiteurs -STR_1844 :{SMALLFONT}{BLACK}Select information type to show in ride/attraction list +STR_1841 :Revenu : {CURRENCY} par heure +STR_1842 :Attraction préférée de : {COMMA16} visiteur +STR_1843 :Attraction préférée de : {COMMA16} visiteurs +STR_1844 :{SMALLFONT}{BLACK}Sélectionnez le type d'information à afficher dans la liste des attractions STR_1845 :{MONTHYEAR} STR_1846 :{COMMA16} visiteurs -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_1847 :{INLINE_SPRITE}{11}{20}{00}{00}{COMMA16} visiteurs +STR_1848 :{INLINE_SPRITE}{10}{20}{00}{00}{COMMA16} visiteurs +STR_1849 :{WINDOW_COLOUR_2}Jouer de la musique 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_1851 :{WINDOW_COLOUR_2}Coût de fonctionnement: {BLACK}{CURRENCY2DP} par heure +STR_1852 :{WINDOW_COLOUR_2}Coût de fonctionnement: {BLACK}Inconnu +STR_1853 :{WINDOW_COLOUR_2}Construit: {BLACK}Cette année +STR_1854 :{WINDOW_COLOUR_2}Construit: {BLACK}L'année dernière +STR_1855 :{WINDOW_COLOUR_2}Construit: {BLACK}il y a {COMMA16} ans +STR_1856 :{WINDOW_COLOUR_2}Bénéfice par objet vendu: {BLACK}{CURRENCY2DP} +STR_1857 :{WINDOW_COLOUR_2}Perte par objet vendu: {BLACK}{CURRENCY2DP} +STR_1858 :{WINDOW_COLOUR_2}Coût: {BLACK}{CURRENCY2DP} par mois +STR_1859 :Hommes de service STR_1860 :Mécaniciens -STR_1861 :Security Guards +STR_1861 :Gardes de sécurité STR_1862 :Animateurs -STR_1863 :Handyman +STR_1863 :Homme de service STR_1864 :Mécanicien -STR_1865 :Security Guard +STR_1865 :Garde de sécurité STR_1866 :Animateur STR_1867 :{BLACK}{COMMA16} {STRINGID} -STR_1868 :Can't change number of rotations... -STR_1869 :{WINDOW_COLOUR_2}Number of rotations: -STR_1870 :{SMALLFONT}{BLACK}Number of complete rotations +STR_1868 :Impossible de changer le nombre de rotations... +STR_1869 :{WINDOW_COLOUR_2}Nombre de rotations: +STR_1870 :{SMALLFONT}{BLACK}Nombre de rotations complètes 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}Revenu: {BLACK}{CURRENCY2DP} par heure +STR_1874 :{WINDOW_COLOUR_2}Profit: {BLACK}{CURRENCY2DP} par heure 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 -STR_1878 :{WINDOW_COLOUR_2}Inspection: +STR_1876 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{251}{19}{00}{00}Inspecter les attractions +STR_1877 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{252}{19}{00}{00}Réparer les attractions +STR_1878 :{WINDOW_COLOUR_2}Inspection : STR_1879 :Toutes les 10 minutes STR_1880 :Toutes les 20 minutes STR_1881 :Toutes les 30 minutes @@ -1887,16 +1889,18 @@ STR_1882 :Toutes les 45 minutes STR_1883 :Toutes les heures STR_1884 :Toutes les 2 heures STR_1885 :Jamais -STR_1886 :Inspecting {STRINGID} -STR_1887 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}{COMMA16} minutes -STR_1888 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}more than 4 hours -STR_1889 :{WINDOW_COLOUR_2}Down-Time: {MOVE_X}{255}{BLACK}{COMMA16}% -STR_1890 :{SMALLFONT}{BLACK}Select how often a mechanic should check this ride -STR_1891 :No {STRINGID} in park yet! -STR_1892 :RollerCoaster Tycoon 2 -STR_1893 :Please insert your RollerCoaster Tycoon 2 CD in the following drive: -STR_1894 :{WINDOW_COLOUR_2}{STRINGID} sold: {BLACK}{COMMA32} -STR_1895 :{SMALLFONT}{BLACK}Build new ride/attraction +STR_1886 :En train d'inspecter {STRINGID} +STR_1887 :{WINDOW_COLOUR_2}Temps écoulé depuis la dernière inspection: {BLACK}{COMMA16} minutes +STR_1888 :{WINDOW_COLOUR_2}Temps écoulé depuis la dernière inspection: {BLACK}plus de 4 heures +STR_1889 :{WINDOW_COLOUR_2}Temps d'arrêt: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1890 :{SMALLFONT}{BLACK}Sélectionnez la fréquence de vérification de l'attraction +STR_1891 :Pas encore de {STRINGID} dans le parc! +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 : +STR_1893 : +STR_1894 :{WINDOW_COLOUR_2}{STRINGID} vendu: {BLACK}{COMMA32} +STR_1895 :{SMALLFONT}{BLACK}Construire une nouvelle attraction STR_1896 :{WINDOW_COLOUR_2}Dépenses/Revenus STR_1897 :{WINDOW_COLOUR_2}Constr. attraction STR_1898 :{WINDOW_COLOUR_2}Coût d'expl. attr. @@ -1919,323 +1923,323 @@ STR_1914 :{BLACK}{CURRENCY2DP} STR_1915 :{RED}{CURRENCY2DP} STR_1916 :{WINDOW_COLOUR_2}Emprunt: STR_1917 :{POP16}{POP16}{POP16}{CURRENCY} -STR_1918 :Impossible d'emprunter d'avantage ! La banque refuse d'augmenter votre emprunt ! -STR_1919 :Pas asser d'argent disponible ! -STR_1920 :Impossible de rembourser l'emprunt ! +STR_1918 :Impossible d'emprunter d'avantage! La banque refuse d'augmenter votre emprunt! +STR_1919 :Pas assez d'argent disponible! +STR_1920 :Impossible de rembourser l'emprunt! STR_1921 :{SMALLFONT}{BLACK}Commencer une nouvelle partie STR_1922 :{SMALLFONT}{BLACK}Continuer une partie sauvegardée STR_1923 :{SMALLFONT}{BLACK}Didacticiel STR_1924 :{SMALLFONT}{BLACK}Quitter -STR_1925 :Can't place person here... +STR_1925 :Impossible de placer quelqu'un ici... STR_1926 :{SMALLFONT} -STR_1927 :{YELLOW}{STRINGID} has broken down -STR_1928 :{RED}{STRINGID} has crashed! -STR_1929 :{RED}{STRINGID} still hasn't been fixed{NEWLINE}Check where your mechanics are and consider organizing them better -STR_1930 :{SMALLFONT}{BLACK}Turn on/off tracking information for this guest - (If tracking is on, guest's movements will be reported in the message area) -STR_1931 :{STRINGID} has joined the queue line for {STRINGID} -STR_1932 :{STRINGID} is on {STRINGID} -STR_1933 :{STRINGID} is in {STRINGID} -STR_1934 :{STRINGID} has left {STRINGID} -STR_1935 :{STRINGID} has left the park -STR_1936 :{STRINGID} has bought {STRINGID} -STR_1937 :{SMALLFONT}{BLACK}Show information about the subject of this message -STR_1938 :{SMALLFONT}{BLACK}Show view of guest -STR_1939 :{SMALLFONT}{BLACK}Show view of staff member -STR_1940 :{SMALLFONT}{BLACK}Show happiness, energy, hunger etc. for this gugest -STR_1941 :{SMALLFONT}{BLACK}Show which rides this guest has been on -STR_1942 :{SMALLFONT}{BLACK}Show financial information about this guest -STR_1943 :{SMALLFONT}{BLACK}Show guest's recent thoughts -STR_1944 :{SMALLFONT}{BLACK}Show items guest is carrying -STR_1945 :{SMALLFONT}{BLACK}Show orders and options for this staff member -STR_1946 :{SMALLFONT}{BLACK}Select costume for this entertainer -STR_1947 :{SMALLFONT}{BLACK}Show areas patrolled by selected staff type, and locate the nearest staff member -STR_1948 :{SMALLFONT}{BLACK}Hire a new staff member of the selected type +STR_1927 :{YELLOW}{STRINGID} s'est cassé +STR_1928 :{RED}{STRINGID} s'est écrasé! +STR_1929 :{RED}{STRINGID} n'est toujours pas réparé{NEWLINE}Vérifiez où sont vos mécaniciens et pensez à leur attribuer des zones de patrouilles +STR_1930 :{SMALLFONT}{BLACK}Activer/Désactiver la surveillance de ce visiteur - (Si la surveillance est activée, les mouvements du visiteur seront annoncés dans la zone de notifications) +STR_1931 :{STRINGID} a rejoint la file d'attente pour {STRINGID} +STR_1932 :{STRINGID} est sur {STRINGID} +STR_1933 :{STRINGID} est dans {STRINGID} +STR_1934 :{STRINGID} a quitté {STRINGID} +STR_1935 :{STRINGID} a quitté le parc +STR_1936 :{STRINGID} a acheté {STRINGID} +STR_1937 :{SMALLFONT}{BLACK}Afficher des informations à propos du sujet de ce message +STR_1938 :{SMALLFONT}{BLACK}Afficher vue du visiteur +STR_1939 :{SMALLFONT}{BLACK}Afficher vue de l'employé +STR_1940 :{SMALLFONT}{BLACK}Afficher l'humeur, l'énergie, la faim... de ce visiteur +STR_1941 :{SMALLFONT}{BLACK}Afficher sur quelles attractions ce visiteur est allé +STR_1942 :{SMALLFONT}{BLACK}Afficher les informations financières à propos de ce visiteur +STR_1943 :{SMALLFONT}{BLACK}Afficher les pensées récentes de ce visiteur +STR_1944 :{SMALLFONT}{BLACK}Afficher les objets que porte ce visiteur +STR_1945 :{SMALLFONT}{BLACK}Afficher les ordres et options pour cet employé +STR_1946 :{SMALLFONT}{BLACK}Sélectionner le costume de cet animateur +STR_1947 :{SMALLFONT}{BLACK}Afficher les zones de patrouilles des employés de ce type, et localiser l'employé le plus proche +STR_1948 :{SMALLFONT}{BLACK}Embaucher un nouvel employé du même type STR_1949 :Résumé financier STR_1950 :Graphique financier STR_1951 :Graphique valeur du parc STR_1952 :Graphique bénéfices STR_1953 :Marketing STR_1954 :Financement recherches -STR_1955 :{WINDOW_COLOUR_2}Number of circuits: -STR_1956 :{SMALLFONT}{BLACK}Number of circuits of track per ride +STR_1955 :{WINDOW_COLOUR_2}Nombre de circuits: +STR_1956 :{SMALLFONT}{BLACK}Nombre de circuits de voie par attraction STR_1957 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} STR_1958 :{COMMA16} -STR_1959 :Can't change number of circuits... -STR_1960 :{WINDOW_COLOUR_2}Balloon price: -STR_1961 :{WINDOW_COLOUR_2}Cuddly Toy price: -STR_1962 :{WINDOW_COLOUR_2}Park Map price: -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_1968 :{WINDOW_COLOUR_2}Ice Cream price: -STR_1969 :{WINDOW_COLOUR_2}Cotton Candy price: +STR_1959 :Impossible de changer le nombre de circuits +STR_1960 :{WINDOW_COLOUR_2}Prix d'un ballon: +STR_1961 :{WINDOW_COLOUR_2}Prix d'une peluche: +STR_1962 :{WINDOW_COLOUR_2}Prix d'une carte du parc: +STR_1963 :{WINDOW_COLOUR_2}Prix d'une photo sur le vif: +STR_1964 :{WINDOW_COLOUR_2}Prix d'un parapluie: +STR_1965 :{WINDOW_COLOUR_2}Prix d'une boisson: +STR_1966 :{WINDOW_COLOUR_2}Prix d'un burger: +STR_1967 :{WINDOW_COLOUR_2}Prix des frites: +STR_1968 :{WINDOW_COLOUR_2}Prix d'une glace: +STR_1969 :{WINDOW_COLOUR_2}Prix d'une barbe-à-papa: STR_1970 :{WINDOW_COLOUR_2} STR_1971 :{WINDOW_COLOUR_2} STR_1972 :{WINDOW_COLOUR_2} -STR_1973 :{WINDOW_COLOUR_2}Pizza price: +STR_1973 :{WINDOW_COLOUR_2}Prix d'une pizza: STR_1974 :{WINDOW_COLOUR_2} -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_1980 :{WINDOW_COLOUR_2}T-Shirt price: -STR_1981 :{WINDOW_COLOUR_2}Donut price: -STR_1982 :{WINDOW_COLOUR_2}Coffee price: +STR_1975 :{WINDOW_COLOUR_2}Prix du popcorn: +STR_1976 :{WINDOW_COLOUR_2}Prix d'un hot-dog: +STR_1977 :{WINDOW_COLOUR_2}Prix du pouple: +STR_1978 :{WINDOW_COLOUR_2}Prix d'un chapeau: +STR_1979 :{WINDOW_COLOUR_2}Prix d'une pomme d'amour: +STR_1980 :{WINDOW_COLOUR_2}Prix d'un T-Shirt: +STR_1981 :{WINDOW_COLOUR_2}Prix d'un donut: +STR_1982 :{WINDOW_COLOUR_2}Prix d'un café: STR_1983 :{WINDOW_COLOUR_2} -STR_1984 :{WINDOW_COLOUR_2}Fried Chicken price: -STR_1985 :{WINDOW_COLOUR_2}Lemonade price: +STR_1984 :{WINDOW_COLOUR_2}Prix du poulet frit: +STR_1985 :{WINDOW_COLOUR_2}Prix de la limonade: STR_1986 :{WINDOW_COLOUR_2} STR_1987 :{WINDOW_COLOUR_2} -STR_1988 :Balloon -STR_1989 :Cuddly Toy -STR_1990 :Park Map -STR_1991 :On-Ride Photo -STR_1992 :Umbrella -STR_1993 :Drink +STR_1988 :Ballon +STR_1989 :Peluche +STR_1990 :Carte du parc +STR_1991 :Photo sur le vif +STR_1992 :Parapluie +STR_1993 :Boisson gazeuse STR_1994 :Burger -STR_1995 :Fries -STR_1996 :Ice Cream -STR_1997 :Cotton Candy -STR_1998 :Empty Can -STR_1999 :Rubbish -STR_2000 :Empty Burger Box +STR_1995 :Frites +STR_1996 :Glace +STR_1997 :Barbe-à-papa +STR_1998 :Canette vide +STR_1999 :Déchet +STR_2000 :Boite à Burger vide STR_2001 :Pizza -STR_2002 :Voucher +STR_2002 :Coupon STR_2003 :Popcorn -STR_2004 :Hot Dog -STR_2005 :Tentacle -STR_2006 :Hat -STR_2007 :Candy Apple +STR_2004 :Hot-Dog +STR_2005 :Poulpe +STR_2006 :Chapeau +STR_2007 :Pomme d'amour STR_2008 :T-Shirt STR_2009 :Donut -STR_2010 :Coffee -STR_2011 :Empty Cup -STR_2012 :Fried Chicken -STR_2013 :Lemonade -STR_2014 :Empty Box -STR_2015 :Empty Bottle -STR_2016 :Balloons -STR_2017 :Cuddly Toys -STR_2018 :Park Maps -STR_2019 :On-Ride Photos -STR_2020 :Umbrellas -STR_2021 :Drinks +STR_2010 :Café +STR_2011 :Tasse vide +STR_2012 :Poulet frit +STR_2013 :Limonade +STR_2014 :Boite vide +STR_2015 :Bouteille vide +STR_2016 :Ballons +STR_2017 :Peluches +STR_2018 :Cartes du parc +STR_2019 :Photos sur le vif +STR_2020 :Parapluies +STR_2021 :Boissons gazeuses STR_2022 :Burgers -STR_2023 :Fries -STR_2024 :Ice Creams -STR_2025 :Cotton Candy -STR_2026 :Empty Cans -STR_2027 :Rubbish -STR_2028 :Empty Burger Boxes +STR_2023 :Frites +STR_2024 :Glaces +STR_2025 :Barbes-à-papa +STR_2026 :Canettes vides +STR_2027 :Déchets +STR_2028 :Boites à Burger vides STR_2029 :Pizzas -STR_2030 :Vouchers +STR_2030 :Coupons STR_2031 :Popcorn -STR_2032 :Hot Dogs -STR_2033 :Tentacles -STR_2034 :Hats -STR_2035 :Candy Apples +STR_2032 :Hot-Dogs +STR_2033 :Poulpe +STR_2034 :Chapeaux +STR_2035 :Pommes d'amour STR_2036 :T-Shirts STR_2037 :Donuts -STR_2038 :Coffees -STR_2039 :Empty Cups -STR_2040 :Fried Chicken -STR_2041 :Lemonade -STR_2042 :Empty Boxes -STR_2043 :Empty Bottles -STR_2044 :a Balloon -STR_2045 :a Cuddly Toy -STR_2046 :a Park Map -STR_2047 :an On-Ride Photo -STR_2048 :an Umbrella -STR_2049 :a Drink -STR_2050 :a Burger -STR_2051 :some Fries -STR_2052 :an Ice Cream -STR_2053 :some Cotton Candy -STR_2054 :an Empty Can -STR_2055 :some Rubbish -STR_2056 :an Empty Burger Box -STR_2057 :a Pizza -STR_2058 :a Voucher -STR_2059 :some Popcorn -STR_2060 :a Hot Dog -STR_2061 :a Tentacle -STR_2062 :a Hat -STR_2063 :a Candy Apple -STR_2064 :a T-Shirt -STR_2065 :a Donut -STR_2066 :a Coffee -STR_2067 :an Empty Cup -STR_2068 :some Fried Chicken -STR_2069 :some Lemonade -STR_2070 :an Empty Box -STR_2071 :an Empty Bottle -STR_2072 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Balloon -STR_2073 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Cuddly Toy -STR_2074 :Map of {STRINGID} -STR_2075 :On-Ride Photo of {STRINGID} -STR_2076 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Umbrella -STR_2077 :Drink +STR_2038 :Cafés +STR_2039 :Tasses vides +STR_2040 :Poulet frit +STR_2041 :Limonade +STR_2042 :Boites vides +STR_2043 :Bouteilles vides +STR_2044 :un Ballon +STR_2045 :une Peluche +STR_2046 :une carte du parc +STR_2047 :une photo sur le vif +STR_2048 :un parapluie +STR_2049 :une boisson gazeuse +STR_2050 :un Burger +STR_2051 :des Frites +STR_2052 :une glace +STR_2053 :une barbe-à-papa +STR_2054 :une canette vide +STR_2055 :un déchet +STR_2056 :une Boite à Burger vide +STR_2057 :une Pizza +STR_2058 :un Coupon +STR_2059 :du Popcorn +STR_2060 :un Hot-Dog +STR_2061 :du Poulpe +STR_2062 :un chapeau +STR_2063 :une pomme d'amour +STR_2064 :un T-Shirt +STR_2065 :un Donut +STR_2066 :un café +STR_2067 :une tasse vide +STR_2068 :du poulet frit +STR_2069 :de la limonade +STR_2070 :une boite vide +STR_2071 :une bouteille vide +STR_2072 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Ballon +STR_2073 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Peluche +STR_2074 :Carte de {STRINGID} +STR_2075 :Photo sur le vif de {STRINGID} +STR_2076 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Parapluie +STR_2077 :Boisson gazeuse STR_2078 :Burger -STR_2079 :Fries -STR_2080 :Ice Cream -STR_2081 :Cotton Candy -STR_2082 :Empty Can -STR_2083 :Rubbish -STR_2084 :Empty Burger Box +STR_2079 :Frites +STR_2080 :Glace +STR_2081 :Barbe-à-papa +STR_2082 :Canette vide +STR_2083 :Déchet +STR_2084 :Boite à Burger vide STR_2085 :Pizza -STR_2086 :Voucher for {STRINGID} +STR_2086 :Coupon pour {STRINGID} STR_2087 :Popcorn -STR_2088 :Hot Dog -STR_2089 :Tentacle -STR_2090 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Hat -STR_2091 :Candy Apple +STR_2088 :Hot-Dog +STR_2089 :Poulpe +STR_2090 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Chapeau +STR_2091 :Pomme d'amour STR_2092 :{OPENQUOTES}{STRINGID}{ENDQUOTES} T-Shirt STR_2093 :Donut -STR_2094 :Coffee -STR_2095 :Empty Cup -STR_2096 :Fried Chicken -STR_2097 :Lemonade -STR_2098 :Empty Box -STR_2099 :Empty Bottle -STR_2100 :{WINDOW_COLOUR_2}On-Ride Photo price: -STR_2101 :{WINDOW_COLOUR_2}On-Ride Photo price: -STR_2102 :{WINDOW_COLOUR_2}On-Ride Photo price: -STR_2103 :{WINDOW_COLOUR_2}Pretzel price: -STR_2104 :{WINDOW_COLOUR_2}Hot Chocolate price: -STR_2105 :{WINDOW_COLOUR_2}Iced Tea price: -STR_2106 :{WINDOW_COLOUR_2}Funnel Cake price: -STR_2107 :{WINDOW_COLOUR_2}Sunglasses price: -STR_2108 :{WINDOW_COLOUR_2}Beef Noodles price: -STR_2109 :{WINDOW_COLOUR_2}Fried Rice Noodles price: -STR_2110 :{WINDOW_COLOUR_2}Wonton Soup price: -STR_2111 :{WINDOW_COLOUR_2}Meatball Soup price: -STR_2112 :{WINDOW_COLOUR_2}Fruit Juice price: -STR_2113 :{WINDOW_COLOUR_2}Soybean Milk price: -STR_2114 :{WINDOW_COLOUR_2}Sujongkwa price: -STR_2115 :{WINDOW_COLOUR_2}Sub Sandwich price: -STR_2116 :{WINDOW_COLOUR_2}Cookie price: +STR_2094 :Café +STR_2095 :Tasse vide +STR_2096 :Poulet frit +STR_2097 :Limonade +STR_2098 :Boite vide +STR_2099 :Bouteille vide +STR_2100 :{WINDOW_COLOUR_2}Prix d'une photo sur le vif: +STR_2101 :{WINDOW_COLOUR_2}Prix d'une photo sur le vif: +STR_2102 :{WINDOW_COLOUR_2}Prix d'une photo sur le vif: +STR_2103 :{WINDOW_COLOUR_2}Prix d'un bretzel: +STR_2104 :{WINDOW_COLOUR_2}Prix d'un chocolat chaud: +STR_2105 :{WINDOW_COLOUR_2}Prix d'un thé glacé: +STR_2106 :{WINDOW_COLOUR_2}Prix d'un funnel cake: +STR_2107 :{WINDOW_COLOUR_2}Prix des lunettes de soleil: +STR_2108 :{WINDOW_COLOUR_2}Prix des nouilles au boeuf: +STR_2109 :{WINDOW_COLOUR_2}Prix des nouilles au riz frit: +STR_2110 :{WINDOW_COLOUR_2}Prix de la soupe aux raviolis: +STR_2111 :{WINDOW_COLOUR_2}Prix de la soupe aux boulettes de viande: +STR_2112 :{WINDOW_COLOUR_2}Prix d'un jus de fruits: +STR_2113 :{WINDOW_COLOUR_2}Prix d'un lait de soja: +STR_2114 :{WINDOW_COLOUR_2}Prix d'un sujongkwa: +STR_2115 :{WINDOW_COLOUR_2}Prix d'un sub sandwich: +STR_2116 :{WINDOW_COLOUR_2}Prix d'un cookie: STR_2117 :{WINDOW_COLOUR_2} STR_2118 :{WINDOW_COLOUR_2} STR_2119 :{WINDOW_COLOUR_2} -STR_2120 :{WINDOW_COLOUR_2}Roast Sausage price: +STR_2120 :{WINDOW_COLOUR_2}Prix d'une saucisse grillée: STR_2121 :{WINDOW_COLOUR_2} -STR_2122 :On-Ride Photo -STR_2123 :On-Ride Photo -STR_2124 :On-Ride Photo -STR_2125 :Pretzel -STR_2126 :Hot Chocolate -STR_2127 :Iced Tea +STR_2122 :Photo sur le vif +STR_2123 :Photo sur le vif +STR_2124 :Photo sur le vif +STR_2125 :Bretzel +STR_2126 :Chocolat chaud +STR_2127 :Thé glacé STR_2128 :Funnel Cake -STR_2129 :Sunglasses -STR_2130 :Beef Noodles -STR_2131 :Fried Rice Noodles -STR_2132 :Wonton Soup -STR_2133 :Meatball Soup -STR_2134 :Fruit Juice -STR_2135 :Soybean Milk +STR_2129 :Lunettes de soleil +STR_2130 :Nouilles au boeuf +STR_2131 :Nouilles au riz frit +STR_2132 :Soupe aux raviolis +STR_2133 :Soupe aux boulettes de viande +STR_2134 :Jus de fruits +STR_2135 :Lait de soja STR_2136 :Sujongkwa STR_2137 :Sub Sandwich STR_2138 :Cookie -STR_2139 :Empty Bowl -STR_2140 :Empty Drink Carton -STR_2141 :Empty Juice Cup -STR_2142 :Roast Sausage -STR_2143 :Empty Bowl -STR_2144 :On-Ride Photos -STR_2145 :On-Ride Photos -STR_2146 :On-Ride Photos -STR_2147 :Pretzels -STR_2148 :Hot Chocolates -STR_2149 :Iced Teas +STR_2139 :Bol vide +STR_2140 :Brique vide +STR_2141 :Tasse de jus vide +STR_2142 :Saucisse grillée +STR_2143 :Bol vide +STR_2144 :Photos sur le vif +STR_2145 :Photos sur le vif +STR_2146 :Photos sur le vif +STR_2147 :Bretzels +STR_2148 :Chocolats chaud +STR_2149 :Thés glacés STR_2150 :Funnel Cakes -STR_2151 :Sunglasses -STR_2152 :Beef Noodles -STR_2153 :Fried Rice Noodles -STR_2154 :Wonton Soups -STR_2155 :Meatball Soups -STR_2156 :Fruit Juices -STR_2157 :Soybean Milks +STR_2151 :Lunettes de soleil +STR_2152 :Nouilles au boeuf +STR_2153 :Nouilles au riz frit +STR_2154 :Soupes aux raviolis +STR_2155 :Soupes aux boulettes de viande +STR_2156 :Jus de fruits +STR_2157 :Laits de soja STR_2158 :Sujongkwa -STR_2159 :Sub Sandwiches +STR_2159 :Sub Sandwichs STR_2160 :Cookies -STR_2161 :Empty Bowls -STR_2162 :Empty Drink Cartons -STR_2163 :Empty Juice cups -STR_2164 :Roast Sausages -STR_2165 :Empty Bowls -STR_2166 :an On-Ride Photo -STR_2167 :an On-Ride Photo -STR_2168 :an On-Ride Photo -STR_2169 :a Pretzel -STR_2170 :a Hot Chocolate -STR_2171 :an Iced Tea -STR_2172 :a Funnel Cake -STR_2173 :a pair of Sunglasses -STR_2174 :some Beef Noodles -STR_2175 :some Fried Rice Noodles -STR_2176 :some Wonton Soup -STR_2177 :some Meatball Soup -STR_2178 :a Fruit Juice -STR_2179 :some Soybean Milk -STR_2180 :some Sujongkwa -STR_2181 :a Sub Sandwich -STR_2182 :a Cookie -STR_2183 :an Empty Bowl -STR_2184 :an Empty Drink Carton -STR_2185 :an Empty Juice Cup -STR_2186 :a Roast Sausage -STR_2187 :an Empty Bowl -STR_2188 :On-Ride Photo of {STRINGID} -STR_2189 :On-Ride Photo of {STRINGID} -STR_2190 :On-Ride Photo of {STRINGID} -STR_2191 :Pretzel -STR_2192 :Hot Chocolate -STR_2193 :Iced Tea +STR_2161 :Bols vides +STR_2162 :Briques vides +STR_2163 :Tasses de jus vides +STR_2164 :Saucisses grillées +STR_2165 :Bols vides +STR_2166 :une photo sur le vif +STR_2167 :une photo sur le vif +STR_2168 :une photo sur le vif +STR_2169 :un bretzel +STR_2170 :un chocolat chaud +STR_2171 :un thé glacé +STR_2172 :un Funnel Cake +STR_2173 :une paire de lunettes de soleil +STR_2174 :des nouilles au boeuf +STR_2175 :des nouilles au riz frit +STR_2176 :de la soupe aux raviolis +STR_2177 :de la soupe aux boulettes de viande +STR_2178 :un jus de fruits +STR_2179 :du lait de soja +STR_2180 :du Sujongkwa +STR_2181 :un Sub Sandwich +STR_2182 :un Cookie +STR_2183 :un bol vide +STR_2184 :une brique vide +STR_2185 :une tasse de jus vide +STR_2186 :une saucisse grillée +STR_2187 :un bol vide +STR_2188 :Photo sur le vif de {STRINGID} +STR_2189 :Photo sur le vif de {STRINGID} +STR_2190 :Photo sur le vif de {STRINGID} +STR_2191 :Bretzel +STR_2192 :Chocolat chaud +STR_2193 :Thé glacé STR_2194 :Funnel Cake -STR_2195 :Sunglasses -STR_2196 :Beef Noodles -STR_2197 :Fried Rice Noodles -STR_2198 :Wonton Soup -STR_2199 :Meatball Soup -STR_2200 :Fruit Juice -STR_2201 :Soybean Milk +STR_2195 :Lunettes de soleil +STR_2196 :Nouilles au boeuf +STR_2197 :Nouilles au riz frit +STR_2198 :Soupe aux raviolis +STR_2199 :Soupe aux boulettes de viande +STR_2200 :Jus de fruits +STR_2201 :Lait de soja STR_2202 :Sujongkwa STR_2203 :Sub Sandwich STR_2204 :Cookie -STR_2205 :Empty Bowl -STR_2206 :Empty Drink Carton -STR_2207 :Empty Juice Cup -STR_2208 :Roast Sausage -STR_2209 :Empty Bowl -STR_2210 :{SMALLFONT}{BLACK}Show list of handymen in park -STR_2211 :{SMALLFONT}{BLACK}Show list of mechanics in park -STR_2212 :{SMALLFONT}{BLACK}Show list of security guards in park -STR_2213 :{SMALLFONT}{BLACK}Show list of entertainers in park -STR_2214 :Construction not possible while game is paused! +STR_2205 :Bol vide +STR_2206 :Brique vide +STR_2207 :Tasse de jus vide +STR_2208 :Saucisse grillée +STR_2209 :Bol vide +STR_2210 :{SMALLFONT}{BLACK}Afficher la liste des hommes de service dans le parc +STR_2211 :{SMALLFONT}{BLACK}Afficher la liste des mécaniciens dans le parc +STR_2212 :{SMALLFONT}{BLACK}Afficher la liste des agents de sécurité dans le parc +STR_2213 :{SMALLFONT}{BLACK}Afficher la liste des animateurs dans le parc +STR_2214 :Construction impossible durant la pause! STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C -STR_2217 :{WINDOW_COLOUR_2}{COMMA16}F -STR_2218 :{RED}{STRINGID} on {STRINGID} hasn't returned to the {STRINGID} yet!{NEWLINE}Check whether it is stuck or has stalled -STR_2219 :{RED}{COMMA16} people have died in an accident on {STRINGID} -STR_2220 :{WINDOW_COLOUR_2}Park Rating: {BLACK}{COMMA16} -STR_2221 :{SMALLFONT}{BLACK}Park Rating: {COMMA16} +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F +STR_2218 :{RED}{STRINGID} sur {STRINGID} n'est pas encore revenu à {STRINGID}!{NEWLINE}Vérifiez si il est coinçé ou au point mort +STR_2219 :{RED}{COMMA16} personnes sont mortes dans un accident sur {STRINGID} +STR_2220 :{WINDOW_COLOUR_2}Notation du parc: {BLACK}{COMMA16} +STR_2221 :{SMALLFONT}{BLACK}Notation du parc: {COMMA16} STR_2222 :{SMALLFONT}{BLACK}{STRINGID} -STR_2223 :{WINDOW_COLOUR_2}Guests in park: {BLACK}{COMMA16} +STR_2223 :{WINDOW_COLOUR_2}Visiteurs dans le parc: {BLACK}{COMMA16} STR_2224 :{WINDOW_COLOUR_2}Argent: {BLACK}{CURRENCY2DP} STR_2225 :{WINDOW_COLOUR_2}Argent: {RED}{CURRENCY2DP} STR_2226 :{WINDOW_COLOUR_2}Valeur du parc: {BLACK}{CURRENCY} STR_2227 :{WINDOW_COLOUR_2}Valeur de l'entreprise: {BLACK}{CURRENCY} -STR_2228 :{WINDOW_COLOUR_2}Last month's profit from food/drink and{NEWLINE}merchandise sales: {BLACK}{CURRENCY} +STR_2228 :{WINDOW_COLOUR_2}Profits du mois dernier provenant de l'alimentation et{NEWLINE} de la vente de marchandise: {BLACK}{CURRENCY} STR_2229 :Slope up to vertical STR_2230 :Vertical track STR_2231 :Holding brake for drop -STR_2232 :Cable lift hill -STR_2233 :{SMALLFONT}{BLACK}Park information -STR_2234 :Recent Messages +STR_2232 :Montée par câble +STR_2233 :{SMALLFONT}{BLACK}Informations sur le parc +STR_2234 :Messages récents STR_2235 :{SMALLFONT}{STRINGID} {STRINGID} STR_2236 :Janvier STR_2237 :Février @@ -2249,11 +2253,11 @@ STR_2244 :Septembre STR_2245 :Octobre STR_2246 :Novembre STR_2247 :Décembre -STR_2248 :Can't demolish ride/attraction... -STR_2249 :{BABYBLUE}New ride/attraction now available:{NEWLINE}{STRINGID} -STR_2250 :{BABYBLUE}New scenery/themeing now available:{NEWLINE}{STRINGID} -STR_2251 :Can only be built on paths! -STR_2252 :Can only be built across paths! +STR_2248 :Impossible de démolir l'attraction... +STR_2249 :{BABYBLUE}Nouvelle attraction disponible:{NEWLINE}{STRINGID} +STR_2250 :{BABYBLUE}Nouveau paysage disponible:{NEWLINE}{STRINGID} +STR_2251 :Ne peut être construit que sur les chemins! +STR_2252 :Ne peut être construit qu'à travers les chemins! STR_2253 :Attractions de transport STR_2254 :Attractions tranquilles STR_2255 :Montagnes russes @@ -2265,7 +2269,7 @@ STR_2260 :Aucun financement STR_2261 :Financement minimum STR_2262 :Financement normal STR_2263 :Financement maximum -STR_2264 :Research funding +STR_2264 :Financement recherches STR_2265 :{WINDOW_COLOUR_2}Coût: {BLACK}{CURRENCY} par mois STR_2266 :Priorités recherches STR_2267 :En cours de développement @@ -2275,9 +2279,9 @@ STR_2270 :{WINDOW_COLOUR_2}Progression: {BLACK}{STRINGID} STR_2271 :{WINDOW_COLOUR_2}Fin prévue: {BLACK}{STRINGID} STR_2272 :{WINDOW_COLOUR_2}Ride/attraction:{NEWLINE}{BLACK}{STRINGID} STR_2273 :{WINDOW_COLOUR_2}Scenery/themeing:{NEWLINE}{BLACK}{STRINGID} -STR_2274 :{SMALLFONT}{BLACK}Show details of this invention or development -STR_2275 :{SMALLFONT}{BLACK}Show funding and options for research & development -STR_2276 :{SMALLFONT}{BLACK}Show research & development status +STR_2274 :{SMALLFONT}{BLACK}Afficher détails de cette invention +STR_2275 :{SMALLFONT}{BLACK}Afficher financement et options de la recherche et du développement +STR_2276 :{SMALLFONT}{BLACK}Afficher status de la recherche et du développement STR_2277 :Inconnu STR_2278 :Attraction de transport STR_2279 :Attraction tranquille @@ -2286,44 +2290,44 @@ STR_2281 :Attraction frisson STR_2282 :Attraction aquatique STR_2283 :Magasins et boutiques STR_2284 :Décor et thèmes -STR_2285 :Initial research -STR_2286 :Designing -STR_2287 :Completing design -STR_2288 :Unknown +STR_2285 :Recherche initiale +STR_2286 :Conception +STR_2287 :Finition du concept +STR_2288 :Inconnu STR_2289 :{STRINGID} {STRINGID} STR_2290 :{SMALLFONT}{BLACK}{STRINGID} {STRINGID} STR_2291 :Choisir scénario pour nouvelle partie -STR_2292 :{WINDOW_COLOUR_2}Rides been on: -STR_2293 :{BLACK} Nothing +STR_2292 :{WINDOW_COLOUR_2}Attractions utilisées: +STR_2293 :{BLACK} Rien 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 -STR_2305 :Track design files -STR_2306 :Save track design -STR_2307 :Select {STRINGID} design -STR_2308 :{STRINGID} Track Designs -STR_2309 :Install New Track Design -STR_2310 :Build custom design +STR_2296 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} payé pour entrer dans le parc +STR_2297 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} dépensé pour {BLACK}{COMMA16} attraction +STR_2298 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} dépensé pour {BLACK}{COMMA16} attractions +STR_2299 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} dépensé pour {BLACK}{COMMA16} aliment +STR_2300 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} dépensé pour {BLACK}{COMMA16} aliments +STR_2301 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} dépensé pour {BLACK}{COMMA16} boisson +STR_2302 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} dépensé pour {BLACK}{COMMA16} boissons +STR_2303 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} dépensé pour {BLACK}{COMMA16} souvenir +STR_2304 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2} dépensé pour {BLACK}{COMMA16} souvenirs +STR_2305 :Fichiers de concepts de voie +STR_2306 :Sauvegarder le concept de voie +STR_2307 :Sélectionner le concept {STRINGID} +STR_2308 :{STRINGID} Concepts de Voies +STR_2309 :Installer un Nouveau Concept de Voie +STR_2310 :Construire un concept personnalisé STR_2311 :{WINDOW_COLOUR_2}Excitement rating: {BLACK}{COMMA2DP32} (approx.) STR_2312 :{WINDOW_COLOUR_2}Intensity rating: {BLACK}{COMMA2DP32} (approx.) STR_2313 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}{COMMA2DP32} (approx.) STR_2314 :{WINDOW_COLOUR_2}Ride length: {BLACK}{STRINGID} STR_2315 :{WINDOW_COLOUR_2}Cost: {BLACK}around {CURRENCY} STR_2316 :{WINDOW_COLOUR_2}Space required: {BLACK}{COMMA16} x {COMMA16} blocks -STR_2317 :{WINDOW_COLOUR_2}Sound Quality: -STR_2318 :Low -STR_2319 :Medium -STR_2320 :High -STR_2321 :{WINDOW_COLOUR_2}Number of rides/attractions: {BLACK}{COMMA16} -STR_2322 :{WINDOW_COLOUR_2}Staff: {BLACK}{COMMA16} +STR_2317 : +STR_2318 : +STR_2319 : +STR_2320 : +STR_2321 :{WINDOW_COLOUR_2}Nombre d'attractions: {BLACK}{COMMA16} +STR_2322 :{WINDOW_COLOUR_2}Personnel: {BLACK}{COMMA16} STR_2323 :{WINDOW_COLOUR_2}Park size: {BLACK}{COMMA32}m{SQUARED} STR_2324 :{WINDOW_COLOUR_2}Park size: {BLACK}{COMMA32}sq.ft. STR_2325 :{SMALLFONT}{BLACK}Buy land to extend park @@ -2337,7 +2341,7 @@ STR_2332 :Units STR_2333 :Son STR_2334 :Pounds ({POUND}) STR_2335 :Dollars ($) -STR_2336 :Franc (F) +STR_2336 :Francs (F) STR_2337 :Deutschmark (DM) STR_2338 :Yen ({YEN}) STR_2339 :Peseta (Pts) @@ -2368,7 +2372,7 @@ STR_2363 :Gridlines on Landscape STR_2364 :{SMALLFONT}{BLACK}Toggle gridlines on landscape on/off STR_2365 :The bank refuses to increase your loan! STR_2366 :Celsius ({DEGREE}C) -STR_2367 :Fahrenheit (F) +STR_2367 :Fahrenheit ({DEGREE}F) STR_2368 :None STR_2369 :Low STR_2370 :Average @@ -2438,12 +2442,12 @@ STR_2433 :{BLACK}Vouchers for free {STRINGID} STR_2434 :{BLACK}Advertising campaign for {STRINGID} STR_2435 :{BLACK}Advertising campaign for {STRINGID} STR_2436 :1 semaine -STR_2437 :2 semaines -STR_2438 :3 semaines -STR_2439 :4 semaines -STR_2440 :5 semaines -STR_2441 :6 semaines -STR_2442 :{BLACK}({STRINGID} remaining) +STR_2437 : +STR_2438 : +STR_2439 : +STR_2440 : +STR_2441 : +STR_2442 : STR_2443 :{WINDOW_COLOUR_2}Cost per week: {BLACK}{CURRENCY2DP} STR_2444 :{WINDOW_COLOUR_2}Total cost: {BLACK}{CURRENCY2DP} STR_2445 :Commencer campagne marketing @@ -2500,7 +2504,7 @@ STR_2495 :Cancel construction mode STR_2496 :Pause game STR_2497 :Zoom view out STR_2498 :Zoom view in -STR_2499 :Rotate view +STR_2499 :Rotate view clockwise STR_2500 :Rotate construction object STR_2501 :Underground view toggle STR_2502 :Remove base land toggle @@ -2682,10 +2686,10 @@ 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_2681 :{MEDIUMFONT}{BLACK}Increases your money by {CURRENCY} +STR_2682 : +STR_2683 : +STR_2684 :{SMALLFONT}{BLACK}Large group of peeps arrive STR_2685 :Simplex Noise Parameters STR_2686 :{WINDOW_COLOUR_2}Low: STR_2687 :{WINDOW_COLOUR_2}High: @@ -2702,11 +2706,11 @@ 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_2701 :Toutes les minutes +STR_2702 :Toutes les 5 minutes +STR_2703 :Toutes les 15 minutes +STR_2704 :Toutes les 30 minutes +STR_2705 :Toutes les heures STR_2706 :Jamais STR_2707 :Open new window STR_2708 :{WINDOW_COLOUR_1}Are you sure you want to overwrite {STRINGID}? @@ -2725,7 +2729,7 @@ 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_2724 :{UINT16}m {UINT16}s STR_2725 :{UINT16}m {UINT16}s STR_2726 :{UINT16}m STR_2727 :{UINT16}m @@ -2762,11 +2766,11 @@ STR_2757 :Force Sun STR_2758 :Force Thunder STR_2759 :Zero Clearance # New strings used in the cheats window previously these were ??? -STR_2760 :+5000 d'argent -STR_2761 :Pay For Entrance -STR_2762 :Pay For Rides +STR_2760 :+{CURRENCY} +STR_2761 : +STR_2762 : STR_2763 :??? -STR_2764 :Happy Guests +STR_2764 : STR_2765 :Large Tram STR_2766 :Win scenario STR_2767 :Freeze Climate @@ -2784,7 +2788,7 @@ STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} # End of new strings STR_2779 :Viewport #{COMMA16} STR_2780 :Extra viewport -STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} STR_2782 :SHIFT + STR_2783 :CTRL + STR_2784 :Change keyboard shortcut @@ -2814,7 +2818,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 @@ -2827,11 +2831,11 @@ 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 -STR_2828 :{WINDOW_COLOUR_2}Most dazzling ride color schemes award +STR_2828 :{WINDOW_COLOUR_2}Most dazzling ride colour schemes award STR_2829 :{WINDOW_COLOUR_2}Most confusing park layout award STR_2830 :{WINDOW_COLOUR_2}Best gentle ride award STR_2831 :{TOPAZ}Your park has received an award for being 'The most untidy park in the country'! @@ -2844,11 +2848,11 @@ 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'! -STR_2845 :{TOPAZ}Your park has received an award for being 'The park with the most dazzling choice of color schemes'! +STR_2845 :{TOPAZ}Your park has received an award for being 'The park with the most dazzling choice of colour schemes'! STR_2846 :{TOPAZ}Your park has received an award for being 'The park with the most confusing layout'! STR_2847 :{TOPAZ}Your park has received an award for being 'The park with the best gentle rides'! STR_2848 :{WINDOW_COLOUR_2}Pas de récompense récente @@ -2862,7 +2866,7 @@ STR_2855 :{RED}{STRINGID} has no path leading from its exit !{NEWLINE}Constru STR_2856 :{WINDOW_COLOUR_2}Didacticiel STR_2857 :{WINDOW_COLOUR_2}(Appuyez sur une touche ou un bouton de la souris pour essayer vous-même) STR_2858 :Can't start marketing campaign... -STR_2859 :Another instance of RollerCoaster Tycoon 2 is already running +STR_2859 :Another instance of OpenRCT2 is already running STR_2860 :Infogrames Interactive credits... STR_2861 :{WINDOW_COLOUR_2}Licensed to Infogrames Interactive Inc. STR_2862 :Remerciements musique... @@ -2972,14 +2976,14 @@ STR_2965 :{WINDOW_COLOUR_2} STR_2966 : STR_2967 : STR_2968 : -STR_2969 :Use of this product is subject to the terms of a license agreement -STR_2970 :found in the product's {OPENQUOTES}ReadMe{ENDQUOTES} file and in the manual -STR_2971 :Main color scheme -STR_2972 :Alternative color scheme 1 -STR_2973 :Alternative color scheme 2 -STR_2974 :Alternative color scheme 3 -STR_2975 :{SMALLFONT}{BLACK}Select which color scheme to change, or paint ride with -STR_2976 :{SMALLFONT}{BLACK}Paint an individual area of this ride using the selected color scheme +STR_2969 : +STR_2970 : +STR_2971 :Main colour scheme +STR_2972 :Alternative colour scheme 1 +STR_2973 :Alternative colour scheme 2 +STR_2974 :Alternative colour scheme 3 +STR_2975 :{SMALLFONT}{BLACK}Select which colour scheme to change, or paint ride with +STR_2976 :{SMALLFONT}{BLACK}Paint an individual area of this ride using the selected colour scheme STR_2977 :Staff member name STR_2978 :Enter new name for this member of staff: STR_2979 :Can't name staff member... @@ -2992,8 +2996,8 @@ STR_2985 :Banner STR_2986 :{SMALLFONT}{BLACK}Change text on banner STR_2987 :{SMALLFONT}{BLACK}Set this banner as a 'no-entry' sign for guests STR_2988 :{SMALLFONT}{BLACK}Demolish this banner -STR_2989 :{SMALLFONT}{BLACK}Select main color -STR_2990 :{SMALLFONT}{BLACK}Select text color +STR_2989 :{SMALLFONT}{BLACK}Select main colour +STR_2990 :{SMALLFONT}{BLACK}Select text colour STR_2991 :Sign STR_2992 :Sign text STR_2993 :Enter new text for this sign: @@ -3084,7 +3088,7 @@ STR_3077 :{RED}CLOSURE NOTICE: Your park has been closed down ! STR_3078 :Plain entrance STR_3079 :Wooden entrance STR_3080 :Canvas tent entrance -STR_3081 :Castle entrance (gray) +STR_3081 :Castle entrance (grey) STR_3082 :Castle entrance (brown) STR_3083 :Jungle entrance STR_3084 :Log cabin entrance @@ -3096,16 +3100,16 @@ STR_3089 :Space entrance STR_3090 :{SMALLFONT}{BLACK}Select style of entrance, exit, and station STR_3091 :You are not allowed to remove this section! STR_3092 :You are not allowed to move or modify the station for this ride! -STR_3093 :{WINDOW_COLOUR_2}Favorite: {BLACK}{STRINGID} +STR_3093 :{WINDOW_COLOUR_2}Favourite: {BLACK}{STRINGID} STR_3094 :N/A STR_3095 :{WINDOW_COLOUR_2}Lift hill chain speed: STR_3096 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} STR_3097 :{SMALLFONT}{BLACK}Select lift hill chain speed STR_3098 :Can't change lift hill speed... -STR_3099 :{SMALLFONT}{BLACK}Select color -STR_3100 :{SMALLFONT}{BLACK}Select second color -STR_3101 :{SMALLFONT}{BLACK}Select third color -STR_3102 :{SMALLFONT}{BLACK}Re-paint colored scenery on landscape +STR_3099 :{SMALLFONT}{BLACK}Select colour +STR_3100 :{SMALLFONT}{BLACK}Select second colour +STR_3101 :{SMALLFONT}{BLACK}Select third colour +STR_3102 :{SMALLFONT}{BLACK}Re-paint coloured scenery on landscape STR_3103 :Can't re-paint this... STR_3104 :{SMALLFONT}{BLACK}List rides STR_3105 :{SMALLFONT}{BLACK}List shops and stalls @@ -3125,8 +3129,8 @@ STR_3118 :{BLACK}{STRINGID} is heading for the ride STR_3119 :{BLACK}{STRINGID} is fixing the ride STR_3120 :{SMALLFONT}{BLACK}Locate nearest available mechanic, or mechanic fixing ride STR_3121 :Unable to locate mechanic, or all nearby mechanics are busy -STR_3122 :{WINDOW_COLOUR_2}Favorite ride of: {BLACK}{COMMA16} guest -STR_3123 :{WINDOW_COLOUR_2}Favorite ride of: {BLACK}{COMMA16} guests +STR_3122 :{WINDOW_COLOUR_2}Favourite ride of: {BLACK}{COMMA16} guest +STR_3123 :{WINDOW_COLOUR_2}Favourite ride of: {BLACK}{COMMA16} guests STR_3124 :Broken {STRINGID} STR_3125 :{WINDOW_COLOUR_2}Excitement Factor: {BLACK}+{COMMA16}% STR_3126 :{WINDOW_COLOUR_2}Intensity Factor: {BLACK}+{COMMA16}% @@ -3163,8 +3167,8 @@ STR_3156 : 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_3160 : +STR_3161 : STR_3162 :Unable to allocate enough memory STR_3163 :Installing new data: STR_3164 :{BLACK}{COMMA16} selected (maximum {COMMA16}) @@ -3175,7 +3179,7 @@ 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 -STR_3172 :The following object must be selected first: +STR_3172 :The following object must be selected first: {STRING} STR_3173 :This object is currently in use STR_3174 :This object is required by another object STR_3175 :This object is always required @@ -3340,7 +3344,7 @@ 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 :Parc Six Flags +STR_3337 : 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 @@ -3365,8 +3369,8 @@ 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_3362 : +STR_3363 : 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 @@ -3450,12 +3454,13 @@ STR_3443 :Page 4 STR_3444 :Page 5 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_5120 :Finances +STR_5121 :Research +STR_5122 :Select rides by track type (like in RCT1) STR_5123 :Renouveler attr. -STR_5124 :Pas de Six Flags +STR_5124 : STR_5125 :All destructable STR_5126 :Random title music STR_5127 :{SMALLFONT}{BLACK}Disable land elevation @@ -3478,7 +3483,7 @@ STR_5143 :Quick Speed STR_5144 :Fast Speed STR_5145 :Turbo Speed STR_5146 :Hyper Speed -STR_5147 :Show cheats button on toolbar +STR_5147 :Cheats STR_5148 :{SMALLFONT}{BLACK}Change the game speed STR_5149 :{SMALLFONT}{BLACK}Open the cheats window STR_5150 :Enable debugging tools @@ -3486,14 +3491,14 @@ STR_5150 :Enable debugging tools STR_5151 :. #Decimal separator STR_5152 :, -STR_5153 :Colour schemes... +STR_5153 :Thèmes... 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_5159 :Quitter OpenRCT2 +STR_5160 :{POP16}{MONTH} {PUSH16}{PUSH16}{STRINGID}, an {POP16}{COMMA16} STR_5161 :Date Format: STR_5162 :Day/Month/Year STR_5163 :Month/Day/Year @@ -3536,12 +3541,12 @@ 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_5203 :Attraction +STR_5204 :Liste des attractions +STR_5205 :Visiteur +STR_5206 :Liste des visiteurs +STR_5207 :Personnel +STR_5208 :Liste personnel STR_5209 :Banner STR_5210 :Object Selection STR_5211 :Invention List @@ -3551,7 +3556,7 @@ STR_5214 :Map Generation STR_5215 :Track Design Manager STR_5216 :Track Design Manager List STR_5217 :Cheats -STR_5218 :Themes +STR_5218 :Thèmes STR_5219 :Options STR_5220 :Keyboard Shortcuts STR_5221 :Change Keyboard Shortcut @@ -3577,7 +3582,7 @@ 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_5244 :Thèmes STR_5245 :Top Toolbar STR_5246 :Bottom Toolbar STR_5247 :Track Editor Bottom Toolbar @@ -3587,8 +3592,8 @@ 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_5254 :Create +STR_5255 :{SMALLFONT}{BLACK}Create a new title sequence from scratch 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 @@ -3602,7 +3607,7 @@ 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_5269 :{SMALLFONT}{BLACK}Controls and interface STR_5270 :{SMALLFONT}{BLACK}Miscellaneous STR_5271 :{SMALLFONT}{BLACK}Twitch STR_5272 :{SMALLFONT}{BLACK}Small Scenery @@ -3611,3 +3616,218 @@ 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 :{SMALLFONT}{BLACK}Makes some 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 :Park cheats +STR_5348 :Ride cheats +STR_5349 :{SMALLFONT}{BLACK}All Rides +STR_5350 :Max +STR_5351 :Min +STR_5352 :{BLACK}Bonheur: +STR_5353 :{BLACK}Energie: +STR_5354 :{BLACK}Faim: +STR_5355 :{BLACK}Soif: +STR_5356 :{BLACK}Nausée: +STR_5357 :{BLACK}Tolérance nausée: +STR_5358 :{BLACK}Toilettes: +STR_5359 :Remove guests +STR_5360 :{SMALLFONT}{BLACK}Removes all guests from the map +STR_5361 :Give all guests: +STR_5362 :{BLACK}Set all guests' preferred ride intensity to: +STR_5363 :More than 1 +STR_5364 :Less than 15 +STR_5365 :{BLACK}Vit. de personnel: +STR_5366 :Normal +STR_5367 :Rapide +STR_5368 :Reset crash status +STR_5369 :Park parameters... +STR_5370 :{SMALLFONT}{BLACK}Click this button to modify park{NEWLINE}parameters like restrictions,{NEWLINE}guest generation and money. +STR_5371 :Object Selection +STR_5372 :Invert right mouse dragging +STR_5373 :Nom {STRINGID} +STR_5374 :Date {STRINGID} +STR_5375 :{UP} +STR_5376 :{DOWN} +STR_5377 :{SMALLFONT}{BLACK}Saves +STR_5378 :{SMALLFONT}{BLACK}Script +STR_5379 :{SMALLFONT}{BLACK}Skip to next wait command +STR_5380 :{SMALLFONT}{BLACK}Start playing title sequence +STR_5381 :{SMALLFONT}{BLACK}Stop playing title sequence +STR_5382 :{SMALLFONT}{BLACK}Restart title sequence +STR_5383 :{SMALLFONT}{BLACK}Create a new title sequence based on the current one +STR_5384 :{SMALLFONT}{BLACK}Delete the current title sequence +STR_5385 :{SMALLFONT}{BLACK}Rename the current title sequence +STR_5386 :{SMALLFONT}{BLACK}Insert a new command +STR_5387 :{SMALLFONT}{BLACK}Edit the selected command +STR_5388 :{SMALLFONT}{BLACK}Delete the selected command +STR_5389 :{SMALLFONT}{BLACK}Skip to the selected command in the title sequence +STR_5390 :{SMALLFONT}{BLACK}Move the selected command down +STR_5391 :{SMALLFONT}{BLACK}Move the selected command up +STR_5392 :{SMALLFONT}{BLACK}Add a save to the title sequence +STR_5393 :{SMALLFONT}{BLACK}Remove the selected save from the title sequence +STR_5394 :{SMALLFONT}{BLACK}Rename the selected save +STR_5395 :{SMALLFONT}{BLACK}Load the selected save in game +STR_5396 :{SMALLFONT}{BLACK}Reload the title sequence if changes have been made to it outside of the game +STR_5397 :Can only be used on the title screen +STR_5398 :Cannot edit title sequence while it's playing +STR_5399 :Press the stop button to continue editing +STR_5400 :Can't change this title sequence +STR_5401 :Create a new title sequence to make changes to +STR_5402 :Failed to load title sequence +STR_5403 :There may be no Load or Wait command or a save may be invalid +STR_5404 :Name already exists +STR_5405 :Enter a name for the save +STR_5406 :Enter a name for the title sequence +STR_5407 :Add +STR_5408 :Remove +STR_5409 :Insert +STR_5410 :Edit +STR_5411 :Reload +STR_5412 :Skip to +STR_5413 :Load +STR_5414 :Load{MOVE_X}{87}Six Flags Magic Mountain.SC6 +STR_5415 :Load{MOVE_X}{87}{STRING} +STR_5416 :Load{MOVE_X}{87}No save selected +STR_5417 :Location +STR_5418 :Location{MOVE_X}{87}{COMMA16} {COMMA16} +STR_5419 :Rotate +STR_5420 :Rotate{MOVE_X}{87}{COMMA16} +STR_5421 :Zoom +STR_5422 :Zoom{MOVE_X}{87}{COMMA16} +STR_5423 :Wait +STR_5424 :Wait{MOVE_X}{87}{COMMA16} +STR_5425 :Restart +STR_5426 :End +STR_5427 :Coordinates: +STR_5428 :Anticlockwise rotations: +STR_5429 :Zoom level: +STR_5430 :Seconds to wait: +STR_5431 :Save to load: +STR_5432 :Command: +STR_5433 :Title Sequences +STR_5434 :Command Editor +STR_5435 :Rename save +STR_5436 :Edit Title Sequences... +STR_5437 :No save selected +STR_5438 :Can't make changes while command editor is open +STR_5439 :A wait command with at least 4 seconds is required with a restart command +STR_5440 :Minimise fullscreen on focus loss +STR_5441 :{SMALLFONT}{BLACK}Identifies rides by track type,{NEWLINE}so vehicles can be changed{NEWLINE}afterwards, like in RCT1. +STR_5442 :Force park rating: +STR_5443 :Vitesse{MOVE_X}{87}{STRINGID} +STR_5444 :Vitesse: +STR_5445 :Vitesse +STR_5446 :Get +STR_5447 :Type {STRINGID} +STR_5448 :Ride / Vehicle {STRINGID} +STR_5449 :Reduce game speed +STR_5450 :Increase game speed +STR_5451 :Open cheats window +STR_5452 :Toggle visibility of toolbars +STR_5453 :Select another ride +STR_5454 :Uncap FPS +STR_5455 :Enable sandbox mode +STR_5456 :Disable clearance checks +STR_5457 :Disable support limits +STR_5458 :Rotate clockwise +STR_5459 :Rotate anti-clockwise +STR_5460 :Rotate view anti-clockwise +STR_5461 :Set guests' parameters +STR_5462 :{CURRENCY} +STR_5463 :Goal: Have fun! +STR_5464 :General +STR_5465 :Climate +STR_5466 :Personnel +STR_5467 :ALT + +STR_5468 :Messages récents +STR_5469 :Scroll map up +STR_5470 :Scroll map left +STR_5471 :Scroll map down +STR_5472 :Scroll map right +STR_5473 :Cycle day / night +STR_5474 :Display text on banners in upper case +STR_5475 :{COMMA16} semaines +STR_5476 :Matériel +STR_5477 :Rendu de la carte +STR_5478 :Contrôles +STR_5479 :Barre d'outils +STR_5480 :Show toolbar buttons for: +STR_5481 :Thèmes +STR_5482 :{WINDOW_COLOUR_2}Temps écoulé depuis la dernière inspection: {BLACK}une minute +STR_5483 :{BLACK}({COMMA16} semaines restantes) +STR_5484 :{BLACK}({COMMA16} semaine restante) +STR_5485 :{SMALLFONT}{STRING} +STR_5486 :{BLACK}{COMMA16} +STR_5487 :{SMALLFONT}{BLACK}Afficher les messages récents +STR_5488 :Pas d'entrée +STR_5489 :{SMALLFONT}{BLACK}Afficher seulement les visiteurs surveillés +STR_5490 :Couper le son lorsque la fenêtre est minimisée +STR_5491 :Liste d'inventions +STR_5492 :Options scénario diff --git a/data/language/german.txt b/data/language/german.txt index c22c41c6a5..0a20a28754 100644 --- a/data/language/german.txt +++ b/data/language/german.txt @@ -54,7 +54,7 @@ STR_0049 :Spukhaus STR_0050 :Erste Hilfe STR_0051 :Zirkus STR_0052 :Geisterbahn -STR_0053 :Twister-Achterbahn +STR_0053 :Stahl-Twister-Achterbahn STR_0054 :Holzachterbahn STR_0055 :Achterbahn mit seitlicher Führung STR_0056 :Wilde Maus @@ -513,31 +513,31 @@ STR_0508 : STR_0509 : STR_0510 : STR_0511 : -STR_0512 : -STR_0513 : +STR_0512 :Eine kompakte Stahlachterbahn mit einem Spirallifthügel und Wagen mit Sitzen in einer Reihe +STR_0513 :Eine Looping-Achterbahn, bei der sich die Fahrgäste in einer stehenden Position befinden STR_0514 :Die unterhalb der Schiene aufgehängten Züge schwingen in Kurven seitlich aus. -STR_0515 : +STR_0515 :Die Fahrgäste sind in Sitzen, die unter den Schienen hängen und durch riesige Schleifen, Kurven und große Gefälle rasen STR_0516 :Eine gemäßigte Achterbahn für Leute, die noch nicht den Mut für längere Bahnen haben STR_0517 :Die Fahrgäste sitzen in Miniaturzügen, die auf einer schmalen Schienenstrecke fahren STR_0518 :Die Passagiere fahren in elektrischen Zügen auf einer Einschienenstrecke STR_0519 :Die Fahrgäste sitzen in kleinen, an einer Einschienenstrecke aufgehängten Wagen, die in Kurven seitlich frei schwingen -STR_0520 : -STR_0521 : -STR_0522 : +STR_0520 :Die Fahrgäste können ihr persönliches Wasserfahrzeug über das Wasser steuern +STR_0521 :Kleine mausförmige Wagen fahren auf einer Holzstrecke, wobei sich die Wagen in Haarnadelkurven und steilen Senken neigen +STR_0522 :Eine kleinere Achterbahn, auf der die Passagiere über der Strecke sitzen, ohne von einem Wagen umgeben zu sein STR_0523 :Die Passagiere sitzen in langsam angetriebenen Wagen auf einer Schienenstrecke -STR_0524 : -STR_0525 : -STR_0526 : +STR_0524 :Der Freefall-Wagen wird mit Druckluft einen hohen Stahlturm hochgeschossen, von wo er dann im freien Fall nach unten saust +STR_0525 :Die Passagiere fahren, nur von der Krümmung und der seitlichen Neigung der halbkreisförmigen Strecke geführt, auf einer verdrehten Strecke +STR_0526 :Rotierende Aussichtskabine, die sich an einem hohen Turm hinauf bewegt STR_0527 :Eine gemäßigte Stahlachterbahn, bei der vertikale Schleifen möglich sind -STR_0528 : -STR_0529 : +STR_0528 :Die Passagiere fahren in Schlauchbooten eine sich windende, halbkreisförmige oder komplett in sich geschlossene Rohrstrecke herunter +STR_0529 :Minenachterbahnzüge fahren auf Stahlschienen, die so aussehen wie alte Zugschienen STR_0530 :Die Wagen hängen an einem Stahlseil, das durchgängig von einem Streckenende zum anderen und wieder zurück führt -STR_0531 : +STR_0531 :Eine kompakte Stahlachterbahn, bei der der Zug durch Schrauben und Schleifen fährt STR_0532 : STR_0533 : -STR_0534 : -STR_0535 : -STR_0536 : +STR_0534 :Selbstbetriebene Benzin-Go-Karts +STR_0535 :Baumstammförmige Boote fahren in einem Wasserkanal und rutschen steile Gefälle herunter, damit die Fahrgäste unten nass werden +STR_0536 :Runde Boote gleiten durch einen breiten Wasserkanal, zischen durch Wasserfälle und schäumende Stromschnellen STR_0537 : STR_0538 : STR_0539 : @@ -556,14 +556,14 @@ STR_0551 : STR_0552 : STR_0553 : STR_0554 :Der Wagen wird mit Hilfe von linearen Induktionsmotoren aus der Station entlang einer langen, ebenen Bahn beschleunigt und dann vertikal nach oben geschossen, von wo er wieder im freien Fall zur Station zurückzukehrt -STR_0555 : -STR_0556 : +STR_0555 :Die Besucher fahren in einem Aufzug einen Turm hinauf oder hinab, um in ein anderes Stockwerk zu gelangen +STR_0556 :Besonders breite Wagen fallen eine vollständige Vertikale herunter - das ultimative Erlebnis des freien Falls STR_0557 : STR_0558 : STR_0559 : STR_0560 : STR_0561 : -STR_0562 : +STR_0562 :Angetriebene Wagen fahren auf einer mehrstöckigen Strecke mit gruseliger Landschaft und Spezialeffekten 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 @@ -572,38 +572,38 @@ STR_0567 :Die Passagiere befinden sich in Sitzen, die an beiden Seiten der Ba STR_0568 : STR_0569 :Die Passagiere, die in speziellen Vorrichtungen unter der Schiene fahren, haben das Gefühl zu fliegen, während sie durch die Lüfte sausen STR_0570 : -STR_0571 : -STR_0572 : -STR_0573 : -STR_0574 : +STR_0571 :Runde Wagen drehen sich auf der Zickzack-Holzstrecke +STR_0572 :Große Boote bewegen sich in einem breiten Wasserkanal, fahren von einem Fließband befördert Anstiege hoch und sausen steile Gefälle hinunter, damit die Fahrgäste mit einem gigantischen Platscher durchnässt werden +STR_0573 :Helikopterförmige Wagen fahren auf einer Stahlstrecke und werden von den Pedaltritten der Fahrer angetrieben +STR_0574 :Die Passagiere befinden sich in speziellen Haltevorrichtungen in liegender Position (entweder auf dem Rücken oder dem Bauch) und fahren auf einer gewundenen Strecke mit Überkopfteilen STR_0575 :Angetriebene Züge, die von einem einzelnen Gleis hängen, befördern die Fahrgäste durch den Park STR_0576 : -STR_0577 : +STR_0577 :Wagen mit Drehgestell fahren auf einer Holzstrecke und rotieren dabei auf speziellen Umkehrabschnitten STR_0578 :Die Wagen fahren auf einer Strecke mit kreisförmigen Reifen, steilen Gefällen und Heartline-Twists STR_0579 : -STR_0580 : -STR_0581 : +STR_0580 :Eine gigantische Stahlachterbahn mit gemäßigten Gefällen und Anstiegen von über 90 Meter +STR_0581 :Ein Ring mit Sitzen, der zur Spitze eines hohen Turms gezogen wird, während er sich leicht dreht, und dann im freien Fall heruntersaust, wobei er unten sanft von Magnetbremsen angehalten wird STR_0582 : STR_0583 : -STR_0584 : -STR_0585 : +STR_0584 :Spezielle Fahrräder fahren auf einer einschienigen Stahlstrecke und werden von den Passagieren angetrieben, indem sie in die Pedale treten +STR_0585 :Die Fahrgäste hängen in Sitzpaaren unter der Strecke und fahren Schleifen und Wendungen durch enge Kurven STR_0586 :Wagen in Bootsform laufen auf einer gewundenen Achterbahn mit steilen Gefällen, wobei sie in Wasserabschnitte klatschen, die in gemäßigtere Flussbereiche führen -STR_0587 : -STR_0588 : +STR_0587 :Nach einem atemberaubenden luftbetriebenen Start schnellt der Zug eine vertikale Strecke hoch, über die Spitze und auf der anderen Seite vertikal nach unten zurück zur Station +STR_0588 :Einzelne Wagen fahren unter einer Zickzack-Strecke mit Haarnadelkurven und steilen Gefällen STR_0589 : -STR_0590 : -STR_0591 : +STR_0590 :Die Fahrgäste fahren in einem U-Boot auf einer Unterwasserstrecke +STR_0591 :Floßförmige Boote winden sich sanft durch eine Flussstrecke STR_0592 : STR_0593 : STR_0594 : STR_0595 : STR_0596 : STR_0597 : -STR_0598 : +STR_0598 :Umgekehrte Achterbahnzüge werden aus der Station beschleunigt und rasen ein vertikales Streckenstück hinauf, sausen wieder hinab durch die Station und fahren einen anderen vertikalen Streckenabschnitt hinauf STR_0599 :Eine kompakte Achterbahn mit unabhängigen Wagen und gemäßigten, sich windenden Gefällen -STR_0600 : +STR_0600 :Angetriebene Minenzüge fahren auf einer gemäßigten und verwundenen Strecke STR_0601 : -STR_0602 : +STR_0602 :Achterbahnzüge werden aus der Station mit Hilfe von linearen Induktionsmotoren beschleunigt und rasen durch gewundene Überkopfteile STR_0603 :Besucher {INT32} STR_0604 :Besucher {INT32} STR_0605 :Besucher {INT32} @@ -834,21 +834,21 @@ STR_0829 :{SMALLFONT}{BLACK}Fenstertitel - Ziehen Sie hier, um das Fenster zu STR_0830 :{SMALLFONT}{BLACK}Ansicht heranzoomen STR_0831 :{SMALLFONT}{BLACK}Ansicht wegzoomen STR_0832 :{SMALLFONT}{BLACK}Ansicht um 90{DEGREE} im Uhrzeigersinn drehen -STR_0833 :{SMALLFONT}{BLACK}Spielpause -STR_0834 :{SMALLFONT}{BLACK}Festplatten- und Spieloptionen +STR_0833 :{SMALLFONT}{BLACK}Spiel pausieren +STR_0834 :{SMALLFONT}{BLACK}Speicher- und Spieloptionen STR_0835 :Spielinitialisierung fehlgeschlagen STR_0836 :Spiel kann nicht im minimierten Zustand gestartet werden STR_0837 :Grafiksystem kann nicht initialisiert werden -STR_0838 :CD-Code {INT32} ist für Ihre RollerCoaster Tycoon 2-CD nicht gültig!{WINDOW_COLOUR_1}{WINDOW_COLOUR_1}Deinstallieren Sie RollerCoaster Tycoon 2% und installieren Sie das Spiel mit dem korrekten CD-Code erneut +STR_0838 : STR_0839 :{UINT16} x {UINT16} STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} -STR_0841 :Desktop-Fenster -STR_0842 :640x480-Vollbild -STR_0843 :800x600-Vollbild -STR_0844 :1024x768-Vollbild -STR_0845 :1152x864-Vollbild -STR_0846 :1280x1024-Vollbild -STR_0847 :Infos zu `RollerCoaster Tycoon 2' +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +STR_0847 :Infos zu `OpenRCT2' STR_0848 :RollerCoaster Tycoon 2 STR_0849 :{WINDOW_COLOUR_2}Version 2.01.032 STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, alle Rechte vorbehalten @@ -880,8 +880,8 @@ STR_0875 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP STR_0876 :{BLACK}{DOWN} 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_0879 :Gelände kann hier nicht gesenkt werden... +STR_0880 :Gelände kann hier nicht erhöht werden... STR_0881 :Objekt ist im Weg STR_0882 :Spiel laden STR_0883 :Spiel speichern @@ -929,12 +929,12 @@ STR_0924 :{SMALLFONT}{BLACK}Spirale nach unten STR_0925 :{SMALLFONT}{BLACK}Spirale nach oben STR_0926 :Dies kann nicht entfernt werden... STR_0927 :Dies kann hier nicht gebaut werden... -STR_0928 :{SMALLFONT}{BLACK}Kettenlift, um Wagen einen Anstieg hinaufzuziehen +STR_0928 :{SMALLFONT}{BLACK}Kettenlift, um Wagen einen{NEWLINE}Anstieg hinaufzuziehen STR_0929 :S-Kurve (links) 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_0931 :Vertikale Schleife (l.) +STR_0932 :Vertikale Schleife (r.) +STR_0933 :Gelände muss erhöht/gesenkt werden STR_0934 :Attraktionseingang im Weg STR_0935 :Attraktionsausgang im Weg STR_0936 :Parkeingang im Weg @@ -1044,10 +1044,10 @@ STR_1039 :Neuen Streckenentwurf installieren STR_1040 :Spiel speichern STR_1041 :Szenario speichern STR_1042 :Landschaft speichern -STR_1043 :RollerCoaster Tycoon 2 - gespeichertes Spiel -STR_1044 :RollerCoaster Tycoon 2 - Szenariodatei -STR_1045 :RollerCoaster Tycoon 2 - Landschaftsdatei -STR_1046 :RollerCoaster Tycoon 2 - Streckenentwurfsdatei +STR_1043 :OpenRCT2 - gespeichertes Spiel +STR_1044 :OpenRCT2 - Szenariodatei +STR_1045 :OpenRCT2 - Landschaftsdatei +STR_1046 :OpenRCT2 - Streckenentwurfsdatei STR_1047 :Speicherung des Spiels fehlgeschlagen! STR_1048 :Speicherung des Szenarios fehlgeschlagen! STR_1049 :Speicherung der Landschaft fehlgeschlagen! @@ -1073,7 +1073,7 @@ STR_1068 :Rotationsliftmodus STR_1069 :Station-zu-Station-Modus STR_1070 :Einzelfahrt pro Eintritt STR_1071 :Unbegrenzte Fahrten pro Eintritt -STR_1072 :Irrgartenmodus +STR_1072 :Labyrinthmodus STR_1073 :Rennmodus STR_1074 :Autoskooter-Modus STR_1075 :Schwingmodus @@ -1160,7 +1160,7 @@ STR_1155 :Höhenmarkierungen an Fußwegen STR_1156 :{MOVE_X}{SMALLFONT}{STRINGID} STR_1157 :{TICK}{MOVE_X}{SMALLFONT}{STRINGID} STR_1158 :Kann nicht entfernt werden... -STR_1159 :{SMALLFONT}{BLACK}Platzieren Sie Szenerien, Beete und andere Objekte +STR_1159 :{SMALLFONT}{BLACK}Platzieren Sie Szenerien, Beete und{NEWLINE}andere Objekte STR_1160 :{SMALLFONT}{BLACK}Seen & Wasseranlagen erstellen/anpassen STR_1161 :Kann hier nicht positioniert werden... STR_1162 :{OUTLINE}{TOPAZ}{STRINGID} @@ -1172,16 +1172,16 @@ STR_1167 :Wasserspiegel kann hier nicht erhöht werden... STR_1168 :Optionen STR_1169 :(Keine) STR_1170 :{STRING} -STR_1171 :{RED}Geschlossen - - -STR_1172 :{YELLOW}{STRINGID} - - +STR_1171 :{RED}Geschlossen - - +STR_1172 :{YELLOW}{STRINGID} - - STR_1173 :{SMALLFONT}{BLACK}Fußwege und Warteschlangenreihen anlegen STR_1174 :Banner im Weg STR_1175 :Kann nicht auf Fußweg mit Neigung angelegt werden STR_1176 :Fußweg kann hier nicht angelegt werden... -STR_1177 :Fußweg kann von hier nicht entfernt werden... +STR_1177 :Fußweg kann hier nicht entfernt werden... STR_1178 :Landneigung unpassend STR_1179 :Fußweg im Weg -STR_1180 :Kann unter Wasser nicht gebaut werden! +STR_1180 :Kann nicht unter Wasser gebaut werden! STR_1181 :Fußwege STR_1182 :Art STR_1183 :Richtung @@ -1382,8 +1382,8 @@ STR_1377 :Heartline-Roll (links) STR_1378 :Heartline-Roll (rechts) STR_1379 :Umdreher (links) STR_1380 :Umdreher (rechts) -STR_1381 :Gebog. Lifthügel (l.) -STR_1382 :Gebog. Lifthügel (r.) +STR_1381 :Gebogener Lifthügel (l.) +STR_1382 :Gebogener Lifthügel (r.) STR_1383 :Viertelschleife STR_1384 :{YELLOW}{STRINGID} STR_1385 :{SMALLFONT}{BLACK}Andere Streckenkonfigurationen @@ -1407,7 +1407,7 @@ 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_1406 :{SMALLFONT}{BLACK}Szenerie ein-/ausschalten (falls{NEWLINE}für diesen Entwurf verfügbar) STR_1407 :{WINDOW_COLOUR_2}Dies bauen... STR_1408 :{WINDOW_COLOUR_2}Kosten: {BLACK}{CURRENCY} STR_1409 :Ein-/Ausgangsplattform @@ -1467,8 +1467,8 @@ STR_1462 :Zu steil für Lifthügel STR_1463 :Besucher STR_1464 :Spirale n. oben (klein) STR_1465 :Spirale n. oben (groß) -STR_1466 :Spirale n. unt. (klein) -STR_1467 :Spirale n. unt. (groß) +STR_1466 :Spirale n. unten (klein) +STR_1467 :Spirale n. unten (groß) STR_1468 :Personal STR_1469 :Fahrt muss mit Stationen anfangen und enden STR_1470 :Station nicht lang genug @@ -1514,7 +1514,7 @@ STR_1509 :{SMALLFONT}{OPENQUOTES}Ich möchte aus {STRINGID} aussteigen{ENDQUO 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} +STR_1513 :{SMALLFONT}{OPENQUOTES}Der Vandalismus hier ist schrecklich{ENDQUOTES} STR_1514 :{SMALLFONT}{OPENQUOTES}Eine tolle Landschaft!{ENDQUOTES} STR_1515 :{SMALLFONT}{OPENQUOTES}Dieser Park ist wirklich sauber und aufgeräumt{ENDQUOTES} STR_1516 :{SMALLFONT}{OPENQUOTES}Die Springbrunnen sind großartig{ENDQUOTES} @@ -1649,7 +1649,7 @@ STR_1644 : STR_1645 : STR_1646 : STR_1647 : -STR_1648 :{SMALLFONT}{OPENQUOTES}Hilfe! Bringt mich runter!{ENDQUOTES} +STR_1648 :{SMALLFONT}{OPENQUOTES}Hilfe! Lasst mich runter!{ENDQUOTES} STR_1649 :{SMALLFONT}{OPENQUOTES}Mir geht das Geld aus!{ENDQUOTES} STR_1650 :{SMALLFONT}{OPENQUOTES}Wow! Eine neue Bahn im Bau!{ENDQUOTES} STR_1651 :{SMALLFONT}{OPENQUOTES}Gute Bahn! Doch nicht so gut wie die Phoenix...{ENDQUOTES} @@ -1674,23 +1674,23 @@ STR_1669 :{WINDOW_COLOUR_2}Zufriedenheit: {BLACK}{COMMA16}% 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_1673 :Drehkontrolle umschalt. STR_1674 :Bremsgeschwindigkeit STR_1675 :{POP16}{VELOCITY} -STR_1676 :{SMALLFONT}{BLACK}Geschwindigkeitsgrenze für Bremsen einstellen +STR_1676 :{SMALLFONT}{BLACK}Geschwindigkeitsgrenze{NEWLINE}für Bremsen einstellen STR_1677 :{WINDOW_COLOUR_2}Popularität: {BLACK}Unbekannt STR_1678 :{WINDOW_COLOUR_2}Popularität: {BLACK}{COMMA16}% STR_1679 :Spirale n. oben (links) -STR_1680 :Spirale n. oben (r.) -STR_1681 :Spirale n. unt. (links) -STR_1682 :Spirale n. unt. (r.) +STR_1680 :Spirale n. oben (rechts) +STR_1681 :Spirale n. unten (links) +STR_1682 :Spirale n. unten (rechts) STR_1683 :Grundflächengröße 2 x 2 STR_1684 :Grundflächengröße 4 x 4 STR_1685 :Grundflächengröße 2 x 4 STR_1686 :Grundflächengröße 5 x 1 STR_1687 :Wasser-Splash STR_1688 :Grundflächengröße 4 x 1 -STR_1689 :Klotzbremsen +STR_1689 :Blockbremsen STR_1690 :{WINDOW_COLOUR_2}{STRINGID}{NEWLINE}{BLACK}{STRINGID} STR_1691 :{WINDOW_COLOUR_2} Kosten: {BLACK}{CURRENCY} STR_1692 :{WINDOW_COLOUR_2} Kosten: {BLACK}ab {CURRENCY} @@ -1709,7 +1709,7 @@ STR_1704 :Es kann kein neuer Mitarbeiter eingestellt werden... STR_1705 :{SMALLFONT}{BLACK}Diesen Mitarbeiter entlassen STR_1706 :{SMALLFONT}{BLACK}Diese Person an einen anderen Ort befördern STR_1707 :Zu viele Mitarbeiter im Spiel -STR_1708 :{SMALLFONT}{BLACK}Patrouillenbereich für diesen Mitarbeiter festlegen +STR_1708 :{SMALLFONT}{BLACK}Patrouillenbereich für diesen{NEWLINE}Mitarbeiter festlegen STR_1709 :Mitarbeiter entlassen STR_1710 :Ja STR_1711 :{WINDOW_COLOUR_1}Möchten Sie {STRINGID} wirklich entlassen? @@ -1731,12 +1731,12 @@ STR_1726 :Land nicht zum Verkauf! STR_1727 :Baurechte nicht zum Verkauf! STR_1728 :Erwerb von Baurechten hier nicht möglich... STR_1729 :Land gehört nicht dem Park! -STR_1730 :{RED}Geschlossen - - -STR_1731 :{WHITE}{STRINGID} - - +STR_1730 :{RED}Geschlossen - - +STR_1731 :{WHITE}{STRINGID} - - STR_1732 :Bauen STR_1733 :Modus STR_1734 :{WINDOW_COLOUR_2}Anzahl der Runden: -STR_1735 :{SMALLFONT}{BLACK}Rundenanzahl der Rundfahrt +STR_1735 :{SMALLFONT}{BLACK}Rundenanzahl STR_1736 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} STR_1737 :{COMMA16} STR_1738 :Rundenanzahl kann nicht geändert werden... @@ -1744,7 +1744,7 @@ STR_1739 :Rennen gewonnen von Besucher {INT32} STR_1740 :Rennen wurde gewonnen von {STRINGID} 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_1743 :{SMALLFONT}{BLACK}Max. Anzahl von Personen zur selben Zeit auf dieser Bahn STR_1744 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} STR_1745 :{COMMA16} STR_1746 :Dies kann nicht geändert werden... @@ -1762,7 +1762,7 @@ STR_1757 :{WINDOW_COLOUR_2}Zuverlässigkeit: {MOVE_X}{255}{BLACK}{COMMA16}% STR_1758 :{SMALLFONT}{BLACK}Baumodus STR_1759 :{SMALLFONT}{BLACK}Verschiebemodus STR_1760 :{SMALLFONT}{BLACK}Ausfüllmodus -STR_1761 :{SMALLFONT}{BLACK}Irrgarten in diese Richtung bauen +STR_1761 :{SMALLFONT}{BLACK}Labyrinth in diese Richtung bauen STR_1762 :Wasserfälle STR_1763 :Stromschnellen STR_1764 :Baumstammstöße @@ -1779,7 +1779,7 @@ STR_1774 :Nur ein Kabellifthügel pro Bahn erlaubt STR_1775 :Aus STR_1776 :Ein STR_1777 :{WINDOW_COLOUR_2}Musik -STR_1778 :{STRINGID} - - +STR_1778 :{STRINGID} - - STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Pandakostüm STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tigerkostüm STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} Elefantenkostüm @@ -1791,10 +1791,10 @@ STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} Astronautenkostüm STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} Banditenkostüm STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} Sheriffkostüm STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} Piratenkostüm -STR_1790 :{SMALLFONT}{BLACK}Uniformfarbe für diesen Mitarbeiter auswählen +STR_1790 :{SMALLFONT}{BLACK}Uniformfarbe für diesen{NEWLINE}Mitarbeiter auswählen STR_1791 :{WINDOW_COLOUR_2}Uniformfarbe: -STR_1792 :Antwortet auf {STRINGID} -Störungsruf -STR_1793 :Unterwegs zu {STRINGID} für eine Inspektion +STR_1792 :Antwortet auf Störung von {STRINGID} +STR_1793 :Unterwegs zur Inspektion von {STRINGID} STR_1794 :Repariert {STRINGID} STR_1795 :Beantwortet einen Funkspruch STR_1796 :Ist ausgefallen und erfordert Reparatur @@ -1817,16 +1817,16 @@ STR_1812 :{SMALLFONT}{BLACK}{STRINGID} STR_1813 :Verschiedene Objekte STR_1814 :Aktionen STR_1815 :Gedanken -STR_1816 :{SMALLFONT}{BLACK}Informationsart auswählen, die in Besucherliste angezeigt werden soll +STR_1816 :{SMALLFONT}{BLACK}Informationsart auswählen, die{NEWLINE}in Besucherliste angezeigt{NEWLINE}werden soll STR_1817 :({COMMA16}) STR_1818 :{WINDOW_COLOUR_2}Alle Besucher 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 Attraktion anzeigen +STR_1823 :{SMALLFONT}{BLACK}Gedanken der Besucher zu dieser{NEWLINE}Attraktion anzeigen STR_1824 :{SMALLFONT}{BLACK}Besucher dieser Attraktion anzeigen -STR_1825 :{SMALLFONT}{BLACK}Anstehende Besucher für diese Attraktion anzeigen +STR_1825 :{SMALLFONT}{BLACK}Anstehende Besucher für diese{NEWLINE}Attraktion anzeigen STR_1826 :Status STR_1827 :Popularität STR_1828 :Zufriedenheit @@ -1845,13 +1845,13 @@ STR_1840 :Ausfallzeit: {COMMA16}% 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 Attraktionsliste angezeigt werden soll +STR_1844 :{SMALLFONT}{BLACK}Informationsart auswählen, die{NEWLINE}in Attraktionsliste angezeigt{NEWLINE}werden soll STR_1845 :{MONTHYEAR} STR_1846 :{COMMA16} Besucher STR_1847 :{INLINE_SPRITE}{11}{20}{00}{00}{COMMA16} Besucher STR_1848 :{INLINE_SPRITE}{10}{20}{00}{00}{COMMA16} Besucher STR_1849 :{WINDOW_COLOUR_2}Musikwiedergabe -STR_1850 :{SMALLFONT}{BLACK}Auswählen, ob Musik für diese Bahn abgespielt werden soll +STR_1850 :{SMALLFONT}{BLACK}Auswählen, ob Musik für diese{NEWLINE}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}Erbaut: {BLACK}Dieses Jahr @@ -1891,10 +1891,10 @@ STR_1886 :Inspektion bei {STRINGID} STR_1887 :{WINDOW_COLOUR_2}Letzte Inspektion vor: {BLACK}{COMMA16} Minuten STR_1888 :{WINDOW_COLOUR_2}Letzte Inspektion vor: {BLACK}mehr als 4 Stunden 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_1890 :{SMALLFONT}{BLACK}Auswählen, wie oft ein Mechaniker{NEWLINE}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_1892 : +STR_1893 : STR_1894 :{WINDOW_COLOUR_2}{STRINGID} verkauft: {BLACK}{COMMA32} STR_1895 :{SMALLFONT}{BLACK}Neue Attraktion bauen STR_1896 :{WINDOW_COLOUR_2}Ausgaben/Einnahmen @@ -1919,7 +1919,7 @@ STR_1914 :{BLACK}{CURRENCY2DP} STR_1915 :{RED}{CURRENCY2DP} STR_1916 :{WINDOW_COLOUR_2}Darlehen: STR_1917 :{POP16}{POP16}{POP16}{CURRENCY} -STR_1918 :Es können keine weiteren Gelder geliehen werden! +STR_1918 :Es kann kein weiteres Darlehnen aufgenommen werden! STR_1919 :Nicht genügend Geld verfügbar! STR_1920 :Darlehen kann nicht zurückgezahlt werden! STR_1921 :{SMALLFONT}{BLACK}Neues Spiel beginnen @@ -1938,18 +1938,18 @@ STR_1933 :{STRINGID} ist in {STRINGID} STR_1934 :{STRINGID} hat {STRINGID} verlassen STR_1935 :{STRINGID} hat den Park verlassen STR_1936 :{STRINGID} hat {STRINGID} gekauft -STR_1937 :{SMALLFONT}{BLACK}Informationen zum Thema dieser Nachricht anzeigen +STR_1937 :{SMALLFONT}{BLACK}Informationen zum Thema dieser{NEWLINE}Nachricht anzeigen STR_1938 :{SMALLFONT}{BLACK}Ansicht des Besuchers anzeigen STR_1939 :{SMALLFONT}{BLACK}Ansicht des Mitarbeiters anzeigen -STR_1940 :{SMALLFONT}{BLACK}Vergnügen, Energie, Hunger, usw. dieses Besuchers anzeigen +STR_1940 :{SMALLFONT}{BLACK}Vergnügen, Energie, Hunger, usw.{NEWLINE}dieses Besuchers anzeigen STR_1941 :{SMALLFONT}{BLACK}Gefahrene Bahnen dieses Besuchers anzeigen -STR_1942 :{SMALLFONT}{BLACK}Finanzinformationen zu diesem Besucher anzeigen +STR_1942 :{SMALLFONT}{BLACK}Finanzinformationen zu diesem{NEWLINE}Besucher anzeigen STR_1943 :{SMALLFONT}{BLACK}Aktuelle Gedanken dieses Besuchers anzeigen -STR_1944 :{SMALLFONT}{BLACK}Objekte anzeigen, die der Besucher bei sich trägt +STR_1944 :{SMALLFONT}{BLACK}Objekte anzeigen, die der{NEWLINE}Besucher bei sich trägt STR_1945 :{SMALLFONT}{BLACK}Anweisungen und Optionen für diesen Mitarbeiter anzeigen STR_1946 :{SMALLFONT}{BLACK}Kostüm für diesen Animateur auswählen -STR_1947 :{SMALLFONT}{BLACK}Vom Mitarbeitertyp abgelaufene Bereiche anzeigen und den nächsten Mitarbeiter suchen -STR_1948 :{SMALLFONT}{BLACK}Neuen Mitarbeiter für den ausgewählten Typ einstellen +STR_1947 :{SMALLFONT}{BLACK}Vom Mitarbeitertyp abgelaufene{NEWLINE}Bereiche anzeigen und den nächsten{NEWLINE}Mitarbeiter suchen +STR_1948 :{SMALLFONT}{BLACK}Neuen Mitarbeiter für den ausgewählten{NEWLINE}Typ einstellen STR_1949 :Finanzübersicht STR_1950 :Finanzdiagramm STR_1951 :Verkehrswertdiagramm @@ -2218,9 +2218,9 @@ STR_2213 :{SMALLFONT}{BLACK}Liste der Animateure im Park anzeigen STR_2214 :Konstruktion während des Pausemodus nicht möglich! STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C -STR_2217 :{WINDOW_COLOUR_2}{COMMA16}F +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F STR_2218 :{RED}{STRINGID} bei {STRINGID} ist noch nicht zu {STRINGID} zurückgekehrt!{NEWLINE}Überprüfen Sie, ob es steckengeblieben ist oder angehalten hat -STR_2219 :{RED}{COMMA16} Menschen sind in einem Unfall gestorben bei {STRINGID} +STR_2219 :{RED}{COMMA16} Menschen sind in einem Unfall bei {STRINGID} gestorben STR_2220 :{WINDOW_COLOUR_2}Parkbewertung: {BLACK}{COMMA16} STR_2221 :{SMALLFONT}{BLACK}Parkbewertung: {COMMA16} STR_2222 :{SMALLFONT}{BLACK}{STRINGID} @@ -2269,13 +2269,13 @@ STR_2264 :Forschungsfinanzierung STR_2265 :{WINDOW_COLOUR_2}Kosten: {BLACK}{CURRENCY} pro Monat STR_2266 :Forschungsprioritäten STR_2267 :Zur Zeit in Entwicklung -STR_2268 :Letzte Entwicklung +STR_2268 :Zuletzt Entwickelt 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}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_2274 :{SMALLFONT}{BLACK}Details zu dieser Erfindung bzw.{NEWLINE}Entwicklung anzeigen STR_2275 :{SMALLFONT}{BLACK}Finanzierung und Optionen für Forschung & Entwicklung anzeigen STR_2276 :{SMALLFONT}{BLACK}Forschungs- & Entwicklungsstatus anzeigen STR_2277 :Unbekannt @@ -2291,7 +2291,7 @@ STR_2286 :Design STR_2287 :Abschluss des Designs STR_2288 :Unbekannt STR_2289 :{STRINGID} {STRINGID} -STR_2290 :{SMALLFONT}{BLACK}{STRINGID} {STRINGID} +STR_2290 : STR_2291 :Szenario für neues Spiel auswählen STR_2292 :{WINDOW_COLOUR_2}Fahrten auf: STR_2293 :{BLACK} Nichts @@ -2318,10 +2318,10 @@ 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ä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_2317 : +STR_2318 : +STR_2319 : +STR_2320 : 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} @@ -2368,7 +2368,7 @@ 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_2367 :Fahrenheit ({DEGREE}F) STR_2368 :Keine STR_2369 :Niedrig STR_2370 :Durchschnitt @@ -2438,12 +2438,12 @@ STR_2433 :{BLACK}Gutscheine für Gratis-{STRINGID} STR_2434 :{BLACK}Werbekampagne für {STRINGID} STR_2435 :{BLACK}Werbekampagne für {STRINGID} STR_2436 :1 Woche -STR_2437 :2 Wochen -STR_2438 :3 Wochen -STR_2439 :4 Wochen -STR_2440 :5 Wochen -STR_2441 :6 Wochen -STR_2442 :{BLACK}({STRINGID} übrig) +STR_2437 : +STR_2438 : +STR_2439 : +STR_2440 : +STR_2441 : +STR_2442 : STR_2443 :{WINDOW_COLOUR_2}Kosten pro Woche: {BLACK}{CURRENCY2DP} STR_2444 :{WINDOW_COLOUR_2}Gesamtkosten: {BLACK}{CURRENCY2DP} STR_2445 :Diese Marketingkampagne starten @@ -2459,17 +2459,17 @@ STR_2454 :{SMALLFONT}{BLACK}{CURRENCY2DP} - STR_2455 :{SMALLFONT}{BLACK}+{CURRENCY2DP} - STR_2456 :{SMALLFONT}{BLACK}{CURRENCY2DP} - STR_2457 :{SMALLFONT}{BLACK}Finanzkonten anzeigen -STR_2458 :{SMALLFONT}{BLACK}Gelddiagramm (abzüglich Darlehen) im Zeitverlauf anzeigen -STR_2459 :{SMALLFONT}{BLACK}Verkehrswertdiagramm im Zeitverlauf anzeigen +STR_2458 :{SMALLFONT}{BLACK}Gelddiagramm (abzüglich Darlehen){NEWLINE}im Zeitverlauf anzeigen +STR_2459 :{SMALLFONT}{BLACK}Verkehrswertdiagramm im{NEWLINE}Zeitverlauf anzeigen STR_2460 :{SMALLFONT}{BLACK}Diagramm zu Wochengewinn anzeigen STR_2461 :{SMALLFONT}{BLACK}Marketingkampagnen anzeigen STR_2462 :{SMALLFONT}{BLACK}Ansicht von Parkeingang anzeigen -STR_2463 :{SMALLFONT}{BLACK}Parkbewertungsdiagramm im Zeitverlauf anzeigen -STR_2464 :{SMALLFONT}{BLACK}Besucherzahlendiagramm im Zeitverlauf anzeigen +STR_2463 :{SMALLFONT}{BLACK}Parkbewertungsdiagramm{NEWLINE}im Zeitverlauf anzeigen +STR_2464 :{SMALLFONT}{BLACK}Besucherzahlendiagramm{NEWLINE}im Zeitverlauf anzeigen STR_2465 :{SMALLFONT}{BLACK}Parkeintrittspreis und -informationen anzeigen STR_2466 :{SMALLFONT}{BLACK}Parkstatistiken anzeigen STR_2467 :{SMALLFONT}{BLACK}Ziele für dieses Spiel anzeigen -STR_2468 :{SMALLFONT}{BLACK}Aktuelle Auszeichnungen anzeigen, die dieser Park erhalten hat +STR_2468 :{SMALLFONT}{BLACK}Aktuelle Auszeichnungen anzeigen,{NEWLINE}die dieser Park erhalten hat STR_2469 :{SMALLFONT}{BLACK}Forschungs- & Entwicklungsgrad auswählen STR_2470 :{SMALLFONT}{BLACK}Nach neuen Transportbahnen forschen STR_2471 :{SMALLFONT}{BLACK}Nach neuen gemäßigten Bahnen forschen @@ -2478,7 +2478,7 @@ 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 Attraktion auswählen +STR_2477 :{SMALLFONT}{BLACK}Betriebsmodus für diese{NEWLINE}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 @@ -2498,10 +2498,10 @@ STR_2492 :{SMALLFONT}{BLACK}Alle Tastenkürzel auf Standardeinstellung zurüc STR_2493 :Oberstes Fenster schließen STR_2494 :Alle freien Fenster schließen STR_2495 :Baumodus abbrechen -STR_2496 :Spielpause +STR_2496 :Spiel pausieren STR_2497 :Ansicht wegzoomen STR_2498 :Ansicht heranzoomen -STR_2499 :Ansicht drehen +STR_2499 :Ansicht im Uhrzeigersinn drehen STR_2500 :Bauobjekt drehen STR_2501 :Sicht auf Untergrund ein/aus STR_2502 :Grundfläche ein/aus @@ -2621,7 +2621,7 @@ STR_2614 :Y STR_2615 :Z STR_2616 :??? STR_2617 :??? -STR_2618 :Menu +STR_2618 :Menü STR_2619 :??? STR_2620 :??? STR_2621 :Zehnertastatur 0 @@ -2684,10 +2684,10 @@ STR_2677 :??? STR_2678 :??? STR_2679 :??? STR_2680 :Alle Forschungen beendet -STR_2681 :{MEDIUMFONT}{BLACK}Erhöht Ihr Geld um 5.000 +STR_2681 :{MEDIUMFONT}{BLACK}Erhöht Ihr Geld um {CURRENCY} 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_2684 :{SMALLFONT}{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: @@ -2704,13 +2704,13 @@ STR_2697 :??? STR_2698 :??? STR_2699 :??? 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_2701 :Jede Minute +STR_2702 :Alle 5 Minuten +STR_2703 :Alle 15 Minuten +STR_2704 :Alle 30 Minuten +STR_2705 :Jede Stunde STR_2706 :Nie -STR_2707 :Neues Fenster +STR_2707 :Systemdialogfeld verwenden STR_2708 :{WINDOW_COLOUR_1}Sind Sie sicher, dass Sie {STRINGID} überschreiben möchten? STR_2709 :Überschreiben STR_2710 :Geben Sie den Dateinamen ein: @@ -2721,8 +2721,8 @@ STR_2714 :- STR_2715 :. STR_2716 :/ STR_2717 :' -STR_2718 :(Hoch) -STR_2719 :(Neue Datei) +STR_2718 :Hoch +STR_2719 :Neue Datei STR_2720 :{UINT16}Sek. STR_2721 :{UINT16}Sek. STR_2722 :{UINT16}Min:{UINT16}Sek. @@ -2764,14 +2764,14 @@ 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_2760 :+{CURRENCY} STR_2761 :Bezahlen für Eintritt STR_2762 :Bezahlen für Bahnen STR_2763 :??? STR_2764 :Glückliche Gäste STR_2765 :Große Straßenbahn STR_2766 :Szenario gewinnen -STR_2767 :Wetter stoppen +STR_2767 :Wetter einfrieren STR_2768 :Wetter fortsetzen STR_2769 :Park öffnen STR_2770 :Park schließen @@ -2786,7 +2786,7 @@ STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} STR_2779 :Ansichtsfenster {COMMA16} STR_2780 :Extra Ansichtsfenster # End of new strings -STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} STR_2782 :UMSCHALT + STR_2783 :STRG + STR_2784 :Tastaturkürzel ändern @@ -2795,9 +2795,9 @@ STR_2786 :{SMALLFONT}{BLACK}Klicken Sie auf die Kürzelbeschreibung, um eine 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_2790 :Namen für die Szenarioübers. eingeben STR_2791 :Namen eingeben -STR_2792 :Geben Sie Ihren Namen für das Szenariodiagramm ein: +STR_2792 :Namen für die Szenarioübersicht eingeben: 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 @@ -2851,7 +2851,7 @@ STR_2842 :{TOPAZ}Ihr Park hat die Auszeichnung `Enttäuschendster Park des La STR_2843 :{TOPAZ}Ihr Park hat die Auszeichnung `Park mit den besten Wasserbahnen des Landes' erhalten! STR_2844 :{TOPAZ}Ihr Park hat die Auszeichnung `Park mit den besten eigenen Bahnentwürfen des Landes' erhalten! STR_2845 :{TOPAZ}Ihr Park hat die Auszeichnung `Park mit der buntesten Farbwahl' erhalten! -STR_2846 :{TOPAZ}Ihr Park hat die Auszeichnung `Park mit der konfusesten Anordnung' erhalten! +STR_2846 :{TOPAZ}Ihr Park hat die Auszeichnung `Park mit der verwirrensten Anordnung' erhalten! STR_2847 :{TOPAZ}Ihr Park hat die Auszeichnung `Park mit den besten gemäßigten Bahnen' erhalten! STR_2848 :{WINDOW_COLOUR_2}Keine aktuellen Auszeichnungen STR_2849 :Neues Szenario erfolgreich installiert @@ -2864,7 +2864,7 @@ STR_2855 :{RED}{STRINGID} hat keinen Fußweg, der vom Ausgang wegführt!{NEWL 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) STR_2858 :Marketingkampage kann nicht gestartet werden... -STR_2859 :RollerCoaster Tycoon 2 läuft bereits +STR_2859 :OpenRCT2 läuft bereits STR_2860 :Infogrames Interactive Credits... STR_2861 :{WINDOW_COLOUR_2}Lizenziert für Infogrames Interactive Inc. STR_2862 :Musik... @@ -2974,8 +2974,8 @@ STR_2965 :{WINDOW_COLOUR_2} STR_2966 : STR_2967 : STR_2968 : -STR_2969 :Die Verwendung dieses Produkts unterliegt den Bestimmungen eines Lizenzvertrages, -STR_2970 :der in der {OPENQUOTES}ReadMe{ENDQUOTES}-Datei und dem Handbuch nachgesehen werden kann +STR_2969 : +STR_2970 : STR_2971 :Hauptfarbschema STR_2972 :Alternatives Farbschema 1 STR_2973 :Alternatives Farbschema 2 @@ -2986,14 +2986,14 @@ STR_2977 :Mitarbeitername 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_2981 :{RED}Kein Zutritt - - STR_2982 :Bannertext -STR_2983 :Neuen Text für diesen Banner eingeben: -STR_2984 :Neuer Text für den Banner kann nicht erstellt werden... +STR_2983 :Neuen Text für dieses Banner eingeben: +STR_2984 :Neuer Text für das Banner kann nicht erstellt werden... STR_2985 :Banner STR_2986 :{SMALLFONT}{BLACK}Text auf Banner ändern -STR_2987 :{SMALLFONT}{BLACK}Legen Sie diesen Banner als `Kein Zutritt'-Schild für Besucher fest -STR_2988 :{SMALLFONT}{BLACK}Diesen Banner abreißen +STR_2987 :{SMALLFONT}{BLACK}Legen Sie dieses Banner als{NEWLINE}`Kein Zutritt'-Schild für{NEWLINE}Besucher fest +STR_2988 :{SMALLFONT}{BLACK}Dieses Banner abreißen STR_2989 :{SMALLFONT}{BLACK}Hauptfarbe auswählen STR_2990 :{SMALLFONT}{BLACK}Textfarbe auswählen STR_2991 :Schild @@ -3077,7 +3077,7 @@ STR_3068 :Andere Parks STR_3069 :Oberster Abschnitt STR_3070 :Neigung auf Ebene STR_3071 :{WINDOW_COLOUR_2}Gleicher Preis im ganzen Park -STR_3072 :{SMALLFONT}{BLACK}Bestimmen Sie, ob dieser Preis im gesamten Park gilt +STR_3072 :{SMALLFONT}{BLACK}Bestimmen Sie, ob dieser Preis{NEWLINE}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 STR_3075 :{RED}WARNUNG: Ihre Parkbewertung liegt immer noch unter dem Wert 700!{NEWLINE}Sie haben noch 2 Wochen Zeit, um die Parkbewertung zu erhöhen, oder Ihr Park wird geschlossen @@ -3095,7 +3095,7 @@ STR_3086 :Abstrakter Eingang STR_3087 :Schnee-/Eis-Eingang STR_3088 :Pagodeneingang STR_3089 :Weltraumeingang -STR_3090 :{SMALLFONT}{BLACK}Wählen Sie Stil für den Eingang, Ausgang und die Station aus +STR_3090 :{SMALLFONT}{BLACK}Wählen Sie Stil für den Eingang,{NEWLINE}Ausgang und die Station aus 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} @@ -3111,7 +3111,7 @@ STR_3102 :{SMALLFONT}{BLACK}Farbige Szenerie auf Gelände neu streichen STR_3103 :Dies kann nicht neu gestrichen werden... STR_3104 :{SMALLFONT}{BLACK}Bahnen auflisten STR_3105 :{SMALLFONT}{BLACK}Läden und Stände auflisten -STR_3106 :{SMALLFONT}{BLACK}Informationskiosks und andere Besuchereinrichtungen auflisten +STR_3106 :{SMALLFONT}{BLACK}Informationsstände und andere Besuchereinrichtungen{NEWLINE}auflisten STR_3107 :Schließen STR_3108 :Testen STR_3109 :Öffnen @@ -3125,8 +3125,8 @@ STR_3116 :{SMALLFONT}{BLACK}Streckenentwurf speichern (erst möglich, wenn di STR_3117 :{BLACK}Mechaniker rufen... STR_3118 :{BLACK}{STRINGID} geht zur Bahn STR_3119 :{BLACK}{STRINGID} repariert die Bahn -STR_3120 :{SMALLFONT}{BLACK}Nächsten verfügbaren Mechaniker oder Mechaniker bei einer Bahnreparatur suchen -STR_3121 :Örtlicher Mechaniker kann nicht gefunden werden, oder alle Mechaniker sind gerade beschäftigt +STR_3120 :{SMALLFONT}{BLACK}Nächsten verfügbaren Mechaniker{NEWLINE}oder Mechaniker bei einer{NEWLINE}Bahnreparatur suchen +STR_3121 :Es befindet sich kein Mechaniker in der Nähe, 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 :Defekt {STRINGID} @@ -3165,8 +3165,8 @@ STR_3156 : STR_3157 :Karte STR_3158 :Diagramm STR_3159 :Liste -STR_3160 :RollerCoaster Tycoon 2: Wird zum ersten Mal gestartet... -STR_3161 :RollerCoaster Tycoon 2: Objektdateien werden überprüft... +STR_3160 : +STR_3161 : STR_3162 :Es kann nicht genügend Geld bereitgestellt werden STR_3163 :Neue Daten werden installiert: STR_3164 :{BLACK}{COMMA16} ausgewählt (maximal {COMMA16}) @@ -3184,7 +3184,7 @@ 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 Attraktionsobjekt ausgewählt werden +STR_3179 :Es muss mindestens eine Attraktion ausgewählt werden STR_3180 :Ungültige Auswahl an Objekten STR_3181 :Objektauswahl - {STRINGID} STR_3182 :Parkeingangsart muss ausgewählt werden @@ -3226,14 +3226,14 @@ STR_3217 :Gelände im Besitz STR_3218 :Baurechte STR_3219 :Gelände zum Verkauf STR_3220 :Baurechte zum Verkauf -STR_3221 :{SMALLFONT}{BLACK}Legen Sie das Gelände fest, das dem Park gehören soll +STR_3221 :{SMALLFONT}{BLACK}Legen Sie das Gelände fest,{NEWLINE}das dem Park gehören soll STR_3222 :{SMALLFONT}{BLACK}Wählen Sie die Baurechte aus, die exklusiv dem Park gehören sollen -STR_3223 :{SMALLFONT}{BLACK}Legen Sie das Gelände fest, das vom Park gekauft werden kann -STR_3224 :{SMALLFONT}{BLACK}Legen Sie die Baurechte fest, die vom Park erworben werden können -STR_3225 :{SMALLFONT}{BLACK}Bau einer zufälligen Objektgruppe um ausgewählte Position herum ein-/ausschalten +STR_3223 :{SMALLFONT}{BLACK}Legen Sie das Gelände fest, das vom{NEWLINE}Park gekauft werden kann +STR_3224 :{SMALLFONT}{BLACK}Legen Sie die Baurechte fest, die vom{NEWLINE}Park erworben werden können +STR_3225 :{SMALLFONT}{BLACK}Bau einer zufälligen Objektgruppe{NEWLINE}um ausgewählte Position herum ein-/ausschalten STR_3226 :{SMALLFONT}{BLACK}Parkeingang bauen STR_3227 :Zu viele Parkeingänge! -STR_3228 :{SMALLFONT}{BLACK}Legen Sie die Startpositionen für Personen fest +STR_3228 :{SMALLFONT}{BLACK}Legen Sie die Startpositionen{NEWLINE}für Personen fest STR_3229 :Blockbremsen können nicht unmittelbar nach der Station eingesetzt werden STR_3230 :Blockbremsen können nicht unmittelbar hintereinander eingesetzt werden STR_3231 :Blockbremsen können nicht unmittelbar nach der Anstiegsspitze eingesetzt werden @@ -3262,26 +3262,26 @@ 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 aufregendere Bahnen bevorzugt -STR_3257 :{SMALLFONT}{BLACK}Wählen Sie aus, ob die Besucher im Allgemeinen weniger aufregende Bahnen vorziehen +STR_3257 :{SMALLFONT}{BLACK}Wählen Sie aus, ob die Besucher im Allgemeinen weniger aufregende{NEWLINE}Bahnen vorziehen STR_3258 :Aufregendere Bahnen bevorzugt -STR_3259 :{SMALLFONT}{BLACK}Wählen Sie aus, ob die Besucher im Allgemeinen aufregendere Bahnen vorziehen +STR_3259 :{SMALLFONT}{BLACK}Wählen Sie aus, ob die Besucher im Allgemeinen aufregendere{NEWLINE}Bahnen vorziehen 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 +STR_3266 :{SMALLFONT}{BLACK}Wählen Sie aus, was der Park für{NEWLINE}Eintritt und Fahrten verlangt STR_3267 :Entfernen von Bäumen verbieten STR_3268 :{SMALLFONT}{BLACK}Entfernen von hohen Bäumen verbieten STR_3269 :Landschaftsänderungen verbieten -STR_3270 :{SMALLFONT}{BLACK}Jegliche Änderungen an der Landschaft verbieten +STR_3270 :{SMALLFONT}{BLACK}Jegliche Änderungen an der{NEWLINE}Landschaft verbieten STR_3271 :Hohe Bauten verbieten STR_3272 :{SMALLFONT}{BLACK}Jegliche hohe Bauten verbieten STR_3273 :Höhere Schwierigkeitsstufe für Parkbewertung STR_3274 :{SMALLFONT}{BLACK}Machen Sie die Parkbewertung schwieriger STR_3275 :Höhere Schwierigkeitsstufe für Besuchergewinnung -STR_3276 :{SMALLFONT}{BLACK}Machen Sie das Anlocken von Besuchern schwieriger +STR_3276 :{SMALLFONT}{BLACK}Machen Sie das Anlocken von{NEWLINE}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/Bezahlen pro Fahrt @@ -3310,20 +3310,20 @@ STR_3301 :{WINDOW_COLOUR_2}Zieldatum: STR_3302 :{WINDOW_COLOUR_2}{MONTHYEAR} STR_3303 :{WINDOW_COLOUR_2}Besucheranzahl: STR_3304 :{WINDOW_COLOUR_2}Verkehrswert: -STR_3305 :{WINDOW_COLOUR_2}Mon. Einkünfte: +STR_3305 :{WINDOW_COLOUR_2}Monatliche Einkünfte: 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}Attraktionen unter Beibehaltungsauftrag: +STR_3312 :{WINDOW_COLOUR_2}Attraktionen unter Beibehaltungsauftrag: STR_3313 :Szenarioname STR_3314 :Namen für Szenario eingeben: STR_3315 :Park-/Szenariodetails 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_3318 :{SMALLFONT}{BLACK}Wählen Sie aus, in welcher Gruppe{NEWLINE}dieses Szenario vorkommt STR_3319 :{WINDOW_COLOUR_2}Szenariogruppe: STR_3320 :Szenariodatei kann nicht gespeichert werden... STR_3321 :Neue Objekte erfolgreich installiert @@ -3338,7 +3338,7 @@ STR_3329 :Parkeingang noch nicht gebaut STR_3330 :Park muss Gelände besitzen STR_3331 :Fußweg vom Parkeingang zum Kartenrand entweder nicht vollständig oder zu komplex - Fußweg darf nicht zu breit sein und sollte so wenige Kreuzungen und Biegungen wie möglich aufweisen STR_3332 :Parkeingang liegt verkehrt herum oder besitzt keinen Fußweg zum Kartenrand -STR_3333 :Plugin-Objekte bei gespeich. Spielen exportieren +STR_3333 :Zusatzobjekte bei gespeich. Spielen exportieren STR_3334 :{SMALLFONT}{BLACK}Wählen Sie aus, ob zusätzliche Plugin-Objektdaten (Zusatzdaten, die nicht zum Hauptprodukt gehören) in Spielständen oder Szenariodateien gespeichert werden sollen, damit jemand, der nicht über die zusätzlichen Objektdaten verfügt, die gespeicherten Daten laden kann STR_3335 :Achterbahn-Designer - Bahnarten & Fahrzeuge auswählen STR_3336 :Streckenentwurf-Manager - Bahnart auswählen @@ -3356,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 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 @@ -3367,8 +3367,8 @@ STR_3358 :Streckenentwurf kann nicht gelöscht werden... STR_3359 :{BLACK}Keine Streckenentwürfe dieser Art 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_3362 : +STR_3363 : STR_3364 :Fortgeschritten STR_3365 :{SMALLFONT}{BLACK}Ermöglichen Sie die Auswahl einzelner Szenerieobjekte zusätzlich zu Szeneriegruppen STR_3366 :{BLACK}= Bahn @@ -3453,9 +3453,9 @@ 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_5120 :Finanzen +STR_5121 :Forschung +STR_5122 :Bahnen nach Streckentyp auswählen (wie in RCT1) STR_5123 :Bahnen erneuern STR_5124 :Keine Six Flags STR_5125 :Alles zerstörbar @@ -3480,20 +3480,20 @@ 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_5147 :Cheats 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_5154 :Anzeige durch Hardware 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_5158 :Spiel beenden +STR_5159 :OpenRCT2 beenden +STR_5160 :{POP16}{MONTH} {PUSH16}{PUSH16}{STRINGID}, Jahr {POP16}{COMMA16} STR_5161 :Datumsformat: STR_5162 :Tag/Monat/Jahr STR_5163 :Monat/Tag/Jahr @@ -3508,7 +3508,7 @@ 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_5175 :Namen Ihres Twitch-Kanals eingeben: STR_5176 :Twitch-Integration aktivieren STR_5177 :Vollbildmodus: STR_5178 :{SMALLFONT}{BLACK}Cheats für Finanzen anzeigen @@ -3573,7 +3573,7 @@ STR_5236 :Fenster: STR_5237 :Farbpalette: STR_5238 :Aktuelles Thema: STR_5239 :Duplizieren -STR_5240 :Name für Thema eingeben: +STR_5240 :Namen 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 @@ -3587,10 +3587,10 @@ 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_5254 :Erstellen +STR_5255 :{SMALLFONT}{BLACK}Eine neue Titelsequenz von{NEWLINE}Grund auf neu erstellen STR_5256 :Neues Thema zum bearbeiten erstellen -STR_5257 :{SMALLFONT}{BLACK}Neues Thema durch duplizieren des aktuellen Themas erstellen +STR_5257 :{SMALLFONT}{BLACK}Neues Thema durch duplizieren des{NEWLINE}aktuellen Themas erstellen STR_5258 :{SMALLFONT}{BLACK}Aktuelles Thema löschen STR_5259 :{SMALLFONT}{BLACK}Aktuelles Thema umbenennen STR_5260 :Riesiger Screenshot @@ -3598,11 +3598,11 @@ 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_5265 :{SMALLFONT}{BLACK}Auswählen, welche Inhaltsquellen{NEWLINE}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_5269 :{SMALLFONT}{BLACK}Bedienung und Oberfläche STR_5270 :{SMALLFONT}{BLACK}Sonstiges STR_5271 :{SMALLFONT}{BLACK}Twitch STR_5272 :{SMALLFONT}{BLACK}Kleine Szenerie @@ -3611,15 +3611,15 @@ 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_5278 :Sandkastenmodus +STR_5279 :Sandkastenmod. 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_5286 :{SMALLFONT}{BLACK}Lässt einige Besucher explodieren STR_5287 :Bahn ist schon defekt STR_5288 :Bahn ist geschlossen STR_5289 :Für diese Bahn sind keine Defekte verfügbar @@ -3677,3 +3677,250 @@ STR_5340 :Lichte Höhe STR_5341 :Kennzeichen STR_5342 :Eine Kachel auf der Karte auswählen STR_5343 :Personal automatisch platzieren +STR_5344 :Changelog +STR_5345 :Cheats für Finanzen +STR_5346 :Cheats für Parkbesucher +STR_5347 :Cheats für Park +STR_5348 :Cheats für Attraktionen +STR_5349 :{SMALLFONT}{BLACK}Alle Attraktionen +STR_5350 :Max +STR_5351 :Min +STR_5352 :{BLACK}Vergnügen: +STR_5353 :{BLACK}Energie: +STR_5354 :{BLACK}Hunger: +STR_5355 :{BLACK}Durst: +STR_5356 :{BLACK}Übelkeit: +STR_5357 :{BLACK}Übelkeitstoleranz: +STR_5358 :{BLACK}Toilette: +STR_5359 :Besucher entfernen +STR_5360 :{SMALLFONT}{BLACK}Alle Besucher von der Karte entfernen +STR_5361 :Gib allen Besuchern: +STR_5362 :{BLACK}Bevorzugte Bahnintensität aller Besucher: +STR_5363 :Mehr als 1 +STR_5364 :Weniger als 15 +STR_5365 :{BLACK}Personalgeschw.: +STR_5366 :Normal +STR_5367 :Schnell +STR_5368 :Unfallstatus entf. +STR_5369 :Parkparameter... +STR_5370 :{SMALLFONT}{BLACK}Klicken Sie diese Schaltfläche um Parkparameter, wie Einschränkungen, Besuchergenerierung und Geld,{NEWLINE}zu bearbeiten +STR_5371 :Objektauswahl +STR_5372 :Ziehen mit rechter Maustaste umkehren +STR_5373 :Name {STRINGID} +STR_5374 :Datum {STRINGID} +STR_5375 :{UP} +STR_5376 :{DOWN} +STR_5377 :{SMALLFONT}{BLACK}Gespeicherte Spiele +STR_5378 :{SMALLFONT}{BLACK}Skript +STR_5379 :{SMALLFONT}{BLACK}Zum nächsten `Warten'-Befehl springen +STR_5380 :{SMALLFONT}{BLACK}Titelsequenz abspielen +STR_5381 :{SMALLFONT}{BLACK}Titelsequenz stoppen +STR_5382 :{SMALLFONT}{BLACK}Titelsequenz neu starten +STR_5383 :{SMALLFONT}{BLACK}Neue Titelsequenz durch duplizieren der aktuellen Titelsequenz erstellen +STR_5384 :{SMALLFONT}{BLACK}Aktuelle Titelsequenz löschen +STR_5385 :{SMALLFONT}{BLACK}Aktuelle Titelsequenz umbenennen +STR_5386 :{SMALLFONT}{BLACK}Neuen Befehl einfügen +STR_5387 :{SMALLFONT}{BLACK}Ausgewählten Befehl bearbeiten +STR_5388 :{SMALLFONT}{BLACK}Ausgewählten Befehl löschen +STR_5389 :{SMALLFONT}{BLACK}Zum ausgewählten Befehl in{NEWLINE}der Titelsequenz springen +STR_5390 :{SMALLFONT}{BLACK}Ausgewählten Befehl nach oben verschieben +STR_5391 :{SMALLFONT}{BLACK}Ausgewählten Befehl nach unten verschieben +STR_5392 :{SMALLFONT}{BLACK}Einen Spielstand zur Titelsequenz hinzufügen +STR_5393 :{SMALLFONT}{BLACK}Ausgewählten Spielstand von{NEWLINE}Titelsequenz entfernen +STR_5394 :{SMALLFONT}{BLACK}Ausgewählten Spielstand umbenennen +STR_5395 :{SMALLFONT}{BLACK}Ausgewählten Spielstand laden +STR_5396 :{SMALLFONT}{BLACK}Titelsequenz neu laden, falls sie außerhalb des Spiels geändert wurde +STR_5397 :Kann nur im Titelbildschirm verwendet werden +STR_5398 :Titelsequenz kann, während sie läuft, nicht geändert werden +STR_5399 :Titelsequenz stoppen, um das Bearbeiten fortzusetzen +STR_5400 :Diese Titelsequenz kann nicht geändert werden +STR_5401 :Erstellen Sie eine neue Titelsequenz, um sie zu bearbeiten +STR_5402 :Titelsequenz konnte nicht geladen werden +STR_5403 :Möglicherweise kein `Laden'-Befehl, `Warten'-Befehl oder ein ungültiger Spielstand vorhanden +STR_5404 :Dieser Name existiert bereits +STR_5405 :Namen für Spielstand eingeben: +STR_5406 :Namen für Titelsequenz eingeben: +STR_5407 :Hinzufügen +STR_5408 :Entfernen +STR_5409 :Einfügen +STR_5410 :Bearbeiten +STR_5411 :Neu laden +STR_5412 :Springen zu +STR_5413 :Laden +STR_5414 :Laden{MOVE_X}{87}Six Flags Magic Mountain.SC6 +STR_5415 :Laden{MOVE_X}{87}{STRING} +STR_5416 :Laden{MOVE_X}{87}Kein Spielstand ausgewählt +STR_5417 :Position +STR_5418 :Position{MOVE_X}{87}{COMMA16} {COMMA16} +STR_5419 :Drehen +STR_5420 :Drehen{MOVE_X}{87}{COMMA16} +STR_5421 :Zoom +STR_5422 :Zoom{MOVE_X}{87}{COMMA16} +STR_5423 :Warten +STR_5424 :Warten{MOVE_X}{87}{COMMA16} +STR_5425 :Neustart +STR_5426 :Ende +STR_5427 :Koordinaten: +STR_5428 :Drehungen gegen Uhrzeigersinn: +STR_5429 :Zoomstufe: +STR_5430 :Zu wartende Sekunden: +STR_5431 :Zu ladender Spielstand: +STR_5432 :Befehl: +STR_5433 :Titelsequenzen +STR_5434 :Befehlseditor +STR_5435 :Spielstand umbenennen +STR_5436 :Titelsequenzen bearbeiten... +STR_5437 :Kein Spielstand ausgewählt +STR_5438 :Es können keine Änderungen vorgenommen werden, solange der Befehlseditor geöffnet ist +STR_5439 :Zusammen mit einem `Neustart'-Befehl muss ein mindestens 4 Sekunden langer `Warten'-Befehl verwendet werden +STR_5440 :Vollbild minimieren, wenn Spiel nicht im Vordergrund +STR_5441 :{SMALLFONT}{BLACK}Identifiziert Bahnen durch Streckentyp, sodass wie in RCT1 Fahrzeuge anschließend geändert werden können +STR_5442 :Parkbewertung: +STR_5443 :Geschwind.{MOVE_X}{87}{STRINGID} +STR_5444 :Geschwindigkeit: +STR_5445 :Geschwindigkeit +STR_5446 :Erhalten +STR_5447 :Typ {STRINGID} +STR_5448 :Bahn / Fahrzeug {STRINGID} +STR_5449 :Spielgeschwindigkeit verringern +STR_5450 :Spielgeschwindigkeit erhöhen +STR_5451 :Cheatfenster anzeigen +STR_5452 :Symbolleiste ein-/ausblenden +STR_5453 :Andere Attraktion auswählen +STR_5454 :FPS-Limit aufheben +STR_5455 :Sandkastenmodus aktivieren +STR_5456 :Konstruktionsüberschneidungen erlauben +STR_5457 :Stützenlimit deaktivieren +STR_5458 :Im Uhrzeigersinn drehen +STR_5459 :Gegen den Uhrzeigersinn drehen +STR_5460 :Ansicht gegen den Uhrzeigers. drehen +STR_5461 :Besucherparameter festlegen +STR_5462 :{CURRENCY} +STR_5463 :Ziel: Viel Spaß! +STR_5464 :Allgemein +STR_5465 :Klima +STR_5466 :Personal +STR_5467 :ALT + +STR_5468 :Letzte Nachrichten +STR_5469 :Karte nach oben verschieben +STR_5470 :Karte nach links verschieben +STR_5471 :Karte nach unten verschieben +STR_5472 :Karte nach rechts verschieben +STR_5473 :Tag-Nacht-Wechsel +STR_5474 :Text auf Banner in Großbuchstaben anzeigen +STR_5475 :{COMMA16} Wochen +STR_5476 :Hardware +STR_5477 :Kartendarstellung +STR_5478 :Bedienung +STR_5479 :Symbolleiste +STR_5480 :Schaltflächen anzeigen für: +STR_5481 :Themen +STR_5482 :{WINDOW_COLOUR_2}Letzte Inspektion vor: {BLACK}1 Minute +STR_5483 :{BLACK}({COMMA16} Wochen verbleibend) +STR_5484 :{BLACK}({COMMA16} Woche verbleibend) +STR_5485 :{SMALLFONT}{STRING} +STR_5486 :{BLACK}{COMMA16} +STR_5487 :{SMALLFONT}{BLACK}Aktuelle Nachrichten anzeigen +STR_5488 :Kein Eingang (nur OpenRCT2!) +STR_5489 :{SMALLFONT}{BLACK}Nur überwachte Besucher anzeigen +STR_5490 :Audio deaktivieren, wenn Spiel nicht im Vordergrund +STR_5491 :Erfindungsliste +STR_5492 :Szenario-Optionen +STR_5493 :Nachricht senden +STR_5494 : +STR_5495 :Spielerliste +STR_5496 :Spieler: +STR_5497 :Ping: +STR_5498 :Serverliste +STR_5499 :Spielername: +STR_5500 :Server hinzufügen +STR_5501 :Server starten +STR_5502 :Mehrspieler +STR_5503 :Hostnamen oder IP-Adresse eingeben: +STR_5504 :{SMALLFONT}{BLACK}Mehrspielerstatus anzeigen +STR_5505 :Verbindung zum Server konnte nicht hergestellt werden +STR_5506 :Besucher ignorieren Bahnintensität +STR_5507 :Parkpfleger mähen standardmäßig Gras +STR_5508 :Laden von Dateien mit unzul. Prüfsummen erlauben +STR_5509 :{SMALLFONT}{BLACK}Erlaubt das Laden von Szenarios und gespeicherten Spielständen, die eine unzulässige Prüfsumme haben, wie Szenarios aus der Demo oder fehlerhafte Spielstände +STR_5510 :Standard Audiogerät +STR_5511 :(UNBEKANNT) +STR_5512 :Spiel speichern unter +STR_5513 :Schnellspeichern +STR_5514 :Vandalismus deaktivieren +STR_5515 :{SMALLFONT}{BLACK}Verhindert Vandalismus durch{NEWLINE}verärgerte Besucher +STR_5516 :{SMALLFONT}{BLACK}Schwarz +STR_5517 :{SMALLFONT}{BLACK}Grau +STR_5518 :{SMALLFONT}{BLACK}Weiß +STR_5519 :{SMALLFONT}{BLACK}Dunkelviolett +STR_5520 :{SMALLFONT}{BLACK}Hellviolett +STR_5521 :{SMALLFONT}{BLACK}Lila +STR_5522 :{SMALLFONT}{BLACK}Dunkelblau +STR_5523 :{SMALLFONT}{BLACK}Hellblau +STR_5524 :{SMALLFONT}{BLACK}Himmelblau +STR_5525 :{SMALLFONT}{BLACK}Dunkles Wasser +STR_5526 :{SMALLFONT}{BLACK}Helles Wasser +STR_5527 :{SMALLFONT}{BLACK}Gesättigtes Grün +STR_5528 :{SMALLFONT}{BLACK}Dunkelgrün +STR_5529 :{SMALLFONT}{BLACK}Moosgrün +STR_5530 :{SMALLFONT}{BLACK}Hellgrün +STR_5531 :{SMALLFONT}{BLACK}Olivgrün +STR_5532 :{SMALLFONT}{BLACK}Dunkles Olivgrün +STR_5533 :{SMALLFONT}{BLACK}Hellgelb +STR_5534 :{SMALLFONT}{BLACK}Gelb +STR_5535 :{SMALLFONT}{BLACK}Dunkelgelb +STR_5536 :{SMALLFONT}{BLACK}Orange +STR_5537 :{SMALLFONT}{BLACK}Dunkelorange +STR_5538 :{SMALLFONT}{BLACK}Hellbraun +STR_5539 :{SMALLFONT}{BLACK}Gesättigtes Braun +STR_5540 :{SMALLFONT}{BLACK}Dunkelbraun +STR_5541 :{SMALLFONT}{BLACK}Lachsrosa +STR_5542 :{SMALLFONT}{BLACK}Bordeauxrot +STR_5543 :{SMALLFONT}{BLACK}Gesättigtes Rot +STR_5544 :{SMALLFONT}{BLACK}Hellrot +STR_5545 :{SMALLFONT}{BLACK}Dunkelrosa +STR_5546 :{SMALLFONT}{BLACK}Leuchtendes Rosa +STR_5547 :{SMALLFONT}{BLACK}Hellrosa +STR_5548 :Alle Betriebsmodi anzeigen +STR_5549 :Jahr/Monat/Tag +STR_5550 :{POP16}{POP16}Jahr {COMMA16}, {PUSH16}{PUSH16}{MONTH} {PUSH16}{PUSH16}{STRINGID} +STR_5551 :Jahr/Tag/Monat +STR_5552 :{POP16}{POP16}Jahr {COMMA16}, {PUSH16}{PUSH16}{PUSH16}{STRINGID} {MONTH} +STR_5553 :Spiel bei geöffnetem Steam Overlay pausieren +STR_5554 :{SMALLFONT}{BLACK}Gebirgswerkzeug aktivieren +STR_5555 :Fahrzeuge anderer Streckentyp. anzeigen +STR_5556 :Spieler entfernen +STR_5557 :Nach Desync. verbunden bleiben (Mehrspieler) +STR_5558 :Damit diese Einstellung wirksam wird, ist ein Neustart erforderlich +STR_5559 :10 Min. Inspektionen +STR_5560 :{SMALLFONT}{BLACK}Setzt die Inspektionszeit aller Bahnen{NEWLINE}auf 'Alle 10 Minuten' +STR_5561 :Sprache konnte nicht geladen werden +STR_5562 :WARNUNG! +STR_5563 :Diese Funktion ist derzeit instabil und mit erhöhter Vorsicht zu verwenden. +STR_5564 :Fehlerhaftes Element einf. +STR_5565 :{SMALLFONT}{BLACK}Fügt ein fehlerhaftes Kartenelement auf der Kachel ein, dadurch werden alle Elemente darüber versteckt. +STR_5566 :Passwort: +STR_5567 :Veröffentlichen +STR_5568 :Passwort benötigt +STR_5569 :Dieser Server benötigt ein Passwort +STR_5570 :Server abrufen +STR_5571 :Spiel beitreten +STR_5572 :Zu Favoriten hinzufügen +STR_5573 :Aus Favoriten entfernen +STR_5574 :Servername: +STR_5575 :Max. Spieler: +STR_5576 :Port: +STR_5577 :Südkoreanischer Won (W) +STR_5578 :Russischer Rubel (R) +STR_5579 :Skalierungsfaktor: +STR_5580 :Tschechische Krone (Kc) + +####################### +# Bahnen/Attraktionen # +####################### + +#WW +[CONDORRD] +STR_NAME :Kondorbahn +STR_DESC :Die Passagiere fahren, in speziellen Gurten hängend, unterhalb der Strecke. In den kondorförmigen Wagen erleben sie dabei ein Gefühl des Fliegens. +STR_CPTY :4 Fahrgäste pro Wagen diff --git a/data/language/hungarian.txt b/data/language/hungarian.txt index 90ddd747cc..74069cab84 100644 --- a/data/language/hungarian.txt +++ b/data/language/hungarian.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 :Libegő -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 :Steel Twister Roller Coaster STR_0054 :Fa hullámvasút STR_0055 :Side-Friction Roller Coaster STR_0056 :Vad egér 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 :Felfüggesztett egysínű -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 hullámvasút -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 : @@ -513,31 +513,31 @@ STR_0508 : STR_0509 : STR_0510 : STR_0511 : -STR_0512 : -STR_0513 : +STR_0512 :A compact roller coaster with a spiral lift hill and smooth, twisting drops. +STR_0513 :A looping roller coaster where the riders ride in a standing position STR_0514 :Trains suspended beneath the roller coaster track swing out to the side around corners -STR_0515 : +STR_0515 :A steel roller coaster with trains that are held beneath the track, with many complex and twisting track elements STR_0516 :A gentle roller coaster for people who haven't yet got the courage to face the larger rides STR_0517 :Passengers ride in miniature trains along a narrow-gauge railway track STR_0518 :Passengers travel in electric trains along a monorail track STR_0519 :Passengers ride in small cars hanging beneath the single-rail track, swinging freely from side to side around corners -STR_0520 : -STR_0521 : -STR_0522 : +STR_0520 :A dock platform where guests can drive/row personal watercraft on a body of water +STR_0521 :A fast and twisting roller coaster with tight turns and steep drops. Intensity is bound to be high. +STR_0522 :A smaller roller coaster where the riders sit above the track with no car around them STR_0523 :Riders travel slowly in powered vehicles along a track-based route -STR_0524 : -STR_0525 : -STR_0526 : +STR_0524 :Freefall car is pneumatically launched up a tall steel tower and then allowed to freefall down +STR_0525 :Riders career down a twisting track guided only by the curvature and banking of the semi-circular track +STR_0526 :Passengers travel in a rotating observation cabin which travels up a tall tower STR_0527 :A smooth steel-tracked roller coaster capable of vertical loops -STR_0528 : -STR_0529 : +STR_0528 :Riders travel in inflatable dinghies down a twisting semi-circular or completely enclosed tube track +STR_0529 :Mine train themed roller coaster trains career along steel roller coaster track made to look like old railway track STR_0530 :Cars hang from a steel cable which runs continuously from one end of the ride to the other and back again -STR_0531 : +STR_0531 :A compact steel-tracked roller coaster where the train travels through corkscrews and loops STR_0532 : STR_0533 : -STR_0534 : -STR_0535 : -STR_0536 : +STR_0534 :Self-drive petrol-engined go karts +STR_0535 :Log-shaped boats travel along a water channel, splashing down steep slopes to soak the riders +STR_0536 :Circular boats meander along a wide water channel, splashing through waterfalls and thrilling riders through foaming rapids STR_0537 : STR_0538 : STR_0539 : @@ -556,14 +556,14 @@ STR_0551 : STR_0552 : STR_0553 : STR_0554 :The car is accelerated out of the station along a long level track using Linear Induction Motors, then heads straight up a vertical spike of track, freefalling back down to return to the station -STR_0555 : -STR_0556 : +STR_0555 :Guests ride in an elevator up or down a vertical tower to get from one level to another +STR_0556 :Extra-wide cars descend completely vertical sloped track for the ultimate freefall roller coaster experience STR_0557 : STR_0558 : STR_0559 : STR_0560 : STR_0561 : -STR_0562 : +STR_0562 :Powered cars travel along a multi-level track past spooky scenery and special effects STR_0563 :Sitting in comfortable trains with only simple lap restraints riders enjoy giant smooth drops and twisting track as well as plenty of 'air time' over the hills STR_0564 :Running on wooden track, this coaster is fast, rough, noisy, and gives an 'out of control' riding experience with plenty of 'air time' STR_0565 :A simple wooden roller coaster capable of only gentle slopes and turns, where the cars are only kept on the track by side friction wheels and gravity @@ -572,38 +572,38 @@ STR_0567 :Sitting in seats suspended either side of the track, riders are pit STR_0568 : STR_0569 :Riding in special harnesses below the track, riders experience the feeling of flight as they swoop through the air STR_0570 : -STR_0571 : -STR_0572 : -STR_0573 : -STR_0574 : +STR_0571 :Circular cars spin around as they travel along the zig-zagging wooden track +STR_0572 :Large capacity boats travel along a wide water channel, propelled up slopes by a conveyer belt, accelerating down steep slopes to soak the riders with a gaint splash +STR_0573 :Powered helicoper shaped cars running on a steel track, controlled by the pedalling of the riders +STR_0574 :Riders are held in special harnesses in a lying-down position, travlling through twisted track and inversions either on their backs or facing the ground STR_0575 :Powered trains hanging from a single rail transport people around the park STR_0576 : -STR_0577 : +STR_0577 :Bogied cars run on wooden tracks, turning around on special reversing sections STR_0578 :Cars run along track enclosed by circular hoops, traversing steep drops and heartline twists STR_0579 : -STR_0580 : -STR_0581 : +STR_0580 :A giant steel roller coaster capable of smooth drops and hills of over 300ft +STR_0581 :A ring of seats is pulled to the top of a tall tower while gently rotating, then allowed to free-fall down, stopping gently at the bottom using magnetic brakes STR_0582 : STR_0583 : -STR_0584 : -STR_0585 : +STR_0584 :Special bicycles run on a steel monorail track, propelled by the pedalling of the riders +STR_0585 :Riders sit in pairs of seats suspended beneath the track as they loop and twist through tight inversions STR_0586 :Boat shaped cars run on roller coaster track to allow twisting curves and steep drops, splashing down into sections of water for gentle river sections -STR_0587 : -STR_0588 : +STR_0587 :After an exhilarating air-powered launch, the train speeds up a vertical track, over the top, and vertically down the other side to return to the station +STR_0588 :Individual cars run beneath a zig-zagging track with hairpin turns and sharp drops STR_0589 : -STR_0590 : -STR_0591 : +STR_0590 :Riders ride in a submerged submarine through an underwater course +STR_0591 :Raft-shaped boats gently meander around a river track STR_0592 : STR_0593 : STR_0594 : STR_0595 : STR_0596 : STR_0597 : -STR_0598 : +STR_0598 :Inverted roller coaster trains are accelerated out of the station to travel up a vertical spike of track, then reverse back through the station to travel backwards up another vertical spike of track STR_0599 :A compact roller coaster with individual cars and smooth twisting drops -STR_0600 : +STR_0600 :Powered mine trains career along a smooth and twisted track layout STR_0601 : -STR_0602 : +STR_0602 :Roller coaster trains are accelerated out of the station by linear induction motors to speed through twisting inversions STR_0603 :{INT32}. vendég STR_0604 :{INT32}. vendég STR_0605 :{INT32}. vendég @@ -839,16 +839,17 @@ STR_0834 :{SMALLFONT}{BLACK}Disk and game options STR_0835 :Nem sikerült inicializálni a játékot STR_0836 :Unable to start game in a minimized state 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_0838 : STR_0839 :{UINT16} x {UINT16} STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} -STR_0841 :Ablakban -STR_0842 :Teljes képernyő, 640x480 -STR_0843 :Teljes képernyő, 800x600 -STR_0844 :Teljes képernyő, 1024x768 -STR_0845 :Teljes képernyő, 1152x864 -STR_0846 :Teljes képernyő, 1280x1024 -STR_0847 :About 'RollerCoaster Tycoon 2' +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +STR_0847 :About 'OpenRCT2' STR_0848 :RollerCoaster Tycoon 2 STR_0849 :{WINDOW_COLOUR_2}Version 2.01.028 STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, all rights reserved @@ -977,7 +978,7 @@ STR_0972 :Mégse 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 @@ -1044,10 +1045,10 @@ STR_1039 :Install new track design STR_1040 :Játék mentése STR_1041 :Save Scenario STR_1042 :Save Landscape -STR_1043 :RollerCoaster Tycoon 2 mentett játék -STR_1044 :RollerCoaster Tycoon 2 Scenario File -STR_1045 :RollerCoaster Tycoon 2 Landscape File -STR_1046 :RollerCoaster Tycoon 2 Track Design File +STR_1043 :OpenRCT2 mentett játék +STR_1044 :OpenRCT2 Scenario File +STR_1045 :OpenRCT2 Landscape File +STR_1046 :OpenRCT2 Track Design File STR_1047 :Játék mentése sikertelen! STR_1048 :Scenario save failed! STR_1049 :Landscape save failed! @@ -1103,13 +1104,13 @@ STR_1098 :Moving to end of {POP16}{STRINGID} STR_1099 :Waiting for passengers at {POP16}{STRINGID} STR_1100 :Waiting to depart {POP16}{STRINGID} STR_1101 :Departing {POP16}{STRINGID} -STR_1102 :Traveling at {VELOCITY} +STR_1102 :Travelling at {VELOCITY} STR_1103 :Arriving at {POP16}{STRINGID} STR_1104 :Unloading passengers at {POP16}{STRINGID} -STR_1105 :Traveling at {VELOCITY} +STR_1105 :Travelling at {VELOCITY} STR_1106 :Crashing! STR_1107 :Crashed! -STR_1108 :Traveling at {VELOCITY} +STR_1108 :Travelling at {VELOCITY} STR_1109 :Swinging STR_1110 :Rotating STR_1111 :Rotating @@ -1121,7 +1122,7 @@ STR_1116 :Operating STR_1117 :Doing circus show STR_1118 :Operating STR_1119 :Waiting for cable lift -STR_1120 :Traveling at {VELOCITY} +STR_1120 :Travelling at {VELOCITY} STR_1121 :Stopping STR_1122 :Waiting for passengers STR_1123 :Waiting to start @@ -1130,18 +1131,18 @@ STR_1125 :Operating STR_1126 :Stopping STR_1127 :Unloading passengers STR_1128 :Stopped by block brakes -STR_1129 :All vehicles in same colors -STR_1130 :Different colors per {STRINGID} -STR_1131 :Different colors per vehicle +STR_1129 :All vehicles in same colours +STR_1130 :Different colours per {STRINGID} +STR_1131 :Different colours per vehicle STR_1132 :Vehicle {POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} STR_1133 :Vehicle {POP16}{COMMA16} STR_1134 :{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} {COMMA16} STR_1135 :{STRINGID} {COMMA16} -STR_1136 :{SMALLFONT}{BLACK}Select main color -STR_1137 :{SMALLFONT}{BLACK}Select additional color 1 -STR_1138 :{SMALLFONT}{BLACK}Select additional color 2 -STR_1139 :{SMALLFONT}{BLACK}Select support structure color -STR_1140 :{SMALLFONT}{BLACK}Select vehicle color scheme option +STR_1136 :{SMALLFONT}{BLACK}Select main colour +STR_1137 :{SMALLFONT}{BLACK}Select additional colour 1 +STR_1138 :{SMALLFONT}{BLACK}Select additional colour 2 +STR_1139 :{SMALLFONT}{BLACK}Select support structure colour +STR_1140 :{SMALLFONT}{BLACK}Select vehicle colour scheme option STR_1141 :{SMALLFONT}{BLACK}Select which vehicle/train to modify STR_1142 :{MOVE_X}{SMALLFONT}{STRINGID} STR_1143 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRINGID} @@ -1216,8 +1217,8 @@ 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_1215 :{WINDOW_COLOUR_2}Synchonise with adjacent stations +STR_1216 :{SMALLFONT}{BLACK}Select whether to synchonise departure with all adjacent stations (for 'racing') STR_1217 :{COMMA16} seconds STR_1218 :{BLACK}{SMALLUP} STR_1219 :{BLACK}{SMALLDOWN} @@ -1397,7 +1398,7 @@ STR_1392 :{SMALLFONT}{BLACK}View of ride/attraction STR_1393 :{SMALLFONT}{BLACK}Vehicle details and options STR_1394 :{SMALLFONT}{BLACK}Operating options STR_1395 :{SMALLFONT}{BLACK}Maintenance options -STR_1396 :{SMALLFONT}{BLACK}Color scheme options +STR_1396 :{SMALLFONT}{BLACK}Colour scheme options STR_1397 :{SMALLFONT}{BLACK}Sound & music options STR_1398 :{SMALLFONT}{BLACK}Measurements and test data STR_1399 :{SMALLFONT}{BLACK}Graphs @@ -1526,9 +1527,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,9 +1539,9 @@ 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 donut 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} STR_1541 : STR_1542 :{SMALLFONT}{OPENQUOTES}This fried chicken from {STRINGID} is really good value{ENDQUOTES} @@ -1560,9 +1561,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,9 +1573,9 @@ 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 donut 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} STR_1575 : STR_1576 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fried chicken from {STRINGID}{ENDQUOTES} @@ -1754,7 +1755,7 @@ STR_1749 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{DUR STR_1750 :{DURATION} STR_1751 :Can't change time limit for ride... STR_1752 :{SMALLFONT}{BLACK}Show list of individual guests in park -STR_1753 :{SMALLFONT}{BLACK}Show summarized list of guests in park +STR_1753 :{SMALLFONT}{BLACK}Show summarised list of guests in park STR_1754 :{BLACK}{COMMA16} guests STR_1755 :{BLACK}{COMMA16} guest STR_1756 :{WINDOW_COLOUR_2}Admission price: @@ -1791,7 +1792,7 @@ STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} Űrhajóskosztüm STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} Banditakosztüm STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} Seriffkosztüm STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} Kalózkosztüm -STR_1790 :{SMALLFONT}{BLACK}Select uniform color for this type of staff +STR_1790 :{SMALLFONT}{BLACK}Select uniform colour for this type of staff STR_1791 :{WINDOW_COLOUR_2}Egyenruha színe: STR_1792 :Responding to {STRINGID} breakdown call STR_1793 :Heading to {STRINGID} for an inspection @@ -1820,7 +1821,7 @@ STR_1815 :Thoughts STR_1816 :{SMALLFONT}{BLACK}Select information type to show in guest list STR_1817 :({COMMA16}) STR_1818 :{WINDOW_COLOUR_2}All guests -STR_1819 :{WINDOW_COLOUR_2}All guests (summarized) +STR_1819 :{WINDOW_COLOUR_2}All guests (summarised) STR_1820 :{WINDOW_COLOUR_2}Guests {STRINGID} STR_1821 :{WINDOW_COLOUR_2}Guests thinking {STRINGID} STR_1822 :{WINDOW_COLOUR_2}Guests thinking about {POP16}{STRINGID} @@ -1835,16 +1836,16 @@ STR_1830 :Queue length STR_1831 :Queue time STR_1832 :Reliability STR_1833 :Down-time -STR_1834 :Guests favorite +STR_1834 :Guests favourite 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_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 STR_1845 :{MONTHYEAR} STR_1846 :{COMMA16} guests @@ -1874,8 +1875,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 @@ -1893,8 +1894,10 @@ STR_1888 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}more than 4 hou STR_1889 :{WINDOW_COLOUR_2}Down-Time: {MOVE_X}{255}{BLACK}{COMMA16}% STR_1890 :{SMALLFONT}{BLACK}Select how often a mechanic should check this ride STR_1891 :No {STRINGID} in park yet! -STR_1892 :RollerCoaster Tycoon 2 -STR_1893 :Please insert your RollerCoaster Tycoon 2 CD in the following drive: +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 : +STR_1893 : STR_1894 :{WINDOW_COLOUR_2}{STRINGID} sold: {BLACK}{COMMA32} STR_1895 :{SMALLFONT}{BLACK}Build new ride/attraction STR_1896 :{WINDOW_COLOUR_2}Expenditure/Income @@ -1930,7 +1933,7 @@ STR_1925 :Can't place person here... STR_1926 :{SMALLFONT} STR_1927 :{YELLOW}{STRINGID} has broken down STR_1928 :{RED}{STRINGID} has crashed! -STR_1929 :{RED}{STRINGID} still hasn't been fixed{NEWLINE}Check where your mechanics are and consider organizing them better +STR_1929 :{RED}{STRINGID} still hasn't been fixed{NEWLINE}Check where your mechanics are and consider organising them better STR_1930 :{SMALLFONT}{BLACK}Turn on/off tracking information for this guest - (If tracking is on, guest's movements will be reported in the message area) STR_1931 :{STRINGID} has joined the queue line for {STRINGID} STR_1932 :{STRINGID} is on {STRINGID} @@ -1968,9 +1971,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,9 +1983,9 @@ 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}Donut price: +STR_1981 :{WINDOW_COLOUR_2}Doughnut price: STR_1982 :{WINDOW_COLOUR_2}Coffee price: STR_1983 :{WINDOW_COLOUR_2} STR_1984 :{WINDOW_COLOUR_2}Fried Chicken price: @@ -1998,7 +2001,7 @@ STR_1993 :Innivaló STR_1994 :Hamburger STR_1995 :Sült krumpli STR_1996 :Jégkrém -STR_1997 :Cotton Candy +STR_1997 :Candyfloss STR_1998 :Üres doboz STR_1999 :Szemét STR_2000 :Üres hamburgerdoboz @@ -2008,9 +2011,9 @@ STR_2003 :Popcorn STR_2004 :Hotdog STR_2005 :Tentacle STR_2006 :Kalap -STR_2007 :Candy Apple +STR_2007 :Toffee Apple STR_2008 :Póló -STR_2009 :Donut +STR_2009 :Doughnut STR_2010 :Kávé STR_2011 :Üres pohár STR_2012 :Sült csirke @@ -2024,9 +2027,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,9 +2039,9 @@ 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 :Donuts +STR_2037 :Doughnuts STR_2038 :Coffees STR_2039 :Empty Cups STR_2040 :Fried Chicken @@ -2052,9 +2055,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,9 +2067,9 @@ 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 Donut +STR_2065 :a Doughnut STR_2066 :a Coffee STR_2067 :an Empty Cup STR_2068 :some Fried Chicken @@ -2080,9 +2083,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,9 +2095,9 @@ 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 :Donut +STR_2093 :Doughnut STR_2094 :Coffee STR_2095 :Empty Cup STR_2096 :Fried Chicken @@ -2218,7 +2221,7 @@ STR_2213 :{SMALLFONT}{BLACK}Show list of entertainers in park STR_2214 :Construction not possible while game is paused! STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C -STR_2217 :{WINDOW_COLOUR_2}{COMMA16}F +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F STR_2218 :{RED}{STRINGID} on {STRINGID} hasn't returned to the {STRINGID} yet!{NEWLINE}Check whether it is stuck or has stalled STR_2219 :{RED}{COMMA16} people have died in an accident on {STRINGID} STR_2220 :{WINDOW_COLOUR_2}Park Rating: {BLACK}{COMMA16} @@ -2318,10 +2321,10 @@ STR_2313 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}{COMMA2DP32} (approx.) STR_2314 :{WINDOW_COLOUR_2}Ride length: {BLACK}{STRINGID} STR_2315 :{WINDOW_COLOUR_2}Cost: {BLACK}around {CURRENCY} STR_2316 :{WINDOW_COLOUR_2}Space required: {BLACK}{COMMA16} x {COMMA16} blocks -STR_2317 :{WINDOW_COLOUR_2}Sound Quality: -STR_2318 :Low -STR_2319 :Medium -STR_2320 :High +STR_2317 : +STR_2318 : +STR_2319 : +STR_2320 : STR_2321 :{WINDOW_COLOUR_2}Number of rides/attractions: {BLACK}{COMMA16} STR_2322 :{WINDOW_COLOUR_2}Staff: {BLACK}{COMMA16} STR_2323 :{WINDOW_COLOUR_2}Park size: {BLACK}{COMMA32}m{SQUARED} @@ -2368,7 +2371,7 @@ STR_2363 :Gridlines on Landscape STR_2364 :{SMALLFONT}{BLACK}Toggle gridlines on landscape on/off STR_2365 :The bank refuses to increase your loan! STR_2366 :Celsius ({DEGREE}C) -STR_2367 :Fahrenheit (F) +STR_2367 :Fahrenheit ({DEGREE}F) STR_2368 :None STR_2369 :Low STR_2370 :Average @@ -2438,12 +2441,12 @@ STR_2433 :{BLACK}Vouchers for free {STRINGID} STR_2434 :{BLACK}Advertising campaign for {STRINGID} STR_2435 :{BLACK}Advertising campaign for {STRINGID} STR_2436 :1 hét -STR_2437 :2 hét -STR_2438 :3 hét -STR_2439 :4 hét -STR_2440 :5 hét -STR_2441 :6 hét -STR_2442 :{BLACK}({STRINGID} van hátra) +STR_2437 : +STR_2438 : +STR_2439 : +STR_2440 : +STR_2441 : +STR_2442 : STR_2443 :{WINDOW_COLOUR_2}Költség hetente: {BLACK}{CURRENCY2DP} STR_2444 :{WINDOW_COLOUR_2}Teljes költség: {BLACK}{CURRENCY2DP} STR_2445 :Reklámkampány indítása @@ -2500,7 +2503,7 @@ STR_2495 :Cancel construction mode STR_2496 :Játék megállítása STR_2497 :Zoom view out STR_2498 :Zoom view in -STR_2499 :Rotate view +STR_2499 :Rotate view clockwise STR_2500 :Rotate construction object STR_2501 :Underground view toggle STR_2502 :Remove base land toggle @@ -2682,10 +2685,10 @@ 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_2681 :{MEDIUMFONT}{BLACK}Increases your money by {CURRENCY} +STR_2682 : +STR_2683 : +STR_2684 :{SMALLFONT}{BLACK}Large group of peeps arrive STR_2685 :Simplex Noise Parameters STR_2686 :{WINDOW_COLOUR_2}Low: STR_2687 :{WINDOW_COLOUR_2}High: @@ -2702,12 +2705,12 @@ 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_2701 :Minden percben +STR_2702 :Minden 5 percben +STR_2703 :Minden 15 percben +STR_2704 :Minden 30 percben +STR_2705 :Minden órában +STR_2706 :Soha STR_2707 :Open new window STR_2708 :{WINDOW_COLOUR_1}Are you sure you want to overwrite {STRINGID}? STR_2709 :Overwrite @@ -2762,11 +2765,11 @@ 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 -STR_2762 :Pay For Rides +STR_2760 :+{CURRENCY} +STR_2761 : +STR_2762 : STR_2763 :??? -STR_2764 :Happy Guests +STR_2764 : STR_2765 :Large Tram STR_2766 :Win scenario STR_2767 :Freeze Climate @@ -2784,7 +2787,7 @@ STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} # End of new strings STR_2779 :Viewport #{COMMA16} STR_2780 :Extra viewport -STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} STR_2782 :SHIFT + STR_2783 :CTRL + STR_2784 :Change keyboard shortcut @@ -2809,12 +2812,12 @@ STR_2802 :Map 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 -STR_2806 :{RED}Guests are complaining about the disgusting state of the paths in your park{NEWLINE}Check where your handymen are and consider organizing them better -STR_2807 :{RED}Guests are complaining about the amount of litter in your park{NEWLINE}Check where your handymen are and consider organizing them better -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_2806 :{RED}Guests are complaining about the disgusting state of the paths in your park{NEWLINE}Check where your handymen are and consider organising them better +STR_2807 :{RED}Guests are complaining about the amount of litter in your park{NEWLINE}Check where your handymen are and consider organising them better +STR_2808 :{RED}Guests are complaining about the vandalism in your park{NEWLINE}Check where your security guards are and consider organising 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 @@ -2827,11 +2830,11 @@ 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 -STR_2828 :{WINDOW_COLOUR_2}Most dazzling ride color schemes award +STR_2828 :{WINDOW_COLOUR_2}Most dazzling ride colour schemes award STR_2829 :{WINDOW_COLOUR_2}Most confusing park layout award STR_2830 :{WINDOW_COLOUR_2}Best gentle ride award STR_2831 :{TOPAZ}Your park has received an award for being 'The most untidy park in the country'! @@ -2844,11 +2847,11 @@ 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'! -STR_2845 :{TOPAZ}Your park has received an award for being 'The park with the most dazzling choice of color schemes'! +STR_2845 :{TOPAZ}Your park has received an award for being 'The park with the most dazzling choice of colour schemes'! STR_2846 :{TOPAZ}Your park has received an award for being 'The park with the most confusing layout'! STR_2847 :{TOPAZ}Your park has received an award for being 'The park with the best gentle rides'! STR_2848 :{WINDOW_COLOUR_2}No recent awards @@ -2862,7 +2865,7 @@ STR_2855 :{RED}{STRINGID} has no path leading from its exit !{NEWLINE}Constru STR_2856 :{WINDOW_COLOUR_2}Tutorial STR_2857 :{WINDOW_COLOUR_2}(Press a key or mouse button to take control) STR_2858 :Can't start marketing campaign... -STR_2859 :Another instance of RollerCoaster Tycoon 2 is already running +STR_2859 :Another instance of OpenRCT2 is already running STR_2860 :Infogrames Interactive credits... STR_2861 :{WINDOW_COLOUR_2}Licensed to Infogrames Interactive Inc. STR_2862 :Music acknowledgements... @@ -2972,14 +2975,14 @@ STR_2965 :{WINDOW_COLOUR_2} STR_2966 : STR_2967 : STR_2968 : -STR_2969 :Use of this product is subject to the terms of a license agreement -STR_2970 :found in the product's {OPENQUOTES}ReadMe{ENDQUOTES} file and in the manual -STR_2971 :Main color scheme -STR_2972 :Alternative color scheme 1 -STR_2973 :Alternative color scheme 2 -STR_2974 :Alternative color scheme 3 -STR_2975 :{SMALLFONT}{BLACK}Select which color scheme to change, or paint ride with -STR_2976 :{SMALLFONT}{BLACK}Paint an individual area of this ride using the selected color scheme +STR_2969 : +STR_2970 : +STR_2971 :Main colour scheme +STR_2972 :Alternative colour scheme 1 +STR_2973 :Alternative colour scheme 2 +STR_2974 :Alternative colour scheme 3 +STR_2975 :{SMALLFONT}{BLACK}Select which colour scheme to change, or paint ride with +STR_2976 :{SMALLFONT}{BLACK}Paint an individual area of this ride using the selected colour scheme STR_2977 :Staff member name STR_2978 :Enter new name for this member of staff: STR_2979 :Can't name staff member... @@ -2992,8 +2995,8 @@ STR_2985 :Banner STR_2986 :{SMALLFONT}{BLACK}Change text on banner STR_2987 :{SMALLFONT}{BLACK}Set this banner as a 'no-entry' sign for guests STR_2988 :{SMALLFONT}{BLACK}Demolish this banner -STR_2989 :{SMALLFONT}{BLACK}Select main color -STR_2990 :{SMALLFONT}{BLACK}Select text color +STR_2989 :{SMALLFONT}{BLACK}Select main colour +STR_2990 :{SMALLFONT}{BLACK}Select text colour STR_2991 :Sign STR_2992 :Sign text STR_2993 :Enter new text for this sign: @@ -3084,7 +3087,7 @@ STR_3077 :{RED}CLOSURE NOTICE: Your park has been closed down ! STR_3078 :Plain entrance STR_3079 :Wooden entrance STR_3080 :Canvas tent entrance -STR_3081 :Castle entrance (gray) +STR_3081 :Castle entrance (grey) STR_3082 :Castle entrance (brown) STR_3083 :Jungle entrance STR_3084 :Log cabin entrance @@ -3096,16 +3099,16 @@ STR_3089 :Space entrance STR_3090 :{SMALLFONT}{BLACK}Select style of entrance, exit, and station STR_3091 :You are not allowed to remove this section! STR_3092 :You are not allowed to move or modify the station for this ride! -STR_3093 :{WINDOW_COLOUR_2}Favorite: {BLACK}{STRINGID} +STR_3093 :{WINDOW_COLOUR_2}Favourite: {BLACK}{STRINGID} STR_3094 :N/A STR_3095 :{WINDOW_COLOUR_2}Lift hill chain speed: STR_3096 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} STR_3097 :{SMALLFONT}{BLACK}Select lift hill chain speed STR_3098 :Can't change lift hill speed... -STR_3099 :{SMALLFONT}{BLACK}Select color -STR_3100 :{SMALLFONT}{BLACK}Select second color -STR_3101 :{SMALLFONT}{BLACK}Select third color -STR_3102 :{SMALLFONT}{BLACK}Re-paint colored scenery on landscape +STR_3099 :{SMALLFONT}{BLACK}Select colour +STR_3100 :{SMALLFONT}{BLACK}Select second colour +STR_3101 :{SMALLFONT}{BLACK}Select third colour +STR_3102 :{SMALLFONT}{BLACK}Re-paint coloured scenery on landscape STR_3103 :Can't re-paint this... STR_3104 :{SMALLFONT}{BLACK}List rides STR_3105 :{SMALLFONT}{BLACK}List shops and stalls @@ -3125,8 +3128,8 @@ STR_3118 :{BLACK}{STRINGID} is heading for the ride STR_3119 :{BLACK}{STRINGID} is fixing the ride STR_3120 :{SMALLFONT}{BLACK}Locate nearest available mechanic, or mechanic fixing ride STR_3121 :Unable to locate mechanic, or all nearby mechanics are busy -STR_3122 :{WINDOW_COLOUR_2}Favorite ride of: {BLACK}{COMMA16} guest -STR_3123 :{WINDOW_COLOUR_2}Favorite ride of: {BLACK}{COMMA16} guests +STR_3122 :{WINDOW_COLOUR_2}Favourite ride of: {BLACK}{COMMA16} guest +STR_3123 :{WINDOW_COLOUR_2}Favourite ride of: {BLACK}{COMMA16} guests STR_3124 :Broken {STRINGID} STR_3125 :{WINDOW_COLOUR_2}Excitement Factor: {BLACK}+{COMMA16}% STR_3126 :{WINDOW_COLOUR_2}Intensity Factor: {BLACK}+{COMMA16}% @@ -3163,8 +3166,8 @@ STR_3156 : STR_3157 :map STR_3158 :graph STR_3159 :list -STR_3160 :RollerCoaster Tycoon 2: Starting for the first time... -STR_3161 :RollerCoaster Tycoon 2: Checking object files... +STR_3160 : +STR_3161 : STR_3162 :Unable to allocate enough memory STR_3163 :Installing new data: STR_3164 :{BLACK}{COMMA16} selected (maximum {COMMA16}) @@ -3175,7 +3178,7 @@ STR_3168 :{WINDOW_COLOUR_2}Text: {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 -STR_3172 :The following object must be selected first: +STR_3172 :The following object must be selected first: {STRING} STR_3173 :This object is currently in use STR_3174 :This object is required by another object STR_3175 :This object is always required @@ -3340,7 +3343,7 @@ 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_3337 : 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 @@ -3365,8 +3368,8 @@ 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_3362 : +STR_3363 : STR_3364 :Advanced STR_3365 :{SMALLFONT}{BLACK}Allow selection of individual items of scenery in addition to scenery groups STR_3366 :{BLACK}= Ride @@ -3375,8 +3378,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... @@ -3394,6 +3397,7 @@ STR_3387 :Roller Coaster Building Tutorial STR_3388 :Unable to switch to selected mode STR_3389 :Unable to select additional item of scenery... STR_3390 :Too many items selected +# Start of tutorial strings. Not used at the moment, so not necessary to translate. STR_3391 :{SMALLFONT}{BLACK}Here is our park - Let's have a quick look around... STR_3392 :{SMALLFONT}{BLACK}Holding down the RIGHT mouse button and moving the mouse is the quickest way to move the view... STR_3393 :{SMALLFONT}{BLACK}To view more of the park, you can zoom the view out using the icon at the top of the screen... @@ -3439,7 +3443,8 @@ STR_3432 :{SMALLFONT}{BLACK}We need to slow the train before the final curve 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_3436 :{SMALLFONT}{BLACK}While waiting for our first riders, we could customise the ride a bit... +# End of tutorial strings STR_3437 :{SMALLFONT}{BLACK}Clear large areas of scenery from landscape STR_3438 :Unable to remove all scenery from here... STR_3439 :Clear Scenery @@ -3450,164 +3455,10 @@ 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 + +# Note: as this is an unmaintained language, don't add new strings unless you intend to become the mainainer. diff --git a/data/language/italian.txt b/data/language/italian.txt index f35da40480..eb538b1c6b 100644 --- a/data/language/italian.txt +++ b/data/language/italian.txt @@ -3,97 +3,97 @@ # Use # at the beginning of a line to leave a comment. STR_0000 : STR_0001 :{STRINGID} {COMMA16} -STR_0002 :Attrazione -STR_0003 :Attrazione +STR_0002 :Spiral Roller Coaster +STR_0003 :Stand-up Roller Coaster STR_0004 :Attrazione oscillante -STR_0005 :Attrazione +STR_0005 :Inverted Roller Coaster 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_0010 :Boat Ride +STR_0011 :Wooden Wild Mouse +STR_0012 :Steeplechase STR_0013 :Attrazione su carrozza -STR_0014 :Attrazione -STR_0015 :Attrazione -STR_0016 :Attrazione +STR_0014 :Launched Freefall +STR_0015 :Bobsleigh Coaster +STR_0016 :Observation Tower STR_0017 :Ottovolante con giro d. morte -STR_0018 :Attrazione -STR_0019 :Attrazione +STR_0018 :Dinghy Slide +STR_0019 :Mine Train Coaster 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_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 :Chiosco -STR_0035 :Attrazione -STR_0036 :Chiosco +STR_0035 :Merry-Go-Round +STR_0036 :Unknown Stall (22) STR_0037 :Chiosco STR_0038 :Servizi igienici -STR_0039 :Attrazione -STR_0040 :Attrazione -STR_0041 :Attrazione -STR_0042 :Attrazione -STR_0043 :Attrazione +STR_0039 :Ferris Wheel +STR_0040 :Motion Simulator +STR_0041 :3D Cinema +STR_0042 :Top Spin +STR_0043 :Space Rings 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_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 :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_0058 :Unknown Ride (38) STR_0059 :Ottovolante aereo invertito -STR_0060 :Attrazione -STR_0061 :Attrazione -STR_0062 :Attrazione -STR_0063 :Attrazione -STR_0064 :Attrazione +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 :Monorotaia sospesa -STR_0066 :Attrazione -STR_0067 :Attrazione +STR_0066 :Unknown Ride (40) +STR_0067 :Reverser Roller Coaster 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_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 :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_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-ottovolante -STR_0090 :Attrazione -STR_0091 :Attrazione -STR_0092 :Attrazione +STR_0090 :Mine Ride +STR_0091 :Unknown Ride (59) +STR_0092 :LIM Launched Roller Coaster STR_0093 : STR_0094 : STR_0095 : @@ -513,31 +513,31 @@ STR_0508 : STR_0509 : STR_0510 : STR_0511 : -STR_0512 : -STR_0513 : +STR_0512 :A compact roller coaster with a spiral lift hill and smooth, twisting drops. +STR_0513 :A looping roller coaster where the riders ride in a standing position STR_0514 :I treni, sospesi sotto l'ottovolante, durante le curve oscillano lateralmente -STR_0515 : +STR_0515 :A steel roller coaster with trains that are held beneath the track, with many complex and twisting track elements 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_0520 :A dock platform where guests can drive/row personal watercraft on a body of water +STR_0521 :A fast and twisting roller coaster with tight turns and steep drops. Intensity is bound to be high. +STR_0522 :A smaller roller coaster where the riders sit above the track with no car around them STR_0523 :I passeggeri viaggiano lentamente su veicoli elettrici lungo un percorso basato su un circuito -STR_0524 : -STR_0525 : -STR_0526 : +STR_0524 :Freefall car is pneumatically launched up a tall steel tower and then allowed to freefall down +STR_0525 :Riders career down a twisting track guided only by the curvature and banking of the semi-circular track +STR_0526 :Passengers travel in a rotating observation cabin which travels up a tall tower STR_0527 :Un rapido ottovolante d'acciaio caratterizzato da cadute verticali -STR_0528 : -STR_0529 : +STR_0528 :Riders travel in inflatable dinghies down a twisting semi-circular or completely enclosed tube track +STR_0529 :Mine train themed roller coaster trains career along steel roller coaster track made to look like old railway track STR_0530 :Le carrozze pendono da un cavo d'acciaio che fa avanti e indietro per tutto il tracciato -STR_0531 : +STR_0531 :A compact steel-tracked roller coaster where the train travels through corkscrews and loops STR_0532 : STR_0533 : -STR_0534 : -STR_0535 : -STR_0536 : +STR_0534 :Self-drive petrol-engined go karts +STR_0535 :Log-shaped boats travel along a water channel, splashing down steep slopes to soak the riders +STR_0536 :Circular boats meander along a wide water channel, splashing through waterfalls and thrilling riders through foaming rapids STR_0537 : STR_0538 : STR_0539 : @@ -556,14 +556,14 @@ 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_0555 :Guests ride in an elevator up or down a vertical tower to get from one level to another +STR_0556 :Extra-wide cars descend completely vertical sloped track for the ultimate freefall roller coaster experience STR_0557 : STR_0558 : STR_0559 : STR_0560 : STR_0561 : -STR_0562 : +STR_0562 :Powered cars travel along a multi-level track past spooky scenery and special effects 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à @@ -572,38 +572,38 @@ STR_0567 :Seduti su sedili sospesi a entrambi i lati del tracciato, i passegg 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_0571 :Circular cars spin around as they travel along the zig-zagging wooden track +STR_0572 :Large capacity boats travel along a wide water channel, propelled up slopes by a conveyer belt, accelerating down steep slopes to soak the riders with a gaint splash +STR_0573 :Powered helicoper shaped cars running on a steel track, controlled by the pedalling of the riders +STR_0574 :Riders are held in special harnesses in a lying-down position, travlling through twisted track and inversions either on their backs or facing the ground STR_0575 :Dei treni elettrici sospesi sotto una singola rotaia trasportano i passeggeri per tutto il parco STR_0576 : -STR_0577 : +STR_0577 :Bogied cars run on wooden tracks, turning around on special reversing sections STR_0578 :Le carrozze corrono per il tracciato caratterizzato da vari giri, ripide discese e curve ondulanti STR_0579 : -STR_0580 : -STR_0581 : +STR_0580 :A giant steel roller coaster capable of smooth drops and hills of over 300ft +STR_0581 :A ring of seats is pulled to the top of a tall tower while gently rotating, then allowed to free-fall down, stopping gently at the bottom using magnetic brakes STR_0582 : STR_0583 : -STR_0584 : -STR_0585 : +STR_0584 :Special bicycles run on a steel monorail track, propelled by the pedalling of the riders +STR_0585 :Riders sit in pairs of seats suspended beneath the track as they loop and twist through tight inversions 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_0587 :After an exhilarating air-powered launch, the train speeds up a vertical track, over the top, and vertically down the other side to return to the station +STR_0588 :Individual cars run beneath a zig-zagging track with hairpin turns and sharp drops STR_0589 : -STR_0590 : -STR_0591 : +STR_0590 :Riders ride in a submerged submarine through an underwater course +STR_0591 :Raft-shaped boats gently meander around a river track STR_0592 : STR_0593 : STR_0594 : STR_0595 : STR_0596 : STR_0597 : -STR_0598 : +STR_0598 :Inverted roller coaster trains are accelerated out of the station to travel up a vertical spike of track, then reverse back through the station to travel backwards up another vertical spike of track STR_0599 :Un ottovolante compatto con carrozze individuali e rapide curve in discesa -STR_0600 : +STR_0600 :Powered mine trains career along a smooth and twisted track layout STR_0601 : -STR_0602 : +STR_0602 :Roller coaster trains are accelerated out of the station by linear induction motors to speed through twisting inversions STR_0603 :Visitatore {INT32} STR_0604 :Visitatore {INT32} STR_0605 :Visitatore {INT32} @@ -839,16 +839,17 @@ 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_0838 : 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' +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +STR_0847 :Informazioni su 'OpenRCT2' 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 @@ -1044,10 +1045,10 @@ 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_1043 :Partita di OpenRCT2 salvata +STR_1044 :File di scenario per OpenRCT2 +STR_1045 :File di paesaggi per OpenRCT2 +STR_1046 :File di design dei tracciati per OpenRCT2 STR_1047 :Salvataggio partita fallito! STR_1048 :Salvataggio scenario fallito! STR_1049 :Salvataggio terreno fallito! @@ -1059,13 +1060,13 @@ 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_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_1064 :Lancio a motore (passing station) STR_1065 :Modalità navetta STR_1066 :Modalità affitto barche STR_1067 :Lancio in salita @@ -1097,7 +1098,7 @@ 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_1096 :Lancio a motore (without passing station) 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} @@ -1451,10 +1452,10 @@ 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_1450 :{INLINE_SPRITE}{09}{20}{00}{00}{SPRITE} {STRINGID}{NEWLINE}({STRINGID}) STR_1451 :{STRINGID}{NEWLINE}({STRINGID}) STR_1452 :Nome del visitatore -STR_1453 :Digita il nome di questo 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} @@ -1713,14 +1714,14 @@ STR_1708 :{SMALLFONT}{BLACK}Fissa la zona che questo dipendente deve controll 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_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 +STR_1714 :{INLINE_SPRITE}{249}{19}{00}{00}{WINDOW_COLOUR_2}Empty litter bins +STR_1715 :{INLINE_SPRITE}{250}{19}{00}{00}{WINDOW_COLOUR_2}Mow grass 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_1719 :Digita il nome del parco: STR_1720 :{SMALLFONT}{BLACK}Battezza il parco STR_1721 :Parco chiuso STR_1722 :Parco aperto @@ -1758,7 +1759,7 @@ 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_1757 :{WINDOW_COLOUR_2}Affidabilità: {MOVE_X}{255}{BLACK}{COMMA16}% STR_1758 :{SMALLFONT}{BLACK}Modalità costruzione STR_1759 :{SMALLFONT}{BLACK}Modalità spostamento STR_1760 :{SMALLFONT}{BLACK}Modalità riempimento @@ -1780,17 +1781,17 @@ 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_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Panda costume +STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tiger costume +STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} Elephant costume +STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} Roman costume +STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} Gorilla costume +STR_1784 :{INLINE_SPRITE}{03}{20}{00}{00} Snowman costume +STR_1785 :{INLINE_SPRITE}{04}{20}{00}{00} Knight costume +STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} Astronaut costume +STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} Bandit costume +STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} Sheriff costume +STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} Pirate costume 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} @@ -1848,8 +1849,8 @@ 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_1847 :{INLINE_SPRITE}{11}{20}{00}{00}{COMMA16} guests +STR_1848 :{INLINE_SPRITE}{10}{20}{00}{00}{COMMA16} guests 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 @@ -1877,8 +1878,8 @@ 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_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 STR_1878 :{WINDOW_COLOUR_2}Ispezione: STR_1879 :Ogni 10 minuti STR_1880 :Ogni 20 minuti @@ -1890,11 +1891,13 @@ 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_1889 :{WINDOW_COLOUR_2}Tempi morti: {MOVE_X}{255}{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à:- +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 : +STR_1893 : 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 @@ -2218,7 +2221,7 @@ 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_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}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} @@ -2318,10 +2321,10 @@ 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_2317 : +STR_2318 : +STR_2319 : +STR_2320 : 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} @@ -2368,7 +2371,7 @@ 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_2367 :Fahrenheit ({DEGREE}F) STR_2368 :Nessuno STR_2369 :Basso STR_2370 :Medio @@ -2438,12 +2441,12 @@ 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_2437 : +STR_2438 : +STR_2439 : +STR_2440 : +STR_2441 : +STR_2442 : 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 @@ -2682,10 +2685,10 @@ 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_2681 :{MEDIUMFONT}{BLACK}Increases your money by {CURRENCY} +STR_2682 : +STR_2683 : +STR_2684 :{SMALLFONT}{BLACK}Large group of peeps arrive STR_2685 :Simplex Noise Parameters STR_2686 :{WINDOW_COLOUR_2}Low: STR_2687 :{WINDOW_COLOUR_2}High: @@ -2702,12 +2705,12 @@ 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_2701 :Ogni minuto +STR_2702 :Ogni 5 minuti +STR_2703 :Ogni 15 minuti +STR_2704 :Ogni 30 minuti +STR_2705 :Ogni ora +STR_2706 :Mai STR_2707 :Open new window STR_2708 :{WINDOW_COLOUR_1}Are you sure you want to overwrite {STRINGID}? STR_2709 :Overwrite @@ -2748,7 +2751,7 @@ STR_2743 :Copy data\css17.dat from your RCT1 installation to data\css50.dat i STR_2744 :[ STR_2745 :\ STR_2746 :] -STR_2747 :# +STR_2747 :{ENDQUOTES} STR_2748 :Barra STR_2749 :My new scenario # New strings used in the cheats window previously these were ??? @@ -2762,11 +2765,11 @@ 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_2760 :+{CURRENCY} +STR_2761 : +STR_2762 : STR_2763 :??? -STR_2764 :Happy Guests +STR_2764 : STR_2765 :Large Tram STR_2766 :Win scenario STR_2767 :Freeze Climate @@ -2783,7 +2786,7 @@ 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_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} STR_2782 :SHIFT + STR_2783 :CTRL + STR_2784 :Modifica la scorciatoia @@ -2794,7 +2797,7 @@ STR_2788 :{WINDOW_COLOUR_2}Congratulazioni!!{NEWLINE}{BLACK}Hai raggiunto il 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_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 @@ -2861,7 +2864,7 @@ STR_2855 :{RED}{STRINGID} non è dotato di un percorso alla sua uscita!!{NEWL 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_2859 :Al momento è in corso un'altra sezione di OpenRCT2 STR_2860 :Riconoscimenti Infogrames... STR_2861 :{WINDOW_COLOUR_2}Concesso in licenza a Infogrames Interactive STR_2862 :Riconoscimenti dei brani musicali... @@ -2971,8 +2974,8 @@ 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_2969 : +STR_2970 : STR_2971 :Modello decorativo principale STR_2972 :Modello decorativo alternativo 1 STR_2973 :Modello decorativo alternativo 2 @@ -2980,12 +2983,12 @@ 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_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_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 @@ -2995,7 +2998,7 @@ 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_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 @@ -3162,8 +3165,8 @@ 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_3160 : +STR_3161 : STR_3162 :Impossibile assegnare abbastanza memoria STR_3163 :Installazione dei nuovi dati: STR_3164 :{BLACK}{COMMA16} selezionati (massimo {COMMA16}) @@ -3316,9 +3319,9 @@ 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_3314 :Digita il nome dello scenario: STR_3315 :Informazioni sul parco/scenario -STR_3316 :Scrivi una descrizione dello 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: @@ -3339,7 +3342,7 @@ 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_3337 : STR_3338 :{BLACK}Disposizione personalizzata STR_3339 :{BLACK}{COMMA16} progetto disponibile o progetto personalizzato STR_3340 :{BLACK}{COMMA16} progetti disponibili o disposizioni personalizzate @@ -3353,7 +3356,7 @@ STR_3347 :L{GREEN}attrazione è troppo grande, contiene troppi elementi o lo STR_3348 :Ribattezza STR_3349 :Cancella STR_3350 :Battezza il progetto di tracciato -STR_3351 :Digita il nome di questo 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 @@ -3364,8 +3367,8 @@ 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_3362 : +STR_3363 : 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 @@ -3393,6 +3396,7 @@ 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 +# Start of tutorial strings. Not used at the moment, so not necessary to translate. 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... @@ -3439,6 +3443,7 @@ STR_3433 :{SMALLFONT}{BLACK}E infine aggiungeremo i 'freni di blocco', che pe 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... +# End of tutorial strings 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. @@ -3450,164 +3455,9 @@ 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 + +# Note: as this is an unmaintained language, don't add new strings unless you intend to become the mainainer. diff --git a/data/language/korean.txt b/data/language/korean.txt new file mode 100644 index 0000000000..33e23a30ee --- /dev/null +++ b/data/language/korean.txt @@ -0,0 +1,3928 @@ +# 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 :스파이럴 롤러코스터 +STR_0003 :스탠드업 롤러코스터 +STR_0004 :서스펜디드 스윙잉 코스터 +STR_0005 :인버티드 롤러코스터 +STR_0006 :주니어 롤러코스터 +STR_0007 :미니어처 레일웨이 +STR_0008 :모노레일 +STR_0009 :미니 서스펜디드 롤러코스터 +STR_0010 :보트 라이드 +STR_0011 :우든 와일드 마우스 +STR_0012 :스티플체이스 +STR_0013 :카 라이드 +STR_0014 :런치드 프리폴 +STR_0015 :봅슬레이 코스터 +STR_0016 :전망탑 +STR_0017 :루핑 롤러코스터 +STR_0018 :디니 슬라이드 +STR_0019 :마인 트레인 코스터 +STR_0020 :체어리프트 +STR_0021 :코르크스크류 롤러코스터 +STR_0022 :미로 +STR_0023 :나선 미끄럼틀 +STR_0024 :고 카트 +STR_0025 :통나무 수로 +STR_0026 :리버 래피드 +STR_0027 :범퍼카 +STR_0028 :바이킹 +STR_0029 :360도 바이킹 +STR_0030 :음식 상점 +STR_0031 :알 수 없는 상점 (1D) +STR_0032 :음료수 상점 +STR_0033 :알 수 없는 상점 (1F) +STR_0034 :상점 +STR_0035 :회전목마 +STR_0036 :알 수 없는 상점 (22) +STR_0037 :안내소 +STR_0038 :화장실 +STR_0039 :관람차 +STR_0040 :모션 시뮬레이터 +STR_0041 :3D 영화관 +STR_0042 :톱 스핀 +STR_0043 :스페이스 링 +STR_0044 :리버스 프리폴 코스터 +STR_0045 :리프트 +STR_0046 :버티컬 드롭 롤러코스터 +STR_0047 :현금 지급기 +STR_0048 :트위스트 +STR_0049 :귀신의 집 +STR_0050 :응급 치료소 +STR_0051 :서커스 쇼 +STR_0052 :고스트 트레인 +STR_0053 :스틸 트위스터 롤러코스터 +STR_0054 :우든 롤러코스터 +STR_0055 :사이드 프릭션 롤러코스터 +STR_0056 :와일드 마우스 +STR_0057 :멀티 디멘션 롤러코스터 +STR_0058 :알 수 없는 놀이기구 (38) +STR_0059 :플라잉 롤러코스터 +STR_0060 :알 수 없는 놀이기구 (3A) +STR_0061 :버지니아 릴 +STR_0062 :스플래시 보트 +STR_0063 :미니 헬리콥터 +STR_0064 :레이 다운 롤러코스터 +STR_0065 :서스펜디드 모노레일 +STR_0066 :알 수 없는 놀이기구 (40) +STR_0067 :리버서 롤러코스터 +STR_0068 :하트라인 트위스터 코스터 +STR_0069 :미니 골프 +STR_0070 :기가 코스터 +STR_0071 :자이로드롭 +STR_0072 :플라잉 사우서 +STR_0073 :이상한 집 +STR_0074 :모노레일 사이클 +STR_0075 :컴팩트 인버티드 코스터 +STR_0076 :워터 코스터 +STR_0077 :에어 파워드 버티컬 코스터 +STR_0078 :인버티드 헤어핀 코스터 +STR_0079 :마술 양탄자 +STR_0080 :서브마린 라이드 +STR_0081 :리버 래프트 +STR_0082 :알 수 없는 놀이기구 (50) +STR_0083 :엔터프라이즈 +STR_0084 :알 수 없는 놀이기구 (52) +STR_0085 :알 수 없는 놀이기구 (53) +STR_0086 :알 수 없는 놀이기구 (54) +STR_0087 :알 수 없는 놀이기구 (55) +STR_0088 :인버티트 임펄스 코스터 +STR_0089 :미니 롤러코스터 +STR_0090 :마인 라이드 +STR_0091 :알 수 없는 놀이기구 (59) +STR_0092 :LIM 런치드 롤러코스터 +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 :코너를 돌 때 롤러코스터 트랙 아래에 달린 차량이 흔들리는 열차입니다 +STR_0515 :복잡하고 꼬인 트랙 요소를 가진 트랙 아래를 달리는 스틸 롤러코스터 차량입니다 +STR_0516 :큰 놀이기구를 탈 용기가 없는 사람들을 위한 얌전한 롤러코스터입니다 +STR_0517 :손님들은 협궤 선로를 따라 달리는 미니어처 열차에 탑승합니다 +STR_0518 :손님들은 모노렝리 트랙을 따라 달리는 전기 차량에 탑승합니다 +STR_0519 :손님들은 코너를 돌 때마다 좌우로 흔들리는, 단선 트랙 아래에 달린 작은 차량에 탑승합니다 +STR_0520 :손님들이 물 위를 다니는 배를 운전하거나 또는 저을 수 있는 선착장입니다 +STR_0521 :급커브와 급하강을 가진 빠르게 꼬인 롤러코스터입니다. 격렬도가 높게 나올 것입니다 +STR_0522 :탑승객이 차량 없이 트랙 위에 앉는 작은 롤러코스터입니다 +STR_0523 :정해진 트랙을 따라 천천히 움직이는 차량입니다 +STR_0524 :자유낙하 차량은 공기 압축 방식으로 높은 철제 탑을 향해 차량을 쏘아올려 자유낙하하는 차량입니다 +STR_0525 :탑승객은 오직 반원형으로 휘어있고 꼬여있는 트랙을 따라 이동합니다 +STR_0526 :탑승객은 높은 곳으로 올라가면서 회전하는 관망대 캐빈에 탑승합니다 +STR_0527 :버티컬 루프를 사용할 수 있는 부드러운 철제 트랙의 롤러코스터입니다 +STR_0528 :탑승객은 공기를 넣은 고무 보트를 타고 반원이나 원형의 튜브 트랙을 따라 이동합니다 +STR_0529 :오래된 기차 선로처럼 보이게 만든 철제 트랙을 따라 움직이는 탄광 열차 테마를 한 롤러코스터 차량입니다. +STR_0530 :철제 케이블에 달린 차량이 연속적으로 놀이기구의 한쪽 끝에서 다른쪽 끝을 왕복 운행합니다 +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 :차량이 선형 유도 모터에 의해 긴 평지 트랙을 따라 가속된 뒤, 수직 상승 트랙에 의해 위로 상승한 뒤 다시 뒤로 자유낙하여 탑승장에 돌아옵니다 +STR_0555 :손님은 엘리베이터에 탑승하여 한쪽에서 다른쪽으로 이동할 수 있습니다 +STR_0556 :폭이 넓은 차량이 수직으로 기울어진 트랙을 따라 내려오면서 극강의 자유 낙하 롤러코스터를 경험하게 해줍니다 +STR_0557 : +STR_0558 : +STR_0559 : +STR_0560 : +STR_0561 : +STR_0562 :무서운 풍경과 특수 효과를 통과하며 여러 높이의 트랙을 따라 이동하는 전동 차량입니다 +STR_0563 :탑승객들은 한 바퀴를 운행하는 편안한 좌석에 앉아 언덕을 오르면서 느낄 수 있는 '무중력 시간'뿐만이 아니라 크고 부드러운 낙하와 꼬인 트랙의 느낌을 즐길 수 있습니다 +STR_0564 :목재 트랙 위를 움직이는 이 롤러코스터는 빠르고, 거칠고, 시끄럽고, 많은 '무중력 시간'과 함께 '제어 불가능할 것 같은' 탑승감을 선사합니다 +STR_0565 :완만한 경사와 커브만을 가진 간단한 목재 롤러코스터로, 이 롤러코스터의 차량은 오직 측면 마찰륜과 중력만으로 트랙 위에 얹혀진 상태로 운행합니다 +STR_0566 :개별적인 롤러코스터 차량이 급커브와 짧고 급한 경사를 가진 지그재그 모양의 트랙을 어지럽게 돌아다닙니다 +STR_0567 :트랙 반대편에 매달린 좌석에 앉아서, 탑승객들은 급강하와 여러 가지 반전 트랙을 통과하면서 거꾸러지는 동안 머리와 다리가 뒤집히게 됩니다 +STR_0568 : +STR_0569 :차량 밑에 달린 특별한 마차에 탑승하여, 탑승객들은 공중으로 급강하면서 하늘을 나는 기분을 느끼게 만듭니다 +STR_0570 : +STR_0571 :원형의 차량이 나무 트랙을 지그재그로 이동하면서 회전합니다 +STR_0572 :대형 보트가 넓은 수로를 따라 컨베이어 벨트에 의해 언덕을 올라간 뒤, 급강하하면서 큰 물보라를 일으켜 탑승객을 젖게 만듭니다 +STR_0573 :탑승객이 직접 페달을 밟아 이동하는, 철제 트랙을 달리는 헬리콥터 모양의 전동 차량입니다 +STR_0574 :탑승객은 특수한 마차에 누운 자세로 매달려, 이리 저리 꼬이고 뒤집히는 트랙을 땅을 등지거나 마주보는 자세로 탑승하게 됩니다 +STR_0575 :공원 여기 저기로 사람들을 실어나르는, 단선 레일에 매달린 전동 열차입니다 +STR_0576 : +STR_0577 :특수한 반전 섹션에서 앞뒤가 바뀌는 목재 트랙을 달리는 보우기 차입니다 +STR_0578 :원형 고리로 둘러싸여 급강하와 하트라인 트위트스를 횡단하는 트랙을 달리는 차량입니다. +STR_0579 : +STR_0580 :90m 이상의 언덕을 부드럽게 오르내리는 거대한 철제 롤러코스터입니다 +STR_0581 :원형 모양의 좌석이 맨 위까지 끌어올려진 다음, 자유 낙하하며, 자기장에 의해 부드럽게 바닥에 정지합니다 +STR_0582 : +STR_0583 : +STR_0584 :탑승객이 스스로 페달을 밟아 이동해야 하는, 특별한 철제 모노레일 트랙 위를 이동하는 자전거입니다 +STR_0585 :탑승객은 트랙 밑에 매달린 좌석 한 쌍에 앉아 루프와 트위스트를 급격히 통과합니다 +STR_0586 :보트 모양의 차량이 꼬인 커브와 급강하가 가능한 롤러코스터 트랙을 달리며, 강 섹션의 물에서는 물보라를 일으키며 감속합니다 +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 :각각의 차량이 부드럽게 꼬인 채로 낙하하는 알찬 구성의 롤러코스터입니다. +STR_0600 :부드럽게 꼬인 트랙 구조를 따라 이동하는 탄광 차량입니다 +STR_0601 : +STR_0602 :롤러코스터 차량은 탑승장에서 선형 유도 모터에 의해 가속하여 트랙을 돌만한 속도까지 올라갑니다 +STR_0603 :손님 {INT32} +STR_0604 :손님 {INT32} +STR_0605 :손님 {INT32} +STR_0606 :손님 {INT32} +STR_0607 :손님 {INT32} +STR_0608 :손님 {INT32} +STR_0609 :손님 {INT32} +STR_0610 :손님 {INT32} +STR_0611 :손님 {INT32} +STR_0612 :손님 {INT32} +STR_0613 :손님 {INT32} +STR_0614 :손님 {INT32} +STR_0615 :손님 {INT32} +STR_0616 :손님 {INT32} +STR_0617 :손님 {INT32} +STR_0618 :손님 {INT32} +STR_0619 :손님 {INT32} +STR_0620 :손님 {INT32} +STR_0621 :손님 {INT32} +STR_0622 :손님 {INT32} +STR_0623 :손님 {INT32} +STR_0624 :손님 {INT32} +STR_0625 :손님 {INT32} +STR_0626 :손님 {INT32} +STR_0627 :손님 {INT32} +STR_0628 :손님 {INT32} +STR_0629 :손님 {INT32} +STR_0630 :손님 {INT32} +STR_0631 :손님 {INT32} +STR_0632 :손님 {INT32} +STR_0633 :손님 {INT32} +STR_0634 :손님 {INT32} +STR_0635 :손님 {INT32} +STR_0636 :손님 {INT32} +STR_0637 :손님 {INT32} +STR_0638 :손님 {INT32} +STR_0639 :손님 {INT32} +STR_0640 :손님 {INT32} +STR_0641 :손님 {INT32} +STR_0642 :손님 {INT32} +STR_0643 :손님 {INT32} +STR_0644 :손님 {INT32} +STR_0645 :손님 {INT32} +STR_0646 :손님 {INT32} +STR_0647 :손님 {INT32} +STR_0648 :손님 {INT32} +STR_0649 :손님 {INT32} +STR_0650 :손님 {INT32} +STR_0651 :손님 {INT32} +STR_0652 :손님 {INT32} +STR_0653 :손님 {INT32} +STR_0654 :손님 {INT32} +STR_0655 :손님 {INT32} +STR_0656 :손님 {INT32} +STR_0657 :손님 {INT32} +STR_0658 :손님 {INT32} +STR_0659 :손님 {INT32} +STR_0660 :손님 {INT32} +STR_0661 :손님 {INT32} +STR_0662 :손님 {INT32} +STR_0663 :손님 {INT32} +STR_0664 :손님 {INT32} +STR_0665 :손님 {INT32} +STR_0666 :손님 {INT32} +STR_0667 :손님 {INT32} +STR_0668 :손님 {INT32} +STR_0669 :손님 {INT32} +STR_0670 :손님 {INT32} +STR_0671 :손님 {INT32} +STR_0672 :손님 {INT32} +STR_0673 :손님 {INT32} +STR_0674 :손님 {INT32} +STR_0675 :손님 {INT32} +STR_0676 :손님 {INT32} +STR_0677 :손님 {INT32} +STR_0678 :손님 {INT32} +STR_0679 :손님 {INT32} +STR_0680 :손님 {INT32} +STR_0681 :손님 {INT32} +STR_0682 :손님 {INT32} +STR_0683 :손님 {INT32} +STR_0684 :손님 {INT32} +STR_0685 :손님 {INT32} +STR_0686 :손님 {INT32} +STR_0687 :손님 {INT32} +STR_0688 :손님 {INT32} +STR_0689 :손님 {INT32} +STR_0690 :손님 {INT32} +STR_0691 :손님 {INT32} +STR_0692 :손님 {INT32} +STR_0693 :손님 {INT32} +STR_0694 :손님 {INT32} +STR_0695 :손님 {INT32} +STR_0696 :손님 {INT32} +STR_0697 :손님 {INT32} +STR_0698 :손님 {INT32} +STR_0699 :손님 {INT32} +STR_0700 :손님 {INT32} +STR_0701 :손님 {INT32} +STR_0702 :손님 {INT32} +STR_0703 :손님 {INT32} +STR_0704 :손님 {INT32} +STR_0705 :손님 {INT32} +STR_0706 :손님 {INT32} +STR_0707 :손님 {INT32} +STR_0708 :손님 {INT32} +STR_0709 :손님 {INT32} +STR_0710 :손님 {INT32} +STR_0711 :손님 {INT32} +STR_0712 :손님 {INT32} +STR_0713 :손님 {INT32} +STR_0714 :손님 {INT32} +STR_0715 :손님 {INT32} +STR_0716 :손님 {INT32} +STR_0717 :손님 {INT32} +STR_0718 :손님 {INT32} +STR_0719 :손님 {INT32} +STR_0720 :손님 {INT32} +STR_0721 :손님 {INT32} +STR_0722 :손님 {INT32} +STR_0723 :손님 {INT32} +STR_0724 :손님 {INT32} +STR_0725 :손님 {INT32} +STR_0726 :손님 {INT32} +STR_0727 :손님 {INT32} +STR_0728 :손님 {INT32} +STR_0729 :손님 {INT32} +STR_0730 :손님 {INT32} +STR_0731 :손님 {INT32} +STR_0732 :손님 {INT32} +STR_0733 :손님 {INT32} +STR_0734 :손님 {INT32} +STR_0735 :손님 {INT32} +STR_0736 :손님 {INT32} +STR_0737 :손님 {INT32} +STR_0738 :손님 {INT32} +STR_0739 :손님 {INT32} +STR_0740 :손님 {INT32} +STR_0741 :손님 {INT32} +STR_0742 :손님 {INT32} +STR_0743 :손님 {INT32} +STR_0744 :손님 {INT32} +STR_0745 :손님 {INT32} +STR_0746 :손님 {INT32} +STR_0747 :손님 {INT32} +STR_0748 :손님 {INT32} +STR_0749 :손님 {INT32} +STR_0750 :손님 {INT32} +STR_0751 :손님 {INT32} +STR_0752 :손님 {INT32} +STR_0753 :손님 {INT32} +STR_0754 :손님 {INT32} +STR_0755 :손님 {INT32} +STR_0756 :손님 {INT32} +STR_0757 :손님 {INT32} +STR_0758 :손님 {INT32} +STR_0759 :손님 {INT32} +STR_0760 :손님 {INT32} +STR_0761 :손님 {INT32} +STR_0762 :손님 {INT32} +STR_0763 :손님 {INT32} +STR_0764 :손님 {INT32} +STR_0765 :손님 {INT32} +STR_0766 :손님 {INT32} +STR_0767 :손님 {INT32} +STR_0768 :미화원 {INT32} +STR_0769 :정비기술자 {INT32} +STR_0770 :경비원 {INT32} +STR_0771 :엔터테이너 {INT32} +STR_0772 :이름 없는 공원{POP16}{POP16} +STR_0773 :이름 없는 공원{POP16}{POP16} +STR_0774 :이름 없는 공원{POP16}{POP16} +STR_0775 :이름 없는 공원{POP16}{POP16} +STR_0776 :이름 없는 공원{POP16}{POP16} +STR_0777 :이름 없는 공원{POP16}{POP16} +STR_0778 :팻말 +STR_0779 :1일 +STR_0780 :2일 +STR_0781 :3일 +STR_0782 :4일 +STR_0783 :5일 +STR_0784 :6일 +STR_0785 :7일 +STR_0786 :8일 +STR_0787 :9일 +STR_0788 :10일 +STR_0789 :11일 +STR_0790 :12일 +STR_0791 :13일 +STR_0792 :14일 +STR_0793 :15일 +STR_0794 :16일 +STR_0795 :17일 +STR_0796 :18일 +STR_0797 :19일 +STR_0798 :20일 +STR_0799 :21일 +STR_0800 :22일 +STR_0801 :23일 +STR_0802 :24일 +STR_0803 :25일 +STR_0804 :26일 +STR_0805 :27일 +STR_0806 :28일 +STR_0807 :29일 +STR_0808 :30일 +STR_0809 :31일 +STR_0810 :1월 +STR_0811 :2월 +STR_0812 :3월 +STR_0813 :4월 +STR_0814 :5월 +STR_0815 :6월 +STR_0816 :7월 +STR_0817 :8월 +STR_0818 :9월 +STR_0819 :10월 +STR_0820 :11월 +STR_0821 :12월 +STR_0822 :그래픽 데이터 파일에 접근할 수 없습니다 +STR_0823 :데이터 파일이 존재하지 않거나 접근할 수 없습니다 +STR_0824 :{BLACK}{CROSS} +STR_0825 :이미 사용 중인 이름입니다 +STR_0826 :이름이 너무 많이 지정되었습니다 +STR_0827 :돈이 부족합니다 - {CURRENCY2DP} 만큼의 돈이 더 필요합니다 +STR_0828 :{SMALLFONT}{BLACK}창 닫기 +STR_0829 :{SMALLFONT}{BLACK}창 제목 - 창을 움직이려면 여기를 드래그하세요 +STR_0830 :{SMALLFONT}{BLACK}화면 확대하기 +STR_0831 :{SMALLFONT}{BLACK}화면 축소하기 +STR_0832 :{SMALLFONT}{BLACK}화면을 시계 방향으로 90{DEGREE}도 회전하기 +STR_0833 :{SMALLFONT}{BLACK}게임 일시정지 +STR_0834 :{SMALLFONT}{BLACK}디스크 및 게임 옵션 +STR_0835 :게임 초기화 실패 +STR_0836 :게임을 최소화 상태에서 실행할 수 없습니다 +STR_0837 :그래픽 시스템을 초기화할 수 없습니다 +STR_0838 :<더 이상 사용하지 않음> +STR_0839 :{UINT16} x {UINT16} +STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 :<더 이상 사용하지 않음> +STR_0842 :<더 이상 사용하지 않음> +STR_0843 :<더 이상 사용하지 않음> +STR_0844 :<더 이상 사용하지 않음> +STR_0845 :<더 이상 사용하지 않음> +STR_0846 :<더 이상 사용하지 않음> +STR_0847 :'OpenRCT2'에 대해서 +STR_0848 :롤러코스터 타이쿤 2 +STR_0849 :{WINDOW_COLOUR_2}버전 2.01.028 +STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, all rights reserved +STR_0851 :{WINDOW_COLOUR_2}디자인 및 프로그래밍: Chris Sawyer +STR_0852 :{WINDOW_COLOUR_2}그래픽: Simon Foster +STR_0853 :{WINDOW_COLOUR_2}효과음 및 배경음악: Allister Brimble +STR_0854 :{WINDOW_COLOUR_2}추가 효과음 녹음: David Ellis +STR_0855 :{WINDOW_COLOUR_2}리프리젠테이션: Marjacq Ltd사의 Jacqui Lyons +STR_0856 :{WINDOW_COLOUR_2}감사드릴 분들: +STR_0857 :{WINDOW_COLOUR_2}Peter James Adcock, Joe Booth 그리고 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 :너무 낮습니다! +STR_0878 :너무 높습니다! +STR_0879 :여기를 더 이상 내릴 수 없습니다... +STR_0880 :여기를 더 이상 올릴 수 없습니다... +STR_0881 :오브젝트가 있습니다 +STR_0882 :게임 불러오기 +STR_0883 :게임 저장하기 +STR_0884 :풍경 불러오기 +STR_0885 :풍경 저장하기 +STR_0886 :게임 종료하기 +STR_0887 :시나리오 에디터 종료하기 +STR_0888 :롤러코스터 디자이너 종료하기 +STR_0889 :트랙 디자인 매니저 종료하기 +STR_0890 :SCR{COMMA16}.BMP +STR_0891 :스크린 샷 +STR_0892 :스크린 샷이 디스크에 다음 이름으로 저장되었습니다: {STRINGID} +STR_0893 :스크린 샷 찍기 실패! +STR_0894 :풍경 데이터 영역이 가득 찼습니다! +STR_0895 :일부분만 땅의 위/아래로 건설할 수 없습니다 +STR_0896 :{POP16}{POP16}{STRINGID} 건설 +STR_0897 :방향 +STR_0898 :{SMALLFONT}{BLACK}왼쪽 커브 +STR_0899 :{SMALLFONT}{BLACK}오른쪽 커브 +STR_0900 :{SMALLFONT}{BLACK}왼쪽 커브 (작은 반경) +STR_0901 :{SMALLFONT}{BLACK}오른쪽 커브 (작은 반경) +STR_0902 :{SMALLFONT}{BLACK}왼쪽 커브 (아주 작은 반경) +STR_0903 :{SMALLFONT}{BLACK}오른쪽 커브 (아주 작은 반경) +STR_0904 :{SMALLFONT}{BLACK}왼쪽 커브 (큰 반경) +STR_0905 :{SMALLFONT}{BLACK}오른쪽 커브 (큰 반경) +STR_0906 :{SMALLFONT}{BLACK}직선 +STR_0907 :경사 +STR_0908 :회전/뱅킹 +STR_0909 :좌석 회전각 +STR_0910 :{SMALLFONT}{BLACK}왼쪽으로 회전 +STR_0911 :{SMALLFONT}{BLACK}오른쪽으로 회전 +STR_0912 :{SMALLFONT}{BLACK}회전 없음 +STR_0913 :{SMALLFONT}{BLACK}이전 조각으로 이동 +STR_0914 :{SMALLFONT}{BLACK}다음 조각으로 이동 +STR_0915 :{SMALLFONT}{BLACK}선택한 조각을 건설 +STR_0916 :{SMALLFONT}{BLACK}선택한 조각을 제거 +STR_0917 :{SMALLFONT}{BLACK}수직 낙하 +STR_0918 :{SMALLFONT}{BLACK}급 하강 +STR_0919 :{SMALLFONT}{BLACK}하강 +STR_0920 :{SMALLFONT}{BLACK}평탄 +STR_0921 :{SMALLFONT}{BLACK}상승 +STR_0922 :{SMALLFONT}{BLACK}급상승 +STR_0923 :{SMALLFONT}{BLACK}수직 상승 +STR_0924 :{SMALLFONT}{BLACK}나선 하강 +STR_0925 :{SMALLFONT}{BLACK}나선 상승 +STR_0926 :여기를 제거할 수 없습니다... +STR_0927 :여기에 건설할 수 없습니다... +STR_0928 :{SMALLFONT}{BLACK}경사를 오르기 위한 체인 리프트 +STR_0929 :S자 트랙 (왼쪽) +STR_0930 :S자 트랙 (오른쪽) +STR_0931 :버티컬 루프 (왼쪽) +STR_0932 :버티컬 루프 (오른쪽) +STR_0933 :땅을 먼저 올리거나 내리세요 +STR_0934 :놀이기구 입구가 있습니다 +STR_0935 :놀이기구 출구가 있습니다 +STR_0936 :공원 입구가 있습니다 +STR_0937 :{SMALLFONT}{BLACK}보기 설정 +STR_0938 :{SMALLFONT}{BLACK}지형 높이와 경사를 보여줌 +STR_0939 :지하/내부 시야 +STR_0940 :땅 안 보이기 +STR_0941 :절벽 안 보이기 +STR_0942 :놀이기구 안 보이기 +STR_0943 :풍경 안 보이기 +STR_0944 :저장 +STR_0945 :저장 안 함 +STR_0946 :취소 +STR_0947 :불러오기 전에 저장하시겠습니까? +STR_0948 :종료하기 전에 저장하시겠습니까? +STR_0949 :종료하기 전에 저장하시겠습니까? +STR_0950 :게임 불러오기 +STR_0951 :게임 종료하기 +STR_0952 :게임 종료하기 +STR_0953 :풍경 불러오기 +STR_0954 : +STR_0955 :{SMALLFONT}{BLACK}이 트랙 조각에서의 좌석 회전 각도를 선택하세요 +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 :취소 +STR_0973 :확인 +STR_0974 :놀이기구 +STR_0975 :상점·매점 +STR_0976 :화장실 및 안내소 +STR_0977 :새로운 운송용 놀이기구 +STR_0978 :새로운 얌전한 놀이기구 +STR_0979 :새로운 롤러코스터 +STR_0980 :새로운 스릴있는 놀이기구 +STR_0981 :새로운 물 놀이기구 +STR_0982 :새로운 상점·매점 +STR_0983 :연구 & 개발 +STR_0984 :{WINDOW_COLOUR_2}{UP}{BLACK} {CURRENCY2DP} +STR_0985 :{WINDOW_COLOUR_2}{DOWN}{BLACK} {CURRENCY2DP} +STR_0986 :{BLACK}{CURRENCY2DP} +STR_0987 :놀이기구나 시설이 너무 많습니다 +STR_0988 :새 놀이기구나 시설을 만들 수 없습니다... +STR_0989 :{STRINGID} +STR_0990 :{SMALLFONT}{BLACK}건설 +STR_0991 :탑승장 선택 +STR_0992 :{SMALLFONT}{BLACK}전체 놀이기구나 시설을 파괴합니다 +STR_0993 :놀이기구/시설 파괴 +STR_0994 :파괴 +STR_0995 :{WINDOW_COLOUR_1}정말 이 놀이기구/시설을 완전히 파괴하시겠습니까? : {STRINGID} +STR_0996 :전경 +STR_0997 :{SMALLFONT}{BLACK}시야 선택 +STR_0998 :탑승장이 너무 많습니다 +STR_0999 :탑승장이 필요합니다 +STR_1000 :트랙이 완성되지 않았습니다 +STR_1001 :트랙이 열차 종류와 맞지 않습니다 +STR_1002 :{POP16}{POP16}{POP16}{STRINGID}(을)를 운행할 수 없습니다... +STR_1003 :Can't test {POP16}{POP16}{POP16}{STRINGID}(을)를 테스트할 수 없습니다... +STR_1004 :{POP16}{POP16}{POP16}{STRINGID}(을)를 닫을 수 없습니다... +STR_1005 :{POP16}{POP16}{POP16}{STRINGID}의 건설을 시작할 수 없습니다... +STR_1006 :먼저 닫아야 합니다 +STR_1007 :차량을 충분히 만들 수 없습니다 +STR_1008 :{SMALLFONT}{BLACK}놀이기구나 시설을 열거나, 닫거나 테스트합니다 +STR_1009 :{SMALLFONT}{BLACK}모든 놀이기구나 시설을 열거나 닫습니다 +STR_1010 :{SMALLFONT}{BLACK}공원을 열거나 닫습니다 +STR_1011 :모두 닫기 +STR_1012 :모두 열기 +STR_1013 :공원 닫기 +STR_1014 :공원 열기 +STR_1015 :이 운행 모드에서는 승강장을 하나만 건설해야 합니다 +STR_1016 :이 운행 모드에서는 승강장이 2개 이상 필요합니다 +STR_1017 :운행 모드를 변경할 수 없습니다... +STR_1018 :변경할 수 없습니다... +STR_1019 :변경할 수 없습니다... +STR_1020 :변경할 수 없습니다... +STR_1021 :{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_1022 :1대당 {POP16}{POP16}{POP16}{COMMA16}량의 차량 +STR_1023 :1대당 {POP16}{POP16}{POP16}{COMMA16}량의 차량 +STR_1024 :1대당 {COMMA16}량의 차량 +STR_1025 :1대당 {COMMA16}량의 차량 +STR_1026 :탑승장이 너무 깁니다! +STR_1027 :{SMALLFONT}{BLACK}여기로 이동 +STR_1028 :지도 끝을 벗어납니다! +STR_1029 :일부분만 수면 위로 나오도록 건설할 수 없습니다! +STR_1030 :수중에만 건설할 수 있습니다! +STR_1031 :물 속에 건설할 수 없습니다! +STR_1032 :물 위에만 건설할 수 있습니다! +STR_1033 :땅 위에만 건설할 수 있습니다! +STR_1034 :땅 위에만 건설할 수 있습니다! +STR_1035 :지역 당국이 나무 높이 이상의 건설을 허용하지 않습니다! +STR_1036 :게임 불러오기 +STR_1037 :풍경 불러오기 +STR_1038 :저장된 게임을 시나리오로 변환 +STR_1039 :새 트랙 디자인을 설치 +STR_1040 :게임 저장하기 +STR_1041 :시나리오 저장하기 +STR_1042 :풍경 저장하기 +STR_1043 :OpenRCT2 저장된 게임 파일 +STR_1044 :OpenRCT2 시나리오 파일 +STR_1045 :OpenRCT2 풍경 파일 +STR_1046 :OpenRCT2 트랙 디자인 파일 +STR_1047 :게임 저장 실패! +STR_1048 :시나리오 저장 실패 +STR_1049 :풍경 저장 실패! +STR_1050 :불러오기 실패...{NEWLINE}파일에 유효하지 않은 데이터가 있습니다! +STR_1051 :트랙 지지대 감추기 +STR_1052 :손님 감추기 +STR_1053 :{SMALLFONT}{BLACK}공원의 놀이기구나 시설 +STR_1054 :{SMALLFONT}{BLACK}놀이기구/시설 이름 +STR_1055 :{SMALLFONT}{BLACK}손님 이름 +STR_1056 :{SMALLFONT}{BLACK}직원 이름 +STR_1057 :놀이기구/시설 이름 +STR_1058 :이 놀이기구/시설의 새 이름을 입력하세요: +STR_1059 :놀이기구/시설의 이름을 바꿀 수 없습니다... +STR_1060 :유효하지 않은 놀이기구/시설의 이름입니다 +STR_1061 :일반 모드 +STR_1062 :연속 순환 모드 +STR_1063 :역방향 인클라인 발진 셔틀 모드 +STR_1064 :급발진 출발 (역 통과) +STR_1065 :셔틀 모드 +STR_1066 :보트 대여 모드 +STR_1067 :상승 발진 +STR_1068 :리프트 회전 모드 +STR_1069 :역 대 역 모드 +STR_1070 :1회 탑승 모드 +STR_1071 :무한 탑승 모드 +STR_1072 :미로 모드 +STR_1073 :레이스 모드 +STR_1074 :범퍼카 모드 +STR_1075 :스윙 모드 +STR_1076 :상점 매점 모드 +STR_1077 :회전 모드 +STR_1078 :전진 회전 +STR_1079 :후진 회전 +STR_1080 :영화: {ENDQUOTES}비행사의 복수사{ENDQUOTES} +STR_1081 :3D 영화: {ENDQUOTES}생쥐의 꼬리{ENDQUOTES} +STR_1082 :스페이스 링 모드 +STR_1083 :초급 모드 +STR_1084 :LIM-파워 발진 +STR_1085 :영화: {ENDQUOTES}스릴 라이더{ENDQUOTES} +STR_1086 :3D 영화: {ENDQUOTES}폭풍의 추적자{ENDQUOTES} +STR_1087 :3D 영화: {ENDQUOTES}스페이스 라이더{ENDQUOTES} +STR_1088 :격렬 모드 +STR_1089 :난폭 모드 +STR_1090 :귀신의 집 모드 +STR_1091 :서커스 쇼 모드 +STR_1092 :하향 발진 +STR_1093 :이상한 집 모드 +STR_1094 :자유낙하 모드 +STR_1095 :연속 순환 블록 섹션 모드 +STR_1096 :급발진 출발 (역을 지나치지 않음) +STR_1097 :급발진 출발 블록 섹션 모드 +STR_1098 :{POP16}{STRINGID}의 끝으로 이동 +STR_1099 :{POP16}{STRINGID}에서 승객 탑승 대기 중 +STR_1100 :{POP16}{STRINGID}에서 출발 대기중 +STR_1101 :{POP16}{STRINGID} 출발 중 +STR_1102 :운행 중 : {VELOCITY} +STR_1103 :{POP16}{STRINGID}에 도착 중 +STR_1104 :{POP16}{STRINGID}에서 승객 하차 중 +STR_1105 :운행 중 : {VELOCITY} +STR_1106 :충돌 중! +STR_1107 :충돌! +STR_1108 :운행 중 : {VELOCITY} +STR_1109 :스윙 중 +STR_1110 :회전 중 +STR_1111 :회전 중 +STR_1112 :운행 중 +STR_1113 :영화 상영 중 +STR_1114 :회전 중 +STR_1115 :운행 중 +STR_1116 :운행 중 +STR_1117 :서커스 쇼 진행 중 +STR_1118 :운행 중 +STR_1119 :케이블 리프트를 기다리는 중 +STR_1120 :운행 중 : {VELOCITY} +STR_1121 :정지하는 중 +STR_1122 :승객 대기 중 +STR_1123 :출발 대기 중 +STR_1124 :출발 중 +STR_1125 :운행 중 +STR_1126 :정지하는 중 +STR_1127 :승객 하차 중 +STR_1128 :블록 브레이크에 의해 정지함 +STR_1129 :모든 차량을 같은 색으로 +STR_1130 :{STRINGID}마다 다른 색 +STR_1131 :차량마다 다른 색 +STR_1132 :차량 {POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1133 :차량 {POP16}{COMMA16} +STR_1134 :{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} {COMMA16} +STR_1135 :{STRINGID} {COMMA16} +STR_1136 :{SMALLFONT}{BLACK}주요 색상을 선택하세요 +STR_1137 :{SMALLFONT}{BLACK}1번 추가 색상을 선택하세요 +STR_1138 :{SMALLFONT}{BLACK}2번 추가 색상을 선택하세요 +STR_1139 :{SMALLFONT}{BLACK}트랙 지지대 색상을 선택하세요 +STR_1140 :{SMALLFONT}{BLACK}차량 색상을 선택하세요 +STR_1141 :{SMALLFONT}{BLACK}어떤 차량/열차를 수정할지 선택하세요 +STR_1142 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1143 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRINGID} +STR_1144 :이 놀이기구/시설의 입구를 건설/파괴할 수 없습니다... +STR_1145 :이 놀이기구/시설의 출구를 건설/파괴할 수 없습니다... +STR_1146 :입구가 아직 설치되지 않았습니다 +STR_1147 :출구가 아직 설치되지 않았습니다 +STR_1148 :1/4을 태우면 +STR_1149 :1/2을 태우면 +STR_1150 :3/4을 태우면 +STR_1151 :모두 태우면 +STR_1152 :한 사람이라도 태우면 +STR_1153 :놀이기구 트랙 높이 표시 +STR_1154 :지형 높이 표시 +STR_1155 :보도 높이 표시 +STR_1156 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1157 :{TICK}{MOVE_X}{SMALLFONT}{STRINGID} +STR_1158 :제거할 수 없습니다... +STR_1159 :{SMALLFONT}{BLACK}풍경, 정원, 기타 시설을 설치합니다 +STR_1160 :{SMALLFONT}{BLACK}호수나 물을 만듭니다 +STR_1161 :여기에 위치시킬 수 없습니다... +STR_1162 :{OUTLINE}{TOPAZ}{STRINGID} +STR_1163 :{STRINGID}{NEWLINE}(수정하려면 오른쪽 클릭하세요) +STR_1164 :{STRINGID}{NEWLINE}(제거하려면 오른쪽 클릭하세요) +STR_1165 :{STRINGID} - {STRINGID} {COMMA16} +STR_1166 :이곳의 물을 내릴 수 없습니다... +STR_1167 :이곳의 물을 올릴 수 없습니다... +STR_1168 :옵션 +STR_1169 :(없음) +STR_1170 :{STRING} +STR_1171 :{RED}닫힘 - - +STR_1172 :{YELLOW}{STRINGID} - - +STR_1173 :{SMALLFONT}{BLACK}보도와 대기줄을 만듭니다 +STR_1174 :전광판 사인이 있습니다 +STR_1175 :경사진 보도 위에 건설할 수 없습니다 +STR_1176 :보도를 여기에 건설할 수 없습니다... +STR_1177 :보도를 제거할 수 없습니다... +STR_1178 :땅의 경사가 적절하지 않습니다 +STR_1179 :중간에 보도가 있습니다 +STR_1180 :수중에 건설할 수 없습니다! +STR_1181 :보도 +STR_1182 :종류 +STR_1183 :방향 +STR_1184 :경사 +STR_1185 :{SMALLFONT}{BLACK}방향 +STR_1186 :{SMALLFONT}{BLACK}아래로 +STR_1187 :{SMALLFONT}{BLACK}평탄 +STR_1188 :{SMALLFONT}{BLACK}위로 +STR_1189 :{SMALLFONT}{BLACK}선택한 보도 조각을 건설 +STR_1190 :{SMALLFONT}{BLACK}이전 보도 조각을 제거 +STR_1191 :{BLACK}{STRINGID} +STR_1192 :{OUTLINE}{RED}{STRINGID} +STR_1193 :{WINDOW_COLOUR_2}{STRINGID} +STR_1194 :닫힘 +STR_1195 :테스트 운행 +STR_1196 :열림 +STR_1197 :고장 +STR_1198 :충돌! +STR_1199 :놀이기구에 {COMMA16}명 있음 +STR_1200 :놀이기구에 {COMMA16}명 있음 +STR_1201 :대기 중인 손님: 없음 +STR_1202 :대기 중인 손님: 1명 +STR_1203 :대기 중인 손님: {COMMA16}명 +STR_1204 :대기 시간: {COMMA16}분 +STR_1205 :대기 시간: {COMMA16}분 +STR_1206 :{WINDOW_COLOUR_2}출발: +STR_1207 :{WINDOW_COLOUR_2}다른 열차가 탑승장에 도착하면 열차를 출발시킴 +STR_1208 :{WINDOW_COLOUR_2}다른 보트가 탑승장에 도착하면 보트를 출발시킴 +STR_1209 :{SMALLFONT}{BLACK}출발하기 전에 승객을 기다릴지 여부를 선택하세요 +STR_1210 :{SMALLFONT}{BLACK}다른 차량이 같은 탑승장에 도착하면 열차를 출발시킬지 여부를 선택하세요 +STR_1211 :{WINDOW_COLOUR_2}최소 대기 시간: +STR_1212 :{WINDOW_COLOUR_2}최대 대기 시간: +STR_1213 :{SMALLFONT}{BLACK}출발하기 전에 최소한으로 기다릴 시간 길이를 선택하세요 +STR_1214 :{SMALLFONT}{BLACK}출발하기 전에 최대한으로 기다릴 시간 길이를 선택하세요 +STR_1215 :{WINDOW_COLOUR_2}인접한 탑승장과 같이 출발시킴 +STR_1216 :{SMALLFONT}{BLACK}모든 인접한 탑승장과 차량을 동시에 출발시킬지 여부를 선택하세요 +STR_1217 :{COMMA16}초 +STR_1218 :{BLACK}{SMALLUP} +STR_1219 :{BLACK}{SMALLDOWN} +STR_1220 :출구만 있음 +STR_1221 :입구 없음 +STR_1222 :출구 없음 +STR_1223 :{SMALLFONT}{BLACK}운송용 놀이기구 +STR_1224 :{SMALLFONT}{BLACK}얌전한 놀이기구 +STR_1225 :{SMALLFONT}{BLACK}롤러코스터 +STR_1226 :{SMALLFONT}{BLACK}스릴있는 놀이기구 +STR_1227 :{SMALLFONT}{BLACK}물 놀이기구 +STR_1228 :{SMALLFONT}{BLACK}상점 & 매점 +STR_1229 :열차 +STR_1230 :열차 +STR_1231 :열차 +STR_1232 :열차 +STR_1233 :{COMMA16} 열차 +STR_1234 :{COMMA16} 열차 +STR_1235 :열차 {COMMA16} +STR_1236 :보트 +STR_1237 :보트 +STR_1238 :보트 +STR_1239 :보트 +STR_1240 :{COMMA16} 보트 +STR_1241 :{COMMA16} 보트 +STR_1242 :보트 {COMMA16} +STR_1243 :트랙 +STR_1244 :트랙 +STR_1245 :트랙 +STR_1246 :트랙 +STR_1247 :{COMMA16} 트랙 +STR_1248 :{COMMA16} 트랙 +STR_1249 :트랙 {COMMA16} +STR_1250 :도킹 승강장 +STR_1251 :도킹 승강장 +STR_1252 :도킹 승강장 +STR_1253 :도킹 승강장 +STR_1254 :{COMMA16} 도킹 승강장 +STR_1255 :{COMMA16} 도킹 승강장 +STR_1256 :도킹 승강장 {COMMA16} +STR_1257 :탑승장 +STR_1258 :탑승장 +STR_1259 :탑승장 +STR_1260 :탑승장 +STR_1261 :{COMMA16} 탑승장 +STR_1262 :{COMMA16} 탑승장 +STR_1263 :탑승장 {COMMA16} +STR_1264 :차 +STR_1265 :차 +STR_1266 :차 +STR_1267 :차 +STR_1268 :{COMMA16} 차 +STR_1269 :{COMMA16} 차 +STR_1270 :차 {COMMA16} +STR_1271 :건물 +STR_1272 :건물 +STR_1273 :건물 +STR_1274 :건물 +STR_1275 :{COMMA16} 건물 +STR_1276 :{COMMA16} 건물 +STR_1277 :건물 {COMMA16} +STR_1278 :구조물 +STR_1279 :구조물 +STR_1280 :구조물 +STR_1281 :구조물 +STR_1282 :{COMMA16} 구조물 +STR_1283 :{COMMA16} 구조물 +STR_1284 :구조물 {COMMA16} +STR_1285 :배 +STR_1286 :배 +STR_1287 :배 +STR_1288 :배 +STR_1289 :{COMMA16} 배 +STR_1290 :{COMMA16} 배 +STR_1291 :배 {COMMA16} +STR_1292 :객실 +STR_1293 :객실 +STR_1294 :객실 +STR_1295 :객실 +STR_1296 :{COMMA16} 객실 +STR_1297 :{COMMA16} 객실 +STR_1298 :객실 {COMMA16} +STR_1299 :휠 +STR_1300 :휠 +STR_1301 :휠 +STR_1302 :휠 +STR_1303 :{COMMA16} 휠 +STR_1304 :{COMMA16} 휠 +STR_1305 :휠 {COMMA16} +STR_1306 :링 +STR_1307 :링 +STR_1308 :링 +STR_1309 :링 +STR_1310 :{COMMA16} 링 +STR_1311 :{COMMA16} 링 +STR_1312 :링 {COMMA16} +STR_1313 :플레이어 +STR_1314 :플레이어 +STR_1315 :플레이어 +STR_1316 :플레이어 +STR_1317 :{COMMA16} 플레이어 +STR_1318 :{COMMA16} 플레이어 +STR_1319 :플레이어 {COMMA16} +STR_1320 :코스 +STR_1321 :코스 +STR_1322 :코스 +STR_1323 :코스 +STR_1324 :{COMMA16} 코스 +STR_1325 :{COMMA16} 코스 +STR_1326 :코스 {COMMA16} +STR_1327 :{SMALLFONT}{BLACK}오브젝트를 90{DEGREE} 회전시킵니다 +STR_1328 :평지가 필요합니다 +STR_1329 :{WINDOW_COLOUR_2}발진 속도: +STR_1330 :{SMALLFONT}{BLACK}탑승장 출발 최대 속도 +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} - 입구{POP16}{POP16} +STR_1336 :{STRINGID} - 탑승장 {POP16}{COMMA16} 입구 +STR_1337 :{STRINGID} - 출구{POP16}{POP16} +STR_1338 :{STRINGID} - 탑승장 {POP16}{COMMA16} 출구 +STR_1339 :{BLACK}테스트 결과가 아직 나오지 않았습니다... +STR_1340 :{WINDOW_COLOUR_2}최대 속력: {BLACK}{VELOCITY} +STR_1341 :{WINDOW_COLOUR_2}탑승 시간: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1342 :{DURATION} +STR_1343 :{DURATION} / +STR_1344 :{WINDOW_COLOUR_2}탑승 길이: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1345 :{LENGTH} +STR_1346 :{LENGTH} / +STR_1347 :{WINDOW_COLOUR_2}평균 속력: {BLACK}{VELOCITY} +STR_1348 :{WINDOW_COLOUR_2}최대 양수 수직 중력값: {BLACK}{COMMA2DP32}g +STR_1349 :{WINDOW_COLOUR_2}최대 양수 수직 중력값: {OUTLINE}{RED}{COMMA2DP32}g +STR_1350 :{WINDOW_COLOUR_2}최대 음수 수직 중력값: {BLACK}{COMMA2DP32}g +STR_1351 :{WINDOW_COLOUR_2}최대 음수 수직 중력값: {OUTLINE}{RED}{COMMA2DP32}g +STR_1352 :{WINDOW_COLOUR_2}최대 측면 중력값: {BLACK}{COMMA2DP32}g +STR_1353 :{WINDOW_COLOUR_2}최대 측면 중력값: {OUTLINE}{RED}{COMMA2DP32}g +STR_1354 :{WINDOW_COLOUR_2}최고 낙하 높이: {BLACK}{LENGTH} +STR_1355 :{WINDOW_COLOUR_2}낙하 회수: {BLACK}{COMMA16} +STR_1356 :{WINDOW_COLOUR_2}뒤집어진 회수: {BLACK}{COMMA16} +STR_1357 :{WINDOW_COLOUR_2}홀 개수: {BLACK}{COMMA16} +STR_1358 :{WINDOW_COLOUR_2}총 '무중력' 시간: {BLACK}{COMMA2DP32}초 +STR_1359 :{WINDOW_COLOUR_2}대기 시간: {BLACK}{COMMA16}분 +STR_1360 :{WINDOW_COLOUR_2}대기 시간: {BLACK}{COMMA16}분 +STR_1361 :속력을 바꿀 수 없습니다... +STR_1362 :발진 속도를 바꿀 수 없습니다... +STR_1363 :지지대가 버틸 수 있는 최대 높이입니다! +STR_1364 :위 트랙의 지지대를 더 이상 늘릴 수 없습니다! +STR_1365 :인라인 트위스트 (왼쪽) +STR_1366 :인라인 트위스트 (오른쪽) +STR_1367 :하프 루프 +STR_1368 :하프 코르크스크류 (왼쪽) +STR_1369 :하프 코르크스크류 (오른쪽) +STR_1370 :바렐 롤 (왼쪽) +STR_1371 :바렐 롤 (오른쪽) +STR_1372 :런치드 리프트 힐 +STR_1373 :대형 하프 루프 (왼쪽) +STR_1374 :대형 하프 루프 (오른쪽) +STR_1375 :위쪽 전송기 +STR_1376 :아래쪽 전송기 +STR_1377 :하트라인 롤 (왼쪽) +STR_1378 :하트라인 롤 (오른쪽) +STR_1379 :리버서 (왼쪽) +STR_1380 :리버서 (오른쪽) +STR_1381 :커브드 리프트 힐 (왼쪽) +STR_1382 :커브드 리프트 힐 (오른쪽) +STR_1383 :1/4 루프 +STR_1384 :{YELLOW}{STRINGID} +STR_1385 :{SMALLFONT}{BLACK}기타 트랙 설정 +STR_1386 :특수 트랙... +STR_1387 :지형 종류를 바꿀 수 없습니다... +STR_1388 :{OUTLINE}{GREEN}+ {CURRENCY} +STR_1389 :{OUTLINE}{RED}- {CURRENCY} +STR_1390 :{CURRENCY2DP} +STR_1391 :{RED}{CURRENCY2DP} +STR_1392 :{SMALLFONT}{BLACK}놀이기구/시설 전경 +STR_1393 :{SMALLFONT}{BLACK}차량 상세 설정 +STR_1394 :{SMALLFONT}{BLACK}운행 설정 +STR_1395 :{SMALLFONT}{BLACK}유지 설정 +STR_1396 :{SMALLFONT}{BLACK}색상 설정 +STR_1397 :{SMALLFONT}{BLACK}효과음 & 배경음악 설정 +STR_1398 :{SMALLFONT}{BLACK}측정 및 테스트 데이터 +STR_1399 :{SMALLFONT}{BLACK}그래프 +STR_1400 :입구 +STR_1401 :출구 +STR_1402 :{SMALLFONT}{BLACK}놀이기구/시설의 입구를 건설하거나 이동합니다 +STR_1403 :{SMALLFONT}{BLACK}놀이기구/시설의 출구를 건설하거나 이동합니다 +STR_1404 :{SMALLFONT}{BLACK}90{DEGREE} 회전 +STR_1405 :{SMALLFONT}{BLACK}반전 +STR_1406 :{SMALLFONT}{BLACK}풍경을 켜거나 끕니다 (단 사용할 수 있는 경우에만 켜짐) +STR_1407 :{WINDOW_COLOUR_2}건설하기... +STR_1408 :{WINDOW_COLOUR_2}예상 가격: {BLACK}{CURRENCY} +STR_1409 :탑승장 출입구 +STR_1410 :버티컬 타워 +STR_1411 :{STRINGID}(이)가 중간에 있습니다 +STR_1412 :{WINDOW_COLOUR_3}이 종류의 놀이기구는 데이터를 기록할 수 없습니다 +STR_1413 :{WINDOW_COLOUR_3}다음 {STRINGID}(이)가 {STRINGID}(을)를 출발할 때 데이터를 기록합니다 +STR_1414 :{SMALLFONT}{BLACK}{DURATION} +STR_1415 :{WINDOW_COLOUR_2}속력 +STR_1416 :{WINDOW_COLOUR_2}고도 +STR_1417 :{WINDOW_COLOUR_2}수직 중력 +STR_1418 :{WINDOW_COLOUR_2}측면 중력 +STR_1419 :{SMALLFONT}{BLACK}{VELOCITY} +STR_1420 :{SMALLFONT}{BLACK}{LENGTH} +STR_1421 :{SMALLFONT}{BLACK}{COMMA16}g +STR_1422 :{SMALLFONT}{BLACK}{POP16}{STRINGID}로부터 데이터 기록 중 +STR_1423 :{SMALLFONT}{BLACK}대기줄 +STR_1424 :{SMALLFONT}{BLACK}보도 +STR_1425 :보도 +STR_1426 :대기줄 +STR_1427 :{WINDOW_COLOUR_2}손님: {BLACK}{COMMA32}명/시간 +STR_1428 :{WINDOW_COLOUR_2}입장료: +STR_1429 :{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1430 :무료 +STR_1431 :걷는 중 +STR_1432 :{STRINGID}(으)로 향하는 중 +STR_1433 :{STRINGID}(에)서 대기 중 +STR_1434 :물에 빠짐 +STR_1435 :{STRINGID} 위에 +STR_1436 :{STRINGID} 안에 +STR_1437 :{STRINGID}에 +STR_1438 :앉음 +STR_1439 :(위치를 선택하세요) +STR_1440 :잔디 깎는 중 +STR_1441 :보도 청소 중 +STR_1442 :쓰레기통 비우는 중 +STR_1443 :정원에 물을 주는 중 +STR_1444 :{STRINGID}(을)를 보는 중 +STR_1445 :{STRINGID}의 건설 장면을 보는 중 +STR_1446 :풍경을 보는 중 +STR_1447 :공원을 떠나는 중 +STR_1448 :새 놀이기구가 건설되는 장면을 보는 중 +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 :손님의 이름 +STR_1453 :이 손님의 이름을 입력하세요: +STR_1454 :손님의 이름을 바꿀 수 없습니다... +STR_1455 :손님 이름으로 적합하지 않습니다 +STR_1456 :{WINDOW_COLOUR_2}사용한 돈: {BLACK}{CURRENCY2DP} +STR_1457 :{WINDOW_COLOUR_2}보유한 돈: {BLACK}{CURRENCY2DP} +STR_1458 :{WINDOW_COLOUR_2}공원에 머무른 시간: {BLACK}{REALTIME} +STR_1459 :트랙 스타일 +STR_1460 :{SMALLFONT}{BLACK}'U' 모양의 천장이 없는 트랙 +STR_1461 :{SMALLFONT}{BLACK}'O' 모양의 천장이 있는 트랙 +STR_1462 :리프트 힐을 쓰기엔 너무 경사가 급합니다 +STR_1463 :손님 +STR_1464 :나선 상승 (작음) +STR_1465 :나선 상승 (큼) +STR_1466 :나선 하강 (작음) +STR_1467 :나선 하강 (큼) +STR_1468 :직원 +STR_1469 :놀이기구는 탑승장에서 시작하고 끝나야 합니다 +STR_1470 :탑승장이 충분히 길지 않습니다 +STR_1471 :{WINDOW_COLOUR_2}속력: +STR_1472 :{SMALLFONT}{BLACK}이 놀이기구의 속력 +STR_1473 :{WINDOW_COLOUR_2}흥미도: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1474 :{WINDOW_COLOUR_2}흥미도: {BLACK}아직 조회할 수 없음 +STR_1475 :{WINDOW_COLOUR_2}격렬도: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1476 :{WINDOW_COLOUR_2}격렬도: {BLACK}아직 조회할 수 없음 +STR_1477 :{WINDOW_COLOUR_2}격렬도: {OUTLINE}{RED}{COMMA2DP32} ({STRINGID}) +STR_1478 :{WINDOW_COLOUR_2}멀미도: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1479 :{WINDOW_COLOUR_2}멀미도: {BLACK}아직 조회할 수 없음 +STR_1480 :{SMALLFONT}{OPENQUOTES}{STRINGID}에 쓸 돈은 없어{ENDQUOTES} +STR_1481 :{SMALLFONT}{OPENQUOTES}내 돈을 전부 다 써버렸어{ENDQUOTES} +STR_1482 :{SMALLFONT}{OPENQUOTES}속이 메스꺼워{ENDQUOTES} +STR_1483 :{SMALLFONT}{OPENQUOTES}속이 정말 메스꺼워{ENDQUOTES} +STR_1484 :{SMALLFONT}{OPENQUOTES}{STRINGID}보다 더 스릴있는 걸 타고 싶어{ENDQUOTES} +STR_1485 :{SMALLFONT}{OPENQUOTES}{STRINGID}(은)는 내가 타기엔 너무 격렬해 보여{ENDQUOTES} +STR_1486 :{SMALLFONT}{OPENQUOTES}아직 {STRINGID}(을)를 다 먹지 않았어{ENDQUOTES} +STR_1487 :{SMALLFONT}{OPENQUOTES}{STRINGID}(은)는 바라만 봐도 속이 메스꺼워{ENDQUOTES} +STR_1488 :{SMALLFONT}{OPENQUOTES}{STRINGID}에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1489 :{SMALLFONT}{OPENQUOTES}집에 가고 싶어{ENDQUOTES} +STR_1490 :{SMALLFONT}{OPENQUOTES}{STRINGID}(은)는 정말 가격이 좋아{ENDQUOTES} +STR_1491 :{SMALLFONT}{OPENQUOTES}{STRINGID}(을)를 이미 갖고 있어{ENDQUOTES} +STR_1492 :{SMALLFONT}{OPENQUOTES}{STRINGID}에 쓸 돈은 없어{ENDQUOTES} +STR_1493 :{SMALLFONT}{OPENQUOTES}배고프지 않아{ENDQUOTES} +STR_1494 :{SMALLFONT}{OPENQUOTES}목마르지 않아{ENDQUOTES} +STR_1495 :{SMALLFONT}{OPENQUOTES}살려주세요! 물에 빠졌어요!{ENDQUOTES} +STR_1496 :{SMALLFONT}{OPENQUOTES}길을 잃어버렸어!{ENDQUOTES} +STR_1497 :{SMALLFONT}{OPENQUOTES}{STRINGID}(은)는 정말 훌륭했어{ENDQUOTES} +STR_1498 :{SMALLFONT}{OPENQUOTES}{STRINGID}(을)를 타려고 한참동안이나 기다렸어{ENDQUOTES} +STR_1499 :{SMALLFONT}{OPENQUOTES}피곤해{ENDQUOTES} +STR_1500 :{SMALLFONT}{OPENQUOTES}배고파{ENDQUOTES} +STR_1501 :{SMALLFONT}{OPENQUOTES}목말라{ENDQUOTES} +STR_1502 :{SMALLFONT}{OPENQUOTES}화장실에 가야겠어{ENDQUOTES} +STR_1503 :{SMALLFONT}{OPENQUOTES}{STRINGID}(을)를 못 찾겠어{ENDQUOTES} +STR_1504 :{SMALLFONT}{OPENQUOTES}{STRINGID}(을)를 이용하는데 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1505 :{SMALLFONT}{OPENQUOTES}비가 오는 동안에는 {STRINGID}에 가지 않을래{ENDQUOTES} +STR_1506 :{SMALLFONT}{OPENQUOTES}여기는 쓰레기가 여기 저기 널려있어{ENDQUOTES} +STR_1507 :{SMALLFONT}{OPENQUOTES}공원 출구를 찾을 수 없어{ENDQUOTES} +STR_1508 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 내리고 싶어{ENDQUOTES} +STR_1509 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 나가고 싶어{ENDQUOTES} +STR_1510 :{SMALLFONT}{OPENQUOTES}{STRINGID}(은)는 안전하지 않아서 가지 않을래{ENDQUOTES} +STR_1511 :{SMALLFONT}{OPENQUOTES}이 길은 역겨워{ENDQUOTES} +STR_1512 :{SMALLFONT}{OPENQUOTES}여긴 사람이 너무 많아{ENDQUOTES} +STR_1513 :{SMALLFONT}{OPENQUOTES}여기는 시설이 막 파괴되어 있어{ENDQUOTES} +STR_1514 :{SMALLFONT}{OPENQUOTES}풍경이 참 좋다!{ENDQUOTES} +STR_1515 :{SMALLFONT}{OPENQUOTES}이 공원은 정말 깨끗하고 깔끔한 것 같아{ENDQUOTES} +STR_1516 :{SMALLFONT}{OPENQUOTES}분수대가 참 훌륭해{ENDQUOTES} +STR_1517 :{SMALLFONT}{OPENQUOTES}여기 음악 좋다{ENDQUOTES} +STR_1518 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 풍선은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1519 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 캐릭터 인형은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1520 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 공원 지도는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1521 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 탑승 사진은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1522 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 우산은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1523 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 음료수는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1524 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 햄버거는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1525 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 감자칩은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1526 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 아이스크림은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1527 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 솜사탕은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1528 : +STR_1529 : +STR_1530 : +STR_1531 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 피자는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1532 : +STR_1533 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 팝콘은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1534 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 핫도그는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1535 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 문어발은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1536 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 모자는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1537 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 사과 토피 사탕은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1538 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 티셔츠는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1539 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 도넛은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1540 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 커피는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1541 : +STR_1542 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 프라이드 치킨은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1543 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 레모네이드는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1544 : +STR_1545 : +STR_1546 : +STR_1547 : +STR_1548 : +STR_1549 : +STR_1550 :{SMALLFONT}{OPENQUOTES}와우!{ENDQUOTES} +STR_1551 :{SMALLFONT}{OPENQUOTES}누가 지켜보는 것 같은 이상한 기분이 들어{ENDQUOTES} +STR_1552 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 풍선에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1553 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 캐릭터 인형에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1554 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 공원 지도에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1555 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 탑승 사진에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1556 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 우산에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1557 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 음료수에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1558 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 햄버거에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1559 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 감자칩에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1560 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 아이스크립에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1561 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 솜사탕에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1562 : +STR_1563 : +STR_1564 : +STR_1565 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 피자에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1566 : +STR_1567 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 팝콘에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1568 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 핫도그에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1569 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 문어발에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1570 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 모자에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1571 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 사과 토피 사탕에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1572 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 티셔츠에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1573 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 도넛에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1574 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 커피에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1575 : +STR_1576 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 프라이드 치킨에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1577 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 레모네이드에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1578 : +STR_1579 : +STR_1580 : +STR_1581 : +STR_1582 : +STR_1583 : +STR_1584 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 탑승 사진은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1585 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 탑승 사진은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1586 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 탑승 사진은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1587 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 프레첼은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1588 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 핫 초코는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1589 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 아이스 티는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1590 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 휜넬 케이크는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1591 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 선글라스는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1592 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 고기국수는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1593 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 볶음쌀국수은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1594 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 만둣국은 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1595 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 미트볼 스프는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1596 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 과일 주스는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1597 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 두유는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1598 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 수정과는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1599 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 샌드위치는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1600 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 쿠키는 가격이 참 적당한 것 같아{ENDQUOTES} +STR_1601 : +STR_1602 : +STR_1603 : +STR_1604 :{SMALLFONT}{OPENQUOTES}{STRINGID}에서 산 구운 소시지는 가격이 참 적당한 것 같아{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}{STRINGID}의 탑승 사진에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1617 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 탑승 사진에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1618 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 탑승 사진에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1619 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 프레첼에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1620 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 핫 초코에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1621 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 아이스 티에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1622 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 휜넬 케이크에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1623 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 선글라스에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1624 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 고기 국수에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1625 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 볶음쌀국수에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1626 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 만둣국에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1627 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 미트볼 스프에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1628 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 과일 주스에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1629 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 두유에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1630 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 수정과에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1631 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 샌드위치에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1632 :{SMALLFONT}{OPENQUOTES}{STRINGID}의 쿠키에 돈을 쓰고 싶지 않아{ENDQUOTES} +STR_1633 : +STR_1634 : +STR_1635 : +STR_1636 :{SMALLFONT}{OPENQUOTES}{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}살려주세요! 절 내려주세요!{ENDQUOTES} +STR_1649 :{SMALLFONT}{OPENQUOTES}돈이 다 떨어져가고 있어요!{ENDQUOTES} +STR_1650 :{SMALLFONT}{OPENQUOTES}와우! 새 놀이기구가 지어지고 있어요!{ENDQUOTES} +STR_1651 :{SMALLFONT}{OPENQUOTES}멋진 놀이기구에요! 하지만 피닉스만큼 멋지진 않네요...{ENDQUOTES} +STR_1652 :{SMALLFONT}{OPENQUOTES}정말 흥분돼요! 인타민 공원의 놀이기구에요!{ENDQUOTES} +STR_1653 :{SMALLFONT}{OPENQUOTES}...그리고 드디어 {STRINGID}에 왔어요!{ENDQUOTES} +STR_1654 :{WINDOW_COLOUR_2}최근 생각: +STR_1655 :{SMALLFONT}{BLACK}땅 위에 보도 건설 +STR_1656 :{SMALLFONT}{BLACK}다리나 터널 보도를 건설 +STR_1657 :{WINDOW_COLOUR_2}좋아하는 놀이기구 +STR_1658 :{WINDOW_COLOUR_2}격렬도: {BLACK}{COMMA16} 이하 +STR_1659 :{WINDOW_COLOUR_2}격렬도: {BLACK}{COMMA16}에서 {COMMA16} 사이 +STR_1660 :{WINDOW_COLOUR_2}격렬도: {BLACK}{COMMA16} 이상 +STR_1661 :{WINDOW_COLOUR_2}멀미 참을성: {BLACK}{STRINGID} +STR_1662 :{WINDOW_COLOUR_2}행복도: +STR_1663 :{WINDOW_COLOUR_2}멀미도: +STR_1664 :{WINDOW_COLOUR_2}에너지: +STR_1665 :{WINDOW_COLOUR_2}배고픔: +STR_1666 :{WINDOW_COLOUR_2}목마름: +STR_1667 :{WINDOW_COLOUR_2}화장실: +STR_1668 :{WINDOW_COLOUR_2}만족도: {BLACK}알 수 없음 +STR_1669 :{WINDOW_COLOUR_2}만족도: {BLACK}{COMMA16}% +STR_1670 :{WINDOW_COLOUR_2}총 고객: {BLACK}{COMMA32} +STR_1671 :{WINDOW_COLOUR_2}총 수익: {BLACK}{CURRENCY2DP} +STR_1672 :브레이크 +STR_1673 :회전 컨트롤 토글 트랙 +STR_1674 :브레이크 속력 +STR_1675 :{POP16}{VELOCITY} +STR_1676 :{SMALLFONT}{BLACK}브레이크의 제한 속도를 설정하세요 +STR_1677 :{WINDOW_COLOUR_2}인기도: {BLACK}알 수 없음 +STR_1678 :{WINDOW_COLOUR_2}인기도: {BLACK}{COMMA16}% +STR_1679 :나선 상승 (왼쪽) +STR_1680 :나선 상승 (오른쪽) +STR_1681 :나선 하강 (왼쪽) +STR_1682 :나선 하강 (오른쪽) +STR_1683 :기본 크기 2 x 2 +STR_1684 :기본 크기 4 x 4 +STR_1685 :기본 크기 2 x 4 +STR_1686 :기본 크기 5 x 1 +STR_1687 :물 튀김 +STR_1688 :기본 크기 4 x 1 +STR_1689 :블록 브레이크 +STR_1690 :{WINDOW_COLOUR_2}{STRINGID}{NEWLINE}{BLACK}{STRINGID} +STR_1691 :{WINDOW_COLOUR_2} 비용: {BLACK}{CURRENCY} +STR_1692 :{WINDOW_COLOUR_2} 비용: {BLACK}{CURRENCY} 이상 +STR_1693 :{SMALLFONT}{BLACK}손님 +STR_1694 :{SMALLFONT}{BLACK}직원 +STR_1695 :{SMALLFONT}{BLACK}수익 및 지출 +STR_1696 :{SMALLFONT}{BLACK}고객 정보 +STR_1697 :대기줄에 놓을 수 없습니다 +STR_1698 :대기줄에만 놓을 수 있습니다 +STR_1699 :게임에 사람이 너무 많습니다 +STR_1700 :새 미화원 고용 +STR_1701 :새 정비기술자 고용 +STR_1702 :새 경비원 고용 +STR_1703 :새 엔터테이너 고용 +STR_1704 :새 직원을 고용할 수 없습니다... +STR_1705 :{SMALLFONT}{BLACK}이 직원을 해고합니다 +STR_1706 :{SMALLFONT}{BLACK}이 사람을 새 장소에 옮깁니다 +STR_1707 :게임에 직원이 너무 많습니다 +STR_1708 :{SMALLFONT}{BLACK}이 직원이 순찰할 영역을 지정합니다 +STR_1709 :직원 해고 +STR_1710 :예 +STR_1711 :{WINDOW_COLOUR_1}{STRINGID}(을)를 정말 해고하시겠습니까? +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_1716 :적합하지 않은 공원 이름입니다 +STR_1717 :공원 이름을 바꿀 수 없습니다... +STR_1718 :공원 이름 +STR_1719 :공원 이름을 입력하세요: +STR_1720 :{SMALLFONT}{BLACK}공원 이름 바꾸기 +STR_1721 :공원 닫힘 +STR_1722 :공원 열림 +STR_1723 :공원을 열 수 없습니다... +STR_1724 :공원을 닫을 수 없습니다... +STR_1725 :땅을 구입할 수 없습니다... +STR_1726 :판매 중인 땅이 아닙니다! +STR_1727 :판매 중인 건설권이 아닙니다! +STR_1728 :이 곳의 건설권을 구입할 수 없습니다... +STR_1729 :공원 소유의 땅이 아닙니다! +STR_1730 :{RED}닫힘 - - +STR_1731 :{WHITE}{STRINGID} - - +STR_1732 :건설 +STR_1733 :모드 +STR_1734 :{WINDOW_COLOUR_2}바퀴 수: +STR_1735 :{SMALLFONT}{BLACK}서킷을 돌 바퀴 수를 설정합니다 +STR_1736 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1737 :{COMMA16} +STR_1738 :바퀴 수를 변경할 수 없습니다... +STR_1739 :레이스 우승자 : 손님 {INT32} +STR_1740 :레이스 우승자 : {STRINGID} +STR_1741 :아직 건설되지 않았습니다! +STR_1742 :{WINDOW_COLOUR_2}최대 놀이기구 탑승 인원: +STR_1743 :{SMALLFONT}{BLACK}이 놀이기구에 한 번에 탑승할 수 있는 최대 인원 수를 설정합니다 +STR_1744 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1745 :{COMMA16} +STR_1746 :변경할 수 없습니다... +STR_1747 :{WINDOW_COLOUR_2}탑승 시간 제한: +STR_1748 :{SMALLFONT}{BLACK}놀이기구 탑승 시간 제한 +STR_1749 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{DURATION} +STR_1750 :{DURATION} +STR_1751 :놀이기구의 탑승 시간을 변경할 수 없습니다... +STR_1752 :{SMALLFONT}{BLACK}공원에 있는 손님의 모든 명단을 보여줍니다 +STR_1753 :{SMALLFONT}{BLACK}공원에 있는 손님을 항목별로 묶어서 보여줍니다 +STR_1754 :{BLACK}{COMMA16} 손님 +STR_1755 :{BLACK}{COMMA16} 손님 +STR_1756 :{WINDOW_COLOUR_2}입장료: +STR_1757 :{WINDOW_COLOUR_2}신뢰도: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1758 :{SMALLFONT}{BLACK}건설 모드 +STR_1759 :{SMALLFONT}{BLACK}이동 모드 +STR_1760 :{SMALLFONT}{BLACK}채우기 모드 +STR_1761 :{SMALLFONT}{BLACK}이 방향으로 미로 건설 +STR_1762 :폭포 +STR_1763 :급류 +STR_1764 :Log Bumps +STR_1765 :탑승 사진 섹션 +STR_1766 :역방향 턴테이블 +STR_1767 :회전 터널 +STR_1768 :스윙 회수를 변경할 수 없습니다... +STR_1769 :{WINDOW_COLOUR_2}스윙 회수: +STR_1770 :{SMALLFONT}{BLACK}가장 높은 스윙의 회수를 지정합니다 +STR_1771 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1772 :{COMMA16} +STR_1773 :한 놀이기구에는 하나의 탑승 사진 섹션만 만들 수 있습니다 +STR_1774 :한 놀이기구에는 하나의 케이블 리프트만 만들 수 있습니다 +STR_1775 :끄기 +STR_1776 :켜기 +STR_1777 :{WINDOW_COLOUR_2}음악 +STR_1778 :{STRINGID} - - +STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} 팬더 복장 +STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} 호랑이 복장 +STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} 코끼리 복장 +STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} 로마 전사 복장 +STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} 고릴라 복장 +STR_1784 :{INLINE_SPRITE}{03}{20}{00}{00} 눈사람 복장 +STR_1785 :{INLINE_SPRITE}{04}{20}{00}{00} 기사 복장 +STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} 우주비행사 복장 +STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} 산적 복장 +STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} 보안관 복장 +STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} 해적 복장 +STR_1790 :{SMALLFONT}{BLACK}이 직종의 유니폼 색상을 선택하세요 +STR_1791 :{WINDOW_COLOUR_2}유니폼 색상: +STR_1792 :{STRINGID} 고장 연락을 받음 +STR_1793 :점검을 위해 {STRINGID}(으)로 이동 중 +STR_1794 :{STRINGID} 수리 중 +STR_1795 :라디오 연락에 응답 중 +STR_1796 :고장이 나서 수리가 필요함 +STR_1797 :이 놀이기구에서는 변경할 수 없는 설정입니다 +STR_1798 :쇼용돌이 +STR_1799 :{POP16}{POP16}{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1800 :안전 차단 +STR_1801 :안전 벨트가 닫힌 채로 안 열림 +STR_1802 :안전 벨트가 열린 채로 안 닫힘 +STR_1803 :문이 닫힌 채로 안 열림 +STR_1804 :문이 열린 채로 안 닫힘 +STR_1805 :차량 고장 +STR_1806 :브레이크 고장 +STR_1807 :제어 불능 +STR_1808 :{WINDOW_COLOUR_2}최근 고장: {BLACK}{STRINGID} +STR_1809 :{WINDOW_COLOUR_2}현재 고장: {OUTLINE}{RED}{STRINGID} +STR_1810 :{WINDOW_COLOUR_2}보유 중: +STR_1811 :여기에 건설할 수 없습니다... +STR_1812 :{SMALLFONT}{BLACK}{STRINGID} +STR_1813 :기타 오브젝트 +STR_1814 :행동 +STR_1815 :생각 +STR_1816 :{SMALLFONT}{BLACK}손님 목록에서 보여줄 정보의 종류를 선택하세요 +STR_1817 :({COMMA16}) +STR_1818 :{WINDOW_COLOUR_2}모든 손님 +STR_1819 :{WINDOW_COLOUR_2}모든 손님 (항목별 분류) +STR_1820 :{WINDOW_COLOUR_2}{STRINGID} 손님 +STR_1821 :{WINDOW_COLOUR_2}{STRINGID} 손님 생각 +STR_1822 :{WINDOW_COLOUR_2}{POP16}{STRINGID}에 대한 손님 생각 +STR_1823 :{SMALLFONT}{BLACK}이 놀이기구/시설에 대한 손님들의 생각을 보여줍니다 +STR_1824 :{SMALLFONT}{BLACK}이 놀이기구/시설에 있는 손님을 보여줍니다 +STR_1825 :{SMALLFONT}{BLACK}이 놀이기구/시설에서 기다리고 있는 손님을 보여줍니다 +STR_1826 :상태 +STR_1827 :인기도 +STR_1828 :만족도 +STR_1829 :수익 +STR_1830 :대기 길이 +STR_1831 :대기 시간 +STR_1832 :신뢰도 +STR_1833 :고장률 +STR_1834 :이 놀이기구를 좋아하는 손님 수 +STR_1835 :인기도 : 알 수 없음 +STR_1836 :인기도: {COMMA16}% +STR_1837 :만족도: 알 수 없움 +STR_1838 :만족도: {COMMA16}% +STR_1839 :신뢰도: {COMMA16}% +STR_1840 :고장률: {COMMA16}% +STR_1841 :수익: 시간당 {CURRENCY2DP} +STR_1842 :좋아하는 손님 수: {COMMA16}명 +STR_1843 :좋아하는 손님 수: {COMMA16}명 +STR_1844 :{SMALLFONT}{BLACK}놀이기구/시설 목록에서 보여줄 정보를 선택하세요 +STR_1845 :{MONTHYEAR} +STR_1846 :{COMMA16} 손님 +STR_1847 :{INLINE_SPRITE}{11}{20}{00}{00}{COMMA16} 손님 +STR_1848 :{INLINE_SPRITE}{10}{20}{00}{00}{COMMA16} 손님 +STR_1849 :{WINDOW_COLOUR_2}음악 재생 +STR_1850 :{SMALLFONT}{BLACK}이 놀이기구에 배경음악을 재생할지를 선택합니다 +STR_1851 :{WINDOW_COLOUR_2}유지비: {BLACK}시간당 {CURRENCY2DP} +STR_1852 :{WINDOW_COLOUR_2}유지비: {BLACK}알 수 없음 +STR_1853 :{WINDOW_COLOUR_2}건설 시점: {BLACK}올해 +STR_1854 :{WINDOW_COLOUR_2}건설 시점: {BLACK}작년 +STR_1855 :{WINDOW_COLOUR_2}건설 시점: {BLACK}{COMMA16}년 전 +STR_1856 :{WINDOW_COLOUR_2}항목당 판매 이익: {BLACK}{CURRENCY2DP} +STR_1857 :{WINDOW_COLOUR_2}항목당 손실: {BLACK}{CURRENCY2DP} +STR_1858 :{WINDOW_COLOUR_2}가격: {BLACK}{CURRENCY2DP}/월 +STR_1859 :미화원 +STR_1860 :정비기술자 +STR_1861 :경비원 +STR_1862 :엔터테이너 +STR_1863 :미화원 +STR_1864 :정비기술자 +STR_1865 :경비원 +STR_1866 :엔터테이너 +STR_1867 :{BLACK}{COMMA16} {STRINGID} +STR_1868 :회전 수를 변경할 수 없습니다... +STR_1869 :{WINDOW_COLOUR_2}회전 수: +STR_1870 :{SMALLFONT}{BLACK}회전 수를 설정합니다 +STR_1871 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1872 :{COMMA16} +STR_1873 :{WINDOW_COLOUR_2}수익: 시간당 {BLACK}{CURRENCY2DP} +STR_1874 :{WINDOW_COLOUR_2}순익: 시간당 {BLACK}{CURRENCY2DP} +STR_1875 :{BLACK} {SPRITE}{BLACK} {STRINGID} +STR_1876 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{251}{19}{00}{00}놀이기구 점검 +STR_1877 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{252}{19}{00}{00}놀이기구 수리 +STR_1878 :{WINDOW_COLOUR_2}점검: +STR_1879 :매 10분마다 +STR_1880 :매 20분마다 +STR_1881 :매 30분마다 +STR_1882 :매 45분마다 +STR_1883 :매 시간마다 +STR_1884 :매 2시간마다 +STR_1885 :점검 안 함 +STR_1886 :{STRINGID} 점검 중 +STR_1887 :{WINDOW_COLOUR_2}지난 점검 이후 지난 시간: {BLACK}{COMMA16}분 +STR_1888 :{WINDOW_COLOUR_2}지난 점검 이후 지난 시간: {BLACK}4시간 이상 +STR_1889 :{WINDOW_COLOUR_2}고장률: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1890 :{SMALLFONT}{BLACK}정비기술자가 이 놀이기구를 얼마나 자주 점검할 지 선택합니다 +STR_1891 :공원에 아직 {STRINGID}(이)가 없습니다! +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 :<더 이상 사용하지 않음> +STR_1893 :<더 이상 사용하지 않음> +STR_1894 :{WINDOW_COLOUR_2}{STRINGID} 판매: {BLACK}{COMMA32} +STR_1895 :{SMALLFONT}{BLACK}새 놀이기구/시설 건설 +STR_1896 :{WINDOW_COLOUR_2}수익/지출 +STR_1897 :{WINDOW_COLOUR_2}놀이기구 건설비 +STR_1898 :{WINDOW_COLOUR_2}놀이기구 유지비 +STR_1899 :{WINDOW_COLOUR_2}땅 구입 +STR_1900 :{WINDOW_COLOUR_2}지형 편집 +STR_1901 :{WINDOW_COLOUR_2}공원 입장료 +STR_1902 :{WINDOW_COLOUR_2}놀이기구 탑승료 +STR_1903 :{WINDOW_COLOUR_2}상점 판매 +STR_1904 :{WINDOW_COLOUR_2}상점 재고 +STR_1905 :{WINDOW_COLOUR_2}음식/음료 판매 +STR_1906 :{WINDOW_COLOUR_2}음식/음료 재고 +STR_1907 :{WINDOW_COLOUR_2}직원 급여 +STR_1908 :{WINDOW_COLOUR_2}광고 +STR_1909 :{WINDOW_COLOUR_2}연구 +STR_1910 :{WINDOW_COLOUR_2}대출 이자 +STR_1911 :{BLACK} 금리: {COMMA16}%/년 +STR_1912 :{MONTH} +STR_1913 :{BLACK}+{CURRENCY2DP} +STR_1914 :{BLACK}{CURRENCY2DP} +STR_1915 :{RED}{CURRENCY2DP} +STR_1916 :{WINDOW_COLOUR_2}대출: +STR_1917 :{POP16}{POP16}{POP16}{CURRENCY} +STR_1918 :더 이상 돈을 빌릴 수 없습니다! +STR_1919 :돈이 충분하지 않습니다! +STR_1920 :대출을 갚을 수 없습니다! +STR_1921 :{SMALLFONT}{BLACK}새로운 게임을 시작합니다 +STR_1922 :{SMALLFONT}{BLACK}저장된 게임을 계속해서 플레이합니다 +STR_1923 :{SMALLFONT}{BLACK}튜토리얼을 봅니다 +STR_1924 :{SMALLFONT}{BLACK}게임을 종료합니다 +STR_1925 :사람을 여기에 놓을 수 없습니다... +STR_1926 :{SMALLFONT} +STR_1927 :{YELLOW}{STRINGID} 고장 발생 +STR_1928 :{RED}{STRINGID} 충돌! +STR_1929 :{RED}{STRINGID} - 아직 수리되지 않음{NEWLINE}정비기술자의 위치와 업무 효율을 점검하세요 +STR_1930 :{SMALLFONT}{BLACK}이 손님의 행동을 추적합니다. (이 설정을 켜면 이 손님의 모든 행동을 메시지 창으로 알려줍니다) +STR_1931 :{STRINGID} - {STRINGID}(을)를 타기 위해 대기줄에 섰습니다 +STR_1932 :{STRINGID} - {STRINGID}(을)를 탔습니다 +STR_1933 :{STRINGID} - {STRINGID} 안에 있습니다 +STR_1934 :{STRINGID} - {STRINGID}(을)를 떠났습니다 +STR_1935 :{STRINGID} - 공원을 떠났습니다 +STR_1936 :{STRINGID} - {STRINGID}(을)를 샀습니다 +STR_1937 :{SMALLFONT}{BLACK}이 메시지의 주제에 대한 정보를 보여줍니다 +STR_1938 :{SMALLFONT}{BLACK}손님 주변으로 화면을 이동합니다 +STR_1939 :{SMALLFONT}{BLACK}직원 주변으로 화면을 이동합니다 +STR_1940 :{SMALLFONT}{BLACK}이 손님의 행복도, 에너지, 배고픔 등의 수치를 보여줍니다 +STR_1941 :{SMALLFONT}{BLACK}이 손님이 이용한 놀이기구를 보여줍니다 +STR_1942 :{SMALLFONT}{BLACK}이 손님의 재정 상황을 보여줍니다 +STR_1943 :{SMALLFONT}{BLACK}손님의 최근 생각을 보여줍니다 +STR_1944 :{SMALLFONT}{BLACK}손님이 가지고 있는 물건을 보여줍니다 +STR_1945 :{SMALLFONT}{BLACK}이 직원이 할 일이나 설정을 보여줍니다 +STR_1946 :{SMALLFONT}{BLACK}이 엔터테이너의 복장을 선택합니다 +STR_1947 :{SMALLFONT}{BLACK}선택한 직원의 행동 영역을 보여주고 가까운 직원을 거기로 이동시킵니다 +STR_1948 :{SMALLFONT}{BLACK}선택한 종류의 직원을 새로 고용합니다 +STR_1949 :재정 요약 +STR_1950 :재정 그래프 +STR_1951 :공원 가치 그래프 +STR_1952 :수익 그래프 +STR_1953 :광고 +STR_1954 :연구 자금 +STR_1955 :{WINDOW_COLOUR_2}바퀴 수: +STR_1956 :{SMALLFONT}{BLACK}탑승 당 바퀴 수 +STR_1957 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1958 :{COMMA16} +STR_1959 :바퀴 수를 변경할 수 없습니다... +STR_1960 :{WINDOW_COLOUR_2}풍선 가격: +STR_1961 :{WINDOW_COLOUR_2}캐릭터 인형 가격: +STR_1962 :{WINDOW_COLOUR_2}공원 지도 가격: +STR_1963 :{WINDOW_COLOUR_2}탑승 사진 가격: +STR_1964 :{WINDOW_COLOUR_2}우산 가격: +STR_1965 :{WINDOW_COLOUR_2}음료수 가격: +STR_1966 :{WINDOW_COLOUR_2}햄버거 가격: +STR_1967 :{WINDOW_COLOUR_2}감자칩 가격: +STR_1968 :{WINDOW_COLOUR_2}아이스크림 가격: +STR_1969 :{WINDOW_COLOUR_2}솜사탕 가격: +STR_1970 :{WINDOW_COLOUR_2} +STR_1971 :{WINDOW_COLOUR_2} +STR_1972 :{WINDOW_COLOUR_2} +STR_1973 :{WINDOW_COLOUR_2}피자 가격: +STR_1974 :{WINDOW_COLOUR_2} +STR_1975 :{WINDOW_COLOUR_2}팝콘 가격: +STR_1976 :{WINDOW_COLOUR_2}핫도그 가격: +STR_1977 :{WINDOW_COLOUR_2}문어발 가격: +STR_1978 :{WINDOW_COLOUR_2}모자 가격: +STR_1979 :{WINDOW_COLOUR_2}사과 토피 사탕 가격: +STR_1980 :{WINDOW_COLOUR_2}티셔츠 가격: +STR_1981 :{WINDOW_COLOUR_2}도넛 가격: +STR_1982 :{WINDOW_COLOUR_2}커피 가격: +STR_1983 :{WINDOW_COLOUR_2} +STR_1984 :{WINDOW_COLOUR_2}치킨 가격: +STR_1985 :{WINDOW_COLOUR_2}레모네이드 가격: +STR_1986 :{WINDOW_COLOUR_2} +STR_1987 :{WINDOW_COLOUR_2} +STR_1988 :풍선 +STR_1989 :캐릭터 인형 +STR_1990 :공원 지도 +STR_1991 :탑승 사진 +STR_1992 :우산 +STR_1993 :음료수 +STR_1994 :햄버거 +STR_1995 :감자칩 +STR_1996 :아이스크림 +STR_1997 :솜사탕 +STR_1998 :빈 캔 +STR_1999 :쓰레기 +STR_2000 :빈 햄버거 박스 +STR_2001 :피자 +STR_2002 :쿠폰 +STR_2003 :팝콘 +STR_2004 :핫도그 +STR_2005 :문어발 +STR_2006 :모자 +STR_2007 :사과 토피 사탕 +STR_2008 :티셔츠 +STR_2009 :도넛 +STR_2010 :커피 +STR_2011 :빈 컵 +STR_2012 :치킨 +STR_2013 :레모네이드 +STR_2014 :빈 박스 +STR_2015 :빈 병 +STR_2016 :풍선 +STR_2017 :캐릭터 인형 +STR_2018 :공원 지도 +STR_2019 :탑승 사진 +STR_2020 :우산 +STR_2021 :음료수 +STR_2022 :햄버거 +STR_2023 :감자칩 +STR_2024 :아이스크림 +STR_2025 :솜사탕 +STR_2026 :빈 캔 +STR_2027 :쓰레기 +STR_2028 :빈 햄버거 박스 +STR_2029 :피자 +STR_2030 :쿠폰 +STR_2031 :팝콘 +STR_2032 :핫도그 +STR_2033 :문어발 +STR_2034 :모자 +STR_2035 :사과 토피 사탕 +STR_2036 :티셔츠 +STR_2037 :도넛 +STR_2038 :커피 +STR_2039 :빈 컵 +STR_2040 :치킨 +STR_2041 :레모네이드 +STR_2042 :빈 박스 +STR_2043 :빈 병 +STR_2044 :풍선 +STR_2045 :캐릭터 인형 +STR_2046 :공원 지도 +STR_2047 :탑승 사진 +STR_2048 :우산 +STR_2049 :음료수 +STR_2050 :햄버거 +STR_2051 :감자칩 +STR_2052 :아이스크림 +STR_2053 :솜사탕 +STR_2054 :빈 캔 +STR_2055 :쓰레기 +STR_2056 :빈 햄버거 박스 +STR_2057 :피자 +STR_2058 :쿠폰 +STR_2059 :팝콘 +STR_2060 :핫도그 +STR_2061 :문어발 +STR_2062 :모자 +STR_2063 :사과 토피 사탕 +STR_2064 :티셔츠 +STR_2065 :도넛 +STR_2066 :커피 +STR_2067 :빈 컵 +STR_2068 :치킨 +STR_2069 :레모네이드 +STR_2070 :빈 박스 +STR_2071 :빈 병 +STR_2072 :{OPENQUOTES}{STRINGID}{ENDQUOTES} 풍선 +STR_2073 :{OPENQUOTES}{STRINGID}{ENDQUOTES} 캐릭터 인형 +STR_2074 :{STRINGID} 지도 +STR_2075 :{STRINGID} 탑승 사진 +STR_2076 :{OPENQUOTES}{STRINGID}{ENDQUOTES} 우산 +STR_2077 :음료수 +STR_2078 :햄버거 +STR_2079 :감자칩 +STR_2080 :아이스크림 +STR_2081 :솜사탕 +STR_2082 :빈 캔 +STR_2083 :쓰레기 +STR_2084 :빈 햄버거 박스 +STR_2085 :피자 +STR_2086 :{STRINGID} 쿠폰 +STR_2087 :팝콘 +STR_2088 :핫도그 +STR_2089 :문어발 +STR_2090 :{OPENQUOTES}{STRINGID}{ENDQUOTES} 모자 +STR_2091 :사과 토피 사탕 +STR_2092 :{OPENQUOTES}{STRINGID}{ENDQUOTES} 티셔츠 +STR_2093 :도넛 +STR_2094 :커피 +STR_2095 :빈 컵 +STR_2096 :치킨 +STR_2097 :레모네이드 +STR_2098 :빈 박스 +STR_2099 :빈 병 +STR_2100 :{WINDOW_COLOUR_2}탑승 사진 가격: +STR_2101 :{WINDOW_COLOUR_2}탑승 사진 가격: +STR_2102 :{WINDOW_COLOUR_2}탑승 사진 가격: +STR_2103 :{WINDOW_COLOUR_2}프레첼 가격: +STR_2104 :{WINDOW_COLOUR_2}핫초코 가격: +STR_2105 :{WINDOW_COLOUR_2}아이스 티 가격: +STR_2106 :{WINDOW_COLOUR_2}휜넬 케이크 가격: +STR_2107 :{WINDOW_COLOUR_2}선글라스 가격: +STR_2108 :{WINDOW_COLOUR_2}고기 국수 가격: +STR_2109 :{WINDOW_COLOUR_2}볶음쌀국수 가격: +STR_2110 :{WINDOW_COLOUR_2}만둣국 가격: +STR_2111 :{WINDOW_COLOUR_2}미트볼 스프 가격: +STR_2112 :{WINDOW_COLOUR_2}과일 주스 가격: +STR_2113 :{WINDOW_COLOUR_2}두유 가격: +STR_2114 :{WINDOW_COLOUR_2}수정과 가격: +STR_2115 :{WINDOW_COLOUR_2}샌드위치 가격: +STR_2116 :{WINDOW_COLOUR_2}쿠키 가격: +STR_2117 :{WINDOW_COLOUR_2} +STR_2118 :{WINDOW_COLOUR_2} +STR_2119 :{WINDOW_COLOUR_2} +STR_2120 :{WINDOW_COLOUR_2}구운 소시지 가격: +STR_2121 :{WINDOW_COLOUR_2} +STR_2122 :탑승 사진 +STR_2123 :탑승 사진 +STR_2124 :탑승 사진 +STR_2125 :프레첼 +STR_2126 :핫초코 +STR_2127 :아이스 티 +STR_2128 :휜넬 케이크 +STR_2129 :선글라스 +STR_2130 :고기 국수 +STR_2131 :볶음쌀국수 +STR_2132 :만둣국 +STR_2133 :미트볼 스프 +STR_2134 :과일 주스 +STR_2135 :두유 +STR_2136 :수정과 +STR_2137 :샌드위치 +STR_2138 :쿠키 +STR_2139 :빈 사발 +STR_2140 :빈 음료수 통 +STR_2141 :빈 주스 컵 +STR_2142 :구운 소시지 +STR_2143 :빈 사발 +STR_2144 :탑승 사진 +STR_2145 :탑승 사진 +STR_2146 :탑승 사진 +STR_2147 :프레첼 +STR_2148 :핫초코 +STR_2149 :아이스 티 +STR_2150 :휜넬 케이크 +STR_2151 :선글라스 +STR_2152 :고기 국수 +STR_2153 :볶음쌀국수 +STR_2154 :만둣국 +STR_2155 :미트볼 스프 +STR_2156 :과일 주스 +STR_2157 :두유 +STR_2158 :수정과 +STR_2159 :샌드위치 +STR_2160 :쿠키 +STR_2161 :빈 사발 +STR_2162 :빈 음료수 통 +STR_2163 :빈 주스 컵 +STR_2164 :구운 소시지 +STR_2165 :빈 사발 +STR_2166 :탑승 사진 +STR_2167 :탑승 사진 +STR_2168 :탑승 사진 +STR_2169 :프레첼 +STR_2170 :핫초코 +STR_2171 :아이스 티 +STR_2172 :휜넬 케이크 +STR_2173 :선글라스 +STR_2174 :고기 국수 +STR_2175 :볶음쌀국수 +STR_2176 :만둣국 +STR_2177 :미트볼 스프 +STR_2178 :과일 주스 +STR_2179 :두유 +STR_2180 :수정과 +STR_2181 :샌드위치 +STR_2182 :쿠키 +STR_2183 :빈 사발 +STR_2184 :빈 음료수 통 +STR_2185 :빈 주스 컵 +STR_2186 :구운 소시지 +STR_2187 :빈 사발 +STR_2188 :{STRINGID}의 탑승 사진 +STR_2189 :{STRINGID}의 탑승 사진 +STR_2190 :{STRINGID}의 탑승 사진 +STR_2191 :프레첼 +STR_2192 :핫초코 +STR_2193 :아이스 티 +STR_2194 :휜넬 케이크 +STR_2195 :선글라스 +STR_2196 :고기 국수 +STR_2197 :볶음쌀국수 +STR_2198 :만둣국 +STR_2199 :미트볼 스프 +STR_2200 :과일 주스 +STR_2201 :두유 +STR_2202 :수정과 +STR_2203 :샌드위치 +STR_2204 :쿠키 +STR_2205 :빈 사발 +STR_2206 :빈 음료수 통 +STR_2207 :빈 주스 컵 +STR_2208 :구운 소시지 +STR_2209 :빈 사발 +STR_2210 :{SMALLFONT}{BLACK}공원의 미화원 목록을 보여줍니다 +STR_2211 :{SMALLFONT}{BLACK}공원의 정비기술자 목록을 보여줍니다 +STR_2212 :{SMALLFONT}{BLACK}공원의 경비원 목록을 보여줍니다 +STR_2213 :{SMALLFONT}{BLACK}공원의 엔터테이너 목록을 보여줍니다 +STR_2214 :게임 일시정지 중에는 건설할 수 없습니다! +STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) +STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F +STR_2218 :{RED}{STRINGID}(놀이기구: {STRINGID})(이)가 {STRINGID}(으)로 아직 돌아오지 않았습니다!{NEWLINE}놀이기구가 멈춰있거나 Check whether it is stuck or has 상점ed +STR_2219 :{RED}{COMMA16}명의 손님이 {STRINGID} 사고로 사망하였습니다! +STR_2220 :{WINDOW_COLOUR_2}공원 등급: {BLACK}{COMMA16} +STR_2221 :{SMALLFONT}{BLACK}공원 등급: {COMMA16} +STR_2222 :{SMALLFONT}{BLACK}{STRINGID} +STR_2223 :{WINDOW_COLOUR_2}공원에 있는 손님 수: {BLACK}{COMMA16} +STR_2224 :{WINDOW_COLOUR_2}재정: {BLACK}{CURRENCY2DP} +STR_2225 :{WINDOW_COLOUR_2}재정: {RED}{CURRENCY2DP} +STR_2226 :{WINDOW_COLOUR_2}공원 가치: {BLACK}{CURRENCY} +STR_2227 :{WINDOW_COLOUR_2}회사 가치: {BLACK}{CURRENCY} +STR_2228 :{WINDOW_COLOUR_2}음식/음료수 또는 물건으로 벌어들인{NEWLINE}지난달 수익: {BLACK}{CURRENCY} +STR_2229 :수직으로 상승 +STR_2230 :수직 트랙 +STR_2231 :낙하 브레이크 +STR_2232 :케이블 리프트 힐 +STR_2233 :{SMALLFONT}{BLACK}공원 정보 +STR_2234 :최근 메시지 +STR_2235 :{SMALLFONT}{STRINGID} {STRINGID} +STR_2236 :1월 +STR_2237 :2월 +STR_2238 :3월 +STR_2239 :4월 +STR_2240 :5월 +STR_2241 :6월 +STR_2242 :7월 +STR_2243 :8월 +STR_2244 :9월 +STR_2245 :10월 +STR_2246 :11월 +STR_2247 :12월 +STR_2248 :놀이기구/시설을 파괴할 수 없습니다... +STR_2249 :{BABYBLUE}새 놀이기구/시설을 사용할 수 있습니다:{NEWLINE}{STRINGID} +STR_2250 :{BABYBLUE}새 풍경/테마를 사용할 수 있습니다:{NEWLINE}{STRINGID} +STR_2251 :보도 위에만 지을 수 있습니다! +STR_2252 :보도를 가로질러야만 설치할 수 있습니다! +STR_2253 :운송용 놀이기구 +STR_2254 :얌전한 놀이기구 +STR_2255 :롤러코스터 +STR_2256 :스릴있는 놀이기구 +STR_2257 :물 놀이기구 +STR_2258 :상점 & 매점 +STR_2259 :풍경 & 테마 +STR_2260 :기금 없음 +STR_2261 :최소 기금 +STR_2262 :정상 기금 +STR_2263 :최대 기금 +STR_2264 :연구 기금 +STR_2265 :{WINDOW_COLOUR_2}비용: {BLACK}{CURRENCY}/월 +STR_2266 :연구 우선순위 +STR_2267 :현재 개발 중인 항목 +STR_2268 :최근에 개발한 항목 +STR_2269 :{WINDOW_COLOUR_2}유형: {BLACK}{STRINGID} +STR_2270 :{WINDOW_COLOUR_2}진행: {BLACK}{STRINGID} +STR_2271 :{WINDOW_COLOUR_2}예상: {BLACK}{STRINGID} +STR_2272 :{WINDOW_COLOUR_2}놀이기구/시술:{NEWLINE}{BLACK}{STRINGID} +STR_2273 :{WINDOW_COLOUR_2}풍경/테마:{NEWLINE}{BLACK}{STRINGID} +STR_2274 :{SMALLFONT}{BLACK}이 개발에 대한 상세 내역을 보여줍니다 +STR_2275 :{SMALLFONT}{BLACK}연구 & 개발을 위한 투자 설정 창을 보여줍니다 +STR_2276 :{SMALLFONT}{BLACK}연구 & 개발 상황을 보여줍니다 +STR_2277 :알 수 없음 +STR_2278 :운송용 놀이기구 +STR_2279 :얌전한 놀이기구 +STR_2280 :롤러코스터 +STR_2281 :스릴있는 놀이기구 +STR_2282 :물 놀이기구 +STR_2283 :상점/매점 +STR_2284 :풍경/테마 +STR_2285 :초기 연구 +STR_2286 :디자인 중 +STR_2287 :디자인 완성 +STR_2288 :알 수 없음 +STR_2289 :{STRINGID} {STRINGID} +STR_2290 :{SMALLFONT}{BLACK}{STRINGID} {STRINGID} +STR_2291 :새 게임을 시작할 시나리오를 선택하세요 +STR_2292 :{WINDOW_COLOUR_2}Rides been on: +STR_2293 :{BLACK} 없음 +STR_2294 :{SMALLFONT}{BLACK}땅 표면 모양을 변경합니다 +STR_2295 :{SMALLFONT}{BLACK}땅의 벽 모양을 변경합니다 +STR_2296 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}(을)를 공원 입장료로 썼습니다 +STR_2297 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}(을)를 {BLACK}{COMMA16} 놀이기구에 썼습니다 +STR_2298 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}(을)를 {BLACK}{COMMA16} 놀이기구에 썼습니다 +STR_2299 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}(을)를 음식 {BLACK}{COMMA16}종류에 썼습니다 +STR_2300 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}(을)를 음식 {BLACK}{COMMA16}종류에 썼습니다 +STR_2301 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}(을)를 음료수 {BLACK}{COMMA16}종류에 썼습니다 +STR_2302 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}(을)를 음료수 {BLACK}{COMMA16}종류에 썼습니다 +STR_2303 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}(을)를 기념품 {BLACK}{COMMA16}종류에 썼습니다 +STR_2304 :{BLACK}{CURRENCY2DP}{WINDOW_COLOUR_2}(을)를 기념품 {BLACK}{COMMA16}종류에 썼습니다 +STR_2305 :트랙 디자인 파일 +STR_2306 :트랙 디자인 저장 +STR_2307 :{STRINGID} 디자인 선택 +STR_2308 :{STRINGID} 트랙 디자인 +STR_2309 :새 트랙 디자인 설치 +STR_2310 :직접 설치 +STR_2311 :{WINDOW_COLOUR_2}흥미도: {BLACK}{COMMA2DP32} (근사치) +STR_2312 :{WINDOW_COLOUR_2}격렬도: {BLACK}{COMMA2DP32} (근사치) +STR_2313 :{WINDOW_COLOUR_2}멀미도: {BLACK}{COMMA2DP32} (근사치) +STR_2314 :{WINDOW_COLOUR_2}놀이기구 길이: {BLACK}{STRINGID} +STR_2315 :{WINDOW_COLOUR_2}비용: {BLACK}약 {CURRENCY} +STR_2316 :{WINDOW_COLOUR_2}필요한 공간: {BLACK}{COMMA16} x {COMMA16}칸 +STR_2317 :<더 이상 사용하지 않음> +STR_2318 :<더 이상 사용하지 않음> +STR_2319 :<더 이상 사용하지 않음> +STR_2320 :<더 이상 사용하지 않음> +STR_2321 :{WINDOW_COLOUR_2}놀이기구/시설 수: {BLACK}{COMMA16} +STR_2322 :{WINDOW_COLOUR_2}직원: {BLACK}{COMMA16} +STR_2323 :{WINDOW_COLOUR_2}공원 크기: {BLACK}{COMMA32}m{SQUARED} +STR_2324 :{WINDOW_COLOUR_2}공원 크기: {BLACK}{COMMA32}sq.ft +STR_2325 :{SMALLFONT}{BLACK}공원을 확장하기 위해 땅을 구입합니다 +STR_2326 :{SMALLFONT}{BLACK}공원 바깥에 있는 땅의 고공 혹은 지하에 건설을 허용해주는 건설권을 구입합니다 +STR_2327 :설정 +STR_2328 :{WINDOW_COLOUR_2}화폐 단위: +STR_2329 :{WINDOW_COLOUR_2}거리 및 속력: +STR_2330 :{WINDOW_COLOUR_2}온도: +STR_2331 :{WINDOW_COLOUR_2}높이 단위: +STR_2332 :유닛 +STR_2333 :효과음 +STR_2334 :파운드 ({POUND}) +STR_2335 :달러 ($) +STR_2336 :프랑 (F) +STR_2337 :독일 마르크 (DM) +STR_2338 :엔 ({YEN}) +STR_2339 :페세타 (Pts) +STR_2340 :리라 (L) +STR_2341 :길더 (fl.) +STR_2342 :크로나 (kr) +STR_2343 :유로 ({EURO}) +STR_2344 :임페리얼법 +STR_2345 :미터법 +STR_2346 :화면 +STR_2347 :{RED}{STRINGID}(이)가 물에 빠졌습니다! +STR_2348 :{SMALLFONT}{BLACK}이 직원에 대한 통계를 보여줍니다 +STR_2349 :{WINDOW_COLOUR_2}급여: {BLACK}{CURRENCY}/월 +STR_2350 :{WINDOW_COLOUR_2}고용: {BLACK}{MONTHYEAR} +STR_2351 :{WINDOW_COLOUR_2}깎은 잔디: {BLACK}{COMMA16}칸 +STR_2352 :{WINDOW_COLOUR_2}물 준 정원: {BLACK}{COMMA16}개 +STR_2353 :{WINDOW_COLOUR_2}치운 토사물: {BLACK}{COMMA16}개 +STR_2354 :{WINDOW_COLOUR_2}비운 쓰레기통: {BLACK}{COMMA16}개 +STR_2355 :{WINDOW_COLOUR_2}수리한 놀이기구: {BLACK}{COMMA16}개 +STR_2356 :{WINDOW_COLOUR_2}점검한 놀이기구: {BLACK}{COMMA16}개 +STR_2357 :집 +STR_2358 :유닛 +STR_2359 :실제 값 +STR_2360 :{WINDOW_COLOUR_2}해상도: +STR_2361 :땅 테두리를 부드럽게 +STR_2362 :{SMALLFONT}{BLACK}땅의 테두리를 부드럽게 보입니다 +STR_2363 :땅에 격자선 보이기 +STR_2364 :{SMALLFONT}{BLACK}땅에 격자선을 보여줍니다 +STR_2365 :은행이 대출을 증가시키는 것을 거절했습니다! +STR_2366 :섭씨 ({DEGREE}C) +STR_2367 :화씨 ({DEGREE}F) +STR_2368 :없음 +STR_2369 :낮음 +STR_2370 :평균 +STR_2371 :높음 +STR_2372 :낮음 +STR_2373 :보통 +STR_2374 :높음 +STR_2375 :매우 높음 +STR_2376 :극한 +STR_2377 :초극한 +STR_2378 :{SMALLFONT}{BLACK}땅 편집 크기 줄이기 +STR_2379 :{SMALLFONT}{BLACK}땅 편집 크기 늘이기 +STR_2380 :{SMALLFONT}{BLACK}물 편집 크기 줄이기 +STR_2381 :{SMALLFONT}{BLACK}물 편집 크기 늘이기 +STR_2382 :땅 +STR_2383 :물 +STR_2384 :{WINDOW_COLOUR_2}대상: +STR_2385 :{BLACK}없음 +STR_2386 :{BLACK}공원에 최소 {COMMA16}명 이상의 손님을 {MONTHYEAR}까지 유치하고, 공원 등급을 600 이상으로 유지하세요 +STR_2387 :{BLACK}최소 {POP16}{POP16}{CURRENCY} 이상의 공원 가치를 {PUSH16}{PUSH16}{PUSH16}{MONTHYEAR}까지 달성하세요 +STR_2388 :{BLACK}즐기세요! +STR_2389 :{BLACK}최고의 {STRINGID}(을)를 건설하세요! +STR_2390 :{BLACK}흥미도가 최소 6.00을 넘는 10개의 다른 종류의 롤러코스터를 공원에 운용하세요 +STR_2391 :{BLACK}공원에 최소 {COMMA16}명 이상의 손님을 유치하세요. 단 한 순간이라도 공원 등급을 700 아래로 떨어뜨려서는 안 됩니다! +STR_2392 :{BLACK}놀이기구 탑승 수익만으로 월 수익을 최소 {POP16}{POP16}{CURRENCY} 이상 달성하세요 +STR_2393 :{BLACK}최소 길이가 {LENGTH} 이상이고 흥미도가 최소 7.00을 넘는 10개의 다른 종류의 롤러코스터를 공원에 운용하세요 +STR_2394 :{BLACK}이 공원에 미완성된 5대의 롤러코스터를 각각의 흥미도가 최소 {POP16}{POP16}{COMMA2DP32} 이상이 되도록 완성하세요 +STR_2395 :{BLACK}대출금을 모두 갚고 공원 가치를 최소 {POP16}{POP16}{CURRENCY} 이상 달성하세요 +STR_2396 :{BLACK}음식, 음료수, 기념품 판매 수익만으로 월 수익을 최소 {POP16}{POP16}{CURRENCY} 이상 달성하세요 +STR_2397 :없음 +STR_2398 :주어진 기간 내에 손님 수 달성 +STR_2399 :주어진 기간 내에 공원 가치 달성 +STR_2400 :즐기기 +STR_2401 :최고의 놀이기구 건설하기 +STR_2402 :10대의 롤러코스터 건설 +STR_2403 :손님 수 달성 (공원 등급 700 이상) +STR_2404 :월 놀이기구 탑승 수익 +STR_2405 :주어진 길이의 롤러코스터 10대 건설 +STR_2406 :롤러코스터 5대 완성 +STR_2407 :대출금을 모두 갚고 주어진 공원 가치 달성 +STR_2408 :월 음식/기념품 판매 수익 +STR_2409 :{WINDOW_COLOUR_2}진행 중인 광고 행사 +STR_2410 :{BLACK}없음 +STR_2411 :{WINDOW_COLOUR_2}시작할 수 있는 광고 행사 +STR_2412 :{SMALLFONT}{BLACK}이 광고 행사를 시작합니다 +STR_2413 :{BLACK}({CURRENCY2DP}/주) +STR_2414 :(선택되지 않음) +STR_2415 :{WINDOW_COLOUR_2}놀이기구: +STR_2416 :{WINDOW_COLOUR_2}항목: +STR_2417 :{WINDOW_COLOUR_2}시간: +STR_2418 :{STRINGID} 무료 입장권 +STR_2419 :{STRINGID} 놀이기구 무료 탑승권 +STR_2420 :{STRINGID} 반값 할인권 +STR_2421 :{STRINGID} 무료 이용권 +STR_2422 :{STRINGID} 광고 +STR_2423 :{STRINGID} 광고 +STR_2424 :{WINDOW_COLOUR_2}공원 무료 입장 쿠폰입니다 +STR_2425 :{WINDOW_COLOUR_2}특정 놀이기구의 무료 탑승 쿠폰입니다 +STR_2426 :{WINDOW_COLOUR_2}공원 입장료 반값 할인 쿠폰입니다 +STR_2427 :{WINDOW_COLOUR_2}음식이나 음료수 무료 이용 쿠폰입니다 +STR_2428 :{WINDOW_COLOUR_2}공원을 광고합니다 +STR_2429 :{WINDOW_COLOUR_2}특정 놀이기구를 광고합니다 +STR_2430 :{BLACK}{STRINGID} 무료 입장권 +STR_2431 :{BLACK}{STRINGID} 무료 탑승 쿠폰 +STR_2432 :{BLACK}{STRINGID} 반값 할인 쿠폰 +STR_2433 :{BLACK}{STRINGID} 무료 이용권 +STR_2434 :{BLACK}{STRINGID} 광고 +STR_2435 :{BLACK}{STRINGID} 광고 +STR_2436 :1주 +STR_2437 :<더 이상 사용하지 않음> +STR_2438 :<더 이상 사용하지 않음> +STR_2439 :<더 이상 사용하지 않음> +STR_2440 :<더 이상 사용하지 않음> +STR_2441 :<더 이상 사용하지 않음> +STR_2442 :<더 이상 사용하지 않음> +STR_2443 :{WINDOW_COLOUR_2}1주당 비용: {BLACK}{CURRENCY2DP} +STR_2444 :{WINDOW_COLOUR_2}총 비용: {BLACK}{CURRENCY2DP} +STR_2445 :이 광고 행사를 시작합니다 +STR_2446 :{YELLOW}공원 무료 입장 이벤트가 종료되었습니다 +STR_2447 :{YELLOW}{STRINGID} 무료 탑승 이벤트가 종료되었습니다 +STR_2448 :{YELLOW}공원 입장료 반값 할인 이벤트가 종료되었습니다 +STR_2449 :{YELLOW}{STRINGID} 무료 이용 이벤트가 종료되었습니다 +STR_2450 :{YELLOW}공원 광고가 종료되었습니다 +STR_2451 :{YELLOW}{STRINGID} 광고가 종료되었습니다 +STR_2452 :{WINDOW_COLOUR_2}재정 (대출 제외): {BLACK}{CURRENCY2DP} +STR_2453 :{WINDOW_COLOUR_2}재정 (대출 제외): {RED}{CURRENCY2DP} +STR_2454 :{SMALLFONT}{BLACK}{CURRENCY2DP} - +STR_2455 :{SMALLFONT}{BLACK}+{CURRENCY2DP} - +STR_2456 :{SMALLFONT}{BLACK}{CURRENCY2DP} - +STR_2457 :{SMALLFONT}{BLACK}재정 요약을 보여줍니다 +STR_2458 :{SMALLFONT}{BLACK}시간에 따른 재정 보유 그래프(대출 제외)를 보여줍니다 +STR_2459 :{SMALLFONT}{BLACK}시간에 따른 공원 가치 그래프를 보여줍니다 +STR_2460 :{SMALLFONT}{BLACK}주간 수익 그래프를 보여줍니다 +STR_2461 :{SMALLFONT}{BLACK}광고 이벤트를 보여줍니다 +STR_2462 :{SMALLFONT}{BLACK}공원 입구 위치로 이동합니다 +STR_2463 :{SMALLFONT}{BLACK}시간에 따른 공원 등급 그래프를 보여줍니다 +STR_2464 :{SMALLFONT}{BLACK}시간에 따른 손님 수 그래프를 보여줍니다 +STR_2465 :{SMALLFONT}{BLACK}공원 입장료와 정보를 보여줍니다 +STR_2466 :{SMALLFONT}{BLACK}공원 통계를 보여줍니다 +STR_2467 :{SMALLFONT}{BLACK}이 게임의 목표를 보여줍니다 +STR_2468 :{SMALLFONT}{BLACK}이 공원이 최근에 받은 상을 보여줍니다 +STR_2469 :{SMALLFONT}{BLACK}연구 & 개발 수준을 선택합니다 +STR_2470 :{SMALLFONT}{BLACK}새 운송용 놀이기구를 개발합니다 +STR_2471 :{SMALLFONT}{BLACK}새 얌전한 놀이기구를 개발합니다 +STR_2472 :{SMALLFONT}{BLACK}새 롤러코스터를 개발합니다 +STR_2473 :{SMALLFONT}{BLACK}새 스릴있는 놀이기구를 개발합니다 +STR_2474 :{SMALLFONT}{BLACK}새 물 놀이기구를 개발합니다 +STR_2475 :{SMALLFONT}{BLACK}새 상점/매점을 개발합니다 +STR_2476 :{SMALLFONT}{BLACK}새 풍경/테마를 개발합니다 +STR_2477 :{SMALLFONT}{BLACK}이 놀이기구/시설의 운영 모드를 선택합니다 +STR_2478 :{SMALLFONT}{BLACK}시간에 따른 속력 그래프를 보여줍니다 +STR_2479 :{SMALLFONT}{BLACK}시간에 따른 고도 그래프를 보여줍니다 +STR_2480 :{SMALLFONT}{BLACK}시간에 따른 수직 가속도 그래프를 보여줍니다 +STR_2481 :{SMALLFONT}{BLACK}시간에 따른 측면 가속도 그래프를 보여줍니다 +STR_2482 :{SMALLFONT}{BLACK}수익: {CURRENCY}/주, 공원 가치: {CURRENCY} +STR_2483 :{WINDOW_COLOUR_2}주간 수익: {BLACK}+{CURRENCY2DP} +STR_2484 :{WINDOW_COLOUR_2}주간 수익: {RED}{CURRENCY2DP} +STR_2485 :조작 +STR_2486 :일반 +STR_2487 :손님들의 '실제' 이름을 표시 +STR_2488 :{SMALLFONT}{BLACK}손님들의 이름을 '실제' 이름으로 보여줄지 번호로 보여줄지를 선택합니다 +STR_2489 :단축키 설정... +STR_2490 :키보드 단축키 +STR_2491 :단축키 초기화 +STR_2492 :{SMALLFONT}{BLACK}모든 키보드 단축키를 기본 설정으로 되돌립니다 +STR_2493 :가장 위에 있는 창 닫기 +STR_2494 :모든 창 닫기 +STR_2495 :건설 모드 취소 +STR_2496 :게임 일시정지 +STR_2497 :화면 축소 +STR_2498 :화면 확대 +STR_2499 :게임 화면 시계 방향으로 회전 +STR_2500 :건설 대상 회전 +STR_2501 :지하 시야 토글 +STR_2502 :땅 표면 제거 +STR_2503 :벽면 제거 +STR_2504 :놀이기구 투명화 +STR_2505 :풍경 투명화 +STR_2506 :지지대 투명화 +STR_2507 :사람 투명화 +STR_2508 :지형 고도 표시 +STR_2509 :놀이기구 트랙 고도 표시 +STR_2510 :보도 고도 표시 +STR_2511 :땅 편집 +STR_2512 :물 편집 +STR_2513 :풍경 제작 +STR_2514 :보도 건설 +STR_2515 :새 놀이기구 건설 +STR_2516 :재정 정보를 보여줍니다 +STR_2517 :개발 정보를 보여줍니다 +STR_2518 :놀이기구 목록을 보여줍니다 +STR_2519 :공원 정보를 보여줍니다 +STR_2520 :손님 목록을 보여줍니다 +STR_2521 :직원 목록을 보여줍니다 +STR_2522 :최근 메시지를 보여줍니다 +STR_2523 :지도 보기 +STR_2524 :스크린 샷 +### The following need to be reordered to match SDL_keycode layout. +STR_2525 :??? +STR_2526 :??? +STR_2527 :??? +STR_2528 :??? +STR_2529 :??? +STR_2530 :??? +STR_2531 :??? +STR_2532 :??? +STR_2533 :백스페이스 +STR_2534 :탭 +STR_2535 :??? +STR_2536 :??? +STR_2537 :Clear +STR_2538 :Return +STR_2539 :??? +STR_2540 :??? +STR_2541 :??? +STR_2542 :??? +STR_2543 :Alt/Menu +STR_2544 :Pause +STR_2545 :Caps +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 :스페이스바 +STR_2558 :PgUp +STR_2559 :PgDn +STR_2560 :End +STR_2561 :Home +STR_2562 :Left +STR_2563 :Up +STR_2564 :Right +STR_2565 :Down +STR_2566 :Select +STR_2567 :Print +STR_2568 :Execute +STR_2569 :Snapshot +STR_2570 :Insert +STR_2571 :Delete +STR_2572 :Help +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 :NumPad 0 +STR_2622 :NumPad 1 +STR_2623 :NumPad 2 +STR_2624 :NumPad 3 +STR_2625 :NumPad 4 +STR_2626 :NumPad 5 +STR_2627 :NumPad 6 +STR_2628 :NumPad 7 +STR_2629 :NumPad 8 +STR_2630 :NumPad 9 +STR_2631 :NumPad * +STR_2632 :NumPad + +STR_2633 :??? +STR_2634 :NumPad - +STR_2635 :NumPad . +STR_2636 :NumPad / +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 :NumLock +STR_2670 :Scroll +STR_2671 :??? +STR_2672 :??? +STR_2673 :??? +STR_2674 :??? +STR_2675 :??? +STR_2676 :??? +STR_2677 :??? +STR_2678 :??? +STR_2679 :??? +STR_2680 :모든 연구가 완료되었습니다 +STR_2681 :{MEDIUMFONT}{BLACK}돈 {CURRENCY} 늘리기 +STR_2682 :<더 이상 사용하지 않음> +STR_2683 :<더 이상 사용하지 않음> +STR_2684 :{SMALLFONT}{BLACK}손님 대규모로 불러오기 +STR_2685 :단일 노이즈 매개 변수 +STR_2686 :{WINDOW_COLOUR_2}저: +STR_2687 :{WINDOW_COLOUR_2}고: +STR_2688 :{WINDOW_COLOUR_2}기본 주파수: +STR_2689 :{WINDOW_COLOUR_2}옥타브: +STR_2690 :지도 생성 +STR_2691 :{WINDOW_COLOUR_2}기본 높이: +STR_2692 :{WINDOW_COLOUR_2}수면 높이: +STR_2693 :{WINDOW_COLOUR_2}지형: +STR_2694 :생성 +STR_2695 :무작위 지형 +STR_2696 :나무 심기 +STR_2697 :??? +STR_2698 :??? +STR_2699 :??? +STR_2700 :자동 저장 주기: +STR_2701 :매 1분마다 +STR_2702 :매 5분마다 +STR_2703 :매 15분마다 +STR_2704 :매 30분마다 +STR_2705 :매 시간마다 +STR_2706 :안 함 +STR_2707 :새 창 열기 +STR_2708 :{WINDOW_COLOUR_1}정말 {STRINGID}에 덮어씌우시겠습니까? +STR_2709 :덮어쓰기 +STR_2710 :파일 이름을 입력하세요. +STR_2711 :; +STR_2712 := +STR_2713 :, +STR_2714 :- +STR_2715 :. +STR_2716 :/ +STR_2717 :' +STR_2718 :(상위 폴더) +STR_2719 :(새 파일) +STR_2720 :{UINT16}초 +STR_2721 :{UINT16}초 +STR_2722 :{UINT16}분 {UINT16}초 +STR_2723 :{UINT16}분 {UINT16}초 +STR_2724 :{UINT16}분 {UINT16}초 +STR_2725 :{UINT16}분 {UINT16}초 +STR_2726 :{UINT16}분 +STR_2727 :{UINT16}분 +STR_2728 :{UINT16}시간 {UINT16}분 +STR_2729 :{UINT16}시간 {UINT16}분 +STR_2730 :{UINT16}시간 {UINT16}분 +STR_2731 :{UINT16}시간 {UINT16}분 +STR_2732 :{COMMA16}ft +STR_2733 :{COMMA16}m +STR_2734 :{COMMA16}mph +STR_2735 :{COMMA16}km/h +STR_2736 :{POP16}{COMMA16}년 {PUSH16}{PUSH16}{MONTH} +STR_2737 :{STRINGID} {POP16}{COMMA16}년 {PUSH16}{PUSH16}{MONTH} +STR_2738 :타이틀 스크린 음악: +STR_2739 :없음 +STR_2740 :롤러코스터 타이쿤 1 +STR_2741 :롤러코스터 타이쿤 2 +STR_2742 :css50.dat 파일을 찾을 수 없습니다 +STR_2743 :data\css17.dat 파일을 RCT1 설치 폴더에서 복사하여 RCT2가 설치된 폴더 안에 data\css50.dat 이름으로 바꾸어 넣으십시오. +STR_2744 :[ +STR_2745 :\ +STR_2746 :] +STR_2747 :{ENDQUOTES} +STR_2748 :바 +STR_2749 :내 새 시나리오 +# New strings used in the cheats window previously these were ??? +STR_2750 :모든 항목을 위로 +STR_2751 :모든 항목을 아래로 +STR_2752 :잔디 청소 +STR_2753 :잔디 깎기 +STR_2754 :물 주기 +STR_2755 :파괴된 시설물 수리 +STR_2756 :쓰레기통 비우기 +STR_2757 :항상 맑음 +STR_2758 :항상 비 +STR_2759 :보도 청소 +STR_2760 :+{CURRENCY} +STR_2761 :<더 이상 사용하지 않음> +STR_2762 :<더 이상 사용하지 않음> +STR_2763 :??? +STR_2764 :<더 이상 사용하지 않음> +STR_2765 :손님 많이 부르기 +STR_2766 :시나리오 클리어 +STR_2767 :기후 고정 +STR_2768 :기후 고정 해제 +STR_2769 :공원 열기 +STR_2770 :공원 닫기 +STR_2771 :게임 속도 느리게 +STR_2772 :게임 속도 빠르게 +STR_2773 :창 모드 +STR_2774 :풀 스크린 +STR_2775 :풀 스크린 (데스크탑) +STR_2776 :언어: +STR_2777 :{MOVE_X}{SMALLFONT}{STRING} +STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} +STR_2779 :외부화면 #{COMMA16} +STR_2780 :추가 외부화면 +# End of new strings +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} +STR_2782 :SHIFT + +STR_2783 :CTRL + +STR_2784 :키보드 단축키 변경 +STR_2785 :{WINDOW_COLOUR_2}새 단축키를 누르세요:{NEWLINE}{OPENQUOTES}{STRINGID}{ENDQUOTES} +STR_2786 :{SMALLFONT}{BLACK}새 단축키를 설정하려면 단축키 설명을 클릭하세요 +STR_2787 :{WINDOW_COLOUR_2}공원 가치: {BLACK}{CURRENCY} +STR_2788 :{WINDOW_COLOUR_2}축하합니다 !{NEWLINE}{BLACK}시나리오 목표를 {CURRENCY}의 회사 가치로 달성하였습니다 ! +STR_2789 :{WINDOW_COLOUR_2}목표 달성에 실패하였습니다 ! +STR_2790 :시나리오 차트에 이름을 기록하세요 +STR_2791 :이름을 입력하세요 +STR_2792 :시나리오 차트에 이름을 기록하세요: +STR_2793 :{SMALLFONT}(달성: {STRINGID}) +STR_2794 :{WINDOW_COLOUR_2}달성: {BLACK}{STRINGID}{NEWLINE}{WINDOW_COLOUR_2}회사 가치: {BLACK}{CURRENCY} +STR_2795 :정렬 +STR_2796 :{SMALLFONT}{BLACK}놀이기구 목록을 정보 종류에 따라 정렬하여 표시합니다. +STR_2797 :화면 가장자리에 커서를 가져가면 화면을 스크롤 +STR_2798 :{SMALLFONT}{BLACK}화면 가장자리에 마우스 커서를 가까이 대면 게임 화면을 스크롤할지를 선택합니다 +STR_2799 :{SMALLFONT}{BLACK}지정되어 있는 조작 키를 확인하거나 변경합니다 +STR_2800 :{WINDOW_COLOUR_2}총 입장료: {BLACK}{COMMA32} +STR_2801 :{WINDOW_COLOUR_2}입장료로 벌어들인 수익: {BLACK}{CURRENCY2DP} +STR_2802 :지도 +STR_2803 :{SMALLFONT}{BLACK}이 손님들을 지도에 하이라이트하여 표시합니다 +STR_2804 :{SMALLFONT}{BLACK}이 직원들을 지도에 하이라이트하여 표시합니다 +STR_2805 :{SMALLFONT}{BLACK}공원의 지도를 표시합니다 +STR_2806 :{RED}손님들이 공원의 더러운 보도 청소 상태에 대해 불평하고 있습니다{NEWLINE}미화원을 더 고용하거나 미화원의 업무 효율성을 점검하세요 +STR_2807 :{RED}손님들이 공원에 널린 쓰레기에 대해 불평하고 있습니다{NEWLINE}미화원을 더 고용하거나 미화원의 업무 효율성을 점검하세요 +STR_2808 :{RED}손님들이 공원에서 일어난 시설물 파괴에 대해 불평하고 있습니다{NEWLINE}경비원을 더 고용하거나 경비원의 업무 효율성을 점검하세요 +STR_2809 :{RED}손님들이 배가 고프지만 음식을 살 곳을 찾지 못하고 있습니다 +STR_2810 :{RED}손님들이 목이 마르지만 음료수를 살 곳을 찾지 못하고 있습니다 +STR_2811 :{RED}손님들이 공원에서 화장실을 찾을 수 없다고 불평하고 있습니다 +STR_2812 :{RED}손님들이 길을 잃었거나 갇혔습니다{NEWLINE}보도의 구조를 손님들이 길을 더 쉽게 찾을 수 있도록 개선하세요 +STR_2813 :{RED}공원 입장료가 너무 비쌉니다!{NEWLINE}손님을 더 유치하려면 공원 입장료를 내리거나 공원 가치를 올리세요 +STR_2814 :{WINDOW_COLOUR_2}가장 지저분한 공원 상 +STR_2815 :{WINDOW_COLOUR_2}가장 깔끔한 공원 상 +STR_2816 :{WINDOW_COLOUR_2}최고의 롤러코스터가 있는 공원 상 +STR_2817 :{WINDOW_COLOUR_2}최고의 공원 이용료 상 +STR_2818 :{WINDOW_COLOUR_2}가장 아름다운 공원 상 +STR_2819 :{WINDOW_COLOUR_2}최악의 공원 이용료 상 +STR_2820 :{WINDOW_COLOUR_2}가장 안전한 공원 상 +STR_2821 :{WINDOW_COLOUR_2}최고의 직원 상 +STR_2822 :{WINDOW_COLOUR_2}최고의 공원 음식 상 +STR_2823 :{WINDOW_COLOUR_2}최악의 공원 음식 상 +STR_2824 :{WINDOW_COLOUR_2}최고의 공원 화장실 상 +STR_2825 :{WINDOW_COLOUR_2}가장 실망스러운 공원 상 +STR_2826 :{WINDOW_COLOUR_2}최고의 물 놀이기구 상 +STR_2827 :{WINDOW_COLOUR_2}최고의 커스텀 디자인 놀이기구 상 +STR_2828 :{WINDOW_COLOUR_2}최고의 눈부신 놀이기구 색상 조합 상 +STR_2829 :{WINDOW_COLOUR_2}가장 복잡한 공원 구조 상 +STR_2830 :{WINDOW_COLOUR_2}최고의 얌전한 놀이기구 상 +STR_2831 :{TOPAZ}공원이 '우리나라에서 가장 지저분한 공원 상'을 받았습니다... +STR_2832 :{TOPAZ}공원이 '우리나라에서 가장 깔끔한 공원 상'을 받았습니다! +STR_2833 :{TOPAZ}공원이 '우리나라 최고의 롤러코스터가 있는 공원 상'을 받았습니다! +STR_2834 :{TOPAZ}공원이 '우리나라 최고의 공원 이용료 상'을 받았습니다! +STR_2835 :{TOPAZ}공원이 '우리나라에서 가장 아름다운 공원 상'을 받았습니다! +STR_2836 :{TOPAZ}공원이 '우리나라 최악의 공원 이용료 상'을 받았습니다... +STR_2837 :{TOPAZ}공원이 '우리나라에서 가장 안전한 공원 상'을 받았습니다! +STR_2838 :{TOPAZ}공원이 '우리나라 최고의 직원 상'을 받았습니다! +STR_2839 :{TOPAZ}공원이 '우리나라 최고의 공원 음식 상'을 받았습니다! +STR_2840 :{TOPAZ}공원이 '우리나라 최악의 공원 음식 상'을 받았습니다... +STR_2841 :{TOPAZ}공원이 '우리나라 최고의 공원 화장실 상'을 받았습니다! +STR_2842 :{TOPAZ}공원이 '우리나라에서 가장 실망스러운 공원 상'을 받았습니다... +STR_2843 :{TOPAZ}공원이 '우리나라 최고의 물 놀이기구 상'을 받았습니다! +STR_2844 :{TOPAZ}공원이 '우리나라 최고의 커스텀 디자인 놀이기구 상'을 받았습니다! +STR_2845 :{TOPAZ}공원이 '우리나라 최고의 눈부신 놀이기구 색상 조합 상'을 받았습니다! +STR_2846 :{TOPAZ}공원이 '우리나라에서 가장 복잡한 공원 구조 상'을 받았습니다... +STR_2847 :{TOPAZ}공원이 '우리나라 최고의 얌전한 놀이기구 상'을 받았습니다! +STR_2848 :{WINDOW_COLOUR_2}최근에 받은 상 없음 +STR_2849 :새 시나리오 설치가 성공적으로 완료되었습니다 +STR_2850 :새 트랙 디자인 설치가 성공적으로 완료되었습니다 +STR_2851 :시나리오가 이미 설치되어 있습니다 +STR_2852 :트랙 디자인이 이미 설치되어 있습니다 +STR_2853 :지역 당국에 의해 금지된 행위입니다! +STR_2854 :{RED}손님들이 {STRINGID}의 입구로 갈 수 없습니다 !{NEWLINE}입구로 가는 길을 만드세요 +STR_2855 :{RED}{STRINGID}의 출구에서 나오는 길이 없습니다 !{NEWLINE}출구로 가는 길을 만드세요 +STR_2856 :{WINDOW_COLOUR_2}튜토리얼 +STR_2857 :{WINDOW_COLOUR_2}(조작하려면 마우스나 키보드 키를 누르세요) +STR_2858 :광고 이벤트를 시작할 수 없습니다... +STR_2859 :OpenRCT2 프로그램이 이미 실행 중입니다 +STR_2860 :Infogrames Interactive 제공... +STR_2861 :{WINDOW_COLOUR_2}Licensed to Infogrames Interactive Inc. +STR_2862 :음악 저작권... +STR_2863 :음악 저작권 +STR_2864 :{WINDOW_COLOUR_2}March - Children of the Regiment: (푸치크) 저작권 없음 +STR_2865 :{WINDOW_COLOUR_2}Heyken's Serenade: (J.Heyken) British Standard Music Coy; GEMA, BRITICO +STR_2866 :{WINDOW_COLOUR_2}In Continental Mood: (작곡가 미상) Copyright Control +STR_2867 :{WINDOW_COLOUR_2}Wedding Journey: (민요) +STR_2868 :{WINDOW_COLOUR_2}Tales from the Vienna Woods: (요한 스트라우스) 저작권 없음 +STR_2869 :{WINDOW_COLOUR_2}Slavonic Dance: (민요) +STR_2870 :{WINDOW_COLOUR_2}Das Alpenhorn: (민요) +STR_2871 :{WINDOW_COLOUR_2}The Blond Sailor: (민요) +STR_2872 :{WINDOW_COLOUR_2}Overture - Poet and Peasant: (주페) 저작권 없음 +STR_2873 :{WINDOW_COLOUR_2}Waltz Medley: (요한 스트라우스) 저작권 없음 +STR_2874 :{WINDOW_COLOUR_2}Bella Bella Bimba: (민요) +STR_2875 :{WINDOW_COLOUR_2}Original recordings (P) 1976 C.J.Mears Organization, used with consent +STR_2876 :{WINDOW_COLOUR_2}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, played by Peter James Adcock) recording {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}수석 프로듀서: Thomas J. Zahorik +STR_2910 :{WINDOW_COLOUR_2}제작 책임자: Bill Levay +STR_2911 :{WINDOW_COLOUR_2}수석 마케팅 프로덕트 매니저: Scott Triola +STR_2912 :{WINDOW_COLOUR_2}프로덕트 개발 V.P.: Scott Walker +STR_2913 :{WINDOW_COLOUR_2}일반 매니저: John Hurlbut +STR_2914 :{WINDOW_COLOUR_2}품질 보증 감독: Michael Craighead +STR_2915 :{WINDOW_COLOUR_2}Q.A. 인증 매니저: Kurt Boutin +STR_2916 :{WINDOW_COLOUR_2}Q.A. 인증 리드: Mark Huggins +STR_2917 :{WINDOW_COLOUR_2}테스터: Dena Irene Fitzgerald, Scott Rollins, Christopher McPhail +STR_2918 :{WINDOW_COLOUR_2}Clif McClure, Erik Maramaldi, Erik Jeffery +STR_2919 :{WINDOW_COLOUR_2}마케팅 감독: Ann Marie Bland +STR_2920 :{WINDOW_COLOUR_2}창조형 서비스 매니저: Steve Martin +STR_2921 :{WINDOW_COLOUR_2}편집 & 문서 서비스 매니저: Elizabeth Mackney +STR_2922 :{WINDOW_COLOUR_2}그래픽 디자이너: Paul Anselmi +STR_2923 :{WINDOW_COLOUR_2}카피라이터: Kurt Carlson +STR_2924 :{WINDOW_COLOUR_2}감사 인사: Peter Matiss +STR_2925 :{WINDOW_COLOUR_2}엔지니어링 스페셜리스트: Ken Edwards +STR_2926 :{WINDOW_COLOUR_2}엔지니어링 서비스 매니저: Luis Rivas +STR_2927 :{WINDOW_COLOUR_2}리드 적합성 분석: Geoffrey Smith +STR_2928 :{WINDOW_COLOUR_2}적합성 분석: Jason Cordero, Burke McQuinn, Kim Jardin +STR_2929 :{WINDOW_COLOUR_2}리드 테스터: Daniel Frisoli +STR_2930 :{WINDOW_COLOUR_2}수석 테스터: 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 :<더 이상 사용하지 않음> +STR_2970 :<더 이상 사용하지 않음> +STR_2971 :주 색상 조합 +STR_2972 :부 색상 조합 1 +STR_2973 :부 색상 조합 2 +STR_2974 :부 색상 조합 3 +STR_2975 :{SMALLFONT}{BLACK}바꾸거나 칠할 놀이기구의 색상 조합을 선택하세요 +STR_2976 :{SMALLFONT}{BLACK}선택한 색상 조합을 사용하여 이 놀이기구의 특정 부분을 칠합니다 +STR_2977 :직원 이름 +STR_2978 :새 직원 이름을 입력하세요: +STR_2979 :직원 이름을 바꿀 수 없습니다... +STR_2980 :게임에 전광판이 너무 많습니다 +STR_2981 :{RED}출입 금지 - - +STR_2982 :전광판 내용 +STR_2983 :이 전광판의 문구를 입력하세요: +STR_2984 :전광판의 내용을 바꿀 수 없습니다... +STR_2985 :전광판 +STR_2986 :{SMALLFONT}{BLACK}전광판의 내용을 바꿉니다 +STR_2987 :{SMALLFONT}{BLACK}이 전광판을 '손님 출입 금지'로 설정합니다 +STR_2988 :{SMALLFONT}{BLACK}이 전광판을 제거합니다 +STR_2989 :{SMALLFONT}{BLACK}주 색상 선택 +STR_2990 :{SMALLFONT}{BLACK}문구 색상 선택 +STR_2991 :팻말 +STR_2992 :팻말 내용 +STR_2993 :이 팻말의 문구를 입력하세요: +STR_2994 :{SMALLFONT}{BLACK}팻말의 내용을 바꿉니다 +STR_2995 :{SMALLFONT}{BLACK}이 팻말을 제거합니다 +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 :파일을 불러올 수 없습니다... +STR_3011 :파일이 올바르지 않은 데이터를 포함하고 있습니다 +STR_3012 :범버카 비트 스타일 +STR_3013 :축제 오르간 스타일 +STR_3014 :로마 팡파르 스타일 +STR_3015 :동양 스타일 +STR_3016 :화상 스타일 +STR_3017 :정글 북 스타일 +STR_3018 :이집트 스타일 +STR_3019 :장난감나라 스타일 +STR_3020 : +STR_3021 :우주 스타일 +STR_3022 :호러 스타일 +STR_3023 :테크노 스타일 +STR_3024 :젠틀 스타일 +STR_3025 :여름 스타일 +STR_3026 :수중 스타일 +STR_3027 :서부 스타일 +STR_3028 :쥐라기 스타일 +STR_3029 :록 스타일 +STR_3030 :래그타임 스타일 +STR_3031 :판타지 스타일 +STR_3032 :록 스타일 2 +STR_3033 :얼음 스타일 +STR_3034 :눈 스타일 +STR_3035 :사용자 음악 1 +STR_3036 :사용자 음악 2 +STR_3037 :중세 스타일 +STR_3038 :도시 스타일 +STR_3039 :오르간 스타일 +STR_3040 :기계적인 스타일 +STR_3041 :현대적인 스타일 +STR_3042 :해적 스타일 +STR_3043 :록 스타일 3 +STR_3044 :사탕 스타일 +STR_3045 :{SMALLFONT}{BLACK}재생할 음악 스타일을 선택하세요 +STR_3046 :이 놀이기구를 수정할 수 없습니다 +STR_3047 :지역 당국이 이 놀이기구를 파괴하거나 수정하는 것을 금지했습니다 +STR_3048 :지역 당국이 광고 이벤트를 금지했습니다 +STR_3049 :골프 홀 A +STR_3050 :골프 홀 B +STR_3051 :골프 홀 C +STR_3052 :골프 홀 D +STR_3053 :골프 홀 E +STR_3054 :불러오는 중... +STR_3055 :하얗게 +STR_3056 :반투명으로 +STR_3057 :{WINDOW_COLOUR_2}건설 예정지 표시: +STR_3058 :벽돌 벽 +STR_3059 :생울타리 벽 +STR_3060 :얼음 벽돌 벽 +STR_3061 :나무 벽 +STR_3062 :{SMALLFONT}{BLACK}표준 롤러코스터 트랙 +STR_3063 :{SMALLFONT}{BLACK}물 튀김 (트랙 일부 잠김) +STR_3064 :초심자 공원 +STR_3065 :도전자 공원 +STR_3066 :전문가 공원 +STR_3067 :{OPENQUOTES}실제{ENDQUOTES} 공원 +STR_3068 :기타 공원 +STR_3069 :탑 섹션 +STR_3070 :평지로 +STR_3071 :{WINDOW_COLOUR_2}공원 내 어디서나 같은 가격으로 +STR_3072 :{SMALLFONT}{BLACK}이 가격을 공원 내에서 모두 통일할지 여부를 선택하세요 +STR_3073 :{RED}경고: 공원 등급이 700 아래로 내려갔습니다 !{NEWLINE}4주 이내에 다시 공원 등급을 올리지 않으면, 공원이 폐쇄될 것입니다 +STR_3074 :{RED}경고: 공원 등급이 아직도 700 아래로 떨어져 있습니다 !{NEWLINE}공원 등급을 올릴 수 있는 시간이 3주 남았습니다 +STR_3075 :{RED}경고: 공원 등급이 아직도 700 아래로 떨어져 있습니다 !{NEWLINE}2주 이내에 다시 공원 등급을 올리지 않으면, 공원이 폐쇄될 것입니다 +STR_3076 :{RED}마지막 경고: 공원 등급이 아직도 700 아래로 떨어져 있습니다 !{NEWLINE}공원 등급을 올리지 않으면 7일 뒤에 공원이 폐쇄될 것입니다 +STR_3077 :{RED}폐쇄 알림 : 공원이 폐쇄되었습니다 ! +STR_3078 :평범한 스타일의 출입구/역 +STR_3079 :나무 스타일의 출입구/역 +STR_3080 :캔버스 텐트 스타일의 출입구/역 +STR_3081 :성 스타일의 출입구/역 (회색) +STR_3082 :성 스타일의 출입구/역 (갈색) +STR_3083 :정글 스타일의 출입구/역 +STR_3084 :통나무 오두막집 스타일의 출입구/역 +STR_3085 :고대/로마 스타일의 출입구/역 +STR_3086 :추상적인 스타일의 출입구/역 +STR_3087 :눈/얼음 스타일의 출입구/역 +STR_3088 :탑 스타일의 출입구/역 +STR_3089 :우주 스타일의 출입구/역 +STR_3090 :{SMALLFONT}{BLACK}출입구와 역의 스타일을 선택하세요 +STR_3091 :이 섹션을 제거할 수 없습니다! +STR_3092 :이 놀이기구의 탑승장을 옮기거나 편집할 수 없습니다! +STR_3093 :{WINDOW_COLOUR_2}가장 좋아하는 것: {BLACK}{STRINGID} +STR_3094 :없음 +STR_3095 :{WINDOW_COLOUR_2}리프트 힐 체인 속도: +STR_3096 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} +STR_3097 :{SMALLFONT}{BLACK}리프트 힐 체인 속력을 선택하세요 +STR_3098 :리프트 힐 체인 속력을 변경할 수 없습니다... +STR_3099 :{SMALLFONT}{BLACK}색을 선택하세요 +STR_3100 :{SMALLFONT}{BLACK}두 번째 색을 선택하세요 +STR_3101 :{SMALLFONT}{BLACK}세 번째 색을 선택하세요 +STR_3102 :{SMALLFONT}{BLACK}이미 설치된 조경물의 색을 다시 칠합니다 +STR_3103 :이 조형물의 색을 다시 칠할 수 없습니다... +STR_3104 :{SMALLFONT}{BLACK}놀이기구 목록 +STR_3105 :{SMALLFONT}{BLACK}상점 & 매점 목록 +STR_3106 :{SMALLFONT}{BLACK}안내소 및 기타 손님 소유물 목록 +STR_3107 :닫기 +STR_3108 :테스트 +STR_3109 :열기 +STR_3110 :{WINDOW_COLOUR_2}블록 섹션: {BLACK}{COMMA16} +STR_3111 :{SMALLFONT}{BLACK}만들고 싶은 디자인을 클릭하세요 +STR_3112 :{SMALLFONT}{BLACK}이름을 바꾸거나 제거할 디자인을 클릭하세요 +STR_3113 :다른 디자인을 선택 +STR_3114 :{SMALLFONT}{BLACK}디자인 선택 창으로 되돌아갑니다 +STR_3115 :{SMALLFONT}{BLACK}트랙 디자인을 저장합니다 +STR_3116 :{SMALLFONT}{BLACK}트랙 디자인을 저장합니다 (놀이기구를 테스트하여 수치가 나와야 저장할 수 있습니다) +STR_3117 :{BLACK}정비기술자에게 연락 중... +STR_3118 :{BLACK}{STRINGID}(이)가 놀이기구로 향하고 있음 +STR_3119 :{BLACK}{STRINGID}(이)가 놀이기구를 수리하고 있음 +STR_3120 :{SMALLFONT}{BLACK}가까운 정비기술자를 찾아서 놀이기구를 수리하게 합니다 +STR_3121 :정비기술자가 근처에 없거나 모두 바쁩니다 +STR_3122 :{WINDOW_COLOUR_2}이 놀이기구를 좋아하는 손님: {BLACK}{COMMA16}명 +STR_3123 :{WINDOW_COLOUR_2}이 놀이기구를 좋아하는 손님: {BLACK}{COMMA16}명 +STR_3124 :고장난 {STRINGID} +STR_3125 :{WINDOW_COLOUR_2}흥미도 인수: {BLACK}+{COMMA16}% +STR_3126 :{WINDOW_COLOUR_2}격렬도 인수: {BLACK}+{COMMA16}% +STR_3127 :{WINDOW_COLOUR_2}멀미도 인수: {BLACK}+{COMMA16}% +STR_3128 :트랙 디자인 저장 +STR_3129 :트랙 디자인을 조형물과 함께 저장 +STR_3130 :저장 +STR_3131 :취소 +STR_3132 :{BLACK}트랙 디자인과 함께 저장할 조형물을 선택하세요... +STR_3133 :경사 위에 지을 수 없습니다 +STR_3134 :{RED}(사용 불가능한 조형물 포함) +STR_3135 :{RED}(차량 디자인 사용 불가 - 놀이기구 수치에 영향이 있을 수 있음) +STR_3136 :경고: 다른 차량 종류로 대체되어 지어질 것이며 기대했던 것과는 다르게 작동할 수 있습니다 +STR_3137 :근처 조형물 선택 +STR_3138 :선택 초기화 +STR_3139 :이 운행 모드에서는 케이블 리프트 힐을 작동할 수 없습니다 +STR_3140 :케이블 리프트 힐은 탑승장 바로 다음에 건설해야 합니다 +STR_3141 :케이블 리프트 힐을 사용하면 2바퀴 이상 차량을 운용할 수 없습니다 +STR_3142 :{WINDOW_COLOUR_2}수용량: {BLACK}{STRINGID} +STR_3143 :{SMALLFONT}{BLACK}손님을 지도에 표시합니다 +STR_3144 :{SMALLFONT}{BLACK}놀이기구와 시설을 지도에 표시합니다 +STR_3145 :{SMALLFONT}{BLACK}왼쪽으로 {STRINGID} 스크롤 +STR_3146 :{SMALLFONT}{BLACK}오른쪽으로 {STRINGID} 스크롤 +STR_3147 :{SMALLFONT}{BLACK}왼쪽으로 {STRINGID} 빠르게 스크롤 +STR_3148 :{SMALLFONT}{BLACK}오른쪽으로 {STRINGID} 빠르게 스크롤 +STR_3149 :{SMALLFONT}{BLACK}왼쪽/오른쪽으로 {STRINGID} 스크롤 +STR_3150 :{SMALLFONT}{BLACK}위로 {STRINGID} 스크롤 +STR_3151 :{SMALLFONT}{BLACK}아래로 {STRINGID} 스크롤 +STR_3152 :{SMALLFONT}{BLACK}위로 {STRINGID} 빠르게 스크롤 +STR_3153 :{SMALLFONT}{BLACK}아래로 {STRINGID} 빠르게 스크롤 +STR_3154 :{SMALLFONT}{BLACK}위/아래로 {STRINGID} 스크롤 +STR_3155 : +STR_3156 : +STR_3157 :지도 +STR_3158 :그래프 +STR_3159 :목록 +STR_3160 :<더 이상 사용하지 않음> +STR_3161 :<더 이상 사용하지 않음> +STR_3162 :충분한 메모리를 할당할 수 없습니다 +STR_3163 :새 데이터 설치중: +STR_3164 :{BLACK}{COMMA16}개 선택 됨 (최대 {COMMA16}개) +STR_3165 : +STR_3166 :{BLACK}(ID: +STR_3167 :{WINDOW_COLOUR_2}{BLACK}{COMMA16}개의 오브젝트 포함 +STR_3168 :{WINDOW_COLOUR_2}텍스트: {BLACK}{STRINGID} +STR_3169 :다음 오브젝트에 대한 데이터를 찾을 수 없습니다: +STR_3170 :그래픽을 저장할 공간이 충분하지 않습니다 +STR_3171 :이 종류의 오브젝트를 너무 많이 선택하였습니다 +STR_3172 :다음 오브젝트를 가장 먼저 선택해야 합니다: {STRING} +STR_3173 :이 오브젝트는 현재 사용 중입니다 +STR_3174 :이 오브젝트는 다른 오브젝트가 필요합니다 +STR_3175 :이 오브젝트는 이미 포함되어 있습니다 +STR_3176 :이 오브젝트를 선택할 수 없습니다 +STR_3177 :이 오브젝트를 선택 해제할 수 없습니다 +STR_3178 :최소한 하나 이상의 보도 오브젝트를 선택해야 합니다 +STR_3179 :최소한 하나 이상의 놀이기구/시설 오브젝트를 선택해야 합니다 +STR_3180 :올바르지 않은 오브젝트 선택 +STR_3181 :오브젝트 선택 - {STRINGID} +STR_3182 :공원 입구 종류를 반드시 선택해야 합니다 +STR_3183 :물 종류를 반드시 선택해야 합니다 +STR_3184 :놀이기구 차량/시설 +STR_3185 :소형 조형물 +STR_3186 :대형 조형물 +STR_3187 :벽/울타리 +STR_3188 :보도 팻말 +STR_3189 :보도 +STR_3190 :공원 기타 +STR_3191 :조형물 분류 +STR_3192 :공원 입구 +STR_3193 :물 +STR_3194 :시나리오 설명 +STR_3195 :연구 목록 +STR_3196 :{WINDOW_COLOUR_2}개발 그룹: {BLACK}{STRINGID} +STR_3197 :{WINDOW_COLOUR_2}게임 시작시 바로 사용할 수 있는 항목: +STR_3198 :{WINDOW_COLOUR_2}게임 중에 연구해야 하는 항목: +STR_3199 :무작위로 섞기 +STR_3200 :{SMALLFONT}{BLACK}게임 중에 연구해야 하는 항목 목록을 무작위로 섞습니다 +STR_3201 :오브젝트 선택 +STR_3202 :풍경 에디터 +STR_3203 :개발 목록 설정 화면 +STR_3204 :설정 선택 +STR_3205 :목표 선택 +STR_3206 :시나리오 저장 +STR_3207 :롤러코스터 디자이너 +STR_3208 :트랙 디자인 매니저 +STR_3209 :이전 단계로: +STR_3210 :다음 단계로: +STR_3211 :{WINDOW_COLOUR_2}지도 크기: +STR_3212 :{POP16}{COMMA16} x {PUSH16}{COMMA16} +STR_3213 :더 이상 맵 크기를 줄일 수 없습니다 +STR_3214 :더 이상 맵 크기를 늘일 수 없습니다 +STR_3215 :지도 가장자리와 너무 가깝습니다 +STR_3216 :{SMALLFONT}{BLACK}공원 소유지 등을 선택합니다 +STR_3217 :소유한 땅 +STR_3218 :소유한 건설권 +STR_3219 :판매 중인 땅 +STR_3220 :판매 중인 건설권 +STR_3221 :{SMALLFONT}{BLACK}공원이 이미 소유하고 있는 땅을 선택합니다 +STR_3222 :{SMALLFONT}{BLACK}공원이 이미 소유하고 있는 건설권을 선택합니다 +STR_3223 :{SMALLFONT}{BLACK}공원이 향후 구입할 수 있는 땅을 선택합니다 +STR_3224 :{SMALLFONT}{BLACK}공원이 향후 구입할 수 있는 건설권을 선택합니다 +STR_3225 :{SMALLFONT}{BLACK}선택한 위치에 오브젝트 숲 건설(무작위 건설) 모드를 켜거나 끕니다 +STR_3226 :{SMALLFONT}{BLACK}공원 입구 건설 +STR_3227 :공원 입구가 너무 많습니다! +STR_3228 :{SMALLFONT}{BLACK}손님이 나타나는 장소를 선택합니다 +STR_3229 :블록 브레이크는 탑승장 바로 다음에 사용할 수 없습니다 +STR_3230 :블록 브레이크는 블록 브레이크 바로 다음에 사용할 수 없습니다 +STR_3231 :블록 브레이크는 이 리프트 힐의 꼭대기 바로 다음에 사용할 수 없습니다 +STR_3232 :설정 - 재정 +STR_3233 :설정 - 손님 +STR_3234 :설정 - 공원 +STR_3235 :{SMALLFONT}{BLACK}재정 관련 설정을 보여줍니다 +STR_3236 :{SMALLFONT}{BLACK}손님 관련 설정을 보여줍니다 +STR_3237 :{SMALLFONT}{BLACK}공원 관련 설정을 보여줍니다 +STR_3238 :돈 무제한 +STR_3239 :{SMALLFONT}{BLACK}재정적 제한이 없도록 이 공원의 돈을 '무제한'으로 만듭니다 +STR_3240 :{WINDOW_COLOUR_2}초기 재정: +STR_3241 :{WINDOW_COLOUR_2}초기 대출: +STR_3242 :{WINDOW_COLOUR_2}최대 대출금: +STR_3243 :{WINDOW_COLOUR_2}연 이자율: +STR_3244 :광고 이벤트를 금지 +STR_3245 :{SMALLFONT}{BLACK}광고나 이벤트를 진행할 수 없도록 금지합니다 +STR_3246 :{WINDOW_COLOUR_2}{CURRENCY} +STR_3247 :{WINDOW_COLOUR_2}{COMMA16}% +STR_3248 :초기 보유 자금을 더 이상 늘릴 수 없습니다! +STR_3249 :초기 보유 자금을 더 이상 줄일 수 없습니다! +STR_3250 :초기 대출금을 더 이상 늘릴 수 없습니다! +STR_3251 :초기 대출금을 더 이상 줄일 수 없습니다! +STR_3252 :최대 대출금을 더 이상 늘릴 수 없습니다! +STR_3253 :최대 대출금을 더 이상 줄일 수 없습니다! +STR_3254 :이자율을 더 이상 늘릴 수 없습니다! +STR_3255 :이자율을 더 이상 줄일 수 없습니다! +STR_3256 :손님들이 격렬하지 않은 놀이기구를 선호함 +STR_3257 :{SMALLFONT}{BLACK}손님들이 일반적으로 덜 격렬한 놀이기구를 선호하게 만들지를 선택합니다 +STR_3258 :손님들이 격렬한 놀이기구를 선호함 +STR_3259 :{SMALLFONT}{BLACK}손님들이 일반적으로 더욱 격렬한 놀이기구를 선호하게 만들지를 선택합니다 +STR_3260 :{WINDOW_COLOUR_2}각 손님의 보유금 (평균): +STR_3261 :{WINDOW_COLOUR_2}손님의 초기 행복도: +STR_3262 :{WINDOW_COLOUR_2}손님의 초기 배고픔: +STR_3263 :{WINDOW_COLOUR_2}손님의 초기 목마름: +STR_3264 :더 이상 늘릴 수 없습니다! +STR_3265 :더 이상 줄일 수 없습니다! +STR_3266 :{SMALLFONT}{BLACK}공원 수익을 입장료로 낼지 놀이기구 탑승료로 낼지를 선택하세요 +STR_3267 :나무 제거 금지 +STR_3268 :{SMALLFONT}{BLACK}키 큰 나무의 제거를 금지합니다 +STR_3269 :지형 편집 금지 +STR_3270 :{SMALLFONT}{BLACK}지형을 편집할 수 없도록 금지합니다 +STR_3271 :나무 높이 이상 건설 금지 +STR_3272 :{SMALLFONT}{BLACK}높은 건축물의 건설을 금지합니다 +STR_3273 :공원 등급 난이도 상승 +STR_3274 :{SMALLFONT}{BLACK}공원 등급값이 더 급변하게 만듭니다 +STR_3275 :손님 생성 난이도 상승 +STR_3276 :{SMALLFONT}{BLACK}공원에 손님을 유치하기 더 어렵게 만듭니다 +STR_3277 :{WINDOW_COLOUR_2}땅 구입 비용: +STR_3278 :{WINDOW_COLOUR_2}건설권 구입 비용: +STR_3279 :놀이기구 탑승료만 받기 +STR_3280 :공원 입장료만 받기 +STR_3281 :{WINDOW_COLOUR_2}입장료: +STR_3282 :{SMALLFONT}{BLACK}목표와 공원 이름을 선택하세요 +STR_3283 :{SMALLFONT}{BLACK}보호할 놀이기구를 선택하세요 +STR_3284 :목표 선택 +STR_3285 :놀이기구 보호 +STR_3286 :{SMALLFONT}{BLACK}이 시나리오의 목표를 선택하세요 +STR_3287 :{WINDOW_COLOUR_2}목표: +STR_3288 :{SMALLFONT}{BLACK}기후 선택 +STR_3289 :{WINDOW_COLOUR_2}기후: +STR_3290 :춥고 습함 +STR_3291 :따뜻함 +STR_3292 :덥고 건조함 +STR_3293 :추움 +STR_3294 :바꾸기... +STR_3295 :{SMALLFONT}{BLACK}공원 이름을 바꿉니다 +STR_3296 :{SMALLFONT}{BLACK}시나리오 이름을 바꿉니다 +STR_3297 :{SMALLFONT}{BLACK}공원/시나리오의 상세 설명을 변경합니다 +STR_3298 :{WINDOW_COLOUR_2}공원 이름: {BLACK}{STRINGID} +STR_3299 :{WINDOW_COLOUR_2}공원/시나리오 상세 설명: +STR_3300 :{WINDOW_COLOUR_2}시나리오 이름: {BLACK}{STRINGID} +STR_3301 :{WINDOW_COLOUR_2}목표 날짜: +STR_3302 :{WINDOW_COLOUR_2}{MONTHYEAR} +STR_3303 :{WINDOW_COLOUR_2}손님 수: +STR_3304 :{WINDOW_COLOUR_2}공원 가치: +STR_3305 :{WINDOW_COLOUR_2}월 수익: +STR_3306 :{WINDOW_COLOUR_2}월 순이익: +STR_3307 :{WINDOW_COLOUR_2}최소 길이: +STR_3308 :{WINDOW_COLOUR_2}흥미도: +STR_3309 :{WINDOW_COLOUR_2}{COMMA16} +STR_3310 :{WINDOW_COLOUR_2}{LENGTH} +STR_3311 :{WINDOW_COLOUR_2}{COMMA2DP32} +STR_3312 :{WINDOW_COLOUR_2}보호되고 있는 놀이기구/시설 순서: +STR_3313 :시나리오 이름 +STR_3314 :시나리오 이름을 입력하세요: +STR_3315 :공원/시나리오 상세 설명 +STR_3316 :이 시나리오의 설명을 입력하세요: +STR_3317 :상세 설명 없음 +STR_3318 :{SMALLFONT}{BLACK}이 시나리오가 나타날 시나리오 분류를 선택하세요 +STR_3319 :{WINDOW_COLOUR_2}시나리오 분류: +STR_3320 :시나리오 파일을 저장할 수 없습니다... +STR_3321 :새 오브젝트가 성공적으로 설치되었습니다 +STR_3322 :{WINDOW_COLOUR_2}목표: {BLACK}{STRINGID} +STR_3323 :오브젝트 데이터가 존재하지 않음, ID: +STR_3324 :확장팩이 필요합니다: +STR_3325 :확장팩이 필요합니다 +STR_3326 :{WINDOW_COLOUR_2}(이미지 없음) +STR_3327 :손님이 나타나는 위치가 지정되지 않았습니다 +STR_3328 :다음 데이터 단계로 진행할 수 없습니다... +STR_3329 :공원 입구가 아직 지어지지 않았습니다 +STR_3330 :공원이 소유한 땅이 하나도 없습니다 +STR_3331 :공원 입구에서 지도 가장자리로 이어지는 길이 이어지지 않았거나 너무 복잡합니다. 1칸 너비의 길을 코너나 교차로가 최대한 없도록 하여 만들어야 합니다. +STR_3332 :공원 입구가 잘못된 방향을 향하고 있거나 지도 가장자리로 가는 길이 없습니다 +STR_3333 :게임 저장시 사용한 오브젝트를 같이 포함하여 저장 +STR_3334 :{SMALLFONT}{BLACK}필요한 경우 플러그 인 오브젝트(기본적으로 지원하지 않고 사용자가 추가된 오브젝트)를 저장된 게임 파일이나 시나리오 파일과 함께 저장합니다. 이러면 그 추가 오브젝트를 갖고 있지 않은 다른 사람이 이 파일을 불러올 때 자동으로 그 오브젝트를 설치하게 되지만 파일 용량이 늘어납니다 +STR_3335 :롤러코스터 디자이너 - 놀이기구 종류 & 차량을 선택하세요 +STR_3336 :트랙 디자인 매니저 - 놀이기구 종류를 선택하세요 +STR_3337 :<더 이상 사용하지 않음> +STR_3338 :{BLACK}커스텀 디자인 구조 +STR_3339 :{BLACK}{COMMA16}개의 디자인, 커스텀 디자인 구조 사용 가능 +STR_3340 :{BLACK}{COMMA16}개의 디자인, 커스텀 디자인 구조 사용 가능 +STR_3341 :{SMALLFONT}{BLACK}게임 도구 +STR_3342 :시나리오 에디터 +STR_3343 :저장된 게임을 시나리오로 변환 +STR_3344 :롤러코스터 디자이너 +STR_3345 :트랙 디자인 매니저 +STR_3346 :트랙 디자인을 저장할 수 없습니다... +STR_3347 :놀이기구가 너무 큽니다 - 너무 많은 요소를 포함하고 있거나 조형물이 너무 넓게 퍼져 있습니다 +STR_3348 :이름 바꾸기 +STR_3349 :삭제 +STR_3350 :트랙 디자인 이름 +STR_3351 :이 트랙 디자인의 새 이름을 입력하세요: +STR_3352 :트랙 디자인 이름을 바꿀 수 없습니다... +STR_3353 :새 이름에 유효하지 않은 문자가 있습니다 +STR_3354 :이 이름으로 된 파일이 이미 존재하거나 파일이 쓰기 불가능한 상태입니다 +STR_3355 :파일이 쓰기 불가능한 상태이거나 잠겨있습니다 +STR_3356 :파일 삭제 +STR_3357 :{WINDOW_COLOUR_2}{STRINGID} 파일을 영구적으로 삭제하시겠습니까 ? +STR_3358 :트랙 디자인을 삭제할 수 없습니다... +STR_3359 :{BLACK}이 종류의 트랙 디자인 없음 +STR_3360 :경고! +STR_3361 :트랙 디자인이 너무 많습니다. 일부가 표시되지 않을 것입니다. +STR_3362 :<더 이상 사용하지 않음> +STR_3363 :<더 이상 사용하지 않음> +STR_3364 :고급 +STR_3365 :{SMALLFONT}{BLACK}조형물 그룹과 함께 조형물 각각을 따로 선택할 수 있게 허용합니다 +STR_3366 :{BLACK}= 놀이기구 +STR_3367 :{BLACK}= 음식 상점 +STR_3368 :{BLACK}= 음료수 상점 +STR_3369 :{BLACK}= 기념품 가게 +STR_3370 :{BLACK}= 안내소 +STR_3371 :{BLACK}= 응급치료소 +STR_3372 :{BLACK}= 현금지급기 +STR_3373 :{BLACK}= 화장실 +STR_3374 :경고: 오브젝트를 너무 많이 선택하였습니다 +STR_3375 :이 조형물 그룹의 모든 오브젝트가 선택되지는 않았습니다 +STR_3376 :새 트랙 디자인 설치... +STR_3377 :{SMALLFONT}{BLACK}새 트랙 디자인 파일 설치 +STR_3378 :설치 +STR_3379 :취소 +STR_3380 :U이 트랙 디자인 파일을 설치할 수 없습니다... +STR_3381 :파일이 적합하지 않거나 유효하지 않은 데이터를 포함하고 있습니다 +STR_3382 :파일 복사에 실패하였습니다 +STR_3383 :트랙 디자인에 지정할 새 이름을 선택하세요 +STR_3384 :같은 이름의 트랙 디자인이 이미 존재합니다 이 디자인에 지정할 다른 이름을 입력하세요: +STR_3385 :초심자 튜토리얼 +STR_3386 :놀이기구 직접 만들기 튜토리얼 +STR_3387 :롤러코스터 만들기 튜토리얼 +STR_3388 :선택한 모드로 바꿀 수 없습니다 +STR_3389 :추가 조형물 항목을 선택할 수 없습니다... +STR_3390 :항목을 너무 많이 선택하였습니다 +STR_3391 :{SMALLFONT}{BLACK}여기 우리 공원이 있습니다. 한 번 둘러보죠... +STR_3392 :{SMALLFONT}{BLACK}마우스 오른쪽 버튼을 누른 채로 움직이면 화면을 빠르게 움직일 수 있습니다... +STR_3393 :{SMALLFONT}{BLACK}공원을 더 많이 보고 싶다면 화면 위쪽에 있는 축소 버튼을 이용하여 화면을 축소할 수 있습니다... +STR_3394 :{SMALLFONT}{BLACK}또 90도씩 화면을 회전시킬 수도 있습니다... +STR_3395 :{SMALLFONT}{BLACK}하지만 이 스케일에서 뭔가를 건설하는 건 조금 힘듭니다. 다시 화면을 확대하여 원래대로 돌려놓읍시다... +STR_3396 :{SMALLFONT}{BLACK}공원의 첫 놀이기구로 간단한 놀이기구를 만들어보죠... +STR_3397 :{SMALLFONT}{BLACK}'유령'처럼 생긴 하얀 이미지는 놀이기구가 지어질 위치를 나타내는 것입니다. 마우스 커서를 움직여서 설치할 위치를 잡고 클릭하여 건설합니다... +STR_3398 :{SMALLFONT}{BLACK}놀이기구는 입구와 출구가 필요합니다. 마우스 커서를 놀이기구의 가장자리에 두고 클릭해서 입구를 먼저 만들고, 그 다음으로 출구도 만듭니다... +STR_3399 :{SMALLFONT}{BLACK}우리가 방금 만든 새 놀이기구에 손님이 접근하기 위해서는 길을 만들어야 합니다... +STR_3400 :{SMALLFONT}{BLACK}놀이기구 입구에 연결하는 길은 '대기줄' 보도라는 특별한 길을 사용할 것입니다... +STR_3401 :{SMALLFONT}{BLACK}출구에 연결하는 길은 그냥 '평범한' 보도면 됩니다... +STR_3402 :{SMALLFONT}{BLACK}좋아요, 놀이기구를 개장해보죠! 놀이기구를 열기 위해서는 놀이기구 창에서 깃발 모양의 아이콘을 클릭하고 '열기'를 선택하세요... +STR_3403 :{SMALLFONT}{BLACK}그런데 손님은 어디있을까요? +STR_3404 :{SMALLFONT}{BLACK}이런, 공원이 아직 닫혀있네요! 공원의 문을 활짝 열어보죠... +STR_3405 :{SMALLFONT}{BLACK}첫 손님이 올 때까지 약간의 조형물을 만들어보죠... +STR_3406 :{SMALLFONT}{BLACK}여기 빈 공원이 있습니다. 이제 여기에 간단한 커스텀 디자인 놀이기구를 만들어보겠습니다... +STR_3407 :{SMALLFONT}{BLACK}먼저 시작할 위치를 골라야 합니다... +STR_3408 :{SMALLFONT}{BLACK}방금 우리가 만든 트랙 섹션은 놀이기구에 손님을 태우고 내리는 '탑승장'입니다... +STR_3409 :{SMALLFONT}{BLACK}이제 탑증상 섹션을 조금 더 추가하여 승강장을 확장해보죠... +STR_3410 :{SMALLFONT}{BLACK}건설 창의 가장 위에 있는 아이콘을 보시면 알겠지만 추가할 수 있는 트랙 조각이 여러 가지 있습니다... +STR_3411 :{SMALLFONT}{BLACK}왼쪽 커브를 선택해보겠습니다... +STR_3412 :{SMALLFONT}{BLACK}커브는 아직 건설되지 않았지만 하얀 유령 이미지가 어디에 지어질지를 보여주고 있습니다. 커다랗게 생긴 '건설하기' 버튼을 클릭해서 실제로 트랙을 건설합시다... +STR_3413 :{SMALLFONT}{BLACK}이제 직진 트랙을 만들고 싶습니다. 직진 트랙 아이콘을 클릭합시다... +STR_3414 :{SMALLFONT}{BLACK}이제 트랙을 완성합시다. 그리고 놀이기구의 입구와 출구를 만들어야 합니다. +STR_3415 :{SMALLFONT}{BLACK}이제 놀이기구가 제대로 돌아가는지 테스트해보죠... +STR_3416 :{SMALLFONT}{BLACK}테스트가 진행되는 동안, 대기줄과 출구 보도를 만들도록 하죠... +STR_3417 :{SMALLFONT}{BLACK}됐습니다. 이제 공원과 놀이기구를 열어보죠... +STR_3418 :{SMALLFONT}{BLACK}우리가 방금 새로 만든 놀이기구가 별로 재미가 없나봅니다. 조형물을 조금 추가해야할 것 같군요? +STR_3419 :{SMALLFONT}{BLACK}조형물 위에 조형물을 얹거나 공중에 띄워 설치하려면, SHIFT 키를 누른 채로 마우스를 움직여 원하는 높이에서 클릭하시면 됩니다... +STR_3420 :{SMALLFONT}{BLACK}일부 조형물은 설치하고 나면 다시 색을 칠할 수 없으니 유의하세요... +STR_3421 :{SMALLFONT}{BLACK}놀이기구에 음악을 흐르게 만들어봅시다.... +STR_3422 :{SMALLFONT}{BLACK}롤러코스터를 만들어보죠 ! +STR_3423 :{SMALLFONT}{BLACK}미리 디자인된 롤러코스터가 있습니다만, 우리는 스스로 트랙을 디자인해서 만들 것입니다... +STR_3424 :{SMALLFONT}{BLACK}탑승장이 만들어졌습니다. 이제 리프트 힐이 필요합니다... +STR_3425 :{SMALLFONT}{BLACK}롤러코스터의 열차에는 동력이 없어서 열차가 첫 번째 언덕을 통과하기 위해서는 '체인 리프트'가 필요합니다... +STR_3426 :{SMALLFONT}{BLACK}리프트 힐이 완성되었습니다. 이제 첫 번째 낙하 구간을 만들죠... +STR_3427 :{SMALLFONT}{BLACK}이런 커브는 좋은 생각이 아닙니다. 탑승자는 열차가 달리면서 측면 중력때문에 측면으로 쏠리기 때문입니다... +STR_3428 :{SMALLFONT}{BLACK}트랙의 커브에 기울임을 주면 탑승자들이 측면으로 쏠리는 대신에 좌석 아래쪽으로 당겨지게 되어 안정적인 탑승감을 선사할 수 있습니다... +STR_3429 :{SMALLFONT}{BLACK}저런, 그렇게 하면 제대로 굴러가질 않습니다! 높이 고도 표시를 보시면 알겠지만 두 번째 언덕이 첫 번째 언덕보다 높습니다... +STR_3430 :{SMALLFONT}{BLACK}열차가 제대로 굴러가게 만드려면, 각 언덕은 이전 언덕보다 조금 낮아야 함을 잊지 마세요... +STR_3431 :{SMALLFONT}{BLACK}훨씬 낫네요. 이제 열차가 언덕을 오를 수 있게 되었습니다! 이제는 몇 개의 특수 트랙을 설치해보겠습니다... +STR_3432 :{SMALLFONT}{BLACK}마지막 커브를 돌아서 탑승장에 돌아가기 전에 열차의 속력을 늦춰야 합니다. 그러니까 브레이크를 걸어보도록 하죠... +STR_3433 :{SMALLFONT}{BLACK}이제 마지막으로 두 대의 여열차가 안전하게 서킷을 돌 수 있도록 만들어주는 '블록 브레이크'를 추가해보죠. +STR_3434 :{SMALLFONT}{BLACK}놀이기구를 테스트하고 제대로 굴러가는 모습을 감상해보도록 하죠! +STR_3435 :{SMALLFONT}{BLACK}훌륭합니다, 잘 작동하네요! 보도를 추가해서 손님들이 새로 만든 롤러코스터에 접근할 수 있게 만들어 주세요... +STR_3436 :{SMALLFONT}{BLACK}첫 번째 탑승자를 기다리는 동안, 놀이기구를 조금만 커스터마이징해보죠... +STR_3437 :{SMALLFONT}{BLACK}조형물을 한꺼번에 제거 +STR_3438 :여기에 있는 모든 조형물을 다 제거하지 못 하였습니다... +STR_3439 :조형물 제거 +STR_3440 :1쪽 +STR_3441 :2쪽 +STR_3442 :3쪽 +STR_3443 :4쪽 +STR_3444 :5쪽 +STR_3445 :순찰 영역 설정 +STR_3446 :순찰 영역 해제 + +# New strings, cleaner +STR_5120 :재정 +STR_5121 :연구 +STR_5122 :놀이기구를 (RCT1처럼) 트랙 종류 별로 선택 +STR_5123 :놀이기구 새 걸로 +STR_5124 :<더 이상 사용하지 않음> +STR_5125 :모두 파괴 가능 +STR_5126 :무작위 타이틀 음악 +STR_5127 :{SMALLFONT}{BLACK}땅을 올리거나 내리지 않음 +STR_5128 :선택 도구 크기 +STR_5129 :선택 도구 크기를 {COMMA16}에서 {COMMA16} 사이의 값으로 입력하세요 +STR_5130 :지도 크기 +STR_5131 :지도 크기를 {COMMA16}에서 {COMMA16} 사이의 값으로 입력하세요 +STR_5132 :모든 놀이기구 수리 +STR_5133 :{SMALLFONT}{BLACK}땅 구입 도구 크기 줄이기 +STR_5134 :{SMALLFONT}{BLACK}땅 구입 도구 크기 늘이기 +STR_5135 :{SMALLFONT}{BLACK}땅 소유권과 건설권 구입하기 +STR_5136 :땅 소유권 +STR_5137 :체인/발사 속력을 {VELOCITY}까지 허용 +STR_5138 :{SMALLFONT}{WINDOW_COLOUR_2}{STRINGID} +STR_5139 :{WHITE}{STRINGID} +STR_5140 :브레이크 고장 안 나게 +STR_5141 :고장 안 나게 +STR_5142 :보통 속도 +STR_5143 :조금 빠른 속도 +STR_5144 :빠른 속도 +STR_5145 :매우 빠른 속도 +STR_5146 :엄청 빠른 속도 +STR_5147 :치트 +STR_5148 :{SMALLFONT}{BLACK}게임 속도를 변경합니다 +STR_5149 :{SMALLFONT}{BLACK}치트 창을 엽니다 +STR_5150 :디버깅 도구를 사용합니다 +STR_5151 :, +STR_5152 :. +STR_5153 :테마 수정... +STR_5154 :하드웨어 디스플레이 +STR_5155 :완성되지 않은 트랙의 테스트 허용 +STR_5156 :{SMALLFONT}{BLACK}대부분의 놀이기구 종류에서 트랙이 완성되지 않아도 테스트를 할 수 있도록 허용합니다. 블록 섹션 모드에는 적용되지 않습니다 +STR_5157 :모든 가격 잠금 해제 +STR_5158 :종료하고 메뉴로 +STR_5159 :OpenRCT2 종료 +STR_5160 :{POP16}{MONTH} {PUSH16}{PUSH16}{STRINGID}, {POP16}{COMMA16}년 +STR_5161 :날짜 형식: +STR_5162 :일/월/년 +STR_5163 :월/일/년 +STR_5164 :트위치 채널 이름 +STR_5165 :손님 이름을 팔로워 이름을 따서 붙이기 +STR_5166 :{SMALLFONT}{BLACK}트위치 채널의 팔로워 이름을 따서 손님 이름으로 사용합니다 +STR_5167 :팔로워 손님 추적 +STR_5168 :{SMALLFONT}{BLACK}채널의 트위치 팔로워 이름을 딴 손님을 추적합니다 +STR_5169 :손님 이름을 트위치 채팅의 접속자 이름을 따서 붙이기 +STR_5170 :{SMALLFONT}{BLACK}트위치 채팅의 접속자 이름을 따서 손님 이름으로 사용합니다 +STR_5171 :채팅 인원 추적 +STR_5172 :{SMALLFONT}{BLACK}트위치 채팅에 참가하고 있는 사람들의 이름을 딴 손님의 행적을 추적합니다 +STR_5173 :트위치 채팅 내용을 뉴스로 전송 +STR_5174 :{SMALLFONT}{BLACK}트위치의 채팅 메시지를 !news를 이용하여 게임 메시지로 알려줍니다 +STR_5175 :트위치 채널 이름 입력 +STR_5176 :트위치 통합 허용 +STR_5177 :풀 스크린 모드: +STR_5178 :{SMALLFONT}{BLACK}재정 치트를 보여줍니다 +STR_5179 :{SMALLFONT}{BLACK}손님 치트를 보여줍니다 +STR_5180 :{SMALLFONT}{BLACK}공원 치트를 보여줍니다 +STR_5181 :{SMALLFONT}{BLACK}놀이기구 치트를 보여줍니다 +STR_5182 :{INT32} +STR_5183 :기본 땅 높이 +STR_5184 :기본 땅 높이를 {COMMA16} 사이의 {COMMA16} 사이의 값으로 입력하세요 +STR_5185 :물 높이 +STR_5186 :물 높이를 {COMMA16}에서 {COMMA16} 사이의 값으로 입력하세요 +STR_5187 :재정 +STR_5188 :새 광고 +STR_5189 :연구 +STR_5190 :지도 +STR_5191 :외부화면 +STR_5192 :최근 뉴스 +STR_5193 :땅 +STR_5194 :물 +STR_5195 :조형물 제거 +STR_5196 :땅 권리 +STR_5197 :조형물 +STR_5198 :보도 +STR_5199 :놀이기구 건설 +STR_5200 :트랙 디자인 건설 +STR_5201 :새 놀이기구 +STR_5202 :트랙 디자인 선택 +STR_5203 :놀이기구 +STR_5204 :놀이기구 목록 +STR_5205 :손님 +STR_5206 :손님 목록 +STR_5207 :직원 +STR_5208 :직원 목록 +STR_5209 :전광판 +STR_5210 :오브젝트 선택 +STR_5211 :개발 목록 +STR_5212 :시나리오 옵션 +STR_5213 :목표 설정 +STR_5214 :지도 생성 +STR_5215 :트랙 디자인 매니저 +STR_5216 :트랙 디자인 매니저 목록 +STR_5217 :치트 +STR_5218 :테마 +STR_5219 :설정 +STR_5220 :키보드 단축키 +STR_5221 :키보드 단축키 변경 +STR_5222 :불러오기/저장 +STR_5223 :저장 입력 +STR_5224 :놀이기구 파괴 확인 +STR_5225 :직원 해고 확인 +STR_5226 :트랙 삭제 확인 +STR_5227 :저장 덮어쓰기 확인 +STR_5228 :{SMALLFONT}{BLACK}주 UI +STR_5229 :{SMALLFONT}{BLACK}공원 +STR_5230 :{SMALLFONT}{BLACK}도구 +STR_5231 :{SMALLFONT}{BLACK}놀이기구 및 손님 +STR_5232 :{SMALLFONT}{BLACK}에디터 +STR_5233 :{SMALLFONT}{BLACK}기타 +STR_5234 :{SMALLFONT}{BLACK}확인창 +STR_5235 :{SMALLFONT}{BLACK}설정 +STR_5236 :창: +STR_5237 :색상표: +STR_5238 :현재 테마: +STR_5239 :복제 +STR_5240 :테마 이름을 입력하세요 +STR_5241 :테마를 변경할 수 없습니다 +STR_5242 :테마 이름이 이미 존재합니다 +STR_5243 :사용할 수 없는 문자가 있습니다 +STR_5244 :테마 +STR_5245 :상단 툴바 +STR_5246 :하단 툴바 +STR_5247 :트랙 에디터 하단 툴바 +STR_5248 :시나리오 에디터 하단 툴바 +STR_5249 :타이틀 메뉴 버튼 +STR_5250 :타이틀 종료 버튼 +STR_5251 :타이틀 설정 버튼 +STR_5252 :타이틀 시나리오 선택 +STR_5253 :공원 정보 +STR_5254 :생성 +STR_5255 :{SMALLFONT}{BLACK}새 타이틀 시퀀스를 스크래치로부터 생성합니다 +STR_5256 :새 테마를 생성하여 다음으로 바꿉니다 +STR_5257 :{SMALLFONT}{BLACK}현재 테마를 기반으로 하여 새 테마를 생성합니다 +STR_5258 :{SMALLFONT}{BLACK}현재 테마를 삭제합니다 +STR_5259 :{SMALLFONT}{BLACK}현재 테마의 이름을 바꿉니다 +STR_5260 :초대형 스크린 샷 +STR_5261 :필터 +STR_5262 :와키 월드 +STR_5263 :타임 트위스터 +STR_5264 :사용자 추가 +STR_5265 :{SMALLFONT}{BLACK}어떤 콘텐츠 내용을 볼지 선택하세요 +STR_5266 :{SMALLFONT}{BLACK}표시 +STR_5267 :{SMALLFONT}{BLACK}문화와 단위 +STR_5268 :{SMALLFONT}{BLACK}오디오 +STR_5269 :{SMALLFONT}{BLACK}제어 및 인터페이스 +STR_5270 :{SMALLFONT}{BLACK}기타 +STR_5271 :{SMALLFONT}{BLACK}Twitch +STR_5272 :{SMALLFONT}{BLACK}소형 조형물 +STR_5273 :{SMALLFONT}{BLACK}대형 조형물 +STR_5274 :{SMALLFONT}{BLACK}보도 +STR_5275 :오브젝트 검색 +STR_5276 :검색할 오브젝트 이름을 입력하세요 +STR_5277 :초기화 +STR_5278 :모래상자 모드 +STR_5279 :모래상자 모드 끄기 +STR_5280 :{SMALLFONT}{BLACK}지도 창에서 땅 소유권 설정이 가능하도록 바꾸고 시나리오 에디터에서만 쓸 수 있던 기능을 사용할 수 있게 만듭니다 +STR_5281 :{SMALLFONT}{BLACK}기능 +STR_5282 :RCT1 놀이기구 열기/닫기 아이콘 +STR_5283 :RCT1 공원 열기/닫기 아이콘 +STR_5284 :RCT1 시나리오 선택 폰트 +STR_5285 :손님 터트리기!!! +STR_5286 :{SMALLFONT}{BLACK}일부 손님을 터뜨립니다 +STR_5287 :놀이기구가 이미 고장난 상태입니다 +STR_5288 :놀이기구가 닫혔습니다 +STR_5289 :이 놀이기구는 고장이 나지 않습니다 +STR_5290 :놀이기구 수리 +STR_5291 :강제로 고장낼 수 없습니다 +STR_5292 :{SMALLFONT}{BLACK}강제로 고장을 냅니다 +STR_5293 :{SMALLFONT}{BLACK}놀이기구/시설을 닫습니다 +STR_5294 :{SMALLFONT}{BLACK}놀이기구/시설을 테스트합니다 +STR_5295 :{SMALLFONT}{BLACK}놀이기구/시설을 엽니다 +STR_5296 :{SMALLFONT}{BLACK}공원을 닫습니다 +STR_5297 :{SMALLFONT}{BLACK}공원을 엽니다 +STR_5298 :{RED}{STRINGID} +STR_5299 :{LIGHTPINK}{STRINGID} +STR_5300 :{SMALLFONT}{BLACK}빠른 직원 해고 +STR_5301 :{MEDIUMFONT}{BLACK}대출금을 모두 갚습니다 +STR_5302 :대출금 모두 갚기 +STR_5303 :일시정지 모드에서 건설 허용 +STR_5304 :타이틀 시퀀스: +STR_5305 :롤러코스터 타이쿤 1 +STR_5306 :롤러코스터 타이쿤 1 (AA) +STR_5307 :롤러코스터 타이쿤 1 (AA + LL) +STR_5308 :롤러코스터 타이쿤 2 +STR_5309 :OpenRCT2 +STR_5310 :무작위 +STR_5311 :{SMALLFONT}{BLACK}디버그 도구 +STR_5312 :콘솔 보이기 +STR_5313 :칸 탐색기 열기 +STR_5314 :칸 탐색기 +STR_5315 :잔디 +STR_5316 :모래 +STR_5317 :진흙 +STR_5318 :바위 +STR_5319 :화성 +STR_5320 :체스판 +STR_5321 :자란 잔디 +STR_5322 :눈 +STR_5323 :격자 (빨강) +STR_5324 :격자 (노랑) +STR_5325 :격자 (파랑) +STR_5326 :격자 (처럭) +STR_5327 :모래 (어두움) +STR_5328 :모래 (밝음) +STR_5329 :체스판 (반전) +STR_5330 :지하 시야 +STR_5331 :바위 +STR_5332 :나무 (빨강) +STR_5333 :나무 (검정) +STR_5334 :눈 +STR_5335 :놀이기구 입구 +STR_5336 :놀이기구 출구 +STR_5337 :공원 입구 +STR_5338 :요소 종류 +STR_5339 :기본 고도 +STR_5340 :최상단 높이 +STR_5341 :플래그 +STR_5342 :지도 칸 선택 +STR_5343 :직원 자동 배치 +STR_5344 :변경기록 +STR_5345 :재정 치트 +STR_5346 :손님 치트 +STR_5347 :공원 치트 +STR_5348 :놀이기구 치트 +STR_5349 :{SMALLFONT}{BLACK}모든 놀이기구 +STR_5350 :최대 +STR_5351 :최소 +STR_5352 :{BLACK}행복도: +STR_5353 :{BLACK}에너지: +STR_5354 :{BLACK}배고픔: +STR_5355 :{BLACK}목마름: +STR_5356 :{BLACK}멀미도: +STR_5357 :{BLACK}멀미 참을성: +STR_5358 :{BLACK}화장실: +STR_5359 :손님 없애기 +STR_5360 :{SMALLFONT}{BLACK}지도 상의 모든 손님을 없앱니다 +STR_5361 :모든 손님에게 다음 물건 주기: +STR_5362 :{BLACK}손님들의 선호 격렬도 설정: +STR_5363 :1 이상 +STR_5364 :15 이하 +STR_5365 :{BLACK}직원 속도: +STR_5366 :보통 +STR_5367 :빠름 +STR_5368 :충돌 이력 제거 +STR_5369 :공원 설정... +STR_5370 :{SMALLFONT}{BLACK}제한, 손님 생성, 돈 등의{NEWLINE}공원과 관련된 설정을 수정하려면{NEWLINE}이 버튼을 클릭하세요. +STR_5371 :오브젝트 선택 +STR_5372 :마우스 오른쪽 드래그시 좌우 반전 +STR_5373 :이름 {STRINGID} +STR_5374 :날짜 {STRINGID} +STR_5375 :{UP} +STR_5376 :{DOWN} +STR_5377 :{SMALLFONT}{BLACK}저장 +STR_5378 :{SMALLFONT}{BLACK}스크립트 +STR_5379 :{SMALLFONT}{BLACK}다음 기다리기 명령으로 건너뜁니다 +STR_5380 :{SMALLFONT}{BLACK}타이틀 시퀀스의 재생을 시작합니다 +STR_5381 :{SMALLFONT}{BLACK}타이틀 시퀀스의 재생을 중지합니다 +STR_5382 :{SMALLFONT}{BLACK}타이틀 시퀀스를 재시작합니다 +STR_5383 :{SMALLFONT}{BLACK}현재 타이클 시퀀스를 기반으로 새 타이틀 시퀀스를 생성합니다 +STR_5384 :{SMALLFONT}{BLACK}현재 타이틀 시퀀스를 삭제합니다 +STR_5385 :{SMALLFONT}{BLACK}현재 타이틀 시퀀스를 이름을 바꿉니다 +STR_5386 :{SMALLFONT}{BLACK}새 명령을 삽입합니다 +STR_5387 :{SMALLFONT}{BLACK}선택한 명령을 수정합니다 +STR_5388 :{SMALLFONT}{BLACK}선택한 명령을 삭제합니다 +STR_5389 :{SMALLFONT}{BLACK}타이틀 시퀀스에서 선택한 명령을 건너뜁니다 +STR_5390 :{SMALLFONT}{BLACK}선택한 명령을 아래로 이동합니다 +STR_5391 :{SMALLFONT}{BLACK}선택한 명령을 위로 이동합니다 +STR_5392 :{SMALLFONT}{BLACK}타이틀 시퀀스에 게임 저장 파일을 추가합니다 +STR_5393 :{SMALLFONT}{BLACK}타이틀 시퀀스에서 선택한 게임 저장 파일을 제거합니다 +STR_5394 :{SMALLFONT}{BLACK}선택한 게임 저장 파일 이름을 바꿉니다 +STR_5395 :{SMALLFONT}{BLACK}선택한 게임 저장 파일을 게임에서 불러옵니다 +STR_5396 :{SMALLFONT}{BLACK}게임 바깥에서 뭔가 변화가 생기면 타이틀 시퀀스를 다시 불러옵니다 +STR_5397 :타이틀 화면에서만 사용할 수 있습니다 +STR_5398 :타이틀 시퀀스가 재생 중일 때에는 수정할 수 없습니다 +STR_5399 :계속 수정하려면 중지 버튼을 누르세요 +STR_5400 :타이틀 시퀀스를 변경할 수 없습니다 +STR_5401 :다음으로 바꾸기 위해 타이틀 시퀀스를 생성합니다: +STR_5402 :타이틀 시퀀스를 불러오는데 실패하였습니다 +STR_5403 :불러오기나 기다리기 명령이 없거나 유효하지 않은 게임 저장 파일이 포함되었을 수 있습니다 +STR_5404 :이미 존재하는 이름입니다 +STR_5405 :세이브 파일의 이름을 입력하세요 +STR_5406 :타이틀 시퀀스 이름을 입력하세요 +STR_5407 :추가 +STR_5408 :제거 +STR_5409 :삽입 +STR_5410 :편집 +STR_5411 :다시 불러오기 +STR_5412 :건너뛰기 +STR_5413 :불러오기 +STR_5414 :불러오기 - {MOVE_X}{87}Six Flags Magic Mountain.SC6 +STR_5415 :불러오기 - {MOVE_X}{87}{STRING} +STR_5416 :불러오기 - {MOVE_X}{87}세이브 선택되지 않음 +STR_5417 :위치 +STR_5418 :위치 - {MOVE_X}{87}{COMMA16} {COMMA16} +STR_5419 :회전 +STR_5420 :{MOVE_X}{87}{COMMA16} 회전 +STR_5421 :확대 +STR_5422 :{MOVE_X}{87}{COMMA16} 확대 +STR_5423 :기다림 +STR_5424 :{MOVE_X}{87}{COMMA16} 동안 기다림 +STR_5425 :재시작 +STR_5426 :끝 +STR_5427 :좌표: +STR_5428 :반시계 방향 회전: +STR_5429 :확대 수준: +STR_5430 :기다릴 시간: +STR_5431 :불러올 세이브 파일: +STR_5432 :명령: +STR_5433 :타이틀 시퀀스 +STR_5434 :명령 에디터 +STR_5435 :세이브 이름 바꾸기 +STR_5436 :타이틀 시퀀스 편집하기... +STR_5437 :선택된 세이브 없음 +STR_5438 :명령 에디터가 열려있을 때 변경할 수 없습니다 +STR_5439 :4초 이상의 기다림 명령은 재시작 명령이 필요합니다. +STR_5440 :커서가 게임 밖으로 나가면 풀스크린을 최소화 +STR_5441 :{SMALLFONT}{BLACK}놀이기구를 RCT1처럼 종류별로 구분합니다. +STR_5442 :공원 등급 고정: +STR_5443 :속도{MOVE_X}{87}{STRINGID} +STR_5444 :속도: +STR_5445 :속도 +STR_5446 :얻기 +STR_5447 :종류 {STRINGID} +STR_5448 :놀이기구 / 차량 {STRINGID} +STR_5449 :게임 속도 느리게 +STR_5450 :게임 속도 빠르게 +STR_5451 :치트 창 열기 +STR_5452 :메뉴 표시 설정 변경 +STR_5453 :다른 놀이기구 선택 +STR_5454 :FPS 제한 해제 +STR_5455 :모래상자 모드 +STR_5456 :겹쳐짓기 모드 +STR_5457 :지지대 제한 없애기 +STR_5458 :시계방향으로 회전 +STR_5459 :반시계방향으로 회전 +STR_5460 :화면을 반시계방향으로 회전 +STR_5461 :손님 매개변수 설정 +STR_5462 :{CURRENCY} +STR_5463 :목표: 즐기세요! +STR_5464 :일반 +STR_5465 :기후 +STR_5466 :직원 +STR_5467 :ALT + +STR_5468 :최근 메시지 +STR_5469 :맵을 위로 스크롤 +STR_5470 :맵을 왼쪽으로 스크롤 +STR_5471 :맵을 아래로 스크롤 +STR_5472 :맵을 오른쪽으로 스크롤 +STR_5473 :밤낮을 순환 +STR_5474 :전광판의 영문자를 대문자로 표시 +STR_5475 :{COMMA16}주 +STR_5476 :하드웨어 +STR_5477 :지도 렌더링 +STR_5478 :컨트롤 +STR_5479 :메뉴 +STR_5480 :메뉴 버튼 보이기: +STR_5481 :테마 +STR_5482 :{WINDOW_COLOUR_2}최근 점검 시간: {BLACK}1분 +STR_5483 :{BLACK}({COMMA16}주 남음) +STR_5484 :{BLACK}({COMMA16}주 남음) +STR_5485 :{SMALLFONT}{STRING} +STR_5486 :{BLACK}{COMMA16} +STR_5487 :{SMALLFONT}{BLACK}최근 메시지 보이기 +STR_5488 :입구 없음 +STR_5489 :{SMALLFONT}{BLACK}추적 중인 손님만 보기 +STR_5490 :게임 밖으로 커서가 나가면 효과음 끄기 +STR_5491 :개발 목록 +STR_5492 :시나리오 설정 +STR_5493 :메시지 보내기 +STR_5494 :<더 이상 사용하지 않음> +STR_5495 :플레이어 목록 +STR_5496 :플레이어: +STR_5497 :핑: +STR_5498 :서버 목록 +STR_5499 :플레이어 이름: +STR_5500 :서버 추가 +STR_5501 :서버 열기 +STR_5502 :멀티플레이 +STR_5503 :호스트네임이나 IP 주소를 입력하세요: +STR_5504 :{SMALLFONT}{BLACK}멀티플레이 창을 엽니다 +STR_5505 :서버에 접속할 수 없습니다 +STR_5506 :손님이 격렬도를 무시하고 탐 +STR_5507 :미화원이 기본적으로 잔디를 깎음 +STR_5508 :올바르지 않은 체크합을 가진 파일 불러오기 허용 +STR_5509 :{SMALLFONT}{BLACK}데모에서 저장한 시나리오나 손상된 저장 파일과 같이 올바르지 않은 체크합을 가진 시나리오나 저장 파일을 불러오는 것을 허용합니다. +STR_5510 :기본 사운드 장치 +STR_5511 :(알 수 없음) +STR_5512 :다른 이름으로 저장 +STR_5513 :(간편) 게임 저장 +STR_5514 :기물을 파손하지 않게 하기 +STR_5515 :{SMALLFONT}{BLACK}손님이 화가 났을 때 기물을 파손하지 않도록 설정합니다 +STR_5516 :{SMALLFONT}{BLACK}검은색 +STR_5517 :{SMALLFONT}{BLACK}회색 +STR_5518 :{SMALLFONT}{BLACK}흰색 +STR_5519 :{SMALLFONT}{BLACK}어두운 보라색 +STR_5520 :{SMALLFONT}{BLACK}보라색 +STR_5521 :{SMALLFONT}{BLACK}밝은 보라색 +STR_5522 :{SMALLFONT}{BLACK}어두운 파란색 +STR_5523 :{SMALLFONT}{BLACK}밝은 파란색 +STR_5524 :{SMALLFONT}{BLACK}아이시 블루 +STR_5525 :{SMALLFONT}{BLACK}틸 +STR_5526 :{SMALLFONT}{BLACK}아쿠아마린 +STR_5527 :{SMALLFONT}{BLACK}짙은 녹색 +STR_5528 :{SMALLFONT}{BLACK}어두운 녹색 +STR_5529 :{SMALLFONT}{BLACK}모스 그린 +STR_5530 :{SMALLFONT}{BLACK}밝은 녹색 +STR_5531 :{SMALLFONT}{BLACK}올리브 그린 +STR_5532 :{SMALLFONT}{BLACK}어두운 올리브 그린 +STR_5533 :{SMALLFONT}{BLACK}밝은 노란색 +STR_5534 :{SMALLFONT}{BLACK}노란색 +STR_5535 :{SMALLFONT}{BLACK}어두운 노란색 +STR_5536 :{SMALLFONT}{BLACK}밝은 주황색 +STR_5537 :{SMALLFONT}{BLACK}어두운 주황색 +STR_5538 :{SMALLFONT}{BLACK}밝은 갈색 +STR_5539 :{SMALLFONT}{BLACK}짙은 갈색 +STR_5540 :{SMALLFONT}{BLACK}어두운 갈색 +STR_5541 :{SMALLFONT}{BLACK}살몬 핑크 +STR_5542 :{SMALLFONT}{BLACK}보르도 레드 +STR_5543 :{SMALLFONT}{BLACK}짙은 빨간색 +STR_5544 :{SMALLFONT}{BLACK}밝은 빨간색 +STR_5545 :{SMALLFONT}{BLACK}어두운 분홍색 +STR_5546 :{SMALLFONT}{BLACK}밝은 분홍색 +STR_5547 :{SMALLFONT}{BLACK}분홍색 +STR_5548 :모든 운행 모드 보이기 +STR_5549 :연/월/일 +STR_5550 :{POP16}{POP16}{COMMA16}년 {PUSH16}{PUSH16}{MONTH} {PUSH16}{PUSH16}{STRINGID} +STR_5551 :연/일/월 +STR_5552 :{POP16}{POP16}{COMMA16}년 {PUSH16}{PUSH16}{PUSH16}{STRINGID} {MONTH} +STR_5553 :스팀 오버레이가 열려있으면 게임을 일시정지 +STR_5554 :{SMALLFONT}{BLACK}산 만들기 도구 사용 +STR_5555 :다른 종류의 놀이기구 차량을 보여줌 +STR_5556 :플레이어 추방 +STR_5557 :비동기화 이후에 계속 접속 (멀티플레이) +STR_5558 :이 설정을 적용하기 위해서는 재시작해야합니다 +STR_5559 :점검 시간 10분으로 +STR_5560 :{SMALLFONT}{BLACK}모든 놀이기구의 점검 시간을 '매 10분마다'로 설정합니다 +STR_5561 :언어 파일을 불러오는 데 실패하였습니다 +STR_5562 :경고! +STR_5563 :이 기능은 현재 불안정하여 오류가 나올 수 있습니다 +STR_5564 :오류 요소를 삽입 +STR_5565 :{SMALLFONT}{BLACK}오류가 난 맵 요소를 칸의 최상단에 삽입합니다. 이는 오류 요소의 위에 있는 그 어떤 요소도 숨길 것입니다. +STR_5566 :암호: +STR_5567 :광고 +STR_5568 :암호 필요 +STR_5569 :이 서버에 접속하려면 암호가 필요합니다 +STR_5570 :서버 검색 +STR_5571 :게임 참여 +STR_5572 :즐겨찾기 등록 +STR_5573 :즐거찾기 제거 +STR_5574 :서버 이름: +STR_5575 :최대 플레이어 수: +STR_5576 :포트: +STR_5577 :대한민국 원 (₩) +STR_5578 :러시아 루블 (R) +STR_5579 :창 크기 조절 배수: + +##################### +# Rides/attractions # +##################### + +#WW +[CONDORRD] +STR_NAME :콘도르 라이드 +STR_DESC :트랙 아래를 달리는 특별한 차량에 탑승한 승객들은 콘도르 모양의 열차 안에서 공중으로 떨어지며 하늘을 나는 기분을 경험하게 됩니다. +STR_CPTY :차량당 4명의 승객 diff --git a/data/language/polish.txt b/data/language/polish.txt index ca5ed8af91..071314a9ab 100644 --- a/data/language/polish.txt +++ b/data/language/polish.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 :Steel 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 : @@ -513,31 +513,31 @@ STR_0508 : STR_0509 : STR_0510 : STR_0511 : -STR_0512 : -STR_0513 : +STR_0512 :A compact roller coaster with a spiral lift hill and smooth, twisting drops. +STR_0513 :A looping roller coaster where the riders ride in a standing position STR_0514 :Trains suspended beneath the roller coaster track swing out to the side around corners -STR_0515 : +STR_0515 :A steel roller coaster with trains that are held beneath the track, with many complex and twisting track elements STR_0516 :A gentle roller coaster for people who haven't yet got the courage to face the larger rides STR_0517 :Passengers ride in miniature trains along a narrow-gauge railway track STR_0518 :Passengers travel in electric trains along a monorail track STR_0519 :Passengers ride in small cars hanging beneath the single-rail track, swinging freely from side to side around corners -STR_0520 : -STR_0521 : -STR_0522 : +STR_0520 :A dock platform where guests can drive/row personal watercraft on a body of water +STR_0521 :A fast and twisting roller coaster with tight turns and steep drops. Intensity is bound to be high. +STR_0522 :A smaller roller coaster where the riders sit above the track with no car around them STR_0523 :Riders travel slowly in powered vehicles along a track-based route -STR_0524 : -STR_0525 : -STR_0526 : +STR_0524 :Freefall car is pneumatically launched up a tall steel tower and then allowed to freefall down +STR_0525 :Riders career down a twisting track guided only by the curvature and banking of the semi-circular track +STR_0526 :Passengers travel in a rotating observation cabin which travels up a tall tower STR_0527 :A smooth steel-tracked roller coaster capable of vertical loops -STR_0528 : -STR_0529 : +STR_0528 :Riders travel in inflatable dinghies down a twisting semi-circular or completely enclosed tube track +STR_0529 :Mine train themed roller coaster trains career along steel roller coaster track made to look like old railway track STR_0530 :Cars hang from a steel cable which runs continuously from one end of the ride to the other and back again -STR_0531 : +STR_0531 :A compact steel-tracked roller coaster where the train travels through corkscrews and loops STR_0532 : STR_0533 : -STR_0534 : -STR_0535 : -STR_0536 : +STR_0534 :Self-drive petrol-engined go karts +STR_0535 :Log-shaped boats travel along a water channel, splashing down steep slopes to soak the riders +STR_0536 :Circular boats meander along a wide water channel, splashing through waterfalls and thrilling riders through foaming rapids STR_0537 : STR_0538 : STR_0539 : @@ -556,14 +556,14 @@ STR_0551 : STR_0552 : STR_0553 : STR_0554 :The car is accelerated out of the station along a long level track using Linear Induction Motors, then heads straight up a vertical spike of track, freefalling back down to return to the station -STR_0555 : -STR_0556 : +STR_0555 :Guests ride in an elevator up or down a vertical tower to get from one level to another +STR_0556 :Extra-wide cars descend completely vertical sloped track for the ultimate freefall roller coaster experience STR_0557 : STR_0558 : STR_0559 : STR_0560 : STR_0561 : -STR_0562 : +STR_0562 :Powered cars travel along a multi-level track past spooky scenery and special effects STR_0563 :Sitting in comfortable trains with only simple lap restraints riders enjoy giant smooth drops and twisting track as well as plenty of 'air time' over the hills STR_0564 :Running on wooden track, this coaster is fast, rough, noisy, and gives an 'out of control' riding experience with plenty of 'air time' STR_0565 :A simple wooden roller coaster capable of only gentle slopes and turns, where the cars are only kept on the track by side friction wheels and gravity @@ -572,38 +572,38 @@ STR_0567 :Sitting in seats suspended either side of the track, riders are pit STR_0568 : STR_0569 :Riding in special harnesses below the track, riders experience the feeling of flight as they swoop through the air STR_0570 : -STR_0571 : -STR_0572 : -STR_0573 : -STR_0574 : +STR_0571 :Circular cars spin around as they travel along the zig-zagging wooden track +STR_0572 :Large capacity boats travel along a wide water channel, propelled up slopes by a conveyer belt, accelerating down steep slopes to soak the riders with a gaint splash +STR_0573 :Powered helicoper shaped cars running on a steel track, controlled by the pedalling of the riders +STR_0574 :Riders are held in special harnesses in a lying-down position, travlling through twisted track and inversions either on their backs or facing the ground STR_0575 :Powered trains hanging from a single rail transport people around the park STR_0576 : -STR_0577 : +STR_0577 :Bogied cars run on wooden tracks, turning around on special reversing sections STR_0578 :Cars run along track enclosed by circular hoops, traversing steep drops and heartline twists STR_0579 : -STR_0580 : -STR_0581 : +STR_0580 :A giant steel roller coaster capable of smooth drops and hills of over 300ft +STR_0581 :A ring of seats is pulled to the top of a tall tower while gently rotating, then allowed to free-fall down, stopping gently at the bottom using magnetic brakes STR_0582 : STR_0583 : -STR_0584 : -STR_0585 : +STR_0584 :Special bicycles run on a steel monorail track, propelled by the pedalling of the riders +STR_0585 :Riders sit in pairs of seats suspended beneath the track as they loop and twist through tight inversions STR_0586 :Boat shaped cars run on roller coaster track to allow twisting curves and steep drops, splashing down into sections of water for gentle river sections -STR_0587 : -STR_0588 : +STR_0587 :After an exhilarating air-powered launch, the train speeds up a vertical track, over the top, and vertically down the other side to return to the station +STR_0588 :Individual cars run beneath a zig-zagging track with hairpin turns and sharp drops STR_0589 : -STR_0590 : -STR_0591 : +STR_0590 :Riders ride in a submerged submarine through an underwater course +STR_0591 :Raft-shaped boats gently meander around a river track STR_0592 : STR_0593 : STR_0594 : STR_0595 : STR_0596 : STR_0597 : -STR_0598 : +STR_0598 :Inverted roller coaster trains are accelerated out of the station to travel up a vertical spike of track, then reverse back through the station to travel backwards up another vertical spike of track STR_0599 :A compact roller coaster with individual cars and smooth twisting drops -STR_0600 : +STR_0600 :Powered mine trains career along a smooth and twisted track layout STR_0601 : -STR_0602 : +STR_0602 :Roller coaster trains are accelerated out of the station by linear induction motors to speed through twisting inversions # ------------------------------------------ Polish start STR_0603 :Gość {INT32} STR_0604 :Gość {INT32} @@ -841,16 +841,17 @@ STR_0834 :{SMALLFONT}{BLACK}Menu zapisu i opcji STR_0835 :Game initialization failed STR_0836 :Unable to start game in a minimized state 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_0838 : STR_0839 :{UINT16} x {UINT16} STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} -STR_0841 :Desktop window -STR_0842 :640x480 full screen -STR_0843 :800x600 full screen -STR_0844 :1024x768 full screen -STR_0845 :1152x864 full screen -STR_0846 :1280x1024 full screen -STR_0847 :About 'RollerCoaster Tycoon 2' +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +STR_0847 :About 'OpenRCT2' STR_0848 :RollerCoaster Tycoon 2 STR_0849 :{WINDOW_COLOUR_2}Version 2.01.028 STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, all rights reserved @@ -1055,10 +1056,10 @@ 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_1043 :Zapis gry OpenRCT2 +STR_1044 :Scenariusz OpenRCT2 +STR_1045 :Krajobrazu OpenRCT2 +STR_1046 :Projekt trasy OpenRCT2 STR_1047 :Zapis gry nieudany! STR_1048 :Zapis scenariusza nieudany! STR_1049 :Zapis krajobrazu nieudany! @@ -1115,13 +1116,13 @@ STR_1098 :Moving to end of {POP16}{STRINGID} STR_1099 :Waiting for passengers at {POP16}{STRINGID} STR_1100 :Waiting to depart {POP16}{STRINGID} STR_1101 :Departing {POP16}{STRINGID} -STR_1102 :Traveling at {VELOCITY} +STR_1102 :Travelling at {VELOCITY} STR_1103 :Arriving at {POP16}{STRINGID} STR_1104 :Unloading passengers at {POP16}{STRINGID} -STR_1105 :Traveling at {VELOCITY} +STR_1105 :Travelling at {VELOCITY} STR_1106 :Crashing! STR_1107 :Crashed! -STR_1108 :Traveling at {VELOCITY} +STR_1108 :Travelling at {VELOCITY} STR_1109 :Swinging STR_1110 :Rotating STR_1111 :Rotating @@ -1133,7 +1134,7 @@ STR_1116 :Operating STR_1117 :Doing circus show STR_1118 :Operating STR_1119 :Waiting for cable lift -STR_1120 :Traveling at {VELOCITY} +STR_1120 :Travelling at {VELOCITY} STR_1121 :Stopping STR_1122 :Waiting for passengers STR_1123 :Waiting to start @@ -1142,18 +1143,18 @@ STR_1125 :Operating STR_1126 :Stopping STR_1127 :Unloading passengers STR_1128 :Stopped by block brakes -STR_1129 :All vehicles in same colors -STR_1130 :Different colors per {STRINGID} -STR_1131 :Different colors per vehicle +STR_1129 :All vehicles in same colours +STR_1130 :Different colours per {STRINGID} +STR_1131 :Different colours per vehicle STR_1132 :Vehicle {POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} STR_1133 :Vehicle {POP16}{COMMA16} STR_1134 :{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} {COMMA16} STR_1135 :{STRINGID} {COMMA16} -STR_1136 :{SMALLFONT}{BLACK}Select main color -STR_1137 :{SMALLFONT}{BLACK}Select additional color 1 -STR_1138 :{SMALLFONT}{BLACK}Select additional color 2 -STR_1139 :{SMALLFONT}{BLACK}Select support structure color -STR_1140 :{SMALLFONT}{BLACK}Select vehicle color scheme option +STR_1136 :{SMALLFONT}{BLACK}Select main colour +STR_1137 :{SMALLFONT}{BLACK}Select additional colour 1 +STR_1138 :{SMALLFONT}{BLACK}Select additional colour 2 +STR_1139 :{SMALLFONT}{BLACK}Select support structure colour +STR_1140 :{SMALLFONT}{BLACK}Select vehicle colour scheme option STR_1141 :{SMALLFONT}{BLACK}Select which vehicle/train to modify STR_1142 :{MOVE_X}{SMALLFONT}{STRINGID} STR_1143 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRINGID} @@ -1411,7 +1412,7 @@ STR_1392 :{SMALLFONT}{BLACK}View of ride/attraction STR_1393 :{SMALLFONT}{BLACK}Vehicle details and options STR_1394 :{SMALLFONT}{BLACK}Operating options STR_1395 :{SMALLFONT}{BLACK}Maintenance options -STR_1396 :{SMALLFONT}{BLACK}Color scheme options +STR_1396 :{SMALLFONT}{BLACK}Colour scheme options STR_1397 :{SMALLFONT}{BLACK}Sound & music options STR_1398 :{SMALLFONT}{BLACK}Measurements and test data STR_1399 :{SMALLFONT}{BLACK}Graphs @@ -1543,9 +1544,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 : @@ -1555,9 +1556,9 @@ 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 donut 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} STR_1541 : STR_1542 :{SMALLFONT}{OPENQUOTES}This fried chicken from {STRINGID} is really good value{ENDQUOTES} @@ -1577,9 +1578,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 : @@ -1589,9 +1590,9 @@ 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 donut 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} STR_1575 : STR_1576 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fried chicken from {STRINGID}{ENDQUOTES} @@ -1775,7 +1776,7 @@ STR_1749 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{DUR STR_1750 :{DURATION} STR_1751 :Can't change time limit for ride... STR_1752 :{SMALLFONT}{BLACK}Show list of individual guests in park -STR_1753 :{SMALLFONT}{BLACK}Show summarized list of guests in park +STR_1753 :{SMALLFONT}{BLACK}Show summarised list of guests in park STR_1754 :{BLACK}{COMMA16} guests STR_1755 :{BLACK}{COMMA16} guest STR_1756 :{WINDOW_COLOUR_2}Admission price: @@ -1802,7 +1803,7 @@ STR_1776 :On 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 +STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tiger costume STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} Elephant costume STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} Roman costume STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} Gorilla costume @@ -1812,8 +1813,8 @@ STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} Astronaut costume STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} Bandit costume STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} Sheriff costume STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} Pirate costume -STR_1790 :{SMALLFONT}{BLACK}Select uniform color for this type of staff -STR_1791 :{WINDOW_COLOUR_2}Uniform color: +STR_1790 :{SMALLFONT}{BLACK}Select uniform colour for this type of staff +STR_1791 :{WINDOW_COLOUR_2}Uniform colour: STR_1792 :Responding to {STRINGID} breakdown call STR_1793 :Heading to {STRINGID} for an inspection STR_1794 :Fixing {STRINGID} @@ -1841,7 +1842,7 @@ STR_1815 :Thoughts STR_1816 :{SMALLFONT}{BLACK}Select information type to show in guest list STR_1817 :({COMMA16}) STR_1818 :{WINDOW_COLOUR_2}All guests -STR_1819 :{WINDOW_COLOUR_2}All guests (summarized) +STR_1819 :{WINDOW_COLOUR_2}All guests (summarised) STR_1820 :{WINDOW_COLOUR_2}Guests {STRINGID} STR_1821 :{WINDOW_COLOUR_2}Guests thinking {STRINGID} STR_1822 :{WINDOW_COLOUR_2}Guests thinking about {POP16}{STRINGID} @@ -1898,8 +1899,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 @@ -1917,8 +1918,10 @@ STR_1888 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}more than 4 hou STR_1889 :{WINDOW_COLOUR_2}Down-Time: {MOVE_X}{255}{BLACK}{COMMA16}% STR_1890 :{SMALLFONT}{BLACK}Select how often a mechanic should check this ride STR_1891 :No {STRINGID} in park yet! -STR_1892 :RollerCoaster Tycoon 2 -STR_1893 :Please insert your RollerCoaster Tycoon 2 CD in the following drive: +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 : +STR_1893 : STR_1894 :{WINDOW_COLOUR_2}{STRINGID} sold: {BLACK}{COMMA32} STR_1895 :{SMALLFONT}{BLACK}Build new ride/attraction # ------------------------------------------ Polish start @@ -1994,9 +1997,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} @@ -2006,9 +2009,9 @@ 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}Donut price: +STR_1981 :{WINDOW_COLOUR_2}Doughnut price: STR_1982 :{WINDOW_COLOUR_2}Coffee price: STR_1983 :{WINDOW_COLOUR_2} STR_1984 :{WINDOW_COLOUR_2}Fried Chicken price: @@ -2022,9 +2025,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 @@ -2034,9 +2037,9 @@ 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 :Donut +STR_2009 :Doughnut STR_2010 :Coffee STR_2011 :Empty Cup STR_2012 :Fried Chicken @@ -2050,9 +2053,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 @@ -2062,9 +2065,9 @@ 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 :Donuts +STR_2037 :Doughnuts STR_2038 :Coffees STR_2039 :Empty Cups STR_2040 :Fried Chicken @@ -2078,9 +2081,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 @@ -2090,9 +2093,9 @@ 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 Donut +STR_2065 :a Doughnut STR_2066 :a Coffee STR_2067 :an Empty Cup STR_2068 :some Fried Chicken @@ -2106,9 +2109,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 @@ -2118,9 +2121,9 @@ 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 :Donut +STR_2093 :Doughnut STR_2094 :Coffee STR_2095 :Empty Cup STR_2096 :Fried Chicken @@ -2244,7 +2247,7 @@ STR_2213 :{SMALLFONT}{BLACK}Show list of entertainers in park STR_2214 :Construction not possible while game is paused! STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C -STR_2217 :{WINDOW_COLOUR_2}{COMMA16}F +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F STR_2218 :{RED}{STRINGID} on {STRINGID} hasn't returned to the {STRINGID} yet!{NEWLINE}Check whether it is stuck or has stalled STR_2219 :{RED}{COMMA16} people have died in an accident on {STRINGID} STR_2220 :{WINDOW_COLOUR_2}Park Rating: {BLACK}{COMMA16} @@ -2399,7 +2402,7 @@ STR_2363 :Siatka terenu STR_2364 :{SMALLFONT}{BLACK}Zawsze wyświetlaj siatkę terenu STR_2365 :Bank nie zgadza się na zwiększenie pożyczki! STR_2366 :Celcjusz ({DEGREE}C) -STR_2367 :Fahrenheit (F) +STR_2367 :Fahrenheit ({DEGREE}F) STR_2368 :Brak STR_2369 :Niskie STR_2370 :Średnie @@ -2472,12 +2475,12 @@ 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_2437 : +STR_2438 : +STR_2439 : +STR_2440 : +STR_2441 : +STR_2442 : STR_2443 :{WINDOW_COLOUR_2}Koszt tygodniowy: {BLACK}{CURRENCY2DP} STR_2444 :{WINDOW_COLOUR_2}Koszt łączny: {BLACK}{CURRENCY2DP} STR_2445 :Rozpocznij kampanię @@ -2537,7 +2540,7 @@ STR_2495 :Cancel construction mode STR_2496 :Pause game STR_2497 :Zoom view out STR_2498 :Zoom view in -STR_2499 :Rotate view +STR_2499 :Rotate view clockwise STR_2500 :Rotate construction object STR_2501 :Underground view toggle STR_2502 :Remove base land toggle @@ -2719,10 +2722,10 @@ 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_2681 :{MEDIUMFONT}{BLACK}Increases your money by {CURRENCY} +STR_2682 : +STR_2683 : +STR_2684 :{SMALLFONT}{BLACK}Large group of peeps arrive STR_2685 :Simplex Noise Parameters STR_2686 :{WINDOW_COLOUR_2}Low: STR_2687 :{WINDOW_COLOUR_2}High: @@ -2739,11 +2742,11 @@ 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_2701 :Every minute +STR_2702 :Every 5 minutes +STR_2703 :Every 15 minutes +STR_2704 :Every 30 minutes +STR_2705 :Every hour STR_2706 :Never STR_2707 :Open new window STR_2708 :{WINDOW_COLOUR_1}Are you sure you want to overwrite {STRINGID}? @@ -2805,11 +2808,11 @@ 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_2760 :+{CURRENCY} +STR_2761 : +STR_2762 : STR_2763 :??? -STR_2764 :Szczęśliwi Goście +STR_2764 : STR_2765 :Przypływ Gości STR_2766 :Wygraj scenariusz STR_2767 :Zablokuj Klimat @@ -2827,7 +2830,7 @@ STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} STR_2779 :Podgląd #{COMMA16} STR_2780 :Dodatkowe okno podglądu # End of new strings -STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} STR_2782 :SHIFT + STR_2783 :CTRL + STR_2784 :Change keyboard shortcut @@ -2859,7 +2862,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 @@ -2872,11 +2875,11 @@ 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 -STR_2828 :{WINDOW_COLOUR_2}Most dazzling ride color schemes award +STR_2828 :{WINDOW_COLOUR_2}Most dazzling ride colour schemes award STR_2829 :{WINDOW_COLOUR_2}Most confusing park layout award STR_2830 :{WINDOW_COLOUR_2}Best gentle ride award STR_2831 :{TOPAZ}Your park has received an award for being 'The most untidy park in the country'! @@ -2889,11 +2892,11 @@ 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'! -STR_2845 :{TOPAZ}Your park has received an award for being 'The park with the most dazzling choice of color schemes'! +STR_2845 :{TOPAZ}Your park has received an award for being 'The park with the most dazzling choice of colour schemes'! STR_2846 :{TOPAZ}Your park has received an award for being 'The park with the most confusing layout'! STR_2847 :{TOPAZ}Your park has received an award for being 'The park with the best gentle rides'! STR_2848 :{WINDOW_COLOUR_2}No recent awards @@ -2907,7 +2910,7 @@ STR_2855 :{RED}{STRINGID} has no path leading from its exit !{NEWLINE}Constru STR_2856 :{WINDOW_COLOUR_2}Tutorial STR_2857 :{WINDOW_COLOUR_2}(Press a key or mouse button to take control) STR_2858 :Can't start marketing campaign... -STR_2859 :Another instance of RollerCoaster Tycoon 2 is already running +STR_2859 :Another instance of OpenRCT2 is already running STR_2860 :Infogrames Interactive credits... STR_2861 :{WINDOW_COLOUR_2}Licensed to Infogrames Interactive Inc. STR_2862 :Music acknowledgements... @@ -3017,14 +3020,14 @@ STR_2965 :{WINDOW_COLOUR_2} STR_2966 : STR_2967 : STR_2968 : -STR_2969 :Use of this product is subject to the terms of a license agreement -STR_2970 :found in the product's {OPENQUOTES}ReadMe{ENDQUOTES} file and in the manual -STR_2971 :Main color scheme -STR_2972 :Alternative color scheme 1 -STR_2973 :Alternative color scheme 2 -STR_2974 :Alternative color scheme 3 -STR_2975 :{SMALLFONT}{BLACK}Select which color scheme to change, or paint ride with -STR_2976 :{SMALLFONT}{BLACK}Paint an individual area of this ride using the selected color scheme +STR_2969 : +STR_2970 : +STR_2971 :Main colour scheme +STR_2972 :Alternative colour scheme 1 +STR_2973 :Alternative colour scheme 2 +STR_2974 :Alternative colour scheme 3 +STR_2975 :{SMALLFONT}{BLACK}Select which colour scheme to change, or paint ride with +STR_2976 :{SMALLFONT}{BLACK}Paint an individual area of this ride using the selected colour scheme STR_2977 :Staff member name STR_2978 :Enter new name for this member of staff: STR_2979 :Can't name staff member... @@ -3037,8 +3040,8 @@ STR_2985 :Banner STR_2986 :{SMALLFONT}{BLACK}Change text on banner STR_2987 :{SMALLFONT}{BLACK}Set this banner as a 'no-entry' sign for guests STR_2988 :{SMALLFONT}{BLACK}Demolish this banner -STR_2989 :{SMALLFONT}{BLACK}Select main color -STR_2990 :{SMALLFONT}{BLACK}Select text color +STR_2989 :{SMALLFONT}{BLACK}Select main colour +STR_2990 :{SMALLFONT}{BLACK}Select text colour STR_2991 :Sign STR_2992 :Sign text STR_2993 :Enter new text for this sign: @@ -3131,7 +3134,7 @@ STR_3077 :{RED}CLOSURE NOTICE: Your park has been closed down ! STR_3078 :Plain entrance STR_3079 :Wooden entrance STR_3080 :Canvas tent entrance -STR_3081 :Castle entrance (gray) +STR_3081 :Castle entrance (grey) STR_3082 :Castle entrance (brown) STR_3083 :Jungle entrance STR_3084 :Log cabin entrance @@ -3143,16 +3146,16 @@ STR_3089 :Space entrance STR_3090 :{SMALLFONT}{BLACK}Select style of entrance, exit, and station STR_3091 :You are not allowed to remove this section! STR_3092 :You are not allowed to move or modify the station for this ride! -STR_3093 :{WINDOW_COLOUR_2}Favorite: {BLACK}{STRINGID} +STR_3093 :{WINDOW_COLOUR_2}Favourite: {BLACK}{STRINGID} STR_3094 :N/A STR_3095 :{WINDOW_COLOUR_2}Lift hill chain speed: STR_3096 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} STR_3097 :{SMALLFONT}{BLACK}Select lift hill chain speed STR_3098 :Can't change lift hill speed... -STR_3099 :{SMALLFONT}{BLACK}Select color -STR_3100 :{SMALLFONT}{BLACK}Select second color -STR_3101 :{SMALLFONT}{BLACK}Select third color -STR_3102 :{SMALLFONT}{BLACK}Re-paint colored scenery on landscape +STR_3099 :{SMALLFONT}{BLACK}Select colour +STR_3100 :{SMALLFONT}{BLACK}Select second colour +STR_3101 :{SMALLFONT}{BLACK}Select third colour +STR_3102 :{SMALLFONT}{BLACK}Re-paint coloured scenery on landscape STR_3103 :Can't re-paint this... STR_3104 :{SMALLFONT}{BLACK}List rides STR_3105 :{SMALLFONT}{BLACK}List shops and stalls @@ -3174,8 +3177,8 @@ STR_3118 :{BLACK}{STRINGID} is heading for the ride STR_3119 :{BLACK}{STRINGID} is fixing the ride STR_3120 :{SMALLFONT}{BLACK}Locate nearest available mechanic, or mechanic fixing ride STR_3121 :Unable to locate mechanic, or all nearby mechanics are busy -STR_3122 :{WINDOW_COLOUR_2}Favorite ride of: {BLACK}{COMMA16} guest -STR_3123 :{WINDOW_COLOUR_2}Favorite ride of: {BLACK}{COMMA16} guests +STR_3122 :{WINDOW_COLOUR_2}Favourite ride of: {BLACK}{COMMA16} guest +STR_3123 :{WINDOW_COLOUR_2}Favourite ride of: {BLACK}{COMMA16} guests STR_3124 :Broken {STRINGID} STR_3125 :{WINDOW_COLOUR_2}Excitement Factor: {BLACK}+{COMMA16}% STR_3126 :{WINDOW_COLOUR_2}Intensity Factor: {BLACK}+{COMMA16}% @@ -3214,8 +3217,8 @@ STR_3156 : STR_3157 :map STR_3158 :graph STR_3159 :list -STR_3160 :RollerCoaster Tycoon 2: Starting for the first time... -STR_3161 :RollerCoaster Tycoon 2: Checking object files... +STR_3160 : +STR_3161 : STR_3162 :Unable to allocate enough memory STR_3163 :Installing new data: STR_3164 :{BLACK}{COMMA16} selected (maximum {COMMA16}) @@ -3226,7 +3229,7 @@ STR_3168 :{WINDOW_COLOUR_2}Text: {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 -STR_3172 :The following object must be selected first: +STR_3172 :The following object must be selected first: {STRING} STR_3173 :This object is currently in use STR_3174 :This object is required by another object STR_3175 :This object is always required @@ -3391,7 +3394,7 @@ 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_3337 : 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 @@ -3418,8 +3421,8 @@ 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_3362 : +STR_3363 : STR_3364 :Advanced STR_3365 :{SMALLFONT}{BLACK}Allow selection of individual items of scenery in addition to scenery groups STR_3366 :{BLACK}= Ride @@ -3428,8 +3431,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... @@ -3449,6 +3452,7 @@ STR_3387 :Budowanie Kolejek Górskich STR_3388 :Unable to switch to selected mode STR_3389 :Unable to select additional item of scenery... STR_3390 :Too many items selected +# Start of tutorial strings. Not used at the moment, so not necessary to translate. STR_3391 :{SMALLFONT}{BLACK}Here is our park - Let's have a quick look around... STR_3392 :{SMALLFONT}{BLACK}Holding down the RIGHT mouse button and moving the mouse is the quickest way to move the view... STR_3393 :{SMALLFONT}{BLACK}To view more of the park, you can zoom the view out using the icon at the top of the screen... @@ -3494,7 +3498,8 @@ STR_3432 :{SMALLFONT}{BLACK}We need to slow the train before the final curve 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_3436 :{SMALLFONT}{BLACK}While waiting for our first riders, we could customise the ride a bit... +# End of tutorial strings # ------------------------------------------ Polish start STR_3437 :{SMALLFONT}{BLACK}Usuwanie scenerii z terenu STR_3438 :Nie można stąd usunąć całej scenerii... @@ -3506,164 +3511,10 @@ 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 + +# Note: as this is an unmaintained language, don't add new strings unless you intend to become the mainainer. diff --git a/data/language/portuguese_br.txt b/data/language/portuguese_br.txt new file mode 100644 index 0000000000..b3e29cc507 --- /dev/null +++ b/data/language/portuguese_br.txt @@ -0,0 +1,3907 @@ +# 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 :Spiral Roller Coaster +STR_0003 :Stand-up Roller Coaster +STR_0004 :Suspended Swinging Coaster +STR_0005 :Inverted Roller Coaster +STR_0006 :Montanha-Russa Junior +STR_0007 :Miniature Railway +STR_0008 :Monotrilho +STR_0009 :Mini Suspended Coaster +STR_0010 :Boat Ride +STR_0011 :Wooden Wild Mouse +STR_0012 :Steeplechase +STR_0013 :Passeio de carro +STR_0014 :Launched Freefall +STR_0015 :Bobsleigh Coaster +STR_0016 :Observation Tower +STR_0017 :Looping Roller Coaster +STR_0018 :Dinghy Slide +STR_0019 :Mine Train Coaster +STR_0020 :Teleférico +STR_0021 :Corkscrew Roller Coaster +STR_0022 :Labirinto +STR_0023 :Spiral Slide +STR_0024 :Karts +STR_0025 :Log Flume +STR_0026 :River Rapids +STR_0027 :Dodgems +STR_0028 :Barco Pirata +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 :Carrossel +STR_0036 :Unknown Stall (22) +STR_0037 :Quiosque de Informações +STR_0038 :Banheiros +STR_0039 :Roda Gigante +STR_0040 :Motion Simulator +STR_0041 :Cinema 3D +STR_0042 :Top Spin +STR_0043 :Giroscopio Humano +STR_0044 :Reverse Freefall Coaster +STR_0045 :Elevador +STR_0046 :Vertical Drop Roller Coaster +STR_0047 :Caixa Eletrônico +STR_0048 :Twist +STR_0049 :Casa Assombrada +STR_0050 :Primeiros Socorros +STR_0051 :Circus Show +STR_0052 :Ghost Train +STR_0053 :Steel 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 :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 :Monotrilho Suspenso +STR_0066 :Unknown Ride (40) +STR_0067 :Reverser Roller Coaster +STR_0068 :Heartline Twister Coaster +STR_0069 :Mini Golfe +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 :Montanha-Russa D'água +STR_0077 :Air Powered Vertical Coaster +STR_0078 :Inverted Hairpin Coaster +STR_0079 :Tapete Mágico +STR_0080 :Submarino +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 Montanha-Russa +STR_0090 :Mine Ride +STR_0091 :Unknown Ride (59) +STR_0092 :LIM Launched Roller Coaster +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 :A compact roller coaster with a spiral lift hill and smooth, twisting drops. +STR_0513 :A looping roller coaster where the riders ride in a standing position +STR_0514 :Trains suspended beneath the roller coaster track swing out to the side around corners +STR_0515 :A steel roller coaster with trains that are held beneath the track, with many complex and twisting track elements +STR_0516 :A gentle roller coaster for people who haven't yet got the courage to face the larger rides +STR_0517 :Passengers ride in miniature trains along a narrow-gauge railway track +STR_0518 :Passengers travel in electric trains along a monorail track +STR_0519 :Passengers ride in small cars hanging beneath the single-rail track, swinging freely from side to side around corners +STR_0520 :A dock platform where guests can drive/row personal watercraft on a body of water +STR_0521 :A fast and twisting roller coaster with tight turns and steep drops. Intensity is bound to be high. +STR_0522 :A smaller roller coaster where the riders sit above the track with no car around them +STR_0523 :Riders travel slowly in powered vehicles along a track-based route +STR_0524 :Freefall car is pneumatically launched up a tall steel tower and then allowed to freefall down +STR_0525 :Riders career down a twisting track guided only by the curvature and banking of the semi-circular track +STR_0526 :Passengers travel in a rotating observation cabin which travels up a tall tower +STR_0527 :A smooth steel-tracked roller coaster capable of vertical loops +STR_0528 :Riders travel in inflatable dinghies down a twisting semi-circular or completely enclosed tube track +STR_0529 :Mine train themed roller coaster trains career along steel roller coaster track made to look like old railway track +STR_0530 :Cars hang from a steel cable which runs continuously from one end of the ride to the other and back again +STR_0531 :A compact steel-tracked roller coaster where the train travels through corkscrews and loops +STR_0532 : +STR_0533 : +STR_0534 :Self-drive petrol-engined go karts +STR_0535 :Log-shaped boats travel along a water channel, splashing down steep slopes to soak the riders +STR_0536 :Circular boats meander along a wide water channel, splashing through waterfalls and thrilling riders through foaming rapids +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 :The car is accelerated out of the station along a long level track using Linear Induction Motors, then heads straight up a vertical spike of track, freefalling back down to return to the station +STR_0555 :Guests ride in an elevator up or down a vertical tower to get from one level to another +STR_0556 :Extra-wide cars descend completely vertical sloped track for the ultimate freefall roller coaster experience +STR_0557 : +STR_0558 : +STR_0559 : +STR_0560 : +STR_0561 : +STR_0562 :Powered cars travel along a multi-level track past spooky scenery and special effects +STR_0563 :Sitting in comfortable trains with only simple lap restraints riders enjoy giant smooth drops and twisting track as well as plenty of 'air time' over the hills +STR_0564 :Running on wooden track, this coaster is fast, rough, noisy, and gives an 'out of control' riding experience with plenty of 'air time' +STR_0565 :A simple wooden roller coaster capable of only gentle slopes and turns, where the cars are only kept on the track by side friction wheels and gravity +STR_0566 :Individual roller coaster cars zip around a tight zig-zag layout of track with sharp corners and short sharp drops +STR_0567 :Sitting in seats suspended either side of the track, riders are pitched head-over-heels while they plunge down steep drops and travel through various inversions +STR_0568 : +STR_0569 :Riding in special harnesses below the track, riders experience the feeling of flight as they swoop through the air +STR_0570 : +STR_0571 :Circular cars spin around as they travel along the zig-zagging wooden track +STR_0572 :Large capacity boats travel along a wide water channel, propelled up slopes by a conveyer belt, accelerating down steep slopes to soak the riders with a gaint splash +STR_0573 :Powered helicoper shaped cars running on a steel track, controlled by the pedalling of the riders +STR_0574 :Riders are held in special harnesses in a lying-down position, travlling through twisted track and inversions either on their backs or facing the ground +STR_0575 :Powered trains hanging from a single rail transport people around the park +STR_0576 : +STR_0577 :Bogied cars run on wooden tracks, turning around on special reversing sections +STR_0578 :Cars run along track enclosed by circular hoops, traversing steep drops and heartline twists +STR_0579 : +STR_0580 :A giant steel roller coaster capable of smooth drops and hills of over 300ft +STR_0581 :A ring of seats is pulled to the top of a tall tower while gently rotating, then allowed to free-fall down, stopping gently at the bottom using magnetic brakes +STR_0582 : +STR_0583 : +STR_0584 :Special bicycles run on a steel monorail track, propelled by the pedalling of the riders +STR_0585 :Riders sit in pairs of seats suspended beneath the track as they loop and twist through tight inversions +STR_0586 :Boat shaped cars run on roller coaster track to allow twisting curves and steep drops, splashing down into sections of water for gentle river sections +STR_0587 :After an exhilarating air-powered launch, the train speeds up a vertical track, over the top, and vertically down the other side to return to the station +STR_0588 :Individual cars run beneath a zig-zagging track with hairpin turns and sharp drops +STR_0589 : +STR_0590 :Riders ride in a submerged submarine through an underwater course +STR_0591 :Raft-shaped boats gently meander around a river track +STR_0592 : +STR_0593 : +STR_0594 : +STR_0595 : +STR_0596 : +STR_0597 : +STR_0598 :Inverted roller coaster trains are accelerated out of the station to travel up a vertical spike of track, then reverse back through the station to travel backwards up another vertical spike of track +STR_0599 :A compact roller coaster with individual cars and smooth twisting drops +STR_0600 :Powered mine trains career along a smooth and twisted track layout +STR_0601 : +STR_0602 :Roller coaster trains are accelerated out of the station by linear induction motors to speed through twisting inversions +STR_0603 :Visitante {INT32} +STR_0604 :Visitante {INT32} +STR_0605 :Visitante {INT32} +STR_0606 :Visitante {INT32} +STR_0607 :Visitante {INT32} +STR_0608 :Visitante {INT32} +STR_0609 :Visitante {INT32} +STR_0610 :Visitante {INT32} +STR_0611 :Visitante {INT32} +STR_0612 :Visitante {INT32} +STR_0613 :Visitante {INT32} +STR_0614 :Visitante {INT32} +STR_0615 :Visitante {INT32} +STR_0616 :Visitante {INT32} +STR_0617 :Visitante {INT32} +STR_0618 :Visitante {INT32} +STR_0619 :Visitante {INT32} +STR_0620 :Visitante {INT32} +STR_0621 :Visitante {INT32} +STR_0622 :Visitante {INT32} +STR_0623 :Visitante {INT32} +STR_0624 :Visitante {INT32} +STR_0625 :Visitante {INT32} +STR_0626 :Visitante {INT32} +STR_0627 :Visitante {INT32} +STR_0628 :Visitante {INT32} +STR_0629 :Visitante {INT32} +STR_0630 :Visitante {INT32} +STR_0631 :Visitante {INT32} +STR_0632 :Visitante {INT32} +STR_0633 :Visitante {INT32} +STR_0634 :Visitante {INT32} +STR_0635 :Visitante {INT32} +STR_0636 :Visitante {INT32} +STR_0637 :Visitante {INT32} +STR_0638 :Visitante {INT32} +STR_0639 :Visitante {INT32} +STR_0640 :Visitante {INT32} +STR_0641 :Visitante {INT32} +STR_0642 :Visitante {INT32} +STR_0643 :Visitante {INT32} +STR_0644 :Visitante {INT32} +STR_0645 :Visitante {INT32} +STR_0646 :Visitante {INT32} +STR_0647 :Visitante {INT32} +STR_0648 :Visitante {INT32} +STR_0649 :Visitante {INT32} +STR_0650 :Visitante {INT32} +STR_0651 :Visitante {INT32} +STR_0652 :Visitante {INT32} +STR_0653 :Visitante {INT32} +STR_0654 :Visitante {INT32} +STR_0655 :Visitante {INT32} +STR_0656 :Visitante {INT32} +STR_0657 :Visitante {INT32} +STR_0658 :Visitante {INT32} +STR_0659 :Visitante {INT32} +STR_0660 :Visitante {INT32} +STR_0661 :Visitante {INT32} +STR_0662 :Visitante {INT32} +STR_0663 :Visitante {INT32} +STR_0664 :Visitante {INT32} +STR_0665 :Visitante {INT32} +STR_0666 :Visitante {INT32} +STR_0667 :Visitante {INT32} +STR_0668 :Visitante {INT32} +STR_0669 :Visitante {INT32} +STR_0670 :Visitante {INT32} +STR_0671 :Visitante {INT32} +STR_0672 :Visitante {INT32} +STR_0673 :Visitante {INT32} +STR_0674 :Visitante {INT32} +STR_0675 :Visitante {INT32} +STR_0676 :Visitante {INT32} +STR_0677 :Visitante {INT32} +STR_0678 :Visitante {INT32} +STR_0679 :Visitante {INT32} +STR_0680 :Visitante {INT32} +STR_0681 :Visitante {INT32} +STR_0682 :Visitante {INT32} +STR_0683 :Visitante {INT32} +STR_0684 :Visitante {INT32} +STR_0685 :Visitante {INT32} +STR_0686 :Visitante {INT32} +STR_0687 :Visitante {INT32} +STR_0688 :Visitante {INT32} +STR_0689 :Visitante {INT32} +STR_0690 :Visitante {INT32} +STR_0691 :Visitante {INT32} +STR_0692 :Visitante {INT32} +STR_0693 :Visitante {INT32} +STR_0694 :Visitante {INT32} +STR_0695 :Visitante {INT32} +STR_0696 :Visitante {INT32} +STR_0697 :Visitante {INT32} +STR_0698 :Visitante {INT32} +STR_0699 :Visitante {INT32} +STR_0700 :Visitante {INT32} +STR_0701 :Visitante {INT32} +STR_0702 :Visitante {INT32} +STR_0703 :Visitante {INT32} +STR_0704 :Visitante {INT32} +STR_0705 :Visitante {INT32} +STR_0706 :Visitante {INT32} +STR_0707 :Visitante {INT32} +STR_0708 :Visitante {INT32} +STR_0709 :Visitante {INT32} +STR_0710 :Visitante {INT32} +STR_0711 :Visitante {INT32} +STR_0712 :Visitante {INT32} +STR_0713 :Visitante {INT32} +STR_0714 :Visitante {INT32} +STR_0715 :Visitante {INT32} +STR_0716 :Visitante {INT32} +STR_0717 :Visitante {INT32} +STR_0718 :Visitante {INT32} +STR_0719 :Visitante {INT32} +STR_0720 :Visitante {INT32} +STR_0721 :Visitante {INT32} +STR_0722 :Visitante {INT32} +STR_0723 :Visitante {INT32} +STR_0724 :Visitante {INT32} +STR_0725 :Visitante {INT32} +STR_0726 :Visitante {INT32} +STR_0727 :Visitante {INT32} +STR_0728 :Visitante {INT32} +STR_0729 :Visitante {INT32} +STR_0730 :Visitante {INT32} +STR_0731 :Visitante {INT32} +STR_0732 :Visitante {INT32} +STR_0733 :Visitante {INT32} +STR_0734 :Visitante {INT32} +STR_0735 :Visitante {INT32} +STR_0736 :Visitante {INT32} +STR_0737 :Visitante {INT32} +STR_0738 :Visitante {INT32} +STR_0739 :Visitante {INT32} +STR_0740 :Visitante {INT32} +STR_0741 :Visitante {INT32} +STR_0742 :Visitante {INT32} +STR_0743 :Visitante {INT32} +STR_0744 :Visitante {INT32} +STR_0745 :Visitante {INT32} +STR_0746 :Visitante {INT32} +STR_0747 :Visitante {INT32} +STR_0748 :Visitante {INT32} +STR_0749 :Visitante {INT32} +STR_0750 :Visitante {INT32} +STR_0751 :Visitante {INT32} +STR_0752 :Visitante {INT32} +STR_0753 :Visitante {INT32} +STR_0754 :Visitante {INT32} +STR_0755 :Visitante {INT32} +STR_0756 :Visitante {INT32} +STR_0757 :Visitante {INT32} +STR_0758 :Visitante {INT32} +STR_0759 :Visitante {INT32} +STR_0760 :Visitante {INT32} +STR_0761 :Visitante {INT32} +STR_0762 :Visitante {INT32} +STR_0763 :Visitante {INT32} +STR_0764 :Visitante {INT32} +STR_0765 :Visitante {INT32} +STR_0766 :Visitante {INT32} +STR_0767 :Visitante {INT32} +STR_0768 :Faz-Tudo {INT32} +STR_0769 :Mecânico {INT32} +STR_0770 :Segurança {INT32} +STR_0771 :Animador {INT32} +STR_0772 :Park Sem Nome{POP16}{POP16} +STR_0773 :Park Sem Nome{POP16}{POP16} +STR_0774 :Park Sem Nome{POP16}{POP16} +STR_0775 :Park Sem Nome{POP16}{POP16} +STR_0776 :Park Sem Nome{POP16}{POP16} +STR_0777 :Park Sem Nome{POP16}{POP16} +STR_0778 :Entrar +STR_0779 :1º de +STR_0780 :2 de +STR_0781 :3 de +STR_0782 :4 de +STR_0783 :5 de +STR_0784 :6 de +STR_0785 :7 de +STR_0786 :8 de +STR_0787 :9 de +STR_0788 :10 de +STR_0789 :11 de +STR_0790 :12 de +STR_0791 :13 de +STR_0792 :14 de +STR_0793 :15 de +STR_0794 :16 de +STR_0795 :17 de +STR_0796 :18 de +STR_0797 :19 de +STR_0798 :20 de +STR_0799 :21 de +STR_0800 :22 de +STR_0801 :23 de +STR_0802 :24 de +STR_0803 :25 de +STR_0804 :26 de +STR_0805 :27 de +STR_0806 :28 de +STR_0807 :29 de +STR_0808 :30 de +STR_0809 :31 de +STR_0810 :Jan +STR_0811 :Fev +STR_0812 :Mar +STR_0813 :Abr +STR_0814 :Mai +STR_0815 :Jun +STR_0816 :Jul +STR_0817 :Ago +STR_0818 :Set +STR_0819 :Out +STR_0820 :Nov +STR_0821 :Dez +STR_0822 :Impossível acessar o arquivo de gráficos +STR_0823 :Arquivo de dados ausente ou inacessível +STR_0824 :{BLACK}{CROSS} +STR_0825 :Nome escolhido já está em uso +STR_0826 :Muitos nomes definidos +STR_0827 :Dinheiro insuficiente - requer {CURRENCY2DP} +STR_0828 :{SMALLFONT}{BLACK}Fechar Janela +STR_0829 :{SMALLFONT}{BLACK}Título da janela - Arraste para mover a janela +STR_0830 :{SMALLFONT}{BLACK}Aumentar Zoom +STR_0831 :{SMALLFONT}{BLACK}Reduzir Zoom +STR_0832 :{SMALLFONT}{BLACK}Rotacionar visão em 90{DEGREE} no sentido horário +STR_0833 :{SMALLFONT}{BLACK}Pausar Jogo +STR_0834 :{SMALLFONT}{BLACK}Opções de disco e jogo +STR_0835 :Inicialização do jogo falhou +STR_0836 :Impossível iniciar o jogo minimizado +STR_0837 :Impossível inicializar o sistema de gráficos +STR_0838 : +STR_0839 :{UINT16} x {UINT16} +STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +STR_0847 :Sobre 'OpenRCT2' +STR_0848 :RollerCoaster Tycoon 2 +STR_0849 :{WINDOW_COLOUR_2}Version 2.01.028 +STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, todos os Direitos Reservados +STR_0851 :{WINDOW_COLOUR_2}Projetado e programado por Chris Sawyer +STR_0852 :{WINDOW_COLOUR_2}Gráficos por Simon Foster +STR_0853 :{WINDOW_COLOUR_2}Som e musícas por Allister Brimble +STR_0854 :{WINDOW_COLOUR_2}Sons adicionais gravador por David Ellis +STR_0855 :{WINDOW_COLOUR_2}Representação por Jacqui Lyons na Marjacq Ltd. +STR_0856 :{WINDOW_COLOUR_2}Obrigado a: +STR_0857 :{WINDOW_COLOUR_2}Peter James Adcock, Joe Booth, and 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 :Muito baixo ! +STR_0878 :Muito alto ! +STR_0879 :Não é possível baixar terra aqui... +STR_0880 :Não é possível aumentar a terra aqui... +STR_0881 :Objeto no caminho +STR_0882 :Carregar Jogo +STR_0883 :Salvar Jogo +STR_0884 :Carregar Landscape +STR_0885 :Salvar Landscape +STR_0886 :Sair do Jogo +STR_0887 :Sair do Editor de Cenário +STR_0888 :Sair do Designer de Montanha-Russa +STR_0889 :Sair do Gerenciamento de Designs de Pista +STR_0890 :SCR{COMMA16}.BMP +STR_0891 :Captura de tela +STR_0892 :Captura de tela salvo no disco como '{STRINGID}' +STR_0893 :Capturas de tela falhou ! +STR_0894 :Landscape data area full ! +STR_0895 :Impossível construir parcialmente em cima e em baixo do chão +STR_0896 :{POP16}{POP16}{STRINGID} Construção +STR_0897 :Sentido +STR_0898 :{SMALLFONT}{BLACK}Curva para esquerda +STR_0899 :{SMALLFONT}{BLACK}Curva para direita +STR_0900 :{SMALLFONT}{BLACK}Curva para esquerda (raio pequeno) +STR_0901 :{SMALLFONT}{BLACK}Curva para direita (raio pequeno) +STR_0902 :{SMALLFONT}{BLACK}Curva para esquerda (raio muito pequeno) +STR_0903 :{SMALLFONT}{BLACK}Curva para esquerda (raio muito pequeno) +STR_0904 :{SMALLFONT}{BLACK}Curva para esquerda (raio grande) +STR_0905 :{SMALLFONT}{BLACK}Curva para esquerda (raio grande) +STR_0906 :{SMALLFONT}{BLACK}Em Linha Reta +STR_0907 :Inclinação +STR_0908 :Rolar/Banking +STR_0909 :Seat Rot. +STR_0910 :{SMALLFONT}{BLACK}Roll for left-hand curve +STR_0911 :{SMALLFONT}{BLACK}Roll for right-hand curve +STR_0912 :{SMALLFONT}{BLACK}No roll +STR_0913 :{SMALLFONT}{BLACK}Move to previous section +STR_0914 :{SMALLFONT}{BLACK}Move to next section +STR_0915 :{SMALLFONT}{BLACK}Construct the selected section +STR_0916 :{SMALLFONT}{BLACK}Remove the highlighted section +STR_0917 :{SMALLFONT}{BLACK}Vertical drop +STR_0918 :{SMALLFONT}{BLACK}Steep slope down +STR_0919 :{SMALLFONT}{BLACK}Slope down +STR_0920 :{SMALLFONT}{BLACK}Level +STR_0921 :{SMALLFONT}{BLACK}Slope up +STR_0922 :{SMALLFONT}{BLACK}Steep slope up +STR_0923 :{SMALLFONT}{BLACK}Vertical rise +STR_0924 :{SMALLFONT}{BLACK}Helix down +STR_0925 :{SMALLFONT}{BLACK}Helix up +STR_0926 :Impossível remover isto... +STR_0927 :Impossível construir isto aqui... +STR_0928 :{SMALLFONT}{BLACK}Corrente elevador, para puxar os carros para cima +STR_0929 :Curva 'S' (esquerda) +STR_0930 :Curva 'S' (direita) +STR_0931 :Loop Vertical (esquerda) +STR_0932 :Loop Vertical (direita) +STR_0933 :Aumentar ou diminuir o terreno primeiro +STR_0934 :Entrada da atração no caminho +STR_0935 :Saída da atração no caminho +STR_0936 :Entrada do parque no caminho +STR_0937 :{SMALLFONT}{BLACK}Opções de visão +STR_0938 :{SMALLFONT}{BLACK}Ajuste de altura do solo e inclinação +STR_0939 :Subterrâneo/Visão interna +STR_0940 :Remover base da terra +STR_0941 :Remover faces verticais +STR_0942 :Ver Através das Atrações +STR_0943 :Ver Através dos Cenários +STR_0944 :Salvar +STR_0945 :Não Salvar +STR_0946 :Cancelar +STR_0947 :Salvar antes de carregar ? +STR_0948 :Salvar antes de sair ? +STR_0949 :Salvar antes de sair ? +STR_0950 :Carregar Jogo +STR_0951 :Sair do Jogo +STR_0952 :Sair do Jogo +STR_0953 :Load Landscape +STR_0954 : +STR_0955 :{SMALLFONT}{BLACK}Escolha um ângulo de rotação do assento para esta seção da pista +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 :Cancelar +STR_0973 :OK +STR_0974 :Atrações +STR_0975 :Lojas, Barracas & Stands +STR_0976 :Banheiros e Quiosques de Informações +STR_0977 :Novas Atrações de Transporte +STR_0978 :Novas Atrações Suaves/Calmas +STR_0979 :Novas Montanhas-Russas +STR_0980 :Novas Atrações Emocionantes +STR_0981 :Novas Atrações Aquáticas +STR_0982 :Novas Lojas, Barracas & Stands +STR_0983 :Pesquisa e Desenvolvimento +STR_0984 :{WINDOW_COLOUR_2}{UP}{BLACK} {CURRENCY2DP} +STR_0985 :{WINDOW_COLOUR_2}{DOWN}{BLACK} {CURRENCY2DP} +STR_0986 :{BLACK}{CURRENCY2DP} +STR_0987 :Muitas atrações +STR_0988 :Impossível criar uma nova atração... +STR_0989 :{STRINGID} +STR_0990 :{SMALLFONT}{BLACK}Construção +STR_0991 :Plataforma da estação +STR_0992 :{SMALLFONT}{BLACK}Demolir toda a atração +STR_0993 :Demolir atração +STR_0994 :Demolir +STR_0995 :{WINDOW_COLOUR_1}Você tem certeza que deseja demolir completamente {STRINGID}? +STR_0996 :Visão Geral +STR_0997 :{SMALLFONT}{BLACK}Ver seleção +STR_0998 :Não há mais estações permitidas nesta atração +STR_0999 :Requer uma plataforma da estação +STR_1000 :A pista não é um circuito completo +STR_1001 :Track unsuitable for type of train +STR_1002 :Impossível Abrir {POP16}{POP16}{POP16}{STRINGID}... +STR_1003 :Impossível Testar {POP16}{POP16}{POP16}{STRINGID}... +STR_1004 :Impossível Fechar {POP16}{POP16}{POP16}{STRINGID}... +STR_1005 :Impossível começar a construção no {POP16}{POP16}{POP16}{STRINGID}... +STR_1006 :Deve ser fechado primeiro +STR_1007 :Impossível criar veículos suficientes +STR_1008 :{SMALLFONT}{BLACK}Abrir, fechar ou testar atração +STR_1009 :{SMALLFONT}{BLACK}Abrir ou fechar todas as atrações +STR_1010 :{SMALLFONT}{BLACK}Abrir ou fechar o parque +STR_1011 :Fechar todos +STR_1012 :Abrir todos +STR_1013 :Fechar parque +STR_1014 :Abrir parque +STR_1015 :Impossível operar com mais de uma plataforma de estação neste modo +STR_1016 :Impossível operar com menos de duas estações neste modo +STR_1017 :Impossível alterar o modo de operação... +STR_1018 :Impossível fazer alterações... +STR_1019 :Impossível fazer alterações... +STR_1020 :Impossível fazer alterações... +STR_1021 :{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_1022 :{POP16}{POP16}{POP16}{COMMA16} carro por trem +STR_1023 :{POP16}{POP16}{POP16}{COMMA16} carros por trens +STR_1024 :{COMMA16} carro por trem +STR_1025 :{COMMA16} carros por trens +STR_1026 :Plataforma da estação é muito longa! +STR_1027 :{SMALLFONT}{BLACK}Localizar isto na Visão Principal +STR_1028 :Fora da borda do mapa! +STR_1029 :Cannot build partly above and partly below water! +STR_1030 :Can only build this underwater! +STR_1031 :Can't build this underwater! +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 :Carregar Jogo +STR_1037 :Load Landscape +STR_1038 :Converter jogo salvo em cenário +STR_1039 :Install new track design +STR_1040 :Salvar Jogo +STR_1041 :Salvar Cenário +STR_1042 :Save Landscape +STR_1043 :OpenRCT2 Jogo Salvo +STR_1044 :OpenRCT2 Arquivo de Cenário +STR_1045 :OpenRCT2 Landscape File +STR_1046 :OpenRCT2 Arquivo de Projeto da Pista +STR_1047 :Falha ao salvar o jogo! +STR_1048 :Falha ao salvar o cenário! +STR_1049 :Landscape save failed! +STR_1050 :Falha ao carregar o jogo...{NEWLINE}Arquivo contém dados inválidos! +STR_1051 :Suportes Invisíveis +STR_1052 :Pessoas Invisíveis +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 +STR_1057 :Ride/attraction name +STR_1058 :Digite o novo nome para esta atração: +STR_1059 :Impossível renomear a atração.. +STR_1060 :Nome inválido para a atração +STR_1061 :Modo normal +STR_1062 :Modo de circuito contínuo +STR_1063 :Reverse-Incline launched shuttle mode +STR_1064 :Lançamento alimentado (estação de passagem) +STR_1065 :Shuttle mode +STR_1066 :Boat hire mode +STR_1067 :Upward launch +STR_1068 :Rotating lift mode +STR_1069 :Station to station mode +STR_1070 :Single ride per admission +STR_1071 :Unlimited rides per admission +STR_1072 :Modo de labirinto +STR_1073 :Modo de corrida +STR_1074 :Modo de Bumper-car +STR_1075 :Modo de Balanço +STR_1076 :Modo de lojas e barraca +STR_1077 :Modo de Rotação +STR_1078 :Rotação para frente +STR_1079 :Rotação para trás +STR_1080 :Film: {ENDQUOTES}Avenging aviators{ENDQUOTES} +STR_1081 :3D film: {ENDQUOTES}Mouse tails{ENDQUOTES} +STR_1082 :Space rings mode +STR_1083 :Beginners mode +STR_1084 :LIM-powered launch +STR_1085 :Film: {ENDQUOTES}Thrill riders{ENDQUOTES} +STR_1086 :Filme em 3D: {ENDQUOTES}Caçadores de tempestades{ENDQUOTES} +STR_1087 :Filme em 3D: {ENDQUOTES}Caçadores do espaço{ENDQUOTES} +STR_1088 :Modo intenso +STR_1089 :Berserk mode +STR_1090 :Haunted house mode +STR_1091 :Circus show mode +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 (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} +STR_1100 :Waiting to depart {POP16}{STRINGID} +STR_1101 :Departing {POP16}{STRINGID} +STR_1102 :Viajando a {VELOCITY} +STR_1103 :Chegando a {POP16}{STRINGID} +STR_1104 :Unloading passengers at {POP16}{STRINGID} +STR_1105 :Viajando a {VELOCITY} +STR_1106 :Falhando! +STR_1107 :Quebrado! +STR_1108 :Viajando a {VELOCITY} +STR_1109 :Balançando +STR_1110 :Rotacionando +STR_1111 :Rotacionando +STR_1112 :Operando +STR_1113 :Mostrando filme +STR_1114 :Rotacionando +STR_1115 :Operando +STR_1116 :Operando +STR_1117 :Doing circus show +STR_1118 :Operando +STR_1119 :Waiting for cable lift +STR_1120 :Viajando a {VELOCITY} +STR_1121 :Terminando +STR_1122 :Aguardando passageiros +STR_1123 :Aguardando para iniciar +STR_1124 :Começando +STR_1125 :Operando +STR_1126 :Terminando +STR_1127 :Desembarcando passageiros +STR_1128 :Parado pelo bloco dos freios +STR_1129 :Todos os veículos com as mesmas cores +STR_1130 :Diferentes cores por {STRINGID} +STR_1131 :Diferentes cores por veículos +STR_1132 :Veículo {POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1133 :Veículo {POP16}{COMMA16} +STR_1134 :{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} {COMMA16} +STR_1135 :{STRINGID} {COMMA16} +STR_1136 :{SMALLFONT}{BLACK}Selecione a cor principal +STR_1137 :{SMALLFONT}{BLACK}Selecione a cor adicional 1 +STR_1138 :{SMALLFONT}{BLACK}Selecione a cor adicional 2 +STR_1139 :{SMALLFONT}{BLACK}Selecione a cor do suporte das estruturas +STR_1140 :{SMALLFONT}{BLACK}Selecione a opção do esquema de cor do veículo +STR_1141 :{SMALLFONT}{BLACK}Selecione o veiculo/Trem para modificar +STR_1142 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1143 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRINGID} +STR_1144 :Impossível contruir/mover a entrada para essa atração... +STR_1145 :Impossível contruir/mover a saida para essa atração... +STR_1146 :Entrada ainda não construida +STR_1147 :Saida ainda não construida +STR_1148 :Um quarto de carga +STR_1149 :Metade de carga +STR_1150 :Três quartos de carga +STR_1151 :Carga total +STR_1152 :Qualquer carga +STR_1153 :Height Marks on Ride Tracks +STR_1154 :Height Marks on Land +STR_1155 :Height Marks on Paths +STR_1156 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1157 :{TICK}{MOVE_X}{SMALLFONT}{STRINGID} +STR_1158 :Impossível remover isto... +STR_1159 :{SMALLFONT}{BLACK}Coloque cenários, jardins, e outros acessórios +STR_1160 :{SMALLFONT}{BLACK}Criar/ajustar lagos e água +STR_1161 :Impossível posicionar isto aqui... +STR_1162 :{OUTLINE}{TOPAZ}{STRINGID} +STR_1163 :{STRINGID}{NEWLINE}(Botão direito para modificar) +STR_1164 :{STRINGID}{NEWLINE}(Botão direito para remover) +STR_1165 :{STRINGID} - {STRINGID} {COMMA16} +STR_1166 :Impossível diminuir o nível da água aqui... +STR_1167 :Impossível aumentar o nível da água aqui... +STR_1168 :Opções +STR_1169 :(Nenhum) +STR_1170 :{STRING} +STR_1171 :{RED}Fechado - - +STR_1172 :{YELLOW}{STRINGID} - - +STR_1173 :{SMALLFONT}{BLACK}Build footpaths and queue lines +STR_1174 :Banner sign in the way +STR_1175 :Can't build this on sloped footpath +STR_1176 :Can't build footpath here... +STR_1177 :Can't remove footpath from here... +STR_1178 :Land slope unsuitable +STR_1179 :Footpath in the way +STR_1180 :Impossível construir isto debaixo de água! +STR_1181 :Caminhos +STR_1182 :Tipo +STR_1183 :Direção +STR_1184 :Inclinação +STR_1185 :{SMALLFONT}{BLACK}Direção +STR_1186 :{SMALLFONT}{BLACK}inclinação para baixo +STR_1187 :{SMALLFONT}{BLACK}Nível +STR_1188 :{SMALLFONT}{BLACK}inclinação para cima +STR_1189 :{SMALLFONT}{BLACK}Construct the selected footpath section +STR_1190 :{SMALLFONT}{BLACK}Remove previous footpath section +STR_1191 :{BLACK}{STRINGID} +STR_1192 :{OUTLINE}{RED}{STRINGID} +STR_1193 :{WINDOW_COLOUR_2}{STRINGID} +STR_1194 :Fechado +STR_1195 :Executar teste +STR_1196 :Aberto +STR_1197 :Enguiçou +STR_1198 :Quebrado! +STR_1199 :{COMMA16} person on ride +STR_1200 :{COMMA16} people on ride +STR_1201 :Nobody in queue line +STR_1202 :1 person in queue line +STR_1203 :{COMMA16} people in queue line +STR_1204 :{COMMA16} minute queue time +STR_1205 :{COMMA16} minutes queue time +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}Synchronise with adjacent stations +STR_1216 :{SMALLFONT}{BLACK}Select whether to synchronise departure with all adjacent stations (for 'racing') +STR_1217 :{COMMA16} seconds +STR_1218 :{BLACK}{SMALLUP} +STR_1219 :{BLACK}{SMALLDOWN} +STR_1220 :Somente Saida +STR_1221 :Sem entrada +STR_1222 :Sem saída +STR_1223 :{SMALLFONT}{BLACK}Atrações de Transporte +STR_1224 :{SMALLFONT}{BLACK}Atrações Suaves/Calmas +STR_1225 :{SMALLFONT}{BLACK}Montanhas-Russas +STR_1226 :{SMALLFONT}{BLACK}Atrações Emocionantes +STR_1227 :{SMALLFONT}{BLACK}Atrações Aquáticas +STR_1228 :{SMALLFONT}{BLACK}Lojas, Barracas & Stands +STR_1229 :trem +STR_1230 :trens +STR_1231 :Trem +STR_1232 :Trens +STR_1233 :{COMMA16} trem +STR_1234 :{COMMA16} trens +STR_1235 :Trem {COMMA16} +STR_1236 :barco +STR_1237 :barcos +STR_1238 :Barco +STR_1239 :Barcos +STR_1240 :{COMMA16} barco +STR_1241 :{COMMA16} barcos +STR_1242 :Barco {COMMA16} +STR_1243 :pista +STR_1244 :pistas +STR_1245 :Pista +STR_1246 :Pistas +STR_1247 :{COMMA16} pista +STR_1248 :{COMMA16} pistas +STR_1249 :Pista {COMMA16} +STR_1250 :plataforma de atracação +STR_1251 :plataformas de atracação +STR_1252 :Plataforma de atracação +STR_1253 :Plataformas de atracação +STR_1254 :{COMMA16} plataforma de atracação +STR_1255 :{COMMA16} plataformas de atracação +STR_1256 :Plataforma de atracação {COMMA16} +STR_1257 :estação +STR_1258 :estações +STR_1259 :Estação +STR_1260 :Estações +STR_1261 :{COMMA16} estação +STR_1262 :{COMMA16} estações +STR_1263 :Estação {COMMA16} +STR_1264 :carro +STR_1265 :carros +STR_1266 :Carro +STR_1267 :Carros +STR_1268 :{COMMA16} carro +STR_1269 :{COMMA16} carros +STR_1270 :Carro {COMMA16} +STR_1271 :construção +STR_1272 :construções +STR_1273 :Construção +STR_1274 :Construções +STR_1275 :{COMMA16} construção +STR_1276 :{COMMA16} construções +STR_1277 :Construção {COMMA16} +STR_1278 :estrutura +STR_1279 :estruturas +STR_1280 :Estrutura +STR_1281 :Estruturas +STR_1282 :{COMMA16} estrutura +STR_1283 :{COMMA16} estruturas +STR_1284 :Estrutura {COMMA16} +STR_1285 :navio +STR_1286 :navios +STR_1287 :Navio +STR_1288 :Navios +STR_1289 :{COMMA16} navio +STR_1290 :{COMMA16} navios +STR_1291 :Navio {COMMA16} +STR_1292 :cabine +STR_1293 :cabines +STR_1294 :Cabine +STR_1295 :Cabines +STR_1296 :{COMMA16} cabine +STR_1297 :{COMMA16} cabines +STR_1298 :Cabine {COMMA16} +STR_1299 :roda +STR_1300 :rodas +STR_1301 :Roda +STR_1302 :Rodas +STR_1303 :{COMMA16} roda +STR_1304 :{COMMA16} rodas +STR_1305 :Roda {COMMA16} +STR_1306 :anel +STR_1307 :anéis +STR_1308 :Anel +STR_1309 :Anéis +STR_1310 :{COMMA16} anel +STR_1311 :{COMMA16} anéis +STR_1312 :Anel {COMMA16} +STR_1313 :jogador +STR_1314 :jogadores +STR_1315 :Jogador +STR_1316 :Jogadores +STR_1317 :{COMMA16} jogador +STR_1318 :{COMMA16} jogadores +STR_1319 :Jogador {COMMA16} +STR_1320 :curso +STR_1321 :cursos +STR_1322 :Curso +STR_1323 :Cursos +STR_1324 :{COMMA16} curso +STR_1325 :{COMMA16} cursos +STR_1326 :Curso {COMMA16} +STR_1327 :{SMALLFONT}{BLACK}Rotacionar objetos em 90{DEGREE} +STR_1328 :Nível da terra necessário +STR_1329 :{WINDOW_COLOUR_2}Velocidade de lançamento: +STR_1330 :{SMALLFONT}{BLACK}Velocidade máxima quando sair da estação +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} - Entrada{POP16}{POP16} +STR_1336 :{STRINGID} - Estação {POP16}{COMMA16} Entrada +STR_1337 :{STRINGID} - Saida{POP16}{POP16} +STR_1338 :{STRINGID} - Estação {POP16}{COMMA16} Saida +STR_1339 :{BLACK}Nenhum resultado de teste ainda... +STR_1340 :{WINDOW_COLOUR_2}Vel. Max.: {BLACK}{VELOCITY} +STR_1341 :{WINDOW_COLOUR_2}Ride time: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1342 :{DURATION} +STR_1343 :{DURATION} / +STR_1344 :{WINDOW_COLOUR_2}Ride length: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1345 :{LENGTH} +STR_1346 :{LENGTH} / +STR_1347 :{WINDOW_COLOUR_2}Average speed: {BLACK}{VELOCITY} +STR_1348 :{WINDOW_COLOUR_2}Max. positive vertical G's: {BLACK}{COMMA2DP32}g +STR_1349 :{WINDOW_COLOUR_2}Max. positive vertical G's: {OUTLINE}{RED}{COMMA2DP32}g +STR_1350 :{WINDOW_COLOUR_2}Max. negative vertical G's: {BLACK}{COMMA2DP32}g +STR_1351 :{WINDOW_COLOUR_2}Max. negative vertical G's: {OUTLINE}{RED}{COMMA2DP32}g +STR_1352 :{WINDOW_COLOUR_2}Max. lateral G's: {BLACK}{COMMA2DP32}g +STR_1353 :{WINDOW_COLOUR_2}Max. lateral G's: {OUTLINE}{RED}{COMMA2DP32}g +STR_1354 :{WINDOW_COLOUR_2}Highest drop height: {BLACK}{LENGTH} +STR_1355 :{WINDOW_COLOUR_2}Drops: {BLACK}{COMMA16} +STR_1356 :{WINDOW_COLOUR_2}Inversions: {BLACK}{COMMA16} +STR_1357 :{WINDOW_COLOUR_2}Holes: {BLACK}{COMMA16} +STR_1358 :{WINDOW_COLOUR_2}Total 'air' time: {BLACK}{COMMA2DP32}secs +STR_1359 :{WINDOW_COLOUR_2}Queue time: {BLACK}{COMMA16} minute +STR_1360 :{WINDOW_COLOUR_2}Queue time: {BLACK}{COMMA16} minutes +STR_1361 :Can't change speed... +STR_1362 :Can't change launch speed... +STR_1363 :Too high for supports! +STR_1364 :Supports for track above can't be extended any further! +STR_1365 :In-line Twist (left) +STR_1366 :In-line Twist (right) +STR_1367 :Half Loop +STR_1368 :Half Corkscrew (left) +STR_1369 :Half Corkscrew (right) +STR_1370 :Barrel Roll (left) +STR_1371 :Barrel Roll (right) +STR_1372 :Launched Lift Hill +STR_1373 :Large Half Loop (left) +STR_1374 :Large Half Loop (right) +STR_1375 :Upper Transfer +STR_1376 :Lower Transfer +STR_1377 :Heartline Roll (left) +STR_1378 :Heartline Roll (right) +STR_1379 :Reverser (left) +STR_1380 :Reverser (right) +STR_1381 :Curved Lift Hill (left) +STR_1382 :Curved Lift Hill (right) +STR_1383 :Quarter Loop +STR_1384 :{YELLOW}{STRINGID} +STR_1385 :{SMALLFONT}{BLACK}Other track configurations +STR_1386 :Especial... +STR_1387 :Can't change land type... +STR_1388 :{OUTLINE}{GREEN}+ {CURRENCY} +STR_1389 :{OUTLINE}{RED}- {CURRENCY} +STR_1390 :{CURRENCY2DP} +STR_1391 :{RED}{CURRENCY2DP} +STR_1392 :{SMALLFONT}{BLACK}Visão da atração +STR_1393 :{SMALLFONT}{BLACK}Opções e detalhes do veiculo +STR_1394 :{SMALLFONT}{BLACK}Opções de operação +STR_1395 :{SMALLFONT}{BLACK}Opções de manutenção +STR_1396 :{SMALLFONT}{BLACK}Opções de esquema de cor +STR_1397 :{SMALLFONT}{BLACK}Opções de som e música +STR_1398 :{SMALLFONT}{BLACK}Medições e dados teste +STR_1399 :{SMALLFONT}{BLACK}Gráficos +STR_1400 :Entrada +STR_1401 :Saída +STR_1402 :{SMALLFONT}{BLACK}Construir ou mover a entrada da atração +STR_1403 :{SMALLFONT}{BLACK}Construir ou mover a saída da atração +STR_1404 :{SMALLFONT}{BLACK}Rotacionar 90{DEGREE} +STR_1405 :{SMALLFONT}{BLACK}Imagem espelhada +STR_1406 :{SMALLFONT}{BLACK}Alternar cenário on / off (se disponível para este projeto) +STR_1407 :{WINDOW_COLOUR_2}Construir isto... +STR_1408 :{WINDOW_COLOUR_2}Custo: {BLACK}{CURRENCY} +STR_1409 :Entrada/Saída Plataforma +STR_1410 :Torre Vertical +STR_1411 :{STRINGID} no caminho +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}Velocidade +STR_1416 :{WINDOW_COLOUR_2}Altitude +STR_1417 :{WINDOW_COLOUR_2}Vert.G's +STR_1418 :{WINDOW_COLOUR_2}Lat.G's +STR_1419 :{SMALLFONT}{BLACK}{VELOCITY} +STR_1420 :{SMALLFONT}{BLACK}{LENGTH} +STR_1421 :{SMALLFONT}{BLACK}{COMMA16}g +STR_1422 :{SMALLFONT}{BLACK}Logging data from {POP16}{STRINGID} +STR_1423 :{SMALLFONT}{BLACK}Caminho da fila +STR_1424 :{SMALLFONT}{BLACK}Trajeto +STR_1425 :Trajeto +STR_1426 :Fila de espera +STR_1427 :{WINDOW_COLOUR_2}Clientes: {BLACK}{COMMA32} por hora +STR_1428 :{WINDOW_COLOUR_2}Preço de entrada: +STR_1429 :{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1430 :Livre +STR_1431 :Andando +STR_1432 :Rumo a {STRINGID} +STR_1433 :Filas para {STRINGID} +STR_1434 :Afogando +STR_1435 :Em {STRINGID} +STR_1436 :In {STRINGID} +STR_1437 :At {STRINGID} +STR_1438 :Sentando +STR_1439 :(select location) +STR_1440 :Cortando grama +STR_1441 :Varrendo calçada +STR_1442 :Esvaziando lixeira +STR_1443 :Regando jardins +STR_1444 :Assistindo {STRINGID} +STR_1445 :Assistindo construção de {STRINGID} +STR_1446 :Olhando para paisagem +STR_1447 :Saindo do parque +STR_1448 :Assistindo a nova atração sendo construida +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 :Nome do Visitante +STR_1453 :Digite o nome para este visitante: +STR_1454 :Não é possivel nomear o visitante... +STR_1455 :Nome invalido para o visitante +STR_1456 :{WINDOW_COLOUR_2}Dinheiro gasto: {BLACK}{CURRENCY2DP} +STR_1457 :{WINDOW_COLOUR_2}Dinheiro no bolso: {BLACK}{CURRENCY2DP} +STR_1458 :{WINDOW_COLOUR_2}Tempo no parque: {BLACK}{REALTIME} +STR_1459 :Estilo da pista +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 :Visitantes +STR_1464 :Hélice cima (pequeno) +STR_1465 :Hélice cima (grande) +STR_1466 :Hélice baixo (pequeno) +STR_1467 :Hélice baixo (grande) +STR_1468 :Funcionários +STR_1469 :Ride must start and end with stations +STR_1470 :Station not long enough +STR_1471 :{WINDOW_COLOUR_2}Velocidade: +STR_1472 :{SMALLFONT}{BLACK}Velocidade desta atração +STR_1473 :{WINDOW_COLOUR_2}Classificação de emoção: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1474 :{WINDOW_COLOUR_2}Classificação de emoção: {BLACK}Indisponível +STR_1475 :{WINDOW_COLOUR_2}Classificação de intensidade: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1476 :{WINDOW_COLOUR_2}Classificação de intensidade: {BLACK}Indisponível +STR_1477 :{WINDOW_COLOUR_2}Classificação de intensidade: {OUTLINE}{RED}{COMMA2DP32} ({STRINGID}) +STR_1478 :{WINDOW_COLOUR_2}Classificação de náuseas: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1479 :{WINDOW_COLOUR_2}Classificação de náuseas: {BLACK}Indisponível +STR_1480 :{SMALLFONT}{OPENQUOTES}Eu não posso pagar{STRINGID}{ENDQUOTES} +STR_1481 :{SMALLFONT}{OPENQUOTES}Eu gastei todo o meu dinheiro{ENDQUOTES} +STR_1482 :{SMALLFONT}{OPENQUOTES}Eu me sinto mal{ENDQUOTES} +STR_1483 :{SMALLFONT}{OPENQUOTES}Eu me sinto muito mal{ENDQUOTES} +STR_1484 :{SMALLFONT}{OPENQUOTES}Eu quero ir em algo mais emocionante do que {STRINGID}{ENDQUOTES} +STR_1485 :{SMALLFONT}{OPENQUOTES}{STRINGID} parece muito intenso para mim{ENDQUOTES} +STR_1486 :{SMALLFONT}{OPENQUOTES}Eu não terminei meu {STRINGID} ainda{ENDQUOTES} +STR_1487 :{SMALLFONT}{OPENQUOTES}Basta olhar para {STRINGID} para me sentir mal{ENDQUOTES} +STR_1488 :{SMALLFONT}{OPENQUOTES}Eu não estou pagando muito para ir em {STRINGID}{ENDQUOTES} +STR_1489 :{SMALLFONT}{OPENQUOTES}Eu quero ir para casa{ENDQUOTES} +STR_1490 :{SMALLFONT}{OPENQUOTES}{STRINGID} é realmente bom preço{ENDQUOTES} +STR_1491 :{SMALLFONT}{OPENQUOTES}Eu já tenho {STRINGID}{ENDQUOTES} +STR_1492 :{SMALLFONT}{OPENQUOTES}Não posso pagar {STRINGID}{ENDQUOTES} +STR_1493 :{SMALLFONT}{OPENQUOTES}Eu não estou com fome{ENDQUOTES} +STR_1494 :{SMALLFONT}{OPENQUOTES}Eu não estou com sede{ENDQUOTES} +STR_1495 :{SMALLFONT}{OPENQUOTES}Socorro! Estou me afogando!{ENDQUOTES} +STR_1496 :{SMALLFONT}{OPENQUOTES}Eu estou perdido!{ENDQUOTES} +STR_1497 :{SMALLFONT}{OPENQUOTES}{STRINGID} foi ótimo{ENDQUOTES} +STR_1498 :{SMALLFONT}{OPENQUOTES}Eu estive na fila para {STRINGID} por anos{ENDQUOTES} +STR_1499 :{SMALLFONT}{OPENQUOTES}Eu estou cansado{ENDQUOTES} +STR_1500 :{SMALLFONT}{OPENQUOTES}Eu estou com fome{ENDQUOTES} +STR_1501 :{SMALLFONT}{OPENQUOTES}Eu estou com sede{ENDQUOTES} +STR_1502 :{SMALLFONT}{OPENQUOTES}Eu preciso ir ao banheiro{ENDQUOTES} +STR_1503 :{SMALLFONT}{OPENQUOTES}Eu não consigo encontrar {STRINGID}{ENDQUOTES} +STR_1504 :{SMALLFONT}{OPENQUOTES}Eu não estou pagando muito de usar {STRINGID}{ENDQUOTES} +STR_1505 :{SMALLFONT}{OPENQUOTES}Eu não estou indo em {STRINGID} enquanto está chovendo{ENDQUOTES} +STR_1506 :{SMALLFONT}{OPENQUOTES}O lixo aqui é muito ruim{ENDQUOTES} +STR_1507 :{SMALLFONT}{OPENQUOTES}Eu não estou encontrando a saída do parque{ENDQUOTES} +STR_1508 :{SMALLFONT}{OPENQUOTES}Eu quero sair{STRINGID}{ENDQUOTES} +STR_1509 :{SMALLFONT}{OPENQUOTES}Eu quero sair do {STRINGID}{ENDQUOTES} +STR_1510 :{SMALLFONT}{OPENQUOTES}Eu não estou indo em {STRINGID} - Não é seguro{ENDQUOTES} +STR_1511 :{SMALLFONT}{OPENQUOTES}Este caminho é nojento{ENDQUOTES} +STR_1512 :{SMALLFONT}{OPENQUOTES}Está lotado aqui{ENDQUOTES} +STR_1513 :{SMALLFONT}{OPENQUOTES}O vandalismo aqui é muito ruim{ENDQUOTES} +STR_1514 :{SMALLFONT}{OPENQUOTES}Excelente cenário!{ENDQUOTES} +STR_1515 :{SMALLFONT}{OPENQUOTES}Este parque é realmente limpo e arrumado{ENDQUOTES} +STR_1516 :{SMALLFONT}{OPENQUOTES}As fontes de salto são ótimas{ENDQUOTES} +STR_1517 :{SMALLFONT}{OPENQUOTES}A música é agradável aqui{ENDQUOTES} +STR_1518 :{SMALLFONT}{OPENQUOTES}Este balão de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1519 :{SMALLFONT}{OPENQUOTES}Este brinquedo pelúcia de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1520 :{SMALLFONT}{OPENQUOTES}Este mapa do parque de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1521 :{SMALLFONT}{OPENQUOTES}Esta foto na atração de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1522 :{SMALLFONT}{OPENQUOTES}Este guarda-chuva de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1523 :{SMALLFONT}{OPENQUOTES}Esta bebida de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1524 :{SMALLFONT}{OPENQUOTES}Este hambúrguer de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1525 :{SMALLFONT}{OPENQUOTES}Estas batatas fritas de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1526 :{SMALLFONT}{OPENQUOTES}Este sorvete de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1527 :{SMALLFONT}{OPENQUOTES}Este algodão-doce de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1528 : +STR_1529 : +STR_1530 : +STR_1531 :{SMALLFONT}{OPENQUOTES}Esta pizza de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1532 : +STR_1533 :{SMALLFONT}{OPENQUOTES}Esta pipoca de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1534 :{SMALLFONT}{OPENQUOTES}Este cachorro quente de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1535 :{SMALLFONT}{OPENQUOTES}Este tentáculo de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1536 :{SMALLFONT}{OPENQUOTES}Este chapéu de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1537 :{SMALLFONT}{OPENQUOTES}Esta maça do amor de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1538 :{SMALLFONT}{OPENQUOTES}Esta camiseta de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1539 :{SMALLFONT}{OPENQUOTES}Esta rosquinha de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1540 :{SMALLFONT}{OPENQUOTES}Este café de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1541 : +STR_1542 :{SMALLFONT}{OPENQUOTES}Este frango frito de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1543 :{SMALLFONT}{OPENQUOTES}Esta limonada de {STRINGID} tem um bom preço{ENDQUOTES} +STR_1544 : +STR_1545 : +STR_1546 : +STR_1547 : +STR_1548 : +STR_1549 : +STR_1550 :{SMALLFONT}{OPENQUOTES}Wow!{ENDQUOTES} +STR_1551 :{SMALLFONT}{OPENQUOTES}I have the strangest feeling someone is watching me{ENDQUOTES} +STR_1552 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a balloon from {STRINGID}{ENDQUOTES} +STR_1553 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a cuddly toy from {STRINGID}{ENDQUOTES} +STR_1554 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a park map from {STRINGID}{ENDQUOTES} +STR_1555 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} +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 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 candyfloss from {STRINGID}{ENDQUOTES} +STR_1562 : +STR_1563 : +STR_1564 : +STR_1565 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for pizza from {STRINGID}{ENDQUOTES} +STR_1566 : +STR_1567 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for popcorn from {STRINGID}{ENDQUOTES} +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 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} +STR_1575 : +STR_1576 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fried chicken from {STRINGID}{ENDQUOTES} +STR_1577 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for lemonade from {STRINGID}{ENDQUOTES} +STR_1578 : +STR_1579 : +STR_1580 : +STR_1581 : +STR_1582 : +STR_1583 : +STR_1584 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} +STR_1585 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} +STR_1586 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} +STR_1587 :{SMALLFONT}{OPENQUOTES}This pretzel from {STRINGID} is really good value{ENDQUOTES} +STR_1588 :{SMALLFONT}{OPENQUOTES}This hot chocolate from {STRINGID} is really good value{ENDQUOTES} +STR_1589 :{SMALLFONT}{OPENQUOTES}This iced tea from {STRINGID} is really good value{ENDQUOTES} +STR_1590 :{SMALLFONT}{OPENQUOTES}This funnel cake from {STRINGID} is really good value{ENDQUOTES} +STR_1591 :{SMALLFONT}{OPENQUOTES}These sunglasses from {STRINGID} are really good value{ENDQUOTES} +STR_1592 :{SMALLFONT}{OPENQUOTES}These beef noodles from {STRINGID} are really good value{ENDQUOTES} +STR_1593 :{SMALLFONT}{OPENQUOTES}These fried rice noodles from {STRINGID} are really good value{ENDQUOTES} +STR_1594 :{SMALLFONT}{OPENQUOTES}This wonton soup from {STRINGID} is really good value{ENDQUOTES} +STR_1595 :{SMALLFONT}{OPENQUOTES}This meatball soup from {STRINGID} is really good value{ENDQUOTES} +STR_1596 :{SMALLFONT}{OPENQUOTES}This fruit juice from {STRINGID} is really good value{ENDQUOTES} +STR_1597 :{SMALLFONT}{OPENQUOTES}This soybean milk from {STRINGID} is really good value{ENDQUOTES} +STR_1598 :{SMALLFONT}{OPENQUOTES}This sujongkwa from {STRINGID} is really good value{ENDQUOTES} +STR_1599 :{SMALLFONT}{OPENQUOTES}This sub sandwich from {STRINGID} is really good value{ENDQUOTES} +STR_1600 :{SMALLFONT}{OPENQUOTES}This cookie from {STRINGID} is really good value{ENDQUOTES} +STR_1601 : +STR_1602 : +STR_1603 : +STR_1604 :{SMALLFONT}{OPENQUOTES}This roast sausage from {STRINGID} are really good value{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}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} +STR_1617 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} +STR_1618 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} +STR_1619 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a pretzel from {STRINGID}{ENDQUOTES} +STR_1620 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for hot chocolate from {STRINGID}{ENDQUOTES} +STR_1621 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for iced tea from {STRINGID}{ENDQUOTES} +STR_1622 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a funnel cake from {STRINGID}{ENDQUOTES} +STR_1623 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for sunglasses from {STRINGID}{ENDQUOTES} +STR_1624 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for beef noodles from {STRINGID}{ENDQUOTES} +STR_1625 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fried rice noodles from {STRINGID}{ENDQUOTES} +STR_1626 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for wonton soup from {STRINGID}{ENDQUOTES} +STR_1627 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for meatball soup from {STRINGID}{ENDQUOTES} +STR_1628 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fruit juice from {STRINGID}{ENDQUOTES} +STR_1629 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for soybean milk from {STRINGID}{ENDQUOTES} +STR_1630 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for sujongkwa from {STRINGID}{ENDQUOTES} +STR_1631 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a sub sandwich from {STRINGID}{ENDQUOTES} +STR_1632 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a cookie from {STRINGID}{ENDQUOTES} +STR_1633 : +STR_1634 : +STR_1635 : +STR_1636 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a roast sausage from {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}Help! Put me down!{ENDQUOTES} +STR_1649 :{SMALLFONT}{OPENQUOTES}I'm running out of cash!{ENDQUOTES} +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}Atração preferida +STR_1658 :{WINDOW_COLOUR_2}intensidade: {BLACK}menor que {COMMA16} +STR_1659 :{WINDOW_COLOUR_2}intensidade: {BLACK}entre {COMMA16} and {COMMA16} +STR_1660 :{WINDOW_COLOUR_2}intensidade: {BLACK}maior que {COMMA16} +STR_1661 :{WINDOW_COLOUR_2}Tolerância à náuseas:{BLACK}{STRINGID} +STR_1662 :{WINDOW_COLOUR_2}Felicidade: +STR_1663 :{WINDOW_COLOUR_2}Náusea: +STR_1664 :{WINDOW_COLOUR_2}Energia: +STR_1665 :{WINDOW_COLOUR_2}Fome: +STR_1666 :{WINDOW_COLOUR_2}Sede: +STR_1667 :{WINDOW_COLOUR_2}Banheiro: +STR_1668 :{WINDOW_COLOUR_2}Satisfação: {BLACK}Desconhecido +STR_1669 :{WINDOW_COLOUR_2}Satisfação: {BLACK}{COMMA16}% +STR_1670 :{WINDOW_COLOUR_2}Total de clientes: {BLACK}{COMMA32} +STR_1671 :{WINDOW_COLOUR_2}Lucro total: {BLACK}{CURRENCY2DP} +STR_1672 :Freios +STR_1673 :Spinning Control Toggle Track +STR_1674 :Velocidade do freio +STR_1675 :{POP16}{VELOCITY} +STR_1676 :{SMALLFONT}{BLACK}Set speed limit for brakes +STR_1677 :{WINDOW_COLOUR_2}Popularidade: {BLACK}Desconhecido +STR_1678 :{WINDOW_COLOUR_2}Popularidade: {BLACK}{COMMA16}% +STR_1679 :Hélice Cima (esquerda) +STR_1680 :Hélice Cima (direita) +STR_1681 :Hélice Baixo (esqueda) +STR_1682 :Hélice Baixo (direita) +STR_1683 :Tamanho da base 2 x 2 +STR_1684 :Tamanho da base 4 x 4 +STR_1685 :Tamanho da base 2 x 4 +STR_1686 :Tamanho da base 5 x 1 +STR_1687 :Respingo da água +STR_1688 :Tamanho da base 4 x 1 +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}Visitantes +STR_1694 :{SMALLFONT}{BLACK}Funcionários +STR_1695 :{SMALLFONT}{BLACK}Rendimentos e gastos +STR_1696 :{SMALLFONT}{BLACK}Informação para os clientes +STR_1697 :Cannot place these on queue line area +STR_1698 :Can only place these on queue area +STR_1699 :Muitas pessoas no jogo +STR_1700 :Contratar novo Faz-Tudo +STR_1701 :Contratar novo Mecânico +STR_1702 :Contratar novo Segurança +STR_1703 :Contratar novo Animador +STR_1704 :Impossível contratar novos funcionários... +STR_1705 :{SMALLFONT}{BLACK}Demitir este funcionário +STR_1706 :{SMALLFONT}{BLACK}Mover essa pessao para um novo local +STR_1707 :Muitos funcionários no jogo +STR_1708 :{SMALLFONT}{BLACK}Definir área de patrulha do funcionário +STR_1709 :Demitir funcionário +STR_1710 :Sim +STR_1711 :{WINDOW_COLOUR_1}Are you sure you want to sack {STRINGID}? +STR_1712 :{INLINE_SPRITE}{247}{19}{00}{00}{WINDOW_COLOUR_2}Varrer calçadas +STR_1713 :{INLINE_SPRITE}{248}{19}{00}{00}{WINDOW_COLOUR_2}Regar jardins +STR_1714 :{INLINE_SPRITE}{249}{19}{00}{00}{WINDOW_COLOUR_2}Esvaziar lixeiras +STR_1715 :{INLINE_SPRITE}{250}{19}{00}{00}{WINDOW_COLOUR_2}Cortar Gramas +STR_1716 :Nome invalido para o park +STR_1717 :Impossível renomear o park... +STR_1718 :Nome do Parque +STR_1719 :Digite o nome para o parque: +STR_1720 :{SMALLFONT}{BLACK}Nome do parque +STR_1721 :Park fechado +STR_1722 :Park aberto +STR_1723 :Impossível abrir o park... +STR_1724 :Impossível fechar o park... +STR_1725 :Impossível comprar Can't buy região... +STR_1726 :Região não está a venda! +STR_1727 :Direitos de construção não está à venda! +STR_1728 :Não pode comprar os direitos de construção aqui... +STR_1729 :Os terrenos não são propriedade do parque! +STR_1730 :{RED}Fechado - - +STR_1731 :{WHITE}{STRINGID} - - +STR_1732 :Construir +STR_1733 :Modo +STR_1734 :{WINDOW_COLOUR_2}Número de voltas: +STR_1735 :{SMALLFONT}{BLACK}Número de voltas do circuito +STR_1736 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1737 :{COMMA16} +STR_1738 :Impossível alterar o número de voltas... +STR_1739 :Corrida ganha pelo visitante {INT32} +STR_1740 :Corrida ganha por {STRINGID} +STR_1741 :Ainda não construido ! +STR_1742 :{WINDOW_COLOUR_2}Max. pessoas na atração: +STR_1743 :{SMALLFONT}{BLACK}Número máximo permitido de pessoas na atração por vez +STR_1744 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1745 :{COMMA16} +STR_1746 :Impossível alterar isto... +STR_1747 :{WINDOW_COLOUR_2}Tempo limite: +STR_1748 :{SMALLFONT}{BLACK}Time limit for ride +STR_1749 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{DURATION} +STR_1750 :{DURATION} +STR_1751 :Can't change time limit for ride... +STR_1752 :{SMALLFONT}{BLACK}Show list of individual guests in park +STR_1753 :{SMALLFONT}{BLACK}Show summarised list of guests in park +STR_1754 :{BLACK}{COMMA16} visitantes +STR_1755 :{BLACK}{COMMA16} visitante +STR_1756 :{WINDOW_COLOUR_2}Preço de entrada: +STR_1757 :{WINDOW_COLOUR_2}Confiabilidade: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1758 :{SMALLFONT}{BLACK}Modo de construção +STR_1759 :{SMALLFONT}{BLACK}Modo de movimentação +STR_1760 :{SMALLFONT}{BLACK}Modo de Preenchiment +STR_1761 :{SMALLFONT}{BLACK}Construir labirinto nessa direção +STR_1762 :Cachoeiras +STR_1763 :Corredeiras +STR_1764 :Log Bumps +STR_1765 :On-ride photo section +STR_1766 :Reverser turntable +STR_1767 :Spinning tunnel +STR_1768 :Can't change number of swings... +STR_1769 :{WINDOW_COLOUR_2}Number of swings: +STR_1770 :{SMALLFONT}{BLACK}Number of complete swings +STR_1771 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1772 :{COMMA16} +STR_1773 :Only one on-ride photo section allowed per ride +STR_1774 :Only one cable lift hill allowed per ride +STR_1775 :Desligado +STR_1776 :Ligado +STR_1777 :{WINDOW_COLOUR_2}Música: +STR_1778 :{STRINGID} - - +STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Fantasia de panda +STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Fantasia de tigre +STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} Fantasia de elefante +STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} Fantasia de romano +STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} Fantasia de gorila +STR_1784 :{INLINE_SPRITE}{03}{20}{00}{00} Fantasia de boneco de neve +STR_1785 :{INLINE_SPRITE}{04}{20}{00}{00} Fantasia de cavaleiro +STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} Fantasia de astronauta +STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} Fantasia de bandido +STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} Fantasia de xerife +STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} Fantasia de pirata +STR_1790 :{SMALLFONT}{BLACK}Selecione a cor do uniforme para este tipo de funcionário +STR_1791 :{WINDOW_COLOUR_2}Cor do uniforme: +STR_1792 :Respondendo a chamada de quebra da {STRINGID} +STR_1793 :Rumo ao {STRINGID} para uma inspecção +STR_1794 :Reparando a {STRINGID} +STR_1795 :Respondendo a chamada do rádio +STR_1796 :Esta quebrado e requer conserto +STR_1797 :Esta opção não pode ser alterada para esta atração +STR_1798 :Turbilhão +STR_1799 :{POP16}{POP16}{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1800 :Segurança cortada +STR_1801 :Restrições presas fechadas +STR_1802 :Restrições presas abertas +STR_1803 :Portas emperradas fechadas +STR_1804 :Portas emperradas abertas +STR_1805 :Veículo em mal funcionamento +STR_1806 :Falha nos freios +STR_1807 :Falha nos controles +STR_1808 :{WINDOW_COLOUR_2}Última quebra: {BLACK}{STRINGID} +STR_1809 :{WINDOW_COLOUR_2}Atualmente quebrado: {OUTLINE}{RED}{STRINGID} +STR_1810 :{WINDOW_COLOUR_2}Transportando: +STR_1811 :Impossível construir isto aqui... +STR_1812 :{SMALLFONT}{BLACK}{STRINGID} +STR_1813 :Objetos váriados +STR_1814 :Ações +STR_1815 :Pensamentos +STR_1816 :{SMALLFONT}{BLACK}Selecione o tipo de informação para mostrar na lista de visitantes +STR_1817 :({COMMA16}) +STR_1818 :{WINDOW_COLOUR_2}Todos os visitantes +STR_1819 :{WINDOW_COLOUR_2}Todos os visitantes (resumido) +STR_1820 :{WINDOW_COLOUR_2}Visitantes {STRINGID} +STR_1821 :{WINDOW_COLOUR_2}Pensamentos dos visitantes {STRINGID} +STR_1822 :{WINDOW_COLOUR_2}Visistantes pensam sobre {{POP16}{STRINGID} +STR_1823 :{SMALLFONT}{BLACK}Mostrar os pensamentos dos visitantes sobre essa atração +STR_1824 :{SMALLFONT}{BLACK}Mostrar os visitantes nesta atração +STR_1825 :{SMALLFONT}{BLACK}Mostrar os visitantes na fila para essa atração +STR_1826 :Estado +STR_1827 :Popularidade +STR_1828 :Satisfação +STR_1829 :Lucro +STR_1830 :Tamanho da fila +STR_1831 :Tempo na fila +STR_1832 :Confiança +STR_1833 :Tempo ocioso +STR_1834 :Visistante favorito +STR_1835 :Popularidade: Desconhecido +STR_1836 :Popularidade: {COMMA16}% +STR_1837 :Satisfação: Desconhecido +STR_1838 :Satisfação: {COMMA16}% +STR_1839 :Confiança: {COMMA16}% +STR_1840 :Tempo ocioso: {COMMA16}% +STR_1841 :Lucro: {CURRENCY2DP} por hora +STR_1842 :Favorito de: {COMMA16} visitante +STR_1843 :Favorito de: {COMMA16} visitantes +STR_1844 :{SMALLFONT}{BLACK}Selecione o tipo de informação para ser exibida na lista de atrações +STR_1845 :{MONTHYEAR} +STR_1846 :{COMMA16} Visitantes +STR_1847 :{INLINE_SPRITE}{11}{20}{00}{00}{COMMA16} Visitantes +STR_1848 :{INLINE_SPRITE}{10}{20}{00}{00}{COMMA16} Visitantes +STR_1849 :{WINDOW_COLOUR_2}Tocar musica +STR_1850 :{SMALLFONT}{BLACK}Selecione a música que deve ser tocada nesta atração +STR_1851 :{WINDOW_COLOUR_2}Custos de funcionamento: {BLACK}{CURRENCY2DP} por hora +STR_1852 :{WINDOW_COLOUR_2}Custos de funcionamento: {BLACK}desconhecido +STR_1853 :{WINDOW_COLOUR_2}Construído: {BLACK}Este Ano +STR_1854 :{WINDOW_COLOUR_2}Construído: {BLACK}Ano Passado +STR_1855 :{WINDOW_COLOUR_2}Construído: {BLACK}{COMMA16} Anos atrás +STR_1856 :{WINDOW_COLOUR_2}Lucro por item vendido: {BLACK}{CURRENCY2DP} +STR_1857 :{WINDOW_COLOUR_2}Prejuízo por item vendido: {BLACK}{CURRENCY2DP} +STR_1858 :{WINDOW_COLOUR_2}Custo: {BLACK}{CURRENCY2DP} por mês +STR_1859 :Faz-Tudo +STR_1860 :Mecânicos +STR_1861 :Seguranças +STR_1862 :Animadores +STR_1863 :Faz-Tudo +STR_1864 :Mecânico +STR_1865 :Segurança +STR_1866 :Animador +STR_1867 :{BLACK}{COMMA16} {STRINGID} +STR_1868 :Impossível alterar o numero de rotações... +STR_1869 :{WINDOW_COLOUR_2}Número de rotações: +STR_1870 :{SMALLFONT}{BLACK}Número de rotações completas +STR_1871 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1872 :{COMMA16} +STR_1873 :{WINDOW_COLOUR_2}Rendimento: {BLACK}{CURRENCY2DP} por hora +STR_1874 :{WINDOW_COLOUR_2}Lucro: {BLACK}{CURRENCY2DP} por hora +STR_1875 :{BLACK} {SPRITE}{BLACK} {STRINGID} +STR_1876 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{251}{19}{00}{00}Inspecionar Atrações +STR_1877 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{252}{19}{00}{00}Consertar Atrações +STR_1878 :{WINDOW_COLOUR_2}Inspeção: +STR_1879 :A cada 10 minutos +STR_1880 :A cada 20 minutos +STR_1881 :A cada 30 minutos +STR_1882 :A cada 45 minutos +STR_1883 :A cada hora +STR_1884 :A cada 2 horas +STR_1885 :Numca +STR_1886 :Inspecionando {STRINGID} +STR_1887 :{WINDOW_COLOUR_2}Tempo desde a última inspeção: {BLACK}{COMMA16} minutos +STR_1888 :{WINDOW_COLOUR_2}Tempo desde a última inspeção: {BLACK}mais de 4 horas +STR_1889 :{WINDOW_COLOUR_2}Tempo ocioso: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1890 :{SMALLFONT}{BLACK}Selecione a frequência com um mecânico deve verificar esta atração +STR_1891 :No {STRINGID} parque ainda! +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 : +STR_1893 : +STR_1894 :{WINDOW_COLOUR_2}{STRINGID} vendido: {BLACK}{COMMA32} +STR_1895 :{SMALLFONT}{BLACK}Construir uma nova atração +STR_1896 :{WINDOW_COLOUR_2}Receitas/Despesas +STR_1897 :{WINDOW_COLOUR_2}Construções +STR_1898 :{WINDOW_COLOUR_2}Func. das atrações +STR_1899 :{WINDOW_COLOUR_2}Compra de terrenos +STR_1900 :{WINDOW_COLOUR_2}Landscaping +STR_1901 :{WINDOW_COLOUR_2}Entradas no parque +STR_1902 :{WINDOW_COLOUR_2}Atrações +STR_1903 :{WINDOW_COLOUR_2}Vendas das lojas +STR_1904 :{WINDOW_COLOUR_2}Estoque das lojas +STR_1905 :{WINDOW_COLOUR_2}Vendas de Comidas +STR_1906 :{WINDOW_COLOUR_2}Estoq. de Comidas +STR_1907 :{WINDOW_COLOUR_2}Funcionários +STR_1908 :{WINDOW_COLOUR_2}Marketing +STR_1909 :{WINDOW_COLOUR_2}Pesquisa +STR_1910 :{WINDOW_COLOUR_2}Juros de empréstimos +STR_1911 :{BLACK} de {COMMA16}% ao ano +STR_1912 :{MONTH} +STR_1913 :{BLACK}+{CURRENCY2DP} +STR_1914 :{BLACK}{CURRENCY2DP} +STR_1915 :{RED}{CURRENCY2DP} +STR_1916 :{WINDOW_COLOUR_2}crédito: +STR_1917 :{POP16}{POP16}{POP16}{CURRENCY} +STR_1918 :Não é possivel emprestar mais dinheiro! +STR_1919 :Não possui dinheiro suficiente! +STR_1920 :Impossível pagar o empréstimo! +STR_1921 :{SMALLFONT}{BLACK}Começar um novo jogo +STR_1922 :{SMALLFONT}{BLACK}Continuar um jogo salvo +STR_1923 :{SMALLFONT}{BLACK}Mostrar Tutoriais +STR_1924 :{SMALLFONT}{BLACK}Sair +STR_1925 :Impossível colocar uma pessoa aqui... +STR_1926 :{SMALLFONT} +STR_1927 :{YELLOW}{STRINGID} Quebrou +STR_1928 :{RED}{STRINGID} Bateu! +STR_1929 :{RED}{STRINGID} still hasn't been fixed{NEWLINE}Check where your mechanics are and consider organizing them better +STR_1930 :{SMALLFONT}{BLACK}Turn on/off tracking information for this guest - (If tracking is on, guest's movements will be reported in the message area) +STR_1931 :{STRINGID} entrou na fila de espera para {STRINGID} +STR_1932 :{STRINGID} está no {STRINGID} +STR_1933 :{STRINGID} esta no {STRINGID} +STR_1934 :{STRINGID} saiu do {STRINGID} +STR_1935 :{STRINGID} saiu do parque +STR_1936 :{STRINGID} comprou {STRINGID} +STR_1937 :{SMALLFONT}{BLACK}Show information about the subject of this message +STR_1938 :{SMALLFONT}{BLACK}Show view of guest +STR_1939 :{SMALLFONT}{BLACK}Show view of staff member +STR_1940 :{SMALLFONT}{BLACK}Show happiness, energy, hunger etc. for this guest +STR_1941 :{SMALLFONT}{BLACK}Show which rides this guest has been on +STR_1942 :{SMALLFONT}{BLACK}Show financial information about this guest +STR_1943 :{SMALLFONT}{BLACK}Show guest's recent thoughts +STR_1944 :{SMALLFONT}{BLACK}Show items guest is carrying +STR_1945 :{SMALLFONT}{BLACK}Show orders and options for this staff member +STR_1946 :{SMALLFONT}{BLACK}Select costume for this entertainer +STR_1947 :{SMALLFONT}{BLACK}Show areas patrolled by selected staff type, and locate the nearest staff member +STR_1948 :{SMALLFONT}{BLACK}Hire a new staff member of the selected type +STR_1949 :Resumo Financeiro +STR_1950 :Gráfico Financeiro +STR_1951 :Gráfico do Valor do Parque +STR_1952 :Gráfico dos Lucros +STR_1953 :Marketing +STR_1954 :Financiamento de Pesquisa +STR_1955 :{WINDOW_COLOUR_2}Number of circuits: +STR_1956 :{SMALLFONT}{BLACK}Number of circuits of track per ride +STR_1957 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1958 :{COMMA16} +STR_1959 :Can't change number of circuits... +STR_1960 :{WINDOW_COLOUR_2}Balloon price: +STR_1961 :{WINDOW_COLOUR_2}Cuddly Toy price: +STR_1962 :{WINDOW_COLOUR_2}Park Map price: +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}Chips price: +STR_1968 :{WINDOW_COLOUR_2}Ice Cream price: +STR_1969 :{WINDOW_COLOUR_2}Candyfloss price: +STR_1970 :{WINDOW_COLOUR_2} +STR_1971 :{WINDOW_COLOUR_2} +STR_1972 :{WINDOW_COLOUR_2} +STR_1973 :{WINDOW_COLOUR_2}Pizza price: +STR_1974 :{WINDOW_COLOUR_2} +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}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: +STR_1983 :{WINDOW_COLOUR_2} +STR_1984 :{WINDOW_COLOUR_2}Fried Chicken price: +STR_1985 :{WINDOW_COLOUR_2}Lemonade price: +STR_1986 :{WINDOW_COLOUR_2} +STR_1987 :{WINDOW_COLOUR_2} +STR_1988 :Balão +STR_1989 :Brinquedo de Pelúcia +STR_1990 :Mapa do parque +STR_1991 :Foto da Atração +STR_1992 :Guarda-Chuva +STR_1993 :Bebida +STR_1994 :Hambúrguer +STR_1995 :Batata Frita +STR_1996 :Sorvete +STR_1997 :Algodão-Doce +STR_1998 :Lata Vazia +STR_1999 :Lixo +STR_2000 :Caixa de Hambúrguer Vazia +STR_2001 :Pizza +STR_2002 :Voucher +STR_2003 :Pipoca +STR_2004 :Cachorro-quente +STR_2005 :Tentáculo +STR_2006 :Chapéu +STR_2007 :Maça do Amor +STR_2008 :Camiseta +STR_2009 :Donut +STR_2010 :Café +STR_2011 :Copo Vazio +STR_2012 :Frango Frito +STR_2013 :Limonada +STR_2014 :Caixa Vazia +STR_2015 :Garrafa Vazia +STR_2016 :Balões +STR_2017 :Brinquedos de Pelúcia +STR_2018 :Mapas do Parque +STR_2019 :Fotos na Atração +STR_2020 :Guarda-Chuvas +STR_2021 :Bebidas +STR_2022 :Hambúrguers +STR_2023 :Batatas Fritas +STR_2024 :Sorvetes +STR_2025 :Algodões-Doces +STR_2026 :Latas Vazias +STR_2027 :Lixos +STR_2028 :Caixas de Hambúrguer Vazias +STR_2029 :Pizzas +STR_2030 :Vouchers +STR_2031 :Pipocas +STR_2032 :Cachorros-quentes +STR_2033 :Tentáculos +STR_2034 :Chapéus +STR_2035 :Maças do Amor +STR_2036 :Camisetas +STR_2037 :Donuts +STR_2038 :Cafés +STR_2039 :Copos Vazios +STR_2040 :Frangos Fritos +STR_2041 :Limonadas +STR_2042 :Caixas Vazias +STR_2043 :Garrafas Vazias +STR_2044 :um balão +STR_2045 :um brinquedo de pelúcia +STR_2046 :um mapa do parque +STR_2047 :uma foto na atração +STR_2048 :um guarda-chuva +STR_2049 :uma bebida +STR_2050 :um hambúrguer +STR_2051 :uma batata frita +STR_2052 :um sorvete +STR_2053 :algum algodão-Doce +STR_2054 :uma lata vazia +STR_2055 :algum lixo +STR_2056 :uma caixa de hambúrguer vazia +STR_2057 :uma pizza +STR_2058 :um voucher +STR_2059 :alguma pipoca +STR_2060 :um cachorro-quente +STR_2061 :um tentáculo +STR_2062 :um chapéu +STR_2063 :uma maça do amor +STR_2064 :uma camiseta +STR_2065 :um Donut +STR_2066 :um café +STR_2067 :um copo vazio +STR_2068 :algum frango frito +STR_2069 :alguma limonada +STR_2070 :uma caixa vazia +STR_2071 :uma garafa vazia +STR_2072 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Balão +STR_2073 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Brinquedo de Pelúcia +STR_2074 :Mapa de {STRINGID} +STR_2075 :foto na atração {STRINGID} +STR_2076 :Guarda-Chuva {OPENQUOTES}{STRINGID}{ENDQUOTES} +STR_2077 :Bebida +STR_2078 :Hambúrguer +STR_2079 :Batata Frita +STR_2080 :Sorvete +STR_2081 :Algodão-Doce +STR_2082 :Lata Vazia +STR_2083 :lixo +STR_2084 :Caixa de Hambúrguer Vazia +STR_2085 :Pizza +STR_2086 :Voucher para {STRINGID} +STR_2087 :Pipoca +STR_2088 :Cachorro-Quente +STR_2089 :Tentáculo +STR_2090 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Chapéu +STR_2091 :Maça do Amor +STR_2092 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Camiseta +STR_2093 :Donut +STR_2094 :Café +STR_2095 :Copo Vazio +STR_2096 :Frango Frito +STR_2097 :Limonada +STR_2098 :Caixa Vazia +STR_2099 :Garafa Vazia +STR_2100 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_2101 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_2102 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_2103 :{WINDOW_COLOUR_2}Pretzel price: +STR_2104 :{WINDOW_COLOUR_2}Hot Chocolate price: +STR_2105 :{WINDOW_COLOUR_2}Iced Tea price: +STR_2106 :{WINDOW_COLOUR_2}Funnel Cake price: +STR_2107 :{WINDOW_COLOUR_2}Sunglasses price: +STR_2108 :{WINDOW_COLOUR_2}Beef Noodles price: +STR_2109 :{WINDOW_COLOUR_2}Fried Rice Noodles price: +STR_2110 :{WINDOW_COLOUR_2}Wonton Soup price: +STR_2111 :{WINDOW_COLOUR_2}Meatball Soup price: +STR_2112 :{WINDOW_COLOUR_2}Fruit Juice price: +STR_2113 :{WINDOW_COLOUR_2}Soybean Milk price: +STR_2114 :{WINDOW_COLOUR_2}Sujongkwa price: +STR_2115 :{WINDOW_COLOUR_2}Sub Sandwich price: +STR_2116 :{WINDOW_COLOUR_2}Cookie price: +STR_2117 :{WINDOW_COLOUR_2} +STR_2118 :{WINDOW_COLOUR_2} +STR_2119 :{WINDOW_COLOUR_2} +STR_2120 :{WINDOW_COLOUR_2}Roast Sausage price: +STR_2121 :{WINDOW_COLOUR_2} +STR_2122 :On-Ride Photo +STR_2123 :On-Ride Photo +STR_2124 :On-Ride Photo +STR_2125 :Pretzel +STR_2126 :Chocolate Quente +STR_2127 :Chá Gelado +STR_2128 :Funnel Cake +STR_2129 :Óculos de sol +STR_2130 :Beef Noodles +STR_2131 :Fried Rice Noodles +STR_2132 :Wonton Soup +STR_2133 :Meatball Soup +STR_2134 :Suco de fruta +STR_2135 :Soybean Milk +STR_2136 :Sujongkwa +STR_2137 :Sub Sandwich +STR_2138 :Cookie +STR_2139 :Empty Bowl +STR_2140 :Empty Drink Carton +STR_2141 :Empty Juice Cup +STR_2142 :Roast Sausage +STR_2143 :Empty Bowl +STR_2144 :On-Ride Photos +STR_2145 :On-Ride Photos +STR_2146 :On-Ride Photos +STR_2147 :Pretzels +STR_2148 :Hot Chocolates +STR_2149 :Chás Gelados +STR_2150 :Funnel Cakes +STR_2151 :Sunglasses +STR_2152 :Beef Noodles +STR_2153 :Fried Rice Noodles +STR_2154 :Wonton Soups +STR_2155 :Meatball Soups +STR_2156 :Fruit Juices +STR_2157 :Soybean Milks +STR_2158 :Sujongkwa +STR_2159 :Sub Sandwiches +STR_2160 :Cookies +STR_2161 :Empty Bowls +STR_2162 :Empty Drink Cartons +STR_2163 :Empty Juice cups +STR_2164 :Roast Sausages +STR_2165 :Empty Bowls +STR_2166 :an On-Ride Photo +STR_2167 :an On-Ride Photo +STR_2168 :an On-Ride Photo +STR_2169 :a Pretzel +STR_2170 :a Hot Chocolate +STR_2171 :an Iced Tea +STR_2172 :a Funnel Cake +STR_2173 :a pair of Sunglasses +STR_2174 :some Beef Noodles +STR_2175 :some Fried Rice Noodles +STR_2176 :some Wonton Soup +STR_2177 :some Meatball Soup +STR_2178 :a Fruit Juice +STR_2179 :some Soybean Milk +STR_2180 :some Sujongkwa +STR_2181 :a Sub Sandwich +STR_2182 :a Cookie +STR_2183 :an Empty Bowl +STR_2184 :an Empty Drink Carton +STR_2185 :an Empty Juice Cup +STR_2186 :a Roast Sausage +STR_2187 :an Empty Bowl +STR_2188 :On-Ride Photo of {STRINGID} +STR_2189 :On-Ride Photo of {STRINGID} +STR_2190 :On-Ride Photo of {STRINGID} +STR_2191 :Pretzel +STR_2192 :Hot Chocolate +STR_2193 :Iced Tea +STR_2194 :Funnel Cake +STR_2195 :Sunglasses +STR_2196 :Beef Noodles +STR_2197 :Fried Rice Noodles +STR_2198 :Wonton Soup +STR_2199 :Meatball Soup +STR_2200 :Fruit Juice +STR_2201 :Soybean Milk +STR_2202 :Sujongkwa +STR_2203 :Sub Sandwich +STR_2204 :Cookie +STR_2205 :Empty Bowl +STR_2206 :Empty Drink Carton +STR_2207 :Empty Juice Cup +STR_2208 :Roast Sausage +STR_2209 :Empty Bowl +STR_2210 :{SMALLFONT}{BLACK}Exibir a lista de faz-tudo no parque +STR_2211 :{SMALLFONT}{BLACK}Exibir a lista de mecanicos no parque +STR_2212 :{SMALLFONT}{BLACK}Exibir a lista de seguranças no parque +STR_2213 :{SMALLFONT}{BLACK}Exibir a lista de animadores no parque +STR_2214 :Construction not possible while game is paused! +STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) +STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F +STR_2218 :{RED}{STRINGID} on {STRINGID} hasn't returned to the {STRINGID} yet!{NEWLINE}Check whether it is stuck or has stalled +STR_2219 :{RED}{COMMA16} people have died in an accident on {STRINGID} +STR_2220 :{WINDOW_COLOUR_2}Classificação do Parque: {BLACK}{COMMA16} +STR_2221 :{SMALLFONT}{BLACK}Classificação do Parque: {COMMA16} +STR_2222 :{SMALLFONT}{BLACK}{STRINGID} +STR_2223 :{WINDOW_COLOUR_2}Visitantes no parque: {BLACK}{COMMA16} +STR_2224 :{WINDOW_COLOUR_2}Dinheiro: {BLACK}{CURRENCY2DP} +STR_2225 :{WINDOW_COLOUR_2}Dinheiro: {RED}{CURRENCY2DP} +STR_2226 :{WINDOW_COLOUR_2}Valor do parque: {BLACK}{CURRENCY} +STR_2227 :{WINDOW_COLOUR_2}Valor da empresa: {BLACK}{CURRENCY} +STR_2228 :{WINDOW_COLOUR_2}Last month's profit from food/drink and{NEWLINE}merchandise sales: {BLACK}{CURRENCY} +STR_2229 :Slope up to vertical +STR_2230 :Vertical track +STR_2231 :Holding brake for drop +STR_2232 :Cable lift hill +STR_2233 :{SMALLFONT}{BLACK}Park information +STR_2234 :Mensagens Recentes +STR_2235 :{SMALLFONT}{STRINGID} {STRINGID} +STR_2236 :Janeiro +STR_2237 :Fevereiro +STR_2238 :Março +STR_2239 :Abril +STR_2240 :Maio +STR_2241 :Junho +STR_2242 :Julho +STR_2243 :Agosto +STR_2244 :Setembro +STR_2245 :Outubro +STR_2246 :Novembro +STR_2247 :Dezembro +STR_2248 :Impossível demolir a atração... +STR_2249 :{BABYBLUE}Nova atração disponível agora:{NEWLINE}{STRINGID} +STR_2250 :{BABYBLUE}Novo Cenário/Tematização disponível agora:{NEWLINE}{STRINGID} +STR_2251 :Somente pode ser construído sobre os caminhos! +STR_2252 :Somente pode ser construído através de caminhos! +STR_2253 :Atrações de Transporte +STR_2254 :Atrações Suaves/Calmas +STR_2255 :Montanhas-Russas +STR_2256 :Atrações Emocionantes +STR_2257 :Atrações Aquáticas +STR_2258 :Lojas & Barracas +STR_2259 :Cenário & Tematização +STR_2260 :Nenhum financiamento +STR_2261 :Financiamento mínimo +STR_2262 :Financiamento normal +STR_2263 :Financiamento máximo +STR_2264 :Financiamento da pesquisa +STR_2265 :{WINDOW_COLOUR_2}Custo: {BLACK}{CURRENCY} por mês +STR_2266 :Prioridades de pesquisa +STR_2267 :Atualmente em desenvolvimento +STR_2268 :Último desenvolvimento +STR_2269 :{WINDOW_COLOUR_2}Tipo: {BLACK}{STRINGID} +STR_2270 :{WINDOW_COLOUR_2}Progresso: {BLACK}{STRINGID} +STR_2271 :{WINDOW_COLOUR_2}Esperado: {BLACK}{STRINGID} +STR_2272 :{WINDOW_COLOUR_2}Atrações:{NEWLINE}{BLACK}{STRINGID} +STR_2273 :{WINDOW_COLOUR_2}Cenário/tematização:{NEWLINE}{BLACK}{STRINGID} +STR_2274 :{SMALLFONT}{BLACK}Mostrar detalhes desta invenção ou desenvolvimento +STR_2275 :{SMALLFONT}{BLACK}Mostrar financiamento e opções para pesquisa e desenvolvimento +STR_2276 :{SMALLFONT}{BLACK}Mostrar estado das pesquisa e desenvolvimentos +STR_2277 :Desconhecido +STR_2278 :Atrações de Transporte +STR_2279 :Atrações Suaves/Calmas +STR_2280 :Montanhas-Russas +STR_2281 :Atrações Emocionantes +STR_2282 :Atrações Aquáticas +STR_2283 :Lojas/Barracas +STR_2284 :Cenário/Tematização +STR_2285 :Pesquisa Inicial +STR_2286 :Projetando +STR_2287 :Completando Projeto +STR_2288 :Desconhecido +STR_2289 :{STRINGID} {STRINGID} +STR_2290 :{SMALLFONT}{BLACK}{STRINGID} {STRINGID} +STR_2291 :Selecione o cenário para novo jogo +STR_2292 :{WINDOW_COLOUR_2}Rides been on: +STR_2293 :{BLACK} Nada +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 +STR_2305 :Track design files +STR_2306 :Save track design +STR_2307 :Select {STRINGID} design +STR_2308 :{STRINGID} Track Designs +STR_2309 :Install New Track Design +STR_2310 :Build custom design +STR_2311 :{WINDOW_COLOUR_2}Classificação de emoção: {BLACK}{COMMA2DP32} (approx.) +STR_2312 :{WINDOW_COLOUR_2}Classificação de intensidade rating: {BLACK}{COMMA2DP32} (approx.) +STR_2313 :{WINDOW_COLOUR_2}Classificação de náuseas: {BLACK}{COMMA2DP32} (approx.) +STR_2314 :{WINDOW_COLOUR_2}Comprimento da atração: {BLACK}{STRINGID} +STR_2315 :{WINDOW_COLOUR_2}Custo: {BLACK}em torno de {CURRENCY} +STR_2316 :{WINDOW_COLOUR_2}Espaço necessário: {BLACK}{COMMA16} x {COMMA16} blocos +STR_2317 : +STR_2318 : +STR_2319 : +STR_2320 : +STR_2321 :{WINDOW_COLOUR_2}Number of rides/attractions: {BLACK}{COMMA16} +STR_2322 :{WINDOW_COLOUR_2}Funcionário: {BLACK}{COMMA16} +STR_2323 :{WINDOW_COLOUR_2}Park size: {BLACK}{COMMA32}m{SQUARED} +STR_2324 :{WINDOW_COLOUR_2}Park size: {BLACK}{COMMA32}sq.ft. +STR_2325 :{SMALLFONT}{BLACK}Comprar terreno para extender o parque +STR_2326 :{SMALLFONT}{BLACK}Comprar os direitos de construção para permitir a construção acima ou abaixo da terra fora do parque +STR_2327 :Opções +STR_2328 :{WINDOW_COLOUR_2}Moeda: +STR_2329 :{WINDOW_COLOUR_2}Distância e Velocidade: +STR_2330 :{WINDOW_COLOUR_2}Temperatura: +STR_2331 :{WINDOW_COLOUR_2}Marcadores Altura: +STR_2332 :Unidades +STR_2333 :Som +STR_2334 :Libras ({POUND}) +STR_2335 :Dolar ($) +STR_2336 :Franco (F) +STR_2337 :Deutschmark (DM) +STR_2338 :Yen ({YEN}) +STR_2339 :Peseta (Pts) +STR_2340 :Lira (L) +STR_2341 :Guilders (fl.) +STR_2342 :Krona (kr) +STR_2343 :Euros ({EURO}) +STR_2344 :Imperial +STR_2345 :Métrica +STR_2346 :Exibição +STR_2347 :{RED}{STRINGID} se afogou! +STR_2348 :{SMALLFONT}{BLACK}Mostrar as estatísticas para esse funcionário +STR_2349 :{WINDOW_COLOUR_2}Salário: {BLACK}{CURRENCY} por mês +STR_2350 :{WINDOW_COLOUR_2}Empregado em: {BLACK}{MONTHYEAR} +STR_2351 :{WINDOW_COLOUR_2}Gramados cortados: {BLACK}{COMMA16} +STR_2352 :{WINDOW_COLOUR_2}Jardins regados: {BLACK}{COMMA16} +STR_2353 :{WINDOW_COLOUR_2}Calçadas varridas: {BLACK}{COMMA16} +STR_2354 :{WINDOW_COLOUR_2}Lixeiras esvaziadas: {BLACK}{COMMA16} +STR_2355 :{WINDOW_COLOUR_2}Atrações consertadas: {BLACK}{COMMA16} +STR_2356 :{WINDOW_COLOUR_2}Atrações Inspecionadas: {BLACK}{COMMA16} +STR_2357 :Casa +STR_2358 :Unidades +STR_2359 :Valores Reais +STR_2360 :{WINDOW_COLOUR_2}Resolução de Tela: +STR_2361 :Landscape Smoothing +STR_2362 :{SMALLFONT}{BLACK}Toggle landscape tile edge smoothing on/off +STR_2363 :Gridlines on Landscape +STR_2364 :{SMALLFONT}{BLACK}Toggle gridlines on landscape on/off +STR_2365 :The bank refuses to increase your loan! +STR_2366 :Celsius ({DEGREE}C) +STR_2367 :Fahrenheit ({DEGREE}F) +STR_2368 :Nenhum +STR_2369 :Baixo +STR_2370 :Médio +STR_2371 :Alto +STR_2372 :Baixo +STR_2373 :Médio +STR_2374 :Alto +STR_2375 :Muito alto +STR_2376 :Extremo +STR_2377 :Ultra Extremo +STR_2378 :{SMALLFONT}{BLACK}Adjust smaller area of land +STR_2379 :{SMALLFONT}{BLACK}Adjust larger area of land +STR_2380 :{SMALLFONT}{BLACK}Adjust smaller area of water +STR_2381 :{SMALLFONT}{BLACK}Adjust larger area of water +STR_2382 :Terra +STR_2383 :Água +STR_2384 :{WINDOW_COLOUR_2}Seu objetivo: +STR_2385 :{BLACK}Nenhum +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! +STR_2389 :{BLACK}Build the best {STRINGID} you can! +STR_2390 :{BLACK}To have 10 different types of roller coasters operating in your park, each with an excitement value of at least 6.00 +STR_2391 :{BLACK}To have at least {COMMA16} guests in your park. You must not let the park rating drop below 700 at any time! +STR_2392 :{BLACK}To achieve a monthly income from ride tickets of at least {POP16}{POP16}{CURRENCY} +STR_2393 :{BLACK}To have 10 different types of roller coasters operating in your park, each with a minimum length of {LENGTH}, and an excitement rating of at least 7.00 +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 :Nenhum +STR_2398 :Number of guests at a given date +STR_2399 :Park value at a given date +STR_2400 :Have fun +STR_2401 :Build the best ride you can +STR_2402 :Build 10 roller coasters +STR_2403 :Number of guests in park +STR_2404 :Monthly income from ride tickets +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}Campanhas de marketing em operação +STR_2410 :{BLACK}Nenhum +STR_2411 :{WINDOW_COLOUR_2}Campanhas de marketing disponíveis +STR_2412 :{SMALLFONT}{BLACK}Comece esta campanha de marketing +STR_2413 :{BLACK}({CURRENCY2DP} por semana) +STR_2414 :(Não Selecionado) +STR_2415 :{WINDOW_COLOUR_2}Atração: +STR_2416 :{WINDOW_COLOUR_2}Item: +STR_2417 :{WINDOW_COLOUR_2}Período de tempo: +STR_2418 :Entrada gratuita para {STRINGID} +STR_2419 :Atração gratuita no {STRINGID} +STR_2420 :Meia-entrada para {STRINGID} +STR_2421 :Gratuito {STRINGID} +STR_2422 :Campanha publicitária para {STRINGID} +STR_2423 :Campanha publicitária para {STRINGID} +STR_2424 :{WINDOW_COLOUR_2}Cupões para entrada gratuita no parque +STR_2425 :{WINDOW_COLOUR_2}Cupões para entrada gratuitas em atrações em especial +STR_2426 :{WINDOW_COLOUR_2}Cupões para meia-entrada para o parque +STR_2427 :{WINDOW_COLOUR_2}Cupões para comida ou bebida de graça +STR_2428 :{WINDOW_COLOUR_2}Campanha publicitária para o parque +STR_2429 :{WINDOW_COLOUR_2}Campanha publicitária para uma atração em especial +STR_2430 :{BLACK}Cupões de entrada gratuita para {STRINGID} +STR_2431 :{BLACK}Cupões para entrada gratuita na atração {STRINGID} +STR_2432 :{BLACK}Cupões de meia-entrada para {STRINGID} +STR_2433 :{BLACK}Cupões de graça{STRINGID} +STR_2434 :{BLACK}Campanha publicitária para {STRINGID} +STR_2435 :{BLACK}Campanha publicitária para {STRINGID} +STR_2436 :1 semana +STR_2437 : +STR_2438 : +STR_2439 : +STR_2440 : +STR_2441 : +STR_2442 : +STR_2443 :{WINDOW_COLOUR_2}Custo por semana: {BLACK}{CURRENCY2DP} +STR_2444 :{WINDOW_COLOUR_2}Custo total: {BLACK}{CURRENCY2DP} +STR_2445 :Comece esta campanha de marketing +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 +STR_2452 :{WINDOW_COLOUR_2}Dinheiro (menos empréstimo): {BLACK}{CURRENCY2DP} +STR_2453 :{WINDOW_COLOUR_2}Dinheiro (menos empréstimo): {RED}{CURRENCY2DP} +STR_2454 :{SMALLFONT}{BLACK}{CURRENCY2DP} - +STR_2455 :{SMALLFONT}{BLACK}+{CURRENCY2DP} - +STR_2456 :{SMALLFONT}{BLACK}{CURRENCY2DP} - +STR_2457 :{SMALLFONT}{BLACK}Mostrar contas financeiras +STR_2458 :{SMALLFONT}{BLACK}Mostrar gráfico de dinheiro (menos de empréstimo) ao longo do tempo +STR_2459 :{SMALLFONT}{BLACK}Mostrar gráfico de valor parque ao longo do tempo +STR_2460 :{SMALLFONT}{BLACK}Mostrar gráfico de lucro semanal +STR_2461 :{SMALLFONT}{BLACK}Mostrar campanhas de marketing +STR_2462 :{SMALLFONT}{BLACK}Mostrar vista da entrada do parque +STR_2463 :{SMALLFONT}{BLACK}Mostrar gráfico de classificações do parque ao longo do tempo +STR_2464 :{SMALLFONT}{BLACK}Mostrar gráfico do número de visitantes ao longo do tempo +STR_2465 :{SMALLFONT}{BLACK}Mostrar preço de entradas no parque e informações +STR_2466 :{SMALLFONT}{BLACK}Mostrar estatísticas do parque +STR_2467 :{SMALLFONT}{BLACK}Mostrar objetivos para este jogo +STR_2468 :{SMALLFONT}{BLACK}Mostrar prêmios recentes que este parque recebeu +STR_2469 :{SMALLFONT}{BLACK}Escolha um nível de pesquisa e desenvolvimento +STR_2470 :{SMALLFONT}{BLACK}Pesquisar novas atrações de transporte +STR_2471 :{SMALLFONT}{BLACK}Pesquisar novas atrações Suaves/Calmas +STR_2472 :{SMALLFONT}{BLACK}Pesquisar novas montanhas-russas +STR_2473 :{SMALLFONT}{BLACK}Pesquisar novas atrações emocionantes +STR_2474 :{SMALLFONT}{BLACK}Pesquisar novas atrações aquáticas +STR_2475 :{SMALLFONT}{BLACK}Pesquisar novas lojas e barracas +STR_2476 :{SMALLFONT}{BLACK}Pesquisar novos cenários e tematizações +STR_2477 :{SMALLFONT}{BLACK}Selecione o modo de operação para esta atração +STR_2478 :{SMALLFONT}{BLACK}Show graph of velocity against time +STR_2479 :{SMALLFONT}{BLACK}Show graph of altitude against time +STR_2480 :{SMALLFONT}{BLACK}Show graph of vertical acceleration against time +STR_2481 :{SMALLFONT}{BLACK}Show graph of lateral acceleration against time +STR_2482 :{SMALLFONT}{BLACK}Profit: {CURRENCY} per week, Park Value: {CURRENCY} +STR_2483 :{WINDOW_COLOUR_2}Lucro semanal: {BLACK}+{CURRENCY2DP} +STR_2484 :{WINDOW_COLOUR_2}Lucro semanal: {RED}{CURRENCY2DP} +STR_2485 :Controles +STR_2486 :Geral +STR_2487 :Exibir nomes 'reais' para os visitantes +STR_2488 :{SMALLFONT}{BLACK}Alternar entre exibir nomes 'reais' para os visitantes e numeros de visitantes +STR_2489 :Teclas de atalho... +STR_2490 :Atalhos do teclado +STR_2491 :Redefinir teclas +STR_2492 :{SMALLFONT}{BLACK}Redefinir todos os atalhos de teclado para as configurações padrão +STR_2493 :Close top-most window +STR_2494 :Close all floating windows +STR_2495 :Cancel construction mode +STR_2496 :Pause game +STR_2497 :Zoom view out +STR_2498 :Zoom view in +STR_2499 :Rotate view clockwise +STR_2500 :Rotate construction object +STR_2501 :Underground view toggle +STR_2502 :Remove base land toggle +STR_2503 :Remove vertical land toggle +STR_2504 :See-through rides toggle +STR_2505 :See-through scenery toggle +STR_2506 :Invisible supports toggle +STR_2507 :Invisible people toggle +STR_2508 :Height marks on land toggle +STR_2509 :Height marks on ride tracks toggle +STR_2510 :Height marks on paths toggle +STR_2511 :Adjust land +STR_2512 :Adjust water +STR_2513 :Build scenery +STR_2514 :Build paths +STR_2515 :Build new ride +STR_2516 :Show financial information +STR_2517 :Show research information +STR_2518 :Show rides list +STR_2519 :Show park information +STR_2520 :Show guest list +STR_2521 :Show staff list +STR_2522 :Show recent messages +STR_2523 :Show map +STR_2524 :Screenshot +### The following need to be reordered to match SDL_keycode layout. +STR_2525 :??? +STR_2526 :??? +STR_2527 :??? +STR_2528 :??? +STR_2529 :??? +STR_2530 :??? +STR_2531 :??? +STR_2532 :??? +STR_2533 :Backspace +STR_2534 :Tab +STR_2535 :??? +STR_2536 :??? +STR_2537 :Clear +STR_2538 :Return +STR_2539 :??? +STR_2540 :??? +STR_2541 :??? +STR_2542 :??? +STR_2543 :Alt/Menu +STR_2544 :Pause +STR_2545 :Caps +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 :Spacebar +STR_2558 :PgUp +STR_2559 :PgDn +STR_2560 :End +STR_2561 :Home +STR_2562 :Left +STR_2563 :Up +STR_2564 :Right +STR_2565 :Down +STR_2566 :Select +STR_2567 :Print +STR_2568 :Execute +STR_2569 :Snapshot +STR_2570 :Insert +STR_2571 :Delete +STR_2572 :Help +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 :NumPad 0 +STR_2622 :NumPad 1 +STR_2623 :NumPad 2 +STR_2624 :NumPad 3 +STR_2625 :NumPad 4 +STR_2626 :NumPad 5 +STR_2627 :NumPad 6 +STR_2628 :NumPad 7 +STR_2629 :NumPad 8 +STR_2630 :NumPad 9 +STR_2631 :NumPad * +STR_2632 :NumPad + +STR_2633 :??? +STR_2634 :NumPad - +STR_2635 :NumPad . +STR_2636 :NumPad / +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 :NumLock +STR_2670 :Scroll +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 {CURRENCY} +STR_2682 : +STR_2683 : +STR_2684 :{SMALLFONT}{BLACK}Large group of peeps arrive +STR_2685 :Parâmetros de ruído simples +STR_2686 :{WINDOW_COLOUR_2}Baixo: +STR_2687 :{WINDOW_COLOUR_2}Alto: +STR_2688 :{WINDOW_COLOUR_2}Frequência base: +STR_2689 :{WINDOW_COLOUR_2}Oitavas: +STR_2690 :Gerador de Mapa +STR_2691 :{WINDOW_COLOUR_2}Altura da base: +STR_2692 :{WINDOW_COLOUR_2}Nível de água: +STR_2693 :{WINDOW_COLOUR_2}Terreno: +STR_2694 :Gerar +STR_2695 :Terreno aleatório +STR_2696 :Colocar árvores +STR_2697 :??? +STR_2698 :??? +STR_2699 :??? +STR_2700 :Salvamento automático: +STR_2701 :A cada minuto +STR_2702 :A cada 5 minutos +STR_2703 :A cada 15 minutos +STR_2704 :A cada 30 minutos +STR_2705 :A cada hora +STR_2706 :Nunca +STR_2707 :Abrir nova janela +STR_2708 :{WINDOW_COLOUR_1}Você tem certeza que quer sobrescrever {STRINGID}? +STR_2709 :Sobrescrever +STR_2710 :Tipo de nome para o arquivo. +STR_2711 :; +STR_2712 := +STR_2713 :, +STR_2714 :- +STR_2715 :. +STR_2716 :/ +STR_2717 :' +STR_2718 :(cima) +STR_2719 :(novo arquivo) +STR_2720 :{UINT16}seg +STR_2721 :{UINT16}segs +STR_2722 :{UINT16}min:{UINT16}seg +STR_2723 :{UINT16}min:{UINT16}segs +STR_2724 :{UINT16}mins:{UINT16}seg +STR_2725 :{UINT16}mins:{UINT16}segs +STR_2726 :{UINT16}min +STR_2727 :{UINT16}mins +STR_2728 :{UINT16}hora:{UINT16}min +STR_2729 :{UINT16}hora:{UINT16}mins +STR_2730 :{UINT16}horas:{UINT16}min +STR_2731 :{UINT16}horas:{UINT16}mins +STR_2732 :{COMMA16}ft +STR_2733 :{COMMA16}m +STR_2734 :{COMMA16}mph +STR_2735 :{COMMA16}km/h +STR_2736 :{MONTH}, Ano {COMMA16} +STR_2737 :{STRINGID} {MONTH}, Ano {COMMA16} +STR_2738 :Musíca da tela de início +STR_2739 :Nenhum +STR_2740 :RollerCoaster Tycoon 1 +STR_2741 :RollerCoaster Tycoon 2 +STR_2742 :css50.dat não encontrado +STR_2743 :Copie data\css17.dat da instalação do seu RCT1 para data\css50.dat na sua pasta de instalação do RCT2. +STR_2744 :[ +STR_2745 :\ +STR_2746 :] +STR_2747 :{ENDQUOTES} +STR_2748 :Bar +STR_2749 :Meu novo cenário +# New strings used in the cheats window previously these were ??? +STR_2750 :Mover todos os itens para o topo +STR_2751 :Mover todos os itens para baixo +STR_2752 :Limpar grama +STR_2753 :Cortar grama +STR_2754 :Regar plantas +STR_2755 :Consertar vandalismo +STR_2756 :Remover vomitos +STR_2757 :Forçar Sol +STR_2758 :Forçar Chuva +STR_2759 :Zero Clearance +STR_2760 :+{CURRENCY} +STR_2761 : +STR_2762 : +STR_2763 :??? +STR_2764 : +STR_2765 :Leva de Visitantes +STR_2766 :Ganhar cenário +STR_2767 :Congelar Clima +STR_2768 :Descongelar Clima +STR_2769 :Abrir o Parque +STR_2770 :Fechar o Parque +STR_2771 :Velocidade de Jogo mais lento +STR_2772 :Velocidade de Jogo mais rápido +STR_2773 :Janela +STR_2774 :Tela Inteira +STR_2775 :Tela Inteira (área de trabalho) +STR_2776 :Linguagem +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_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} +STR_2782 :SHIFT + +STR_2783 :CTRL + +STR_2784 :Mudar atalho do teclado +STR_2785 :{WINDOW_COLOUR_2}Press new shortcut key for:{NEWLINE}{OPENQUOTES}{STRINGID}{ENDQUOTES} +STR_2786 :{SMALLFONT}{BLACK}Click on shortcut description to select new key +STR_2787 :{WINDOW_COLOUR_2}Valor do parque: {BLACK}{CURRENCY} +STR_2788 :{WINDOW_COLOUR_2}Parabéns !{NEWLINE}{BLACK}Você alcançou seu objetivo com o valor da empresa de {CURRENCY} ! +STR_2789 :{WINDOW_COLOUR_2}Você falhou no seu objetivo ! +STR_2790 :Digite o nome do gráfico do cenário +STR_2791 :Digite o nome +STR_2792 :Por favor, insira o seu nome para o gráfico do cenário: +STR_2793 :{SMALLFONT}(Completado por {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_2796 :{SMALLFONT}{BLACK}Sort the ride list into order using the information type displayed +STR_2797 :Move a tela quando o ponteiro estiver na borda da tela +STR_2798 :{SMALLFONT}{BLACK}Selecione se deseja mover a tela quando o ponteiro do mouse estiver na borda da tela +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 :Mapa +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}Exibir o mapa do parque +STR_2806 :{RED}Guests are complaining about the disgusting state of the paths in your park{NEWLINE}Check where your handymen are and consider organising them better +STR_2807 :{RED}Guests are complaining about the amount of litter in your park{NEWLINE}Check where your handymen are and consider organising them better +STR_2808 :{RED}Guests are complaining about the vandalism in your park{NEWLINE}Check where your security guards are and consider organising 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 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}O maior prêmio de parque desarrumado +STR_2815 :{WINDOW_COLOUR_2}O maior prêmio de parque arrumado +STR_2816 :{WINDOW_COLOUR_2}Prêmio para o parque com as melhores montanhas-russas +STR_2817 :{WINDOW_COLOUR_2}Prêmio do parque com melhor valor +STR_2818 :{WINDOW_COLOUR_2}Prêmio do mais belo parque +STR_2819 :{WINDOW_COLOUR_2}Prêmio do parque com pior valor +STR_2820 :{WINDOW_COLOUR_2}Prêmio do parque mais seguro +STR_2821 :{WINDOW_COLOUR_2}Prêmio da melhor equipe +STR_2822 :{WINDOW_COLOUR_2}Prêmio da melhor comida de parque +STR_2823 :{WINDOW_COLOUR_2}Prêmio da pior comida de parque +STR_2824 :{WINDOW_COLOUR_2}Prêmio dos melhores banheiro de parque +STR_2825 :{WINDOW_COLOUR_2}Prêmio do parque mais decepcionante +STR_2826 :{WINDOW_COLOUR_2}Prêmio das melhores atrações aquáticas +STR_2827 :{WINDOW_COLOUR_2}Prêmio das melhores atrações customizadas +STR_2828 :{WINDOW_COLOUR_2}Prêmio do mais deslumbrante esquema de cor da atração +STR_2829 :{WINDOW_COLOUR_2}Prêmio do formato do parque mais confuso +STR_2830 :{WINDOW_COLOUR_2}Prêmio das melhores atrações suaves/calmas +STR_2831 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque mais desarrumado do país'! +STR_2832 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque mais arrumado do país'! +STR_2833 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque com as melhores montanhas-russas'! +STR_2834 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque com o melhor valor do país "! +STR_2835 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O mais belo parque do país'! +STR_2836 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque com o pior valor do país'! +STR_2837 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque mais seguro do país'! +STR_2838 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque com a melhor equipe'! +STR_2839 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque com a melhor comida do país'! +STR_2840 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque com a pior comida do país'! +STR_2841 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque com as melhores instalações sanitárias do país'! +STR_2842 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque mais decepcionante do país'! +STR_2843 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque com as melhores atrações aquáticas do país'! +STR_2844 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque com as melhores atrações customizadas'! +STR_2845 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque com a escolha de esquemas de cores mais deslumbrante'! +STR_2846 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque com o formato mais confuso'! +STR_2847 :{TOPAZ}Seu parque recebeu um prêmio por ser 'O parque com as melhores atrações suaves/calmas'! +STR_2848 :{WINDOW_COLOUR_2}Não há prêmios recentes +STR_2849 :New scenario installed successfully +STR_2850 :New track design installed successfully +STR_2851 :Scenario already installed +STR_2852 :Track design already installed +STR_2853 :Forbidden by the local authority! +STR_2854 :{RED}Guests can't get to the entrance of {STRINGID} !{NEWLINE}Construct a path to the entrance +STR_2855 :{RED}{STRINGID} has no path leading from its exit !{NEWLINE}Construct a path from the ride exit +STR_2856 :{WINDOW_COLOUR_2}Tutorial +STR_2857 :{WINDOW_COLOUR_2}(Press a key or mouse button to take control) +STR_2858 :Impossível começar uma campanha de marketing... +STR_2859 :Another instance of OpenRCT2 is already running +STR_2860 :Infogrames Interactive credits... +STR_2861 :{WINDOW_COLOUR_2}Licensed to Infogrames Interactive Inc. +STR_2862 :Music acknowledgements... +STR_2863 :Music acknowledgements +STR_2864 :{WINDOW_COLOUR_2}March - Children of the Regiment: (Fucik) non copyright +STR_2865 :{WINDOW_COLOUR_2}Heyken's Serenade: (J.Heyken) British Standard Music Coy; GEMA, BRITICO +STR_2866 :{WINDOW_COLOUR_2}In Continental Mood: (Composer unknown) Copyright Control +STR_2867 :{WINDOW_COLOUR_2}Wedding Journey: (Traditional) +STR_2868 :{WINDOW_COLOUR_2}Tales from the Vienna Woods: (Johann Strauss) non copyright +STR_2869 :{WINDOW_COLOUR_2}Slavonic Dance: (Traditional) +STR_2870 :{WINDOW_COLOUR_2}Das Alpenhorn: (Traditional) +STR_2871 :{WINDOW_COLOUR_2}The Blond Sailor: (Traditional) +STR_2872 :{WINDOW_COLOUR_2}Overture - Poet and Peasant: (Suppe) non copyright +STR_2873 :{WINDOW_COLOUR_2}Waltz Medley: (Johann Strauss) non copyright +STR_2874 :{WINDOW_COLOUR_2}Bella Bella Bimba: (Traditional) +STR_2875 :{WINDOW_COLOUR_2}Original recordings (P) 1976 C.J.Mears Organization, used with consent +STR_2876 :{WINDOW_COLOUR_2}RollerCoaster Tycoon 2 Title Music: (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, played by Peter James Adcock) recording {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}Senior Producer: Thomas J. Zahorik +STR_2910 :{WINDOW_COLOUR_2}Executive Producer: Bill Levay +STR_2911 :{WINDOW_COLOUR_2}Senior Marketing Product Manager: Scott Triola +STR_2912 :{WINDOW_COLOUR_2}V.P. of Product Development: Scott Walker +STR_2913 :{WINDOW_COLOUR_2}General Manager: John Hurlbut +STR_2914 :{WINDOW_COLOUR_2}Director of Quality Assurance: Michael Craighead +STR_2915 :{WINDOW_COLOUR_2}Q.A. Certification Manager: Kurt Boutin +STR_2916 :{WINDOW_COLOUR_2}Q.A. Certification Lead: Mark Huggins +STR_2917 :{WINDOW_COLOUR_2}Testers: Dena Irene Fitzgerald, Scott Rollins, Christopher McPhail +STR_2918 :{WINDOW_COLOUR_2}Clif McClure, Erik Maramaldi, Erik Jeffery +STR_2919 :{WINDOW_COLOUR_2}Director of Marketing: Ann Marie Bland +STR_2920 :{WINDOW_COLOUR_2}Manager of Creative Services: Steve Martin +STR_2921 :{WINDOW_COLOUR_2}Manager of Editorial & Documentation Services: Elizabeth Mackney +STR_2922 :{WINDOW_COLOUR_2}Graphic Designer: Paul Anselmi +STR_2923 :{WINDOW_COLOUR_2}Copywriter: Kurt Carlson +STR_2924 :{WINDOW_COLOUR_2}Special Thanks to: Peter Matiss +STR_2925 :{WINDOW_COLOUR_2}Engineering Specialist: Ken Edwards +STR_2926 :{WINDOW_COLOUR_2}Engineering Services Manager: Luis Rivas +STR_2927 :{WINDOW_COLOUR_2}Lead Compatibility Analyst: Geoffrey Smith +STR_2928 :{WINDOW_COLOUR_2}Compatibility Analysts: Jason Cordero, Burke McQuinn, Kim Jardin +STR_2929 :{WINDOW_COLOUR_2}Lead Tester: Daniel Frisoli +STR_2930 :{WINDOW_COLOUR_2}Senior Tester: 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 : +STR_2970 : +STR_2971 :Main colour scheme +STR_2972 :Alternative colour scheme 1 +STR_2973 :Alternative colour scheme 2 +STR_2974 :Alternative colour scheme 3 +STR_2975 :{SMALLFONT}{BLACK}Select which colour scheme to change, or paint ride with +STR_2976 :{SMALLFONT}{BLACK}Paint an individual area of this ride using the selected colour scheme +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_2982 :Banner text +STR_2983 :Enter new text for this banner: +STR_2984 :Can't set new text for banner... +STR_2985 :Banner +STR_2986 :{SMALLFONT}{BLACK}Change text on banner +STR_2987 :{SMALLFONT}{BLACK}Set this banner as a 'no-entry' sign for guests +STR_2988 :{SMALLFONT}{BLACK}Demolish this banner +STR_2989 :{SMALLFONT}{BLACK}Select main colour +STR_2990 :{SMALLFONT}{BLACK}Select text colour +STR_2991 :Sign +STR_2992 :Sign text +STR_2993 :Enter new text for this sign: +STR_2994 :{SMALLFONT}{BLACK}Change text on sign +STR_2995 :{SMALLFONT}{BLACK}Demolish this sign +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 :Unable to load file... +STR_3011 :File contains invalid data +STR_3012 :Dodgems beat style +STR_3013 :Fairground organ style +STR_3014 :Roman fanfare style +STR_3015 :Oriental style +STR_3016 :Martian style +STR_3017 :Jungle drums style +STR_3018 :Egyptian style +STR_3019 :Toyland style +STR_3020 : +STR_3021 :Space style +STR_3022 :Horror style +STR_3023 :Techno style +STR_3024 :Gentle style +STR_3025 :Summer style +STR_3026 :Water style +STR_3027 :Wild west style +STR_3028 :Jurassic style +STR_3029 :Rock style +STR_3030 :Ragtime style +STR_3031 :Fantasy style +STR_3032 :Rock style 2 +STR_3033 :Ice style +STR_3034 :Snow style +STR_3035 :Custom music 1 +STR_3036 :Custom music 2 +STR_3037 :Medieval style +STR_3038 :Urban style +STR_3039 :Organ style +STR_3040 :Mechanical style +STR_3041 :Modern style +STR_3042 :Pirates style +STR_3043 :Rock style 3 +STR_3044 :Candy style +STR_3045 :{SMALLFONT}{BLACK}Select style of music to play +STR_3046 :This ride cannot be modified +STR_3047 :Local authority forbids demolition or modifications to this ride +STR_3048 :Marketing campaigns forbidden by local authority +STR_3049 :Golf hole A +STR_3050 :Golf hole B +STR_3051 :Golf hole C +STR_3052 :Golf hole D +STR_3053 :Golf hole E +STR_3054 :Carregando... +STR_3055 :Branco +STR_3056 :Translúcido +STR_3057 :{WINDOW_COLOUR_2}Marcador de Construção: +STR_3058 :Brick walls +STR_3059 :Hedges +STR_3060 :Ice blocks +STR_3061 :Wooden fences +STR_3062 :{SMALLFONT}{BLACK}Standard roller coaster track +STR_3063 :{SMALLFONT}{BLACK}Water channel (track submerged) +STR_3064 :Beginner Parks +STR_3065 :Challenging Parks +STR_3066 :Expert Parks +STR_3067 :{OPENQUOTES}Real{ENDQUOTES} Parks +STR_3068 :Other Parks +STR_3069 :Top Section +STR_3070 :Slope to Level +STR_3071 :{WINDOW_COLOUR_2}Same price throughout park +STR_3072 :{SMALLFONT}{BLACK}Select whether this price is used throughout the entire park +STR_3073 :{RED}WARNING: Your park rating has dropped below 700 !{NEWLINE}If you haven't raised the park rating in 4 weeks, your park will be closed down +STR_3074 :{RED}WARNING: Your park rating is still below 700 !{NEWLINE}You have 3 weeks to raise the park rating +STR_3075 :{RED}WARNING: Your park rating is still below 700 !{NEWLINE}You have only 2 weeks to raise the park rating, or your park will be closed down +STR_3076 :{RED}FINAL WARNING: Your park rating is still below 700 !{NEWLINE}In just 7 days your park will be closed down unless you can raise the rating +STR_3077 :{RED}CLOSURE NOTICE: Your park has been closed down ! +STR_3078 :Plain entrance +STR_3079 :Wooden entrance +STR_3080 :Canvas tent entrance +STR_3081 :Castle entrance (grey) +STR_3082 :Castle entrance (brown) +STR_3083 :Jungle entrance +STR_3084 :Log cabin entrance +STR_3085 :Classical/Roman entrance +STR_3086 :Abstract entrance +STR_3087 :Snow/Ice entrance +STR_3088 :Pagoda entrance +STR_3089 :Space entrance +STR_3090 :{SMALLFONT}{BLACK}Select style of entrance, exit, and station +STR_3091 :You are not allowed to remove this section! +STR_3092 :You are not allowed to move or modify the station for this ride! +STR_3093 :{WINDOW_COLOUR_2}Favorito: {BLACK}{STRINGID} +STR_3094 :N/A +STR_3095 :{WINDOW_COLOUR_2}Lift hill chain speed: +STR_3096 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} +STR_3097 :{SMALLFONT}{BLACK}Select lift hill chain speed +STR_3098 :Can't change lift hill speed... +STR_3099 :{SMALLFONT}{BLACK}Select colour +STR_3100 :{SMALLFONT}{BLACK}Select second colour +STR_3101 :{SMALLFONT}{BLACK}Select third colour +STR_3102 :{SMALLFONT}{BLACK}Re-paint coloured scenery on landscape +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 :Fechar +STR_3108 :Testar +STR_3109 :Abrir +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 +STR_3113 :Select a different design +STR_3114 :{SMALLFONT}{BLACK}Go back to design selection window +STR_3115 :{SMALLFONT}{BLACK}Save track design +STR_3116 :{SMALLFONT}{BLACK}Save track design (Not possible until ride has been tested and statistics have been generated) +STR_3117 :{BLACK}Calling mechanic... +STR_3118 :{BLACK}{STRINGID} is heading for the ride +STR_3119 :{BLACK}{STRINGID} is fixing the ride +STR_3120 :{SMALLFONT}{BLACK}Locate nearest available mechanic, or mechanic fixing ride +STR_3121 :Unable to locate mechanic, or all nearby mechanics are busy +STR_3122 :{WINDOW_COLOUR_2}Favourite ride of: {BLACK}{COMMA16} guest +STR_3123 :{WINDOW_COLOUR_2}Favourite ride of: {BLACK}{COMMA16} guests +STR_3124 :Broken {STRINGID} +STR_3125 :{WINDOW_COLOUR_2}Excitement Factor: {BLACK}+{COMMA16}% +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_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) +STR_3135 :{RED}(Vehicle design unavailable - Ride performance may be affected) +STR_3136 :Warning: This design will be built with an alternative vehicle type and may not perform as expected +STR_3137 :Select Nearby Scenery +STR_3138 :Reset Selection +STR_3139 :Cable lift unable to work in this operating mode +STR_3140 :Cable lift hill must start immediately after station +STR_3141 :Multi-circuit per ride not possible with cable lift hill +STR_3142 :{WINDOW_COLOUR_2}Capacidade: {BLACK}{STRINGID} +STR_3143 :{SMALLFONT}{BLACK}Mostrar pessoa no mapa +STR_3144 :{SMALLFONT}{BLACK}Mostrar atrações e barracas no mapa +STR_3145 :{SMALLFONT}{BLACK}Scroll {STRINGID} esqueda +STR_3146 :{SMALLFONT}{BLACK}Scroll {STRINGID} direita +STR_3147 :{SMALLFONT}{BLACK}Scroll {STRINGID} esquerda rápido +STR_3148 :{SMALLFONT}{BLACK}Scroll {STRINGID} direita rápido +STR_3149 :{SMALLFONT}{BLACK}Scroll {STRINGID} esqueda/direita +STR_3150 :{SMALLFONT}{BLACK}Scroll {STRINGID} cima +STR_3151 :{SMALLFONT}{BLACK}Scroll {STRINGID} baixo +STR_3152 :{SMALLFONT}{BLACK}Scroll {STRINGID} cima rápido +STR_3153 :{SMALLFONT}{BLACK}Scroll {STRINGID} baixo rápido +STR_3154 :{SMALLFONT}{BLACK}Scroll {STRINGID} cima/baixo +STR_3155 : +STR_3156 : +STR_3157 :mapa +STR_3158 :gráfico +STR_3159 :lista +STR_3160 : +STR_3161 : +STR_3162 :Unable to allocate enough memory +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_3169 :Data for the following object not found: +STR_3170 :Not enough space for graphics +STR_3171 :Too many objects of this type selected +STR_3172 :The following object must be selected first: {STRING} +STR_3173 :This object is currently in use +STR_3174 :This object is required by another object +STR_3175 :This object is always required +STR_3176 :Unable to select this object +STR_3177 :Unable to de-select this object +STR_3178 :At least one path object must be selected +STR_3179 :At least one ride vehicle/attraction object must be selected +STR_3180 :Invalid selection of objects +STR_3181 :Object Selection - {STRINGID} +STR_3182 :Park entrance type must be selected +STR_3183 :Water type must be selected +STR_3184 :Ride Vehicles/Attractions +STR_3185 :Small Scenery +STR_3186 :Large Scenery +STR_3187 :Walls/Fences +STR_3188 :Path Signs +STR_3189 :Footpaths +STR_3190 :Path Extras +STR_3191 :Scenery Groups +STR_3192 :Park Entrance +STR_3193 :Water +STR_3194 :Scenario Description +STR_3195 :Invention List +STR_3196 :{WINDOW_COLOUR_2}Research Group: {BLACK}{STRINGID} +STR_3197 :{WINDOW_COLOUR_2}Items pre-invented at start of game: +STR_3198 :{WINDOW_COLOUR_2}Items to invent during game: +STR_3199 :Random Shuffle +STR_3200 :{SMALLFONT}{BLACK}Randomly shuffle the list of items to invent during the game +STR_3201 :Object Selection +STR_3202 :Landscape Editor +STR_3203 :Invention List Set Up +STR_3204 :Options Selection +STR_3205 :Objective Selection +STR_3206 :Save Scenario +STR_3207 :Roller Coaster Designer +STR_3208 :Track Designs Manager +STR_3209 :Back to Previous Step: +STR_3210 :Forward to Next Step: +STR_3211 :{WINDOW_COLOUR_2}Map size: +STR_3212 :{POP16}{COMMA16} x {PUSH16}{COMMA16} +STR_3213 :Can't decrease map size any further +STR_3214 :Can't increase map size any further +STR_3215 :Too close to edge of map +STR_3216 :{SMALLFONT}{BLACK}Select park-owned land etc. +STR_3217 :Land Owned +STR_3218 :Construction Rights Owned +STR_3219 :Land For Sale +STR_3220 :Construction Rights For Sale +STR_3221 :{SMALLFONT}{BLACK}Set land to be owned by the park +STR_3222 :{SMALLFONT}{BLACK}Set construction rights only to be owned by the park +STR_3223 :{SMALLFONT}{BLACK}Set land to be available to purchase by the park +STR_3224 :{SMALLFONT}{BLACK}Set construction rights to be available to purchase by the park +STR_3225 :{SMALLFONT}{BLACK}Toggle on/off building a random cluster of objects around the selected position +STR_3226 :{SMALLFONT}{BLACK}Build park entrance +STR_3227 :Too many park entrances! +STR_3228 :{SMALLFONT}{BLACK}Set starting positions for people +STR_3229 :Block Brakes cannot be used directly after station +STR_3230 :Block Brakes cannot be used directly after each other +STR_3231 :Block Brakes cannot be used directly after the top of this lift hill +STR_3232 :Options - Financial +STR_3233 :Options - Guests +STR_3234 :Options - Park +STR_3235 :{SMALLFONT}{BLACK}Show financial options +STR_3236 :{SMALLFONT}{BLACK}Show guest options +STR_3237 :{SMALLFONT}{BLACK}Show park options +STR_3238 :No Money +STR_3239 :{SMALLFONT}{BLACK}Make this park a 'no money' park with no financial restrictions +STR_3240 :{WINDOW_COLOUR_2}Dinheiro inicial: +STR_3241 :{WINDOW_COLOUR_2}Empréstimo inicial: +STR_3242 :{WINDOW_COLOUR_2}Maximum loan size: +STR_3243 :{WINDOW_COLOUR_2}Annual interest rate: +STR_3244 :Forbid marketing campaigns +STR_3245 :{SMALLFONT}{BLACK}Forbid advertising, promotional schemes, and other marketing campaigns +STR_3246 :{WINDOW_COLOUR_2}{CURRENCY} +STR_3247 :{WINDOW_COLOUR_2}{COMMA16}% +STR_3248 :Can't increase initial cash any further! +STR_3249 :Can't reduce initial cash any further! +STR_3250 :Can't increase initial loan any further! +STR_3251 :Can't reduce initial loan any further! +STR_3252 :Can't increase maximum loan size any further! +STR_3253 :Can't reduce maximum loan size any further! +STR_3254 :Can't increase interest rate any further! +STR_3255 :Can't reduce interest rate any further! +STR_3256 :Guests prefer less intense rides +STR_3257 :{SMALLFONT}{BLACK}Select whether guests should generally prefer less intense rides only +STR_3258 :Guests prefer more intense rides +STR_3259 :{SMALLFONT}{BLACK}Select whether guests should generally prefer more intense rides only +STR_3260 :{WINDOW_COLOUR_2}Cash per guest (average): +STR_3261 :{WINDOW_COLOUR_2}Guests initial happiness: +STR_3262 :{WINDOW_COLOUR_2}Guests initial hunger: +STR_3263 :{WINDOW_COLOUR_2}Guests initial thirst: +STR_3264 :Can't increase this any further! +STR_3265 :Can't reduce this any further! +STR_3266 :{SMALLFONT}{BLACK}Select how this park charges for entrance and rides +STR_3267 :Forbid tree removal +STR_3268 :{SMALLFONT}{BLACK}Forbid tall trees being removed +STR_3269 :Forbid landscape changes +STR_3270 :{SMALLFONT}{BLACK}Forbid any changes to the landscape +STR_3271 :Proibir construção alta +STR_3272 :{SMALLFONT}{BLACK}Proibir qualquer construção alta +STR_3273 :Classificação do parque com alto nível de dificuldade +STR_3274 :{SMALLFONT}{BLACK}Fazer p valor da classificação do parque mais desafiador +STR_3275 :Geração de visitantes com maior nível de dificuldade +STR_3276 :{SMALLFONT}{BLACK}Tornar mais difícil atrair clientes para o parque +STR_3277 :{WINDOW_COLOUR_2}Custo para comprar terreno: +STR_3278 :{WINDOW_COLOUR_2}Custo para comprar os direitos de construção: +STR_3279 :Entrada gratuita no parque / Pagamento por atrações +STR_3280 :Pague para entrar no Parque / Atrações gratuitas +STR_3281 :{WINDOW_COLOUR_2}Preço de entrada: +STR_3282 :{SMALLFONT}{BLACK}Selecione o objetivo e nome do parque +STR_3283 :{SMALLFONT}{BLACK}Selecione as atrações a serem preservadas +STR_3284 :Seleção de Objetivo +STR_3285 :Atrações Conservadas +STR_3286 :{SMALLFONT}{BLACK}Selecione o objetivo para este cenário +STR_3287 :{WINDOW_COLOUR_2}Objetivo: +STR_3288 :{SMALLFONT}{BLACK}Selecione o clima +STR_3289 :{WINDOW_COLOUR_2}Clima: +STR_3290 :Frio e úmido +STR_3291 :Morno +STR_3292 :Quente e seco +STR_3293 :Frio +STR_3294 :Mudar... +STR_3295 :{SMALLFONT}{BLACK}Change name of park +STR_3296 :{SMALLFONT}{BLACK}Change name of scenario +STR_3297 :{SMALLFONT}{BLACK}Change detail notes about park / scenario +STR_3298 :{WINDOW_COLOUR_2}Park Name: {BLACK}{STRINGID} +STR_3299 :{WINDOW_COLOUR_2}Park/Scenario Details: +STR_3300 :{WINDOW_COLOUR_2}Scenario Name: {BLACK}{STRINGID} +STR_3301 :{WINDOW_COLOUR_2}Objective Date: +STR_3302 :{WINDOW_COLOUR_2}{MONTHYEAR} +STR_3303 :{WINDOW_COLOUR_2}Numero de visitantes: +STR_3304 :{WINDOW_COLOUR_2}Valor do parque: +STR_3305 :{WINDOW_COLOUR_2}Monthly income: +STR_3306 :{WINDOW_COLOUR_2}Monthly profit: +STR_3307 :{WINDOW_COLOUR_2}Minimum length: +STR_3308 :{WINDOW_COLOUR_2}Excitement rating: +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 :Nome do Cenário +STR_3314 :Digite o nome para o cenário: +STR_3315 :Detalhes do Parque/Cenário +STR_3316 :Digite a descrição para o cenário: +STR_3317 :No details yet +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_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_3327 :Starting positions for people not set +STR_3328 :Can't advance to next editor stage... +STR_3329 :Park entrance not yet built +STR_3330 :Park must own some land +STR_3331 :Path from park entrance to map edge either not complete or too complex - Path must be single-width with as few junctions and corners as possible +STR_3332 :Park entrance is the wrong way round or has no path leading to the map edge +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 : +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_3341 :{SMALLFONT}{BLACK}Ferramentas de Jogo +STR_3342 :Editor de Cenário +STR_3343 :Converter Jogo Salvo em Cenário +STR_3344 :Designer de Montanha-Russa +STR_3345 :Gerenciamento de Designs de Pista +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 :Renomear +STR_3349 :Deletar +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 : +STR_3363 : +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}= Barraca de Comida +STR_3368 :{BLACK}= Barraca de Bebida +STR_3369 :{BLACK}= Barraca de Lembrança +STR_3370 :{BLACK}= Quiosque de Informação +STR_3371 :{BLACK}= Primeiros Socorros +STR_3372 :{BLACK}= Caixa Eletrônico +STR_3373 :{BLACK}= Banheiro +STR_3374 :Aviso: Muitos objetos selecionados! +STR_3375 :Nem todos os objetos neste grupo de cenário podem ser selecionado +STR_3376 :Instalar um novo projeto de pista... +STR_3377 :{SMALLFONT}{BLACK}Instalar um novo arquivo de projeto de pista +STR_3378 :Instalar +STR_3379 :Cancelar +STR_3380 :Impossível instalar este projeto de pista... +STR_3381 :O arquivo não é compatível ou contém dados inválidos +STR_3382 :Cópia de arquivo falhou +STR_3383 :Selecione um novo nome para o projeto da pista +STR_3384 :An existing track design already has this name - Please select a new name for this design: +STR_3385 :Tutorial Iniciante +STR_3386 :Tutorial de Atrações Customizadas +STR_3387 :Tutorial de construção de Montanha-Russas +STR_3388 :Impossível alterar para o modo selecionado +STR_3389 :Impossível selecionar o item adicional de cenário... +STR_3390 :Muitos itens selecionados +# Start of tutorial strings. Not used at the moment, so not necessary to translate. +STR_3391 :{SMALLFONT}{BLACK}Here is our park - Let's have a quick look around... +STR_3392 :{SMALLFONT}{BLACK}Holding down the RIGHT mouse button and moving the mouse is the quickest way to move the view... +STR_3393 :{SMALLFONT}{BLACK}To view more of the park, you can zoom the view out using the icon at the top of the screen... +STR_3394 :{SMALLFONT}{BLACK}You can also rotate the view in 90 degree steps... +STR_3395 :{SMALLFONT}{BLACK}Building anything at this scale is a bit difficult, so let's zoom the view back in again... +STR_3396 :{SMALLFONT}{BLACK}Let's build a simple ride to get the park started... +STR_3397 :{SMALLFONT}{BLACK}The white 'ghost' image shows where the ride will be built. We'll move the pointer to select the position then click to build it... +STR_3398 :{SMALLFONT}{BLACK}Rides need an entrance and an exit. We'll move the pointer to a square on the edge of the ride and then click to build first the entrance and then the exit... +STR_3399 :{SMALLFONT}{BLACK}We need to build footpaths to allow guests to reach our new ride... +STR_3400 :{SMALLFONT}{BLACK}For the path to the ride entrance we'll use a special 'queue line' path... +STR_3401 :{SMALLFONT}{BLACK}For the exit path, just an 'ordinary' path will do... +STR_3402 :{SMALLFONT}{BLACK}Right, lets open the ride! To open the ride we click the flag icon on the ride window and select 'open'... +STR_3403 :{SMALLFONT}{BLACK}But where are the guests? +STR_3404 :{SMALLFONT}{BLACK}Oh - The park is still closed! Right - Let's open it... +STR_3405 :{SMALLFONT}{BLACK}While we're waiting for our first guests, let's build some scenery... +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 customise the ride a bit... +# End of tutorial strings +STR_3437 :{SMALLFONT}{BLACK}Clear large areas of scenery from landscape +STR_3438 :Impossível remover todos os cenários a partir daqui... +STR_3439 :Limpar Cenário +STR_3440 :Página 1 +STR_3441 :Página 2 +STR_3442 :Página 3 +STR_3443 :Página 4 +STR_3444 :Página 5 +STR_3445 :Definir a Área de Patrulha +STR_3446 :Cancelar a Área de Patrulha +# New strings, cleaner +STR_5120 :Finanças +STR_5121 :Pesquisas +STR_5122 :Select rides by track type (like in RCT1) +STR_5123 :Renovar atrações +STR_5124 : +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 :Consertar todas as atrações +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 :Trapaças +STR_5148 :{SMALLFONT}{BLACK}Change the game speed +STR_5149 :{SMALLFONT}{BLACK}Exibir opções de trapaça +STR_5150 :Habilitar ferramentas de depuração +STR_5151 :, +STR_5152 :. +STR_5153 :Editar Temas... +STR_5154 :Exibição por Hardware +STR_5155 :Permitir o teste de atrações incompletas +STR_5156 :{SMALLFONT}{BLACK}Permite testar a maioria dos tipos de atrações, mesmo quando a atração está inacabada, não se aplica bloquear os modos seccionados +STR_5157 :Unlock all prices +STR_5158 :Sair para o menu +STR_5159 :Sair do OpenRCT2 +STR_5160 :{POP16}{MONTH} {PUSH16}{PUSH16}{STRINGID}, Ano {POP16}{COMMA16} +STR_5161 :Formato da Data: +STR_5162 :Dia/Mês/Ano +STR_5163 :Mês/Dia/Ano +STR_5164 :Nome do canal do Twitch +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 :Habilita integração com Twitch +STR_5177 :Modo tela inteira: +STR_5178 :{SMALLFONT}{BLACK}Mostrar trapaças financeiras +STR_5179 :{SMALLFONT}{BLACK}Mostrar trapaças de visitantes +STR_5180 :{SMALLFONT}{BLACK}Mostrar trapaças do parque +STR_5181 :{SMALLFONT}{BLACK}Mostrar trapaças das atrações +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 :Finanças +STR_5188 :Nova Campanha +STR_5189 :Pesquisa +STR_5190 :Mapa +STR_5191 :Viewport +STR_5192 :Recent News +STR_5193 :Land +STR_5194 :Água +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 :Create +STR_5255 :{SMALLFONT}{BLACK}Create a new title sequence from scratch +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 and interface +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 :Claro +STR_5278 :Modo sandbox ativado +STR_5279 :Modo sandbox desativado +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 :EXPLODIR!! +STR_5286 :{SMALLFONT}{BLACK}Explodir alguns visitantes +STR_5287 :Atração já está quebrada +STR_5288 :Atração está fechada +STR_5289 :Indisponível quebra para essa atração +STR_5290 :Consertar atração +STR_5291 :Impossível forçar quebra +STR_5292 :{SMALLFONT}{BLACK}Forçar quebra +STR_5293 :{SMALLFONT}{BLACK}Fechar atração +STR_5294 :{SMALLFONT}{BLACK}Testar atração +STR_5295 :{SMALLFONT}{BLACK}Abrir atração +STR_5296 :{SMALLFONT}{BLACK}Fechar parque +STR_5297 :{SMALLFONT}{BLACK}Abrir parque +STR_5298 :{RED}{STRINGID} +STR_5299 :{LIGHTPINK}{STRINGID} +STR_5300 :{SMALLFONT}{BLACK}Quick fire staff +STR_5301 :{MEDIUMFONT}{BLACK}Limpar seu empréstimo +STR_5302 :Limpar empréstimo +STR_5303 :Allow building in pause mode +STR_5304 :Sequencia de Títulos: +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 :Aleatório +STR_5311 :{SMALLFONT}{BLACK}Ferramentas de depuração +STR_5312 :Exibir console +STR_5313 :Exibir inspetor de título +STR_5314 :Inspetor de título +STR_5315 :Grama +STR_5316 :Areia +STR_5317 :Sujeira +STR_5318 :Pedra +STR_5319 :Marciano +STR_5320 :Tabuleiro de damas +STR_5321 :Tufos de grama +STR_5322 :Gelo +STR_5323 :Grade (vermelho) +STR_5324 :Grade (amarelo) +STR_5325 :Grade (azul) +STR_5326 :Grade (verde) +STR_5327 :Areia (escura) +STR_5328 :Areia (clara) +STR_5329 :Tabuleiro de damas (Invertido) +STR_5330 :Visão subterrânea +STR_5331 :Pedra +STR_5332 :Madeira (vermelha) +STR_5333 :Madeira (preta) +STR_5334 :Gelo +STR_5335 :Entrada da atração +STR_5336 :Saida da atração +STR_5337 :Entrada do parque +STR_5338 :Tipo de elemento +STR_5339 :Altura da base +STR_5340 :Altura de passagem +STR_5341 :Bandeiras +STR_5342 :Escolha o titulo do mapa +STR_5343 :Colocar automaticamente funcionários +STR_5344 :Log de mudanças +STR_5345 :Trapaça financeira +STR_5346 :Trapaça do visitante +STR_5347 :Trapaça da atração +STR_5348 :Trapaça do parque +STR_5349 :{SMALLFONT}{BLACK}Todas as Atrações +STR_5350 :Max +STR_5351 :Min +STR_5352 :{BLACK}Felicidade: +STR_5353 :{BLACK}Energia: +STR_5354 :{BLACK}Fome: +STR_5355 :{BLACK}Sede: +STR_5356 :{BLACK}Náusea: +STR_5357 :{BLACK}Tolerância a náusea +STR_5358 :{BLACK}Banheiro: +STR_5359 :Remove os visitantes +STR_5360 :{SMALLFONT}{BLACK}Remove todos os visitantes do mapa +STR_5361 :{BLACK}De a todos os visitantes: +STR_5362 :{BLACK}Intensidade preferida: +STR_5363 :Maior que 1 +STR_5364 :Menor que 15 +STR_5365 :{BLACK}Vel. dos funcionários: +STR_5366 :Normal +STR_5367 :Rápido +STR_5368 :Redefinir o status de acidente +STR_5369 :Parâmetros do parque... +STR_5370 :{SMALLFONT}{BLACK}Clique nesse botão para modificar os parâmetros {NEWLINE}do parque com restrições,{NEWLINE}geração de visitantes e dinheiro. +STR_5371 :Object Selection +STR_5372 :Inverter seleção do botão direito do mouse +STR_5373 :Nome {STRINGID} +STR_5374 :Data {STRINGID} +STR_5375 :{UP} +STR_5376 :{DOWN} +STR_5377 :{SMALLFONT}{BLACK}Saves +STR_5378 :{SMALLFONT}{BLACK}Script +STR_5379 :{SMALLFONT}{BLACK}Skip to next wait command +STR_5380 :{SMALLFONT}{BLACK}Start playing title sequence +STR_5381 :{SMALLFONT}{BLACK}Stop playing title sequence +STR_5382 :{SMALLFONT}{BLACK}Restart title sequence +STR_5383 :{SMALLFONT}{BLACK}Create a new title sequence based on the current one +STR_5384 :{SMALLFONT}{BLACK}Delete the current title sequence +STR_5385 :{SMALLFONT}{BLACK}Rename the current title sequence +STR_5386 :{SMALLFONT}{BLACK}Insert a new command +STR_5387 :{SMALLFONT}{BLACK}Edit the selected command +STR_5388 :{SMALLFONT}{BLACK}Delete the selected command +STR_5389 :{SMALLFONT}{BLACK}Skip to the selected command in the title sequence +STR_5390 :{SMALLFONT}{BLACK}Move the selected command down +STR_5391 :{SMALLFONT}{BLACK}Move the selected command up +STR_5392 :{SMALLFONT}{BLACK}Add a save to the title sequence +STR_5393 :{SMALLFONT}{BLACK}Remove the selected save from the title sequence +STR_5394 :{SMALLFONT}{BLACK}Rename the selected save +STR_5395 :{SMALLFONT}{BLACK}Load the selected save in game +STR_5396 :{SMALLFONT}{BLACK}Reload the title sequence if changes have been made to it outside of the game +STR_5397 :Can only be used on the title screen +STR_5398 :Cannot edit title sequence while it's playing +STR_5399 :Press the stop button to continue editing +STR_5400 :Impossível alterar esta sequência de título +STR_5401 :Criar uma nova sequência de título para fazer alterações para +STR_5402 :Falha ao carregar a sequência do título +STR_5403 :Não pode haver nenhuma carga, comando de espera ou uma gravação pode ser inválida +STR_5404 :Este nome já existe +STR_5405 :Insira um nome para o salvar +STR_5406 :Insira um nome para a sequência de título +STR_5407 :Adicionar +STR_5408 :Remoder +STR_5409 :Inserir +STR_5410 :Editar +STR_5411 :Recarregar +STR_5412 :Ir para +STR_5413 :Carregar +STR_5414 :Carregar{MOVE_X}{87}Six Flags Magic Mountain.SC6 +STR_5415 :Carregar{MOVE_X}{87}{STRING} +STR_5416 :Carregar{MOVE_X}{87}Salvar não selecionado +STR_5417 :localização +STR_5418 :Localização{MOVE_X}{87}{COMMA16} {COMMA16} +STR_5419 :Rotacionar +STR_5420 :Rotacionar{MOVE_X}{87}{COMMA16} +STR_5421 :Ampliar +STR_5422 :Ampliar{MOVE_X}{87}{COMMA16} +STR_5423 :Aguarde +STR_5424 :Wait{MOVE_X}{87}{COMMA16} +STR_5425 :Reiniciar +STR_5426 :Fim +STR_5427 :Cordenadas: +STR_5428 :Rotações anti-horário: +STR_5429 :Nível de ampliação: +STR_5430 :Segundos de espera: +STR_5431 :Salvar para carregar: +STR_5432 :Comando: +STR_5433 :Sequências de título +STR_5434 :Command Editor +STR_5435 :Rename save +STR_5436 :Editar a sequência de título... +STR_5437 :Salvar não selecionado +STR_5438 :Impossível fazer mudanças enquanto editor de comando está aberto +STR_5439 :Um comando de espera com pelo menos 4 segundos é necessário com um comando de reinicialização +STR_5440 :Minimizar tela inteira quando perder o faco +STR_5441 :{SMALLFONT}{BLACK}Identificar as atrações por tipo de pista,{NEWLINE}assim os veículos podem ser alterados {NEWLINE}depois, como no RCT1. +STR_5442 :Forças a classificação do parque: +STR_5443 :Velocidade{MOVE_X}{87}{STRINGID} +STR_5444 :Velocidade: +STR_5445 :Velocidade +STR_5446 :Conseguir +STR_5447 :Tipo {STRINGID} +STR_5448 :Atração / Veículo {STRINGID} +STR_5449 :Reduzir a velocidade do jogo +STR_5450 :Aumentar a velocidade do jogo +STR_5451 :Abrir janela de trapaças +STR_5452 :Alternar a visibilidade da barra de ferramentas +STR_5453 :Selecione outra atração +STR_5454 :Remover limite de FPS +STR_5455 :Ativar o modo sandbox +STR_5456 :Desabilitar as verificações de depuração +STR_5457 :Desativar limites de apoio +STR_5458 :Rotacionar no sentido horário +STR_5459 :Rotacionar anti-horário +STR_5460 :Rotacionar visão sentido anti-horário +STR_5461 :Definir parâmetros dos visitantes +STR_5462 :{CURRENCY} +STR_5463 :Objetivo: Divirta-se! +STR_5464 :Geral +STR_5465 :Clima +STR_5466 :Funcionários +STR_5467 :ALT + +STR_5468 :Mensagens recentes +STR_5469 :Desloca mapa para cima +STR_5470 :Desloca mapa para esquerda +STR_5471 :Desloca mapa para baixo +STR_5472 :Desloca mapa para direita +STR_5473 :Ciclo dia / noite +STR_5474 :Exibie texto nos banners em letras maiúsculas +STR_5475 :{COMMA16} semanas +STR_5476 :Hardware +STR_5477 :Renderização do mapa +STR_5478 :Controles +STR_5479 :Barra de Ferramentas +STR_5480 :Mostrar os botões da barra de ferramentas para: +STR_5481 :Temas +STR_5482 :{WINDOW_COLOUR_2}Tempo desde a última inspeção: {BLACK}1 minuto +STR_5483 :{BLACK}({COMMA16} semanas restantes) +STR_5484 :{BLACK}({COMMA16} semana restante) +STR_5485 :{SMALLFONT}{STRING} +STR_5486 :{BLACK}{COMMA16} +STR_5487 :{SMALLFONT}{BLACK}Exibir as mensagens recentes +STR_5488 :Entrada proibida +STR_5489 :{SMALLFONT}{BLACK}Mostrar apenas os visitantes monitorados +STR_5490 :Desativar som quando perder o foco +STR_5491 :Lista de Invenções +STR_5492 :Opções de cenário +STR_5493 :Enviar Mensagem +STR_5494 : +STR_5495 :Lista de Jogadores +STR_5496 :Jogador: +STR_5497 :Ping: +STR_5498 :Lista de Servidores +STR_5499 :Nome do Jogador: +STR_5500 :Adic. Servidor +STR_5501 :Iniciar Servidor +STR_5502 :Multijogador +STR_5503 :Digite o nome do servidor ou o endereço de IP: +STR_5504 :{SMALLFONT}{BLACK}Exibir o estado do multijogador +STR_5505 :Impossível se conectar ao servidor. +STR_5506 :Os Visistantes ignoram as intensidades +STR_5507 :Faz-Tudo corta a grama por padrão +STR_5508 :Carregamento de arquivos com checksums incorreto +STR_5509 :{SMALLFONT}{BLACK}Permitir o carregamento de cenários e jogos salvos que possuam checksum incorreto, como os cenários do demo e jogos salvos danificados. +STR_5510 :Dispositivo de som padrão +STR_5511 :(DESCONHECIDO) +STR_5512 :Salvar Jogo Como +STR_5513 :(Rapido) salvar jogo +STR_5514 :Desativar vandalismo +STR_5515 :{SMALLFONT}{BLACK}Parar o vandalismo dos visitantes no seu parque quando eles estão com raiva +STR_5516 :{SMALLFONT}{BLACK}Preto +STR_5517 :{SMALLFONT}{BLACK}Cinza +STR_5518 :{SMALLFONT}{BLACK}Branco +STR_5519 :{SMALLFONT}{BLACK}Roxo escuro +STR_5520 :{SMALLFONT}{BLACK}Roxo claro +STR_5521 :{SMALLFONT}{BLACK}Roxo brilhante +STR_5522 :{SMALLFONT}{BLACK}Azul escuro +STR_5523 :{SMALLFONT}{BLACK}Azul claro +STR_5524 :{SMALLFONT}{BLACK}Azul Gelo +STR_5525 :{SMALLFONT}{BLACK}Azul esverdeado +STR_5526 :{SMALLFONT}{BLACK}Turquesa +STR_5527 :{SMALLFONT}{BLACK}Verde saturado +STR_5528 :{SMALLFONT}{BLACK}Verde escuro +STR_5529 :{SMALLFONT}{BLACK}Moss green +STR_5530 :{SMALLFONT}{BLACK}Bright green +STR_5531 :{SMALLFONT}{BLACK}Olive green +STR_5532 :{SMALLFONT}{BLACK}Verde oliva escuro +STR_5533 :{SMALLFONT}{BLACK}Amarelo brilhante +STR_5534 :{SMALLFONT}{BLACK}Amarelo +STR_5535 :{SMALLFONT}{BLACK}Amarelo escuro +STR_5536 :{SMALLFONT}{BLACK}Laranja claro +STR_5537 :{SMALLFONT}{BLACK}Laranja escuro +STR_5538 :{SMALLFONT}{BLACK}Marrrom claro +STR_5539 :{SMALLFONT}{BLACK}Marrom saturado +STR_5540 :{SMALLFONT}{BLACK}Marrom escuro +STR_5541 :{SMALLFONT}{BLACK}Salmão +STR_5542 :{SMALLFONT}{BLACK}Vermelho vinho +STR_5543 :{SMALLFONT}{BLACK}Vermelho saturado +STR_5544 :{SMALLFONT}{BLACK}Vermelho brilhante +STR_5545 :{SMALLFONT}{BLACK}Rosa escuro +STR_5546 :{SMALLFONT}{BLACK}Rosa brilhante +STR_5547 :{SMALLFONT}{BLACK}Rosa claro +STR_5548 :Exibir todos os modos operacionais +STR_5549 :Ano/Mês/Dia +STR_5550 :{POP16}{POP16}Ano {COMMA16}, {PUSH16}{PUSH16}{MONTH} {PUSH16}{PUSH16}{STRINGID} +STR_5551 :Ano/Mês/Dia +STR_5552 :{POP16}{POP16}Ano {COMMA16}, {PUSH16}{PUSH16}{PUSH16}{STRINGID} {MONTH} +STR_5553 :Pausar o jogo quando a Steam estiver aberta sobrepondo +STR_5554 :{SMALLFONT}{BLACK}Habilitar ferramenta de montanha +STR_5555 :Exibir veiculos de outros tipos de atrações +STR_5556 :Remover Jogador +STR_5557 :Manter conectado após dessincronização (Multijogador) + +##################### +# Rides/attractions # +##################### + +#WW +[CONDORRD] +STR_NAME :Condor +STR_DESC :Montando em arreios especiais sob a pista, os passageiros experimentarão a sensação de voar pelo ar em uma estrutura na forma de Condor +STR_CPTY :4 passageiros por carro \ No newline at end of file diff --git a/data/language/russian.txt b/data/language/russian.txt new file mode 100644 index 0000000000..d731aec1e8 --- /dev/null +++ b/data/language/russian.txt @@ -0,0 +1,3463 @@ +# 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 :Спиральные горки +STR_0003 :Стоячие горки +STR_0004 :Подвесные раскачивающиеся горки +STR_0005 :Обратные горки +STR_0006 :Детские горки +STR_0007 :Миниатюрная железная дорога +STR_0008 :Монорельс +STR_0009 :Мини стоячие горки +STR_0010 :Заезд на лодках +STR_0011 :Деревянная дикая мышь +STR_0012 :Steeplechase +STR_0013 :Заезд на машиинах +STR_0014 :Запуск в свободное подение +STR_0015 :Бобслей +STR_0016 :Смотровая башня +STR_0017 :Петляющие горки +STR_0018 :Скольжение в шлюпке +STR_0019 :Горки в шахте +STR_0020 :Кресельный лифт +STR_0021 :Штопорные горки +STR_0022 :Лабиринт +STR_0023 :Спуск по спирали +STR_0024 :Гонки +STR_0025 :Сплав на бревне +STR_0026 :Речные пороги +STR_0027 :Автодром +STR_0028 :Пиратский корабль +STR_0029 :Раскачивающийся инвертированный корабль +STR_0030 :Киоск с едой +STR_0031 :Неизвестный киоск (1D) +STR_0032 :Киоск с питьём +STR_0033 :Неизвестный киоск (1F) +STR_0034 :Магазинчик +STR_0035 :Карусель +STR_0036 :Неизвестный киоск (22) +STR_0037 :Информационный стенд +STR_0038 :Туалеты +STR_0039 :Колесо обозрения +STR_0040 :Симулятор движения +STR_0041 :3D Кинотеатр +STR_0042 :Top Spin +STR_0043 :Космические кольца +STR_0044 :Обратное подение +STR_0045 :Лифт +STR_0046 :Vertical Drop Roller Coaster +STR_0047 :Банкомат +STR_0048 :Раскрутка +STR_0049 :Дом с привидениями +STR_0050 :Палатка первой помощи +STR_0051 :Цирковое представление +STR_0052 :Призрачный поезд +STR_0053 :Стальные извивающиеся горки +STR_0054 :Деревянные горки +STR_0055 :Side-Friction Roller Coaster +STR_0056 :Дикая мышь +STR_0057 :Мультипространственные горки +STR_0058 :Неизвестный атракцион (38) +STR_0059 :Парящие горки +STR_0060 :Неизвестный атракцион (3A) +STR_0061 :Virginia Reel +STR_0062 :Лодки с брызгами +STR_0063 :Мини-вертолётики +STR_0064 :Лежачие горки +STR_0065 :Подвесной монорельс +STR_0066 :Неизвестный атракцион (40) +STR_0067 :Обратные горки +STR_0068 :Кардиограмные переплетёные горки +STR_0069 :Мини-гольф +STR_0070 :Огромные горки +STR_0071 :Roto-Drop +STR_0072 :Летающие блюдца +STR_0073 :Дом кривых зеркал +STR_0074 :Монорельсовые велосипеды +STR_0075 :Компактные инвертированые горки +STR_0076 :Водные горки +STR_0077 :Вертикальные горки на воздушной тяги +STR_0078 :Inverted Hairpin Coaster +STR_0079 :Ковёр-самолёт +STR_0080 :Заплыв на подводной лодке +STR_0081 :Речной рафтинг +STR_0082 :Неизвесный атракцион (50) +STR_0083 :Центрефуга +STR_0084 :Неизвестный атракцион (52) +STR_0085 :Неизвестный атракцион (53) +STR_0086 :Неизвестный атракцион (54) +STR_0087 :Неизвестный атракцион (55) +STR_0088 :Инвертированые импульсовые горки +STR_0089 :Мини-горки +STR_0090 :Шахтёрская поездка +STR_0091 :Неизвестный атракцион (59) +STR_0092 :ЛИМ запускающие горки +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 :Дно вагонеток раскачивается по пути, прыжимаясь к сторонам на поворотах. +STR_0515 :Стальные горки с вагонетками, которые прикриплены к треку, с множеством сложных и закрученых элементов. +STR_0516 :Мягкие горки для людей, которых ещё не хватает духа, чтобы столкнутся с большими заездами. +STR_0517 :Пассажиры едут в поездах по узко-калиберной железной дороге. +STR_0518 :Пассажиры путишествуют в электрических поездах по морельсовой дороге. +STR_0519 :Пассажиры едут в меленьких машинках, удерживающихся за одно-рельсовую дорогу, свободно раскачиваясь из стороны в сторону около поворотов. +STR_0520 :Причал, где гости могут кататься/грести на личных водных судах по водному пространству. +STR_0521 :Быстрые и закрученые горки, с жёсткими поворотами и крутыми выпадами. Обязательно высокая интенсивновсть. +STR_0522 :Небольшие горки, где посетители сидят над путями без вагонетонетки около них. +STR_0523 :Пассажири неспеша путишествуют в электро-мобилях по маршруту, основаному на треке. +STR_0524 :Капсула свободного падения пневматически запускается вверх по высокой стальной башне и потом переходит в свободное подение. +STR_0525 :Пассажиры быстро движутся вниз по закрученому пути, направляемые только кривизной и виражами полу-круглого трека. +STR_0526 :Пассажиры поднимаются во вращающейся кабине для обозрения, которая поднимается по высокой башне. +STR_0527 :Плавные стальные горки с мёртвыми петлями. +STR_0528 :Пассажири сплавляются на надувныъ шлюпках по извилистому полу-круглому треку, или по полностью закрытой трубе. +STR_0529 :Стилизованые под шахтёрские вагонетки вогончики быстро едут по стальным горкам, который выглядит, как старая железная дорога. +STR_0530 :Прикреплённые вагонетки к стальному кабелю, которые едут из одного конца трассы к другому, и обратно. +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 :Разогнемая на станции вагонетка движется по длинно-уровневому пути, используюя линейный индукционный двигатель, после чего, устримляется прямиком вверх по вертикальному стержню, свободно падая обратно вниз, чтобы вернуться на станцию. +STR_0555 :Посетители катаются на лифте вверх, ли вниз по вертикальной башне, чтобы попасть с одного этажа на другой. +STR_0556 :Экстро-широкие вагонетки опускаются по совершенно вертикально-наклонённому пути, для максимального испытывания свободного падения. +STR_0557 : +STR_0558 : +STR_0559 : +STR_0560 : +STR_0561 : +STR_0562 :Самоходные вагончики едут по мульти-уровневому пути, проезжая страшные декорации и специальные эффекты. +STR_0563 :Сидя в комфортных вагончиках, только с простыми поручнями, пассажиры наслаждаются большими мягкими выподами и извилистым путём, так же часто, как и "временем в воздухе" на возвышенностях. +STR_0564 :Бегущий по деревянному пути, этот атракцион быстр, жёсткий, шумный и дающие ощущение неуправляемой поездки с большм количеством "времени в воздухе". +STR_0565 :A simple wooden roller coaster capable of only gentle slopes and turns, where the cars are only kept on the track by side friction wheels and gravity +STR_0566 :Individual roller coaster cars zip around a tight zig-zag layout of track with sharp corners and short sharp drops +STR_0567 :Sitting in seats suspended either side of the track, riders are pitched head-over-heels while they plunge down steep drops and travel through various inversions +STR_0568 : +STR_0569 :Riding in special harnesses below the track, riders experience the feeling of flight as they swoop through the air +STR_0570 : +STR_0571 :Circular cars spin around as they travel along the zig-zagging wooden track +STR_0572 :Large capacity boats travel along a wide water channel, propelled up slopes by a conveyer belt, accelerating down steep slopes to soak the riders with a gaint splash +STR_0573 :Powered helicoper shaped cars running on a steel track, controlled by the pedalling of the riders +STR_0574 :Riders are held in special harnesses in a lying-down position, travlling through twisted track and inversions either on their backs or facing the ground +STR_0575 :Powered trains hanging from a single rail transport people around the park +STR_0576 : +STR_0577 :Bogied cars run on wooden tracks, turning around on special reversing sections +STR_0578 :Cars run along track enclosed by circular hoops, traversing steep drops and heartline twists +STR_0579 : +STR_0580 :A giant steel roller coaster capable of smooth drops and hills of over 300ft +STR_0581 :A ring of seats is pulled to the top of a tall tower while gently rotating, then allowed to free-fall down, stopping gently at the bottom using magnetic brakes +STR_0582 : +STR_0583 : +STR_0584 :Special bicycles run on a steel monorail track, propelled by the pedalling of the riders +STR_0585 :Riders sit in pairs of seats suspended beneath the track as they loop and twist through tight inversions +STR_0586 :Boat shaped cars run on roller coaster track to allow twisting curves and steep drops, splashing down into sections of water for gentle river sections +STR_0587 :After an exhilarating air-powered launch, the train speeds up a vertical track, over the top, and vertically down the other side to return to the station +STR_0588 :Individual cars run beneath a zig-zagging track with hairpin turns and sharp drops +STR_0589 : +STR_0590 :Riders ride in a submerged submarine through an underwater course +STR_0591 :Raft-shaped boats gently meander around a river track +STR_0592 : +STR_0593 : +STR_0594 : +STR_0595 : +STR_0596 : +STR_0597 : +STR_0598 :Inverted roller coaster trains are accelerated out of the station to travel up a vertical spike of track, then reverse back through the station to travel backwards up another vertical spike of track +STR_0599 :A compact roller coaster with individual cars and smooth twisting drops +STR_0600 :Powered mine trains career along a smooth and twisted track layout +STR_0601 : +STR_0602 :Roller coaster trains are accelerated out of the station by linear induction motors to speed through twisting inversions +STR_0603 :Guest {INT32} +STR_0604 :Guest {INT32} +STR_0605 :Guest {INT32} +STR_0606 :Guest {INT32} +STR_0607 :Guest {INT32} +STR_0608 :Guest {INT32} +STR_0609 :Guest {INT32} +STR_0610 :Guest {INT32} +STR_0611 :Guest {INT32} +STR_0612 :Guest {INT32} +STR_0613 :Guest {INT32} +STR_0614 :Guest {INT32} +STR_0615 :Guest {INT32} +STR_0616 :Guest {INT32} +STR_0617 :Guest {INT32} +STR_0618 :Guest {INT32} +STR_0619 :Guest {INT32} +STR_0620 :Guest {INT32} +STR_0621 :Guest {INT32} +STR_0622 :Guest {INT32} +STR_0623 :Guest {INT32} +STR_0624 :Guest {INT32} +STR_0625 :Guest {INT32} +STR_0626 :Guest {INT32} +STR_0627 :Guest {INT32} +STR_0628 :Guest {INT32} +STR_0629 :Guest {INT32} +STR_0630 :Guest {INT32} +STR_0631 :Guest {INT32} +STR_0632 :Guest {INT32} +STR_0633 :Guest {INT32} +STR_0634 :Guest {INT32} +STR_0635 :Guest {INT32} +STR_0636 :Guest {INT32} +STR_0637 :Guest {INT32} +STR_0638 :Guest {INT32} +STR_0639 :Guest {INT32} +STR_0640 :Guest {INT32} +STR_0641 :Guest {INT32} +STR_0642 :Guest {INT32} +STR_0643 :Guest {INT32} +STR_0644 :Guest {INT32} +STR_0645 :Guest {INT32} +STR_0646 :Guest {INT32} +STR_0647 :Guest {INT32} +STR_0648 :Guest {INT32} +STR_0649 :Guest {INT32} +STR_0650 :Guest {INT32} +STR_0651 :Guest {INT32} +STR_0652 :Guest {INT32} +STR_0653 :Guest {INT32} +STR_0654 :Guest {INT32} +STR_0655 :Guest {INT32} +STR_0656 :Guest {INT32} +STR_0657 :Guest {INT32} +STR_0658 :Guest {INT32} +STR_0659 :Guest {INT32} +STR_0660 :Guest {INT32} +STR_0661 :Guest {INT32} +STR_0662 :Guest {INT32} +STR_0663 :Guest {INT32} +STR_0664 :Guest {INT32} +STR_0665 :Guest {INT32} +STR_0666 :Guest {INT32} +STR_0667 :Guest {INT32} +STR_0668 :Guest {INT32} +STR_0669 :Guest {INT32} +STR_0670 :Guest {INT32} +STR_0671 :Guest {INT32} +STR_0672 :Guest {INT32} +STR_0673 :Guest {INT32} +STR_0674 :Guest {INT32} +STR_0675 :Guest {INT32} +STR_0676 :Guest {INT32} +STR_0677 :Guest {INT32} +STR_0678 :Guest {INT32} +STR_0679 :Guest {INT32} +STR_0680 :Guest {INT32} +STR_0681 :Guest {INT32} +STR_0682 :Guest {INT32} +STR_0683 :Guest {INT32} +STR_0684 :Guest {INT32} +STR_0685 :Guest {INT32} +STR_0686 :Guest {INT32} +STR_0687 :Guest {INT32} +STR_0688 :Guest {INT32} +STR_0689 :Guest {INT32} +STR_0690 :Guest {INT32} +STR_0691 :Guest {INT32} +STR_0692 :Guest {INT32} +STR_0693 :Guest {INT32} +STR_0694 :Guest {INT32} +STR_0695 :Guest {INT32} +STR_0696 :Guest {INT32} +STR_0697 :Guest {INT32} +STR_0698 :Guest {INT32} +STR_0699 :Guest {INT32} +STR_0700 :Guest {INT32} +STR_0701 :Guest {INT32} +STR_0702 :Guest {INT32} +STR_0703 :Guest {INT32} +STR_0704 :Guest {INT32} +STR_0705 :Guest {INT32} +STR_0706 :Guest {INT32} +STR_0707 :Guest {INT32} +STR_0708 :Guest {INT32} +STR_0709 :Guest {INT32} +STR_0710 :Guest {INT32} +STR_0711 :Guest {INT32} +STR_0712 :Guest {INT32} +STR_0713 :Guest {INT32} +STR_0714 :Guest {INT32} +STR_0715 :Guest {INT32} +STR_0716 :Guest {INT32} +STR_0717 :Guest {INT32} +STR_0718 :Guest {INT32} +STR_0719 :Guest {INT32} +STR_0720 :Guest {INT32} +STR_0721 :Guest {INT32} +STR_0722 :Guest {INT32} +STR_0723 :Guest {INT32} +STR_0724 :Guest {INT32} +STR_0725 :Guest {INT32} +STR_0726 :Guest {INT32} +STR_0727 :Guest {INT32} +STR_0728 :Guest {INT32} +STR_0729 :Guest {INT32} +STR_0730 :Guest {INT32} +STR_0731 :Guest {INT32} +STR_0732 :Guest {INT32} +STR_0733 :Guest {INT32} +STR_0734 :Guest {INT32} +STR_0735 :Guest {INT32} +STR_0736 :Guest {INT32} +STR_0737 :Guest {INT32} +STR_0738 :Guest {INT32} +STR_0739 :Guest {INT32} +STR_0740 :Guest {INT32} +STR_0741 :Guest {INT32} +STR_0742 :Guest {INT32} +STR_0743 :Guest {INT32} +STR_0744 :Guest {INT32} +STR_0745 :Guest {INT32} +STR_0746 :Guest {INT32} +STR_0747 :Guest {INT32} +STR_0748 :Guest {INT32} +STR_0749 :Guest {INT32} +STR_0750 :Guest {INT32} +STR_0751 :Guest {INT32} +STR_0752 :Guest {INT32} +STR_0753 :Guest {INT32} +STR_0754 :Guest {INT32} +STR_0755 :Guest {INT32} +STR_0756 :Guest {INT32} +STR_0757 :Guest {INT32} +STR_0758 :Guest {INT32} +STR_0759 :Guest {INT32} +STR_0760 :Guest {INT32} +STR_0761 :Guest {INT32} +STR_0762 :Guest {INT32} +STR_0763 :Guest {INT32} +STR_0764 :Guest {INT32} +STR_0765 :Guest {INT32} +STR_0766 :Guest {INT32} +STR_0767 :Guest {INT32} +STR_0768 :Handyman {INT32} +STR_0769 :Mechanic {INT32} +STR_0770 :Security Guard {INT32} +STR_0771 :Entertainer {INT32} +STR_0772 :Unnamed park{POP16}{POP16} +STR_0773 :Unnamed park{POP16}{POP16} +STR_0774 :Unnamed park{POP16}{POP16} +STR_0775 :Unnamed park{POP16}{POP16} +STR_0776 :Unnamed park{POP16}{POP16} +STR_0777 :Unnamed park{POP16}{POP16} +STR_0778 :Sign +STR_0779 :1st +STR_0780 :2nd +STR_0781 :3rd +STR_0782 :4th +STR_0783 :5th +STR_0784 :6th +STR_0785 :7th +STR_0786 :8th +STR_0787 :9th +STR_0788 :10th +STR_0789 :11th +STR_0790 :12th +STR_0791 :13th +STR_0792 :14th +STR_0793 :15th +STR_0794 :16th +STR_0795 :17th +STR_0796 :18th +STR_0797 :19th +STR_0798 :20th +STR_0799 :21st +STR_0800 :22nd +STR_0801 :23rd +STR_0802 :24th +STR_0803 :25th +STR_0804 :26th +STR_0805 :27th +STR_0806 :28th +STR_0807 :29th +STR_0808 :30th +STR_0809 :31st +STR_0810 :Jan +STR_0811 :Feb +STR_0812 :Mar +STR_0813 :Apr +STR_0814 :May +STR_0815 :Jun +STR_0816 :Jul +STR_0817 :Aug +STR_0818 :Sep +STR_0819 :Oct +STR_0820 :Nov +STR_0821 :Dec +STR_0822 :Unable to access graphic data file +STR_0823 :Missing or inaccessible data file +STR_0824 :{BLACK}{CROSS} +STR_0825 :Chosen name in use already +STR_0826 :Too many names defined +STR_0827 :Not enough cash - requires {CURRENCY2DP} +STR_0828 :{SMALLFONT}{BLACK}Close window +STR_0829 :{SMALLFONT}{BLACK}Window title - Drag this to move window +STR_0830 :{SMALLFONT}{BLACK}Zoom view in +STR_0831 :{SMALLFONT}{BLACK}Zoom view out +STR_0832 :{SMALLFONT}{BLACK}Rotate view 90{DEGREE} clockwise +STR_0833 :{SMALLFONT}{BLACK}Pause game +STR_0834 :{SMALLFONT}{BLACK}Disk and game options +STR_0835 :Game initialisation failed +STR_0836 :Unable to start game in a minimised state +STR_0837 :Unable to initialise graphics system +STR_0838 : +STR_0839 :{UINT16} x {UINT16} +STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +STR_0847 :About 'OpenRCT2' +STR_0848 :RollerCoaster Tycoon 2 +STR_0849 :{WINDOW_COLOUR_2}Version 2.01.028 +STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, all rights reserved +STR_0851 :{WINDOW_COLOUR_2}Designed and programmed by Chris Sawyer +STR_0852 :{WINDOW_COLOUR_2}Graphics by Simon Foster +STR_0853 :{WINDOW_COLOUR_2}Sound and music by Allister Brimble +STR_0854 :{WINDOW_COLOUR_2}Additional sounds recorded by David Ellis +STR_0855 :{WINDOW_COLOUR_2}Representation by Jacqui Lyons at Marjacq Ltd. +STR_0856 :{WINDOW_COLOUR_2}Thanks to: +STR_0857 :{WINDOW_COLOUR_2}Peter James Adcock, Joe Booth, and 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 :Too low ! +STR_0878 :Too high ! +STR_0879 :Can't lower land here... +STR_0880 :Can't raise land here... +STR_0881 :Object in the way +STR_0882 :Load Game +STR_0883 :Save Game +STR_0884 :Load Landscape +STR_0885 :Save Landscape +STR_0886 :Quit Game +STR_0887 :Quit Scenario Editor +STR_0888 :Quit Roller Coaster Designer +STR_0889 :Quit Track Designs Manager +STR_0890 :SCR{COMMA16}.BMP +STR_0891 :Screenshot +STR_0892 :Screenshot saved to disk as '{STRINGID}' +STR_0893 :Screenshot failed ! +STR_0894 :Landscape data area full ! +STR_0895 :Can't build partly above and partly below ground +STR_0896 :{POP16}{POP16}{STRINGID} Construction +STR_0897 :Direction +STR_0898 :{SMALLFONT}{BLACK}Left-hand curve +STR_0899 :{SMALLFONT}{BLACK}Right-hand curve +STR_0900 :{SMALLFONT}{BLACK}Left-hand curve (small radius) +STR_0901 :{SMALLFONT}{BLACK}Right-hand curve (small radius) +STR_0902 :{SMALLFONT}{BLACK}Left-hand curve (very small radius) +STR_0903 :{SMALLFONT}{BLACK}Right-hand curve (very small radius) +STR_0904 :{SMALLFONT}{BLACK}Left-hand curve (large radius) +STR_0905 :{SMALLFONT}{BLACK}Right-hand curve (large radius) +STR_0906 :{SMALLFONT}{BLACK}Straight +STR_0907 :Slope +STR_0908 :Roll/Banking +STR_0909 :Seat Rot. +STR_0910 :{SMALLFONT}{BLACK}Roll for left-hand curve +STR_0911 :{SMALLFONT}{BLACK}Roll for right-hand curve +STR_0912 :{SMALLFONT}{BLACK}No roll +STR_0913 :{SMALLFONT}{BLACK}Move to previous section +STR_0914 :{SMALLFONT}{BLACK}Move to next section +STR_0915 :{SMALLFONT}{BLACK}Construct the selected section +STR_0916 :{SMALLFONT}{BLACK}Remove the highlighted section +STR_0917 :{SMALLFONT}{BLACK}Vertical drop +STR_0918 :{SMALLFONT}{BLACK}Steep slope down +STR_0919 :{SMALLFONT}{BLACK}Slope down +STR_0920 :{SMALLFONT}{BLACK}Level +STR_0921 :{SMALLFONT}{BLACK}Slope up +STR_0922 :{SMALLFONT}{BLACK}Steep slope up +STR_0923 :{SMALLFONT}{BLACK}Vertical rise +STR_0924 :{SMALLFONT}{BLACK}Helix down +STR_0925 :{SMALLFONT}{BLACK}Helix up +STR_0926 :Can't remove this... +STR_0927 :Can't construct this here... +STR_0928 :{SMALLFONT}{BLACK}Chain lift, to pull cars up slopes +STR_0929 :'S' Bend (left) +STR_0930 :'S' Bend (right) +STR_0931 :Vertical Loop (left) +STR_0932 :Vertical Loop (right) +STR_0933 :Raise or lower land first +STR_0934 :Ride entrance in the way +STR_0935 :Ride exit in the way +STR_0936 :Park entrance in the way +STR_0937 :{SMALLFONT}{BLACK}View options +STR_0938 :{SMALLFONT}{BLACK}Adjust land height and slope +STR_0939 :Underground/Inside View +STR_0940 :Remove Base Land +STR_0941 :Remove Vertical Faces +STR_0942 :See-Through Rides +STR_0943 :See-Through Scenery +STR_0944 :Save +STR_0945 :Don't Save +STR_0946 :Cancel +STR_0947 :Save this before loading ? +STR_0948 :Save this before quitting ? +STR_0949 :Save this before quitting ? +STR_0950 :Load Game +STR_0951 :Quit Game +STR_0952 :Quit Game +STR_0953 :Load Landscape +STR_0954 : +STR_0955 :{SMALLFONT}{BLACK}Select seat rotation angle for this track section +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 :Cancel +STR_0973 :OK +STR_0974 :Rides +STR_0975 :Shops and Stalls +STR_0976 :Toilets and Information Kiosks +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_0984 :{WINDOW_COLOUR_2}{UP}{BLACK} {CURRENCY2DP} +STR_0985 :{WINDOW_COLOUR_2}{DOWN}{BLACK} {CURRENCY2DP} +STR_0986 :{BLACK}{CURRENCY2DP} +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 +STR_0998 :No more stations allowed on this ride +STR_0999 :Requires a station platform +STR_1000 :Track is not a complete circuit +STR_1001 :Track unsuitable for type of train +STR_1002 :Can't open {POP16}{POP16}{POP16}{STRINGID}... +STR_1003 :Can't test {POP16}{POP16}{POP16}{STRINGID}... +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 +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... +STR_1018 :Can't make changes... +STR_1019 :Can't make changes... +STR_1020 :Can't make changes... +STR_1021 :{POP16}{POP16}{POP16}{POP16}{STRINGID} +STR_1022 :{POP16}{POP16}{POP16}{COMMA16} car per train +STR_1023 :{POP16}{POP16}{POP16}{COMMA16} cars per train +STR_1024 :{COMMA16} car per train +STR_1025 :{COMMA16} cars per train +STR_1026 :Station platform too long! +STR_1027 :{SMALLFONT}{BLACK}Locate this on Main View +STR_1028 :Off edge of map! +STR_1029 :Cannot build partly above and partly below water! +STR_1030 :Can only build this underwater! +STR_1031 :Can't build this underwater! +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 :OpenRCT2 Saved Game +STR_1044 :OpenRCT2 Scenario File +STR_1045 :OpenRCT2 Landscape File +STR_1046 :OpenRCT2 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 +STR_1057 :Ride/attraction name +STR_1058 :Enter new name for this ride/attraction: +STR_1059 :Can't rename ride/attraction... +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 (passing station) +STR_1065 :Shuttle mode +STR_1066 :Boat hire mode +STR_1067 :Upward launch +STR_1068 :Rotating lift mode +STR_1069 :Station to station mode +STR_1070 :Single ride per admission +STR_1071 :Unlimited rides per admission +STR_1072 :Maze mode +STR_1073 :Race mode +STR_1074 :Bumper-car mode +STR_1075 :Swing mode +STR_1076 :Shop stall mode +STR_1077 :Rotation mode +STR_1078 :Forward rotation +STR_1079 :Backward rotation +STR_1080 :Film: {ENDQUOTES}Avenging aviators{ENDQUOTES} +STR_1081 :3D film: {ENDQUOTES}Mouse tails{ENDQUOTES} +STR_1082 :Space rings mode +STR_1083 :Beginners mode +STR_1084 :LIM-powered launch +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 mode +STR_1089 :Berserk mode +STR_1090 :Haunted house mode +STR_1091 :Circus show mode +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 (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} +STR_1100 :Waiting to depart {POP16}{STRINGID} +STR_1101 :Departing {POP16}{STRINGID} +STR_1102 :Travelling at {VELOCITY} +STR_1103 :Arriving at {POP16}{STRINGID} +STR_1104 :Unloading passengers at {POP16}{STRINGID} +STR_1105 :Travelling at {VELOCITY} +STR_1106 :Crashing! +STR_1107 :Crashed! +STR_1108 :Travelling at {VELOCITY} +STR_1109 :Swinging +STR_1110 :Rotating +STR_1111 :Rotating +STR_1112 :Operating +STR_1113 :Showing film +STR_1114 :Rotating +STR_1115 :Operating +STR_1116 :Operating +STR_1117 :Doing circus show +STR_1118 :Operating +STR_1119 :Waiting for cable lift +STR_1120 :Travelling at {VELOCITY} +STR_1121 :Stopping +STR_1122 :Waiting for passengers +STR_1123 :Waiting to start +STR_1124 :Starting +STR_1125 :Operating +STR_1126 :Stopping +STR_1127 :Unloading passengers +STR_1128 :Stopped by block brakes +STR_1129 :All vehicles in same colours +STR_1130 :Different colours per {STRINGID} +STR_1131 :Different colours per vehicle +STR_1132 :Vehicle {POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1133 :Vehicle {POP16}{COMMA16} +STR_1134 :{POP16}{POP16}{POP16}{POP16}{POP16}{STRINGID} {COMMA16} +STR_1135 :{STRINGID} {COMMA16} +STR_1136 :{SMALLFONT}{BLACK}Select main colour +STR_1137 :{SMALLFONT}{BLACK}Select additional colour 1 +STR_1138 :{SMALLFONT}{BLACK}Select additional colour 2 +STR_1139 :{SMALLFONT}{BLACK}Select support structure colour +STR_1140 :{SMALLFONT}{BLACK}Select vehicle colour scheme option +STR_1141 :{SMALLFONT}{BLACK}Select which vehicle/train to modify +STR_1142 :{MOVE_X}{SMALLFONT}{STRINGID} +STR_1143 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRINGID} +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 +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_1162 :{OUTLINE}{TOPAZ}{STRINGID} +STR_1163 :{STRINGID}{NEWLINE}(Right-Click to Modify) +STR_1164 :{STRINGID}{NEWLINE}(Right-Click to Remove) +STR_1165 :{STRINGID} - {STRINGID} {COMMA16} +STR_1166 :Can't lower water level here... +STR_1167 :Can't raise water level here... +STR_1168 :Options +STR_1169 :(None) +STR_1170 :{STRING} +STR_1171 :{RED}Closed - - +STR_1172 :{YELLOW}{STRINGID} - - +STR_1173 :{SMALLFONT}{BLACK}Build footpaths and queue lines +STR_1174 :Banner sign in the way +STR_1175 :Can't build this on sloped footpath +STR_1176 :Can't build footpath here... +STR_1177 :Can't remove footpath from here... +STR_1178 :Land slope unsuitable +STR_1179 :Footpath in the way +STR_1180 :Can't build this underwater! +STR_1181 :Footpaths +STR_1182 :Type +STR_1183 :Direction +STR_1184 :Slope +STR_1185 :{SMALLFONT}{BLACK}Direction +STR_1186 :{SMALLFONT}{BLACK}Slope down +STR_1187 :{SMALLFONT}{BLACK}Level +STR_1188 :{SMALLFONT}{BLACK}Slope up +STR_1189 :{SMALLFONT}{BLACK}Construct the selected footpath section +STR_1190 :{SMALLFONT}{BLACK}Remove previous footpath section +STR_1191 :{BLACK}{STRINGID} +STR_1192 :{OUTLINE}{RED}{STRINGID} +STR_1193 :{WINDOW_COLOUR_2}{STRINGID} +STR_1194 :Closed +STR_1195 :Test Run +STR_1196 :Open +STR_1197 :Broken Down +STR_1198 :Crashed! +STR_1199 :{COMMA16} person on ride +STR_1200 :{COMMA16} people on ride +STR_1201 :Nobody in queue line +STR_1202 :1 person in queue line +STR_1203 :{COMMA16} people in queue line +STR_1204 :{COMMA16} minute queue time +STR_1205 :{COMMA16} minutes queue time +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}Synchronise with adjacent stations +STR_1216 :{SMALLFONT}{BLACK}Select whether to synchronise departure with all adjacent stations (for 'racing') +STR_1217 :{COMMA16} seconds +STR_1218 :{BLACK}{SMALLUP} +STR_1219 :{BLACK}{SMALLDOWN} +STR_1220 :Exit only +STR_1221 :No entrance +STR_1222 :No exit +STR_1223 :{SMALLFONT}{BLACK}Transport rides +STR_1224 :{SMALLFONT}{BLACK}Gentle rides +STR_1225 :{SMALLFONT}{BLACK}Roller coasters +STR_1226 :{SMALLFONT}{BLACK}Thrill rides +STR_1227 :{SMALLFONT}{BLACK}Water rides +STR_1228 :{SMALLFONT}{BLACK}Shops & stalls +STR_1229 :train +STR_1230 :trains +STR_1231 :Train +STR_1232 :Trains +STR_1233 :{COMMA16} train +STR_1234 :{COMMA16} trains +STR_1235 :Train {COMMA16} +STR_1236 :boat +STR_1237 :boats +STR_1238 :Boat +STR_1239 :Boats +STR_1240 :{COMMA16} boat +STR_1241 :{COMMA16} boats +STR_1242 :Boat {COMMA16} +STR_1243 :track +STR_1244 :tracks +STR_1245 :Track +STR_1246 :Tracks +STR_1247 :{COMMA16} track +STR_1248 :{COMMA16} tracks +STR_1249 :Track {COMMA16} +STR_1250 :docking platform +STR_1251 :docking platforms +STR_1252 :Docking platform +STR_1253 :Docking platforms +STR_1254 :{COMMA16} docking platform +STR_1255 :{COMMA16} docking platforms +STR_1256 :Docking platform {COMMA16} +STR_1257 :station +STR_1258 :stations +STR_1259 :Station +STR_1260 :Stations +STR_1261 :{COMMA16} station +STR_1262 :{COMMA16} stations +STR_1263 :Station {COMMA16} +STR_1264 :car +STR_1265 :cars +STR_1266 :Car +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_1278 :structure +STR_1279 :structures +STR_1280 :Structure +STR_1281 :Structures +STR_1282 :{COMMA16} structure +STR_1283 :{COMMA16} structures +STR_1284 :Structure {COMMA16} +STR_1285 :ship +STR_1286 :ships +STR_1287 :Ship +STR_1288 :Ships +STR_1289 :{COMMA16} ship +STR_1290 :{COMMA16} ships +STR_1291 :Ship {COMMA16} +STR_1292 :cabin +STR_1293 :cabins +STR_1294 :Cabin +STR_1295 :Cabins +STR_1296 :{COMMA16} cabin +STR_1297 :{COMMA16} cabins +STR_1298 :Cabin {COMMA16} +STR_1299 :wheel +STR_1300 :wheels +STR_1301 :Wheel +STR_1302 :Wheels +STR_1303 :{COMMA16} wheel +STR_1304 :{COMMA16} wheels +STR_1305 :Wheel {COMMA16} +STR_1306 :ring +STR_1307 :rings +STR_1308 :Ring +STR_1309 :Rings +STR_1310 :{COMMA16} ring +STR_1311 :{COMMA16} rings +STR_1312 :Ring {COMMA16} +STR_1313 :player +STR_1314 :players +STR_1315 :Player +STR_1316 :Players +STR_1317 :{COMMA16} player +STR_1318 :{COMMA16} players +STR_1319 :Player {COMMA16} +STR_1320 :course +STR_1321 :courses +STR_1322 :Course +STR_1323 :Courses +STR_1324 :{COMMA16} course +STR_1325 :{COMMA16} courses +STR_1326 :Course {COMMA16} +STR_1327 :{SMALLFONT}{BLACK}Rotate objects by 90{DEGREE} +STR_1328 :Level land required +STR_1329 :{WINDOW_COLOUR_2}Launch speed: +STR_1330 :{SMALLFONT}{BLACK}Maximum speed when leaving station +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} - Entrance{POP16}{POP16} +STR_1336 :{STRINGID} - Station {POP16}{COMMA16} Entrance +STR_1337 :{STRINGID} - Exit{POP16}{POP16} +STR_1338 :{STRINGID} - Station {POP16}{COMMA16} Exit +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} +STR_1342 :{DURATION} +STR_1343 :{DURATION} / +STR_1344 :{WINDOW_COLOUR_2}Ride length: {BLACK}{STRINGID}{STRINGID}{STRINGID}{STRINGID} +STR_1345 :{LENGTH} +STR_1346 :{LENGTH} / +STR_1347 :{WINDOW_COLOUR_2}Average speed: {BLACK}{VELOCITY} +STR_1348 :{WINDOW_COLOUR_2}Max. positive vertical G's: {BLACK}{COMMA2DP32}g +STR_1349 :{WINDOW_COLOUR_2}Max. positive vertical G's: {OUTLINE}{RED}{COMMA2DP32}g +STR_1350 :{WINDOW_COLOUR_2}Max. negative vertical G's: {BLACK}{COMMA2DP32}g +STR_1351 :{WINDOW_COLOUR_2}Max. negative vertical G's: {OUTLINE}{RED}{COMMA2DP32}g +STR_1352 :{WINDOW_COLOUR_2}Max. lateral G's: {BLACK}{COMMA2DP32}g +STR_1353 :{WINDOW_COLOUR_2}Max. lateral G's: {OUTLINE}{RED}{COMMA2DP32}g +STR_1354 :{WINDOW_COLOUR_2}Highest drop height: {BLACK}{LENGTH} +STR_1355 :{WINDOW_COLOUR_2}Drops: {BLACK}{COMMA16} +STR_1356 :{WINDOW_COLOUR_2}Inversions: {BLACK}{COMMA16} +STR_1357 :{WINDOW_COLOUR_2}Holes: {BLACK}{COMMA16} +STR_1358 :{WINDOW_COLOUR_2}Total 'air' time: {BLACK}{COMMA2DP32}secs +STR_1359 :{WINDOW_COLOUR_2}Queue time: {BLACK}{COMMA16} minute +STR_1360 :{WINDOW_COLOUR_2}Queue time: {BLACK}{COMMA16} minutes +STR_1361 :Can't change speed... +STR_1362 :Can't change launch speed... +STR_1363 :Too high for supports! +STR_1364 :Supports for track above can't be extended any further! +STR_1365 :In-line Twist (left) +STR_1366 :In-line Twist (right) +STR_1367 :Half Loop +STR_1368 :Half Corkscrew (left) +STR_1369 :Half Corkscrew (right) +STR_1370 :Barrel Roll (left) +STR_1371 :Barrel Roll (right) +STR_1372 :Launched Lift Hill +STR_1373 :Large Half Loop (left) +STR_1374 :Large Half Loop (right) +STR_1375 :Upper Transfer +STR_1376 :Lower Transfer +STR_1377 :Heartline Roll (left) +STR_1378 :Heartline Roll (right) +STR_1379 :Reverser (left) +STR_1380 :Reverser (right) +STR_1381 :Curved Lift Hill (left) +STR_1382 :Curved Lift Hill (right) +STR_1383 :Quarter Loop +STR_1384 :{YELLOW}{STRINGID} +STR_1385 :{SMALLFONT}{BLACK}Other track configurations +STR_1386 :Special... +STR_1387 :Can't change land type... +STR_1388 :{OUTLINE}{GREEN}+ {CURRENCY} +STR_1389 :{OUTLINE}{RED}- {CURRENCY} +STR_1390 :{CURRENCY2DP} +STR_1391 :{RED}{CURRENCY2DP} +STR_1392 :{SMALLFONT}{BLACK}View of ride/attraction +STR_1393 :{SMALLFONT}{BLACK}Vehicle details and options +STR_1394 :{SMALLFONT}{BLACK}Operating options +STR_1395 :{SMALLFONT}{BLACK}Maintenance options +STR_1396 :{SMALLFONT}{BLACK}Colour scheme options +STR_1397 :{SMALLFONT}{BLACK}Sound & music options +STR_1398 :{SMALLFONT}{BLACK}Measurements and test data +STR_1399 :{SMALLFONT}{BLACK}Graphs +STR_1400 :Entrance +STR_1401 :Exit +STR_1402 :{SMALLFONT}{BLACK}Build or move entrance to ride/attraction +STR_1403 :{SMALLFONT}{BLACK}Build or move exit from ride/attraction +STR_1404 :{SMALLFONT}{BLACK}Rotate 90{DEGREE} +STR_1405 :{SMALLFONT}{BLACK}Mirror image +STR_1406 :{SMALLFONT}{BLACK}Toggle scenery on/off (if available for this design) +STR_1407 :{WINDOW_COLOUR_2}Build this... +STR_1408 :{WINDOW_COLOUR_2}Cost: {BLACK}{CURRENCY} +STR_1409 :Entry/Exit Platform +STR_1410 :Vertical Tower +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_1416 :{WINDOW_COLOUR_2}Altitude +STR_1417 :{WINDOW_COLOUR_2}Vert.G's +STR_1418 :{WINDOW_COLOUR_2}Lat.G's +STR_1419 :{SMALLFONT}{BLACK}{VELOCITY} +STR_1420 :{SMALLFONT}{BLACK}{LENGTH} +STR_1421 :{SMALLFONT}{BLACK}{COMMA16}g +STR_1422 :{SMALLFONT}{BLACK}Logging data from {POP16}{STRINGID} +STR_1423 :{SMALLFONT}{BLACK}Queue line path +STR_1424 :{SMALLFONT}{BLACK}Footpath +STR_1425 :Footpath +STR_1426 :Queue Line +STR_1427 :{WINDOW_COLOUR_2}Customers: {BLACK}{COMMA32} per hour +STR_1428 :{WINDOW_COLOUR_2}Admission price: +STR_1429 :{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1430 :Free +STR_1431 :Walking +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_1438 :Sitting +STR_1439 :(select location) +STR_1440 :Mowing grass +STR_1441 :Sweeping footpath +STR_1442 :Emptying litter bin +STR_1443 :Watering gardens +STR_1444 :Watching {STRINGID} +STR_1445 :Watching construction of {STRINGID} +STR_1446 :Looking at scenery +STR_1447 :Leaving the park +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_1453 :Enter name for this guest: +STR_1454 :Can't name guest... +STR_1455 :Invalid name for guest +STR_1456 :{WINDOW_COLOUR_2}Cash spent: {BLACK}{CURRENCY2DP} +STR_1457 :{WINDOW_COLOUR_2}Cash in pocket: {BLACK}{CURRENCY2DP} +STR_1458 :{WINDOW_COLOUR_2}Time in park: {BLACK}{REALTIME} +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_1464 :Helix up (small) +STR_1465 :Helix up (large) +STR_1466 :Helix down (small) +STR_1467 :Helix down (large) +STR_1468 :Staff +STR_1469 :Ride must start and end with stations +STR_1470 :Station not long enough +STR_1471 :{WINDOW_COLOUR_2}Speed: +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 +STR_1475 :{WINDOW_COLOUR_2}Intensity rating: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1476 :{WINDOW_COLOUR_2}Intensity rating: {BLACK}Not yet available +STR_1477 :{WINDOW_COLOUR_2}Intensity rating: {OUTLINE}{RED}{COMMA2DP32} ({STRINGID}) +STR_1478 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}{COMMA2DP32} ({STRINGID}) +STR_1479 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}Not yet available +STR_1480 :{SMALLFONT}{OPENQUOTES}I can't afford {STRINGID}{ENDQUOTES} +STR_1481 :{SMALLFONT}{OPENQUOTES}I've spent all my money{ENDQUOTES} +STR_1482 :{SMALLFONT}{OPENQUOTES}I feel sick{ENDQUOTES} +STR_1483 :{SMALLFONT}{OPENQUOTES}I feel very sick{ENDQUOTES} +STR_1484 :{SMALLFONT}{OPENQUOTES}I want to go on something more thrilling than {STRINGID}{ENDQUOTES} +STR_1485 :{SMALLFONT}{OPENQUOTES}{STRINGID} looks too intense for me{ENDQUOTES} +STR_1486 :{SMALLFONT}{OPENQUOTES}I haven't finished my {STRINGID} yet{ENDQUOTES} +STR_1487 :{SMALLFONT}{OPENQUOTES}Just looking at {STRINGID} makes me feel sick{ENDQUOTES} +STR_1488 :{SMALLFONT}{OPENQUOTES}I'm not paying that much to go on {STRINGID}{ENDQUOTES} +STR_1489 :{SMALLFONT}{OPENQUOTES}I want to go home{ENDQUOTES} +STR_1490 :{SMALLFONT}{OPENQUOTES}{STRINGID} is really good value{ENDQUOTES} +STR_1491 :{SMALLFONT}{OPENQUOTES}I've already got {STRINGID}{ENDQUOTES} +STR_1492 :{SMALLFONT}{OPENQUOTES}I can't afford {STRINGID}{ENDQUOTES} +STR_1493 :{SMALLFONT}{OPENQUOTES}I'm not hungry{ENDQUOTES} +STR_1494 :{SMALLFONT}{OPENQUOTES}I'm not thirsty{ENDQUOTES} +STR_1495 :{SMALLFONT}{OPENQUOTES}Help! I'm drowning!{ENDQUOTES} +STR_1496 :{SMALLFONT}{OPENQUOTES}I'm lost!{ENDQUOTES} +STR_1497 :{SMALLFONT}{OPENQUOTES}{STRINGID} was great{ENDQUOTES} +STR_1498 :{SMALLFONT}{OPENQUOTES}I've been queuing for {STRINGID} for ages{ENDQUOTES} +STR_1499 :{SMALLFONT}{OPENQUOTES}I'm tired{ENDQUOTES} +STR_1500 :{SMALLFONT}{OPENQUOTES}I'm hungry{ENDQUOTES} +STR_1501 :{SMALLFONT}{OPENQUOTES}I'm thirsty{ENDQUOTES} +STR_1502 :{SMALLFONT}{OPENQUOTES}I need to go to the bathroom{ENDQUOTES} +STR_1503 :{SMALLFONT}{OPENQUOTES}I can't find {STRINGID}{ENDQUOTES} +STR_1504 :{SMALLFONT}{OPENQUOTES}I'm not paying that much to use {STRINGID}{ENDQUOTES} +STR_1505 :{SMALLFONT}{OPENQUOTES}I'm not going on {STRINGID} while it's raining{ENDQUOTES} +STR_1506 :{SMALLFONT}{OPENQUOTES}The litter here is really bad{ENDQUOTES} +STR_1507 :{SMALLFONT}{OPENQUOTES}I can't find the park exit{ENDQUOTES} +STR_1508 :{SMALLFONT}{OPENQUOTES}I want to get off {STRINGID}{ENDQUOTES} +STR_1509 :{SMALLFONT}{OPENQUOTES}I want to get out of {STRINGID}{ENDQUOTES} +STR_1510 :{SMALLFONT}{OPENQUOTES}I'm not going on {STRINGID} - It isn't safe{ENDQUOTES} +STR_1511 :{SMALLFONT}{OPENQUOTES}This path is disgusting{ENDQUOTES} +STR_1512 :{SMALLFONT}{OPENQUOTES}It's too crowded here{ENDQUOTES} +STR_1513 :{SMALLFONT}{OPENQUOTES}The vandalism here is really bad{ENDQUOTES} +STR_1514 :{SMALLFONT}{OPENQUOTES}Great scenery!{ENDQUOTES} +STR_1515 :{SMALLFONT}{OPENQUOTES}This park is really clean and tidy{ENDQUOTES} +STR_1516 :{SMALLFONT}{OPENQUOTES}The jumping fountains are great{ENDQUOTES} +STR_1517 :{SMALLFONT}{OPENQUOTES}The music is nice here{ENDQUOTES} +STR_1518 :{SMALLFONT}{OPENQUOTES}This balloon from {STRINGID} is really good value{ENDQUOTES} +STR_1519 :{SMALLFONT}{OPENQUOTES}This cuddly toy from {STRINGID} is really good value{ENDQUOTES} +STR_1520 :{SMALLFONT}{OPENQUOTES}This park map from {STRINGID} is really good value{ENDQUOTES} +STR_1521 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} +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 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 candyfloss from {STRINGID} is really good value{ENDQUOTES} +STR_1528 : +STR_1529 : +STR_1530 : +STR_1531 :{SMALLFONT}{OPENQUOTES}This pizza from {STRINGID} is really good value{ENDQUOTES} +STR_1532 : +STR_1533 :{SMALLFONT}{OPENQUOTES}This popcorn from {STRINGID} is really good value{ENDQUOTES} +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 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} +STR_1541 : +STR_1542 :{SMALLFONT}{OPENQUOTES}This fried chicken from {STRINGID} is really good value{ENDQUOTES} +STR_1543 :{SMALLFONT}{OPENQUOTES}This lemonade from {STRINGID} is really good value{ENDQUOTES} +STR_1544 : +STR_1545 : +STR_1546 : +STR_1547 : +STR_1548 : +STR_1549 : +STR_1550 :{SMALLFONT}{OPENQUOTES}Wow!{ENDQUOTES} +STR_1551 :{SMALLFONT}{OPENQUOTES}I have the strangest feeling someone is watching me{ENDQUOTES} +STR_1552 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a balloon from {STRINGID}{ENDQUOTES} +STR_1553 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a cuddly toy from {STRINGID}{ENDQUOTES} +STR_1554 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a park map from {STRINGID}{ENDQUOTES} +STR_1555 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} +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 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 candyfloss from {STRINGID}{ENDQUOTES} +STR_1562 : +STR_1563 : +STR_1564 : +STR_1565 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for pizza from {STRINGID}{ENDQUOTES} +STR_1566 : +STR_1567 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for popcorn from {STRINGID}{ENDQUOTES} +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 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} +STR_1575 : +STR_1576 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fried chicken from {STRINGID}{ENDQUOTES} +STR_1577 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for lemonade from {STRINGID}{ENDQUOTES} +STR_1578 : +STR_1579 : +STR_1580 : +STR_1581 : +STR_1582 : +STR_1583 : +STR_1584 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} +STR_1585 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} +STR_1586 :{SMALLFONT}{OPENQUOTES}This on-ride photo from {STRINGID} is really good value{ENDQUOTES} +STR_1587 :{SMALLFONT}{OPENQUOTES}This pretzel from {STRINGID} is really good value{ENDQUOTES} +STR_1588 :{SMALLFONT}{OPENQUOTES}This hot chocolate from {STRINGID} is really good value{ENDQUOTES} +STR_1589 :{SMALLFONT}{OPENQUOTES}This iced tea from {STRINGID} is really good value{ENDQUOTES} +STR_1590 :{SMALLFONT}{OPENQUOTES}This funnel cake from {STRINGID} is really good value{ENDQUOTES} +STR_1591 :{SMALLFONT}{OPENQUOTES}These sunglasses from {STRINGID} are really good value{ENDQUOTES} +STR_1592 :{SMALLFONT}{OPENQUOTES}These beef noodles from {STRINGID} are really good value{ENDQUOTES} +STR_1593 :{SMALLFONT}{OPENQUOTES}These fried rice noodles from {STRINGID} are really good value{ENDQUOTES} +STR_1594 :{SMALLFONT}{OPENQUOTES}This wonton soup from {STRINGID} is really good value{ENDQUOTES} +STR_1595 :{SMALLFONT}{OPENQUOTES}This meatball soup from {STRINGID} is really good value{ENDQUOTES} +STR_1596 :{SMALLFONT}{OPENQUOTES}This fruit juice from {STRINGID} is really good value{ENDQUOTES} +STR_1597 :{SMALLFONT}{OPENQUOTES}This soybean milk from {STRINGID} is really good value{ENDQUOTES} +STR_1598 :{SMALLFONT}{OPENQUOTES}This sujongkwa from {STRINGID} is really good value{ENDQUOTES} +STR_1599 :{SMALLFONT}{OPENQUOTES}This sub sandwich from {STRINGID} is really good value{ENDQUOTES} +STR_1600 :{SMALLFONT}{OPENQUOTES}This cookie from {STRINGID} is really good value{ENDQUOTES} +STR_1601 : +STR_1602 : +STR_1603 : +STR_1604 :{SMALLFONT}{OPENQUOTES}This roast sausage from {STRINGID} are really good value{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}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} +STR_1617 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} +STR_1618 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for an on-ride photo from {STRINGID}{ENDQUOTES} +STR_1619 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a pretzel from {STRINGID}{ENDQUOTES} +STR_1620 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for hot chocolate from {STRINGID}{ENDQUOTES} +STR_1621 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for iced tea from {STRINGID}{ENDQUOTES} +STR_1622 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a funnel cake from {STRINGID}{ENDQUOTES} +STR_1623 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for sunglasses from {STRINGID}{ENDQUOTES} +STR_1624 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for beef noodles from {STRINGID}{ENDQUOTES} +STR_1625 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fried rice noodles from {STRINGID}{ENDQUOTES} +STR_1626 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for wonton soup from {STRINGID}{ENDQUOTES} +STR_1627 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for meatball soup from {STRINGID}{ENDQUOTES} +STR_1628 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fruit juice from {STRINGID}{ENDQUOTES} +STR_1629 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for soybean milk from {STRINGID}{ENDQUOTES} +STR_1630 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for sujongkwa from {STRINGID}{ENDQUOTES} +STR_1631 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a sub sandwich from {STRINGID}{ENDQUOTES} +STR_1632 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a cookie from {STRINGID}{ENDQUOTES} +STR_1633 : +STR_1634 : +STR_1635 : +STR_1636 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a roast sausage from {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}Help! Put me down!{ENDQUOTES} +STR_1649 :{SMALLFONT}{OPENQUOTES}I'm running out of cash!{ENDQUOTES} +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: +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_1673 :Spinning Control Toggle Track +STR_1674 :Brake speed +STR_1675 :{POP16}{VELOCITY} +STR_1676 :{SMALLFONT}{BLACK}Set speed limit for brakes +STR_1677 :{WINDOW_COLOUR_2}Popularity: {BLACK}Unknown +STR_1678 :{WINDOW_COLOUR_2}Popularity: {BLACK}{COMMA16}% +STR_1679 :Helix up (left) +STR_1680 :Helix up (right) +STR_1681 :Helix down (left) +STR_1682 :Helix down (right) +STR_1683 :Base size 2 x 2 +STR_1684 :Base size 4 x 4 +STR_1685 :Base size 2 x 4 +STR_1686 :Base size 5 x 1 +STR_1687 :Water splash +STR_1688 :Base size 4 x 1 +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_1694 :{SMALLFONT}{BLACK}Staff +STR_1695 :{SMALLFONT}{BLACK}Income and costs +STR_1696 :{SMALLFONT}{BLACK}Customer information +STR_1697 :Cannot place these on queue line area +STR_1698 :Can only place these on queue area +STR_1699 :Too many people in game +STR_1700 :Hire new Handyman +STR_1701 :Hire new Mechanic +STR_1702 :Hire new Security Guard +STR_1703 :Hire new Entertainer +STR_1704 :Can't hire new staff... +STR_1705 :{SMALLFONT}{BLACK}Sack this staff member +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_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 +STR_1714 :{INLINE_SPRITE}{249}{19}{00}{00}{WINDOW_COLOUR_2}Empty litter bins +STR_1715 :{INLINE_SPRITE}{250}{19}{00}{00}{WINDOW_COLOUR_2}Mow grass +STR_1716 :Invalid name for park +STR_1717 :Can't rename park... +STR_1718 :Park Name +STR_1719 :Enter name for park: +STR_1720 :{SMALLFONT}{BLACK}Name park +STR_1721 :Park closed +STR_1722 :Park open +STR_1723 :Can't open park... +STR_1724 :Can't close park... +STR_1725 :Can't buy land... +STR_1726 :Land not for sale! +STR_1727 :Construction rights not for sale! +STR_1728 :Can't buy construction rights here... +STR_1729 :Land not owned by park! +STR_1730 :{RED}Closed - - +STR_1731 :{WHITE}{STRINGID} - - +STR_1732 :Build +STR_1733 :Mode +STR_1734 :{WINDOW_COLOUR_2}Number of laps: +STR_1735 :{SMALLFONT}{BLACK}Number of laps of circuit +STR_1736 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1737 :{COMMA16} +STR_1738 :Can't change number of laps... +STR_1739 :Race won by guest {INT32} +STR_1740 :Race won by {STRINGID} +STR_1741 :Not yet constructed ! +STR_1742 :{WINDOW_COLOUR_2}Max. people on ride: +STR_1743 :{SMALLFONT}{BLACK}Maximum number of people allowed on this ride at one time +STR_1744 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1745 :{COMMA16} +STR_1746 :Can't change this... +STR_1747 :{WINDOW_COLOUR_2}Time limit: +STR_1748 :{SMALLFONT}{BLACK}Time limit for ride +STR_1749 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{DURATION} +STR_1750 :{DURATION} +STR_1751 :Can't change time limit for ride... +STR_1752 :{SMALLFONT}{BLACK}Show list of individual guests in park +STR_1753 :{SMALLFONT}{BLACK}Show summarised list of guests in park +STR_1754 :{BLACK}{COMMA16} guests +STR_1755 :{BLACK}{COMMA16} guest +STR_1756 :{WINDOW_COLOUR_2}Admission price: +STR_1757 :{WINDOW_COLOUR_2}Reliability: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1758 :{SMALLFONT}{BLACK}Build mode +STR_1759 :{SMALLFONT}{BLACK}Move mode +STR_1760 :{SMALLFONT}{BLACK}Fill-in mode +STR_1761 :{SMALLFONT}{BLACK}Build maze in this direction +STR_1762 :Waterfalls +STR_1763 :Rapids +STR_1764 :Log Bumps +STR_1765 :On-ride photo section +STR_1766 :Reverser turntable +STR_1767 :Spinning tunnel +STR_1768 :Can't change number of swings... +STR_1769 :{WINDOW_COLOUR_2}Number of swings: +STR_1770 :{SMALLFONT}{BLACK}Number of complete swings +STR_1771 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1772 :{COMMA16} +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_1778 :{STRINGID} - - +STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Panda costume +STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tiger costume +STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} Elephant costume +STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} Roman costume +STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} Gorilla costume +STR_1784 :{INLINE_SPRITE}{03}{20}{00}{00} Snowman costume +STR_1785 :{INLINE_SPRITE}{04}{20}{00}{00} Knight costume +STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} Astronaut costume +STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} Bandit costume +STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} Sheriff costume +STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} Pirate costume +STR_1790 :{SMALLFONT}{BLACK}Select uniform colour for this type of staff +STR_1791 :{WINDOW_COLOUR_2}Uniform colour: +STR_1792 :Responding to {STRINGID} breakdown call +STR_1793 :Heading to {STRINGID} for an inspection +STR_1794 :Fixing {STRINGID} +STR_1795 :Answering radio call +STR_1796 :Has broken down and requires fixing +STR_1797 :This option cannot be changed for this ride +STR_1798 :Whirlpool +STR_1799 :{POP16}{POP16}{POP16}{POP16}{POP16}{CURRENCY2DP} +STR_1800 :Safety cut-out +STR_1801 :Restraints stuck closed +STR_1802 :Restraints stuck open +STR_1803 :Doors stuck closed +STR_1804 :Doors stuck open +STR_1805 :Vehicle malfunction +STR_1806 :Brakes failure +STR_1807 :Control failure +STR_1808 :{WINDOW_COLOUR_2}Last breakdown: {BLACK}{STRINGID} +STR_1809 :{WINDOW_COLOUR_2}Current breakdown: {OUTLINE}{RED}{STRINGID} +STR_1810 :{WINDOW_COLOUR_2}Carrying: +STR_1811 :Can't build this here... +STR_1812 :{SMALLFONT}{BLACK}{STRINGID} +STR_1813 :Miscellaneous Objects +STR_1814 :Actions +STR_1815 :Thoughts +STR_1816 :{SMALLFONT}{BLACK}Select information type to show in guest list +STR_1817 :({COMMA16}) +STR_1818 :{WINDOW_COLOUR_2}All guests +STR_1819 :{WINDOW_COLOUR_2}All guests (summarised) +STR_1820 :{WINDOW_COLOUR_2}Guests {STRINGID} +STR_1821 :{WINDOW_COLOUR_2}Guests thinking {STRINGID} +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 favourite +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: {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 +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}{CURRENCY2DP} 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_1867 :{BLACK}{COMMA16} {STRINGID} +STR_1868 :Can't change number of rotations... +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}{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 +STR_1878 :{WINDOW_COLOUR_2}Inspection: +STR_1879 :Every 10 minutes +STR_1880 :Every 20 minutes +STR_1881 :Every 30 minutes +STR_1882 :Every 45 minutes +STR_1883 :Every hour +STR_1884 :Every 2 hours +STR_1885 :Never +STR_1886 :Inspecting {STRINGID} +STR_1887 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}{COMMA16} minutes +STR_1888 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}more than 4 hours +STR_1889 :{WINDOW_COLOUR_2}Down-Time: {MOVE_X}{255}{BLACK}{COMMA16}% +STR_1890 :{SMALLFONT}{BLACK}Select how often a mechanic should check this ride +STR_1891 :No {STRINGID} in park yet! +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 : +STR_1893 : +STR_1894 :{WINDOW_COLOUR_2}{STRINGID} sold: {BLACK}{COMMA32} +STR_1895 :{SMALLFONT}{BLACK}Build new ride/attraction +STR_1896 :{WINDOW_COLOUR_2}Expenditure/Income +STR_1897 :{WINDOW_COLOUR_2}Ride construction +STR_1898 :{WINDOW_COLOUR_2}Ride running costs +STR_1899 :{WINDOW_COLOUR_2}Land purchase +STR_1900 :{WINDOW_COLOUR_2}Landscaping +STR_1901 :{WINDOW_COLOUR_2}Park entrance tickets +STR_1902 :{WINDOW_COLOUR_2}Ride tickets +STR_1903 :{WINDOW_COLOUR_2}Shop sales +STR_1904 :{WINDOW_COLOUR_2}Shop stock +STR_1905 :{WINDOW_COLOUR_2}Food/drink sales +STR_1906 :{WINDOW_COLOUR_2}Food/drink stock +STR_1907 :{WINDOW_COLOUR_2}Staff wages +STR_1908 :{WINDOW_COLOUR_2}Marketing +STR_1909 :{WINDOW_COLOUR_2}Research +STR_1910 :{WINDOW_COLOUR_2}Loan interest +STR_1911 :{BLACK} at {COMMA16}% per year +STR_1912 :{MONTH} +STR_1913 :{BLACK}+{CURRENCY2DP} +STR_1914 :{BLACK}{CURRENCY2DP} +STR_1915 :{RED}{CURRENCY2DP} +STR_1916 :{WINDOW_COLOUR_2}Loan: +STR_1917 :{POP16}{POP16}{POP16}{CURRENCY} +STR_1918 :Can't borrow any more money! +STR_1919 :Not enough cash available! +STR_1920 :Can't pay back loan! +STR_1921 :{SMALLFONT}{BLACK}Start a new game +STR_1922 :{SMALLFONT}{BLACK}Continue playing a saved game +STR_1923 :{SMALLFONT}{BLACK}Show tutorial +STR_1924 :{SMALLFONT}{BLACK}Exit +STR_1925 :Can't place person here... +STR_1926 :{SMALLFONT} +STR_1927 :{YELLOW}{STRINGID} has broken down +STR_1928 :{RED}{STRINGID} has crashed! +STR_1929 :{RED}{STRINGID} still hasn't been fixed{NEWLINE}Check where your mechanics are and consider organizing them better +STR_1930 :{SMALLFONT}{BLACK}Turn on/off tracking information for this guest - (If tracking is on, guest's movements will be reported in the message area) +STR_1931 :{STRINGID} has joined the queue line for {STRINGID} +STR_1932 :{STRINGID} is on {STRINGID} +STR_1933 :{STRINGID} is in {STRINGID} +STR_1934 :{STRINGID} has left {STRINGID} +STR_1935 :{STRINGID} has left the park +STR_1936 :{STRINGID} has bought {STRINGID} +STR_1937 :{SMALLFONT}{BLACK}Show information about the subject of this message +STR_1938 :{SMALLFONT}{BLACK}Show view of guest +STR_1939 :{SMALLFONT}{BLACK}Show view of staff member +STR_1940 :{SMALLFONT}{BLACK}Show happiness, energy, hunger etc. for this guest +STR_1941 :{SMALLFONT}{BLACK}Show which rides this guest has been on +STR_1942 :{SMALLFONT}{BLACK}Show financial information about this guest +STR_1943 :{SMALLFONT}{BLACK}Show guest's recent thoughts +STR_1944 :{SMALLFONT}{BLACK}Show items guest is carrying +STR_1945 :{SMALLFONT}{BLACK}Show orders and options for this staff member +STR_1946 :{SMALLFONT}{BLACK}Select costume for this entertainer +STR_1947 :{SMALLFONT}{BLACK}Show areas patrolled by selected staff type, and locate the nearest staff member +STR_1948 :{SMALLFONT}{BLACK}Hire a new staff member of the selected type +STR_1949 :Financial Summary +STR_1950 :Financial Graph +STR_1951 :Park Value Graph +STR_1952 :Profit Graph +STR_1953 :Marketing +STR_1954 :Research Funding +STR_1955 :{WINDOW_COLOUR_2}Number of circuits: +STR_1956 :{SMALLFONT}{BLACK}Number of circuits of track per ride +STR_1957 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} +STR_1958 :{COMMA16} +STR_1959 :Can't change number of circuits... +STR_1960 :{WINDOW_COLOUR_2}Balloon price: +STR_1961 :{WINDOW_COLOUR_2}Cuddly Toy price: +STR_1962 :{WINDOW_COLOUR_2}Park Map price: +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}Chips price: +STR_1968 :{WINDOW_COLOUR_2}Ice Cream price: +STR_1969 :{WINDOW_COLOUR_2}Candyfloss price: +STR_1970 :{WINDOW_COLOUR_2} +STR_1971 :{WINDOW_COLOUR_2} +STR_1972 :{WINDOW_COLOUR_2} +STR_1973 :{WINDOW_COLOUR_2}Pizza price: +STR_1974 :{WINDOW_COLOUR_2} +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}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: +STR_1983 :{WINDOW_COLOUR_2} +STR_1984 :{WINDOW_COLOUR_2}Fried Chicken price: +STR_1985 :{WINDOW_COLOUR_2}Lemonade price: +STR_1986 :{WINDOW_COLOUR_2} +STR_1987 :{WINDOW_COLOUR_2} +STR_1988 :Balloon +STR_1989 :Cuddly Toy +STR_1990 :Park Map +STR_1991 :On-Ride Photo +STR_1992 :Umbrella +STR_1993 :Drink +STR_1994 :Burger +STR_1995 :Chips +STR_1996 :Ice Cream +STR_1997 :Candyfloss +STR_1998 :Empty Can +STR_1999 :Rubbish +STR_2000 :Empty Burger Box +STR_2001 :Pizza +STR_2002 :Voucher +STR_2003 :Popcorn +STR_2004 :Hot Dog +STR_2005 :Tentacle +STR_2006 :Hat +STR_2007 :Toffee Apple +STR_2008 :T-Shirt +STR_2009 :Doughnut +STR_2010 :Coffee +STR_2011 :Empty Cup +STR_2012 :Fried Chicken +STR_2013 :Lemonade +STR_2014 :Empty Box +STR_2015 :Empty Bottle +STR_2016 :Balloons +STR_2017 :Cuddly Toys +STR_2018 :Park Maps +STR_2019 :On-Ride Photos +STR_2020 :Umbrellas +STR_2021 :Drinks +STR_2022 :Burgers +STR_2023 :Chips +STR_2024 :Ice Creams +STR_2025 :Candyfloss +STR_2026 :Empty Cans +STR_2027 :Rubbish +STR_2028 :Empty Burger Boxes +STR_2029 :Pizzas +STR_2030 :Vouchers +STR_2031 :Popcorn +STR_2032 :Hot Dogs +STR_2033 :Tentacles +STR_2034 :Hats +STR_2035 :Toffee Apples +STR_2036 :T-Shirts +STR_2037 :Doughnuts +STR_2038 :Coffees +STR_2039 :Empty Cups +STR_2040 :Fried Chicken +STR_2041 :Lemonade +STR_2042 :Empty Boxes +STR_2043 :Empty Bottles +STR_2044 :a Balloon +STR_2045 :a Cuddly Toy +STR_2046 :a Park Map +STR_2047 :an On-Ride Photo +STR_2048 :an Umbrella +STR_2049 :a Drink +STR_2050 :a Burger +STR_2051 :some Chips +STR_2052 :an Ice Cream +STR_2053 :some Candyfloss +STR_2054 :an Empty Can +STR_2055 :some Rubbish +STR_2056 :an Empty Burger Box +STR_2057 :a Pizza +STR_2058 :a Voucher +STR_2059 :some Popcorn +STR_2060 :a Hot Dog +STR_2061 :a Tentacle +STR_2062 :a Hat +STR_2063 :a Toffee Apple +STR_2064 :a T-Shirt +STR_2065 :a Doughnut +STR_2066 :a Coffee +STR_2067 :an Empty Cup +STR_2068 :some Fried Chicken +STR_2069 :some Lemonade +STR_2070 :an Empty Box +STR_2071 :an Empty Bottle +STR_2072 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Balloon +STR_2073 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Cuddly Toy +STR_2074 :Map of {STRINGID} +STR_2075 :On-Ride Photo of {STRINGID} +STR_2076 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Umbrella +STR_2077 :Drink +STR_2078 :Burger +STR_2079 :Chips +STR_2080 :Ice Cream +STR_2081 :Candyfloss +STR_2082 :Empty Can +STR_2083 :Rubbish +STR_2084 :Empty Burger Box +STR_2085 :Pizza +STR_2086 :Voucher for {STRINGID} +STR_2087 :Popcorn +STR_2088 :Hot Dog +STR_2089 :Tentacle +STR_2090 :{OPENQUOTES}{STRINGID}{ENDQUOTES} Hat +STR_2091 :Toffee Apple +STR_2092 :{OPENQUOTES}{STRINGID}{ENDQUOTES} T-Shirt +STR_2093 :Doughnut +STR_2094 :Coffee +STR_2095 :Empty Cup +STR_2096 :Fried Chicken +STR_2097 :Lemonade +STR_2098 :Empty Box +STR_2099 :Empty Bottle +STR_2100 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_2101 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_2102 :{WINDOW_COLOUR_2}On-Ride Photo price: +STR_2103 :{WINDOW_COLOUR_2}Pretzel price: +STR_2104 :{WINDOW_COLOUR_2}Hot Chocolate price: +STR_2105 :{WINDOW_COLOUR_2}Iced Tea price: +STR_2106 :{WINDOW_COLOUR_2}Funnel Cake price: +STR_2107 :{WINDOW_COLOUR_2}Sunglasses price: +STR_2108 :{WINDOW_COLOUR_2}Beef Noodles price: +STR_2109 :{WINDOW_COLOUR_2}Fried Rice Noodles price: +STR_2110 :{WINDOW_COLOUR_2}Wonton Soup price: +STR_2111 :{WINDOW_COLOUR_2}Meatball Soup price: +STR_2112 :{WINDOW_COLOUR_2}Fruit Juice price: +STR_2113 :{WINDOW_COLOUR_2}Soybean Milk price: +STR_2114 :{WINDOW_COLOUR_2}Sujongkwa price: +STR_2115 :{WINDOW_COLOUR_2}Sub Sandwich price: +STR_2116 :{WINDOW_COLOUR_2}Cookie price: +STR_2117 :{WINDOW_COLOUR_2} +STR_2118 :{WINDOW_COLOUR_2} +STR_2119 :{WINDOW_COLOUR_2} +STR_2120 :{WINDOW_COLOUR_2}Roast Sausage price: +STR_2121 :{WINDOW_COLOUR_2} +STR_2122 :On-Ride Photo +STR_2123 :On-Ride Photo +STR_2124 :On-Ride Photo +STR_2125 :Pretzel +STR_2126 :Hot Chocolate +STR_2127 :Iced Tea +STR_2128 :Funnel Cake +STR_2129 :Sunglasses +STR_2130 :Beef Noodles +STR_2131 :Fried Rice Noodles +STR_2132 :Wonton Soup +STR_2133 :Meatball Soup +STR_2134 :Fruit Juice +STR_2135 :Soybean Milk +STR_2136 :Sujongkwa +STR_2137 :Sub Sandwich +STR_2138 :Cookie +STR_2139 :Empty Bowl +STR_2140 :Empty Drink Carton +STR_2141 :Empty Juice Cup +STR_2142 :Roast Sausage +STR_2143 :Empty Bowl +STR_2144 :On-Ride Photos +STR_2145 :On-Ride Photos +STR_2146 :On-Ride Photos +STR_2147 :Pretzels +STR_2148 :Hot Chocolates +STR_2149 :Iced Teas +STR_2150 :Funnel Cakes +STR_2151 :Sunglasses +STR_2152 :Beef Noodles +STR_2153 :Fried Rice Noodles +STR_2154 :Wonton Soups +STR_2155 :Meatball Soups +STR_2156 :Fruit Juices +STR_2157 :Soybean Milks +STR_2158 :Sujongkwa +STR_2159 :Sub Sandwiches +STR_2160 :Cookies +STR_2161 :Empty Bowls +STR_2162 :Empty Drink Cartons +STR_2163 :Empty Juice cups +STR_2164 :Roast Sausages +STR_2165 :Empty Bowls +STR_2166 :an On-Ride Photo +STR_2167 :an On-Ride Photo +STR_2168 :an On-Ride Photo +STR_2169 :a Pretzel +STR_2170 :a Hot Chocolate +STR_2171 :an Iced Tea +STR_2172 :a Funnel Cake +STR_2173 :a pair of Sunglasses +STR_2174 :some Beef Noodles +STR_2175 :some Fried Rice Noodles +STR_2176 :some Wonton Soup +STR_2177 :some Meatball Soup +STR_2178 :a Fruit Juice +STR_2179 :some Soybean Milk +STR_2180 :some Sujongkwa +STR_2181 :a Sub Sandwich +STR_2182 :a Cookie +STR_2183 :an Empty Bowl +STR_2184 :an Empty Drink Carton +STR_2185 :an Empty Juice Cup +STR_2186 :a Roast Sausage +STR_2187 :an Empty Bowl +STR_2188 :On-Ride Photo of {STRINGID} +STR_2189 :On-Ride Photo of {STRINGID} +STR_2190 :On-Ride Photo of {STRINGID} +STR_2191 :Pretzel +STR_2192 :Hot Chocolate +STR_2193 :Iced Tea +STR_2194 :Funnel Cake +STR_2195 :Sunglasses +STR_2196 :Beef Noodles +STR_2197 :Fried Rice Noodles +STR_2198 :Wonton Soup +STR_2199 :Meatball Soup +STR_2200 :Fruit Juice +STR_2201 :Soybean Milk +STR_2202 :Sujongkwa +STR_2203 :Sub Sandwich +STR_2204 :Cookie +STR_2205 :Empty Bowl +STR_2206 :Empty Drink Carton +STR_2207 :Empty Juice Cup +STR_2208 :Roast Sausage +STR_2209 :Empty Bowl +STR_2210 :{SMALLFONT}{BLACK}Show list of handymen in park +STR_2211 :{SMALLFONT}{BLACK}Show list of mechanics in park +STR_2212 :{SMALLFONT}{BLACK}Show list of security guards in park +STR_2213 :{SMALLFONT}{BLACK}Show list of entertainers in park +STR_2214 :Construction not possible while game is paused! +STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) +STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F +STR_2218 :{RED}{STRINGID} on {STRINGID} hasn't returned to the {STRINGID} yet!{NEWLINE}Check whether it is stuck or has stalled +STR_2219 :{RED}{COMMA16} people have died in an accident on {STRINGID} +STR_2220 :{WINDOW_COLOUR_2}Park Rating: {BLACK}{COMMA16} +STR_2221 :{SMALLFONT}{BLACK}Park Rating: {COMMA16} +STR_2222 :{SMALLFONT}{BLACK}{STRINGID} +STR_2223 :{WINDOW_COLOUR_2}Guests in park: {BLACK}{COMMA16} +STR_2224 :{WINDOW_COLOUR_2}Cash: {BLACK}{CURRENCY2DP} +STR_2225 :{WINDOW_COLOUR_2}Cash: {RED}{CURRENCY2DP} +STR_2226 :{WINDOW_COLOUR_2}Park value: {BLACK}{CURRENCY} +STR_2227 :{WINDOW_COLOUR_2}Company value: {BLACK}{CURRENCY} +STR_2228 :{WINDOW_COLOUR_2}Last month's profit from food/drink and{NEWLINE}merchandise sales: {BLACK}{CURRENCY} +STR_2229 :Slope up to vertical +STR_2230 :Vertical track +STR_2231 :Holding brake for drop +STR_2232 :Cable lift hill +STR_2233 :{SMALLFONT}{BLACK}Park information +STR_2234 :Recent Messages +STR_2235 :{SMALLFONT}{STRINGID} {STRINGID} +STR_2236 :January +STR_2237 :February +STR_2238 :March +STR_2239 :April +STR_2240 :May +STR_2241 :June +STR_2242 :July +STR_2243 :August +STR_2244 :September +STR_2245 :October +STR_2246 :November +STR_2247 :December +STR_2248 :Can't demolish ride/attraction... +STR_2249 :{BABYBLUE}New ride/attraction now available:{NEWLINE}{STRINGID} +STR_2250 :{BABYBLUE}New scenery/themeing now available:{NEWLINE}{STRINGID} +STR_2251 :Can only be built on paths! +STR_2252 :Can only be built across paths! +STR_2253 :Transport Rides +STR_2254 :Gentle Rides +STR_2255 :Roller Coasters +STR_2256 :Thrill Rides +STR_2257 :Water Rides +STR_2258 :Shops & Stalls +STR_2259 :Scenery & Themeing +STR_2260 :No funding +STR_2261 :Minimum funding +STR_2262 :Normal funding +STR_2263 :Maximum funding +STR_2264 :Research funding +STR_2265 :{WINDOW_COLOUR_2}Cost: {BLACK}{CURRENCY} per month +STR_2266 :Research priorities +STR_2267 :Currently in development +STR_2268 :Last development +STR_2269 :{WINDOW_COLOUR_2}Type: {BLACK}{STRINGID} +STR_2270 :{WINDOW_COLOUR_2}Progress: {BLACK}{STRINGID} +STR_2271 :{WINDOW_COLOUR_2}Expected: {BLACK}{STRINGID} +STR_2272 :{WINDOW_COLOUR_2}Ride/attraction:{NEWLINE}{BLACK}{STRINGID} +STR_2273 :{WINDOW_COLOUR_2}Scenery/themeing:{NEWLINE}{BLACK}{STRINGID} +STR_2274 :{SMALLFONT}{BLACK}Show details of this invention or development +STR_2275 :{SMALLFONT}{BLACK}Show funding and options for research & development +STR_2276 :{SMALLFONT}{BLACK}Show research & development status +STR_2277 :Unknown +STR_2278 :Transport Ride +STR_2279 :Gentle Ride +STR_2280 :Roller Coaster +STR_2281 :Thrill Ride +STR_2282 :Water Ride +STR_2283 :Shop/Stall +STR_2284 :Scenery/Themeing +STR_2285 :Initial research +STR_2286 :Designing +STR_2287 :Completing design +STR_2288 :Unknown +STR_2289 :{STRINGID} {STRINGID} +STR_2290 :{SMALLFONT}{BLACK}{STRINGID} {STRINGID} +STR_2291 :Select scenario for new game +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 +STR_2305 :Track design files +STR_2306 :Save track design +STR_2307 :Select {STRINGID} design +STR_2308 :{STRINGID} Track Designs +STR_2309 :Install New Track Design +STR_2310 :Build custom design +STR_2311 :{WINDOW_COLOUR_2}Excitement rating: {BLACK}{COMMA2DP32} (approx.) +STR_2312 :{WINDOW_COLOUR_2}Intensity rating: {BLACK}{COMMA2DP32} (approx.) +STR_2313 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}{COMMA2DP32} (approx.) +STR_2314 :{WINDOW_COLOUR_2}Ride length: {BLACK}{STRINGID} +STR_2315 :{WINDOW_COLOUR_2}Cost: {BLACK}around {CURRENCY} +STR_2316 :{WINDOW_COLOUR_2}Space required: {BLACK}{COMMA16} x {COMMA16} blocks +STR_2317 : +STR_2318 : +STR_2319 : +STR_2320 : +STR_2321 :{WINDOW_COLOUR_2}Number of rides/attractions: {BLACK}{COMMA16} +STR_2322 :{WINDOW_COLOUR_2}Staff: {BLACK}{COMMA16} +STR_2323 :{WINDOW_COLOUR_2}Park size: {BLACK}{COMMA32}m{SQUARED} +STR_2324 :{WINDOW_COLOUR_2}Park size: {BLACK}{COMMA32}sq.ft. +STR_2325 :{SMALLFONT}{BLACK}Buy land to extend park +STR_2326 :{SMALLFONT}{BLACK}Buy construction rights to allow construction above or below land outside the park +STR_2327 :Options +STR_2328 :{WINDOW_COLOUR_2}Currency: +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_2334 :Pounds ({POUND}) +STR_2335 :Dollars ($) +STR_2336 :Franc (F) +STR_2337 :Deutschmark (DM) +STR_2338 :Yen ({YEN}) +STR_2339 :Peseta (Pts) +STR_2340 :Lira (L) +STR_2341 :Guilders (fl.) +STR_2342 :Krona (kr) +STR_2343 :Euros ({EURO}) +STR_2344 :Imperial +STR_2345 :Metric +STR_2346 :Display +STR_2347 :{RED}{STRINGID} has drowned! +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 +STR_2358 :Units +STR_2359 :Real Values +STR_2360 :{WINDOW_COLOUR_2}Display Resolution: +STR_2361 :Landscape Smoothing +STR_2362 :{SMALLFONT}{BLACK}Toggle landscape tile edge smoothing on/off +STR_2363 :Gridlines on Landscape +STR_2364 :{SMALLFONT}{BLACK}Toggle gridlines on landscape on/off +STR_2365 :The bank refuses to increase your loan! +STR_2366 :Celsius ({DEGREE}C) +STR_2367 :Fahrenheit ({DEGREE}F) +STR_2368 :None +STR_2369 :Low +STR_2370 :Average +STR_2371 :High +STR_2372 :Low +STR_2373 :Medium +STR_2374 :High +STR_2375 :Very high +STR_2376 :Extreme +STR_2377 :Ultra-Extreme +STR_2378 :{SMALLFONT}{BLACK}Adjust smaller area of land +STR_2379 :{SMALLFONT}{BLACK}Adjust larger area of land +STR_2380 :{SMALLFONT}{BLACK}Adjust smaller area of water +STR_2381 :{SMALLFONT}{BLACK}Adjust larger area of water +STR_2382 :Land +STR_2383 :Water +STR_2384 :{WINDOW_COLOUR_2}Your objective: +STR_2385 :{BLACK}None +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! +STR_2389 :{BLACK}Build the best {STRINGID} you can! +STR_2390 :{BLACK}To have 10 different types of roller coasters operating in your park, each with an excitement value of at least 6.00 +STR_2391 :{BLACK}To have at least {COMMA16} guests in your park. You must not let the park rating drop below 700 at any time! +STR_2392 :{BLACK}To achieve a monthly income from ride tickets of at least {POP16}{POP16}{CURRENCY} +STR_2393 :{BLACK}To have 10 different types of roller coasters operating in your park, each with a minimum length of {LENGTH}, and an excitement rating of at least 7.00 +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_2398 :Number of guests at a given date +STR_2399 :Park value at a given date +STR_2400 :Have fun +STR_2401 :Build the best ride you can +STR_2402 :Build 10 roller coasters +STR_2403 :Number of guests in park +STR_2404 :Monthly income from ride tickets +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 : +STR_2438 : +STR_2439 : +STR_2440 : +STR_2441 : +STR_2442 : +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 +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} - +STR_2455 :{SMALLFONT}{BLACK}+{CURRENCY2DP} - +STR_2456 :{SMALLFONT}{BLACK}{CURRENCY2DP} - +STR_2457 :{SMALLFONT}{BLACK}Show financial accounts +STR_2458 :{SMALLFONT}{BLACK}Show graph of cash (less loan) over time +STR_2459 :{SMALLFONT}{BLACK}Show graph of park value over time +STR_2460 :{SMALLFONT}{BLACK}Show graph of weekly profit +STR_2461 :{SMALLFONT}{BLACK}Show marketing campaigns +STR_2462 :{SMALLFONT}{BLACK}Show view of park entrance +STR_2463 :{SMALLFONT}{BLACK}Show graph of park ratings over time +STR_2464 :{SMALLFONT}{BLACK}Show graph of guest numbers over time +STR_2465 :{SMALLFONT}{BLACK}Show park entrance price and information +STR_2466 :{SMALLFONT}{BLACK}Show park statistics +STR_2467 :{SMALLFONT}{BLACK}Show objectives for this game +STR_2468 :{SMALLFONT}{BLACK}Show recent awards this park has received +STR_2469 :{SMALLFONT}{BLACK}Select level of research & development +STR_2470 :{SMALLFONT}{BLACK}Research new transport rides +STR_2471 :{SMALLFONT}{BLACK}Research new gentle rides +STR_2472 :{SMALLFONT}{BLACK}Research new roller coasters +STR_2473 :{SMALLFONT}{BLACK}Research new thrill rides +STR_2474 :{SMALLFONT}{BLACK}Research new water rides +STR_2475 :{SMALLFONT}{BLACK}Research new shops and stalls +STR_2476 :{SMALLFONT}{BLACK}Research new scenery and themeing +STR_2477 :{SMALLFONT}{BLACK}Select operating mode for this ride/attraction +STR_2478 :{SMALLFONT}{BLACK}Show graph of velocity against time +STR_2479 :{SMALLFONT}{BLACK}Show graph of altitude against time +STR_2480 :{SMALLFONT}{BLACK}Show graph of vertical acceleration against time +STR_2481 :{SMALLFONT}{BLACK}Show graph of lateral acceleration against time +STR_2482 :{SMALLFONT}{BLACK}Profit: {CURRENCY} per week, Park Value: {CURRENCY} +STR_2483 :{WINDOW_COLOUR_2}Weekly profit: {BLACK}+{CURRENCY2DP} +STR_2484 :{WINDOW_COLOUR_2}Weekly profit: {RED}{CURRENCY2DP} +STR_2485 :Controls +STR_2486 :General +STR_2487 :Show 'real' names of guests +STR_2488 :{SMALLFONT}{BLACK}Toggle between showing 'real' names of guests and guest numbers +STR_2489 :Shortcut keys... +STR_2490 :Keyboard shortcuts +STR_2491 :Reset keys +STR_2492 :{SMALLFONT}{BLACK}Set all keyboard shortcuts back to default settings +STR_2493 :Close top-most window +STR_2494 :Close all floating windows +STR_2495 :Cancel construction mode +STR_2496 :Pause game +STR_2497 :Zoom view out +STR_2498 :Zoom view in +STR_2499 :Rotate view clockwise +STR_2500 :Rotate construction object +STR_2501 :Underground view toggle +STR_2502 :Remove base land toggle +STR_2503 :Remove vertical land toggle +STR_2504 :See-through rides toggle +STR_2505 :See-through scenery toggle +STR_2506 :Invisible supports toggle +STR_2507 :Invisible people toggle +STR_2508 :Height marks on land toggle +STR_2509 :Height marks on ride tracks toggle +STR_2510 :Height marks on paths toggle +STR_2511 :Adjust land +STR_2512 :Adjust water +STR_2513 :Build scenery +STR_2514 :Build paths +STR_2515 :Build new ride +STR_2516 :Show financial information +STR_2517 :Show research information +STR_2518 :Show rides list +STR_2519 :Show park information +STR_2520 :Show guest list +STR_2521 :Show staff list +STR_2522 :Show recent messages +STR_2523 :Show map +STR_2524 :Screenshot +### The following need to be reordered to match SDL_keycode layout. +STR_2525 :??? +STR_2526 :??? +STR_2527 :??? +STR_2528 :??? +STR_2529 :??? +STR_2530 :??? +STR_2531 :??? +STR_2532 :??? +STR_2533 :Backspace +STR_2534 :Tab +STR_2535 :??? +STR_2536 :??? +STR_2537 :Clear +STR_2538 :Return +STR_2539 :??? +STR_2540 :??? +STR_2541 :??? +STR_2542 :??? +STR_2543 :Alt/Menu +STR_2544 :Pause +STR_2545 :Caps +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 :Spacebar +STR_2558 :PgUp +STR_2559 :PgDn +STR_2560 :End +STR_2561 :Home +STR_2562 :Left +STR_2563 :Up +STR_2564 :Right +STR_2565 :Down +STR_2566 :Select +STR_2567 :Print +STR_2568 :Execute +STR_2569 :Snapshot +STR_2570 :Insert +STR_2571 :Delete +STR_2572 :Help +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 :NumPad 0 +STR_2622 :NumPad 1 +STR_2623 :NumPad 2 +STR_2624 :NumPad 3 +STR_2625 :NumPad 4 +STR_2626 :NumPad 5 +STR_2627 :NumPad 6 +STR_2628 :NumPad 7 +STR_2629 :NumPad 8 +STR_2630 :NumPad 9 +STR_2631 :NumPad * +STR_2632 :NumPad + +STR_2633 :??? +STR_2634 :NumPad - +STR_2635 :NumPad . +STR_2636 :NumPad / +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 :NumLock +STR_2670 :Scroll +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 {CURRENCY} +STR_2682 : +STR_2683 : +STR_2684 :{SMALLFONT}{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 minute +STR_2702 :Every 5 minutes +STR_2703 :Every 15 minutes +STR_2704 :Every 30 minutes +STR_2705 :Every hour +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}, 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 :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 :+{CURRENCY} +STR_2761 : +STR_2762 : +STR_2763 :??? +STR_2764 : +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 +# End of new strings +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} +STR_2782 :SHIFT + +STR_2783 :CTRL + +STR_2784 :Change keyboard shortcut +STR_2785 :{WINDOW_COLOUR_2}Press new shortcut key for:{NEWLINE}{OPENQUOTES}{STRINGID}{ENDQUOTES} +STR_2786 :{SMALLFONT}{BLACK}Click on shortcut description to select new key +STR_2787 :{WINDOW_COLOUR_2}Park value: {BLACK}{CURRENCY} +STR_2788 :{WINDOW_COLOUR_2}Congratulations !{NEWLINE}{BLACK}You achieved your objective with a company value of {CURRENCY} ! +STR_2789 :{WINDOW_COLOUR_2}You have failed your objective ! +STR_2790 :Enter name into scenario chart +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_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_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 +STR_2806 :{RED}Guests are complaining about the disgusting state of the paths in your park{NEWLINE}Check where your handymen are and consider organising them better +STR_2807 :{RED}Guests are complaining about the amount of litter in your park{NEWLINE}Check where your handymen are and consider organising them better +STR_2808 :{RED}Guests are complaining about the vandalism in your park{NEWLINE}Check where your security guards are and consider organising 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 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 +STR_2815 :{WINDOW_COLOUR_2}Tidiest park award +STR_2816 :{WINDOW_COLOUR_2}Award for the park with the best roller coasters +STR_2817 :{WINDOW_COLOUR_2}Best value park award +STR_2818 :{WINDOW_COLOUR_2}Most beautiful park award +STR_2819 :{WINDOW_COLOUR_2}Worst value park award +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 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 +STR_2828 :{WINDOW_COLOUR_2}Most dazzling ride colour schemes award +STR_2829 :{WINDOW_COLOUR_2}Most confusing park layout award +STR_2830 :{WINDOW_COLOUR_2}Best gentle ride award +STR_2831 :{TOPAZ}Your park has received an award for being 'The most untidy park in the country'! +STR_2832 :{TOPAZ}Your park has received an award for being 'The tidiest park in the country'! +STR_2833 :{TOPAZ}Your park has received an award for being 'The park with the best roller coasters'! +STR_2834 :{TOPAZ}Your park has received an award for being 'The best value park in the country'! +STR_2835 :{TOPAZ}Your park has received an award for being 'The most beautiful park in the country'! +STR_2836 :{TOPAZ}Your park has received an award for being 'The worst value park in the country'! +STR_2837 :{TOPAZ}Your park has received an award for being 'The safest park in the country'! +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 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'! +STR_2845 :{TOPAZ}Your park has received an award for being 'The park with the most dazzling choice of colour schemes'! +STR_2846 :{TOPAZ}Your park has received an award for being 'The park with the most confusing layout'! +STR_2847 :{TOPAZ}Your park has received an award for being 'The park with the best gentle rides'! +STR_2848 :{WINDOW_COLOUR_2}No recent awards +STR_2849 :New scenario installed successfully +STR_2850 :New track design installed successfully +STR_2851 :Scenario already installed +STR_2852 :Track design already installed +STR_2853 :Forbidden by the local authority! +STR_2854 :{RED}Guests can't get to the entrance of {STRINGID} !{NEWLINE}Construct a path to the entrance +STR_2855 :{RED}{STRINGID} has no path leading from its exit !{NEWLINE}Construct a path from the ride exit +STR_2856 :{WINDOW_COLOUR_2}Tutorial +STR_2857 :{WINDOW_COLOUR_2}(Press a key or mouse button to take control) +STR_2858 :Can't start marketing campaign... +STR_2859 :Another instance of OpenRCT2 is already running +STR_2860 :Infogrames Interactive credits... +STR_2861 :{WINDOW_COLOUR_2}Licensed to Infogrames Interactive Inc. +STR_2862 :Music acknowledgements... +STR_2863 :Music acknowledgements +STR_2864 :{WINDOW_COLOUR_2}March - Children of the Regiment: (Fucik) non copyright +STR_2865 :{WINDOW_COLOUR_2}Heyken's Serenade: (J.Heyken) British Standard Music Coy; GEMA, BRITICO +STR_2866 :{WINDOW_COLOUR_2}In Continental Mood: (Composer unknown) Copyright Control +STR_2867 :{WINDOW_COLOUR_2}Wedding Journey: (Traditional) +STR_2868 :{WINDOW_COLOUR_2}Tales from the Vienna Woods: (Johann Strauss) non copyright +STR_2869 :{WINDOW_COLOUR_2}Slavonic Dance: (Traditional) +STR_2870 :{WINDOW_COLOUR_2}Das Alpenhorn: (Traditional) +STR_2871 :{WINDOW_COLOUR_2}The Blond Sailor: (Traditional) +STR_2872 :{WINDOW_COLOUR_2}Overture - Poet and Peasant: (Suppe) non copyright +STR_2873 :{WINDOW_COLOUR_2}Waltz Medley: (Johann Strauss) non copyright +STR_2874 :{WINDOW_COLOUR_2}Bella Bella Bimba: (Traditional) +STR_2875 :{WINDOW_COLOUR_2}Original recordings (P) 1976 C.J.Mears Organization, used with consent +STR_2876 :{WINDOW_COLOUR_2}RollerCoaster Tycoon 2 Title Music: (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, played by Peter James Adcock) recording {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}Senior Producer: Thomas J. Zahorik +STR_2910 :{WINDOW_COLOUR_2}Executive Producer: Bill Levay +STR_2911 :{WINDOW_COLOUR_2}Senior Marketing Product Manager: Scott Triola +STR_2912 :{WINDOW_COLOUR_2}V.P. of Product Development: Scott Walker +STR_2913 :{WINDOW_COLOUR_2}General Manager: John Hurlbut +STR_2914 :{WINDOW_COLOUR_2}Director of Quality Assurance: Michael Craighead +STR_2915 :{WINDOW_COLOUR_2}Q.A. Certification Manager: Kurt Boutin +STR_2916 :{WINDOW_COLOUR_2}Q.A. Certification Lead: Mark Huggins +STR_2917 :{WINDOW_COLOUR_2}Testers: Dena Irene Fitzgerald, Scott Rollins, Christopher McPhail +STR_2918 :{WINDOW_COLOUR_2}Clif McClure, Erik Maramaldi, Erik Jeffery +STR_2919 :{WINDOW_COLOUR_2}Director of Marketing: Ann Marie Bland +STR_2920 :{WINDOW_COLOUR_2}Manager of Creative Services: Steve Martin +STR_2921 :{WINDOW_COLOUR_2}Manager of Editorial & Documentation Services: Elizabeth Mackney +STR_2922 :{WINDOW_COLOUR_2}Graphic Designer: Paul Anselmi +STR_2923 :{WINDOW_COLOUR_2}Copywriter: Kurt Carlson +STR_2924 :{WINDOW_COLOUR_2}Special Thanks to: Peter Matiss +STR_2925 :{WINDOW_COLOUR_2}Engineering Specialist: Ken Edwards +STR_2926 :{WINDOW_COLOUR_2}Engineering Services Manager: Luis Rivas +STR_2927 :{WINDOW_COLOUR_2}Lead Compatibility Analyst: Geoffrey Smith +STR_2928 :{WINDOW_COLOUR_2}Compatibility Analysts: Jason Cordero, Burke McQuinn, Kim Jardin +STR_2929 :{WINDOW_COLOUR_2}Lead Tester: Daniel Frisoli +STR_2930 :{WINDOW_COLOUR_2}Senior Tester: 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 : +STR_2970 : +STR_2971 :Main colour scheme +STR_2972 :Alternative colour scheme 1 +STR_2973 :Alternative colour scheme 2 +STR_2974 :Alternative colour scheme 3 +STR_2975 :{SMALLFONT}{BLACK}Select which colour scheme to change, or paint ride with +STR_2976 :{SMALLFONT}{BLACK}Paint an individual area of this ride using the selected colour scheme +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_2982 :Banner text +STR_2983 :Enter new text for this banner: +STR_2984 :Can't set new text for banner... +STR_2985 :Banner +STR_2986 :{SMALLFONT}{BLACK}Change text on banner +STR_2987 :{SMALLFONT}{BLACK}Set this banner as a 'no-entry' sign for guests +STR_2988 :{SMALLFONT}{BLACK}Demolish this banner +STR_2989 :{SMALLFONT}{BLACK}Select main colour +STR_2990 :{SMALLFONT}{BLACK}Select text colour +STR_2991 :Sign +STR_2992 :Sign text +STR_2993 :Enter new text for this sign: +STR_2994 :{SMALLFONT}{BLACK}Change text on sign +STR_2995 :{SMALLFONT}{BLACK}Demolish this sign +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 :Unable to load file... +STR_3011 :File contains invalid data +STR_3012 :Dodgems beat style +STR_3013 :Fairground organ style +STR_3014 :Roman fanfare style +STR_3015 :Oriental style +STR_3016 :Martian style +STR_3017 :Jungle drums style +STR_3018 :Egyptian style +STR_3019 :Toyland style +STR_3020 : +STR_3021 :Space style +STR_3022 :Horror style +STR_3023 :Techno style +STR_3024 :Gentle style +STR_3025 :Summer style +STR_3026 :Water style +STR_3027 :Wild west style +STR_3028 :Jurassic style +STR_3029 :Rock style +STR_3030 :Ragtime style +STR_3031 :Fantasy style +STR_3032 :Rock style 2 +STR_3033 :Ice style +STR_3034 :Snow style +STR_3035 :Custom music 1 +STR_3036 :Custom music 2 +STR_3037 :Medieval style +STR_3038 :Urban style +STR_3039 :Organ style +STR_3040 :Mechanical style +STR_3041 :Modern style +STR_3042 :Pirates style +STR_3043 :Rock style 3 +STR_3044 :Candy style +STR_3045 :{SMALLFONT}{BLACK}Select style of music to play +STR_3046 :This ride cannot be modified +STR_3047 :Local authority forbids demolition or modifications to this ride +STR_3048 :Marketing campaigns forbidden by local authority +STR_3049 :Golf hole A +STR_3050 :Golf hole B +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_3057 :{WINDOW_COLOUR_2}Construction Marker: +STR_3058 :Brick walls +STR_3059 :Hedges +STR_3060 :Ice blocks +STR_3061 :Wooden fences +STR_3062 :{SMALLFONT}{BLACK}Standard roller coaster track +STR_3063 :{SMALLFONT}{BLACK}Water channel (track submerged) +STR_3064 :Beginner Parks +STR_3065 :Challenging Parks +STR_3066 :Expert Parks +STR_3067 :{OPENQUOTES}Real{ENDQUOTES} Parks +STR_3068 :Other Parks +STR_3069 :Top Section +STR_3070 :Slope to Level +STR_3071 :{WINDOW_COLOUR_2}Same price throughout park +STR_3072 :{SMALLFONT}{BLACK}Select whether this price is used throughout the entire park +STR_3073 :{RED}WARNING: Your park rating has dropped below 700 !{NEWLINE}If you haven't raised the park rating in 4 weeks, your park will be closed down +STR_3074 :{RED}WARNING: Your park rating is still below 700 !{NEWLINE}You have 3 weeks to raise the park rating +STR_3075 :{RED}WARNING: Your park rating is still below 700 !{NEWLINE}You have only 2 weeks to raise the park rating, or your park will be closed down +STR_3076 :{RED}FINAL WARNING: Your park rating is still below 700 !{NEWLINE}In just 7 days your park will be closed down unless you can raise the rating +STR_3077 :{RED}CLOSURE NOTICE: Your park has been closed down ! +STR_3078 :Plain entrance +STR_3079 :Wooden entrance +STR_3080 :Canvas tent entrance +STR_3081 :Castle entrance (grey) +STR_3082 :Castle entrance (brown) +STR_3083 :Jungle entrance +STR_3084 :Log cabin entrance +STR_3085 :Classical/Roman entrance +STR_3086 :Abstract entrance +STR_3087 :Snow/Ice entrance +STR_3088 :Pagoda entrance +STR_3089 :Space entrance +STR_3090 :{SMALLFONT}{BLACK}Select style of entrance, exit, and station +STR_3091 :You are not allowed to remove this section! +STR_3092 :You are not allowed to move or modify the station for this ride! +STR_3093 :{WINDOW_COLOUR_2}Favourite: {BLACK}{STRINGID} +STR_3094 :N/A +STR_3095 :{WINDOW_COLOUR_2}Lift hill chain speed: +STR_3096 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{VELOCITY} +STR_3097 :{SMALLFONT}{BLACK}Select lift hill chain speed +STR_3098 :Can't change lift hill speed... +STR_3099 :{SMALLFONT}{BLACK}Select colour +STR_3100 :{SMALLFONT}{BLACK}Select second colour +STR_3101 :{SMALLFONT}{BLACK}Select third colour +STR_3102 :{SMALLFONT}{BLACK}Re-paint coloured scenery on landscape +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 +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 +STR_3113 :Select a different design +STR_3114 :{SMALLFONT}{BLACK}Go back to design selection window +STR_3115 :{SMALLFONT}{BLACK}Save track design +STR_3116 :{SMALLFONT}{BLACK}Save track design (Not possible until ride has been tested and statistics have been generated) +STR_3117 :{BLACK}Calling mechanic... +STR_3118 :{BLACK}{STRINGID} is heading for the ride +STR_3119 :{BLACK}{STRINGID} is fixing the ride +STR_3120 :{SMALLFONT}{BLACK}Locate nearest available mechanic, or mechanic fixing ride +STR_3121 :Unable to locate mechanic, or all nearby mechanics are busy +STR_3122 :{WINDOW_COLOUR_2}Favourite ride of: {BLACK}{COMMA16} guest +STR_3123 :{WINDOW_COLOUR_2}Favourite ride of: {BLACK}{COMMA16} guests +STR_3124 :Broken {STRINGID} +STR_3125 :{WINDOW_COLOUR_2}Excitement Factor: {BLACK}+{COMMA16}% +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_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) +STR_3135 :{RED}(Vehicle design unavailable - Ride performance may be affected) +STR_3136 :Warning: This design will be built with an alternative vehicle type and may not perform as expected +STR_3137 :Select Nearby Scenery +STR_3138 :Reset Selection +STR_3139 :Cable lift unable to work in this operating mode +STR_3140 :Cable lift hill must start immediately after station +STR_3141 :Multi-circuit per ride not possible with cable lift hill +STR_3142 :{WINDOW_COLOUR_2}Capacity: {BLACK}{STRINGID} +STR_3143 :{SMALLFONT}{BLACK}Show people on map +STR_3144 :{SMALLFONT}{BLACK}Show rides and stalls on map +STR_3145 :{SMALLFONT}{BLACK}Scroll {STRINGID} left +STR_3146 :{SMALLFONT}{BLACK}Scroll {STRINGID} right +STR_3147 :{SMALLFONT}{BLACK}Scroll {STRINGID} left fast +STR_3148 :{SMALLFONT}{BLACK}Scroll {STRINGID} right fast +STR_3149 :{SMALLFONT}{BLACK}Scroll {STRINGID} left/right +STR_3150 :{SMALLFONT}{BLACK}Scroll {STRINGID} up +STR_3151 :{SMALLFONT}{BLACK}Scroll {STRINGID} down +STR_3152 :{SMALLFONT}{BLACK}Scroll {STRINGID} up fast +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_3160 : +STR_3161 : +STR_3162 :Unable to allocate enough memory +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_3169 :Data for the following object not found: +STR_3170 :Not enough space for graphics +STR_3171 :Too many objects of this type selected +STR_3172 :The following object must be selected first: {STRING} +STR_3173 :This object is currently in use +STR_3174 :This object is required by another object +STR_3175 :This object is always required +STR_3176 :Unable to select this object +STR_3177 :Unable to de-select this object +STR_3178 :At least one path object must be selected +STR_3179 :At least one ride vehicle/attraction object must be selected +STR_3180 :Invalid selection of objects +STR_3181 :Object Selection - {STRINGID} +STR_3182 :Park entrance type must be selected +STR_3183 :Water type must be selected +STR_3184 :Ride Vehicles/Attractions +STR_3185 :Small Scenery +STR_3186 :Large Scenery +STR_3187 :Walls/Fences +STR_3188 :Path Signs +STR_3189 :Footpaths +STR_3190 :Path Extras +STR_3191 :Scenery Groups +STR_3192 :Park Entrance +STR_3193 :Water +STR_3194 :Scenario Description +STR_3195 :Invention List +STR_3196 :{WINDOW_COLOUR_2}Research Group: {BLACK}{STRINGID} +STR_3197 :{WINDOW_COLOUR_2}Items pre-invented at start of game: +STR_3198 :{WINDOW_COLOUR_2}Items to invent during game: +STR_3199 :Random Shuffle +STR_3200 :{SMALLFONT}{BLACK}Randomly shuffle the list of items to invent during the game +STR_3201 :Object Selection +STR_3202 :Landscape Editor +STR_3203 :Invention List Set Up +STR_3204 :Options Selection +STR_3205 :Objective Selection +STR_3206 :Save Scenario +STR_3207 :Roller Coaster Designer +STR_3208 :Track Designs Manager +STR_3209 :Back to Previous Step: +STR_3210 :Forward to Next Step: +STR_3211 :{WINDOW_COLOUR_2}Map size: +STR_3212 :{POP16}{COMMA16} x {PUSH16}{COMMA16} +STR_3213 :Can't decrease map size any further +STR_3214 :Can't increase map size any further +STR_3215 :Too close to edge of map +STR_3216 :{SMALLFONT}{BLACK}Select park-owned land etc. +STR_3217 :Land Owned +STR_3218 :Construction Rights Owned +STR_3219 :Land For Sale +STR_3220 :Construction Rights For Sale +STR_3221 :{SMALLFONT}{BLACK}Set land to be owned by the park +STR_3222 :{SMALLFONT}{BLACK}Set construction rights only to be owned by the park +STR_3223 :{SMALLFONT}{BLACK}Set land to be available to purchase by the park +STR_3224 :{SMALLFONT}{BLACK}Set construction rights to be available to purchase by the park +STR_3225 :{SMALLFONT}{BLACK}Toggle on/off building a random cluster of objects around the selected position +STR_3226 :{SMALLFONT}{BLACK}Build park entrance +STR_3227 :Too many park entrances! +STR_3228 :{SMALLFONT}{BLACK}Set starting positions for people +STR_3229 :Block Brakes cannot be used directly after station +STR_3230 :Block Brakes cannot be used directly after each other +STR_3231 :Block Brakes cannot be used directly after the top of this lift hill +STR_3232 :Options - Financial +STR_3233 :Options - Guests +STR_3234 :Options - Park +STR_3235 :{SMALLFONT}{BLACK}Show financial options +STR_3236 :{SMALLFONT}{BLACK}Show guest options +STR_3237 :{SMALLFONT}{BLACK}Show park options +STR_3238 :No Money +STR_3239 :{SMALLFONT}{BLACK}Make this park a 'no money' park with no financial restrictions +STR_3240 :{WINDOW_COLOUR_2}Initial cash: +STR_3241 :{WINDOW_COLOUR_2}Initial loan: +STR_3242 :{WINDOW_COLOUR_2}Maximum loan size: +STR_3243 :{WINDOW_COLOUR_2}Annual interest rate: +STR_3244 :Forbid marketing campaigns +STR_3245 :{SMALLFONT}{BLACK}Forbid advertising, promotional schemes, and other marketing campaigns +STR_3246 :{WINDOW_COLOUR_2}{CURRENCY} +STR_3247 :{WINDOW_COLOUR_2}{COMMA16}% +STR_3248 :Can't increase initial cash any further! +STR_3249 :Can't reduce initial cash any further! +STR_3250 :Can't increase initial loan any further! +STR_3251 :Can't reduce initial loan any further! +STR_3252 :Can't increase maximum loan size any further! +STR_3253 :Can't reduce maximum loan size any further! +STR_3254 :Can't increase interest rate any further! +STR_3255 :Can't reduce interest rate any further! +STR_3256 :Guests prefer less intense rides +STR_3257 :{SMALLFONT}{BLACK}Select whether guests should generally prefer less intense rides only +STR_3258 :Guests prefer more intense rides +STR_3259 :{SMALLFONT}{BLACK}Select whether guests should generally prefer more intense rides only +STR_3260 :{WINDOW_COLOUR_2}Cash per guest (average): +STR_3261 :{WINDOW_COLOUR_2}Guests initial happiness: +STR_3262 :{WINDOW_COLOUR_2}Guests initial hunger: +STR_3263 :{WINDOW_COLOUR_2}Guests initial thirst: +STR_3264 :Can't increase this any further! +STR_3265 :Can't reduce this any further! +STR_3266 :{SMALLFONT}{BLACK}Select how this park charges for entrance and rides +STR_3267 :Forbid tree removal +STR_3268 :{SMALLFONT}{BLACK}Forbid tall trees being removed +STR_3269 :Forbid landscape changes +STR_3270 :{SMALLFONT}{BLACK}Forbid any changes to the landscape +STR_3271 :Forbid high construction +STR_3272 :{SMALLFONT}{BLACK}Forbid any tall construction +STR_3273 :Park rating higher difficult level +STR_3274 :{SMALLFONT}{BLACK}Make the park rating value more challenging +STR_3275 :Guest generation higher difficult level +STR_3276 :{SMALLFONT}{BLACK}Make it more difficult to attract guests to the park +STR_3277 :{WINDOW_COLOUR_2}Cost to buy land: +STR_3278 :{WINDOW_COLOUR_2}Cost to buy construction rights: +STR_3279 :Free park entry / Pay per ride +STR_3280 :Pay to enter park / Free rides +STR_3281 :{WINDOW_COLOUR_2}Entry price: +STR_3282 :{SMALLFONT}{BLACK}Select objective and park name +STR_3283 :{SMALLFONT}{BLACK}Select rides to be preserved +STR_3284 :Objective Selection +STR_3285 :Preserved Rides +STR_3286 :{SMALLFONT}{BLACK}Select objective for this scenario +STR_3287 :{WINDOW_COLOUR_2}Objective: +STR_3288 :{SMALLFONT}{BLACK}Select climate +STR_3289 :{WINDOW_COLOUR_2}Climate: +STR_3290 :Cool and wet +STR_3291 :Warm +STR_3292 :Hot and dry +STR_3293 :Cold +STR_3294 :Change... +STR_3295 :{SMALLFONT}{BLACK}Change name of park +STR_3296 :{SMALLFONT}{BLACK}Change name of scenario +STR_3297 :{SMALLFONT}{BLACK}Change detail notes about park / scenario +STR_3298 :{WINDOW_COLOUR_2}Park Name: {BLACK}{STRINGID} +STR_3299 :{WINDOW_COLOUR_2}Park/Scenario Details: +STR_3300 :{WINDOW_COLOUR_2}Scenario Name: {BLACK}{STRINGID} +STR_3301 :{WINDOW_COLOUR_2}Objective Date: +STR_3302 :{WINDOW_COLOUR_2}{MONTHYEAR} +STR_3303 :{WINDOW_COLOUR_2}Number of guests: +STR_3304 :{WINDOW_COLOUR_2}Park value: +STR_3305 :{WINDOW_COLOUR_2}Monthly income: +STR_3306 :{WINDOW_COLOUR_2}Monthly profit: +STR_3307 :{WINDOW_COLOUR_2}Minimum length: +STR_3308 :{WINDOW_COLOUR_2}Excitement rating: +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_3314 :Enter name for scenario: +STR_3315 :Park/Scenario Details +STR_3316 :Enter description of this scenario: +STR_3317 :No details yet +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_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_3327 :Starting positions for people not set +STR_3328 :Can't advance to next editor stage... +STR_3329 :Park entrance not yet built +STR_3330 :Park must own some land +STR_3331 :Path from park entrance to map edge either not complete or too complex - Path must be single-width with as few junctions and corners as possible +STR_3332 :Park entrance is the wrong way round or has no path leading to the map edge +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 : +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_3341 :{SMALLFONT}{BLACK}Game tools +STR_3342 :Scenario Editor +STR_3343 :Convert Saved Game to Scenario +STR_3344 :Roller Coaster Designer +STR_3345 :Track Designs Manager +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 : +STR_3363 : +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}= 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... +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_3385 :Beginners Tutorial +STR_3386 :Custom Rides Tutorial +STR_3387 :Roller Coaster Building Tutorial +STR_3388 :Unable to switch to selected mode +STR_3389 :Unable to select additional item of scenery... +STR_3390 :Too many items selected +# Start of tutorial strings. Not used at the moment, so not necessary to translate. +STR_3391 :{SMALLFONT}{BLACK}Here is our park - Let's have a quick look around... +STR_3392 :{SMALLFONT}{BLACK}Holding down the RIGHT mouse button and moving the mouse is the quickest way to move the view... +STR_3393 :{SMALLFONT}{BLACK}To view more of the park, you can zoom the view out using the icon at the top of the screen... +STR_3394 :{SMALLFONT}{BLACK}You can also rotate the view in 90 degree steps... +STR_3395 :{SMALLFONT}{BLACK}Building anything at this scale is a bit difficult, so let's zoom the view back in again... +STR_3396 :{SMALLFONT}{BLACK}Let's build a simple ride to get the park started... +STR_3397 :{SMALLFONT}{BLACK}The white 'ghost' image shows where the ride will be built. We'll move the pointer to select the position then click to build it... +STR_3398 :{SMALLFONT}{BLACK}Rides need an entrance and an exit. We'll move the pointer to a square on the edge of the ride and then click to build first the entrance and then the exit... +STR_3399 :{SMALLFONT}{BLACK}We need to build footpaths to allow guests to reach our new ride... +STR_3400 :{SMALLFONT}{BLACK}For the path to the ride entrance we'll use a special 'queue line' path... +STR_3401 :{SMALLFONT}{BLACK}For the exit path, just an 'ordinary' path will do... +STR_3402 :{SMALLFONT}{BLACK}Right, lets open the ride! To open the ride we click the flag icon on the ride window and select 'open'... +STR_3403 :{SMALLFONT}{BLACK}But where are the guests? +STR_3404 :{SMALLFONT}{BLACK}Oh - The park is still closed! Right - Let's open it... +STR_3405 :{SMALLFONT}{BLACK}While we're waiting for our first guests, let's build some scenery... +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 customise the ride a bit... +# End of tutorial strings +STR_3437 :{SMALLFONT}{BLACK}Clear large areas of scenery from landscape +STR_3438 :Unable to remove all scenery from here... +STR_3439 :Clear Scenery +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 + +# Thousands separator +STR_5151 :. +# Decimal separator +STR_5152 :, diff --git a/data/language/spanish_sp.txt b/data/language/spanish_sp.txt index 9e3b0cbb9c..787a788e5f 100644 --- a/data/language/spanish_sp.txt +++ b/data/language/spanish_sp.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 :Steel 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 : @@ -513,31 +513,31 @@ STR_0508 : STR_0509 : STR_0510 : STR_0511 : -STR_0512 : -STR_0513 : +STR_0512 :A compact roller coaster with a spiral lift hill and smooth, twisting drops. +STR_0513 :A looping roller coaster where the riders ride in a standing position STR_0514 :Trains suspended beneath the roller coaster track swing out to the side around corners -STR_0515 : +STR_0515 :A steel roller coaster with trains that are held beneath the track, with many complex and twisting track elements STR_0516 :A gentle roller coaster for people who haven't yet got the courage to face the larger rides STR_0517 :Passengers ride in miniature trains along a narrow-gauge railway track STR_0518 :Passengers travel in electric trains along a monorail track STR_0519 :Passengers ride in small cars hanging beneath the single-rail track, swinging freely from side to side around corners -STR_0520 : -STR_0521 : -STR_0522 : +STR_0520 :A dock platform where guests can drive/row personal watercraft on a body of water +STR_0521 :A fast and twisting roller coaster with tight turns and steep drops. Intensity is bound to be high. +STR_0522 :A smaller roller coaster where the riders sit above the track with no car around them STR_0523 :Riders travel slowly in powered vehicles along a track-based route -STR_0524 : -STR_0525 : -STR_0526 : +STR_0524 :Freefall car is pneumatically launched up a tall steel tower and then allowed to freefall down +STR_0525 :Riders career down a twisting track guided only by the curvature and banking of the semi-circular track +STR_0526 :Passengers travel in a rotating observation cabin which travels up a tall tower STR_0527 :A smooth steel-tracked roller coaster capable of vertical loops -STR_0528 : -STR_0529 : +STR_0528 :Riders travel in inflatable dinghies down a twisting semi-circular or completely enclosed tube track +STR_0529 :Mine train themed roller coaster trains career along steel roller coaster track made to look like old railway track STR_0530 :Cars hang from a steel cable which runs continuously from one end of the ride to the other and back again -STR_0531 : +STR_0531 :A compact steel-tracked roller coaster where the train travels through corkscrews and loops STR_0532 : STR_0533 : -STR_0534 : -STR_0535 : -STR_0536 : +STR_0534 :Self-drive petrol-engined go karts +STR_0535 :Log-shaped boats travel along a water channel, splashing down steep slopes to soak the riders +STR_0536 :Circular boats meander along a wide water channel, splashing through waterfalls and thrilling riders through foaming rapids STR_0537 : STR_0538 : STR_0539 : @@ -556,14 +556,14 @@ STR_0551 : STR_0552 : STR_0553 : STR_0554 :The car is accelerated out of the station along a long level track using Linear Induction Motors, then heads straight up a vertical spike of track, freefalling back down to return to the station -STR_0555 : -STR_0556 : +STR_0555 :Guests ride in an elevator up or down a vertical tower to get from one level to another +STR_0556 :Extra-wide cars descend completely vertical sloped track for the ultimate freefall roller coaster experience STR_0557 : STR_0558 : STR_0559 : STR_0560 : STR_0561 : -STR_0562 : +STR_0562 :Powered cars travel along a multi-level track past spooky scenery and special effects STR_0563 :Sitting in comfortable trains with only simple lap restraints riders enjoy giant smooth drops and twisting track as well as plenty of 'air time' over the hills STR_0564 :Running on wooden track, this coaster is fast, rough, noisy, and gives an 'out of control' riding experience with plenty of 'air time' STR_0565 :A simple wooden roller coaster capable of only gentle slopes and turns, where the cars are only kept on the track by side friction wheels and gravity @@ -572,38 +572,38 @@ STR_0567 :Sitting in seats suspended either side of the track, riders are pit STR_0568 : STR_0569 :Riding in special harnesses below the track, riders experience the feeling of flight as they swoop through the air STR_0570 : -STR_0571 : -STR_0572 : -STR_0573 : -STR_0574 : +STR_0571 :Circular cars spin around as they travel along the zig-zagging wooden track +STR_0572 :Large capacity boats travel along a wide water channel, propelled up slopes by a conveyer belt, accelerating down steep slopes to soak the riders with a gaint splash +STR_0573 :Powered helicoper shaped cars running on a steel track, controlled by the pedalling of the riders +STR_0574 :Riders are held in special harnesses in a lying-down position, travlling through twisted track and inversions either on their backs or facing the ground STR_0575 :Powered trains hanging from a single rail transport people around the park STR_0576 : -STR_0577 : +STR_0577 :Bogied cars run on wooden tracks, turning around on special reversing sections STR_0578 :Cars run along track enclosed by circular hoops, traversing steep drops and heartline twists STR_0579 : -STR_0580 : -STR_0581 : +STR_0580 :A giant steel roller coaster capable of smooth drops and hills of over 300ft +STR_0581 :A ring of seats is pulled to the top of a tall tower while gently rotating, then allowed to free-fall down, stopping gently at the bottom using magnetic brakes STR_0582 : STR_0583 : -STR_0584 : -STR_0585 : +STR_0584 :Special bicycles run on a steel monorail track, propelled by the pedalling of the riders +STR_0585 :Riders sit in pairs of seats suspended beneath the track as they loop and twist through tight inversions STR_0586 :Boat shaped cars run on roller coaster track to allow twisting curves and steep drops, splashing down into sections of water for gentle river sections -STR_0587 : -STR_0588 : +STR_0587 :After an exhilarating air-powered launch, the train speeds up a vertical track, over the top, and vertically down the other side to return to the station +STR_0588 :Individual cars run beneath a zig-zagging track with hairpin turns and sharp drops STR_0589 : -STR_0590 : -STR_0591 : +STR_0590 :Riders ride in a submerged submarine through an underwater course +STR_0591 :Raft-shaped boats gently meander around a river track STR_0592 : STR_0593 : STR_0594 : STR_0595 : STR_0596 : STR_0597 : -STR_0598 : +STR_0598 :Inverted roller coaster trains are accelerated out of the station to travel up a vertical spike of track, then reverse back through the station to travel backwards up another vertical spike of track STR_0599 :A compact roller coaster with individual cars and smooth twisting drops -STR_0600 : +STR_0600 :Powered mine trains career along a smooth and twisted track layout STR_0601 : -STR_0602 : +STR_0602 :Roller coaster trains are accelerated out of the station by linear induction motors to speed through twisting inversions STR_0603 :Visitante {INT32} STR_0604 :Visitante {INT32} STR_0605 :Visitante {INT32} @@ -836,19 +836,20 @@ STR_0831 :{SMALLFONT}{BLACK}Zoom view out STR_0832 :{SMALLFONT}{BLACK}Rotate view 90{DEGREE} clockwise STR_0833 :{SMALLFONT}{BLACK}Pause game STR_0834 :{SMALLFONT}{BLACK}Disk and game options -STR_0835 :Game initialization failed +STR_0835 :Game initialisation failed STR_0836 :Unable to start game in a minimised state STR_0837 :Unable to initialise 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_0838 : STR_0839 :{UINT16} x {UINT16} STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} -STR_0841 :Desktop window -STR_0842 :640x480 full screen -STR_0843 :800x600 full screen -STR_0844 :1024x768 full screen -STR_0845 :1152x864 full screen -STR_0846 :1280x1024 full screen -STR_0847 :About 'RollerCoaster Tycoon 2' +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +STR_0847 :About 'OpenRCT2' STR_0848 :RollerCoaster Tycoon 2 STR_0849 :{WINDOW_COLOUR_2}Version 2.01.028 STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, all rights reserved @@ -977,7 +978,7 @@ STR_0972 :Cancelar 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 @@ -1044,10 +1045,10 @@ 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_1043 :OpenRCT2 Saved Game +STR_1044 :OpenRCT2 Scenario File +STR_1045 :OpenRCT2 Landscape File +STR_1046 :OpenRCT2 Track Design File STR_1047 :Game save failed! STR_1048 :Scenario save failed! STR_1049 :Landscape save failed! @@ -1526,9 +1527,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 : @@ -1560,9 +1561,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 : @@ -1781,7 +1782,7 @@ STR_1776 :On 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 +STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tiger costume STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} Elephant costume STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} Roman costume STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} Gorilla costume @@ -1842,7 +1843,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 @@ -1874,8 +1875,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 @@ -1893,8 +1894,10 @@ STR_1888 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}more than 4 hou STR_1889 :{WINDOW_COLOUR_2}Down-Time: {MOVE_X}{255}{BLACK}{COMMA16}% STR_1890 :{SMALLFONT}{BLACK}Select how often a mechanic should check this ride STR_1891 :No {STRINGID} in park yet! -STR_1892 :RollerCoaster Tycoon 2 -STR_1893 :Please insert your RollerCoaster Tycoon 2 CD in the following drive: +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 : +STR_1893 : STR_1894 :{WINDOW_COLOUR_2}{STRINGID} sold: {BLACK}{COMMA32} STR_1895 :{SMALLFONT}{BLACK}Build new ride/attraction STR_1896 :{WINDOW_COLOUR_2}Expenditure/Income @@ -1930,7 +1933,7 @@ STR_1925 :Can't place person here... STR_1926 :{SMALLFONT} STR_1927 :{YELLOW}{STRINGID} has broken down STR_1928 :{RED}{STRINGID} has crashed! -STR_1929 :{RED}{STRINGID} still hasn't been fixed{NEWLINE}Check where your mechanics are and consider organizing them better +STR_1929 :{RED}{STRINGID} still hasn't been fixed{NEWLINE}Check where your mechanics are and consider organising them better STR_1930 :{SMALLFONT}{BLACK}Turn on/off tracking information for this guest - (If tracking is on, guest's movements will be reported in the message area) STR_1931 :{STRINGID} has joined the queue line for {STRINGID} STR_1932 :{STRINGID} is on {STRINGID} @@ -1968,9 +1971,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 +1983,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 +1999,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 +2011,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 +2027,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 +2039,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 +2055,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 +2067,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 +2083,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 +2095,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 @@ -2218,7 +2221,7 @@ STR_2213 :{SMALLFONT}{BLACK}Show list of entertainers in park STR_2214 :Construction not possible while game is paused! STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C -STR_2217 :{WINDOW_COLOUR_2}{COMMA16}F +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F STR_2218 :{RED}{STRINGID} on {STRINGID} hasn't returned to the {STRINGID} yet!{NEWLINE}Check whether it is stuck or has stalled STR_2219 :{RED}{COMMA16} people have died in an accident on {STRINGID} STR_2220 :{WINDOW_COLOUR_2}Park Rating: {BLACK}{COMMA16} @@ -2318,10 +2321,10 @@ STR_2313 :{WINDOW_COLOUR_2}Nausea rating: {BLACK}{COMMA2DP32} (approx.) STR_2314 :{WINDOW_COLOUR_2}Ride length: {BLACK}{STRINGID} STR_2315 :{WINDOW_COLOUR_2}Cost: {BLACK}around {CURRENCY} STR_2316 :{WINDOW_COLOUR_2}Space required: {BLACK}{COMMA16} x {COMMA16} blocks -STR_2317 :{WINDOW_COLOUR_2}Sound Quality: -STR_2318 :Low -STR_2319 :Medium -STR_2320 :High +STR_2317 : +STR_2318 : +STR_2319 : +STR_2320 : STR_2321 :{WINDOW_COLOUR_2}Number of rides/attractions: {BLACK}{COMMA16} STR_2322 :{WINDOW_COLOUR_2}Staff: {BLACK}{COMMA16} STR_2323 :{WINDOW_COLOUR_2}Park size: {BLACK}{COMMA32}m{SQUARED} @@ -2368,7 +2371,7 @@ STR_2363 :Gridlines on Landscape STR_2364 :{SMALLFONT}{BLACK}Toggle gridlines on landscape on/off STR_2365 :The bank refuses to increase your loan! STR_2366 :Celsius ({DEGREE}C) -STR_2367 :Fahrenheit (F) +STR_2367 :Fahrenheit ({DEGREE}F) STR_2368 :None STR_2369 :Low STR_2370 :Average @@ -2438,12 +2441,12 @@ 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_2437 : +STR_2438 : +STR_2439 : +STR_2440 : +STR_2441 : +STR_2442 : 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 @@ -2500,7 +2503,7 @@ STR_2495 :Cancelar construction mode STR_2496 :Pause game STR_2497 :Zoom view out STR_2498 :Zoom view in -STR_2499 :Rotate view +STR_2499 :Rotate view clockwise STR_2500 :Rotate construction object STR_2501 :Underground view toggle STR_2502 :Remove base land toggle @@ -2682,10 +2685,10 @@ 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_2681 :{MEDIUMFONT}{BLACK}Increases your money by {CURRENCY} +STR_2682 : +STR_2683 : +STR_2684 :{SMALLFONT}{BLACK}Large group of peeps arrive STR_2685 :Simplex Noise Parameters STR_2686 :{WINDOW_COLOUR_2}Low: STR_2687 :{WINDOW_COLOUR_2}High: @@ -2702,11 +2705,11 @@ 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_2701 :Every minute +STR_2702 :Every 5 minutes +STR_2703 :Every 15 minutes +STR_2704 :Every 30 minutes +STR_2705 :Every hour STR_2706 :Never STR_2707 :Open new window STR_2708 :{WINDOW_COLOUR_1}Are you sure you want to overwrite {STRINGID}? @@ -2762,11 +2765,11 @@ 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 -STR_2762 :Pay For Rides +STR_2760 :+{CURRENCY} +STR_2761 : +STR_2762 : STR_2763 :??? -STR_2764 :Happy Guests +STR_2764 : STR_2765 :Large Tram STR_2766 :Win scenario STR_2767 :Freeze Climate @@ -2784,7 +2787,7 @@ STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} # End of new strings STR_2779 :Viewport #{COMMA16} STR_2780 :Extra viewport -STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} STR_2782 :SHIFT + STR_2783 :CTRL + STR_2784 :Change keyboard shortcut @@ -2809,12 +2812,12 @@ STR_2802 :Map 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 -STR_2806 :{RED}Guests are complaining about the disgusting state of the paths in your park{NEWLINE}Check where your handymen are and consider organizing them better -STR_2807 :{RED}Guests are complaining about the amount of litter in your park{NEWLINE}Check where your handymen are and consider organizing them better -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_2806 :{RED}Guests are complaining about the disgusting state of the paths in your park{NEWLINE}Check where your handymen are and consider organising them better +STR_2807 :{RED}Guests are complaining about the amount of litter in your park{NEWLINE}Check where your handymen are and consider organising them better +STR_2808 :{RED}Guests are complaining about the vandalism in your park{NEWLINE}Check where your security guards are and consider organising 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 @@ -2827,7 +2830,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 @@ -2844,7 +2847,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'! @@ -2862,7 +2865,7 @@ STR_2855 :{RED}{STRINGID} has no path leading from its exit !{NEWLINE}Constru STR_2856 :{WINDOW_COLOUR_2}Tutorial STR_2857 :{WINDOW_COLOUR_2}(Press a key or mouse button to take control) STR_2858 :Can't start marketing campaign... -STR_2859 :Another instance of RollerCoaster Tycoon 2 is already running +STR_2859 :Another instance of OpenRCT is already running STR_2860 :Infogrames Interactive credits... STR_2861 :{WINDOW_COLOUR_2}Licensed to Infogrames Interactive Inc. STR_2862 :Music acknowledgements... @@ -2972,8 +2975,8 @@ STR_2965 :{WINDOW_COLOUR_2} STR_2966 : STR_2967 : STR_2968 : -STR_2969 :Use of this product is subject to the terms of a licence agreement -STR_2970 :found in the product's {OPENQUOTES}ReadMe{ENDQUOTES} file and in the manual +STR_2969 : +STR_2970 : STR_2971 :Main colour scheme STR_2972 :Alternative colour scheme 1 STR_2973 :Alternative colour scheme 2 @@ -3163,8 +3166,8 @@ STR_3156 : STR_3157 :map STR_3158 :graph STR_3159 :list -STR_3160 :RollerCoaster Tycoon 2: Starting for the first time... -STR_3161 :RollerCoaster Tycoon 2: Checking object files... +STR_3160 : +STR_3161 : STR_3162 :Unable to allocate enough memory STR_3163 :Installing new data: STR_3164 :{BLACK}{COMMA16} selected (maximum {COMMA16}) @@ -3175,7 +3178,7 @@ STR_3168 :{WINDOW_COLOUR_2}Text: {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 -STR_3172 :The following object must be selected first: +STR_3172 :The following object must be selected first: {STRING} STR_3173 :This object is currently in use STR_3174 :This object is required by another object STR_3175 :This object is always required @@ -3340,7 +3343,7 @@ 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_3337 : 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 @@ -3365,8 +3368,8 @@ 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_3362 : +STR_3363 : STR_3364 :Advanced STR_3365 :{SMALLFONT}{BLACK}Allow selection of individual items of scenery in addition to scenery groups STR_3366 :{BLACK}= Ride @@ -3375,8 +3378,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... @@ -3394,6 +3397,7 @@ STR_3387 :Roller Coaster Building Tutorial STR_3388 :Unable to switch to selected mode STR_3389 :Unable to select additional item of scenery... STR_3390 :Too many items selected +# Start of tutorial strings. Not used at the moment, so not necessary to translate. STR_3391 :{SMALLFONT}{BLACK}Here is our park - Let's have a quick look around... STR_3392 :{SMALLFONT}{BLACK}Holding down the RIGHT mouse button and moving the mouse is the quickest way to move the view... STR_3393 :{SMALLFONT}{BLACK}To view more of the park, you can zoom the view out using the icon at the top of the screen... @@ -3440,6 +3444,7 @@ STR_3433 :{SMALLFONT}{BLACK}And finally we'll add 'block brakes', which allow 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 customise the ride a bit... +# End of tutorial strings STR_3437 :{SMALLFONT}{BLACK}Clear large areas of scenery from landscape STR_3438 :Unable to remove all scenery from here... STR_3439 :Clear Scenery @@ -3451,164 +3456,9 @@ 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 + +# Note: as this is an unmaintained language, don't add new strings unless you intend to become the mainainer. diff --git a/data/language/swedish.txt b/data/language/swedish.txt index 0d50bc975d..a5ef9b4bb9 100644 --- a/data/language/swedish.txt +++ b/data/language/swedish.txt @@ -3,97 +3,97 @@ # Use # at the beginning of a line to leave a comment. STR_0000 : STR_0001 :{STRINGID} {COMMA16} -STR_0002 :Åktur -STR_0003 :Åktur +STR_0002 :Spiral berg- och dalbana +STR_0003 :Stående berg- och dalbana STR_0004 :Hängande svängande bana -STR_0005 :Åktur +STR_0005 :Inverterad berg- och dalbana STR_0006 :Junior berg- och dalbana STR_0007 :Miniatyr-tåg STR_0008 :Balkbana STR_0009 :Liten hängande bana -STR_0010 :Åktur -STR_0011 :Åktur -STR_0012 :Åktur +STR_0010 :Båttur +STR_0011 :Vildmus i trä +STR_0012 :Hinderbana STR_0013 :Bilåktur -STR_0014 :Åktur -STR_0015 :Åktur -STR_0016 :Åktur +STR_0014 :Launched Freefall +STR_0015 :Bobsleigh Coaster +STR_0016 :Observationstorn STR_0017 :Loopande berg- och dalbana -STR_0018 :Åktur -STR_0019 :Åktur +STR_0018 :Dinghy Slide +STR_0019 :Gruvtåg STR_0020 :Stolslift -STR_0021 :Åktur -STR_0022 :Åktur -STR_0023 :Åktur -STR_0024 :Åktur -STR_0025 :Åktur -STR_0026 :Åktur -STR_0027 :Åktur -STR_0028 :Åktur -STR_0029 :Åktur -STR_0030 :Stånd -STR_0031 :Stånd -STR_0032 :Stånd -STR_0033 :Stånd +STR_0021 :Korkskruvs berg- och dalbana +STR_0022 :Labyrint +STR_0023 :Spiral Slide +STR_0024 :Go Karts +STR_0025 :Log Flume +STR_0026 :River Rapids +STR_0027 :Dodgems +STR_0028 :Piratskepp +STR_0029 :Svängande omvänt Piratskepp +STR_0030 :Matstånd +STR_0031 :Okänt Stånd (1D) +STR_0032 :Dryckesstånd +STR_0033 :Okänt Stånd (1F) STR_0034 :Stånd -STR_0035 :Åktur -STR_0036 :Stånd +STR_0035 :Karusell +STR_0036 :Okänt Stånd (22) STR_0037 :Kiosk STR_0038 :Toalett -STR_0039 :Åktur -STR_0040 :Åktur -STR_0041 :Åktur -STR_0042 :Åktur -STR_0043 :Åktur +STR_0039 :Pariserhjul +STR_0040 :Rörelsesimulator +STR_0041 :3D Bio +STR_0042 :Top Spin +STR_0043 :Rymdringar STR_0044 :Bakvänd fritt fall-bana STR_0045 :Lift -STR_0046 :Åktur -STR_0047 :Åktur -STR_0048 :Åktur -STR_0049 :Åktur -STR_0050 :Åktur -STR_0051 :Åktur -STR_0052 :Åktur +STR_0046 :Vertical Drop Roller Coaster +STR_0047 :Bankomat +STR_0048 :Twist +STR_0049 :Spökhuset +STR_0050 :Första Hjälpen +STR_0051 :Cirkusföreställning +STR_0052 :Spöktåget STR_0053 :Hyper-snurr berg- och dalbana STR_0054 :Berg- och dalbana i trä STR_0055 :Sidofriktion berg- och dalbana STR_0056 :Vilda Musen STR_0057 :Flerdimensionell berg- och dalbana -STR_0058 :Åktur +STR_0058 :Okänd Åktur (38) STR_0059 :Inverterad berg- och dalbana -STR_0060 :Åktur -STR_0061 :Åktur -STR_0062 :Åktur -STR_0063 :Åktur -STR_0064 :Åktur +STR_0060 :Okänd Åktur (3A) +STR_0061 :Virginia Reel +STR_0062 :Splash Boats +STR_0063 :Mini Helicopters +STR_0064 :Liggande berg- och dalbana STR_0065 :Hängande balkbana -STR_0066 :Åktur -STR_0067 :Åktur +STR_0066 :Okänd Åktur (40) +STR_0067 :Reverser Roller Coaster STR_0068 :Skruvbana -STR_0069 :Åktur -STR_0070 :Åktur -STR_0071 :Åktur -STR_0072 :Åktur -STR_0073 :Åktur -STR_0074 :Åktur -STR_0075 :Åktur +STR_0069 :Mini Golf +STR_0070 :Giga Coaster +STR_0071 :Roto-Fall +STR_0072 :Flying Saucers +STR_0073 :Crooked House +STR_0074 :Monorail Cycles +STR_0075 :Compact Inverted Coaster STR_0076 :Vattenbana -STR_0077 :Åktur -STR_0078 :Åktur -STR_0079 :Åktur -STR_0080 :Åktur -STR_0081 :Åktur -STR_0082 :Åktur -STR_0083 :Åktur -STR_0084 :Åktur -STR_0085 :Åktur -STR_0086 :Åktur -STR_0087 :Åktur -STR_0088 :Åktur +STR_0077 :Air Powered Vertical Coaster +STR_0078 :Inverted Hairpin Coaster +STR_0079 :Magisk matta +STR_0080 :Submarine Ride +STR_0081 :River Rafts +STR_0082 :Okänd Åktur (50) +STR_0083 :Enterprise +STR_0084 :Okänd Åktur (52) +STR_0085 :Okänd Åktur (53) +STR_0086 :Okänd Åktur (54) +STR_0087 :Okänd Åktur (55) +STR_0088 :Inverted Impulse Coaster STR_0089 :Mini berg- och dalbana -STR_0090 :Åktur -STR_0091 :Åktur -STR_0092 :Åktur +STR_0090 :Mine Ride +STR_0091 :Okänd Åktur (59) +STR_0092 :LIM Launched Roller Coaster STR_0093 : STR_0094 : STR_0095 : @@ -513,31 +513,31 @@ STR_0508 : STR_0509 : STR_0510 : STR_0511 : -STR_0512 : -STR_0513 : +STR_0512 :A compact roller coaster with a spiral lift hill and smooth, twisting drops. +STR_0513 :A looping roller coaster where the riders ride in a standing position STR_0514 :Hängande tåg under banan svingar ut åt sidan i svängar -STR_0515 : +STR_0515 :A steel roller coaster with trains that are held beneath the track, with many complex and twisting track elements STR_0516 :En snäll berg- och dalbana för de som inte har mod nog att utmana större åkturer STR_0517 :Passagerare åker i miniatyrtåg på en smal tågräls STR_0518 :Passagerare åker i elektriska tåg på en balkbana STR_0519 :Passagerare åker i små vagnar som hänger under en enkelspårig bana, fritt svingande från sida till sida i svängar -STR_0520 : -STR_0521 : -STR_0522 : +STR_0520 :A dock platform where guests can drive/row personal watercraft on a body of water +STR_0521 :A fast and twisting roller coaster with tight turns and steep drops. Intensity is bound to be high. +STR_0522 :A smaller roller coaster where the riders sit above the track with no car around them STR_0523 :Passagerare åker sakta i motoriserade fordon på en spår-baserad väg -STR_0524 : -STR_0525 : -STR_0526 : +STR_0524 :Freefall car is pneumatically launched up a tall steel tower and then allowed to freefall down +STR_0525 :Riders career down a twisting track guided only by the curvature and banking of the semi-circular track +STR_0526 :Passengers travel in a rotating observation cabin which travels up a tall tower STR_0527 :En mjuk berg- och dalbana byggd av stål som kan göra vertikala loopar -STR_0528 : -STR_0529 : +STR_0528 :Riders travel in inflatable dinghies down a twisting semi-circular or completely enclosed tube track +STR_0529 :Mine train themed roller coaster trains career along steel roller coaster track made to look like old railway track STR_0530 :Vagnar hänger från en stålkabel som kör kontinuerligt från ena sidan åkturen till den andra, och sedan tillbaka igen -STR_0531 : +STR_0531 :A compact steel-tracked roller coaster where the train travels through corkscrews and loops STR_0532 : STR_0533 : -STR_0534 : -STR_0535 : -STR_0536 : +STR_0534 :Self-drive petrol-engined go karts +STR_0535 :Log-shaped boats travel along a water channel, splashing down steep slopes to soak the riders +STR_0536 :Circular boats meander along a wide water channel, splashing through waterfalls and thrilling riders through foaming rapids STR_0537 : STR_0538 : STR_0539 : @@ -556,14 +556,14 @@ STR_0551 : STR_0552 : STR_0553 : 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_0555 :Guests ride in an elevator up or down a vertical tower to get from one level to another +STR_0556 :Extra-wide cars descend completely vertical sloped track for the ultimate freefall roller coaster experience STR_0557 : STR_0558 : STR_0559 : STR_0560 : STR_0561 : -STR_0562 : +STR_0562 :Powered cars travel along a multi-level track past spooky scenery and special effects STR_0563 :Sittandes i bekväma vagnar njuter passagerare av enorma nedförsbackar och spännande svängar, samt mycket tid flygandes över topparna STR_0564 :Den här berg- och dalbanan i trä är snabb, tuff, högljudd, och ger en känsla av att tappa kontrollen. Dessutom spenderar man mycket tid flygandes över topparna STR_0565 :En enkel berg- och dalbana i trä som bara har snälla backar och svängar. Vagnarna hålls på banan med sidofriktion på hjulen och gravitation @@ -572,38 +572,38 @@ STR_0567 :Passagerare sitter i säten på varsin sida av banan och vänds upp STR_0568 : STR_0569 :Hängandes i speciella selar får passagerare känna på känslan av att flyga runt i luften STR_0570 : -STR_0571 : -STR_0572 : -STR_0573 : -STR_0574 : +STR_0571 :Circular cars spin around as they travel along the zig-zagging wooden track +STR_0572 :Large capacity boats travel along a wide water channel, propelled up slopes by a conveyer belt, accelerating down steep slopes to soak the riders with a gaint splash +STR_0573 :Powered helicoper shaped cars running on a steel track, controlled by the pedalling of the riders +STR_0574 :Riders are held in special harnesses in a lying-down position, travlling through twisted track and inversions either on their backs or facing the ground 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_0577 :Bogied cars run on wooden tracks, turning around on special reversing sections STR_0578 :Vagnar åker runt en bana omgiven av ringar utför branta nedförsbackar och skruvar STR_0579 : -STR_0580 : -STR_0581 : +STR_0580 :A giant steel roller coaster capable of smooth drops and hills of over 300ft +STR_0581 :A ring of seats is pulled to the top of a tall tower while gently rotating, then allowed to free-fall down, stopping gently at the bottom using magnetic brakes STR_0582 : STR_0583 : -STR_0584 : -STR_0585 : +STR_0584 :Special bicycles run on a steel monorail track, propelled by the pedalling of the riders +STR_0585 :Riders sit in pairs of seats suspended beneath the track as they loop and twist through tight inversions STR_0586 :Båtformade vagnar åker på berg- och dalbanespår med snurriga svängar och branta nedförsbackar, men plumsar då och då ner i lugna vattensektioner -STR_0587 : -STR_0588 : +STR_0587 :After an exhilarating air-powered launch, the train speeds up a vertical track, over the top, and vertically down the other side to return to the station +STR_0588 :Individual cars run beneath a zig-zagging track with hairpin turns and sharp drops STR_0589 : -STR_0590 : -STR_0591 : +STR_0590 :Riders ride in a submerged submarine through an underwater course +STR_0591 :Raft-shaped boats gently meander around a river track STR_0592 : STR_0593 : STR_0594 : STR_0595 : STR_0596 : STR_0597 : -STR_0598 : +STR_0598 :Inverted roller coaster trains are accelerated out of the station to travel up a vertical spike of track, then reverse back through the station to travel backwards up another vertical spike of track STR_0599 :En kompakt berg- och dalbana med individuella vagnar och mjuka snurrade nedförsbackar -STR_0600 : +STR_0600 :Powered mine trains career along a smooth and twisted track layout STR_0601 : -STR_0602 : +STR_0602 :Roller coaster trains are accelerated out of the station by linear induction motors to speed through twisting inversions STR_0603 :Gäst {INT32} STR_0604 :Gäst {INT32} STR_0605 :Gäst {INT32} @@ -839,16 +839,17 @@ STR_0834 :{SMALLFONT}{BLACK}Inställningar STR_0835 :Spelet kunde inte starta STR_0836 :Kan inte starta spelet minimerat STR_0837 :Kan inte initiera grafiksystemet -STR_0838 :CD-nyckeln {INT32} är inte giltig för RollerCoaster Tycoon 2!{WINDOW_COLOUR_1}{WINDOW_COLOUR_1}Var god avinstallera RollerCoaster Tycoon 2% och återinstallera med rätt CD-nyckel +STR_0838 : STR_0839 :{UINT16} x {UINT16} STR_0840 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{UINT16} x {UINT16} -STR_0841 :Skrivbordsfönster -STR_0842 :640x480 helskärm -STR_0843 :800x600 helskärm -STR_0844 :1024x768 helskärm -STR_0845 :1152x864 helskärm -STR_0846 :1280x1024 helskärm -STR_0847 :Om 'RollerCoaster Tycoon 2' +# The following six strings were used for display resolutions, but have been replaced. +STR_0841 : +STR_0842 : +STR_0843 : +STR_0844 : +STR_0845 : +STR_0846 : +STR_0847 :Om 'OpenRCT2' STR_0848 :RollerCoaster Tycoon 2 STR_0849 :{WINDOW_COLOUR_2}Version 2.01.028 STR_0850 :{WINDOW_COLOUR_2}Copyright {COPYRIGHT} 2002 Chris Sawyer, alla rättigheter förbehålls @@ -883,8 +884,8 @@ STR_0878 :För högt ! STR_0879 :Kan inte sänka landnivån här... STR_0880 :Kan inte höja landnivån här... STR_0881 :Ett objekt är i vägen -STR_0882 :Spara Spel -STR_0883 :Ladda Spel +STR_0882 :Ladda Spel +STR_0883 :Spara Spel STR_0884 :Ladda Landskap STR_0885 :Spara Landskap STR_0886 :Avsluta Spel @@ -1044,10 +1045,10 @@ STR_1039 :Installera ny bandesign STR_1040 :Spara Spel STR_1041 :Spara Scenario STR_1042 :Spara Landskap -STR_1043 :RollerCoaster Tycoon 2 Sparat Spel -STR_1044 :RollerCoaster Tycoon 2 Sparat Scenario -STR_1045 :RollerCoaster Tycoon 2 Sparat Landskap -STR_1046 :RollerCoaster Tycoon 2 Sparad Bandesign +STR_1043 :OpenRCT2 Sparat Spel +STR_1044 :OpenRCT2 Sparat Scenario +STR_1045 :OpenRCT2 Sparat Landskap +STR_1046 :OpenRCT2 Sparad Bandesign STR_1047 :Misslyckades med att spara spelet! STR_1048 :Misslyckades med att spara scenario! STR_1049 :Misslyckades med att spara landskap! @@ -1066,7 +1067,7 @@ STR_1061 :Normalt läge STR_1062 :Kontinuerligt banläge #TODO STR_1063 :Reverse-Incline launched shuttle mode -STR_1064 :Accelererad start +STR_1064 :Accelererad start (passing station) STR_1065 :Pendlarläge STR_1066 :Uthyrning STR_1067 :Uppskjut @@ -1093,12 +1094,12 @@ STR_1087 :3D film: {ENDQUOTES}Rymdrädarna{ENDQUOTES} STR_1088 :Intensivt läge STR_1089 :Berserkläge STR_1090 :Spökhuset -STR_1091 :Circusvisning +STR_1091 :Cirkusvisning STR_1092 :Nedåtriktad start STR_1093 :Snea huset STR_1094 :Fritt fall STR_1095 :Blockavdelat kontinuerligt banläge -STR_1096 :Motoriserad start +STR_1096 :Motoriserad start (utan att passera station) STR_1097 :Blockavdelad motoriserad start STR_1098 :Rör sig mot slutet av {POP16}{STRINGID} STR_1099 :Väntar på passagerare vid {POP16}{STRINGID} @@ -1115,11 +1116,11 @@ STR_1109 :Svingar STR_1110 :Roterar STR_1111 :Roterar STR_1112 :Pågår -STR_1113 :Showing film +STR_1113 :Visar film STR_1114 :Rotating STR_1115 :Pågår STR_1116 :Pågår -STR_1117 :Circusshow pågår +STR_1117 :Cirkusshow pågår STR_1118 :Pågår STR_1119 :Väntar på linbanevagn STR_1120 :Åker i {VELOCITY} @@ -1749,7 +1750,7 @@ STR_1742 :{WINDOW_COLOUR_2}Max. people on Åktur: STR_1743 :{SMALLFONT}{BLACK}Maximum number of people allowed on this Åktur at one time STR_1744 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} STR_1745 :{COMMA16} -STR_1746 :Can't change this... +STR_1746 :Kan inte ändra detta... STR_1747 :{WINDOW_COLOUR_2}Tidsgräns: STR_1748 :{SMALLFONT}{BLACK}Tidsgräns för åkturen STR_1749 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{DURATION} @@ -1876,8 +1877,8 @@ STR_1869 :{WINDOW_COLOUR_2}Antal rotationer: STR_1870 :{SMALLFONT}{BLACK}Antal hela rotationer STR_1871 :{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{POP16}{COMMA16} STR_1872 :{COMMA16} -STR_1873 :{WINDOW_COLOUR_2}Inkomst: {BLACK}{CURRENCY} per timme -STR_1874 :{WINDOW_COLOUR_2}Vinst: {BLACK}{CURRENCY} per timme +STR_1873 :{WINDOW_COLOUR_2}Inkomst: {BLACK}{CURRENCY2DP} per timme +STR_1874 :{WINDOW_COLOUR_2}Vinst: {BLACK}{CURRENCY2DP} per timme STR_1875 :{BLACK} {SPRITE}{BLACK} {STRINGID} STR_1876 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{251}{19}{00}{00}Inspektera åkturer STR_1877 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{252}{19}{00}{00}Fixa åkturer @@ -1895,8 +1896,10 @@ STR_1888 :{WINDOW_COLOUR_2}Tid sen senaste inspektion: {BLACK}mer än 4 timma STR_1889 :{WINDOW_COLOUR_2}Dötid: {MOVE_X}{255}{BLACK}{COMMA16}% STR_1890 :{SMALLFONT}{BLACK}Välj hur ofta en mekaniker ska göra underhåll på den här åkturen STR_1891 :Ingen {STRINGID} i parken än! -STR_1892 :RollerCoaster Tycoon 2 -STR_1893 :Var god sätt in din RollerCoaster Tycoon 2-skiva i följande CD-läsare: +# The following two strings were used to display an error when the disc was missing. +# This has been replaced in OpenRCT2. +STR_1892 : +STR_1893 : STR_1894 :{WINDOW_COLOUR_2}{STRINGID} sålde: {BLACK}{COMMA32} STR_1895 :{SMALLFONT}{BLACK}Bygg ny Åktur/attraktion STR_1896 :{WINDOW_COLOUR_2}Utgifter/Inkomster @@ -2220,7 +2223,7 @@ STR_2213 :{SMALLFONT}{BLACK}Visa en lista över alla underhållare STR_2214 :Konstruktion är inte möjligt när spelet är pausat! STR_2215 :{STRINGID}{NEWLINE}({STRINGID}) STR_2216 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}C -STR_2217 :{WINDOW_COLOUR_2}{COMMA16}F +STR_2217 :{WINDOW_COLOUR_2}{COMMA16}{DEGREE}F STR_2218 :{RED}{STRINGID} på {STRINGID} har inte kommit tillbaka till {STRINGID} än!{NEWLINE}Kolla om den är fast STR_2219 :{RED}{COMMA16} personer har dött i en olycka på {STRINGID} STR_2220 :{WINDOW_COLOUR_2}Parkomdöme: {BLACK}{COMMA16} @@ -2320,10 +2323,10 @@ STR_2313 :{WINDOW_COLOUR_2}Illamåendenivå: {BLACK}{COMMA2DP32} (approx.) STR_2314 :{WINDOW_COLOUR_2}Åkturslängd: {BLACK}{STRINGID} STR_2315 :{WINDOW_COLOUR_2}Kostnad: {BLACK}ca {CURRENCY} STR_2316 :{WINDOW_COLOUR_2}Storlek: {BLACK}{COMMA16} x {COMMA16} blocks -STR_2317 :{WINDOW_COLOUR_2}Ljudkvalitet: -STR_2318 :Låg -STR_2319 :Mellan -STR_2320 :Hög +STR_2317 : +STR_2318 : +STR_2319 : +STR_2320 : STR_2321 :{WINDOW_COLOUR_2}Antal åkturer/attraktioner: {BLACK}{COMMA16} STR_2322 :{WINDOW_COLOUR_2}Personal: {BLACK}{COMMA16} STR_2323 :{WINDOW_COLOUR_2}Parkstorlek: {BLACK}{COMMA32}m{SQUARED} @@ -2370,7 +2373,7 @@ STR_2363 :Rutmönster på terräng STR_2364 :{SMALLFONT}{BLACK}Sätt på/av rutmönster på terrängen STR_2365 :Banken vägrar att utöka ditt lån! STR_2366 :Celsius ({DEGREE}C) -STR_2367 :Fahrenheit (F) +STR_2367 :Fahrenheit ({DEGREE}F) STR_2368 :Ingen STR_2369 :Låg STR_2370 :Mellan @@ -2440,12 +2443,12 @@ STR_2433 :{BLACK}Kuponger för gratis {STRINGID} STR_2434 :{BLACK}Kampanj för {STRINGID} STR_2435 :{BLACK}Kampanj för {STRINGID} STR_2436 :1 vecka -STR_2437 :2 veckor -STR_2438 :3 veckor -STR_2439 :4 veckor -STR_2440 :5 veckor -STR_2441 :6 veckor -STR_2442 :{BLACK}({STRINGID} återstår) +STR_2437 : +STR_2438 : +STR_2439 : +STR_2440 : +STR_2441 : +STR_2442 : STR_2443 :{WINDOW_COLOUR_2}Kostnad per vecka: {BLACK}{CURRENCY2DP} STR_2444 :{WINDOW_COLOUR_2}Totalkostnad: {BLACK}{CURRENCY2DP} STR_2445 :Starta kampanjen @@ -2683,11 +2686,11 @@ 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_2680 :All forskning färdig +STR_2681 :{MEDIUMFONT}{BLACK}Ökar pengarna med {CURRENCY} +STR_2682 : +STR_2683 : +STR_2684 :{SMALLFONT}{BLACK}En stor grupp anländer STR_2685 :Simplex Noise Parameters STR_2686 :{WINDOW_COLOUR_2}Low: STR_2687 :{WINDOW_COLOUR_2}High: @@ -2697,23 +2700,23 @@ 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_2694 :Generera +STR_2695 :Slumpvis terräng +STR_2696 :Placera trä 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_2700 :Autospar frekvens: +STR_2701 :Varje minut +STR_2702 :Var 5:e minut +STR_2703 :Var 15:e minut +STR_2704 :Var 30:e minut +STR_2705 :Varje timme +STR_2706 :Aldrig +STR_2707 :Öppna ett nytt fönster +STR_2708 :{WINDOW_COLOUR_1}Är du säker på att du vill skriva över {STRINGID}? +STR_2709 :Skriv över +STR_2710 :Skriv namnet på filen. STR_2711 :; STR_2712 := STR_2713 :, @@ -2723,24 +2726,24 @@ 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_2720 :{UINT16}sek +STR_2721 :{UINT16}sek +STR_2722 :{UINT16}min:{UINT16}sek +STR_2723 :{UINT16}min:{UINT16}sek +STR_2724 :{UINT16}mins:{UINT16}sek +STR_2725 :{UINT16}mins:{UINT16}sek 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_2728 :{UINT16}tim:{UINT16}min +STR_2729 :{UINT16}tim:{UINT16}mins +STR_2730 :{UINT16}tim:{UINT16}min +STR_2731 :{UINT16}tim:{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_2736 :{MONTH}, År {COMMA16} +STR_2737 :{STRINGID} {MONTH}, År {COMMA16} STR_2738 :Title screen music: STR_2739 :None STR_2740 :RollerCoaster Tycoon 1 @@ -2765,11 +2768,11 @@ 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é -STR_2762 :Betala För Åkturer +STR_2760 :+{CURRENCY} +STR_2761 : +STR_2762 : STR_2763 :??? -STR_2764 :Glada Gäster +STR_2764 : STR_2765 :Stort Tåg STR_2766 :Win scenario STR_2767 :Frys Klimat @@ -2787,7 +2790,7 @@ STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} # End of new strings STR_2779 :Viewport #{COMMA16} STR_2780 :Extra viewport -STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID} +STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID} STR_2782 :SHIFT + STR_2783 :CTRL + STR_2784 :Ändra snabbtangenter @@ -2867,7 +2870,7 @@ STR_2855 :{RED}{STRINGID} har ingen gångväg från sin utgång !{NEWLINE}Byg STR_2856 :{WINDOW_COLOUR_2}Handledning STR_2857 :{WINDOW_COLOUR_2}(Tryck ner en tangent eller musknapp för att ta kontroll) STR_2858 :Kan inte påbörja kampanj... -STR_2859 :En annan instans av RollerCoaster Tycoon 2 körs redan +STR_2859 :En annan instans av OpenRCT2 körs redan STR_2860 :Om Infogrames Interactive... STR_2861 :{WINDOW_COLOUR_2}Licensed to Infogrames Interactive Inc. STR_2862 :Om Musik... @@ -2905,7 +2908,7 @@ STR_2893 :{WINDOW_COLOUR_2}Searchlight Rag: (Scott Joplin/Allister Brimble) 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 Åktur: (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} @@ -2977,8 +2980,8 @@ STR_2965 :{WINDOW_COLOUR_2} STR_2966 : STR_2967 : STR_2968 : -STR_2969 :Use of this product is subject to the terms of a license agreement -STR_2970 :found in the product's {OPENQUOTES}ReadMe{ENDQUOTES} file and in the manual +STR_2969 : +STR_2970 : STR_2971 :Huvudfärg STR_2972 :Andra färg STR_2973 :Tredje färg @@ -3168,8 +3171,8 @@ STR_3156 : STR_3157 :karta STR_3158 :graf STR_3159 :lista -STR_3160 :RollerCoaster Tycoon 2: Startar för första gången... -STR_3161 :RollerCoaster Tycoon 2: Kollar objektfiler... +STR_3160 : +STR_3161 : STR_3162 :Kan inte allokera nog minne STR_3163 :Installerar ny data: STR_3164 :{BLACK}{COMMA16} valda (av max {COMMA16}) @@ -3345,7 +3348,7 @@ STR_3333 :Exportera plug-in-objekt med sparade spel STR_3334 :{SMALLFONT}{BLACK}Välj om plug-in objekt (extra objekt som inte följer med basspelet) ska sparas i sparade spel och scenarion, vilket låter spelare importera denna data STR_3335 :Berg- och dalbane-designer - Välj Åkturstyp & Fordon STR_3336 :Bandesign-hanterare - Välj Åkturstype -STR_3337 :Six Flags Park +STR_3337 : STR_3338 :{BLACK}Egendesignad layout STR_3339 :{BLACK}{COMMA16} design tillgängliga, eller egendesignad layout STR_3340 :{BLACK}{COMMA16} designer tillgängliga, eller egendesignad layout @@ -3399,6 +3402,7 @@ STR_3387 :Handledning för byggande av Berg- och dalbanor STR_3388 :Kan inte byta till det valda läget STR_3389 :Kan inte markera fler dekorationer... STR_3390 :För många saker markerade +# Start of tutorial strings. Not used at the moment, so not necessary to translate. STR_3391 :{SMALLFONT}{BLACK}Här är vår park - Låt oss titta runt en snabbis... STR_3392 :{SMALLFONT}{BLACK}Det snabbaste sättet att flytta kameran är att hålla ner den HÖGRA musknappen samtidigt som du flyttar musen... STR_3393 :{SMALLFONT}{BLACK}För att se mer av parken kan du zooma ut genom att klicka på ikonen på toppen av skärmen... @@ -3445,6 +3449,7 @@ STR_3433 :{SMALLFONT}{BLACK}Till sist lägger vi till 'blockbromsar', som lå STR_3434 :{SMALLFONT}{BLACK}Nu testar vi åkturen och se om den fungerar! STR_3435 :{SMALLFONT}{BLACK}Fantastiskt - Den fungerade! Dags att lägga till gångväger för att släppa in våra gäster till vår nya berg- och dalbana... STR_3436 :{SMALLFONT}{BLACK}Medans vi väntar på våra första passagerare kan vi modifiera åkturen lite grann... +# End of tutorial strings STR_3437 :{SMALLFONT}{BLACK}Rensa stora områden av dekorationer från terrängen STR_3438 :Kan inte ta bort alla dekorationer härifrån... STR_3439 :Rensa Dekorationer @@ -3455,164 +3460,10 @@ 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 + +# Note: as this is an unmaintained language, don't add new strings unless you intend to become the mainainer. diff --git a/data/title/faas.sv6 b/data/title/faas.sv6 deleted file mode 100644 index bb7ce80cb7..0000000000 Binary files a/data/title/faas.sv6 and /dev/null differ diff --git a/data/title/achilleshiel.sv6 b/data/title/openrct2/achilleshiel.sv6 similarity index 100% rename from data/title/achilleshiel.sv6 rename to data/title/openrct2/achilleshiel.sv6 diff --git a/data/title/openrct2/alexfablelake.SV6 b/data/title/openrct2/alexfablelake.SV6 new file mode 100644 index 0000000000..b48dbf132e Binary files /dev/null and b/data/title/openrct2/alexfablelake.SV6 differ diff --git a/data/title/openrct2/bigfoot.sv6 b/data/title/openrct2/bigfoot.sv6 new file mode 100644 index 0000000000..662a7b28ac Binary files /dev/null and b/data/title/openrct2/bigfoot.sv6 differ diff --git a/data/title/openrct2/gymnasiast1.sv6 b/data/title/openrct2/gymnasiast1.sv6 new file mode 100644 index 0000000000..916823ef7a Binary files /dev/null and b/data/title/openrct2/gymnasiast1.sv6 differ diff --git a/data/title/openrct2/gymnasiast2.sv6 b/data/title/openrct2/gymnasiast2.sv6 new file mode 100644 index 0000000000..a678752eb4 Binary files /dev/null and b/data/title/openrct2/gymnasiast2.sv6 differ diff --git a/data/title/mci.sv6 b/data/title/openrct2/mci.sv6 similarity index 100% rename from data/title/mci.sv6 rename to data/title/openrct2/mci.sv6 diff --git a/data/title/openrct2/netgrouppark.sv6 b/data/title/openrct2/netgrouppark.sv6 new file mode 100644 index 0000000000..4d8554ce80 Binary files /dev/null and b/data/title/openrct2/netgrouppark.sv6 differ diff --git a/data/title/openrct2/pfckrutonium1.sv6 b/data/title/openrct2/pfckrutonium1.sv6 new file mode 100644 index 0000000000..907da0bde0 Binary files /dev/null and b/data/title/openrct2/pfckrutonium1.sv6 differ diff --git a/data/title/openrct2/phann.sv6 b/data/title/openrct2/phann.sv6 new file mode 100644 index 0000000000..ca3846acb5 Binary files /dev/null and b/data/title/openrct2/phann.sv6 differ diff --git a/data/title/poke.sv6 b/data/title/openrct2/poke.sv6 similarity index 100% rename from data/title/poke.sv6 rename to data/title/openrct2/poke.sv6 diff --git a/data/title/rid6.sv6 b/data/title/openrct2/rid6.sv6 similarity index 100% rename from data/title/rid6.sv6 rename to data/title/openrct2/rid6.sv6 diff --git a/data/title/openrct2/script.txt b/data/title/openrct2/script.txt new file mode 100644 index 0000000000..0943a1bd72 --- /dev/null +++ b/data/title/openrct2/script.txt @@ -0,0 +1,81 @@ +# OpenRCT2 0.0.3 Title Sequence Script +# Arranged by Gymnasiast (Michael Steenbeek). +# Based on the 0.0.2 script, which was arranged by IntelOrca. + + +LOAD pfckrutonium1.sv6 +LOCATION 7 41 +WAIT 10 + +LOAD netgrouppark.sv6 +LOCATION 91 10 +WAIT 9 + +LOCATION 25 15 +WAIT 9 + +LOAD bigfoot.sv6 +LOCATION 58 29 +WAIT 10 + +ROTATE 1 +LOCATION 29 63 +WAIT 10 + +LOAD gymnasiast2.sv6 +LOCATION 39 79 +WAIT 11 + +LOAD achilleshiel.sv6 +LOCATION 25 77 +WAIT 10 + +LOCATION 36 58 +ROTATE 3 +WAIT 8 + +LOAD mci.sv6 +LOCATION 46 60 +WAIT 6 + +LOCATION 76 32 +ROTATE 1 +WAIT 11 + +LOAD phann.sv6 +LOCATION 96 73 +WAIT 8 + +LOAD rid6.sv6 +LOCATION 56 34 +WAIT 8 + +LOCATION 10 29 +ROTATE 1 +WAIT 8 + +LOAD gymnasiast1.sv6 +LOCATION 51 46 +WAIT 11 + +LOAD alexfablelake.SV6 +LOCATION 50 25 +WAIT 9 + +ROTATE 1 +LOCATION 35 74 +WAIT 9 + +LOAD poke.sv6 +LOCATION 43 83 +WAIT 9 + +LOCATION 63 35 +ROTATE 3 +WAIT 9 + +LOCATION 12 47 +ROTATE 3 +WAIT 6 + +RESTART diff --git a/data/title/pfckrutonium1.sv6 b/data/title/pfckrutonium1.sv6 deleted file mode 100644 index 25ba708455..0000000000 Binary files a/data/title/pfckrutonium1.sv6 and /dev/null differ diff --git a/data/title/pfckrutonium2.sv6 b/data/title/pfckrutonium2.sv6 deleted file mode 100644 index 59de4c0c38..0000000000 Binary files a/data/title/pfckrutonium2.sv6 and /dev/null differ diff --git a/data/title/rct2/script.txt b/data/title/rct2/script.txt new file mode 100644 index 0000000000..3f4e303f7b --- /dev/null +++ b/data/title/rct2/script.txt @@ -0,0 +1,34 @@ +# RollerCoaster Tycoon 2 Title Sequence + +LOADMM + +LOCATION 210 112 +WAIT 13 + +ROTATE 1 +LOCATION 210 112 +WAIT 14 + +ROTATE 3 +LOCATION 167 180 +WAIT 12 + +ROTATE 1 +LOCATION 155 189 +WAIT 12 + +LOCATION 106 39 +WAIT 12 + +LOCATION 182 50 +WAIT 12 + +ROTATE 3 +LOCATION 209 47 +WAIT 12 + +ROTATE 1 +LOCATION 159 93 +WAIT 12 + +RESTART diff --git a/data/title/script.txt b/data/title/script.txt deleted file mode 100644 index 861dbd25e8..0000000000 --- a/data/title/script.txt +++ /dev/null @@ -1,106 +0,0 @@ -# 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 deleted file mode 100644 index a40b6425a4..0000000000 Binary files a/data/title/shotguns.sv6 and /dev/null differ diff --git a/data/title/triggerdeath.sv6 b/data/title/triggerdeath.sv6 deleted file mode 100644 index ff00a979bb..0000000000 Binary files a/data/title/triggerdeath.sv6 and /dev/null differ diff --git a/distribution/changelog.txt b/distribution/changelog.txt index ea635d13f8..9a56b27bae 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,3 +1,66 @@ +0.0.3-beta (2015-11-30) +------------------------------------------------------------------------ +- Feature: Adding extra title sequences. +- Feature: Title sequences can be edited in-game. +- Feature: Uncapped FPS. +- Feature: Ride selection in the Editor can now be sorted on track type or vehicle type. +- Feature: Load/save window can be sorted on date. +- Feature: Sandbox now a menu toggle. +- Feature: Improved ability to disable clearance checks via menu toggle. +- Feature: Added ability to disable support limits via menu toggle. +- Feature: Cheat to clear the crash record of each ride. +- Feature: Cheat to set all rides to 10 minute inspections. +- Feature: Cheats for guest parameters like hunger, energy, nausea etc. +- Feature: Cheats for park parameters like guest generation, loan settings and switching to and from not using money. +- Feature: Cheats for showing vehicles from other track types and enabling all operating modes. +- Feature: Clear Scenery can now be used for sizes up to 64x64. +- Feature: The mountain tool can now be used for sizes up to 64x64. +- Feature: Built-in load/save window is now used for converting saved games to scenarios. +- Feature: Cooperative multiplayer (has some game-breaking bugs). +- Feature: Native Linux support. +- Feature: Console commands for fixing 'Name already in use' and banner count errors. +- Feature: Scenario and object descriptions are now translatable. +- Feature: UI stays responsive in pause mode. +- Feature: Marketing campaign can now be run for up to 12 weeks. +- Feature: Day/night cycle. +- Feature: Added ability to save (over last file) as opposed to save as. +- Feature: Custom user data path specified by command line argument. +- Feature: Full UTF-8 language support. +- Feature: TTF font integration for non-Latin languages. +- Feature: Added support for Traditional Chinese, Simplified Chinese, Korean, Russian, Finnish and Brazilian Portuguese. +- Feature: Added South Korean Won and Russian Rouble as currencies. +- Feature: Allow different date formats. +- Feature: Option to automatically pause the game on minimise from fullscreen. +- Feature: Option to automatically pause when Steam overlay is activated. +- Feature: Option to display all scrolling text banners as upper case (RCT1 style) +- Feature: Option to mute audio when game is not focused. +- Feature: Option to automatically place staff after hire. +- Feature: Option to enable 'mow grass' by default for handymen (RCT1 style) +- Feature: Option to ignore invalid checksums on loaded parks. +- Feature: Option to scale game display for better compatibility with high DPI screens. +- Alteration: Autosave is now measured in real-time rather than in-game date. +- Alteration: Hacked rides no longer have their reliability set to 0. +- Technical: DirectDraw, DirectInput, DirectPlay and DirectSound dependencies are no longer used. +- Removed: Six Flags branding and limitations. +- Removed: Infogrames disclaimer. +- Fix: When placing a track, the preview will now use the same orientation as the ghost. +- Fix: Grouping vehicles by track type no longer interferes with research. +- Fix: Fix corrupt map elements when loading a game. +- Fix: Fix corrupt peep counter when loading a game. +- Fix: Parks created in the Scenario Editor now select the standard staff uniform colours by default. +- Fix: Launched TD4 rides will now always use the RCT1 launch mode (that doesn't pass the station) (original bug). +- Fix: Guests will no longer ignore no entry signs if the tile contains more than one fence (original bug). +- Fix: Right-clicking a piece of launched lift will no longer crash the game (original bug). +- Fix: Fix bugs in calculation of Heartline Twister and Launched Freefall ratings (original bugs). +- Fix: Map window now displays the usable map size, not the technical one (original bug). +- Fix: TD4 River Rapids will now have the correct seat colour (original bug). +- Fix: Message sound will no longer play in the editor modes (original bug). +- Fix: Scenarios created with the Scenario Editor will now have the correct initial temperature for their climate (original bug). +- Fix: Financial information can no longer be accessed from the rides/attractions menu in parks that don't use money (original bug). +- Fix: The path tool and tracked-ride construction tool no longer interfere with one another in certain situations (original bug). +- Fix: Building a flat ride partially out of park boundaries will no longer trigger a misleading "too high for supports" message (original bug). +- Fix: On-ride photos are now factored into the calculations of a ride's income and profit per hour (original bug). + 0.0.2-beta (2015-06-21) ------------------------------------------------------------------------ - Feature: Intro sequence does not show by default. @@ -42,4 +105,4 @@ - 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 +- Fix: Litter bins now get full and require emptying by handymen. diff --git a/distribution/known_issues.txt b/distribution/known_issues.txt index 082aa54cc5..9e0a74180f 100644 --- a/distribution/known_issues.txt +++ b/distribution/known_issues.txt @@ -1,11 +1,6 @@ -Release version: 0.0.2-beta +Release version: 0.0.3-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 +Some 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 index b08d4d7da7..0ba70659e4 100644 --- a/distribution/readme.txt +++ b/distribution/readme.txt @@ -1,5 +1,5 @@ -Last updated: 2015-06-21 -Release version: 0.0.2-beta +Last updated: 2015-30-11 +Release version: 0.0.3-beta ------------------------------------------------------------------------ diff --git a/distribution/windows/install.nsi b/distribution/windows/install.nsi index 29177fc8a6..837658b62f 100644 --- a/distribution/windows/install.nsi +++ b/distribution/windows/install.nsi @@ -1,7 +1,7 @@ # Version numbers to update !define /ifndef APPV_MAJOR 0 !define /ifndef APPV_MINOR 0 -!define /ifndef APPV_MAINT 2 +!define /ifndef APPV_MAINT 3 !define /ifndef APPV_BUILD 0 !define /ifndef APPV_EXTRA "-beta" @@ -122,6 +122,9 @@ Section "!OpenRCT2" Section1 ; Copy the rest of the stuff SetOutPath "$INSTDIR\" + ; Copy curl ca file + File ..\..\curl-ca-bundle.crt + ; Copy curl ca file File ..\..\curl-ca-bundle.crt @@ -367,14 +370,14 @@ FunctionEnd ; $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 @@ -385,7 +388,7 @@ Function VersionCompare Push $5 Push $6 Push $7 - + begin: StrCpy $2 -1 IntOp $2 $2 + 1 @@ -395,7 +398,7 @@ Function VersionCompare StrCpy $4 $0 $2 IntOp $2 $2 + 1 StrCpy $0 $0 '' $2 - + StrCpy $2 -1 IntOp $2 $2 + 1 StrCpy $3 $1 1 $2 @@ -404,32 +407,32 @@ Function VersionCompare 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 @@ -438,7 +441,7 @@ Function VersionCompare goto end newer2: StrCpy $0 2 - + end: Pop $7 Pop $6 diff --git a/distribution/windows/win32.txt b/distribution/windows/win32.txt index ddf41a88ec..55988ec058 100644 --- a/distribution/windows/win32.txt +++ b/distribution/windows/win32.txt @@ -1,5 +1,5 @@ !define APPBITS 32 ; Define number of bits for the architecture -!define EXTRA_VERSION "XP SP3, Vista, 7 and 8.1" +!define EXTRA_VERSION "Vista, 7, 8.1 and 10" !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/dockerfiles/32bit/Dockerfile b/dockerfiles/32bit/Dockerfile new file mode 100644 index 0000000000..30ce06b4c4 --- /dev/null +++ b/dockerfiles/32bit/Dockerfile @@ -0,0 +1,29 @@ +FROM nfnty/arch-mini + +RUN pacman -Syyu --noconfirm +RUN pacman -S --noconfirm git curl jshon expac yajl wget unzip cmake +RUN pacman -S --noconfirm --needed base-devel + +RUN useradd -mg root travis +RUN usermod -aG wheel travis +RUN sed -i 's/# %wheel ALL=(ALL) NOPASSWD: ALL/%wheel ALL=(ALL) NOPASSWD: ALL/g' /etc/sudoers + +WORKDIR /tmp +USER travis +RUN curl -sLO https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=package-query +RUN mv PKGBUILD?h=package-query PKGBUILD +RUN makepkg +USER root +RUN pacman --noconfirm -U *.pkg.tar.xz +USER travis +RUN curl -sLO https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=yaourt +RUN mv PKGBUILD?h=yaourt PKGBUILD +RUN makepkg +USER root +RUN pacman --noconfirm -U *.pkg.tar.xz + +RUN pacman -R --noconfirm gcc +RUN yes | pacman -S gcc-libs-multilib +RUN pacman -S --noconfirm gcc-multilib +USER travis +RUN yaourt -S --noconfirm lib32-jansson lib32-curl lib32-sdl2 lib32-sdl2_ttf lib32-speex diff --git a/dockerfiles/full/Dockerfile b/dockerfiles/full/Dockerfile new file mode 100644 index 0000000000..a4202ee790 --- /dev/null +++ b/dockerfiles/full/Dockerfile @@ -0,0 +1,60 @@ +FROM nfnty/arch-mini + +RUN pacman -Syyu --noconfirm +RUN pacman -S --noconfirm git curl jshon expac +RUN pacman -S --noconfirm --needed base-devel +RUN pacman -S --noconfirm yajl + +RUN useradd -mg root travis +RUN usermod -aG wheel travis +RUN sed -i 's/# %wheel ALL=(ALL) NOPASSWD: ALL/%wheel ALL=(ALL) NOPASSWD: ALL/g' /etc/sudoers + +WORKDIR /tmp +USER travis +RUN curl -sLO https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=package-query +RUN mv PKGBUILD?h=package-query PKGBUILD +RUN makepkg +USER root +RUN pacman --noconfirm -U *.pkg.tar.xz +USER travis +RUN curl -sLO https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=yaourt +RUN mv PKGBUILD?h=yaourt PKGBUILD +RUN makepkg +USER root +RUN pacman --noconfirm -U *.pkg.tar.xz + +RUN pacman -R --noconfirm gcc +RUN yes | pacman -S gcc-libs-multilib +RUN pacman -S --noconfirm gcc-multilib cmake +RUN pacman -S --noconfirm cmake +USER travis +RUN yaourt -S --noconfirm mingw-w64-headers +RUN yaourt -S --noconfirm mingw-w64-gcc +RUN yaourt -S --noconfirm wine +RUN yaourt -S --noconfirm mingw-w64-zlib mingw-w64-pkg-config +RUN gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys D9C4D26D0E604491 BB5869F064EA74AB 9D5EAAF69013B842 D605848ED7E69871 4DE8FF2A63C7CC90 +RUN yaourt -S --noconfirm mingw-w64-openssl +RUN yaourt -S --noconfirm mingw-w64-jansson +RUN yaourt -S --noconfirm mingw-w64-libtasn1 +RUN yaourt -S --noconfirm mingw-w64-gmp +RUN yaourt -S --noconfirm mingw-w64-nettle +RUN yaourt -S --noconfirm mingw-w64-libffi +RUN yaourt -S --noconfirm mingw-w64-p11-kit +RUN yaourt -S --noconfirm mingw-w64-readline +RUN yaourt -S --noconfirm mingw-w64-gnutls +RUN yaourt -S --noconfirm mingw-w64-libunistring +RUN yaourt -S --noconfirm mingw-w64-termcap +RUN yaourt -S --noconfirm mingw-w64-gettext +RUN yaourt -S --noconfirm mingw-w64-libidn +RUN yaourt -S --noconfirm mingw-w64-curl +RUN yaourt -S --noconfirm mingw-w64-expat +RUN yaourt -S --noconfirm mingw-w64-libdbus +RUN yaourt -S --noconfirm mingw-w64-sdl2 +RUN yaourt -S --noconfirm mingw-w64-sdl2_ttf +RUN yaourt -S --noconfirm wget unzip +RUN yaourt -S --noconfirm lib32-jansson lib32-curl lib32-sdl2 lib32-sdl2_ttf +RUN yaourt -S --noconfirm lib32-speex +#RUN git clone https://github.com/OpenRCT2/OpenRCT2 +#WORKDIR /tmp/OpenRCT2 +#RUN ./install.sh +#RUN ./build.sh diff --git a/install.sh b/install.sh index 72cef29197..eb04f41dd3 100755 --- a/install.sh +++ b/install.sh @@ -1,13 +1,110 @@ #!/bin/bash SDL2_PV=2.0.3 +SDL2_TTF_PV=2.0.12 cachedir=.cache +liburl=https://openrct2.website/files/orctlibs.zip mkdir -p $cachedir -echo `uname` +echo $(uname) -if [[ `uname` == "Darwin" ]]; then +# Sets default target to "linux", if none specified +TARGET=${TARGET-linux} +# keep in sync with version in build.sh +libversion=3 +libVFile="./libversion" + +function download { + if command -v curl > /dev/null 2>&1; then + curl -L -o "$2" "$1" + elif command -v wget > /dev/null 2>&1; then + wget -O "$2" "$1" + else + echo "Please install either wget or curl to continue" + exit 1 + fi +} + +function download_sdl { + if [[ ! -f $cachedir/SDL2-devel-${SDL2_PV}-mingw.tar.gz ]]; then + download http://libsdl.org/release/SDL2-devel-${SDL2_PV}-mingw.tar.gz $cachedir/SDL2-devel-${SDL2_PV}-mingw.tar.gz; + fi + if [[ ! -f $cachedir/SDL2_ttf-devel-${SDL2_TTF_PV}-mingw.tar.gz ]]; then + download https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-devel-${SDL2_TTF_PV}-mingw.tar.gz $cachedir/SDL2_ttf-devel-${SDL2_TTF_PV}-mingw.tar.gz; + fi + if [[ ! -d $cachedir/SDL2-${SDL2_PV} ]]; then + pushd $cachedir + tar -xzf SDL2-devel-${SDL2_PV}-mingw.tar.gz + popd + fi + if [[ ! -d $cachedir/SDL2_ttf-${SDL2_TTF_PV} ]]; then + pushd $cachedir + tar -xzf SDL2_ttf-devel-${SDL2_TTF_PV}-mingw.tar.gz + popd + fi + # Apply platform patch + mingw_patch=libsdl2-mingw-2.0.3-fix-platform-detection-for-mingw.patch + if [[ ! -f $cachedir/$mingw_patch ]]; then + download "https://github.com/anyc/anyc-overlay/raw/master/media-libs/libsdl2-mingw/files/$mingw_patch" $cachedir/$mingw_patch; + + # XXX not sure how to make this idempotent. + pushd $cachedir/SDL2-${SDL2_PV}/i686-w64-mingw32/include/SDL2/ + echo "Applying patch." + patch -p2 < ../../../../$mingw_patch + popd + fi +} + +function download_libs { + if [[ ! -f $cachedir/orctlibs.zip ]]; then + download $liburl $cachedir/orctlibs.zip; + fi + if [[ ! -d $cachedir/orctlibs ]]; then + mkdir -p $cachedir/orctlibs + pushd $cachedir/orctlibs + unzip -uaq ../orctlibs.zip + popd + fi +} + +function install_cross_tools { + if [[ ! -d /usr/local/cross-tools ]]; then + sudo mkdir -p /usr/local/cross-tools + 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/ + sudo cp -r $cachedir/SDL2_ttf-${SDL2_TTF_PV}/i686-w64-mingw32 /usr/local/cross-tools/ + fi + if [[ ! -d /usr/local/cross-tools/orctlibs ]]; then + sudo mkdir -p /usr/local/cross-tools/orctlibs + sudo cp -rf $cachedir/orctlibs/glob/* /usr/local/cross-tools/orctlibs/. + fi +} + +function install_pkg_config { + if [[ ! -f $cachedir/i686-w64-mingw32-pkg-config ]]; then + # If this fails to work because of newlines, be sure you are running this + # script with Bash, and not sh. We should really move this to a separate + # file. + echo -e "#!/bin/sh\nexport PKG_CONFIG_PATH=/usr/local/cross-tools/i686-w64-mingw32/lib/pkgconfig:/usr/local/cross-tools/orctlibs/lib/pkgconfig\npkg-config \$@" > $cachedir/i686-w64-mingw32-pkg-config; + fi + + chmod +x $cachedir/i686-w64-mingw32-pkg-config + sudo cp $cachedir/i686-w64-mingw32-pkg-config /usr/local/bin/ + + ls -al /usr/local/bin | grep pkg-config + cat /usr/local/bin/i686-w64-mingw32-pkg-config +} + +function install_local_libs { + mkdir -p lib + cp -rf $cachedir/orctlibs/local/* ./lib/. +} + +echo TARGET = $TARGET + +if [[ $(uname) == "Darwin" ]]; then echo "Installation of OpenRCT2 assumes you have homebrew and use it to install packages." echo "Check if brew is installed" @@ -28,13 +125,6 @@ if [[ `uname` == "Darwin" ]]; then echo "brew was found" fi - echo "Check if wget is installed" - which -s wget - if [ $? -eq 1 ]; then - echo "wget is not installed, installing wget.." - eval "$package_command install wget" - fi - # Install packages with whatever command was found. # Very possible I'm missing some dependencies here. eval "$package_command install cmake wine" @@ -53,7 +143,7 @@ if [[ `uname` == "Darwin" ]]; then mingw_tar=$mingw_name"_20130531".tar.bz2 mingw_path=/usr/local/$mingw_name 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 + download "https://downloads.sourceforge.net/project/mingw-w64/Toolchains targetting Win32/Automated Builds/$mingw_tar" $cachedir/$mingw_tar fi if [[ ! -d "$mingw_path" ]]; then @@ -72,58 +162,53 @@ if [[ `uname` == "Darwin" ]]; then popd popd fi -elif [[ `uname` == "Linux" ]]; then - sudo apt-get install -y --force-yes binutils-mingw-w64-i686 gcc-mingw-w64-i686 g++-mingw-w64-i686 +elif [[ $(uname) == "Linux" ]]; then + if [[ -z "$TRAVIS" ]]; then + sudo apt-get install -y binutils-mingw-w64-i686 gcc-mingw-w64-i686 g++-mingw-w64-i686 cmake + if [[ -z "$DISABLE_G2_BUILD" ]]; then + sudo apt-get install -y wine + fi + else + # prevent build.sh from re-doing all the steps again + case "$TARGET" in + "linux") + sudo dpkg --add-architecture i386 + sudo apt-get update + sudo apt-get install --no-install-recommends -y --force-yes cmake libsdl2-dev:i386 libsdl2-ttf-dev:i386 gcc-4.8 pkg-config:i386 g++-4.8-multilib gcc-4.8-multilib libjansson-dev:i386 libspeex-dev:i386 libspeexdsp-dev:i386 libcurl4-openssl-dev:i386 libcrypto++-dev:i386 clang + download https://launchpad.net/ubuntu/+archive/primary/+files/libjansson4_2.7-1ubuntu1_i386.deb libjansson4_2.7-1ubuntu1_i386.deb + download https://launchpad.net/ubuntu/+archive/primary/+files/libjansson-dev_2.7-1ubuntu1_i386.deb libjansson-dev_2.7-1ubuntu1_i386.deb + sudo dpkg -i libjansson4_2.7-1ubuntu1_i386.deb + sudo dpkg -i libjansson-dev_2.7-1ubuntu1_i386.deb + sudo apt-get install -f + ;; + "windows") + sudo apt-get update + sudo apt-get install -y --force-yes binutils-mingw-w64-i686 gcc-mingw-w64-i686 g++-mingw-w64-i686 cmake + ;; + "docker32") + docker pull openrct2/openrct2:32bit-only + ;; + *) + echo "unkown target $TARGET" + exit 1 + esac + fi fi -if [[ ! -f $cachedir/SDL2-devel-${SDL2_PV}-mingw.tar.gz ]]; then - wget http://libsdl.org/release/SDL2-devel-${SDL2_PV}-mingw.tar.gz --output-document $cachedir/SDL2-devel-${SDL2_PV}-mingw.tar.gz; -fi -if [[ ! -d $cachedir/SDL2-${SDL2_PV} ]]; then - pushd $cachedir - 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 +download_libs +# mind the gap (trailing space) +if [[ $(uname) == "Darwin" ]]; then + shasum -a 256 $cachedir/orctlibs.zip | cut -f1 -d\ > $libVFile +else + sha256sum $cachedir/orctlibs.zip | cut -f1 -d\ > $libVFile fi +echo "Downloaded library with sha256sum: $(cat $libVFile)" +# Local libs are required for all targets +install_local_libs -# Apply platform patch -mingw_patch=libsdl2-mingw-2.0.3-fix-platform-detection-for-mingw.patch -if [[ ! -f $cachedir/$mingw_patch ]]; then - wget "https://github.com/anyc/anyc-overlay/raw/master/media-libs/libsdl2-mingw/files/$mingw_patch" --output-document $cachedir/$mingw_patch; - - # XXX not sure how to make this idempotent. - pushd $cachedir/SDL2-${SDL2_PV}/i686-w64-mingw32/include/SDL2/ - echo "Applying patch." - patch -p2 < ../../../../$mingw_patch - popd +if [[ $TARGET == "windows" ]]; then + download_sdl + install_cross_tools + install_pkg_config +# $TARGET == "windows" fi - -if [[ ! -d /usr/local/cross-tools ]]; then - sudo mkdir -p /usr/local/cross-tools -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 - # script with Bash, and not sh. We should really move this to a separate - # file. - echo -e "#!/bin/sh\nexport PKG_CONFIG_LIBDIR=/usr/local/cross-tools/i686-w64-mingw32/lib/pkgconfig\npkg-config \$@" > $cachedir/i686-w64-mingw32-pkg-config; -fi - -chmod +x $cachedir/i686-w64-mingw32-pkg-config -sudo cp $cachedir/i686-w64-mingw32-pkg-config /usr/local/bin/ - -ls -al /usr/local/bin | grep pkg-config -cat /usr/local/bin/i686-w64-mingw32-pkg-config diff --git a/lib/argparse/argparse.c b/lib/argparse/argparse.c deleted file mode 100644 index 3ecd4d1f2e..0000000000 --- a/lib/argparse/argparse.c +++ /dev/null @@ -1,323 +0,0 @@ -#include "argparse.h" - -#define OPT_UNSET 1 - -static const char * -prefix_skip(const char *str, const char *prefix) -{ - size_t len = strlen(prefix); - return strncmp(str, prefix, len) ? NULL : str + len; -} - -int -prefix_cmp(const char *str, const char *prefix) -{ - for (;; str++, prefix++) - if (!*prefix) - return 0; - else if (*str != *prefix) - return (unsigned char)*prefix - (unsigned char)*str; -} - -static void -argparse_error(struct argparse *this, const struct argparse_option *opt, - const char *reason) -{ - if (!strncmp(this->argv[0], "--", 2)) { - fprintf(stderr, "error: option `%s` %s\n", opt->long_name, reason); - exit(1); - } else { - fprintf(stderr, "error: option `%c` %s\n", opt->short_name, reason); - exit(1); - } -} - -static int -argparse_getvalue(struct argparse *this, const struct argparse_option *opt, - int flags) -{ - const char *s = NULL; - if (!opt->value) - goto skipped; - switch (opt->type) { - case ARGPARSE_OPT_BOOLEAN: - if (flags & OPT_UNSET) { - *(int *)opt->value = *(int *)opt->value - 1; - } else { - *(int *)opt->value = *(int *)opt->value + 1; - } - if (*(int *)opt->value < 0) { - *(int *)opt->value = 0; - } - break; - case ARGPARSE_OPT_BIT: - if (flags & OPT_UNSET) { - *(int *)opt->value &= ~opt->data; - } else { - *(int *)opt->value |= opt->data; - } - break; - case ARGPARSE_OPT_STRING: - if (this->optvalue) { - *(const char **)opt->value = this->optvalue; - this->optvalue = NULL; - } else if (this->argc > 1) { - this->argc--; - *(const char **)opt->value = *++this->argv; - } else { - argparse_error(this, opt, "requires a value"); - } - break; - case ARGPARSE_OPT_INTEGER: - if (this->optvalue) { - *(int *)opt->value = strtol(this->optvalue, (char **)&s, 0); - this->optvalue = NULL; - } else if (this->argc > 1) { - this->argc--; - *(int *)opt->value = strtol(*++this->argv, (char **)&s, 0); - } else { - argparse_error(this, opt, "requires a value"); - } - if (s[0] != '\0') - argparse_error(this, opt, "expects a numerical value"); - break; - default: - assert(0); - } - -skipped: - if (opt->callback) { - return opt->callback(this, opt); - } - - return 0; -} - -static void -argparse_options_check(const struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - switch (options->type) { - case ARGPARSE_OPT_END: - case ARGPARSE_OPT_BOOLEAN: - case ARGPARSE_OPT_BIT: - case ARGPARSE_OPT_INTEGER: - case ARGPARSE_OPT_STRING: - case ARGPARSE_OPT_GROUP: - continue; - default: - fprintf(stderr, "wrong option type: %d", options->type); - break; - } - } -} - -static int -argparse_short_opt(struct argparse *this, const struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - if (options->short_name == *this->optvalue) { - this->optvalue = this->optvalue[1] ? this->optvalue + 1 : NULL; - return argparse_getvalue(this, options, 0); - } - } - return -2; -} - -static int -argparse_long_opt(struct argparse *this, const struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - const char *rest; - int opt_flags = 0; - if (!options->long_name) - continue; - - rest = prefix_skip(this->argv[0] + 2, options->long_name); - if (!rest) { - // Negation allowed? - if (options->flags & OPT_NONEG) { - continue; - } - // Only boolean/bit allow negation. - if (options->type != ARGPARSE_OPT_BOOLEAN && options->type != ARGPARSE_OPT_BIT) { - continue; - } - - if (!prefix_cmp(this->argv[0] + 2, "no-")) { - rest = prefix_skip(this->argv[0] + 2 + 3, options->long_name); - if (!rest) - continue; - opt_flags |= OPT_UNSET; - } else { - continue; - } - } - if (*rest) { - if (*rest != '=') - continue; - this->optvalue = rest + 1; - } - return argparse_getvalue(this, options, opt_flags); - } - return -2; -} - -int -argparse_init(struct argparse *this, struct argparse_option *options, - const char *const *usage, int flags) -{ - memset(this, 0, sizeof(*this)); - this->options = options; - this->usage = usage; - this->flags = flags; - return 0; -} - -int -argparse_parse(struct argparse *this, int argc, const char **argv) -{ - this->argc = argc - 1; - this->argv = argv + 1; - this->out = argv; - - argparse_options_check(this->options); - - for (; this->argc; this->argc--, this->argv++) { - const char *arg = this->argv[0]; - if (arg[0] != '-' || !arg[1]) { - if (this->flags & ARGPARSE_STOP_AT_NON_OPTION) { - goto end; - } - // if it's not option or is a single char '-', copy verbatimly - this->out[this->cpidx++] = this->argv[0]; - continue; - } - // short option - if (arg[1] != '-') { - this->optvalue = arg + 1; - switch (argparse_short_opt(this, this->options)) { - case -1: - break; - case -2: - goto unknown; - } - while (this->optvalue) { - switch (argparse_short_opt(this, this->options)) { - case -1: - break; - case -2: - goto unknown; - } - } - continue; - } - // if '--' presents - if (!arg[2]) { - this->argc--; - this->argv++; - break; - } - // long option - switch (argparse_long_opt(this, this->options)) { - case -1: - break; - case -2: - goto unknown; - } - continue; - -unknown: - fprintf(stderr, "error: unknown option `%s`\n", this->argv[0]); - argparse_usage(this); - exit(1); - } - -end: - memmove(this->out + this->cpidx, this->argv, - this->argc * sizeof(*this->out)); - this->out[this->cpidx + this->argc] = NULL; - - return this->cpidx + this->argc; -} - -void -argparse_usage(struct argparse *this) -{ - fprintf(stdout, "Usage: %s\n", *this->usage++); - while (*this->usage && **this->usage) - fprintf(stdout, " or: %s\n", *this->usage++); - fputc('\n', stdout); - - const struct argparse_option *options; - - // figure out best width - size_t usage_opts_width = 0; - size_t len; - options = this->options; - for (; options->type != ARGPARSE_OPT_END; options++) { - len = 0; - if ((options)->short_name) { - len += 2; - } - if ((options)->short_name && (options)->long_name) { - len += 2; // separator ", " - } - if ((options)->long_name) { - len += strlen((options)->long_name) + 2; - } - if (options->type == ARGPARSE_OPT_INTEGER) { - len += strlen("="); - } else if (options->type == ARGPARSE_OPT_STRING) { - len += strlen("="); - } - len = ceil((float)len / 4) * 4; - if (usage_opts_width < len) { - usage_opts_width = len; - } - } - usage_opts_width += 4; // 4 spaces prefix - - options = this->options; - for (; options->type != ARGPARSE_OPT_END; options++) { - size_t pos = 0; - int pad = 0; - if (options->type == ARGPARSE_OPT_GROUP) { - fputc('\n', stdout); - pos += fprintf(stdout, "%s", options->help); - fputc('\n', stdout); - continue; - } - pos = fprintf(stdout, " "); - if (options->short_name) { - pos += fprintf(stdout, "-%c", options->short_name); - } - if (options->long_name && options->short_name) { - pos += fprintf(stdout, ", "); - } - if (options->long_name) { - pos += fprintf(stdout, "--%s", options->long_name); - } - if (options->type == ARGPARSE_OPT_INTEGER) { - pos += fprintf(stdout, "="); - } else if (options->type == ARGPARSE_OPT_STRING) { - pos += fprintf(stdout, "="); - } - if (pos <= usage_opts_width) { - pad = usage_opts_width - pos; - } else { - fputc('\n', stdout); - pad = usage_opts_width; - } - fprintf(stdout, "%*s%s\n", pad + 2, "", options->help); - } -} - -int -argparse_help_cb(struct argparse *this, const struct argparse_option *option) -{ - (void)option; - argparse_usage(this); - exit(0); - return 0; -} diff --git a/lib/argparse/argparse.h b/lib/argparse/argparse.h deleted file mode 100644 index 350ee58df4..0000000000 --- a/lib/argparse/argparse.h +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef ARGPARSE_H -#define ARGPARSE_H -/** - * Command-line arguments parsing library. - * - * This module is inspired by parse-options.c (git) and python's argparse - * module. - * - * Arguments parsing is common task in cli program, but traditional `getopt` - * libraries are not easy to use. This library provides high-level arguments - * parsing solutions. - * - * The program defines what arguments it requires, and `argparse` will figure - * out how to parse those out of `argc` and `argv`, it also automatically - * generates help and usage messages and issues errors when users give the - * program invalid arguments. - * - * Reserved namespaces: - * argparse - * OPT - * Author: Yecheng Fu - */ - -#include -#include -#include -#include -#include -#include - -struct argparse; -struct argparse_option; - -typedef int argparse_callback(struct argparse *this, - const struct argparse_option *option); - -enum argparse_flag { - ARGPARSE_STOP_AT_NON_OPTION = 1, -}; - -enum argparse_option_type { - /* special */ - ARGPARSE_OPT_END, - ARGPARSE_OPT_GROUP, - /* options with no arguments */ - ARGPARSE_OPT_BOOLEAN, - ARGPARSE_OPT_BIT, - /* options with arguments (optional or required) */ - ARGPARSE_OPT_INTEGER, - ARGPARSE_OPT_STRING, -}; - -enum argparse_option_flags { - OPT_NONEG = 1, /* Negation disabled. */ -}; - -/* - * Argparse option struct. - * - * `type`: - * holds the type of the option, you must have an ARGPARSE_OPT_END last in your - * array. - * - * `short_name`: - * the character to use as a short option name, '\0' if none. - * - * `long_name`: - * the long option name, without the leading dash, NULL if none. - * - * `value`: - * stores pointer to the value to be filled. - * - * `help`: - * the short help message associated to what the option does. - * Must never be NULL (except for ARGPARSE_OPT_END). - * - * `callback`: - * function is called when corresponding argument is parsed. - * - * `data`: - * associated data. Callbacks can use it like they want. - * - * `flags`: - * option flags. - * - */ -struct argparse_option { - enum argparse_option_type type; - const char short_name; - const char *long_name; - void *value; - const char *help; - argparse_callback *callback; - intptr_t data; - int flags; -}; - -/* - * argpparse - */ -struct argparse { - // user supplied - const struct argparse_option *options; - const char *const *usage; - int flags; - // internal context - int argc; - const char **argv; - const char **out; - int cpidx; - const char *optvalue; // current option value -}; - -// builtin callbacks -int argparse_help_cb(struct argparse *this, - const struct argparse_option *option); - -// builtin option macros -#define OPT_END() { ARGPARSE_OPT_END } -#define OPT_BOOLEAN(...) { ARGPARSE_OPT_BOOLEAN, __VA_ARGS__ } -#define OPT_BIT(...) { ARGPARSE_OPT_BIT, __VA_ARGS__ } -#define OPT_INTEGER(...) { ARGPARSE_OPT_INTEGER, __VA_ARGS__ } -#define OPT_STRING(...) { ARGPARSE_OPT_STRING, __VA_ARGS__ } -#define OPT_GROUP(h) { ARGPARSE_OPT_GROUP, 0, NULL, NULL, h, NULL } -#define OPT_HELP() OPT_BOOLEAN('h', "help", NULL, "show this help message and exit", argparse_help_cb) - -int argparse_init(struct argparse *this, struct argparse_option *options, - const char *const *usage, int flags); -int argparse_parse(struct argparse *this, int argc, const char **argv); -void argparse_usage(struct argparse *this); - -#endif diff --git a/lib/cutest/CuTest.c b/lib/cutest/CuTest.c deleted file mode 100644 index 8f611991a8..0000000000 --- a/lib/cutest/CuTest.c +++ /dev/null @@ -1,339 +0,0 @@ -#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 deleted file mode 100644 index 8b32773d2b..0000000000 --- a/lib/cutest/CuTest.h +++ /dev/null @@ -1,116 +0,0 @@ -#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 deleted file mode 100644 index fd81689df4..0000000000 --- a/lib/cutest/license.txt +++ /dev/null @@ -1,38 +0,0 @@ -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/lib/libspeex/arch.h b/lib/libspeex/arch.h deleted file mode 100644 index d38c36ce7c..0000000000 --- a/lib/libspeex/arch.h +++ /dev/null @@ -1,239 +0,0 @@ -/* Copyright (C) 2003 Jean-Marc Valin */ -/** - @file arch.h - @brief Various architecture definitions Speex -*/ -/* - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - - Neither the name of the Xiph.org Foundation nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef ARCH_H -#define ARCH_H - -#ifndef SPEEX_VERSION -#define SPEEX_MAJOR_VERSION 1 /**< Major Speex version. */ -#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */ -#define SPEEX_MICRO_VERSION 15 /**< Micro Speex version. */ -#define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */ -#define SPEEX_VERSION "speex-1.2beta3" /**< Speex version string. */ -#endif - -/* A couple test to catch stupid option combinations */ -#ifdef FIXED_POINT - -#ifdef FLOATING_POINT -#error You cannot compile as floating point and fixed point at the same time -#endif -#ifdef _USE_SSE -#error SSE is only for floating-point -#endif -#if ((defined (ARM4_ASM)||defined (ARM4_ASM)) && defined(BFIN_ASM)) || (defined (ARM4_ASM)&&defined(ARM5E_ASM)) -#error Make up your mind. What CPU do you have? -#endif -#ifdef VORBIS_PSYCHO -#error Vorbis-psy model currently not implemented in fixed-point -#endif - -#else - -#ifndef FLOATING_POINT -#error You now need to define either FIXED_POINT or FLOATING_POINT -#endif -#if defined (ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM) -#error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions? -#endif -#ifdef FIXED_POINT_DEBUG -#error "Don't you think enabling fixed-point is a good thing to do if you want to debug that?" -#endif - - -#endif - -#ifndef OUTSIDE_SPEEX -#include "speex/speex_types.h" -#endif - -#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */ -#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */ -#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */ -#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ -#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */ -#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */ -#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ - -#ifdef FIXED_POINT - -typedef spx_int16_t spx_word16_t; -typedef spx_int32_t spx_word32_t; -typedef spx_word32_t spx_mem_t; -typedef spx_word16_t spx_coef_t; -typedef spx_word16_t spx_lsp_t; -typedef spx_word32_t spx_sig_t; - -#define Q15ONE 32767 - -#define LPC_SCALING 8192 -#define SIG_SCALING 16384 -#define LSP_SCALING 8192. -#define GAMMA_SCALING 32768. -#define GAIN_SCALING 64 -#define GAIN_SCALING_1 0.015625 - -#define LPC_SHIFT 13 -#define LSP_SHIFT 13 -#define SIG_SHIFT 14 -#define GAIN_SHIFT 6 - -#define VERY_SMALL 0 -#define VERY_LARGE32 ((spx_word32_t)2147483647) -#define VERY_LARGE16 ((spx_word16_t)32767) -#define Q15_ONE ((spx_word16_t)32767) - - -#ifdef FIXED_DEBUG -#include "fixed_debug.h" -#else - -#include "fixed_generic.h" - -#ifdef ARM5E_ASM -#include "fixed_arm5e.h" -#elif defined (ARM4_ASM) -#include "fixed_arm4.h" -#elif defined (BFIN_ASM) -#include "fixed_bfin.h" -#endif - -#endif - - -#else - -typedef float spx_mem_t; -typedef float spx_coef_t; -typedef float spx_lsp_t; -typedef float spx_sig_t; -typedef float spx_word16_t; -typedef float spx_word32_t; - -#define Q15ONE 1.0f -#define LPC_SCALING 1.f -#define SIG_SCALING 1.f -#define LSP_SCALING 1.f -#define GAMMA_SCALING 1.f -#define GAIN_SCALING 1.f -#define GAIN_SCALING_1 1.f - - -#define VERY_SMALL 1e-15f -#define VERY_LARGE32 1e15f -#define VERY_LARGE16 1e15f -#define Q15_ONE ((spx_word16_t)1.f) - -#define QCONST16(x,bits) (x) -#define QCONST32(x,bits) (x) - -#define NEG16(x) (-(x)) -#define NEG32(x) (-(x)) -#define EXTRACT16(x) (x) -#define EXTEND32(x) (x) -#define SHR16(a,shift) (a) -#define SHL16(a,shift) (a) -#define SHR32(a,shift) (a) -#define SHL32(a,shift) (a) -#define PSHR16(a,shift) (a) -#define PSHR32(a,shift) (a) -#define VSHR32(a,shift) (a) -#define SATURATE16(x,a) (x) -#define SATURATE32(x,a) (x) - -#define PSHR(a,shift) (a) -#define SHR(a,shift) (a) -#define SHL(a,shift) (a) -#define SATURATE(x,a) (x) - -#define ADD16(a,b) ((a)+(b)) -#define SUB16(a,b) ((a)-(b)) -#define ADD32(a,b) ((a)+(b)) -#define SUB32(a,b) ((a)-(b)) -#define MULT16_16_16(a,b) ((a)*(b)) -#define MULT16_16(a,b) ((spx_word32_t)(a)*(spx_word32_t)(b)) -#define MAC16_16(c,a,b) ((c)+(spx_word32_t)(a)*(spx_word32_t)(b)) - -#define MULT16_32_Q11(a,b) ((a)*(b)) -#define MULT16_32_Q13(a,b) ((a)*(b)) -#define MULT16_32_Q14(a,b) ((a)*(b)) -#define MULT16_32_Q15(a,b) ((a)*(b)) -#define MULT16_32_P15(a,b) ((a)*(b)) - -#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b)) -#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) - -#define MAC16_16_Q11(c,a,b) ((c)+(a)*(b)) -#define MAC16_16_Q13(c,a,b) ((c)+(a)*(b)) -#define MAC16_16_P13(c,a,b) ((c)+(a)*(b)) -#define MULT16_16_Q11_32(a,b) ((a)*(b)) -#define MULT16_16_Q13(a,b) ((a)*(b)) -#define MULT16_16_Q14(a,b) ((a)*(b)) -#define MULT16_16_Q15(a,b) ((a)*(b)) -#define MULT16_16_P15(a,b) ((a)*(b)) -#define MULT16_16_P13(a,b) ((a)*(b)) -#define MULT16_16_P14(a,b) ((a)*(b)) - -#define DIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) -#define PDIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) -#define DIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) -#define PDIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) - - -#endif - - -#if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) - -/* 2 on TI C5x DSP */ -#define BYTES_PER_CHAR 2 -#define BITS_PER_CHAR 16 -#define LOG2_BITS_PER_CHAR 4 - -#else - -#define BYTES_PER_CHAR 1 -#define BITS_PER_CHAR 8 -#define LOG2_BITS_PER_CHAR 3 - -#endif - - - -#ifdef FIXED_DEBUG -extern long long spx_mips; -#endif - - -#endif diff --git a/lib/libspeex/config.h b/lib/libspeex/config.h deleted file mode 100644 index abd35f0914..0000000000 --- a/lib/libspeex/config.h +++ /dev/null @@ -1,20 +0,0 @@ -// Microsoft version of 'inline' -#define inline __inline - -// Visual Studio support alloca(), but it always align variables to 16-bit -// boundary, while SSE need 128-bit alignment. So we disable alloca() when -// SSE is enabled. -#ifndef _USE_SSE -# define USE_ALLOCA -#endif - -/* Default to floating point */ -#ifndef FIXED_POINT -# define FLOATING_POINT -# define USE_SMALLFT -#else -# define USE_KISS_FFT -#endif - -/* We don't support visibility on Win32 */ -#define EXPORT diff --git a/lib/libspeex/os_support.h b/lib/libspeex/os_support.h deleted file mode 100644 index 6b74b0c22f..0000000000 --- a/lib/libspeex/os_support.h +++ /dev/null @@ -1,169 +0,0 @@ -/* Copyright (C) 2007 Jean-Marc Valin - - File: os_support.h - This is the (tiny) OS abstraction layer. Aside from math.h, this is the - only place where system headers are allowed. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef OS_SUPPORT_H -#define OS_SUPPORT_H - -#include -#include -#include - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#ifdef OS_SUPPORT_CUSTOM -#include "os_support_custom.h" -#endif - -/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free - NOTE: speex_alloc needs to CLEAR THE MEMORY */ -#ifndef OVERRIDE_SPEEX_ALLOC -static inline void *speex_alloc (int size) -{ - /* WARNING: this is not equivalent to malloc(). If you want to use malloc() - or your own allocator, YOU NEED TO CLEAR THE MEMORY ALLOCATED. Otherwise - you will experience strange bugs */ - return calloc(size,1); -} -#endif - -/** Same as speex_alloc, except that the area is only needed inside a Speex call (might cause problem with wideband though) */ -#ifndef OVERRIDE_SPEEX_ALLOC_SCRATCH -static inline void *speex_alloc_scratch (int size) -{ - /* Scratch space doesn't need to be cleared */ - return calloc(size,1); -} -#endif - -/** Speex wrapper for realloc. To do your own dynamic allocation, all you need to do is replace this function, speex_alloc and speex_free */ -#ifndef OVERRIDE_SPEEX_REALLOC -static inline void *speex_realloc (void *ptr, int size) -{ - return realloc(ptr, size); -} -#endif - -/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_alloc */ -#ifndef OVERRIDE_SPEEX_FREE -static inline void speex_free (void *ptr) -{ - free(ptr); -} -#endif - -/** Same as speex_free, except that the area is only needed inside a Speex call (might cause problem with wideband though) */ -#ifndef OVERRIDE_SPEEX_FREE_SCRATCH -static inline void speex_free_scratch (void *ptr) -{ - free(ptr); -} -#endif - -/** Copy n bytes of memory from src to dst. The 0* term provides compile-time type checking */ -#ifndef OVERRIDE_SPEEX_COPY -#define SPEEX_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) -#endif - -/** Copy n bytes of memory from src to dst, allowing overlapping regions. The 0* term - provides compile-time type checking */ -#ifndef OVERRIDE_SPEEX_MOVE -#define SPEEX_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) -#endif - -/** Set n bytes of memory to value of c, starting at address s */ -#ifndef OVERRIDE_SPEEX_MEMSET -#define SPEEX_MEMSET(dst, c, n) (memset((dst), (c), (n)*sizeof(*(dst)))) -#endif - - -#ifndef OVERRIDE_SPEEX_FATAL -static inline void _speex_fatal(const char *str, const char *file, int line) -{ - fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); - exit(1); -} -#endif - -#ifndef OVERRIDE_SPEEX_WARNING -static inline void speex_warning(const char *str) -{ -#ifndef DISABLE_WARNINGS - fprintf (stderr, "warning: %s\n", str); -#endif -} -#endif - -#ifndef OVERRIDE_SPEEX_WARNING_INT -static inline void speex_warning_int(const char *str, int val) -{ -#ifndef DISABLE_WARNINGS - fprintf (stderr, "warning: %s %d\n", str, val); -#endif -} -#endif - -#ifndef OVERRIDE_SPEEX_NOTIFY -static inline void speex_notify(const char *str) -{ -#ifndef DISABLE_NOTIFICATIONS - fprintf (stderr, "notification: %s\n", str); -#endif -} -#endif - -#ifndef OVERRIDE_SPEEX_PUTC -/** Speex wrapper for putc */ -static inline void _speex_putc(int ch, void *file) -{ - FILE *f = (FILE *)file; - fprintf(f, "%c", ch); -} -#endif - -#define speex_fatal(str) _speex_fatal(str, __FILE__, __LINE__); -#define speex_assert(cond) {if (!(cond)) {speex_fatal("assertion failed: " #cond);}} - -#ifndef RELEASE -static inline void print_vec(float *vec, int len, char *name) -{ - int i; - printf ("%s ", name); - for (i=0;i -static void *speex_alloc (int size) {return calloc(size,1);} -static void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);} -static void speex_free (void *ptr) {free(ptr);} -#include "speex_resampler.h" -#include "arch.h" -#else /* OUTSIDE_SPEEX */ - -#include "speex/speex_resampler.h" -#include "arch.h" -#include "os_support.h" -#endif /* OUTSIDE_SPEEX */ - -#include "stack_alloc.h" -#include - -#ifndef M_PI -#define M_PI 3.14159263 -#endif - -#ifdef FIXED_POINT -#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) -#else -#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) -#endif - -#define IMAX(a,b) ((a) > (b) ? (a) : (b)) -#define IMIN(a,b) ((a) < (b) ? (a) : (b)) - -#ifndef NULL -#define NULL 0 -#endif - -#ifdef _USE_SSE -#include "resample_sse.h" -#endif - -/* Numer of elements to allocate on the stack */ -#ifdef VAR_ARRAYS -#define FIXED_STACK_ALLOC 8192 -#else -#define FIXED_STACK_ALLOC 1024 -#endif - -typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *); - -struct SpeexResamplerState_ { - spx_uint32_t in_rate; - spx_uint32_t out_rate; - spx_uint32_t num_rate; - spx_uint32_t den_rate; - - int quality; - spx_uint32_t nb_channels; - spx_uint32_t filt_len; - spx_uint32_t mem_alloc_size; - spx_uint32_t buffer_size; - int int_advance; - int frac_advance; - float cutoff; - spx_uint32_t oversample; - int initialised; - int started; - - /* These are per-channel */ - spx_int32_t *last_sample; - spx_uint32_t *samp_frac_num; - spx_uint32_t *magic_samples; - - spx_word16_t *mem; - spx_word16_t *sinc_table; - spx_uint32_t sinc_table_length; - resampler_basic_func resampler_ptr; - - int in_stride; - int out_stride; -} ; - -static double kaiser12_table[68] = { - 0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076, - 0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014, - 0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601, - 0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014, - 0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490, - 0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546, - 0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178, - 0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947, - 0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058, - 0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438, - 0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734, - 0.00001000, 0.00000000}; -/* -static double kaiser12_table[36] = { - 0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741, - 0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762, - 0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274, - 0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466, - 0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291, - 0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000}; -*/ -static double kaiser10_table[36] = { - 0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446, - 0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347, - 0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962, - 0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451, - 0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739, - 0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000}; - -static double kaiser8_table[36] = { - 0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200, - 0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126, - 0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272, - 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758, - 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, - 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000}; - -static double kaiser6_table[36] = { - 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003, - 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, - 0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561, - 0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058, - 0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600, - 0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000}; - -struct FuncDef { - double *table; - int oversample; -}; - -static struct FuncDef _KAISER12 = {kaiser12_table, 64}; -#define KAISER12 (&_KAISER12) -/*static struct FuncDef _KAISER12 = {kaiser12_table, 32}; -#define KAISER12 (&_KAISER12)*/ -static struct FuncDef _KAISER10 = {kaiser10_table, 32}; -#define KAISER10 (&_KAISER10) -static struct FuncDef _KAISER8 = {kaiser8_table, 32}; -#define KAISER8 (&_KAISER8) -static struct FuncDef _KAISER6 = {kaiser6_table, 32}; -#define KAISER6 (&_KAISER6) - -struct QualityMapping { - int base_length; - int oversample; - float downsample_bandwidth; - float upsample_bandwidth; - struct FuncDef *window_func; -}; - - -/* This table maps conversion quality to internal parameters. There are two - reasons that explain why the up-sampling bandwidth is larger than the - down-sampling bandwidth: - 1) When up-sampling, we can assume that the spectrum is already attenuated - close to the Nyquist rate (from an A/D or a previous resampling filter) - 2) Any aliasing that occurs very close to the Nyquist rate will be masked - by the sinusoids/noise just below the Nyquist rate (guaranteed only for - up-sampling). -*/ -static const struct QualityMapping quality_map[11] = { - { 8, 4, 0.830f, 0.860f, KAISER6 }, /* Q0 */ - { 16, 4, 0.850f, 0.880f, KAISER6 }, /* Q1 */ - { 32, 4, 0.882f, 0.910f, KAISER6 }, /* Q2 */ /* 82.3% cutoff ( ~60 dB stop) 6 */ - { 48, 8, 0.895f, 0.917f, KAISER8 }, /* Q3 */ /* 84.9% cutoff ( ~80 dB stop) 8 */ - { 64, 8, 0.921f, 0.940f, KAISER8 }, /* Q4 */ /* 88.7% cutoff ( ~80 dB stop) 8 */ - { 80, 16, 0.922f, 0.940f, KAISER10}, /* Q5 */ /* 89.1% cutoff (~100 dB stop) 10 */ - { 96, 16, 0.940f, 0.945f, KAISER10}, /* Q6 */ /* 91.5% cutoff (~100 dB stop) 10 */ - {128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */ /* 93.1% cutoff (~100 dB stop) 10 */ - {160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */ /* 94.5% cutoff (~100 dB stop) 10 */ - {192, 32, 0.968f, 0.968f, KAISER12}, /* Q9 */ /* 95.5% cutoff (~100 dB stop) 10 */ - {256, 32, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */ -}; -/*8,24,40,56,80,104,128,160,200,256,320*/ -static double compute_func(float x, struct FuncDef *func) -{ - float y, frac; - double interp[4]; - int ind; - y = x*func->oversample; - ind = (int)floor(y); - frac = (y-ind); - /* CSE with handle the repeated powers */ - interp[3] = -0.1666666667*frac + 0.1666666667*(frac*frac*frac); - interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac); - /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ - interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac); - /* Just to make sure we don't have rounding problems */ - interp[1] = 1.f-interp[3]-interp[2]-interp[0]; - - /*sum = frac*accum[1] + (1-frac)*accum[2];*/ - return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3]; -} - -#if 0 -#include -int main(int argc, char **argv) -{ - int i; - for (i=0;i<256;i++) - { - printf ("%f\n", compute_func(i/256., KAISER12)); - } - return 0; -} -#endif - -#ifdef FIXED_POINT -/* The slow way of computing a sinc for the table. Should improve that some day */ -static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func) -{ - /*fprintf (stderr, "%f ", x);*/ - float xx = x * cutoff; - if (fabs(x)<1e-6f) - return WORD2INT(32768.*cutoff); - else if (fabs(x) > .5f*N) - return 0; - /*FIXME: Can it really be any slower than this? */ - return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func)); -} -#else -/* The slow way of computing a sinc for the table. Should improve that some day */ -static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func) -{ - /*fprintf (stderr, "%f ", x);*/ - float xx = x * cutoff; - if (fabs(x)<1e-6) - return cutoff; - else if (fabs(x) > .5*N) - return 0; - /*FIXME: Can it really be any slower than this? */ - return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func); -} -#endif - -#ifdef FIXED_POINT -static void cubic_coef(spx_word16_t x, spx_word16_t interp[4]) -{ - /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation - but I know it's MMSE-optimal on a sinc */ - spx_word16_t x2, x3; - x2 = MULT16_16_P15(x, x); - x3 = MULT16_16_P15(x, x2); - interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15); - interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1)); - interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15); - /* Just to make sure we don't have rounding problems */ - interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3]; - if (interp[2]<32767) - interp[2]+=1; -} -#else -static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4]) -{ - /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation - but I know it's MMSE-optimal on a sinc */ - interp[0] = -0.16667f*frac + 0.16667f*frac*frac*frac; - interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac; - /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ - interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac; - /* Just to make sure we don't have rounding problems */ - interp[2] = 1.-interp[0]-interp[1]-interp[3]; -} -#endif - -static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) -{ - const int N = st->filt_len; - int out_sample = 0; - int last_sample = st->last_sample[channel_index]; - spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; - const spx_word16_t *sinc_table = st->sinc_table; - const int out_stride = st->out_stride; - const int int_advance = st->int_advance; - const int frac_advance = st->frac_advance; - const spx_uint32_t den_rate = st->den_rate; - spx_word32_t sum; - int j; - - while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) - { - const spx_word16_t *sinc = & sinc_table[samp_frac_num*N]; - const spx_word16_t *iptr = & in[last_sample]; - -#ifndef OVERRIDE_INNER_PRODUCT_SINGLE - float accum[4] = {0,0,0,0}; - - for(j=0;j= den_rate) - { - samp_frac_num -= den_rate; - last_sample++; - } - } - - st->last_sample[channel_index] = last_sample; - st->samp_frac_num[channel_index] = samp_frac_num; - return out_sample; -} - -#ifdef FIXED_POINT -#else -/* This is the same as the previous function, except with a double-precision accumulator */ -static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) -{ - const int N = st->filt_len; - int out_sample = 0; - int last_sample = st->last_sample[channel_index]; - spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; - const spx_word16_t *sinc_table = st->sinc_table; - const int out_stride = st->out_stride; - const int int_advance = st->int_advance; - const int frac_advance = st->frac_advance; - const spx_uint32_t den_rate = st->den_rate; - double sum; - int j; - - while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) - { - const spx_word16_t *sinc = & sinc_table[samp_frac_num*N]; - const spx_word16_t *iptr = & in[last_sample]; - -#ifndef OVERRIDE_INNER_PRODUCT_DOUBLE - double accum[4] = {0,0,0,0}; - - for(j=0;j= den_rate) - { - samp_frac_num -= den_rate; - last_sample++; - } - } - - st->last_sample[channel_index] = last_sample; - st->samp_frac_num[channel_index] = samp_frac_num; - return out_sample; -} -#endif - -static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) -{ - const int N = st->filt_len; - int out_sample = 0; - int last_sample = st->last_sample[channel_index]; - spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; - const int out_stride = st->out_stride; - const int int_advance = st->int_advance; - const int frac_advance = st->frac_advance; - const spx_uint32_t den_rate = st->den_rate; - int j; - spx_word32_t sum; - - while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) - { - const spx_word16_t *iptr = & in[last_sample]; - - const int offset = samp_frac_num*st->oversample/st->den_rate; -#ifdef FIXED_POINT - const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); -#else - const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; -#endif - spx_word16_t interp[4]; - - -#ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE - spx_word32_t accum[4] = {0,0,0,0}; - - for(j=0;jsinc_table[4+(j+1)*st->oversample-offset-2]); - accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); - accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); - accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); - } - - cubic_coef(frac, interp); - sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); -#else - cubic_coef(frac, interp); - sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); -#endif - - out[out_stride * out_sample++] = PSHR32(sum,15); - last_sample += int_advance; - samp_frac_num += frac_advance; - if (samp_frac_num >= den_rate) - { - samp_frac_num -= den_rate; - last_sample++; - } - } - - st->last_sample[channel_index] = last_sample; - st->samp_frac_num[channel_index] = samp_frac_num; - return out_sample; -} - -#ifdef FIXED_POINT -#else -/* This is the same as the previous function, except with a double-precision accumulator */ -static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) -{ - const int N = st->filt_len; - int out_sample = 0; - int last_sample = st->last_sample[channel_index]; - spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; - const int out_stride = st->out_stride; - const int int_advance = st->int_advance; - const int frac_advance = st->frac_advance; - const spx_uint32_t den_rate = st->den_rate; - int j; - spx_word32_t sum; - - while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) - { - const spx_word16_t *iptr = & in[last_sample]; - - const int offset = samp_frac_num*st->oversample/st->den_rate; -#ifdef FIXED_POINT - const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); -#else - const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; -#endif - spx_word16_t interp[4]; - - -#ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE - double accum[4] = {0,0,0,0}; - - for(j=0;jsinc_table[4+(j+1)*st->oversample-offset-2]); - accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); - accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); - accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); - } - - cubic_coef(frac, interp); - sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); -#else - cubic_coef(frac, interp); - sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); -#endif - - out[out_stride * out_sample++] = PSHR32(sum,15); - last_sample += int_advance; - samp_frac_num += frac_advance; - if (samp_frac_num >= den_rate) - { - samp_frac_num -= den_rate; - last_sample++; - } - } - - st->last_sample[channel_index] = last_sample; - st->samp_frac_num[channel_index] = samp_frac_num; - return out_sample; -} -#endif - -static void update_filter(SpeexResamplerState *st) -{ - spx_uint32_t old_length; - - old_length = st->filt_len; - st->oversample = quality_map[st->quality].oversample; - st->filt_len = quality_map[st->quality].base_length; - - if (st->num_rate > st->den_rate) - { - /* down-sampling */ - st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate; - /* FIXME: divide the numerator and denominator by a certain amount if they're too large */ - st->filt_len = st->filt_len*st->num_rate / st->den_rate; - /* Round down to make sure we have a multiple of 4 */ - st->filt_len &= (~0x3); - if (2*st->den_rate < st->num_rate) - st->oversample >>= 1; - if (4*st->den_rate < st->num_rate) - st->oversample >>= 1; - if (8*st->den_rate < st->num_rate) - st->oversample >>= 1; - if (16*st->den_rate < st->num_rate) - st->oversample >>= 1; - if (st->oversample < 1) - st->oversample = 1; - } else { - /* up-sampling */ - st->cutoff = quality_map[st->quality].upsample_bandwidth; - } - - /* Choose the resampling type that requires the least amount of memory */ - if (st->den_rate <= st->oversample) - { - spx_uint32_t i; - if (!st->sinc_table) - st->sinc_table = (spx_word16_t *)speex_alloc(st->filt_len*st->den_rate*sizeof(spx_word16_t)); - else if (st->sinc_table_length < st->filt_len*st->den_rate) - { - st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,st->filt_len*st->den_rate*sizeof(spx_word16_t)); - st->sinc_table_length = st->filt_len*st->den_rate; - } - for (i=0;iden_rate;i++) - { - spx_int32_t j; - for (j=0;jfilt_len;j++) - { - st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-(spx_int32_t)st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func); - } - } -#ifdef FIXED_POINT - st->resampler_ptr = resampler_basic_direct_single; -#else - if (st->quality>8) - st->resampler_ptr = resampler_basic_direct_double; - else - st->resampler_ptr = resampler_basic_direct_single; -#endif - /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/ - } else { - spx_int32_t i; - if (!st->sinc_table) - st->sinc_table = (spx_word16_t *)speex_alloc((st->filt_len*st->oversample+8)*sizeof(spx_word16_t)); - else if (st->sinc_table_length < st->filt_len*st->oversample+8) - { - st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,(st->filt_len*st->oversample+8)*sizeof(spx_word16_t)); - st->sinc_table_length = st->filt_len*st->oversample+8; - } - for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++) - st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func); -#ifdef FIXED_POINT - st->resampler_ptr = resampler_basic_interpolate_single; -#else - if (st->quality>8) - st->resampler_ptr = resampler_basic_interpolate_double; - else - st->resampler_ptr = resampler_basic_interpolate_single; -#endif - /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/ - } - st->int_advance = st->num_rate/st->den_rate; - st->frac_advance = st->num_rate%st->den_rate; - - - /* Here's the place where we update the filter memory to take into account - the change in filter length. It's probably the messiest part of the code - due to handling of lots of corner cases. */ - if (!st->mem) - { - spx_uint32_t i; - st->mem_alloc_size = st->filt_len-1 + st->buffer_size; - st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); - for (i=0;inb_channels*st->mem_alloc_size;i++) - st->mem[i] = 0; - /*speex_warning("init filter");*/ - } else if (!st->started) - { - spx_uint32_t i; - st->mem_alloc_size = st->filt_len-1 + st->buffer_size; - st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); - for (i=0;inb_channels*st->mem_alloc_size;i++) - st->mem[i] = 0; - /*speex_warning("reinit filter");*/ - } else if (st->filt_len > old_length) - { - spx_int32_t i; - /* Increase the filter length */ - /*speex_warning("increase filter size");*/ - int old_alloc_size = st->mem_alloc_size; - if ((st->filt_len-1 + st->buffer_size) > st->mem_alloc_size) - { - st->mem_alloc_size = st->filt_len-1 + st->buffer_size; - st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); - } - for (i=st->nb_channels-1;i>=0;i--) - { - spx_int32_t j; - spx_uint32_t olen = old_length; - /*if (st->magic_samples[i])*/ - { - /* Try and remove the magic samples as if nothing had happened */ - - /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */ - olen = old_length + 2*st->magic_samples[i]; - for (j=old_length-2+st->magic_samples[i];j>=0;j--) - st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j]; - for (j=0;jmagic_samples[i];j++) - st->mem[i*st->mem_alloc_size+j] = 0; - st->magic_samples[i] = 0; - } - if (st->filt_len > olen) - { - /* If the new filter length is still bigger than the "augmented" length */ - /* Copy data going backward */ - for (j=0;jmem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)]; - /* Then put zeros for lack of anything better */ - for (;jfilt_len-1;j++) - st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0; - /* Adjust last_sample */ - st->last_sample[i] += (st->filt_len - olen)/2; - } else { - /* Put back some of the magic! */ - st->magic_samples[i] = (olen - st->filt_len)/2; - for (j=0;jfilt_len-1+st->magic_samples[i];j++) - st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; - } - } - } else if (st->filt_len < old_length) - { - spx_uint32_t i; - /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic" - samples so they can be used directly as input the next time(s) */ - for (i=0;inb_channels;i++) - { - spx_uint32_t j; - spx_uint32_t old_magic = st->magic_samples[i]; - st->magic_samples[i] = (old_length - st->filt_len)/2; - /* We must copy some of the memory that's no longer used */ - /* Copy data going backward */ - for (j=0;jfilt_len-1+st->magic_samples[i]+old_magic;j++) - st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; - st->magic_samples[i] += old_magic; - } - } - -} - -EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) -{ - return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err); -} - -EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) -{ - spx_uint32_t i; - SpeexResamplerState *st; - if (quality > 10 || quality < 0) - { - if (err) - *err = RESAMPLER_ERR_INVALID_ARG; - return NULL; - } - st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState)); - st->initialised = 0; - st->started = 0; - st->in_rate = 0; - st->out_rate = 0; - st->num_rate = 0; - st->den_rate = 0; - st->quality = -1; - st->sinc_table_length = 0; - st->mem_alloc_size = 0; - st->filt_len = 0; - st->mem = 0; - st->resampler_ptr = 0; - - st->cutoff = 1.f; - st->nb_channels = nb_channels; - st->in_stride = 1; - st->out_stride = 1; - -#ifdef FIXED_POINT - st->buffer_size = 160; -#else - st->buffer_size = 160; -#endif - - /* Per channel data */ - st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int)); - st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); - st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); - for (i=0;ilast_sample[i] = 0; - st->magic_samples[i] = 0; - st->samp_frac_num[i] = 0; - } - - speex_resampler_set_quality(st, quality); - speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate); - - - update_filter(st); - - st->initialised = 1; - if (err) - *err = RESAMPLER_ERR_SUCCESS; - - return st; -} - -EXPORT void speex_resampler_destroy(SpeexResamplerState *st) -{ - speex_free(st->mem); - speex_free(st->sinc_table); - speex_free(st->last_sample); - speex_free(st->magic_samples); - speex_free(st->samp_frac_num); - speex_free(st); -} - -static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) -{ - int j=0; - const int N = st->filt_len; - int out_sample = 0; - spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; - spx_uint32_t ilen; - - st->started = 1; - - /* Call the right resampler through the function ptr */ - out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len); - - if (st->last_sample[channel_index] < (spx_int32_t)*in_len) - *in_len = st->last_sample[channel_index]; - *out_len = out_sample; - st->last_sample[channel_index] -= *in_len; - - ilen = *in_len; - - for(j=0;jmagic_samples[channel_index]; - spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; - const int N = st->filt_len; - - speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len); - - st->magic_samples[channel_index] -= tmp_in_len; - - /* If we couldn't process all "magic" input samples, save the rest for next time */ - if (st->magic_samples[channel_index]) - { - spx_uint32_t i; - for (i=0;imagic_samples[channel_index];i++) - mem[N-1+i]=mem[N-1+i+tmp_in_len]; - } - *out += out_len*st->out_stride; - return out_len; -} - -#ifdef FIXED_POINT -EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) -#else -EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) -#endif -{ - int j; - spx_uint32_t ilen = *in_len; - spx_uint32_t olen = *out_len; - spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; - const int filt_offs = st->filt_len - 1; - const spx_uint32_t xlen = st->mem_alloc_size - filt_offs; - const int istride = st->in_stride; - - if (st->magic_samples[channel_index]) - olen -= speex_resampler_magic(st, channel_index, &out, olen); - if (! st->magic_samples[channel_index]) { - while (ilen && olen) { - spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; - spx_uint32_t ochunk = olen; - - if (in) { - for(j=0;jout_stride; - if (in) - in += ichunk * istride; - } - } - *in_len -= ilen; - *out_len -= olen; - return RESAMPLER_ERR_SUCCESS; -} - -#ifdef FIXED_POINT -EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) -#else -EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) -#endif -{ - int j; - const int istride_save = st->in_stride; - const int ostride_save = st->out_stride; - spx_uint32_t ilen = *in_len; - spx_uint32_t olen = *out_len; - spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; - const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1); -#ifdef VAR_ARRAYS - const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC; - VARDECL(spx_word16_t *ystack); - ALLOC(ystack, ylen, spx_word16_t); -#else - const unsigned int ylen = FIXED_STACK_ALLOC; - spx_word16_t ystack[FIXED_STACK_ALLOC]; -#endif - - st->out_stride = 1; - - while (ilen && olen) { - spx_word16_t *y = ystack; - spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; - spx_uint32_t ochunk = (olen > ylen) ? ylen : olen; - spx_uint32_t omagic = 0; - - if (st->magic_samples[channel_index]) { - omagic = speex_resampler_magic(st, channel_index, &y, ochunk); - ochunk -= omagic; - olen -= omagic; - } - if (! st->magic_samples[channel_index]) { - if (in) { - for(j=0;jfilt_len-1]=WORD2INT(in[j*istride_save]); -#else - x[j+st->filt_len-1]=in[j*istride_save]; -#endif - } else { - for(j=0;jfilt_len-1]=0; - } - - speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk); - } else { - ichunk = 0; - ochunk = 0; - } - - for (j=0;jout_stride = ostride_save; - *in_len -= ilen; - *out_len -= olen; - - return RESAMPLER_ERR_SUCCESS; -} - -EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) -{ - spx_uint32_t i; - int istride_save, ostride_save; - spx_uint32_t bak_len = *out_len; - istride_save = st->in_stride; - ostride_save = st->out_stride; - st->in_stride = st->out_stride = st->nb_channels; - for (i=0;inb_channels;i++) - { - *out_len = bak_len; - if (in != NULL) - speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len); - else - speex_resampler_process_float(st, i, NULL, in_len, out+i, out_len); - } - st->in_stride = istride_save; - st->out_stride = ostride_save; - return RESAMPLER_ERR_SUCCESS; -} - -EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) -{ - spx_uint32_t i; - int istride_save, ostride_save; - spx_uint32_t bak_len = *out_len; - istride_save = st->in_stride; - ostride_save = st->out_stride; - st->in_stride = st->out_stride = st->nb_channels; - for (i=0;inb_channels;i++) - { - *out_len = bak_len; - if (in != NULL) - speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len); - else - speex_resampler_process_int(st, i, NULL, in_len, out+i, out_len); - } - st->in_stride = istride_save; - st->out_stride = ostride_save; - return RESAMPLER_ERR_SUCCESS; -} - -EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) -{ - return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate); -} - -EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) -{ - *in_rate = st->in_rate; - *out_rate = st->out_rate; -} - -EXPORT int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate) -{ - spx_uint32_t fact; - spx_uint32_t old_den; - spx_uint32_t i; - if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den) - return RESAMPLER_ERR_SUCCESS; - - old_den = st->den_rate; - st->in_rate = in_rate; - st->out_rate = out_rate; - st->num_rate = ratio_num; - st->den_rate = ratio_den; - /* FIXME: This is terribly inefficient, but who cares (at least for now)? */ - for (fact=2;fact<=IMIN(st->num_rate, st->den_rate);fact++) - { - while ((st->num_rate % fact == 0) && (st->den_rate % fact == 0)) - { - st->num_rate /= fact; - st->den_rate /= fact; - } - } - - if (old_den > 0) - { - for (i=0;inb_channels;i++) - { - st->samp_frac_num[i]=st->samp_frac_num[i]*st->den_rate/old_den; - /* Safety net */ - if (st->samp_frac_num[i] >= st->den_rate) - st->samp_frac_num[i] = st->den_rate-1; - } - } - - if (st->initialised) - update_filter(st); - return RESAMPLER_ERR_SUCCESS; -} - -EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) -{ - *ratio_num = st->num_rate; - *ratio_den = st->den_rate; -} - -EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality) -{ - if (quality > 10 || quality < 0) - return RESAMPLER_ERR_INVALID_ARG; - if (st->quality == quality) - return RESAMPLER_ERR_SUCCESS; - st->quality = quality; - if (st->initialised) - update_filter(st); - return RESAMPLER_ERR_SUCCESS; -} - -EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) -{ - *quality = st->quality; -} - -EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) -{ - st->in_stride = stride; -} - -EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) -{ - *stride = st->in_stride; -} - -EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) -{ - st->out_stride = stride; -} - -EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) -{ - *stride = st->out_stride; -} - -EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st) -{ - return st->filt_len / 2; -} - -EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st) -{ - return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate; -} - -EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st) -{ - spx_uint32_t i; - for (i=0;inb_channels;i++) - st->last_sample[i] = st->filt_len/2; - return RESAMPLER_ERR_SUCCESS; -} - -EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st) -{ - spx_uint32_t i; - for (i=0;inb_channels*(st->filt_len-1);i++) - st->mem[i] = 0; - return RESAMPLER_ERR_SUCCESS; -} - -EXPORT const char *speex_resampler_strerror(int err) -{ - switch (err) - { - case RESAMPLER_ERR_SUCCESS: - return "Success."; - case RESAMPLER_ERR_ALLOC_FAILED: - return "Memory allocation failed."; - case RESAMPLER_ERR_BAD_STATE: - return "Bad resampler state."; - case RESAMPLER_ERR_INVALID_ARG: - return "Invalid argument."; - case RESAMPLER_ERR_PTR_OVERLAP: - return "Input and output buffers overlap."; - default: - return "Unknown error. Bad error code or strange version mismatch."; - } -} diff --git a/lib/libspeex/speex/speex_resampler.h b/lib/libspeex/speex/speex_resampler.h deleted file mode 100644 index 54eef8d7b8..0000000000 --- a/lib/libspeex/speex/speex_resampler.h +++ /dev/null @@ -1,340 +0,0 @@ -/* Copyright (C) 2007 Jean-Marc Valin - - File: speex_resampler.h - Resampling code - - The design goals of this code are: - - Very fast algorithm - - Low memory requirement - - Good *perceptual* quality (and not best SNR) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - - -#ifndef SPEEX_RESAMPLER_H -#define SPEEX_RESAMPLER_H - -#ifdef OUTSIDE_SPEEX - -/********* WARNING: MENTAL SANITY ENDS HERE *************/ - -/* If the resampler is defined outside of Speex, we change the symbol names so that - there won't be any clash if linking with Speex later on. */ - -/* #define RANDOM_PREFIX your software name here */ -#ifndef RANDOM_PREFIX -#error "Please define RANDOM_PREFIX (above) to something specific to your project to prevent symbol name clashes" -#endif - -#define CAT_PREFIX2(a,b) a ## b -#define CAT_PREFIX(a,b) CAT_PREFIX2(a, b) - -#define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init) -#define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac) -#define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy) -#define speex_resampler_process_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_float) -#define speex_resampler_process_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_int) -#define speex_resampler_process_interleaved_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_float) -#define speex_resampler_process_interleaved_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_int) -#define speex_resampler_set_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate) -#define speex_resampler_get_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_get_rate) -#define speex_resampler_set_rate_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate_frac) -#define speex_resampler_get_ratio CAT_PREFIX(RANDOM_PREFIX,_resampler_get_ratio) -#define speex_resampler_set_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_set_quality) -#define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality) -#define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride) -#define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride) -#define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride) -#define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride) -#define speex_resampler_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency) -#define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency) -#define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros) -#define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem) -#define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror) - -#define spx_int16_t short -#define spx_int32_t int -#define spx_uint16_t unsigned short -#define spx_uint32_t unsigned int - -#else /* OUTSIDE_SPEEX */ - -#include "speex/speex_types.h" - -#endif /* OUTSIDE_SPEEX */ - -#ifdef __cplusplus -extern "C" { -#endif - -#define SPEEX_RESAMPLER_QUALITY_MAX 10 -#define SPEEX_RESAMPLER_QUALITY_MIN 0 -#define SPEEX_RESAMPLER_QUALITY_DEFAULT 4 -#define SPEEX_RESAMPLER_QUALITY_VOIP 3 -#define SPEEX_RESAMPLER_QUALITY_DESKTOP 5 - -enum { - RESAMPLER_ERR_SUCCESS = 0, - RESAMPLER_ERR_ALLOC_FAILED = 1, - RESAMPLER_ERR_BAD_STATE = 2, - RESAMPLER_ERR_INVALID_ARG = 3, - RESAMPLER_ERR_PTR_OVERLAP = 4, - - RESAMPLER_ERR_MAX_ERROR -}; - -struct SpeexResamplerState_; -typedef struct SpeexResamplerState_ SpeexResamplerState; - -/** Create a new resampler with integer input and output rates. - * @param nb_channels Number of channels to be processed - * @param in_rate Input sampling rate (integer number of Hz). - * @param out_rate Output sampling rate (integer number of Hz). - * @param quality Resampling quality between 0 and 10, where 0 has poor quality - * and 10 has very high quality. - * @return Newly created resampler state - * @retval NULL Error: not enough memory - */ -SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, - spx_uint32_t in_rate, - spx_uint32_t out_rate, - int quality, - int *err); - -/** Create a new resampler with fractional input/output rates. The sampling - * rate ratio is an arbitrary rational number with both the numerator and - * denominator being 32-bit integers. - * @param nb_channels Number of channels to be processed - * @param ratio_num Numerator of the sampling rate ratio - * @param ratio_den Denominator of the sampling rate ratio - * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). - * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). - * @param quality Resampling quality between 0 and 10, where 0 has poor quality - * and 10 has very high quality. - * @return Newly created resampler state - * @retval NULL Error: not enough memory - */ -SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, - spx_uint32_t ratio_num, - spx_uint32_t ratio_den, - spx_uint32_t in_rate, - spx_uint32_t out_rate, - int quality, - int *err); - -/** Destroy a resampler state. - * @param st Resampler state - */ -void speex_resampler_destroy(SpeexResamplerState *st); - -/** Resample a float array. The input and output buffers must *not* overlap. - * @param st Resampler state - * @param channel_index Index of the channel to process for the multi-channel - * base (0 otherwise) - * @param in Input buffer - * @param in_len Number of input samples in the input buffer. Returns the - * number of samples processed - * @param out Output buffer - * @param out_len Size of the output buffer. Returns the number of samples written - */ -int speex_resampler_process_float(SpeexResamplerState *st, - spx_uint32_t channel_index, - const float *in, - spx_uint32_t *in_len, - float *out, - spx_uint32_t *out_len); - -/** Resample an int array. The input and output buffers must *not* overlap. - * @param st Resampler state - * @param channel_index Index of the channel to process for the multi-channel - * base (0 otherwise) - * @param in Input buffer - * @param in_len Number of input samples in the input buffer. Returns the number - * of samples processed - * @param out Output buffer - * @param out_len Size of the output buffer. Returns the number of samples written - */ -int speex_resampler_process_int(SpeexResamplerState *st, - spx_uint32_t channel_index, - const spx_int16_t *in, - spx_uint32_t *in_len, - spx_int16_t *out, - spx_uint32_t *out_len); - -/** Resample an interleaved float array. The input and output buffers must *not* overlap. - * @param st Resampler state - * @param in Input buffer - * @param in_len Number of input samples in the input buffer. Returns the number - * of samples processed. This is all per-channel. - * @param out Output buffer - * @param out_len Size of the output buffer. Returns the number of samples written. - * This is all per-channel. - */ -int speex_resampler_process_interleaved_float(SpeexResamplerState *st, - const float *in, - spx_uint32_t *in_len, - float *out, - spx_uint32_t *out_len); - -/** Resample an interleaved int array. The input and output buffers must *not* overlap. - * @param st Resampler state - * @param in Input buffer - * @param in_len Number of input samples in the input buffer. Returns the number - * of samples processed. This is all per-channel. - * @param out Output buffer - * @param out_len Size of the output buffer. Returns the number of samples written. - * This is all per-channel. - */ -int speex_resampler_process_interleaved_int(SpeexResamplerState *st, - const spx_int16_t *in, - spx_uint32_t *in_len, - spx_int16_t *out, - spx_uint32_t *out_len); - -/** Set (change) the input/output sampling rates (integer value). - * @param st Resampler state - * @param in_rate Input sampling rate (integer number of Hz). - * @param out_rate Output sampling rate (integer number of Hz). - */ -int speex_resampler_set_rate(SpeexResamplerState *st, - spx_uint32_t in_rate, - spx_uint32_t out_rate); - -/** Get the current input/output sampling rates (integer value). - * @param st Resampler state - * @param in_rate Input sampling rate (integer number of Hz) copied. - * @param out_rate Output sampling rate (integer number of Hz) copied. - */ -void speex_resampler_get_rate(SpeexResamplerState *st, - spx_uint32_t *in_rate, - spx_uint32_t *out_rate); - -/** Set (change) the input/output sampling rates and resampling ratio - * (fractional values in Hz supported). - * @param st Resampler state - * @param ratio_num Numerator of the sampling rate ratio - * @param ratio_den Denominator of the sampling rate ratio - * @param in_rate Input sampling rate rounded to the nearest integer (in Hz). - * @param out_rate Output sampling rate rounded to the nearest integer (in Hz). - */ -int speex_resampler_set_rate_frac(SpeexResamplerState *st, - spx_uint32_t ratio_num, - spx_uint32_t ratio_den, - spx_uint32_t in_rate, - spx_uint32_t out_rate); - -/** Get the current resampling ratio. This will be reduced to the least - * common denominator. - * @param st Resampler state - * @param ratio_num Numerator of the sampling rate ratio copied - * @param ratio_den Denominator of the sampling rate ratio copied - */ -void speex_resampler_get_ratio(SpeexResamplerState *st, - spx_uint32_t *ratio_num, - spx_uint32_t *ratio_den); - -/** Set (change) the conversion quality. - * @param st Resampler state - * @param quality Resampling quality between 0 and 10, where 0 has poor - * quality and 10 has very high quality. - */ -int speex_resampler_set_quality(SpeexResamplerState *st, - int quality); - -/** Get the conversion quality. - * @param st Resampler state - * @param quality Resampling quality between 0 and 10, where 0 has poor - * quality and 10 has very high quality. - */ -void speex_resampler_get_quality(SpeexResamplerState *st, - int *quality); - -/** Set (change) the input stride. - * @param st Resampler state - * @param stride Input stride - */ -void speex_resampler_set_input_stride(SpeexResamplerState *st, - spx_uint32_t stride); - -/** Get the input stride. - * @param st Resampler state - * @param stride Input stride copied - */ -void speex_resampler_get_input_stride(SpeexResamplerState *st, - spx_uint32_t *stride); - -/** Set (change) the output stride. - * @param st Resampler state - * @param stride Output stride - */ -void speex_resampler_set_output_stride(SpeexResamplerState *st, - spx_uint32_t stride); - -/** Get the output stride. - * @param st Resampler state copied - * @param stride Output stride - */ -void speex_resampler_get_output_stride(SpeexResamplerState *st, - spx_uint32_t *stride); - -/** Get the latency in input samples introduced by the resampler. - * @param st Resampler state - */ -int speex_resampler_get_input_latency(SpeexResamplerState *st); - -/** Get the latency in output samples introduced by the resampler. - * @param st Resampler state - */ -int speex_resampler_get_output_latency(SpeexResamplerState *st); - -/** Make sure that the first samples to go out of the resamplers don't have - * leading zeros. This is only useful before starting to use a newly created - * resampler. It is recommended to use that when resampling an audio file, as - * it will generate a file with the same length. For real-time processing, - * it is probably easier not to use this call (so that the output duration - * is the same for the first frame). - * @param st Resampler state - */ -int speex_resampler_skip_zeros(SpeexResamplerState *st); - -/** Reset a resampler so a new (unrelated) stream can be processed. - * @param st Resampler state - */ -int speex_resampler_reset_mem(SpeexResamplerState *st); - -/** Returns the English meaning for an error code - * @param err Error code - * @return English string - */ -const char *speex_resampler_strerror(int err); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/libspeex/speex/speex_types.h b/lib/libspeex/speex/speex_types.h deleted file mode 100644 index 852fed801d..0000000000 --- a/lib/libspeex/speex/speex_types.h +++ /dev/null @@ -1,126 +0,0 @@ -/* speex_types.h taken from libogg */ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * - * by the Xiph.Org Foundation http://www.xiph.org/ * - * * - ******************************************************************** - - function: #ifdef jail to whip a few platforms into the UNIX ideal. - last mod: $Id: os_types.h 7524 2004-08-11 04:20:36Z conrad $ - - ********************************************************************/ -/** - @file speex_types.h - @brief Speex types -*/ -#ifndef _SPEEX_TYPES_H -#define _SPEEX_TYPES_H - -#if defined(_WIN32) - -# if defined(__CYGWIN__) -# include <_G_config.h> - typedef _G_int32_t spx_int32_t; - typedef _G_uint32_t spx_uint32_t; - typedef _G_int16_t spx_int16_t; - typedef _G_uint16_t spx_uint16_t; -# elif defined(__MINGW32__) - typedef short spx_int16_t; - typedef unsigned short spx_uint16_t; - typedef int spx_int32_t; - typedef unsigned int spx_uint32_t; -# elif defined(__MWERKS__) - typedef int spx_int32_t; - typedef unsigned int spx_uint32_t; - typedef short spx_int16_t; - typedef unsigned short spx_uint16_t; -# else - /* MSVC/Borland */ - typedef __int32 spx_int32_t; - typedef unsigned __int32 spx_uint32_t; - typedef __int16 spx_int16_t; - typedef unsigned __int16 spx_uint16_t; -# endif - -#elif defined(__MACOS__) - -# include - typedef SInt16 spx_int16_t; - typedef UInt16 spx_uint16_t; - typedef SInt32 spx_int32_t; - typedef UInt32 spx_uint32_t; - -#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ - -# include - typedef int16_t spx_int16_t; - typedef u_int16_t spx_uint16_t; - typedef int32_t spx_int32_t; - typedef u_int32_t spx_uint32_t; - -#elif defined(__BEOS__) - - /* Be */ -# include - typedef int16_t spx_int16_t; - typedef u_int16_t spx_uint16_t; - typedef int32_t spx_int32_t; - typedef u_int32_t spx_uint32_t; - -#elif defined (__EMX__) - - /* OS/2 GCC */ - typedef short spx_int16_t; - typedef unsigned short spx_uint16_t; - typedef int spx_int32_t; - typedef unsigned int spx_uint32_t; - -#elif defined (DJGPP) - - /* DJGPP */ - typedef short spx_int16_t; - typedef int spx_int32_t; - typedef unsigned int spx_uint32_t; - -#elif defined(R5900) - - /* PS2 EE */ - typedef int spx_int32_t; - typedef unsigned spx_uint32_t; - typedef short spx_int16_t; - -#elif defined(__SYMBIAN32__) - - /* Symbian GCC */ - typedef signed short spx_int16_t; - typedef unsigned short spx_uint16_t; - typedef signed int spx_int32_t; - typedef unsigned int spx_uint32_t; - -#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) - - typedef short spx_int16_t; - typedef unsigned short spx_uint16_t; - typedef long spx_int32_t; - typedef unsigned long spx_uint32_t; - -#elif defined(CONFIG_TI_C6X) - - typedef short spx_int16_t; - typedef unsigned short spx_uint16_t; - typedef int spx_int32_t; - typedef unsigned int spx_uint32_t; - -#else - -# include - -#endif - -#endif /* _SPEEX_TYPES_H */ diff --git a/lib/libspeex/stack_alloc.h b/lib/libspeex/stack_alloc.h deleted file mode 100644 index f2a10921c5..0000000000 --- a/lib/libspeex/stack_alloc.h +++ /dev/null @@ -1,115 +0,0 @@ -/* Copyright (C) 2002 Jean-Marc Valin */ -/** - @file stack_alloc.h - @brief Temporary memory allocation on stack -*/ -/* - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - - Neither the name of the Xiph.org Foundation nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef STACK_ALLOC_H -#define STACK_ALLOC_H - -#ifdef USE_ALLOCA -# ifdef WIN32 -# include -# else -# ifdef HAVE_ALLOCA_H -# include -# else -# include -# endif -# endif -#endif - -/** - * @def ALIGN(stack, size) - * - * Aligns the stack to a 'size' boundary - * - * @param stack Stack - * @param size New size boundary - */ - -/** - * @def PUSH(stack, size, type) - * - * Allocates 'size' elements of type 'type' on the stack - * - * @param stack Stack - * @param size Number of elements - * @param type Type of element - */ - -/** - * @def VARDECL(var) - * - * Declare variable on stack - * - * @param var Variable to declare - */ - -/** - * @def ALLOC(var, size, type) - * - * Allocate 'size' elements of 'type' on stack - * - * @param var Name of variable to allocate - * @param size Number of elements - * @param type Type of element - */ - -#ifdef ENABLE_VALGRIND - -#include - -#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) - -#define PUSH(stack, size, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(type)),VALGRIND_MAKE_WRITABLE(stack, ((size)*sizeof(type))),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type)))) - -#else - -#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) - -#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type)))) - -#endif - -#if defined(VAR_ARRAYS) -#define VARDECL(var) -#define ALLOC(var, size, type) type var[size] -#elif defined(USE_ALLOCA) -#define VARDECL(var) var -#define ALLOC(var, size, type) var = _alloca(sizeof(type)*(size)) -#else -#define VARDECL(var) var -#define ALLOC(var, size, type) var = PUSH(stack, size, type) -#endif - - -#endif diff --git a/lib/lodepng/lodepng.c b/lib/lodepng/lodepng.c deleted file mode 100644 index e4f35d7dd5..0000000000 --- a/lib/lodepng/lodepng.c +++ /dev/null @@ -1,6260 +0,0 @@ -/* -LodePNG version 20131222 - -Copyright (c) 2005-2013 Lode Vandevenne - -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. -*/ - -/* -The manual and changelog are in the header file "lodepng.h" -Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for C. -*/ - -#include "lodepng.h" - -#include -#include - -#ifdef LODEPNG_COMPILE_CPP -#include -#endif /*LODEPNG_COMPILE_CPP*/ - -#define VERSION_STRING "20131222" - -/* -This source file is built up in the following large parts. The code sections -with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way. --Tools for C and common code for PNG and Zlib --C Code for Zlib (huffman, deflate, ...) --C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...) --The C++ wrapper around all of the above -*/ - -/*The malloc, realloc and free functions defined here with "lodepng_" in front -of the name, so that you can easily change them to others related to your -platform if needed. Everything else in the code calls these. Pass --DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler, or comment out -#define LODEPNG_COMPILE_ALLOCATORS in the header, to disable the ones here and -define them in your own project's source files without needing to change -lodepng source code. Don't forget to remove "static" if you copypaste them -from here.*/ - -#ifdef LODEPNG_COMPILE_ALLOCATORS -static void* lodepng_malloc(size_t size) -{ - return malloc(size); -} - -static void* lodepng_realloc(void* ptr, size_t new_size) -{ - return realloc(ptr, new_size); -} - -static void lodepng_free(void* ptr) -{ - free(ptr); -} -#else /*LODEPNG_COMPILE_ALLOCATORS*/ -void* lodepng_malloc(size_t size); -void* lodepng_realloc(void* ptr, size_t new_size); -void lodepng_free(void* ptr); -#endif /*LODEPNG_COMPILE_ALLOCATORS*/ - -/* ////////////////////////////////////////////////////////////////////////// */ -/* ////////////////////////////////////////////////////////////////////////// */ -/* // Tools for C, and common code for PNG and Zlib. // */ -/* ////////////////////////////////////////////////////////////////////////// */ -/* ////////////////////////////////////////////////////////////////////////// */ - -/* -Often in case of an error a value is assigned to a variable and then it breaks -out of a loop (to go to the cleanup phase of a function). This macro does that. -It makes the error handling code shorter and more readable. - -Example: if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83); -*/ -#define CERROR_BREAK(errorvar, code)\ -{\ - errorvar = code;\ - break;\ -} - -/*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/ -#define ERROR_BREAK(code) CERROR_BREAK(error, code) - -/*Set error var to the error code, and return it.*/ -#define CERROR_RETURN_ERROR(errorvar, code)\ -{\ - errorvar = code;\ - return code;\ -} - -/*Try the code, if it returns error, also return the error.*/ -#define CERROR_TRY_RETURN(call)\ -{\ - unsigned error = call;\ - if(error) return error;\ -} - -/* -About uivector, ucvector and string: --All of them wrap dynamic arrays or text strings in a similar way. --LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version. --The string tools are made to avoid problems with compilers that declare things like strncat as deprecated. --They're not used in the interface, only internally in this file as static functions. --As with many other structs in this file, the init and cleanup functions serve as ctor and dtor. -*/ - -#ifdef LODEPNG_COMPILE_ZLIB -/*dynamic vector of unsigned ints*/ -typedef struct uivector -{ - unsigned* data; - size_t size; /*size in number of unsigned longs*/ - size_t allocsize; /*allocated size in bytes*/ -} uivector; - -static void uivector_cleanup(void* p) -{ - ((uivector*)p)->size = ((uivector*)p)->allocsize = 0; - lodepng_free(((uivector*)p)->data); - ((uivector*)p)->data = NULL; -} - -/*returns 1 if success, 0 if failure ==> nothing done*/ -static unsigned uivector_resize(uivector* p, size_t size) -{ - if(size * sizeof(unsigned) > p->allocsize) - { - size_t newsize = size * sizeof(unsigned) * 2; - void* data = lodepng_realloc(p->data, newsize); - if(data) - { - p->allocsize = newsize; - p->data = (unsigned*)data; - p->size = size; - } - else return 0; - } - else p->size = size; - return 1; -} - -/*resize and give all new elements the value*/ -static unsigned uivector_resizev(uivector* p, size_t size, unsigned value) -{ - size_t oldsize = p->size, i; - if(!uivector_resize(p, size)) return 0; - for(i = oldsize; i < size; i++) p->data[i] = value; - return 1; -} - -static void uivector_init(uivector* p) -{ - p->data = NULL; - p->size = p->allocsize = 0; -} - -#ifdef LODEPNG_COMPILE_ENCODER -/*returns 1 if success, 0 if failure ==> nothing done*/ -static unsigned uivector_push_back(uivector* p, unsigned c) -{ - if(!uivector_resize(p, p->size + 1)) return 0; - p->data[p->size - 1] = c; - return 1; -} - -/*copy q to p, returns 1 if success, 0 if failure ==> nothing done*/ -static unsigned uivector_copy(uivector* p, const uivector* q) -{ - size_t i; - if(!uivector_resize(p, q->size)) return 0; - for(i = 0; i < q->size; i++) p->data[i] = q->data[i]; - return 1; -} -#endif /*LODEPNG_COMPILE_ENCODER*/ -#endif /*LODEPNG_COMPILE_ZLIB*/ - -/* /////////////////////////////////////////////////////////////////////////// */ - -/*dynamic vector of unsigned chars*/ -typedef struct ucvector -{ - unsigned char* data; - size_t size; /*used size*/ - size_t allocsize; /*allocated size*/ -} ucvector; - -/*returns 1 if success, 0 if failure ==> nothing done*/ -static unsigned ucvector_resize(ucvector* p, size_t size) -{ - if(size * sizeof(unsigned char) > p->allocsize) - { - size_t newsize = size * sizeof(unsigned char) * 2; - void* data = lodepng_realloc(p->data, newsize); - if(data) - { - p->allocsize = newsize; - p->data = (unsigned char*)data; - p->size = size; - } - else return 0; /*error: not enough memory*/ - } - else p->size = size; - return 1; -} - -#ifdef LODEPNG_COMPILE_PNG - -static void ucvector_cleanup(void* p) -{ - ((ucvector*)p)->size = ((ucvector*)p)->allocsize = 0; - lodepng_free(((ucvector*)p)->data); - ((ucvector*)p)->data = NULL; -} - -static void ucvector_init(ucvector* p) -{ - p->data = NULL; - p->size = p->allocsize = 0; -} - -#ifdef LODEPNG_COMPILE_DECODER -/*resize and give all new elements the value*/ -static unsigned ucvector_resizev(ucvector* p, size_t size, unsigned char value) -{ - size_t oldsize = p->size, i; - if(!ucvector_resize(p, size)) return 0; - for(i = oldsize; i < size; i++) p->data[i] = value; - return 1; -} -#endif /*LODEPNG_COMPILE_DECODER*/ -#endif /*LODEPNG_COMPILE_PNG*/ - -#ifdef LODEPNG_COMPILE_ZLIB -/*you can both convert from vector to buffer&size and vica versa. If you use -init_buffer to take over a buffer and size, it is not needed to use cleanup*/ -static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size) -{ - p->data = buffer; - p->allocsize = p->size = size; -} -#endif /*LODEPNG_COMPILE_ZLIB*/ - -#if (defined(LODEPNG_COMPILE_PNG) && defined(LODEPNG_COMPILE_ANCILLARY_CHUNKS)) || defined(LODEPNG_COMPILE_ENCODER) -/*returns 1 if success, 0 if failure ==> nothing done*/ -static unsigned ucvector_push_back(ucvector* p, unsigned char c) -{ - if(!ucvector_resize(p, p->size + 1)) return 0; - p->data[p->size - 1] = c; - return 1; -} -#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ - - -/* ////////////////////////////////////////////////////////////////////////// */ - -#ifdef LODEPNG_COMPILE_PNG -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS -/*returns 1 if success, 0 if failure ==> nothing done*/ -static unsigned string_resize(char** out, size_t size) -{ - char* data = (char*)lodepng_realloc(*out, size + 1); - if(data) - { - data[size] = 0; /*null termination char*/ - *out = data; - } - return data != 0; -} - -/*init a {char*, size_t} pair for use as string*/ -static void string_init(char** out) -{ - *out = NULL; - string_resize(out, 0); -} - -/*free the above pair again*/ -static void string_cleanup(char** out) -{ - lodepng_free(*out); - *out = NULL; -} - -static void string_set(char** out, const char* in) -{ - size_t insize = strlen(in), i = 0; - if(string_resize(out, insize)) - { - for(i = 0; i < insize; i++) - { - (*out)[i] = in[i]; - } - } -} -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ -#endif /*LODEPNG_COMPILE_PNG*/ - -/* ////////////////////////////////////////////////////////////////////////// */ - -unsigned lodepng_read32bitInt(const unsigned char* buffer) -{ - return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; -} - -#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER) -/*buffer must have at least 4 allocated bytes available*/ -static void lodepng_set32bitInt(unsigned char* buffer, unsigned value) -{ - buffer[0] = (unsigned char)((value >> 24) & 0xff); - buffer[1] = (unsigned char)((value >> 16) & 0xff); - buffer[2] = (unsigned char)((value >> 8) & 0xff); - buffer[3] = (unsigned char)((value ) & 0xff); -} -#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ - -#ifdef LODEPNG_COMPILE_ENCODER -static void lodepng_add32bitInt(ucvector* buffer, unsigned value) -{ - ucvector_resize(buffer, buffer->size + 4); /*todo: give error if resize failed*/ - lodepng_set32bitInt(&buffer->data[buffer->size - 4], value); -} -#endif /*LODEPNG_COMPILE_ENCODER*/ - -/* ////////////////////////////////////////////////////////////////////////// */ -/* / File IO / */ -/* ////////////////////////////////////////////////////////////////////////// */ - -#ifdef LODEPNG_COMPILE_DISK - -unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) -{ - FILE* file; - long size; - - /*provide some proper output values if error will happen*/ - *out = 0; - *outsize = 0; - - file = fopen(filename, "rb"); - if(!file) return 78; - - /*get filesize:*/ - fseek(file , 0 , SEEK_END); - size = ftell(file); - rewind(file); - - /*read contents of the file into the vector*/ - *outsize = 0; - *out = (unsigned char*)lodepng_malloc((size_t)size); - if(size && (*out)) (*outsize) = fread(*out, 1, (size_t)size, file); - - fclose(file); - if(!(*out) && size) return 83; /*the above malloc failed*/ - return 0; -} - -/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ -unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename) -{ - FILE* file; - file = fopen(filename, "wb" ); - if(!file) return 79; - fwrite((char*)buffer , 1 , buffersize, file); - fclose(file); - return 0; -} - -#endif /*LODEPNG_COMPILE_DISK*/ - -/* ////////////////////////////////////////////////////////////////////////// */ -/* ////////////////////////////////////////////////////////////////////////// */ -/* // End of common code and tools. Begin of Zlib related code. // */ -/* ////////////////////////////////////////////////////////////////////////// */ -/* ////////////////////////////////////////////////////////////////////////// */ - -#ifdef LODEPNG_COMPILE_ZLIB -#ifdef LODEPNG_COMPILE_ENCODER -/*TODO: this ignores potential out of memory errors*/ -#define addBitToStream(/*size_t**/ bitpointer, /*ucvector**/ bitstream, /*unsigned char*/ bit)\ -{\ - /*add a new byte at the end*/\ - if(((*bitpointer) & 7) == 0) ucvector_push_back(bitstream, (unsigned char)0);\ - /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/\ - (bitstream->data[bitstream->size - 1]) |= (bit << ((*bitpointer) & 0x7));\ - (*bitpointer)++;\ -} - -static void addBitsToStream(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) -{ - size_t i; - for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1)); -} - -static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) -{ - size_t i; - for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1)); -} -#endif /*LODEPNG_COMPILE_ENCODER*/ - -#ifdef LODEPNG_COMPILE_DECODER - -#define READBIT(bitpointer, bitstream) ((bitstream[bitpointer >> 3] >> (bitpointer & 0x7)) & (unsigned char)1) - -static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream) -{ - unsigned char result = (unsigned char)(READBIT(*bitpointer, bitstream)); - (*bitpointer)++; - return result; -} - -static unsigned readBitsFromStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) -{ - unsigned result = 0, i; - for(i = 0; i < nbits; i++) - { - result += ((unsigned)READBIT(*bitpointer, bitstream)) << i; - (*bitpointer)++; - } - return result; -} -#endif /*LODEPNG_COMPILE_DECODER*/ - -/* ////////////////////////////////////////////////////////////////////////// */ -/* / Deflate - Huffman / */ -/* ////////////////////////////////////////////////////////////////////////// */ - -#define FIRST_LENGTH_CODE_INDEX 257 -#define LAST_LENGTH_CODE_INDEX 285 -/*256 literals, the end code, some length codes, and 2 unused codes*/ -#define NUM_DEFLATE_CODE_SYMBOLS 288 -/*the distance codes have their own symbols, 30 used, 2 unused*/ -#define NUM_DISTANCE_SYMBOLS 32 -/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/ -#define NUM_CODE_LENGTH_CODES 19 - -/*the base lengths represented by codes 257-285*/ -static const unsigned LENGTHBASE[29] - = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, - 67, 83, 99, 115, 131, 163, 195, 227, 258}; - -/*the extra bits used by codes 257-285 (added to base length)*/ -static const unsigned LENGTHEXTRA[29] - = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, - 4, 4, 4, 4, 5, 5, 5, 5, 0}; - -/*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/ -static const unsigned DISTANCEBASE[30] - = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, - 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; - -/*the extra bits of backwards distances (added to base)*/ -static const unsigned DISTANCEEXTRA[30] - = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, - 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; - -/*the order in which "code length alphabet code lengths" are stored, out of this -the huffman tree of the dynamic huffman tree lengths is generated*/ -static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES] - = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - -/* ////////////////////////////////////////////////////////////////////////// */ - -/* -Huffman tree struct, containing multiple representations of the tree -*/ -typedef struct HuffmanTree -{ - unsigned* tree2d; - unsigned* tree1d; - unsigned* lengths; /*the lengths of the codes of the 1d-tree*/ - unsigned maxbitlen; /*maximum number of bits a single code can get*/ - unsigned numcodes; /*number of symbols in the alphabet = number of codes*/ -} HuffmanTree; - -/*function used for debug purposes to draw the tree in ascii art with C++*/ -/* -static void HuffmanTree_draw(HuffmanTree* tree) -{ - std::cout << "tree. length: " << tree->numcodes << " maxbitlen: " << tree->maxbitlen << std::endl; - for(size_t i = 0; i < tree->tree1d.size; i++) - { - if(tree->lengths.data[i]) - std::cout << i << " " << tree->tree1d.data[i] << " " << tree->lengths.data[i] << std::endl; - } - std::cout << std::endl; -}*/ - -static void HuffmanTree_init(HuffmanTree* tree) -{ - tree->tree2d = 0; - tree->tree1d = 0; - tree->lengths = 0; -} - -static void HuffmanTree_cleanup(HuffmanTree* tree) -{ - lodepng_free(tree->tree2d); - lodepng_free(tree->tree1d); - lodepng_free(tree->lengths); -} - -/*the tree representation used by the decoder. return value is error*/ -static unsigned HuffmanTree_make2DTree(HuffmanTree* tree) -{ - unsigned nodefilled = 0; /*up to which node it is filled*/ - unsigned treepos = 0; /*position in the tree (1 of the numcodes columns)*/ - unsigned n, i; - - tree->tree2d = (unsigned*)lodepng_malloc(tree->numcodes * 2 * sizeof(unsigned)); - if(!tree->tree2d) return 83; /*alloc fail*/ - - /* - convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means - uninited, a value >= numcodes is an address to another bit, a value < numcodes - is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as - many columns as codes - 1. - A good huffmann tree has N * 2 - 1 nodes, of which N - 1 are internal nodes. - Here, the internal nodes are stored (what their 0 and 1 option point to). - There is only memory for such good tree currently, if there are more nodes - (due to too long length codes), error 55 will happen - */ - for(n = 0; n < tree->numcodes * 2; n++) - { - tree->tree2d[n] = 32767; /*32767 here means the tree2d isn't filled there yet*/ - } - - for(n = 0; n < tree->numcodes; n++) /*the codes*/ - { - for(i = 0; i < tree->lengths[n]; i++) /*the bits for this code*/ - { - unsigned char bit = (unsigned char)((tree->tree1d[n] >> (tree->lengths[n] - i - 1)) & 1); - if(treepos > tree->numcodes - 2) return 55; /*oversubscribed, see comment in lodepng_error_text*/ - if(tree->tree2d[2 * treepos + bit] == 32767) /*not yet filled in*/ - { - if(i + 1 == tree->lengths[n]) /*last bit*/ - { - tree->tree2d[2 * treepos + bit] = n; /*put the current code in it*/ - treepos = 0; - } - else - { - /*put address of the next step in here, first that address has to be found of course - (it's just nodefilled + 1)...*/ - nodefilled++; - /*addresses encoded with numcodes added to it*/ - tree->tree2d[2 * treepos + bit] = nodefilled + tree->numcodes; - treepos = nodefilled; - } - } - else treepos = tree->tree2d[2 * treepos + bit] - tree->numcodes; - } - } - - for(n = 0; n < tree->numcodes * 2; n++) - { - if(tree->tree2d[n] == 32767) tree->tree2d[n] = 0; /*remove possible remaining 32767's*/ - } - - return 0; -} - -/* -Second step for the ...makeFromLengths and ...makeFromFrequencies functions. -numcodes, lengths and maxbitlen must already be filled in correctly. return -value is error. -*/ -static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) -{ - uivector blcount; - uivector nextcode; - unsigned bits, n, error = 0; - - uivector_init(&blcount); - uivector_init(&nextcode); - - tree->tree1d = (unsigned*)lodepng_malloc(tree->numcodes * sizeof(unsigned)); - if(!tree->tree1d) error = 83; /*alloc fail*/ - - if(!uivector_resizev(&blcount, tree->maxbitlen + 1, 0) - || !uivector_resizev(&nextcode, tree->maxbitlen + 1, 0)) - error = 83; /*alloc fail*/ - - if(!error) - { - /*step 1: count number of instances of each code length*/ - for(bits = 0; bits < tree->numcodes; bits++) blcount.data[tree->lengths[bits]]++; - /*step 2: generate the nextcode values*/ - for(bits = 1; bits <= tree->maxbitlen; bits++) - { - nextcode.data[bits] = (nextcode.data[bits - 1] + blcount.data[bits - 1]) << 1; - } - /*step 3: generate all the codes*/ - for(n = 0; n < tree->numcodes; n++) - { - if(tree->lengths[n] != 0) tree->tree1d[n] = nextcode.data[tree->lengths[n]]++; - } - } - - uivector_cleanup(&blcount); - uivector_cleanup(&nextcode); - - if(!error) return HuffmanTree_make2DTree(tree); - else return error; -} - -/* -given the code lengths (as stored in the PNG file), generate the tree as defined -by Deflate. maxbitlen is the maximum bits that a code in the tree can have. -return value is error. -*/ -static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen, - size_t numcodes, unsigned maxbitlen) -{ - unsigned i; - tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned)); - if(!tree->lengths) return 83; /*alloc fail*/ - for(i = 0; i < numcodes; i++) tree->lengths[i] = bitlen[i]; - tree->numcodes = (unsigned)numcodes; /*number of symbols*/ - tree->maxbitlen = maxbitlen; - return HuffmanTree_makeFromLengths2(tree); -} - -#ifdef LODEPNG_COMPILE_ENCODER - -/* -A coin, this is the terminology used for the package-merge algorithm and the -coin collector's problem. This is used to generate the huffman tree. -A coin can be multiple coins (when they're merged) -*/ -typedef struct Coin -{ - uivector symbols; - float weight; /*the sum of all weights in this coin*/ -} Coin; - -static void coin_init(Coin* c) -{ - uivector_init(&c->symbols); -} - -/*argument c is void* so that this dtor can be given as function pointer to the vector resize function*/ -static void coin_cleanup(void* c) -{ - uivector_cleanup(&((Coin*)c)->symbols); -} - -static void coin_copy(Coin* c1, const Coin* c2) -{ - c1->weight = c2->weight; - uivector_copy(&c1->symbols, &c2->symbols); -} - -static void add_coins(Coin* c1, const Coin* c2) -{ - size_t i; - for(i = 0; i < c2->symbols.size; i++) uivector_push_back(&c1->symbols, c2->symbols.data[i]); - c1->weight += c2->weight; -} - -static void init_coins(Coin* coins, size_t num) -{ - size_t i; - for(i = 0; i < num; i++) coin_init(&coins[i]); -} - -static void cleanup_coins(Coin* coins, size_t num) -{ - size_t i; - for(i = 0; i < num; i++) coin_cleanup(&coins[i]); -} - -static int coin_compare(const void* a, const void* b) { - float wa = ((const Coin*)a)->weight; - float wb = ((const Coin*)b)->weight; - return wa > wb ? 1 : wa < wb ? -1 : 0; -} - -static unsigned append_symbol_coins(Coin* coins, const unsigned* frequencies, unsigned numcodes, size_t sum) -{ - unsigned i; - unsigned j = 0; /*index of present symbols*/ - for(i = 0; i < numcodes; i++) - { - if(frequencies[i] != 0) /*only include symbols that are present*/ - { - coins[j].weight = frequencies[i] / (float)sum; - uivector_push_back(&coins[j].symbols, i); - j++; - } - } - return 0; -} - -unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, - size_t numcodes, unsigned maxbitlen) -{ - unsigned i, j; - size_t sum = 0, numpresent = 0; - unsigned error = 0; - Coin* coins; /*the coins of the currently calculated row*/ - Coin* prev_row; /*the previous row of coins*/ - unsigned numcoins; - unsigned coinmem; - - if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/ - - for(i = 0; i < numcodes; i++) - { - if(frequencies[i] > 0) - { - numpresent++; - sum += frequencies[i]; - } - } - - for(i = 0; i < numcodes; i++) lengths[i] = 0; - - /*ensure at least two present symbols. There should be at least one symbol - according to RFC 1951 section 3.2.7. To decoders incorrectly require two. To - make these work as well ensure there are at least two symbols. The - Package-Merge code below also doesn't work correctly if there's only one - symbol, it'd give it the theoritical 0 bits but in practice zlib wants 1 bit*/ - if(numpresent == 0) - { - lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/ - } - else if(numpresent == 1) - { - for(i = 0; i < numcodes; i++) - { - if(frequencies[i]) - { - lengths[i] = 1; - lengths[i == 0 ? 1 : 0] = 1; - break; - } - } - } - else - { - /*Package-Merge algorithm represented by coin collector's problem - For every symbol, maxbitlen coins will be created*/ - - coinmem = numpresent * 2; /*max amount of coins needed with the current algo*/ - coins = (Coin*)lodepng_malloc(sizeof(Coin) * coinmem); - prev_row = (Coin*)lodepng_malloc(sizeof(Coin) * coinmem); - if(!coins || !prev_row) - { - lodepng_free(coins); - lodepng_free(prev_row); - return 83; /*alloc fail*/ - } - init_coins(coins, coinmem); - init_coins(prev_row, coinmem); - - /*first row, lowest denominator*/ - error = append_symbol_coins(coins, frequencies, numcodes, sum); - numcoins = numpresent; - qsort(coins, numcoins, sizeof(Coin), coin_compare); - if(!error) - { - unsigned numprev = 0; - for(j = 1; j <= maxbitlen && !error; j++) /*each of the remaining rows*/ - { - unsigned tempnum; - Coin* tempcoins; - /*swap prev_row and coins, and their amounts*/ - tempcoins = prev_row; prev_row = coins; coins = tempcoins; - tempnum = numprev; numprev = numcoins; numcoins = tempnum; - - cleanup_coins(coins, numcoins); - init_coins(coins, numcoins); - - numcoins = 0; - - /*fill in the merged coins of the previous row*/ - for(i = 0; i + 1 < numprev; i += 2) - { - /*merge prev_row[i] and prev_row[i + 1] into new coin*/ - Coin* coin = &coins[numcoins++]; - coin_copy(coin, &prev_row[i]); - add_coins(coin, &prev_row[i + 1]); - } - /*fill in all the original symbols again*/ - if(j < maxbitlen) - { - error = append_symbol_coins(coins + numcoins, frequencies, numcodes, sum); - numcoins += numpresent; - } - qsort(coins, numcoins, sizeof(Coin), coin_compare); - } - } - - if(!error) - { - /*calculate the lenghts of each symbol, as the amount of times a coin of each symbol is used*/ - for(i = 0; i < numpresent - 1; i++) - { - Coin* coin = &coins[i]; - for(j = 0; j < coin->symbols.size; j++) lengths[coin->symbols.data[j]]++; - } - } - - cleanup_coins(coins, coinmem); - lodepng_free(coins); - cleanup_coins(prev_row, coinmem); - lodepng_free(prev_row); - } - - return error; -} - -/*Create the Huffman tree given the symbol frequencies*/ -static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies, - size_t mincodes, size_t numcodes, unsigned maxbitlen) -{ - unsigned error = 0; - while(!frequencies[numcodes - 1] && numcodes > mincodes) numcodes--; /*trim zeroes*/ - tree->maxbitlen = maxbitlen; - tree->numcodes = (unsigned)numcodes; /*number of symbols*/ - tree->lengths = (unsigned*)lodepng_realloc(tree->lengths, numcodes * sizeof(unsigned)); - if(!tree->lengths) return 83; /*alloc fail*/ - /*initialize all lengths to 0*/ - memset(tree->lengths, 0, numcodes * sizeof(unsigned)); - - error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen); - if(!error) error = HuffmanTree_makeFromLengths2(tree); - return error; -} - -static unsigned HuffmanTree_getCode(const HuffmanTree* tree, unsigned index) -{ - return tree->tree1d[index]; -} - -static unsigned HuffmanTree_getLength(const HuffmanTree* tree, unsigned index) -{ - return tree->lengths[index]; -} -#endif /*LODEPNG_COMPILE_ENCODER*/ - -/*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/ -static unsigned generateFixedLitLenTree(HuffmanTree* tree) -{ - unsigned i, error = 0; - unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); - if(!bitlen) return 83; /*alloc fail*/ - - /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/ - for(i = 0; i <= 143; i++) bitlen[i] = 8; - for(i = 144; i <= 255; i++) bitlen[i] = 9; - for(i = 256; i <= 279; i++) bitlen[i] = 7; - for(i = 280; i <= 287; i++) bitlen[i] = 8; - - error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15); - - lodepng_free(bitlen); - return error; -} - -/*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/ -static unsigned generateFixedDistanceTree(HuffmanTree* tree) -{ - unsigned i, error = 0; - unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); - if(!bitlen) return 83; /*alloc fail*/ - - /*there are 32 distance codes, but 30-31 are unused*/ - for(i = 0; i < NUM_DISTANCE_SYMBOLS; i++) bitlen[i] = 5; - error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15); - - lodepng_free(bitlen); - return error; -} - -#ifdef LODEPNG_COMPILE_DECODER - -/* -returns the code, or (unsigned)(-1) if error happened -inbitlength is the length of the complete buffer, in bits (so its byte length times 8) -*/ -static unsigned huffmanDecodeSymbol(const unsigned char* in, size_t* bp, - const HuffmanTree* codetree, size_t inbitlength) -{ - unsigned treepos = 0, ct; - for(;;) - { - if(*bp >= inbitlength) return (unsigned)(-1); /*error: end of input memory reached without endcode*/ - /* - decode the symbol from the tree. The "readBitFromStream" code is inlined in - the expression below because this is the biggest bottleneck while decoding - */ - ct = codetree->tree2d[(treepos << 1) + READBIT(*bp, in)]; - (*bp)++; - if(ct < codetree->numcodes) return ct; /*the symbol is decoded, return it*/ - else treepos = ct - codetree->numcodes; /*symbol not yet decoded, instead move tree position*/ - - if(treepos >= codetree->numcodes) return (unsigned)(-1); /*error: it appeared outside the codetree*/ - } -} -#endif /*LODEPNG_COMPILE_DECODER*/ - -#ifdef LODEPNG_COMPILE_DECODER - -/* ////////////////////////////////////////////////////////////////////////// */ -/* / Inflator (Decompressor) / */ -/* ////////////////////////////////////////////////////////////////////////// */ - -/*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/ -static void getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d) -{ - /*TODO: check for out of memory errors*/ - generateFixedLitLenTree(tree_ll); - generateFixedDistanceTree(tree_d); -} - -/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/ -static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, - const unsigned char* in, size_t* bp, size_t inlength) -{ - /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/ - unsigned error = 0; - unsigned n, HLIT, HDIST, HCLEN, i; - size_t inbitlength = inlength * 8; - - /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/ - unsigned* bitlen_ll = 0; /*lit,len code lengths*/ - unsigned* bitlen_d = 0; /*dist code lengths*/ - /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/ - unsigned* bitlen_cl = 0; - HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/ - - if((*bp) >> 3 >= inlength - 2) return 49; /*error: the bit pointer is or will go past the memory*/ - - /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/ - HLIT = readBitsFromStream(bp, in, 5) + 257; - /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/ - HDIST = readBitsFromStream(bp, in, 5) + 1; - /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/ - HCLEN = readBitsFromStream(bp, in, 4) + 4; - - HuffmanTree_init(&tree_cl); - - while(!error) - { - /*read the code length codes out of 3 * (amount of code length codes) bits*/ - - bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned)); - if(!bitlen_cl) ERROR_BREAK(83 /*alloc fail*/); - - for(i = 0; i < NUM_CODE_LENGTH_CODES; i++) - { - if(i < HCLEN) bitlen_cl[CLCL_ORDER[i]] = readBitsFromStream(bp, in, 3); - else bitlen_cl[CLCL_ORDER[i]] = 0; /*if not, it must stay 0*/ - } - - error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7); - if(error) break; - - /*now we can use this tree to read the lengths for the tree that this function will return*/ - bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); - bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); - if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/); - for(i = 0; i < NUM_DEFLATE_CODE_SYMBOLS; i++) bitlen_ll[i] = 0; - for(i = 0; i < NUM_DISTANCE_SYMBOLS; i++) bitlen_d[i] = 0; - - /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/ - i = 0; - while(i < HLIT + HDIST) - { - unsigned code = huffmanDecodeSymbol(in, bp, &tree_cl, inbitlength); - if(code <= 15) /*a length code*/ - { - if(i < HLIT) bitlen_ll[i] = code; - else bitlen_d[i - HLIT] = code; - i++; - } - else if(code == 16) /*repeat previous*/ - { - unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/ - unsigned value; /*set value to the previous code*/ - - if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ - if (i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/ - - replength += readBitsFromStream(bp, in, 2); - - if(i < HLIT + 1) value = bitlen_ll[i - 1]; - else value = bitlen_d[i - HLIT - 1]; - /*repeat this value in the next lengths*/ - for(n = 0; n < replength; n++) - { - if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/ - if(i < HLIT) bitlen_ll[i] = value; - else bitlen_d[i - HLIT] = value; - i++; - } - } - else if(code == 17) /*repeat "0" 3-10 times*/ - { - unsigned replength = 3; /*read in the bits that indicate repeat length*/ - if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ - - replength += readBitsFromStream(bp, in, 3); - - /*repeat this value in the next lengths*/ - for(n = 0; n < replength; n++) - { - if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/ - - if(i < HLIT) bitlen_ll[i] = 0; - else bitlen_d[i - HLIT] = 0; - i++; - } - } - else if(code == 18) /*repeat "0" 11-138 times*/ - { - unsigned replength = 11; /*read in the bits that indicate repeat length*/ - if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ - - replength += readBitsFromStream(bp, in, 7); - - /*repeat this value in the next lengths*/ - for(n = 0; n < replength; n++) - { - if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/ - - if(i < HLIT) bitlen_ll[i] = 0; - else bitlen_d[i - HLIT] = 0; - i++; - } - } - else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ - { - if(code == (unsigned)(-1)) - { - /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol - (10=no endcode, 11=wrong jump outside of tree)*/ - error = (*bp) > inbitlength ? 10 : 11; - } - else error = 16; /*unexisting code, this can never happen*/ - break; - } - } - if(error) break; - - if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/ - - /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/ - error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15); - if(error) break; - error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15); - - break; /*end of error-while*/ - } - - lodepng_free(bitlen_cl); - lodepng_free(bitlen_ll); - lodepng_free(bitlen_d); - HuffmanTree_cleanup(&tree_cl); - - return error; -} - -/*inflate a block with dynamic of fixed Huffman tree*/ -static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size_t* bp, - size_t* pos, size_t inlength, unsigned btype) -{ - unsigned error = 0; - HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/ - HuffmanTree tree_d; /*the huffman tree for distance codes*/ - size_t inbitlength = inlength * 8; - - HuffmanTree_init(&tree_ll); - HuffmanTree_init(&tree_d); - - if(btype == 1) getTreeInflateFixed(&tree_ll, &tree_d); - else if(btype == 2) error = getTreeInflateDynamic(&tree_ll, &tree_d, in, bp, inlength); - - while(!error) /*decode all symbols until end reached, breaks at end code*/ - { - /*code_ll is literal, length or end code*/ - unsigned code_ll = huffmanDecodeSymbol(in, bp, &tree_ll, inbitlength); - if(code_ll <= 255) /*literal symbol*/ - { - if((*pos) >= out->size) - { - /*reserve more room at once*/ - if(!ucvector_resize(out, ((*pos) + 1) * 2)) ERROR_BREAK(83 /*alloc fail*/); - } - out->data[(*pos)] = (unsigned char)(code_ll); - (*pos)++; - } - else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ - { - unsigned code_d, distance; - unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/ - size_t start, forward, backward, length; - - /*part 1: get length base*/ - length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX]; - - /*part 2: get extra bits and add the value of that to length*/ - numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX]; - if(*bp >= inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ - length += readBitsFromStream(bp, in, numextrabits_l); - - /*part 3: get distance code*/ - code_d = huffmanDecodeSymbol(in, bp, &tree_d, inbitlength); - if(code_d > 29) - { - if(code_ll == (unsigned)(-1)) /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ - { - /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol - (10=no endcode, 11=wrong jump outside of tree)*/ - error = (*bp) > inlength * 8 ? 10 : 11; - } - else error = 18; /*error: invalid distance code (30-31 are never used)*/ - break; - } - distance = DISTANCEBASE[code_d]; - - /*part 4: get extra bits from distance*/ - numextrabits_d = DISTANCEEXTRA[code_d]; - if(*bp >= inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ - - distance += readBitsFromStream(bp, in, numextrabits_d); - - /*part 5: fill in all the out[n] values based on the length and dist*/ - start = (*pos); - if(distance > start) ERROR_BREAK(52); /*too long backward distance*/ - backward = start - distance; - if((*pos) + length >= out->size) - { - /*reserve more room at once*/ - if(!ucvector_resize(out, ((*pos) + length) * 2)) ERROR_BREAK(83 /*alloc fail*/); - } - - for(forward = 0; forward < length; forward++) - { - out->data[(*pos)] = out->data[backward]; - (*pos)++; - backward++; - if(backward >= start) backward = start - distance; - } - } - else if(code_ll == 256) - { - break; /*end code, break the loop*/ - } - else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ - { - /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol - (10=no endcode, 11=wrong jump outside of tree)*/ - error = (*bp) > inlength * 8 ? 10 : 11; - break; - } - } - - HuffmanTree_cleanup(&tree_ll); - HuffmanTree_cleanup(&tree_d); - - return error; -} - -static unsigned inflateNoCompression(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength) -{ - /*go to first boundary of byte*/ - size_t p; - unsigned LEN, NLEN, n, error = 0; - while(((*bp) & 0x7) != 0) (*bp)++; - p = (*bp) / 8; /*byte position*/ - - /*read LEN (2 bytes) and NLEN (2 bytes)*/ - if(p >= inlength - 4) return 52; /*error, bit pointer will jump past memory*/ - LEN = in[p] + 256 * in[p + 1]; p += 2; - NLEN = in[p] + 256 * in[p + 1]; p += 2; - - /*check if 16-bit NLEN is really the one's complement of LEN*/ - if(LEN + NLEN != 65535) return 21; /*error: NLEN is not one's complement of LEN*/ - - if((*pos) + LEN >= out->size) - { - if(!ucvector_resize(out, (*pos) + LEN)) return 83; /*alloc fail*/ - } - - /*read the literal data: LEN bytes are now stored in the out buffer*/ - if(p + LEN > inlength) return 23; /*error: reading outside of in buffer*/ - for(n = 0; n < LEN; n++) out->data[(*pos)++] = in[p++]; - - (*bp) = p * 8; - - return error; -} - -static unsigned lodepng_inflatev(ucvector* out, - const unsigned char* in, size_t insize, - const LodePNGDecompressSettings* settings) -{ - /*bit pointer in the "in" data, current byte is bp >> 3, current bit is bp & 0x7 (from lsb to msb of the byte)*/ - size_t bp = 0; - unsigned BFINAL = 0; - size_t pos = 0; /*byte position in the out buffer*/ - - unsigned error = 0; - - (void)settings; - - while(!BFINAL) - { - unsigned BTYPE; - if(bp + 2 >= insize * 8) return 52; /*error, bit pointer will jump past memory*/ - BFINAL = readBitFromStream(&bp, in); - BTYPE = 1 * readBitFromStream(&bp, in); - BTYPE += 2 * readBitFromStream(&bp, in); - - if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ - else if(BTYPE == 0) error = inflateNoCompression(out, in, &bp, &pos, insize); /*no compression*/ - else error = inflateHuffmanBlock(out, in, &bp, &pos, insize, BTYPE); /*compression, BTYPE 01 or 10*/ - - if(error) return error; - } - - /*Only now we know the true size of out, resize it to that*/ - if(!ucvector_resize(out, pos)) error = 83; /*alloc fail*/ - - return error; -} - -unsigned lodepng_inflate(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, - const LodePNGDecompressSettings* settings) -{ - unsigned error; - ucvector v; - ucvector_init_buffer(&v, *out, *outsize); - error = lodepng_inflatev(&v, in, insize, settings); - *out = v.data; - *outsize = v.size; - return error; -} - -static unsigned inflate(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, - const LodePNGDecompressSettings* settings) -{ - if(settings->custom_inflate) - { - return settings->custom_inflate(out, outsize, in, insize, settings); - } - else - { - return lodepng_inflate(out, outsize, in, insize, settings); - } -} - -#endif /*LODEPNG_COMPILE_DECODER*/ - -#ifdef LODEPNG_COMPILE_ENCODER - -/* ////////////////////////////////////////////////////////////////////////// */ -/* / Deflator (Compressor) / */ -/* ////////////////////////////////////////////////////////////////////////// */ - -static const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258; - -/*bitlen is the size in bits of the code*/ -static void addHuffmanSymbol(size_t* bp, ucvector* compressed, unsigned code, unsigned bitlen) -{ - addBitsToStreamReversed(bp, compressed, code, bitlen); -} - -/*search the index in the array, that has the largest value smaller than or equal to the given value, -given array must be sorted (if no value is smaller, it returns the size of the given array)*/ -static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value) -{ - /*linear search implementation*/ - /*for(size_t i = 1; i < array_size; i++) if(array[i] > value) return i - 1; - return array_size - 1;*/ - - /*binary search implementation (not that much faster) (precondition: array_size > 0)*/ - size_t left = 1; - size_t right = array_size - 1; - while(left <= right) - { - size_t mid = (left + right) / 2; - if(array[mid] <= value) left = mid + 1; /*the value to find is more to the right*/ - else if(array[mid - 1] > value) right = mid - 1; /*the value to find is more to the left*/ - else return mid - 1; - } - return array_size - 1; -} - -static void addLengthDistance(uivector* values, size_t length, size_t distance) -{ - /*values in encoded vector are those used by deflate: - 0-255: literal bytes - 256: end - 257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits) - 286-287: invalid*/ - - unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length); - unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]); - unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance); - unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]); - - uivector_push_back(values, length_code + FIRST_LENGTH_CODE_INDEX); - uivector_push_back(values, extra_length); - uivector_push_back(values, dist_code); - uivector_push_back(values, extra_distance); -} - -static const unsigned HASH_BIT_MASK = 65535; -static const unsigned HASH_NUM_VALUES = 65536; -static const unsigned HASH_NUM_CHARACTERS = 3; -static const unsigned HASH_SHIFT = 2; -/* -The HASH_NUM_CHARACTERS value is used to make encoding faster by using longer -sequences to generate a hash value from the stream bytes. Setting it to 3 -gives exactly the same compression as the brute force method, since deflate's -run length encoding starts with lengths of 3. Setting it to higher values, -like 6, can make the encoding faster (not always though!), but will cause the -encoding to miss any length between 3 and this value, so that the compression -may be worse (but this can vary too depending on the image, sometimes it is -even a bit better instead). -The HASH_NUM_VALUES is the amount of unique possible hash values that -combinations of bytes can give, the higher it is the more memory is needed, but -if it's too low the advantage of hashing is gone. -*/ - -typedef struct Hash -{ - int* head; /*hash value to head circular pos*/ - int* val; /*circular pos to hash value*/ - /*circular pos to prev circular pos*/ - unsigned short* chain; - unsigned short* zeros; -} Hash; - -static unsigned hash_init(Hash* hash, unsigned windowsize) -{ - unsigned i; - hash->head = (int*)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES); - hash->val = (int*)lodepng_malloc(sizeof(int) * windowsize); - hash->chain = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); - hash->zeros = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); - - if(!hash->head || !hash->val || !hash->chain || !hash->zeros) return 83; /*alloc fail*/ - - /*initialize hash table*/ - for(i = 0; i < HASH_NUM_VALUES; i++) hash->head[i] = -1; - for(i = 0; i < windowsize; i++) hash->val[i] = -1; - for(i = 0; i < windowsize; i++) hash->chain[i] = i; /*same value as index indicates uninitialized*/ - - return 0; -} - -static void hash_cleanup(Hash* hash) -{ - lodepng_free(hash->head); - lodepng_free(hash->val); - lodepng_free(hash->chain); - lodepng_free(hash->zeros); -} - -static unsigned getHash(const unsigned char* data, size_t size, size_t pos) -{ - unsigned result = 0; - if (HASH_NUM_CHARACTERS == 3 && pos + 2 < size) { - result ^= (data[pos + 0] << (0 * HASH_SHIFT)); - result ^= (data[pos + 1] << (1 * HASH_SHIFT)); - result ^= (data[pos + 2] << (2 * HASH_SHIFT)); - } else { - size_t amount, i; - if(pos >= size) return 0; - amount = HASH_NUM_CHARACTERS; - if(pos + amount >= size) amount = size - pos; - for(i = 0; i < amount; i++) result ^= (data[pos + i] << (i * HASH_SHIFT)); - } - return result & HASH_BIT_MASK; -} - -static unsigned countZeros(const unsigned char* data, size_t size, size_t pos) -{ - const unsigned char* start = data + pos; - const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH; - if(end > data + size) end = data + size; - data = start; - while (data != end && *data == 0) data++; - /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/ - return (unsigned)(data - start); -} - -/*wpos = pos & (windowsize - 1)*/ -static void updateHashChain(Hash* hash, size_t wpos, int hashval) -{ - hash->val[wpos] = hashval; - if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval]; - hash->head[hashval] = wpos; -} - -/* -LZ77-encode the data. Return value is error code. The input are raw bytes, the output -is in the form of unsigned integers with codes representing for example literal bytes, or -length/distance pairs. -It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a -sliding window (of windowsize) is used, and all past bytes in that window can be used as -the "dictionary". A brute force search through all possible distances would be slow, and -this hash technique is one out of several ways to speed this up. -*/ -static unsigned encodeLZ77(uivector* out, Hash* hash, - const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize, - unsigned minmatch, unsigned nicematch, unsigned lazymatching) -{ - unsigned pos, i, error = 0; - /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/ - unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8; - unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64; - - unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/ - unsigned numzeros = 0; - - unsigned offset; /*the offset represents the distance in LZ77 terminology*/ - unsigned length; - unsigned lazy = 0; - unsigned lazylength = 0, lazyoffset = 0; - unsigned hashval; - unsigned current_offset, current_length; - const unsigned char *lastptr, *foreptr, *backptr; - unsigned hashpos, prevpos; - - if(windowsize <= 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/ - if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/ - - if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH; - - for(pos = inpos; pos < insize; pos++) - { - size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/ - unsigned chainlength = 0; - - hashval = getHash(in, insize, pos); - updateHashChain(hash, wpos, hashval); - - if(usezeros && hashval == 0) - { - if (numzeros == 0) numzeros = countZeros(in, insize, pos); - else if (pos + numzeros >= insize || in[pos + numzeros - 1] != 0) numzeros--; - hash->zeros[wpos] = numzeros; - } - else - { - numzeros = 0; - } - - /*the length and offset found for the current position*/ - length = 0; - offset = 0; - - prevpos = hash->head[hashval]; - hashpos = hash->chain[prevpos]; - - lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH]; - - /*search for the longest string*/ - for(;;) - { - /*stop when went completely around the circular buffer*/ - if(prevpos < wpos && hashpos > prevpos && hashpos <= wpos) break; - if(prevpos > wpos && (hashpos <= wpos || hashpos > prevpos)) break; - if(chainlength++ >= maxchainlength) break; - - current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize; - if(current_offset > 0) - { - /*test the next characters*/ - foreptr = &in[pos]; - backptr = &in[pos - current_offset]; - - /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/ - if(usezeros && hashval == 0 && hash->val[hashpos] == 0 /*hashval[hashpos] may be out of date*/) - { - unsigned skip = hash->zeros[hashpos]; - if(skip > numzeros) skip = numzeros; - backptr += skip; - foreptr += skip; - } - - while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/ - { - ++backptr; - ++foreptr; - } - current_length = (unsigned)(foreptr - &in[pos]); - - if(current_length > length) - { - length = current_length; /*the longest length*/ - offset = current_offset; /*the offset that is related to this longest length*/ - /*jump out once a length of max length is found (speed gain). This also jumps - out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/ - if(current_length >= nicematch) break; - } - } - - if(hashpos == hash->chain[hashpos]) break; - - prevpos = hashpos; - hashpos = hash->chain[hashpos]; - } - - if(lazymatching) - { - if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH) - { - lazy = 1; - lazylength = length; - lazyoffset = offset; - continue; /*try the next byte*/ - } - if(lazy) - { - lazy = 0; - if(pos == 0) ERROR_BREAK(81); - if(length > lazylength + 1) - { - /*push the previous character as literal*/ - if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/); - } - else - { - length = lazylength; - offset = lazyoffset; - hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/ - pos--; - } - } - } - if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/); - - /*encode it as length/distance pair or literal value*/ - if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/ - { - if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); - } - else if(length < minmatch || (length == 3 && offset > 4096)) - { - /*compensate for the fact that longer offsets have more extra bits, a - length of only 3 may be not worth it then*/ - if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); - } - else - { - addLengthDistance(out, length, offset); - for(i = 1; i < length; i++) - { - pos++; - wpos = pos & (windowsize - 1); - hashval = getHash(in, insize, pos); - updateHashChain(hash, wpos, hashval); - if(usezeros && hashval == 0) - { - if (numzeros == 0) numzeros = countZeros(in, insize, pos); - else if (pos + numzeros >= insize || in[pos + numzeros - 1] != 0) numzeros--; - hash->zeros[wpos] = numzeros; - } - else - { - numzeros = 0; - } - } - } - } /*end of the loop through each character of input*/ - - return error; -} - -/* /////////////////////////////////////////////////////////////////////////// */ - -static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize) -{ - /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte, - 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/ - - size_t i, j, numdeflateblocks = (datasize + 65534) / 65535; - unsigned datapos = 0; - for(i = 0; i < numdeflateblocks; i++) - { - unsigned BFINAL, BTYPE, LEN, NLEN; - unsigned char firstbyte; - - BFINAL = (i == numdeflateblocks - 1); - BTYPE = 0; - - firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1) << 1) + ((BTYPE & 2) << 1)); - ucvector_push_back(out, firstbyte); - - LEN = 65535; - if(datasize - datapos < 65535) LEN = (unsigned)datasize - datapos; - NLEN = 65535 - LEN; - - ucvector_push_back(out, (unsigned char)(LEN % 256)); - ucvector_push_back(out, (unsigned char)(LEN / 256)); - ucvector_push_back(out, (unsigned char)(NLEN % 256)); - ucvector_push_back(out, (unsigned char)(NLEN / 256)); - - /*Decompressed data*/ - for(j = 0; j < 65535 && datapos < datasize; j++) - { - ucvector_push_back(out, data[datapos++]); - } - } - - return 0; -} - -/* -write the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees. -tree_ll: the tree for lit and len codes. -tree_d: the tree for distance codes. -*/ -static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encoded, - const HuffmanTree* tree_ll, const HuffmanTree* tree_d) -{ - size_t i = 0; - for(i = 0; i < lz77_encoded->size; i++) - { - unsigned val = lz77_encoded->data[i]; - addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_ll, val), HuffmanTree_getLength(tree_ll, val)); - if(val > 256) /*for a length code, 3 more things have to be added*/ - { - unsigned length_index = val - FIRST_LENGTH_CODE_INDEX; - unsigned n_length_extra_bits = LENGTHEXTRA[length_index]; - unsigned length_extra_bits = lz77_encoded->data[++i]; - - unsigned distance_code = lz77_encoded->data[++i]; - - unsigned distance_index = distance_code; - unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index]; - unsigned distance_extra_bits = lz77_encoded->data[++i]; - - addBitsToStream(bp, out, length_extra_bits, n_length_extra_bits); - addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_d, distance_code), - HuffmanTree_getLength(tree_d, distance_code)); - addBitsToStream(bp, out, distance_extra_bits, n_distance_extra_bits); - } - } -} - -/*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/ -static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, - const unsigned char* data, size_t datapos, size_t dataend, - const LodePNGCompressSettings* settings, int final) -{ - unsigned error = 0; - - /* - A block is compressed as follows: The PNG data is lz77 encoded, resulting in - literal bytes and length/distance pairs. This is then huffman compressed with - two huffman trees. One huffman tree is used for the lit and len values ("ll"), - another huffman tree is used for the dist values ("d"). These two trees are - stored using their code lengths, and to compress even more these code lengths - are also run-length encoded and huffman compressed. This gives a huffman tree - of code lengths "cl". The code lenghts used to describe this third tree are - the code length code lengths ("clcl"). - */ - - /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/ - uivector lz77_encoded; - HuffmanTree tree_ll; /*tree for lit,len values*/ - HuffmanTree tree_d; /*tree for distance codes*/ - HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/ - uivector frequencies_ll; /*frequency of lit,len codes*/ - uivector frequencies_d; /*frequency of dist codes*/ - uivector frequencies_cl; /*frequency of code length codes*/ - uivector bitlen_lld; /*lit,len,dist code lenghts (int bits), literally (without repeat codes).*/ - uivector bitlen_lld_e; /*bitlen_lld encoded with repeat codes (this is a rudemtary run length compression)*/ - /*bitlen_cl is the code length code lengths ("clcl"). The bit lengths of codes to represent tree_cl - (these are written as is in the file, it would be crazy to compress these using yet another huffman - tree that needs to be represented by yet another set of code lengths)*/ - uivector bitlen_cl; - size_t datasize = dataend - datapos; - - /* - Due to the huffman compression of huffman tree representations ("two levels"), there are some anologies: - bitlen_lld is to tree_cl what data is to tree_ll and tree_d. - bitlen_lld_e is to bitlen_lld what lz77_encoded is to data. - bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded. - */ - - unsigned BFINAL = final; - size_t numcodes_ll, numcodes_d, i; - unsigned HLIT, HDIST, HCLEN; - - uivector_init(&lz77_encoded); - HuffmanTree_init(&tree_ll); - HuffmanTree_init(&tree_d); - HuffmanTree_init(&tree_cl); - uivector_init(&frequencies_ll); - uivector_init(&frequencies_d); - uivector_init(&frequencies_cl); - uivector_init(&bitlen_lld); - uivector_init(&bitlen_lld_e); - uivector_init(&bitlen_cl); - - /*This while loop never loops due to a break at the end, it is here to - allow breaking out of it to the cleanup phase on error conditions.*/ - while(!error) - { - if(settings->use_lz77) - { - error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, - settings->minmatch, settings->nicematch, settings->lazymatching); - if(error) break; - } - else - { - if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/); - for(i = datapos; i < dataend; i++) lz77_encoded.data[i] = data[i]; /*no LZ77, but still will be Huffman compressed*/ - } - - if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83 /*alloc fail*/); - if(!uivector_resizev(&frequencies_d, 30, 0)) ERROR_BREAK(83 /*alloc fail*/); - - /*Count the frequencies of lit, len and dist codes*/ - for(i = 0; i < lz77_encoded.size; i++) - { - unsigned symbol = lz77_encoded.data[i]; - frequencies_ll.data[symbol]++; - if(symbol > 256) - { - unsigned dist = lz77_encoded.data[i + 2]; - frequencies_d.data[dist]++; - i += 3; - } - } - frequencies_ll.data[256] = 1; /*there will be exactly 1 end code, at the end of the block*/ - - /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/ - error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll.data, 257, frequencies_ll.size, 15); - if(error) break; - /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least 2 symbols in the dist tree*/ - error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d.data, 2, frequencies_d.size, 15); - if(error) break; - - numcodes_ll = tree_ll.numcodes; if(numcodes_ll > 286) numcodes_ll = 286; - numcodes_d = tree_d.numcodes; if(numcodes_d > 30) numcodes_d = 30; - /*store the code lengths of both generated trees in bitlen_lld*/ - for(i = 0; i < numcodes_ll; i++) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_ll, (unsigned)i)); - for(i = 0; i < numcodes_d; i++) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_d, (unsigned)i)); - - /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times), - 17 (3-10 zeroes), 18 (11-138 zeroes)*/ - for(i = 0; i < (unsigned)bitlen_lld.size; i++) - { - unsigned j = 0; /*amount of repititions*/ - while(i + j + 1 < (unsigned)bitlen_lld.size && bitlen_lld.data[i + j + 1] == bitlen_lld.data[i]) j++; - - if(bitlen_lld.data[i] == 0 && j >= 2) /*repeat code for zeroes*/ - { - j++; /*include the first zero*/ - if(j <= 10) /*repeat code 17 supports max 10 zeroes*/ - { - uivector_push_back(&bitlen_lld_e, 17); - uivector_push_back(&bitlen_lld_e, j - 3); - } - else /*repeat code 18 supports max 138 zeroes*/ - { - if(j > 138) j = 138; - uivector_push_back(&bitlen_lld_e, 18); - uivector_push_back(&bitlen_lld_e, j - 11); - } - i += (j - 1); - } - else if(j >= 3) /*repeat code for value other than zero*/ - { - size_t k; - unsigned num = j / 6, rest = j % 6; - uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); - for(k = 0; k < num; k++) - { - uivector_push_back(&bitlen_lld_e, 16); - uivector_push_back(&bitlen_lld_e, 6 - 3); - } - if(rest >= 3) - { - uivector_push_back(&bitlen_lld_e, 16); - uivector_push_back(&bitlen_lld_e, rest - 3); - } - else j -= rest; - i += j; - } - else /*too short to benefit from repeat code*/ - { - uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); - } - } - - /*generate tree_cl, the huffmantree of huffmantrees*/ - - if(!uivector_resizev(&frequencies_cl, NUM_CODE_LENGTH_CODES, 0)) ERROR_BREAK(83 /*alloc fail*/); - for(i = 0; i < bitlen_lld_e.size; i++) - { - frequencies_cl.data[bitlen_lld_e.data[i]]++; - /*after a repeat code come the bits that specify the number of repetitions, - those don't need to be in the frequencies_cl calculation*/ - if(bitlen_lld_e.data[i] >= 16) i++; - } - - error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl.data, - frequencies_cl.size, frequencies_cl.size, 7); - if(error) break; - - if(!uivector_resize(&bitlen_cl, tree_cl.numcodes)) ERROR_BREAK(83 /*alloc fail*/); - for(i = 0; i < tree_cl.numcodes; i++) - { - /*lenghts of code length tree is in the order as specified by deflate*/ - bitlen_cl.data[i] = HuffmanTree_getLength(&tree_cl, CLCL_ORDER[i]); - } - while(bitlen_cl.data[bitlen_cl.size - 1] == 0 && bitlen_cl.size > 4) - { - /*remove zeros at the end, but minimum size must be 4*/ - if(!uivector_resize(&bitlen_cl, bitlen_cl.size - 1)) ERROR_BREAK(83 /*alloc fail*/); - } - if(error) break; - - /* - Write everything into the output - - After the BFINAL and BTYPE, the dynamic block consists out of the following: - - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN - - (HCLEN+4)*3 bits code lengths of code length alphabet - - HLIT + 257 code lenghts of lit/length alphabet (encoded using the code length - alphabet, + possible repetition codes 16, 17, 18) - - HDIST + 1 code lengths of distance alphabet (encoded using the code length - alphabet, + possible repetition codes 16, 17, 18) - - compressed data - - 256 (end code) - */ - - /*Write block type*/ - addBitToStream(bp, out, BFINAL); - addBitToStream(bp, out, 0); /*first bit of BTYPE "dynamic"*/ - addBitToStream(bp, out, 1); /*second bit of BTYPE "dynamic"*/ - - /*write the HLIT, HDIST and HCLEN values*/ - HLIT = (unsigned)(numcodes_ll - 257); - HDIST = (unsigned)(numcodes_d - 1); - HCLEN = (unsigned)bitlen_cl.size - 4; - /*trim zeroes for HCLEN. HLIT and HDIST were already trimmed at tree creation*/ - while(!bitlen_cl.data[HCLEN + 4 - 1] && HCLEN > 0) HCLEN--; - addBitsToStream(bp, out, HLIT, 5); - addBitsToStream(bp, out, HDIST, 5); - addBitsToStream(bp, out, HCLEN, 4); - - /*write the code lenghts of the code length alphabet*/ - for(i = 0; i < HCLEN + 4; i++) addBitsToStream(bp, out, bitlen_cl.data[i], 3); - - /*write the lenghts of the lit/len AND the dist alphabet*/ - for(i = 0; i < bitlen_lld_e.size; i++) - { - addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_cl, bitlen_lld_e.data[i]), - HuffmanTree_getLength(&tree_cl, bitlen_lld_e.data[i])); - /*extra bits of repeat codes*/ - if(bitlen_lld_e.data[i] == 16) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 2); - else if(bitlen_lld_e.data[i] == 17) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 3); - else if(bitlen_lld_e.data[i] == 18) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 7); - } - - /*write the compressed data symbols*/ - writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); - /*error: the length of the end code 256 must be larger than 0*/ - if(HuffmanTree_getLength(&tree_ll, 256) == 0) ERROR_BREAK(64); - - /*write the end code*/ - addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); - - break; /*end of error-while*/ - } - - /*cleanup*/ - uivector_cleanup(&lz77_encoded); - HuffmanTree_cleanup(&tree_ll); - HuffmanTree_cleanup(&tree_d); - HuffmanTree_cleanup(&tree_cl); - uivector_cleanup(&frequencies_ll); - uivector_cleanup(&frequencies_d); - uivector_cleanup(&frequencies_cl); - uivector_cleanup(&bitlen_lld_e); - uivector_cleanup(&bitlen_lld); - uivector_cleanup(&bitlen_cl); - - return error; -} - -static unsigned deflateFixed(ucvector* out, size_t* bp, Hash* hash, - const unsigned char* data, - size_t datapos, size_t dataend, - const LodePNGCompressSettings* settings, int final) -{ - HuffmanTree tree_ll; /*tree for literal values and length codes*/ - HuffmanTree tree_d; /*tree for distance codes*/ - - unsigned BFINAL = final; - unsigned error = 0; - size_t i; - - HuffmanTree_init(&tree_ll); - HuffmanTree_init(&tree_d); - - generateFixedLitLenTree(&tree_ll); - generateFixedDistanceTree(&tree_d); - - addBitToStream(bp, out, BFINAL); - addBitToStream(bp, out, 1); /*first bit of BTYPE*/ - addBitToStream(bp, out, 0); /*second bit of BTYPE*/ - - if(settings->use_lz77) /*LZ77 encoded*/ - { - uivector lz77_encoded; - uivector_init(&lz77_encoded); - error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, - settings->minmatch, settings->nicematch, settings->lazymatching); - if(!error) writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); - uivector_cleanup(&lz77_encoded); - } - else /*no LZ77, but still will be Huffman compressed*/ - { - for(i = datapos; i < dataend; i++) - { - addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, data[i]), HuffmanTree_getLength(&tree_ll, data[i])); - } - } - /*add END code*/ - if(!error) addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); - - /*cleanup*/ - HuffmanTree_cleanup(&tree_ll); - HuffmanTree_cleanup(&tree_d); - - return error; -} - -static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize, - const LodePNGCompressSettings* settings) -{ - unsigned error = 0; - size_t i, blocksize, numdeflateblocks; - size_t bp = 0; /*the bit pointer*/ - Hash hash; - - if(settings->btype > 2) return 61; - else if(settings->btype == 0) return deflateNoCompression(out, in, insize); - else if(settings->btype == 1) blocksize = insize; - else /*if(settings->btype == 2)*/ - { - blocksize = insize / 8 + 8; - if(blocksize < 65535) blocksize = 65535; - } - - numdeflateblocks = (insize + blocksize - 1) / blocksize; - if(numdeflateblocks == 0) numdeflateblocks = 1; - - error = hash_init(&hash, settings->windowsize); - if(error) return error; - - for(i = 0; i < numdeflateblocks && !error; i++) - { - int final = i == numdeflateblocks - 1; - size_t start = i * blocksize; - size_t end = start + blocksize; - if(end > insize) end = insize; - - if(settings->btype == 1) error = deflateFixed(out, &bp, &hash, in, start, end, settings, final); - else if(settings->btype == 2) error = deflateDynamic(out, &bp, &hash, in, start, end, settings, final); - } - - hash_cleanup(&hash); - - return error; -} - -unsigned lodepng_deflate(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, - const LodePNGCompressSettings* settings) -{ - unsigned error; - ucvector v; - ucvector_init_buffer(&v, *out, *outsize); - error = lodepng_deflatev(&v, in, insize, settings); - *out = v.data; - *outsize = v.size; - return error; -} - -static unsigned deflate(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, - const LodePNGCompressSettings* settings) -{ - if(settings->custom_deflate) - { - return settings->custom_deflate(out, outsize, in, insize, settings); - } - else - { - return lodepng_deflate(out, outsize, in, insize, settings); - } -} - -#endif /*LODEPNG_COMPILE_DECODER*/ - -/* ////////////////////////////////////////////////////////////////////////// */ -/* / Adler32 */ -/* ////////////////////////////////////////////////////////////////////////// */ - -static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len) -{ - unsigned s1 = adler & 0xffff; - unsigned s2 = (adler >> 16) & 0xffff; - - while(len > 0) - { - /*at least 5550 sums can be done before the sums overflow, saving a lot of module divisions*/ - unsigned amount = len > 5550 ? 5550 : len; - len -= amount; - while(amount > 0) - { - s1 += (*data++); - s2 += s1; - amount--; - } - s1 %= 65521; - s2 %= 65521; - } - - return (s2 << 16) | s1; -} - -/*Return the adler32 of the bytes data[0..len-1]*/ -static unsigned adler32(const unsigned char* data, unsigned len) -{ - return update_adler32(1L, data, len); -} - -/* ////////////////////////////////////////////////////////////////////////// */ -/* / Zlib / */ -/* ////////////////////////////////////////////////////////////////////////// */ - -#ifdef LODEPNG_COMPILE_DECODER - -unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, - size_t insize, const LodePNGDecompressSettings* settings) -{ - unsigned error = 0; - unsigned CM, CINFO, FDICT; - - if(insize < 2) return 53; /*error, size of zlib data too small*/ - /*read information from zlib header*/ - if((in[0] * 256 + in[1]) % 31 != 0) - { - /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/ - return 24; - } - - CM = in[0] & 15; - CINFO = (in[0] >> 4) & 15; - /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/ - FDICT = (in[1] >> 5) & 1; - /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/ - - if(CM != 8 || CINFO > 7) - { - /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/ - return 25; - } - if(FDICT != 0) - { - /*error: the specification of PNG says about the zlib stream: - "The additional flags shall not specify a preset dictionary."*/ - return 26; - } - - error = inflate(out, outsize, in + 2, insize - 2, settings); - if(error) return error; - - if(!settings->ignore_adler32) - { - unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]); - unsigned checksum = adler32(*out, (unsigned)(*outsize)); - if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/ - } - - return 0; /*no error*/ -} - -static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, - size_t insize, const LodePNGDecompressSettings* settings) -{ - if(settings->custom_zlib) - { - return settings->custom_zlib(out, outsize, in, insize, settings); - } - else - { - return lodepng_zlib_decompress(out, outsize, in, insize, settings); - } -} - -#endif /*LODEPNG_COMPILE_DECODER*/ - -#ifdef LODEPNG_COMPILE_ENCODER - -unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, - size_t insize, const LodePNGCompressSettings* settings) -{ - /*initially, *out must be NULL and outsize 0, if you just give some random *out - that's pointing to a non allocated buffer, this'll crash*/ - ucvector outv; - size_t i; - unsigned error; - unsigned char* deflatedata = 0; - size_t deflatesize = 0; - - unsigned ADLER32; - /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/ - unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/ - unsigned FLEVEL = 0; - unsigned FDICT = 0; - unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64; - unsigned FCHECK = 31 - CMFFLG % 31; - CMFFLG += FCHECK; - - /*ucvector-controlled version of the output buffer, for dynamic array*/ - ucvector_init_buffer(&outv, *out, *outsize); - - ucvector_push_back(&outv, (unsigned char)(CMFFLG / 256)); - ucvector_push_back(&outv, (unsigned char)(CMFFLG % 256)); - - error = deflate(&deflatedata, &deflatesize, in, insize, settings); - - if(!error) - { - ADLER32 = adler32(in, (unsigned)insize); - for(i = 0; i < deflatesize; i++) ucvector_push_back(&outv, deflatedata[i]); - lodepng_free(deflatedata); - lodepng_add32bitInt(&outv, ADLER32); - } - - *out = outv.data; - *outsize = outv.size; - - return error; -} - -/* compress using the default or custom zlib function */ -static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, - size_t insize, const LodePNGCompressSettings* settings) -{ - if(settings->custom_zlib) - { - return settings->custom_zlib(out, outsize, in, insize, settings); - } - else - { - return lodepng_zlib_compress(out, outsize, in, insize, settings); - } -} - -#endif /*LODEPNG_COMPILE_ENCODER*/ - -#else /*no LODEPNG_COMPILE_ZLIB*/ - -#ifdef LODEPNG_COMPILE_DECODER -static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, - size_t insize, const LodePNGDecompressSettings* settings) -{ - if (!settings->custom_zlib) return 87; /*no custom zlib function provided */ - return settings->custom_zlib(out, outsize, in, insize, settings); -} -#endif /*LODEPNG_COMPILE_DECODER*/ -#ifdef LODEPNG_COMPILE_ENCODER -static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, - size_t insize, const LodePNGCompressSettings* settings) -{ - if (!settings->custom_zlib) return 87; /*no custom zlib function provided */ - return settings->custom_zlib(out, outsize, in, insize, settings); -} -#endif /*LODEPNG_COMPILE_ENCODER*/ - -#endif /*LODEPNG_COMPILE_ZLIB*/ - -/* ////////////////////////////////////////////////////////////////////////// */ - -#ifdef LODEPNG_COMPILE_ENCODER - -/*this is a good tradeoff between speed and compression ratio*/ -#define DEFAULT_WINDOWSIZE 2048 - -void lodepng_compress_settings_init(LodePNGCompressSettings* settings) -{ - /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/ - settings->btype = 2; - settings->use_lz77 = 1; - settings->windowsize = DEFAULT_WINDOWSIZE; - settings->minmatch = 3; - settings->nicematch = 128; - settings->lazymatching = 1; - - settings->custom_zlib = 0; - settings->custom_deflate = 0; - settings->custom_context = 0; -} - -const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0}; - - -#endif /*LODEPNG_COMPILE_ENCODER*/ - -#ifdef LODEPNG_COMPILE_DECODER - -void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) -{ - settings->ignore_adler32 = 0; - - settings->custom_zlib = 0; - settings->custom_inflate = 0; - settings->custom_context = 0; -} - -const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0}; - -#endif /*LODEPNG_COMPILE_DECODER*/ - -/* ////////////////////////////////////////////////////////////////////////// */ -/* ////////////////////////////////////////////////////////////////////////// */ -/* // End of Zlib related code. Begin of PNG related code. // */ -/* ////////////////////////////////////////////////////////////////////////// */ -/* ////////////////////////////////////////////////////////////////////////// */ - -#ifdef LODEPNG_COMPILE_PNG - -/* ////////////////////////////////////////////////////////////////////////// */ -/* / CRC32 / */ -/* ////////////////////////////////////////////////////////////////////////// */ - -/* CRC polynomial: 0xedb88320 */ -static unsigned lodepng_crc32_table[256] = { - 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u, - 249268274u, 2044508324u, 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u, - 498536548u, 1789927666u, 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u, - 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 4195302755u, 2366115317u, - 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u, - 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u, - 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u, - 671266974u, 1594198024u, 3322730930u, 2970347812u, 795835527u, 1483230225u, 3244367275u, 3060149565u, - 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u, - 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u, - 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u, - 1706088902u, 314042704u, 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u, - 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u, - 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, 2852801631u, 3708648649u, - 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u, - 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u, - 3988292384u, 2596254646u, 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u, - 3814918930u, 2489596804u, 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u, - 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 426522225u, 1852507879u, - 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u, - 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u, - 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u, - 3412177804u, 3160834842u, 628085408u, 1382605366u, 3423369109u, 3138078467u, 570562233u, 1426400815u, - 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u, - 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u, - 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u, - 2262029012u, 4057260610u, 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u, - 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 1634467795u, 376229701u, - 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u, - 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u, - 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u, - 3009837614u, 3294710456u, 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u -}; - -/*Return the CRC of the bytes buf[0..len-1].*/ -unsigned lodepng_crc32(const unsigned char* buf, size_t len) -{ - unsigned c = 0xffffffffL; - size_t n; - - for(n = 0; n < len; n++) - { - c = lodepng_crc32_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); - } - return c ^ 0xffffffffL; -} - -/* ////////////////////////////////////////////////////////////////////////// */ -/* / Reading and writing single bits and bytes from/to stream for LodePNG / */ -/* ////////////////////////////////////////////////////////////////////////// */ - -static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream) -{ - unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1); - (*bitpointer)++; - return result; -} - -static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) -{ - unsigned result = 0; - size_t i; - for(i = nbits - 1; i < nbits; i--) - { - result += (unsigned)readBitFromReversedStream(bitpointer, bitstream) << i; - } - return result; -} - -#ifdef LODEPNG_COMPILE_DECODER -static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) -{ - /*the current bit in bitstream must be 0 for this to work*/ - if(bit) - { - /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/ - bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7))); - } - (*bitpointer)++; -} -#endif /*LODEPNG_COMPILE_DECODER*/ - -static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) -{ - /*the current bit in bitstream may be 0 or 1 for this to work*/ - if(bit == 0) bitstream[(*bitpointer) >> 3] &= (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7)))); - else bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7))); - (*bitpointer)++; -} - -/* ////////////////////////////////////////////////////////////////////////// */ -/* / PNG chunks / */ -/* ////////////////////////////////////////////////////////////////////////// */ - -unsigned lodepng_chunk_length(const unsigned char* chunk) -{ - return lodepng_read32bitInt(&chunk[0]); -} - -void lodepng_chunk_type(char type[5], const unsigned char* chunk) -{ - unsigned i; - for(i = 0; i < 4; i++) type[i] = chunk[4 + i]; - type[4] = 0; /*null termination char*/ -} - -unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type) -{ - if(strlen(type) != 4) return 0; - return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]); -} - -unsigned char lodepng_chunk_ancillary(const unsigned char* chunk) -{ - return((chunk[4] & 32) != 0); -} - -unsigned char lodepng_chunk_private(const unsigned char* chunk) -{ - return((chunk[6] & 32) != 0); -} - -unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk) -{ - return((chunk[7] & 32) != 0); -} - -unsigned char* lodepng_chunk_data(unsigned char* chunk) -{ - return &chunk[8]; -} - -const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk) -{ - return &chunk[8]; -} - -unsigned lodepng_chunk_check_crc(const unsigned char* chunk) -{ - unsigned length = lodepng_chunk_length(chunk); - unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]); - /*the CRC is taken of the data and the 4 chunk type letters, not the length*/ - unsigned checksum = lodepng_crc32(&chunk[4], length + 4); - if(CRC != checksum) return 1; - else return 0; -} - -void lodepng_chunk_generate_crc(unsigned char* chunk) -{ - unsigned length = lodepng_chunk_length(chunk); - unsigned CRC = lodepng_crc32(&chunk[4], length + 4); - lodepng_set32bitInt(chunk + 8 + length, CRC); -} - -unsigned char* lodepng_chunk_next(unsigned char* chunk) -{ - unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; - return &chunk[total_chunk_length]; -} - -const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk) -{ - unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; - return &chunk[total_chunk_length]; -} - -unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk) -{ - unsigned i; - unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; - unsigned char *chunk_start, *new_buffer; - size_t new_length = (*outlength) + total_chunk_length; - if(new_length < total_chunk_length || new_length < (*outlength)) return 77; /*integer overflow happened*/ - - new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); - if(!new_buffer) return 83; /*alloc fail*/ - (*out) = new_buffer; - (*outlength) = new_length; - chunk_start = &(*out)[new_length - total_chunk_length]; - - for(i = 0; i < total_chunk_length; i++) chunk_start[i] = chunk[i]; - - return 0; -} - -unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, - const char* type, const unsigned char* data) -{ - unsigned i; - unsigned char *chunk, *new_buffer; - size_t new_length = (*outlength) + length + 12; - if(new_length < length + 12 || new_length < (*outlength)) return 77; /*integer overflow happened*/ - new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); - if(!new_buffer) return 83; /*alloc fail*/ - (*out) = new_buffer; - (*outlength) = new_length; - chunk = &(*out)[(*outlength) - length - 12]; - - /*1: length*/ - lodepng_set32bitInt(chunk, (unsigned)length); - - /*2: chunk name (4 letters)*/ - chunk[4] = type[0]; - chunk[5] = type[1]; - chunk[6] = type[2]; - chunk[7] = type[3]; - - /*3: the data*/ - for(i = 0; i < length; i++) chunk[8 + i] = data[i]; - - /*4: CRC (of the chunkname characters and the data)*/ - lodepng_chunk_generate_crc(chunk); - - return 0; -} - -/* ////////////////////////////////////////////////////////////////////////// */ -/* / Color types and such / */ -/* ////////////////////////////////////////////////////////////////////////// */ - -/*return type is a LodePNG error code*/ -static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) /*bd = bitdepth*/ -{ - switch(colortype) - { - case 0: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; /*grey*/ - case 2: if(!( bd == 8 || bd == 16)) return 37; break; /*RGB*/ - case 3: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; /*palette*/ - case 4: if(!( bd == 8 || bd == 16)) return 37; break; /*grey + alpha*/ - case 6: if(!( bd == 8 || bd == 16)) return 37; break; /*RGBA*/ - default: return 31; - } - return 0; /*allowed color type / bits combination*/ -} - -static unsigned getNumColorChannels(LodePNGColorType colortype) -{ - switch(colortype) - { - case 0: return 1; /*grey*/ - case 2: return 3; /*RGB*/ - case 3: return 1; /*palette*/ - case 4: return 2; /*grey + alpha*/ - case 6: return 4; /*RGBA*/ - } - return 0; /*unexisting color type*/ -} - -static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth) -{ - /*bits per pixel is amount of channels * bits per channel*/ - return getNumColorChannels(colortype) * bitdepth; -} - -/* ////////////////////////////////////////////////////////////////////////// */ - -void lodepng_color_mode_init(LodePNGColorMode* info) -{ - info->key_defined = 0; - info->key_r = info->key_g = info->key_b = 0; - info->colortype = LCT_RGBA; - info->bitdepth = 8; - info->palette = 0; - info->palettesize = 0; -} - -void lodepng_color_mode_cleanup(LodePNGColorMode* info) -{ - lodepng_palette_clear(info); -} - -unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source) -{ - size_t i; - lodepng_color_mode_cleanup(dest); - *dest = *source; - if(source->palette) - { - dest->palette = (unsigned char*)lodepng_malloc(1024); - if(!dest->palette && source->palettesize) return 83; /*alloc fail*/ - for(i = 0; i < source->palettesize * 4; i++) dest->palette[i] = source->palette[i]; - } - return 0; -} - -static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b) -{ - size_t i; - if(a->colortype != b->colortype) return 0; - if(a->bitdepth != b->bitdepth) return 0; - if(a->key_defined != b->key_defined) return 0; - if(a->key_defined) - { - if(a->key_r != b->key_r) return 0; - if(a->key_g != b->key_g) return 0; - if(a->key_b != b->key_b) return 0; - } - if(a->palettesize != b->palettesize) return 0; - for(i = 0; i < a->palettesize * 4; i++) - { - if(a->palette[i] != b->palette[i]) return 0; - } - return 1; -} - -void lodepng_palette_clear(LodePNGColorMode* info) -{ - if(info->palette) lodepng_free(info->palette); - info->palette = 0; - info->palettesize = 0; -} - -unsigned lodepng_palette_add(LodePNGColorMode* info, - unsigned char r, unsigned char g, unsigned char b, unsigned char a) -{ - unsigned char* data; - /*the same resize technique as C++ std::vectors is used, and here it's made so that for a palette with - the max of 256 colors, it'll have the exact alloc size*/ - if(!info->palette) /*allocate palette if empty*/ - { - /*room for 256 colors with 4 bytes each*/ - data = (unsigned char*)lodepng_realloc(info->palette, 1024); - if(!data) return 83; /*alloc fail*/ - else info->palette = data; - } - info->palette[4 * info->palettesize + 0] = r; - info->palette[4 * info->palettesize + 1] = g; - info->palette[4 * info->palettesize + 2] = b; - info->palette[4 * info->palettesize + 3] = a; - info->palettesize++; - return 0; -} - -unsigned lodepng_get_bpp(const LodePNGColorMode* info) -{ - /*calculate bits per pixel out of colortype and bitdepth*/ - return lodepng_get_bpp_lct(info->colortype, info->bitdepth); -} - -unsigned lodepng_get_channels(const LodePNGColorMode* info) -{ - return getNumColorChannels(info->colortype); -} - -unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info) -{ - return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA; -} - -unsigned lodepng_is_alpha_type(const LodePNGColorMode* info) -{ - return (info->colortype & 4) != 0; /*4 or 6*/ -} - -unsigned lodepng_is_palette_type(const LodePNGColorMode* info) -{ - return info->colortype == LCT_PALETTE; -} - -unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info) -{ - size_t i; - for(i = 0; i < info->palettesize; i++) - { - if(info->palette[i * 4 + 3] < 255) return 1; - } - return 0; -} - -unsigned lodepng_can_have_alpha(const LodePNGColorMode* info) -{ - return info->key_defined - || lodepng_is_alpha_type(info) - || lodepng_has_palette_alpha(info); -} - -size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color) -{ - return (w * h * lodepng_get_bpp(color) + 7) / 8; -} - -size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) -{ - return (w * h * lodepng_get_bpp_lct(colortype, bitdepth) + 7) / 8; -} - -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - -static void LodePNGUnknownChunks_init(LodePNGInfo* info) -{ - unsigned i; - for(i = 0; i < 3; i++) info->unknown_chunks_data[i] = 0; - for(i = 0; i < 3; i++) info->unknown_chunks_size[i] = 0; -} - -static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info) -{ - unsigned i; - for(i = 0; i < 3; i++) lodepng_free(info->unknown_chunks_data[i]); -} - -static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src) -{ - unsigned i; - - LodePNGUnknownChunks_cleanup(dest); - - for(i = 0; i < 3; i++) - { - size_t j; - dest->unknown_chunks_size[i] = src->unknown_chunks_size[i]; - dest->unknown_chunks_data[i] = (unsigned char*)lodepng_malloc(src->unknown_chunks_size[i]); - if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/ - for(j = 0; j < src->unknown_chunks_size[i]; j++) - { - dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j]; - } - } - - return 0; -} - -/******************************************************************************/ - -static void LodePNGText_init(LodePNGInfo* info) -{ - info->text_num = 0; - info->text_keys = NULL; - info->text_strings = NULL; -} - -static void LodePNGText_cleanup(LodePNGInfo* info) -{ - size_t i; - for(i = 0; i < info->text_num; i++) - { - string_cleanup(&info->text_keys[i]); - string_cleanup(&info->text_strings[i]); - } - lodepng_free(info->text_keys); - lodepng_free(info->text_strings); -} - -static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) -{ - size_t i = 0; - dest->text_keys = 0; - dest->text_strings = 0; - dest->text_num = 0; - for(i = 0; i < source->text_num; i++) - { - CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i])); - } - return 0; -} - -void lodepng_clear_text(LodePNGInfo* info) -{ - LodePNGText_cleanup(info); -} - -unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) -{ - char** new_keys = (char**)(lodepng_realloc(info->text_keys, sizeof(char*) * (info->text_num + 1))); - char** new_strings = (char**)(lodepng_realloc(info->text_strings, sizeof(char*) * (info->text_num + 1))); - if(!new_keys || !new_strings) - { - lodepng_free(new_keys); - lodepng_free(new_strings); - return 83; /*alloc fail*/ - } - - info->text_num++; - info->text_keys = new_keys; - info->text_strings = new_strings; - - string_init(&info->text_keys[info->text_num - 1]); - string_set(&info->text_keys[info->text_num - 1], key); - - string_init(&info->text_strings[info->text_num - 1]); - string_set(&info->text_strings[info->text_num - 1], str); - - return 0; -} - -/******************************************************************************/ - -static void LodePNGIText_init(LodePNGInfo* info) -{ - info->itext_num = 0; - info->itext_keys = NULL; - info->itext_langtags = NULL; - info->itext_transkeys = NULL; - info->itext_strings = NULL; -} - -static void LodePNGIText_cleanup(LodePNGInfo* info) -{ - size_t i; - for(i = 0; i < info->itext_num; i++) - { - string_cleanup(&info->itext_keys[i]); - string_cleanup(&info->itext_langtags[i]); - string_cleanup(&info->itext_transkeys[i]); - string_cleanup(&info->itext_strings[i]); - } - lodepng_free(info->itext_keys); - lodepng_free(info->itext_langtags); - lodepng_free(info->itext_transkeys); - lodepng_free(info->itext_strings); -} - -static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) -{ - size_t i = 0; - dest->itext_keys = 0; - dest->itext_langtags = 0; - dest->itext_transkeys = 0; - dest->itext_strings = 0; - dest->itext_num = 0; - for(i = 0; i < source->itext_num; i++) - { - CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i], - source->itext_transkeys[i], source->itext_strings[i])); - } - return 0; -} - -void lodepng_clear_itext(LodePNGInfo* info) -{ - LodePNGIText_cleanup(info); -} - -unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, - const char* transkey, const char* str) -{ - char** new_keys = (char**)(lodepng_realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1))); - char** new_langtags = (char**)(lodepng_realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1))); - char** new_transkeys = (char**)(lodepng_realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1))); - char** new_strings = (char**)(lodepng_realloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1))); - if(!new_keys || !new_langtags || !new_transkeys || !new_strings) - { - lodepng_free(new_keys); - lodepng_free(new_langtags); - lodepng_free(new_transkeys); - lodepng_free(new_strings); - return 83; /*alloc fail*/ - } - - info->itext_num++; - info->itext_keys = new_keys; - info->itext_langtags = new_langtags; - info->itext_transkeys = new_transkeys; - info->itext_strings = new_strings; - - string_init(&info->itext_keys[info->itext_num - 1]); - string_set(&info->itext_keys[info->itext_num - 1], key); - - string_init(&info->itext_langtags[info->itext_num - 1]); - string_set(&info->itext_langtags[info->itext_num - 1], langtag); - - string_init(&info->itext_transkeys[info->itext_num - 1]); - string_set(&info->itext_transkeys[info->itext_num - 1], transkey); - - string_init(&info->itext_strings[info->itext_num - 1]); - string_set(&info->itext_strings[info->itext_num - 1], str); - - return 0; -} -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - -void lodepng_info_init(LodePNGInfo* info) -{ - lodepng_color_mode_init(&info->color); - info->interlace_method = 0; - info->compression_method = 0; - info->filter_method = 0; -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - info->background_defined = 0; - info->background_r = info->background_g = info->background_b = 0; - - LodePNGText_init(info); - LodePNGIText_init(info); - - info->time_defined = 0; - info->phys_defined = 0; - - LodePNGUnknownChunks_init(info); -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ -} - -void lodepng_info_cleanup(LodePNGInfo* info) -{ - lodepng_color_mode_cleanup(&info->color); -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - LodePNGText_cleanup(info); - LodePNGIText_cleanup(info); - - LodePNGUnknownChunks_cleanup(info); -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ -} - -unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) -{ - lodepng_info_cleanup(dest); - *dest = *source; - lodepng_color_mode_init(&dest->color); - CERROR_TRY_RETURN(lodepng_color_mode_copy(&dest->color, &source->color)); - -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - CERROR_TRY_RETURN(LodePNGText_copy(dest, source)); - CERROR_TRY_RETURN(LodePNGIText_copy(dest, source)); - - LodePNGUnknownChunks_init(dest); - CERROR_TRY_RETURN(LodePNGUnknownChunks_copy(dest, source)); -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - return 0; -} - -void lodepng_info_swap(LodePNGInfo* a, LodePNGInfo* b) -{ - LodePNGInfo temp = *a; - *a = *b; - *b = temp; -} - -/* ////////////////////////////////////////////////////////////////////////// */ - -/*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/ -static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in) -{ - unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/ - /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/ - unsigned p = index & m; - in &= (1 << bits) - 1; /*filter out any other bits of the input value*/ - in = in << (bits * (m - p)); - if(p == 0) out[index * bits / 8] = in; - else out[index * bits / 8] |= in; -} - -typedef struct ColorTree ColorTree; - -/* -One node of a color tree -This is the data structure used to count the number of unique colors and to get a palette -index for a color. It's like an octree, but because the alpha channel is used too, each -node has 16 instead of 8 children. -*/ -struct ColorTree -{ - ColorTree* children[16]; /*up to 16 pointers to ColorTree of next level*/ - int index; /*the payload. Only has a meaningful value if this is in the last level*/ -}; - -static void color_tree_init(ColorTree* tree) -{ - int i; - for(i = 0; i < 16; i++) tree->children[i] = 0; - tree->index = -1; -} - -static void color_tree_cleanup(ColorTree* tree) -{ - int i; - for(i = 0; i < 16; i++) - { - if(tree->children[i]) - { - color_tree_cleanup(tree->children[i]); - lodepng_free(tree->children[i]); - } - } -} - -/*returns -1 if color not present, its index otherwise*/ -static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) -{ - int bit = 0; - for(bit = 0; bit < 8; bit++) - { - int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); - if(!tree->children[i]) return -1; - else tree = tree->children[i]; - } - return tree ? tree->index : -1; -} - -#ifdef LODEPNG_COMPILE_ENCODER -static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) -{ - return color_tree_get(tree, r, g, b, a) >= 0; -} -#endif /*LODEPNG_COMPILE_ENCODER*/ - -/*color is not allowed to already exist. -Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist")*/ -static void color_tree_add(ColorTree* tree, - unsigned char r, unsigned char g, unsigned char b, unsigned char a, int index) -{ - int bit; - for(bit = 0; bit < 8; bit++) - { - int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); - if(!tree->children[i]) - { - tree->children[i] = (ColorTree*)lodepng_malloc(sizeof(ColorTree)); - color_tree_init(tree->children[i]); - } - tree = tree->children[i]; - } - tree->index = index; -} - -/*put a pixel, given its RGBA color, into image of any color type*/ -static unsigned rgba8ToPixel(unsigned char* out, size_t i, - const LodePNGColorMode* mode, ColorTree* tree /*for palette*/, - unsigned char r, unsigned char g, unsigned char b, unsigned char a) -{ - if(mode->colortype == LCT_GREY) - { - unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; - if(mode->bitdepth == 8) out[i] = grey; - else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = grey; - else - { - /*take the most significant bits of grey*/ - grey = (grey >> (8 - mode->bitdepth)) & ((1 << mode->bitdepth) - 1); - addColorBits(out, i, mode->bitdepth, grey); - } - } - else if(mode->colortype == LCT_RGB) - { - if(mode->bitdepth == 8) - { - out[i * 3 + 0] = r; - out[i * 3 + 1] = g; - out[i * 3 + 2] = b; - } - else - { - out[i * 6 + 0] = out[i * 6 + 1] = r; - out[i * 6 + 2] = out[i * 6 + 3] = g; - out[i * 6 + 4] = out[i * 6 + 5] = b; - } - } - else if(mode->colortype == LCT_PALETTE) - { - int index = color_tree_get(tree, r, g, b, a); - if(index < 0) return 82; /*color not in palette*/ - if(mode->bitdepth == 8) out[i] = index; - else addColorBits(out, i, mode->bitdepth, index); - } - else if(mode->colortype == LCT_GREY_ALPHA) - { - unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; - if(mode->bitdepth == 8) - { - out[i * 2 + 0] = grey; - out[i * 2 + 1] = a; - } - else if(mode->bitdepth == 16) - { - out[i * 4 + 0] = out[i * 4 + 1] = grey; - out[i * 4 + 2] = out[i * 4 + 3] = a; - } - } - else if(mode->colortype == LCT_RGBA) - { - if(mode->bitdepth == 8) - { - out[i * 4 + 0] = r; - out[i * 4 + 1] = g; - out[i * 4 + 2] = b; - out[i * 4 + 3] = a; - } - else - { - out[i * 8 + 0] = out[i * 8 + 1] = r; - out[i * 8 + 2] = out[i * 8 + 3] = g; - out[i * 8 + 4] = out[i * 8 + 5] = b; - out[i * 8 + 6] = out[i * 8 + 7] = a; - } - } - - return 0; /*no error*/ -} - -/*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/ -static unsigned rgba16ToPixel(unsigned char* out, size_t i, - const LodePNGColorMode* mode, - unsigned short r, unsigned short g, unsigned short b, unsigned short a) -{ - if(mode->bitdepth != 16) return 85; /*must be 16 for this function*/ - if(mode->colortype == LCT_GREY) - { - unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; - out[i * 2 + 0] = (grey >> 8) & 255; - out[i * 2 + 1] = grey & 255; - } - else if(mode->colortype == LCT_RGB) - { - out[i * 6 + 0] = (r >> 8) & 255; - out[i * 6 + 1] = r & 255; - out[i * 6 + 2] = (g >> 8) & 255; - out[i * 6 + 3] = g & 255; - out[i * 6 + 4] = (b >> 8) & 255; - out[i * 6 + 5] = b & 255; - } - else if(mode->colortype == LCT_GREY_ALPHA) - { - unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; - out[i * 4 + 0] = (grey >> 8) & 255; - out[i * 4 + 1] = grey & 255; - out[i * 4 + 2] = (a >> 8) & 255; - out[i * 4 + 3] = a & 255; - } - else if(mode->colortype == LCT_RGBA) - { - out[i * 8 + 0] = (r >> 8) & 255; - out[i * 8 + 1] = r & 255; - out[i * 8 + 2] = (g >> 8) & 255; - out[i * 8 + 3] = g & 255; - out[i * 8 + 4] = (b >> 8) & 255; - out[i * 8 + 5] = b & 255; - out[i * 8 + 6] = (a >> 8) & 255; - out[i * 8 + 7] = a & 255; - } - - return 0; /*no error*/ -} - -/*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/ -static unsigned getPixelColorRGBA8(unsigned char* r, unsigned char* g, - unsigned char* b, unsigned char* a, - const unsigned char* in, size_t i, - const LodePNGColorMode* mode, - unsigned fix_png) -{ - if(mode->colortype == LCT_GREY) - { - if(mode->bitdepth == 8) - { - *r = *g = *b = in[i]; - if(mode->key_defined && *r == mode->key_r) *a = 0; - else *a = 255; - } - else if(mode->bitdepth == 16) - { - *r = *g = *b = in[i * 2 + 0]; - if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; - else *a = 255; - } - else - { - unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ - size_t j = i * mode->bitdepth; - unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); - *r = *g = *b = (value * 255) / highest; - if(mode->key_defined && value == mode->key_r) *a = 0; - else *a = 255; - } - } - else if(mode->colortype == LCT_RGB) - { - if(mode->bitdepth == 8) - { - *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2]; - if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0; - else *a = 255; - } - else - { - *r = in[i * 6 + 0]; - *g = in[i * 6 + 2]; - *b = in[i * 6 + 4]; - if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r - && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g - && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; - else *a = 255; - } - } - else if(mode->colortype == LCT_PALETTE) - { - unsigned index; - if(mode->bitdepth == 8) index = in[i]; - else - { - size_t j = i * mode->bitdepth; - index = readBitsFromReversedStream(&j, in, mode->bitdepth); - } - - if(index >= mode->palettesize) - { - /*This is an error according to the PNG spec, but fix_png can ignore it*/ - if(!fix_png) return (mode->bitdepth == 8 ? 46 : 47); /*index out of palette*/ - *r = *g = *b = 0; - *a = 255; - } - else - { - *r = mode->palette[index * 4 + 0]; - *g = mode->palette[index * 4 + 1]; - *b = mode->palette[index * 4 + 2]; - *a = mode->palette[index * 4 + 3]; - } - } - else if(mode->colortype == LCT_GREY_ALPHA) - { - if(mode->bitdepth == 8) - { - *r = *g = *b = in[i * 2 + 0]; - *a = in[i * 2 + 1]; - } - else - { - *r = *g = *b = in[i * 4 + 0]; - *a = in[i * 4 + 2]; - } - } - else if(mode->colortype == LCT_RGBA) - { - if(mode->bitdepth == 8) - { - *r = in[i * 4 + 0]; - *g = in[i * 4 + 1]; - *b = in[i * 4 + 2]; - *a = in[i * 4 + 3]; - } - else - { - *r = in[i * 8 + 0]; - *g = in[i * 8 + 2]; - *b = in[i * 8 + 4]; - *a = in[i * 8 + 6]; - } - } - - return 0; /*no error*/ -} - -/*Similar to getPixelColorRGBA8, but with all the for loops inside of the color -mode test cases, optimized to convert the colors much faster, when converting -to RGBA or RGB with 8 bit per cannel. buffer must be RGBA or RGB output with -enough memory, if has_alpha is true the output is RGBA. mode has the color mode -of the input buffer.*/ -static unsigned getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, - unsigned has_alpha, const unsigned char* in, - const LodePNGColorMode* mode, - unsigned fix_png) -{ - unsigned num_channels = has_alpha ? 4 : 3; - size_t i; - if(mode->colortype == LCT_GREY) - { - if(mode->bitdepth == 8) - { - for(i = 0; i < numpixels; i++, buffer += num_channels) - { - buffer[0] = buffer[1] = buffer[2] = in[i]; - if(has_alpha) buffer[3] = mode->key_defined && in[i] == mode->key_r ? 0 : 255; - } - } - else if(mode->bitdepth == 16) - { - for(i = 0; i < numpixels; i++, buffer += num_channels) - { - buffer[0] = buffer[1] = buffer[2] = in[i * 2]; - if(has_alpha) buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255; - } - } - else - { - unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ - size_t j = 0; - for(i = 0; i < numpixels; i++, buffer += num_channels) - { - unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); - buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; - if(has_alpha) buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255; - } - } - } - else if(mode->colortype == LCT_RGB) - { - if(mode->bitdepth == 8) - { - for(i = 0; i < numpixels; i++, buffer += num_channels) - { - buffer[0] = in[i * 3 + 0]; - buffer[1] = in[i * 3 + 1]; - buffer[2] = in[i * 3 + 2]; - if(has_alpha) buffer[3] = mode->key_defined && buffer[0] == mode->key_r - && buffer[1]== mode->key_g && buffer[2] == mode->key_b ? 0 : 255; - } - } - else - { - for(i = 0; i < numpixels; i++, buffer += num_channels) - { - buffer[0] = in[i * 6 + 0]; - buffer[1] = in[i * 6 + 2]; - buffer[2] = in[i * 6 + 4]; - if(has_alpha) buffer[3] = mode->key_defined - && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r - && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g - && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255; - } - } - } - else if(mode->colortype == LCT_PALETTE) - { - unsigned index; - size_t j = 0; - for(i = 0; i < numpixels; i++, buffer += num_channels) - { - if(mode->bitdepth == 8) index = in[i]; - else index = readBitsFromReversedStream(&j, in, mode->bitdepth); - - if(index >= mode->palettesize) - { - /*This is an error according to the PNG spec, but fix_png can ignore it*/ - if(!fix_png) return (mode->bitdepth == 8 ? 46 : 47); /*index out of palette*/ - buffer[0] = buffer[1] = buffer[2] = 0; - if(has_alpha) buffer[3] = 255; - } - else - { - buffer[0] = mode->palette[index * 4 + 0]; - buffer[1] = mode->palette[index * 4 + 1]; - buffer[2] = mode->palette[index * 4 + 2]; - if(has_alpha) buffer[3] = mode->palette[index * 4 + 3]; - } - } - } - else if(mode->colortype == LCT_GREY_ALPHA) - { - if(mode->bitdepth == 8) - { - for(i = 0; i < numpixels; i++, buffer += num_channels) - { - buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; - if(has_alpha) buffer[3] = in[i * 2 + 1]; - } - } - else - { - for(i = 0; i < numpixels; i++, buffer += num_channels) - { - buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; - if(has_alpha) buffer[3] = in[i * 4 + 2]; - } - } - } - else if(mode->colortype == LCT_RGBA) - { - if(mode->bitdepth == 8) - { - for(i = 0; i < numpixels; i++, buffer += num_channels) - { - buffer[0] = in[i * 4 + 0]; - buffer[1] = in[i * 4 + 1]; - buffer[2] = in[i * 4 + 2]; - if(has_alpha) buffer[3] = in[i * 4 + 3]; - } - } - else - { - for(i = 0; i < numpixels; i++, buffer += num_channels) - { - buffer[0] = in[i * 8 + 0]; - buffer[1] = in[i * 8 + 2]; - buffer[2] = in[i * 8 + 4]; - if(has_alpha) buffer[3] = in[i * 8 + 6]; - } - } - } - - return 0; /*no error*/ -} - -/*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with -given color type, but the given color type must be 16-bit itself.*/ -static unsigned getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a, - const unsigned char* in, size_t i, const LodePNGColorMode* mode) -{ - if(mode->bitdepth != 16) return 85; /*error: this function only supports 16-bit input*/ - - if(mode->colortype == LCT_GREY) - { - *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1]; - if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; - else *a = 65535; - } - else if(mode->colortype == LCT_RGB) - { - *r = 256 * in[i * 6 + 0] + in[i * 6 + 1]; - *g = 256 * in[i * 6 + 2] + in[i * 6 + 3]; - *b = 256 * in[i * 6 + 4] + in[i * 6 + 5]; - if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r - && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g - && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; - else *a = 65535; - } - else if(mode->colortype == LCT_GREY_ALPHA) - { - *r = *g = *b = 256 * in[i * 4 + 0] + in[i * 4 + 1]; - *a = 256 * in[i * 4 + 2] + in[i * 4 + 3]; - } - else if(mode->colortype == LCT_RGBA) - { - *r = 256 * in[i * 8 + 0] + in[i * 8 + 1]; - *g = 256 * in[i * 8 + 2] + in[i * 8 + 3]; - *b = 256 * in[i * 8 + 4] + in[i * 8 + 5]; - *a = 256 * in[i * 8 + 6] + in[i * 8 + 7]; - } - else return 85; /*error: this function only supports 16-bit input, not palettes*/ - - return 0; /*no error*/ -} - -/* -converts from any color type to 24-bit or 32-bit (later maybe more supported). return value = LodePNG error code -the out buffer must have (w * h * bpp + 7) / 8 bytes, where bpp is the bits per pixel of the output color type -(lodepng_get_bpp) for < 8 bpp images, there may _not_ be padding bits at the end of scanlines. -*/ -unsigned lodepng_convert(unsigned char* out, const unsigned char* in, - LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, - unsigned w, unsigned h, unsigned fix_png) -{ - unsigned error = 0; - size_t i; - ColorTree tree; - size_t numpixels = w * h; - - if(lodepng_color_mode_equal(mode_out, mode_in)) - { - size_t numbytes = lodepng_get_raw_size(w, h, mode_in); - for(i = 0; i < numbytes; i++) out[i] = in[i]; - return error; - } - - if(mode_out->colortype == LCT_PALETTE) - { - size_t palsize = 1 << mode_out->bitdepth; - if(mode_out->palettesize < palsize) palsize = mode_out->palettesize; - color_tree_init(&tree); - for(i = 0; i < palsize; i++) - { - unsigned char* p = &mode_out->palette[i * 4]; - color_tree_add(&tree, p[0], p[1], p[2], p[3], i); - } - } - - if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16) - { - for(i = 0; i < numpixels; i++) - { - unsigned short r = 0, g = 0, b = 0, a = 0; - error = getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); - if(error) break; - error = rgba16ToPixel(out, i, mode_out, r, g, b, a); - if(error) break; - } - } - else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) - { - error = getPixelColorsRGBA8(out, numpixels, 1, in, mode_in, fix_png); - } - else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) - { - error = getPixelColorsRGBA8(out, numpixels, 0, in, mode_in, fix_png); - } - else - { - unsigned char r = 0, g = 0, b = 0, a = 0; - for(i = 0; i < numpixels; i++) - { - error = getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in, fix_png); - if(error) break; - error = rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a); - if(error) break; - } - } - - if(mode_out->colortype == LCT_PALETTE) - { - color_tree_cleanup(&tree); - } - - return error; -} - -#ifdef LODEPNG_COMPILE_ENCODER - -typedef struct ColorProfile -{ - unsigned char sixteenbit; /*needs more than 8 bits per channel*/ - unsigned char sixteenbit_done; - - - unsigned char colored; /*not greyscale*/ - unsigned char colored_done; - - unsigned char key; /*a color key is required, or more*/ - unsigned short key_r; /*these values are always in 16-bit bitdepth in the profile*/ - unsigned short key_g; - unsigned short key_b; - unsigned char alpha; /*alpha channel, or alpha palette, required*/ - unsigned char alpha_done; - - unsigned numcolors; - ColorTree tree; /*for listing the counted colors, up to 256*/ - unsigned char* palette; /*size 1024. Remember up to the first 256 RGBA colors*/ - unsigned maxnumcolors; /*if more than that amount counted*/ - unsigned char numcolors_done; - - unsigned greybits; /*amount of bits required for greyscale (1, 2, 4, 8). Does not take 16 bit into account.*/ - unsigned char greybits_done; - -} ColorProfile; - -static void color_profile_init(ColorProfile* profile, const LodePNGColorMode* mode) -{ - profile->sixteenbit = 0; - profile->sixteenbit_done = mode->bitdepth == 16 ? 0 : 1; - - profile->colored = 0; - profile->colored_done = lodepng_is_greyscale_type(mode) ? 1 : 0; - - profile->key = 0; - profile->alpha = 0; - profile->alpha_done = lodepng_can_have_alpha(mode) ? 0 : 1; - - profile->numcolors = 0; - color_tree_init(&profile->tree); - profile->palette = (unsigned char*)lodepng_malloc(1024); - profile->maxnumcolors = 257; - if(lodepng_get_bpp(mode) <= 8) - { - int bpp = lodepng_get_bpp(mode); - profile->maxnumcolors = bpp == 1 ? 2 : (bpp == 2 ? 4 : (bpp == 4 ? 16 : 256)); - } - profile->numcolors_done = 0; - - profile->greybits = 1; - profile->greybits_done = lodepng_get_bpp(mode) == 1 ? 1 : 0; -} - -static void color_profile_cleanup(ColorProfile* profile) -{ - color_tree_cleanup(&profile->tree); - lodepng_free(profile->palette); -} - -/*function used for debug purposes with C++*/ -/*void printColorProfile(ColorProfile* p) -{ - std::cout << "sixteenbit: " << (int)p->sixteenbit << std::endl; - std::cout << "sixteenbit_done: " << (int)p->sixteenbit_done << std::endl; - std::cout << "colored: " << (int)p->colored << std::endl; - std::cout << "colored_done: " << (int)p->colored_done << std::endl; - std::cout << "key: " << (int)p->key << std::endl; - std::cout << "key_r: " << (int)p->key_r << std::endl; - std::cout << "key_g: " << (int)p->key_g << std::endl; - std::cout << "key_b: " << (int)p->key_b << std::endl; - std::cout << "alpha: " << (int)p->alpha << std::endl; - std::cout << "alpha_done: " << (int)p->alpha_done << std::endl; - std::cout << "numcolors: " << (int)p->numcolors << std::endl; - std::cout << "maxnumcolors: " << (int)p->maxnumcolors << std::endl; - std::cout << "numcolors_done: " << (int)p->numcolors_done << std::endl; - std::cout << "greybits: " << (int)p->greybits << std::endl; - std::cout << "greybits_done: " << (int)p->greybits_done << std::endl; -}*/ - -/*Returns how many bits needed to represent given value (max 8 bit)*/ -unsigned getValueRequiredBits(unsigned short value) -{ - if(value == 0 || value == 255) return 1; - /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/ - if(value % 17 == 0) return value % 85 == 0 ? 2 : 4; - return 8; -} - -/*profile must already have been inited with mode. -It's ok to set some parameters of profile to done already.*/ -static unsigned get_color_profile(ColorProfile* profile, - const unsigned char* in, - size_t numpixels /*must be full image size, for certain filesize based choices*/, - const LodePNGColorMode* mode, - unsigned fix_png) -{ - unsigned error = 0; - size_t i; - - if(mode->bitdepth == 16) - { - for(i = 0; i < numpixels; i++) - { - unsigned short r, g, b, a; - error = getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); - if(error) break; - - /*a color is considered good for 8-bit if the first byte and the second byte are equal, - (so if it's divisible through 257), NOT necessarily if the second byte is 0*/ - if(!profile->sixteenbit_done - && (((r & 255) != ((r >> 8) & 255)) - || ((g & 255) != ((g >> 8) & 255)) - || ((b & 255) != ((b >> 8) & 255)))) - { - profile->sixteenbit = 1; - profile->sixteenbit_done = 1; - profile->greybits_done = 1; /*greybits is not applicable anymore at 16-bit*/ - profile->numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/ - } - - if(!profile->colored_done && (r != g || r != b)) - { - profile->colored = 1; - profile->colored_done = 1; - profile->greybits_done = 1; /*greybits is not applicable anymore*/ - } - - if(!profile->alpha_done && a != 65535) - { - /*only use color key if numpixels large enough to justify tRNS chunk size*/ - if(a == 0 && numpixels > 16 && !(profile->key && (r != profile->key_r || g != profile->key_g || b != profile->key_b))) - { - if(!profile->alpha && !profile->key) - { - profile->key = 1; - profile->key_r = r; - profile->key_g = g; - profile->key_b = b; - } - } - else - { - profile->alpha = 1; - profile->alpha_done = 1; - profile->greybits_done = 1; /*greybits is not applicable anymore*/ - } - } - - /* Color key cannot be used if an opaque pixel also has that RGB color. */ - if(!profile->alpha_done && a == 65535 && profile->key - && r == profile->key_r && g == profile->key_g && b == profile->key_b) - { - profile->alpha = 1; - profile->alpha_done = 1; - profile->greybits_done = 1; /*greybits is not applicable anymore*/ - } - - if(!profile->greybits_done) - { - /*assuming 8-bit r, this test does not care about 16-bit*/ - unsigned bits = getValueRequiredBits(r); - if(bits > profile->greybits) profile->greybits = bits; - if(profile->greybits >= 8) profile->greybits_done = 1; - } - - if(!profile->numcolors_done) - { - /*assuming 8-bit rgba, this test does not care about 16-bit*/ - if(!color_tree_has(&profile->tree, (unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a)) - { - color_tree_add(&profile->tree, (unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a, - profile->numcolors); - if(profile->numcolors < 256) - { - unsigned char* p = profile->palette; - unsigned i = profile->numcolors; - p[i * 4 + 0] = (unsigned char)r; - p[i * 4 + 1] = (unsigned char)g; - p[i * 4 + 2] = (unsigned char)b; - p[i * 4 + 3] = (unsigned char)a; - } - profile->numcolors++; - if(profile->numcolors >= profile->maxnumcolors) profile->numcolors_done = 1; - } - } - - if(profile->alpha_done && profile->numcolors_done - && profile->colored_done && profile->sixteenbit_done && profile->greybits_done) - { - break; - } - }; - } - else /* < 16-bit */ - { - for(i = 0; i < numpixels; i++) - { - unsigned char r = 0, g = 0, b = 0, a = 0; - error = getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode, fix_png); - if(error) break; - - if(!profile->colored_done && (r != g || r != b)) - { - profile->colored = 1; - profile->colored_done = 1; - profile->greybits_done = 1; /*greybits is not applicable anymore*/ - } - - if(!profile->alpha_done && a != 255) - { - if(a == 0 && !(profile->key && (r != profile->key_r || g != profile->key_g || b != profile->key_b))) - { - if(!profile->key) - { - profile->key = 1; - profile->key_r = r; - profile->key_g = g; - profile->key_b = b; - } - } - else - { - profile->alpha = 1; - profile->alpha_done = 1; - profile->greybits_done = 1; /*greybits is not applicable anymore*/ - } - } - - /* Color key cannot be used if an opaque pixel also has that RGB color. */ - if(!profile->alpha_done && a == 255 && profile->key - && r == profile->key_r && g == profile->key_g && b == profile->key_b) - { - profile->alpha = 1; - profile->alpha_done = 1; - profile->greybits_done = 1; /*greybits is not applicable anymore*/ - } - - if(!profile->greybits_done) - { - unsigned bits = getValueRequiredBits(r); - if(bits > profile->greybits) profile->greybits = bits; - if(profile->greybits >= 8) profile->greybits_done = 1; - } - - if(!profile->numcolors_done) - { - if(!color_tree_has(&profile->tree, r, g, b, a)) - { - - color_tree_add(&profile->tree, r, g, b, a, profile->numcolors); - if(profile->numcolors < 256) - { - unsigned char* p = profile->palette; - unsigned i = profile->numcolors; - p[i * 4 + 0] = r; - p[i * 4 + 1] = g; - p[i * 4 + 2] = b; - p[i * 4 + 3] = a; - } - profile->numcolors++; - if(profile->numcolors >= profile->maxnumcolors) profile->numcolors_done = 1; - } - } - - if(profile->alpha_done && profile->numcolors_done && profile->colored_done && profile->greybits_done) - { - break; - } - }; - } - - /*make the profile's key always 16-bit for consistency*/ - if(mode->bitdepth < 16) - { - /*repeat each byte twice*/ - profile->key_r *= 257; - profile->key_g *= 257; - profile->key_b *= 257; - } - - return error; -} - -static void setColorKeyFrom16bit(LodePNGColorMode* mode_out, unsigned r, unsigned g, unsigned b, unsigned bitdepth) -{ - unsigned mask = (1 << bitdepth) - 1; - mode_out->key_defined = 1; - mode_out->key_r = r & mask; - mode_out->key_g = g & mask; - mode_out->key_b = b & mask; -} - -/*updates values of mode with a potentially smaller color model. mode_out should -contain the user chosen color model, but will be overwritten with the new chosen one.*/ -unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, - const unsigned char* image, unsigned w, unsigned h, - const LodePNGColorMode* mode_in, - LodePNGAutoConvert auto_convert) -{ - ColorProfile profile; - unsigned error = 0; - int no_nibbles = auto_convert == LAC_AUTO_NO_NIBBLES || auto_convert == LAC_AUTO_NO_NIBBLES_NO_PALETTE; - int no_palette = auto_convert == LAC_AUTO_NO_PALETTE || auto_convert == LAC_AUTO_NO_NIBBLES_NO_PALETTE; - - if(auto_convert == LAC_ALPHA) - { - if(mode_out->colortype != LCT_RGBA && mode_out->colortype != LCT_GREY_ALPHA) return 0; - } - - color_profile_init(&profile, mode_in); - if(auto_convert == LAC_ALPHA) - { - profile.colored_done = 1; - profile.greybits_done = 1; - profile.numcolors_done = 1; - profile.sixteenbit_done = 1; - } - error = get_color_profile(&profile, image, w * h, mode_in, 0 /*fix_png*/); - if(!error && auto_convert == LAC_ALPHA) - { - if(!profile.alpha) - { - mode_out->colortype = (mode_out->colortype == LCT_RGBA ? LCT_RGB : LCT_GREY); - if(profile.key) setColorKeyFrom16bit(mode_out, profile.key_r, profile.key_g, profile.key_b, mode_out->bitdepth); - } - } - else if(!error && auto_convert != LAC_ALPHA) - { - mode_out->key_defined = 0; - - if(profile.sixteenbit) - { - mode_out->bitdepth = 16; - if(profile.alpha) - { - mode_out->colortype = profile.colored ? LCT_RGBA : LCT_GREY_ALPHA; - } - else - { - mode_out->colortype = profile.colored ? LCT_RGB : LCT_GREY; - if(profile.key) setColorKeyFrom16bit(mode_out, profile.key_r, profile.key_g, profile.key_b, mode_out->bitdepth); - } - } - else /*less than 16 bits per channel*/ - { - /*don't add palette overhead if image hasn't got a lot of pixels*/ - unsigned n = profile.numcolors; - int palette_ok = !no_palette && n <= 256 && (n * 2 < w * h); - unsigned palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8)); - int grey_ok = !profile.colored && !profile.alpha; /*grey without alpha, with potentially low bits*/ - if(palette_ok || grey_ok) - { - if(!palette_ok || (grey_ok && profile.greybits <= palettebits)) - { - unsigned grey = profile.key_r; - mode_out->colortype = LCT_GREY; - mode_out->bitdepth = profile.greybits; - if(profile.key) setColorKeyFrom16bit(mode_out, grey, grey, grey, mode_out->bitdepth); - } - else - { - /*fill in the palette*/ - unsigned i; - unsigned char* p = profile.palette; - /*remove potential earlier palette*/ - lodepng_palette_clear(mode_out); - for(i = 0; i < profile.numcolors; i++) - { - error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]); - if(error) break; - } - - mode_out->colortype = LCT_PALETTE; - mode_out->bitdepth = palettebits; - } - } - else /*8-bit per channel*/ - { - mode_out->bitdepth = 8; - if(profile.alpha) - { - mode_out->colortype = profile.colored ? LCT_RGBA : LCT_GREY_ALPHA; - } - else - { - mode_out->colortype = profile.colored ? LCT_RGB : LCT_GREY /*LCT_GREY normally won't occur, already done earlier*/; - if(profile.key) setColorKeyFrom16bit(mode_out, profile.key_r, profile.key_g, profile.key_b, mode_out->bitdepth); - } - } - } - } - - color_profile_cleanup(&profile); - - if(mode_out->colortype == LCT_PALETTE && mode_in->palettesize == mode_out->palettesize) - { - /*In this case keep the palette order of the input, so that the user can choose an optimal one*/ - size_t i; - for(i = 0; i < mode_in->palettesize * 4; i++) - { - mode_out->palette[i] = mode_in->palette[i]; - } - } - - if(no_nibbles && mode_out->bitdepth < 8) - { - /*palette can keep its small amount of colors, as long as no indices use it*/ - mode_out->bitdepth = 8; - } - - return error; -} - -#endif /* #ifdef LODEPNG_COMPILE_ENCODER */ - -/* -Paeth predicter, used by PNG filter type 4 -The parameters are of type short, but should come from unsigned chars, the shorts -are only needed to make the paeth calculation correct. -*/ -static unsigned char paethPredictor(short a, short b, short c) -{ - short pa = abs(b - c); - short pb = abs(a - c); - short pc = abs(a + b - c - c); - - if(pc < pa && pc < pb) return (unsigned char)c; - else if(pb < pa) return (unsigned char)b; - else return (unsigned char)a; -} - -/*shared values used by multiple Adam7 related functions*/ - -static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/ -static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/ -static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/ -static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/ - -/* -Outputs various dimensions and positions in the image related to the Adam7 reduced images. -passw: output containing the width of the 7 passes -passh: output containing the height of the 7 passes -filter_passstart: output containing the index of the start and end of each - reduced image with filter bytes -padded_passstart output containing the index of the start and end of each - reduced image when without filter bytes but with padded scanlines -passstart: output containing the index of the start and end of each reduced - image without padding between scanlines, but still padding between the images -w, h: width and height of non-interlaced image -bpp: bits per pixel -"padded" is only relevant if bpp is less than 8 and a scanline or image does not - end at a full byte -*/ -static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], - size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp) -{ - /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/ - unsigned i; - - /*calculate width and height in pixels of each pass*/ - for(i = 0; i < 7; i++) - { - passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i]; - passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i]; - if(passw[i] == 0) passh[i] = 0; - if(passh[i] == 0) passw[i] = 0; - } - - filter_passstart[0] = padded_passstart[0] = passstart[0] = 0; - for(i = 0; i < 7; i++) - { - /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/ - filter_passstart[i + 1] = filter_passstart[i] - + ((passw[i] && passh[i]) ? passh[i] * (1 + (passw[i] * bpp + 7) / 8) : 0); - /*bits padded if needed to fill full byte at end of each scanline*/ - padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7) / 8); - /*only padded at end of reduced image*/ - passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8; - } -} - -#ifdef LODEPNG_COMPILE_DECODER - -/* ////////////////////////////////////////////////////////////////////////// */ -/* / PNG Decoder / */ -/* ////////////////////////////////////////////////////////////////////////// */ - -/*read the information from the header and store it in the LodePNGInfo. return value is error*/ -unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, - const unsigned char* in, size_t insize) -{ - LodePNGInfo* info = &state->info_png; - if(insize == 0 || in == 0) - { - CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/ - } - if(insize < 29) - { - CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/ - } - - /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/ - lodepng_info_cleanup(info); - lodepng_info_init(info); - - if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 - || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) - { - CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/ - } - if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') - { - CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/ - } - - /*read the values given in the header*/ - *w = lodepng_read32bitInt(&in[16]); - *h = lodepng_read32bitInt(&in[20]); - info->color.bitdepth = in[24]; - info->color.colortype = (LodePNGColorType)in[25]; - info->compression_method = in[26]; - info->filter_method = in[27]; - info->interlace_method = in[28]; - - if(!state->decoder.ignore_crc) - { - unsigned CRC = lodepng_read32bitInt(&in[29]); - unsigned checksum = lodepng_crc32(&in[12], 17); - if(CRC != checksum) - { - CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/ - } - } - - /*error: only compression method 0 is allowed in the specification*/ - if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32); - /*error: only filter method 0 is allowed in the specification*/ - if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33); - /*error: only interlace methods 0 and 1 exist in the specification*/ - if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34); - - state->error = checkColorValidity(info->color.colortype, info->color.bitdepth); - return state->error; -} - -static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, - size_t bytewidth, unsigned char filterType, size_t length) -{ - /* - For PNG filter method 0 - unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, - the filter works byte per byte (bytewidth = 1) - precon is the previous unfiltered scanline, recon the result, scanline the current one - the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead - recon and scanline MAY be the same memory address! precon must be disjoint. - */ - - size_t i; - switch(filterType) - { - case 0: - for(i = 0; i < length; i++) recon[i] = scanline[i]; - break; - case 1: - for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; - for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth]; - break; - case 2: - if(precon) - { - for(i = 0; i < length; i++) recon[i] = scanline[i] + precon[i]; - } - else - { - for(i = 0; i < length; i++) recon[i] = scanline[i]; - } - break; - case 3: - if(precon) - { - for(i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2; - for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2); - } - else - { - for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; - for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2; - } - break; - case 4: - if(precon) - { - for(i = 0; i < bytewidth; i++) - { - recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ - } - for(i = bytewidth; i < length; i++) - { - recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); - } - } - else - { - for(i = 0; i < bytewidth; i++) - { - recon[i] = scanline[i]; - } - for(i = bytewidth; i < length; i++) - { - /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/ - recon[i] = (scanline[i] + recon[i - bytewidth]); - } - } - break; - default: return 36; /*error: unexisting filter type given*/ - } - return 0; -} - -static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) -{ - /* - For PNG filter method 0 - this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times) - out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline - w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel - in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes) - */ - - unsigned y; - unsigned char* prevline = 0; - - /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ - size_t bytewidth = (bpp + 7) / 8; - size_t linebytes = (w * bpp + 7) / 8; - - for(y = 0; y < h; y++) - { - size_t outindex = linebytes * y; - size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ - unsigned char filterType = in[inindex]; - - CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes)); - - prevline = &out[outindex]; - } - - return 0; -} - -/* -in: Adam7 interlaced image, with no padding bits between scanlines, but between - reduced images so that each reduced image starts at a byte. -out: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h -bpp: bits per pixel -out has the following size in bits: w * h * bpp. -in is possibly bigger due to padding bits between reduced images. -out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation -(because that's likely a little bit faster) -NOTE: comments about padding bits are only relevant if bpp < 8 -*/ -static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) -{ - unsigned passw[7], passh[7]; - size_t filter_passstart[8], padded_passstart[8], passstart[8]; - unsigned i; - - Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); - - if(bpp >= 8) - { - for(i = 0; i < 7; i++) - { - unsigned x, y, b; - size_t bytewidth = bpp / 8; - for(y = 0; y < passh[i]; y++) - for(x = 0; x < passw[i]; x++) - { - size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; - size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; - for(b = 0; b < bytewidth; b++) - { - out[pixeloutstart + b] = in[pixelinstart + b]; - } - } - } - } - else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ - { - for(i = 0; i < 7; i++) - { - unsigned x, y, b; - unsigned ilinebits = bpp * passw[i]; - unsigned olinebits = bpp * w; - size_t obp, ibp; /*bit pointers (for out and in buffer)*/ - for(y = 0; y < passh[i]; y++) - for(x = 0; x < passw[i]; x++) - { - ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); - obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; - for(b = 0; b < bpp; b++) - { - unsigned char bit = readBitFromReversedStream(&ibp, in); - /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/ - setBitOfReversedStream0(&obp, out, bit); - } - } - } - } -} - -static void removePaddingBits(unsigned char* out, const unsigned char* in, - size_t olinebits, size_t ilinebits, unsigned h) -{ - /* - After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need - to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers - for the Adam7 code, the color convert code and the output to the user. - in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must - have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits - also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7 - only useful if (ilinebits - olinebits) is a value in the range 1..7 - */ - unsigned y; - size_t diff = ilinebits - olinebits; - size_t ibp = 0, obp = 0; /*input and output bit pointers*/ - for(y = 0; y < h; y++) - { - size_t x; - for(x = 0; x < olinebits; x++) - { - unsigned char bit = readBitFromReversedStream(&ibp, in); - setBitOfReversedStream(&obp, out, bit); - } - ibp += diff; - } -} - -/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from -the IDAT chunks (with filter index bytes and possible padding bits) -return value is error*/ -static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, - unsigned w, unsigned h, const LodePNGInfo* info_png) -{ - /* - This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. - Steps: - *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8) - *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace - NOTE: the in buffer will be overwritten with intermediate data! - */ - unsigned bpp = lodepng_get_bpp(&info_png->color); - if(bpp == 0) return 31; /*error: invalid colortype*/ - - if(info_png->interlace_method == 0) - { - if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) - { - CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp)); - removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h); - } - /*we can immediatly filter into the out buffer, no other steps needed*/ - else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp)); - } - else /*interlace_method is 1 (Adam7)*/ - { - unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; - unsigned i; - - Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); - - for(i = 0; i < 7; i++) - { - CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp)); - /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, - move bytes instead of bits or move not at all*/ - if(bpp < 8) - { - /*remove padding bits in scanlines; after this there still may be padding - bits between the different reduced images: each reduced image still starts nicely at a byte*/ - removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, - ((passw[i] * bpp + 7) / 8) * 8, passh[i]); - } - } - - Adam7_deinterlace(out, in, w, h, bpp); - } - - return 0; -} - -static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) -{ - unsigned pos = 0, i; - if(color->palette) lodepng_free(color->palette); - color->palettesize = chunkLength / 3; - color->palette = (unsigned char*)lodepng_malloc(4 * color->palettesize); - if(!color->palette && color->palettesize) - { - color->palettesize = 0; - return 83; /*alloc fail*/ - } - if(color->palettesize > 256) return 38; /*error: palette too big*/ - - for(i = 0; i < color->palettesize; i++) - { - color->palette[4 * i + 0] = data[pos++]; /*R*/ - color->palette[4 * i + 1] = data[pos++]; /*G*/ - color->palette[4 * i + 2] = data[pos++]; /*B*/ - color->palette[4 * i + 3] = 255; /*alpha*/ - } - - return 0; /* OK */ -} - -static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) -{ - unsigned i; - if(color->colortype == LCT_PALETTE) - { - /*error: more alpha values given than there are palette entries*/ - if(chunkLength > color->palettesize) return 38; - - for(i = 0; i < chunkLength; i++) color->palette[4 * i + 3] = data[i]; - } - else if(color->colortype == LCT_GREY) - { - /*error: this chunk must be 2 bytes for greyscale image*/ - if(chunkLength != 2) return 30; - - color->key_defined = 1; - color->key_r = color->key_g = color->key_b = 256 * data[0] + data[1]; - } - else if(color->colortype == LCT_RGB) - { - /*error: this chunk must be 6 bytes for RGB image*/ - if(chunkLength != 6) return 41; - - color->key_defined = 1; - color->key_r = 256 * data[0] + data[1]; - color->key_g = 256 * data[2] + data[3]; - color->key_b = 256 * data[4] + data[5]; - } - else return 42; /*error: tRNS chunk not allowed for other color models*/ - - return 0; /* OK */ -} - - -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS -/*background color chunk (bKGD)*/ -static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) -{ - if(info->color.colortype == LCT_PALETTE) - { - /*error: this chunk must be 1 byte for indexed color image*/ - if(chunkLength != 1) return 43; - - info->background_defined = 1; - info->background_r = info->background_g = info->background_b = data[0]; - } - else if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) - { - /*error: this chunk must be 2 bytes for greyscale image*/ - if(chunkLength != 2) return 44; - - info->background_defined = 1; - info->background_r = info->background_g = info->background_b - = 256 * data[0] + data[1]; - } - else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) - { - /*error: this chunk must be 6 bytes for greyscale image*/ - if(chunkLength != 6) return 45; - - info->background_defined = 1; - info->background_r = 256 * data[0] + data[1]; - info->background_g = 256 * data[2] + data[3]; - info->background_b = 256 * data[4] + data[5]; - } - - return 0; /* OK */ -} - -/*text chunk (tEXt)*/ -static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) -{ - unsigned error = 0; - char *key = 0, *str = 0; - unsigned i; - - while(!error) /*not really a while loop, only used to break on error*/ - { - unsigned length, string2_begin; - - length = 0; - while(length < chunkLength && data[length] != 0) length++; - /*even though it's not allowed by the standard, no error is thrown if - there's no null termination char, if the text is empty*/ - if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ - - key = (char*)lodepng_malloc(length + 1); - if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ - - key[length] = 0; - for(i = 0; i < length; i++) key[i] = data[i]; - - string2_begin = length + 1; /*skip keyword null terminator*/ - - length = chunkLength < string2_begin ? 0 : chunkLength - string2_begin; - str = (char*)lodepng_malloc(length + 1); - if(!str) CERROR_BREAK(error, 83); /*alloc fail*/ - - str[length] = 0; - for(i = 0; i < length; i++) str[i] = data[string2_begin + i]; - - error = lodepng_add_text(info, key, str); - - break; - } - - lodepng_free(key); - lodepng_free(str); - - return error; -} - -/*compressed text chunk (zTXt)*/ -static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, - const unsigned char* data, size_t chunkLength) -{ - unsigned error = 0; - unsigned i; - - unsigned length, string2_begin; - char *key = 0; - ucvector decoded; - - ucvector_init(&decoded); - - while(!error) /*not really a while loop, only used to break on error*/ - { - for(length = 0; length < chunkLength && data[length] != 0; length++) ; - if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ - if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ - - key = (char*)lodepng_malloc(length + 1); - if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ - - key[length] = 0; - for(i = 0; i < length; i++) key[i] = data[i]; - - if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ - - string2_begin = length + 2; - if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ - - length = chunkLength - string2_begin; - /*will fail if zlib error, e.g. if length is too small*/ - error = zlib_decompress(&decoded.data, &decoded.size, - (unsigned char*)(&data[string2_begin]), - length, zlibsettings); - if(error) break; - ucvector_push_back(&decoded, 0); - - error = lodepng_add_text(info, key, (char*)decoded.data); - - break; - } - - lodepng_free(key); - ucvector_cleanup(&decoded); - - return error; -} - -/*international text chunk (iTXt)*/ -static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, - const unsigned char* data, size_t chunkLength) -{ - unsigned error = 0; - unsigned i; - - unsigned length, begin, compressed; - char *key = 0, *langtag = 0, *transkey = 0; - ucvector decoded; - ucvector_init(&decoded); - - while(!error) /*not really a while loop, only used to break on error*/ - { - /*Quick check if the chunk length isn't too small. Even without check - it'd still fail with other error checks below if it's too short. This just gives a different error code.*/ - if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/ - - /*read the key*/ - for(length = 0; length < chunkLength && data[length] != 0; length++) ; - if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/ - if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ - - key = (char*)lodepng_malloc(length + 1); - if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ - - key[length] = 0; - for(i = 0; i < length; i++) key[i] = data[i]; - - /*read the compression method*/ - compressed = data[length + 1]; - if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ - - /*even though it's not allowed by the standard, no error is thrown if - there's no null termination char, if the text is empty for the next 3 texts*/ - - /*read the langtag*/ - begin = length + 3; - length = 0; - for(i = begin; i < chunkLength && data[i] != 0; i++) length++; - - langtag = (char*)lodepng_malloc(length + 1); - if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/ - - langtag[length] = 0; - for(i = 0; i < length; i++) langtag[i] = data[begin + i]; - - /*read the transkey*/ - begin += length + 1; - length = 0; - for(i = begin; i < chunkLength && data[i] != 0; i++) length++; - - transkey = (char*)lodepng_malloc(length + 1); - if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/ - - transkey[length] = 0; - for(i = 0; i < length; i++) transkey[i] = data[begin + i]; - - /*read the actual text*/ - begin += length + 1; - - length = chunkLength < begin ? 0 : chunkLength - begin; - - if(compressed) - { - /*will fail if zlib error, e.g. if length is too small*/ - error = zlib_decompress(&decoded.data, &decoded.size, - (unsigned char*)(&data[begin]), - length, zlibsettings); - if(error) break; - if(decoded.allocsize < decoded.size) decoded.allocsize = decoded.size; - ucvector_push_back(&decoded, 0); - } - else - { - if(!ucvector_resize(&decoded, length + 1)) CERROR_BREAK(error, 83 /*alloc fail*/); - - decoded.data[length] = 0; - for(i = 0; i < length; i++) decoded.data[i] = data[begin + i]; - } - - error = lodepng_add_itext(info, key, langtag, transkey, (char*)decoded.data); - - break; - } - - lodepng_free(key); - lodepng_free(langtag); - lodepng_free(transkey); - ucvector_cleanup(&decoded); - - return error; -} - -static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) -{ - if(chunkLength != 7) return 73; /*invalid tIME chunk size*/ - - info->time_defined = 1; - info->time.year = 256 * data[0] + data[+ 1]; - info->time.month = data[2]; - info->time.day = data[3]; - info->time.hour = data[4]; - info->time.minute = data[5]; - info->time.second = data[6]; - - return 0; /* OK */ -} - -static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) -{ - if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/ - - info->phys_defined = 1; - info->phys_x = 16777216 * data[0] + 65536 * data[1] + 256 * data[2] + data[3]; - info->phys_y = 16777216 * data[4] + 65536 * data[5] + 256 * data[6] + data[7]; - info->phys_unit = data[8]; - - return 0; /* OK */ -} -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - -/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/ -static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, - LodePNGState* state, - const unsigned char* in, size_t insize) -{ - unsigned char IEND = 0; - const unsigned char* chunk; - size_t i; - ucvector idat; /*the data from idat chunks*/ - ucvector scanlines; - - /*for unknown chunk order*/ - unsigned unknown = 0; -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/ -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - - /*provide some proper output values if error will happen*/ - *out = 0; - - state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/ - if(state->error) return; - - ucvector_init(&idat); - chunk = &in[33]; /*first byte of the first chunk after the header*/ - - /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. - IDAT data is put at the start of the in buffer*/ - while(!IEND && !state->error) - { - unsigned chunkLength; - const unsigned char* data; /*the data in the chunk*/ - - /*error: size of the in buffer too small to contain next chunk*/ - if((size_t)((chunk - in) + 12) > insize || chunk < in) CERROR_BREAK(state->error, 30); - - /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/ - chunkLength = lodepng_chunk_length(chunk); - /*error: chunk length larger than the max PNG chunk size*/ - if(chunkLength > 2147483647) CERROR_BREAK(state->error, 63); - - if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) - { - CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/ - } - - data = lodepng_chunk_data_const(chunk); - - /*IDAT chunk, containing compressed image data*/ - if(lodepng_chunk_type_equals(chunk, "IDAT")) - { - size_t oldsize = idat.size; - if(!ucvector_resize(&idat, oldsize + chunkLength)) CERROR_BREAK(state->error, 83 /*alloc fail*/); - for(i = 0; i < chunkLength; i++) idat.data[oldsize + i] = data[i]; -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - critical_pos = 3; -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - } - /*IEND chunk*/ - else if(lodepng_chunk_type_equals(chunk, "IEND")) - { - IEND = 1; - } - /*palette chunk (PLTE)*/ - else if(lodepng_chunk_type_equals(chunk, "PLTE")) - { - state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength); - if(state->error) break; -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - critical_pos = 2; -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - } - /*palette transparency chunk (tRNS)*/ - else if(lodepng_chunk_type_equals(chunk, "tRNS")) - { - state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength); - if(state->error) break; - } -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - /*background color chunk (bKGD)*/ - else if(lodepng_chunk_type_equals(chunk, "bKGD")) - { - state->error = readChunk_bKGD(&state->info_png, data, chunkLength); - if(state->error) break; - } - /*text chunk (tEXt)*/ - else if(lodepng_chunk_type_equals(chunk, "tEXt")) - { - if(state->decoder.read_text_chunks) - { - state->error = readChunk_tEXt(&state->info_png, data, chunkLength); - if(state->error) break; - } - } - /*compressed text chunk (zTXt)*/ - else if(lodepng_chunk_type_equals(chunk, "zTXt")) - { - if(state->decoder.read_text_chunks) - { - state->error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); - if(state->error) break; - } - } - /*international text chunk (iTXt)*/ - else if(lodepng_chunk_type_equals(chunk, "iTXt")) - { - if(state->decoder.read_text_chunks) - { - state->error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); - if(state->error) break; - } - } - else if(lodepng_chunk_type_equals(chunk, "tIME")) - { - state->error = readChunk_tIME(&state->info_png, data, chunkLength); - if(state->error) break; - } - else if(lodepng_chunk_type_equals(chunk, "pHYs")) - { - state->error = readChunk_pHYs(&state->info_png, data, chunkLength); - if(state->error) break; - } -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - else /*it's not an implemented chunk type, so ignore it: skip over the data*/ - { - /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/ - if(!lodepng_chunk_ancillary(chunk)) CERROR_BREAK(state->error, 69); - - unknown = 1; -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - if(state->decoder.remember_unknown_chunks) - { - state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1], - &state->info_png.unknown_chunks_size[critical_pos - 1], chunk); - if(state->error) break; - } -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - } - - if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/ - { - if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/ - } - - if(!IEND) chunk = lodepng_chunk_next_const(chunk); - } - - ucvector_init(&scanlines); - if(!state->error) - { - /*maximum final image length is already reserved in the vector's length - this is not really necessary*/ - if(!ucvector_resize(&scanlines, lodepng_get_raw_size(*w, *h, &state->info_png.color) + *h)) - { - state->error = 83; /*alloc fail*/ - } - } - if(!state->error) - { - /*decompress with the Zlib decompressor*/ - state->error = zlib_decompress(&scanlines.data, &scanlines.size, idat.data, - idat.size, &state->decoder.zlibsettings); - } - ucvector_cleanup(&idat); - - if(!state->error) - { - ucvector outv; - ucvector_init(&outv); - if(!ucvector_resizev(&outv, - lodepng_get_raw_size(*w, *h, &state->info_png.color), 0)) state->error = 83; /*alloc fail*/ - if(!state->error) state->error = postProcessScanlines(outv.data, scanlines.data, *w, *h, &state->info_png); - *out = outv.data; - } - ucvector_cleanup(&scanlines); -} - -unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, - LodePNGState* state, - const unsigned char* in, size_t insize) -{ - *out = 0; - decodeGeneric(out, w, h, state, in, insize); - if(state->error) return state->error; - if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) - { - /*same color type, no copying or converting of data needed*/ - /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype - the raw image has to the end user*/ - if(!state->decoder.color_convert) - { - state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color); - if(state->error) return state->error; - } - } - else - { - /*color conversion needed; sort of copy of the data*/ - unsigned char* data = *out; - size_t outsize; - - /*TODO: check if this works according to the statement in the documentation: "The converter can convert - from greyscale input color type, to 8-bit greyscale or greyscale with alpha"*/ - if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA) - && !(state->info_raw.bitdepth == 8)) - { - return 56; /*unsupported color mode conversion*/ - } - - outsize = lodepng_get_raw_size(*w, *h, &state->info_raw); - *out = (unsigned char*)lodepng_malloc(outsize); - if(!(*out)) - { - state->error = 83; /*alloc fail*/ - } - else state->error = lodepng_convert(*out, data, &state->info_raw, &state->info_png.color, *w, *h, state->decoder.fix_png); - lodepng_free(data); - } - return state->error; -} - -unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, - size_t insize, LodePNGColorType colortype, unsigned bitdepth) -{ - unsigned error; - LodePNGState state; - lodepng_state_init(&state); - state.info_raw.colortype = colortype; - state.info_raw.bitdepth = bitdepth; - error = lodepng_decode(out, w, h, &state, in, insize); - lodepng_state_cleanup(&state); - return error; -} - -unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) -{ - return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8); -} - -unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) -{ - return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8); -} - -#ifdef LODEPNG_COMPILE_DISK -unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, - LodePNGColorType colortype, unsigned bitdepth) -{ - unsigned char* buffer; - size_t buffersize; - unsigned error; - error = lodepng_load_file(&buffer, &buffersize, filename); - if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth); - lodepng_free(buffer); - return error; -} - -unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) -{ - return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8); -} - -unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) -{ - return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8); -} -#endif /*LODEPNG_COMPILE_DISK*/ - -void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) -{ - settings->color_convert = 1; -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - settings->read_text_chunks = 1; - settings->remember_unknown_chunks = 0; -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - settings->ignore_crc = 0; - settings->fix_png = 0; - lodepng_decompress_settings_init(&settings->zlibsettings); -} - -#endif /*LODEPNG_COMPILE_DECODER*/ - -#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) - -void lodepng_state_init(LodePNGState* state) -{ -#ifdef LODEPNG_COMPILE_DECODER - lodepng_decoder_settings_init(&state->decoder); -#endif /*LODEPNG_COMPILE_DECODER*/ -#ifdef LODEPNG_COMPILE_ENCODER - lodepng_encoder_settings_init(&state->encoder); -#endif /*LODEPNG_COMPILE_ENCODER*/ - lodepng_color_mode_init(&state->info_raw); - lodepng_info_init(&state->info_png); - state->error = 1; -} - -void lodepng_state_cleanup(LodePNGState* state) -{ - lodepng_color_mode_cleanup(&state->info_raw); - lodepng_info_cleanup(&state->info_png); -} - -void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source) -{ - lodepng_state_cleanup(dest); - *dest = *source; - lodepng_color_mode_init(&dest->info_raw); - lodepng_info_init(&dest->info_png); - dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); if(dest->error) return; - dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); if(dest->error) return; -} - -#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ - -#ifdef LODEPNG_COMPILE_ENCODER - -/* ////////////////////////////////////////////////////////////////////////// */ -/* / PNG Encoder / */ -/* ////////////////////////////////////////////////////////////////////////// */ - -/*chunkName must be string of 4 characters*/ -static unsigned addChunk(ucvector* out, const char* chunkName, const unsigned char* data, size_t length) -{ - CERROR_TRY_RETURN(lodepng_chunk_create(&out->data, &out->size, (unsigned)length, chunkName, data)); - out->allocsize = out->size; /*fix the allocsize again*/ - return 0; -} - -static void writeSignature(ucvector* out) -{ - /*8 bytes PNG signature, aka the magic bytes*/ - ucvector_push_back(out, 137); - ucvector_push_back(out, 80); - ucvector_push_back(out, 78); - ucvector_push_back(out, 71); - ucvector_push_back(out, 13); - ucvector_push_back(out, 10); - ucvector_push_back(out, 26); - ucvector_push_back(out, 10); -} - -static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, - LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method) -{ - unsigned error = 0; - ucvector header; - ucvector_init(&header); - - lodepng_add32bitInt(&header, w); /*width*/ - lodepng_add32bitInt(&header, h); /*height*/ - ucvector_push_back(&header, (unsigned char)bitdepth); /*bit depth*/ - ucvector_push_back(&header, (unsigned char)colortype); /*color type*/ - ucvector_push_back(&header, 0); /*compression method*/ - ucvector_push_back(&header, 0); /*filter method*/ - ucvector_push_back(&header, interlace_method); /*interlace method*/ - - error = addChunk(out, "IHDR", header.data, header.size); - ucvector_cleanup(&header); - - return error; -} - -static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) -{ - unsigned error = 0; - size_t i; - ucvector PLTE; - ucvector_init(&PLTE); - for(i = 0; i < info->palettesize * 4; i++) - { - /*add all channels except alpha channel*/ - if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]); - } - error = addChunk(out, "PLTE", PLTE.data, PLTE.size); - ucvector_cleanup(&PLTE); - - return error; -} - -static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) -{ - unsigned error = 0; - size_t i; - ucvector tRNS; - ucvector_init(&tRNS); - if(info->colortype == LCT_PALETTE) - { - size_t amount = info->palettesize; - /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/ - for(i = info->palettesize; i > 0; i--) - { - if(info->palette[4 * (i - 1) + 3] == 255) amount--; - else break; - } - /*add only alpha channel*/ - for(i = 0; i < amount; i++) ucvector_push_back(&tRNS, info->palette[4 * i + 3]); - } - else if(info->colortype == LCT_GREY) - { - if(info->key_defined) - { - ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256)); - ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256)); - } - } - else if(info->colortype == LCT_RGB) - { - if(info->key_defined) - { - ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256)); - ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256)); - ucvector_push_back(&tRNS, (unsigned char)(info->key_g / 256)); - ucvector_push_back(&tRNS, (unsigned char)(info->key_g % 256)); - ucvector_push_back(&tRNS, (unsigned char)(info->key_b / 256)); - ucvector_push_back(&tRNS, (unsigned char)(info->key_b % 256)); - } - } - - error = addChunk(out, "tRNS", tRNS.data, tRNS.size); - ucvector_cleanup(&tRNS); - - return error; -} - -static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize, - LodePNGCompressSettings* zlibsettings) -{ - ucvector zlibdata; - unsigned error = 0; - - /*compress with the Zlib compressor*/ - ucvector_init(&zlibdata); - error = zlib_compress(&zlibdata.data, &zlibdata.size, data, datasize, zlibsettings); - if(!error) error = addChunk(out, "IDAT", zlibdata.data, zlibdata.size); - ucvector_cleanup(&zlibdata); - - return error; -} - -static unsigned addChunk_IEND(ucvector* out) -{ - unsigned error = 0; - error = addChunk(out, "IEND", 0, 0); - return error; -} - -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - -static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) -{ - unsigned error = 0; - size_t i; - ucvector text; - ucvector_init(&text); - for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&text, (unsigned char)keyword[i]); - if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ - ucvector_push_back(&text, 0); /*0 termination char*/ - for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&text, (unsigned char)textstring[i]); - error = addChunk(out, "tEXt", text.data, text.size); - ucvector_cleanup(&text); - - return error; -} - -static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring, - LodePNGCompressSettings* zlibsettings) -{ - unsigned error = 0; - ucvector data, compressed; - size_t i, textsize = strlen(textstring); - - ucvector_init(&data); - ucvector_init(&compressed); - for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]); - if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ - ucvector_push_back(&data, 0); /*0 termination char*/ - ucvector_push_back(&data, 0); /*compression method: 0*/ - - error = zlib_compress(&compressed.data, &compressed.size, - (unsigned char*)textstring, textsize, zlibsettings); - if(!error) - { - for(i = 0; i < compressed.size; i++) ucvector_push_back(&data, compressed.data[i]); - error = addChunk(out, "zTXt", data.data, data.size); - } - - ucvector_cleanup(&compressed); - ucvector_cleanup(&data); - return error; -} - -static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* keyword, const char* langtag, - const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings) -{ - unsigned error = 0; - ucvector data; - size_t i, textsize = strlen(textstring); - - ucvector_init(&data); - - for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]); - if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ - ucvector_push_back(&data, 0); /*null termination char*/ - ucvector_push_back(&data, compressed ? 1 : 0); /*compression flag*/ - ucvector_push_back(&data, 0); /*compression method*/ - for(i = 0; langtag[i] != 0; i++) ucvector_push_back(&data, (unsigned char)langtag[i]); - ucvector_push_back(&data, 0); /*null termination char*/ - for(i = 0; transkey[i] != 0; i++) ucvector_push_back(&data, (unsigned char)transkey[i]); - ucvector_push_back(&data, 0); /*null termination char*/ - - if(compressed) - { - ucvector compressed_data; - ucvector_init(&compressed_data); - error = zlib_compress(&compressed_data.data, &compressed_data.size, - (unsigned char*)textstring, textsize, zlibsettings); - if(!error) - { - for(i = 0; i < compressed_data.size; i++) ucvector_push_back(&data, compressed_data.data[i]); - } - ucvector_cleanup(&compressed_data); - } - else /*not compressed*/ - { - for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&data, (unsigned char)textstring[i]); - } - - if(!error) error = addChunk(out, "iTXt", data.data, data.size); - ucvector_cleanup(&data); - return error; -} - -static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) -{ - unsigned error = 0; - ucvector bKGD; - ucvector_init(&bKGD); - if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) - { - ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256)); - ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); - } - else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) - { - ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256)); - ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); - ucvector_push_back(&bKGD, (unsigned char)(info->background_g / 256)); - ucvector_push_back(&bKGD, (unsigned char)(info->background_g % 256)); - ucvector_push_back(&bKGD, (unsigned char)(info->background_b / 256)); - ucvector_push_back(&bKGD, (unsigned char)(info->background_b % 256)); - } - else if(info->color.colortype == LCT_PALETTE) - { - ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); /*palette index*/ - } - - error = addChunk(out, "bKGD", bKGD.data, bKGD.size); - ucvector_cleanup(&bKGD); - - return error; -} - -static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) -{ - unsigned error = 0; - unsigned char* data = (unsigned char*)lodepng_malloc(7); - if(!data) return 83; /*alloc fail*/ - data[0] = (unsigned char)(time->year / 256); - data[1] = (unsigned char)(time->year % 256); - data[2] = time->month; - data[3] = time->day; - data[4] = time->hour; - data[5] = time->minute; - data[6] = time->second; - error = addChunk(out, "tIME", data, 7); - lodepng_free(data); - return error; -} - -static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info) -{ - unsigned error = 0; - ucvector data; - ucvector_init(&data); - - lodepng_add32bitInt(&data, info->phys_x); - lodepng_add32bitInt(&data, info->phys_y); - ucvector_push_back(&data, info->phys_unit); - - error = addChunk(out, "pHYs", data.data, data.size); - ucvector_cleanup(&data); - - return error; -} - -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - -static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline, - size_t length, size_t bytewidth, unsigned char filterType) -{ - size_t i; - switch(filterType) - { - case 0: /*None*/ - for(i = 0; i < length; i++) out[i] = scanline[i]; - break; - case 1: /*Sub*/ - if(prevline) - { - for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; - for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth]; - } - else - { - for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; - for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth]; - } - break; - case 2: /*Up*/ - if(prevline) - { - for(i = 0; i < length; i++) out[i] = scanline[i] - prevline[i]; - } - else - { - for(i = 0; i < length; i++) out[i] = scanline[i]; - } - break; - case 3: /*Average*/ - if(prevline) - { - for(i = 0; i < bytewidth; i++) out[i] = scanline[i] - prevline[i] / 2; - for(i = bytewidth; i < length; i++) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) / 2); - } - else - { - for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; - for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth] / 2; - } - break; - case 4: /*Paeth*/ - if(prevline) - { - /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/ - for(i = 0; i < bytewidth; i++) out[i] = (scanline[i] - prevline[i]); - for(i = bytewidth; i < length; i++) - { - out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth])); - } - } - else - { - for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; - /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/ - for(i = bytewidth; i < length; i++) out[i] = (scanline[i] - scanline[i - bytewidth]); - } - break; - default: return; /*unexisting filter type given*/ - } -} - -/* log2 approximation. A slight bit faster than std::log. */ -static float flog2(float f) -{ - float result = 0; - while(f > 32) { result += 4; f /= 16; } - while(f > 2) { result++; f /= 2; } - return result + 1.442695f * (f * f * f / 3 - 3 * f * f / 2 + 3 * f - 1.83333f); -} - -static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, - const LodePNGColorMode* info, const LodePNGEncoderSettings* settings) -{ - /* - For PNG filter method 0 - out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are - the scanlines with 1 extra byte per scanline - */ - - unsigned bpp = lodepng_get_bpp(info); - /*the width of a scanline in bytes, not including the filter type*/ - size_t linebytes = (w * bpp + 7) / 8; - /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ - size_t bytewidth = (bpp + 7) / 8; - const unsigned char* prevline = 0; - unsigned x, y; - unsigned error = 0; - LodePNGFilterStrategy strategy = settings->filter_strategy; - - /* - There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard: - * If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e. - use fixed filtering, with the filter None). - * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is - not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply - all five filters and select the filter that produces the smallest sum of absolute values per row. - This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true. - - If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed, - but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum - heuristic is used. - */ - if(settings->filter_palette_zero && - (info->colortype == LCT_PALETTE || info->bitdepth < 8)) strategy = LFS_ZERO; - - if(bpp == 0) return 31; /*error: invalid color type*/ - - if(strategy == LFS_ZERO) - { - for(y = 0; y < h; y++) - { - size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ - size_t inindex = linebytes * y; - out[outindex] = 0; /*filter type byte*/ - filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, 0); - prevline = &in[inindex]; - } - } - else if(strategy == LFS_MINSUM) - { - /*adaptive filtering*/ - size_t sum[5]; - ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ - size_t smallest = 0; - unsigned type, bestType = 0; - - for(type = 0; type < 5; type++) - { - ucvector_init(&attempt[type]); - if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/ - } - - if(!error) - { - for(y = 0; y < h; y++) - { - /*try the 5 filter types*/ - for(type = 0; type < 5; type++) - { - filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); - - /*calculate the sum of the result*/ - sum[type] = 0; - if(type == 0) - { - for(x = 0; x < linebytes; x++) sum[type] += (unsigned char)(attempt[type].data[x]); - } - else - { - for(x = 0; x < linebytes; x++) - { - /*For differences, each byte should be treated as signed, values above 127 are negative - (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there. - This means filtertype 0 is almost never chosen, but that is justified.*/ - signed char s = (signed char)(attempt[type].data[x]); - sum[type] += s < 0 ? -s : s; - } - } - - /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ - if(type == 0 || sum[type] < smallest) - { - bestType = type; - smallest = sum[type]; - } - } - - prevline = &in[y * linebytes]; - - /*now fill the out values*/ - out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ - for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; - } - } - - for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); - } - else if(strategy == LFS_ENTROPY) - { - float sum[5]; - ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ - float smallest = 0; - unsigned type, bestType = 0; - unsigned count[256]; - - for(type = 0; type < 5; type++) - { - ucvector_init(&attempt[type]); - if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/ - } - - for(y = 0; y < h; y++) - { - /*try the 5 filter types*/ - for(type = 0; type < 5; type++) - { - filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); - for(x = 0; x < 256; x++) count[x] = 0; - for(x = 0; x < linebytes; x++) count[attempt[type].data[x]]++; - count[type]++; /*the filter type itself is part of the scanline*/ - sum[type] = 0; - for(x = 0; x < 256; x++) - { - float p = count[x] / (float)(linebytes + 1); - sum[type] += count[x] == 0 ? 0 : flog2(1 / p) * p; - } - /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ - if(type == 0 || sum[type] < smallest) - { - bestType = type; - smallest = sum[type]; - } - } - - prevline = &in[y * linebytes]; - - /*now fill the out values*/ - out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ - for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; - } - - for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); - } - else if(strategy == LFS_PREDEFINED) - { - for(y = 0; y < h; y++) - { - size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ - size_t inindex = linebytes * y; - unsigned type = settings->predefined_filters[y]; - out[outindex] = type; /*filter type byte*/ - filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); - prevline = &in[inindex]; - } - } - else if(strategy == LFS_BRUTE_FORCE) - { - /*brute force filter chooser. - deflate the scanline after every filter attempt to see which one deflates best. - This is very slow and gives only slightly smaller, sometimes even larger, result*/ - size_t size[5]; - ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ - size_t smallest = 0; - unsigned type = 0, bestType = 0; - unsigned char* dummy; - LodePNGCompressSettings zlibsettings = settings->zlibsettings; - /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose, - to simulate the true case where the tree is the same for the whole image. Sometimes it gives - better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare - cases better compression. It does make this a bit less slow, so it's worth doing this.*/ - zlibsettings.btype = 1; - /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG - images only, so disable it*/ - zlibsettings.custom_zlib = 0; - zlibsettings.custom_deflate = 0; - for(type = 0; type < 5; type++) - { - ucvector_init(&attempt[type]); - ucvector_resize(&attempt[type], linebytes); /*todo: give error if resize failed*/ - } - for(y = 0; y < h; y++) /*try the 5 filter types*/ - { - for(type = 0; type < 5; type++) - { - unsigned testsize = attempt[type].size; - /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/ - - filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); - size[type] = 0; - dummy = 0; - zlib_compress(&dummy, &size[type], attempt[type].data, testsize, &zlibsettings); - lodepng_free(dummy); - /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/ - if(type == 0 || size[type] < smallest) - { - bestType = type; - smallest = size[type]; - } - } - prevline = &in[y * linebytes]; - out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ - for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; - } - for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); - } - else return 88; /* unknown filter strategy */ - - return error; -} - -static void addPaddingBits(unsigned char* out, const unsigned char* in, - size_t olinebits, size_t ilinebits, unsigned h) -{ - /*The opposite of the removePaddingBits function - olinebits must be >= ilinebits*/ - unsigned y; - size_t diff = olinebits - ilinebits; - size_t obp = 0, ibp = 0; /*bit pointers*/ - for(y = 0; y < h; y++) - { - size_t x; - for(x = 0; x < ilinebits; x++) - { - unsigned char bit = readBitFromReversedStream(&ibp, in); - setBitOfReversedStream(&obp, out, bit); - } - /*obp += diff; --> no, fill in some value in the padding bits too, to avoid - "Use of uninitialised value of size ###" warning from valgrind*/ - for(x = 0; x < diff; x++) setBitOfReversedStream(&obp, out, 0); - } -} - -/* -in: non-interlaced image with size w*h -out: the same pixels, but re-ordered according to PNG's Adam7 interlacing, with - no padding bits between scanlines, but between reduced images so that each - reduced image starts at a byte. -bpp: bits per pixel -there are no padding bits, not between scanlines, not between reduced images -in has the following size in bits: w * h * bpp. -out is possibly bigger due to padding bits between reduced images -NOTE: comments about padding bits are only relevant if bpp < 8 -*/ -static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) -{ - unsigned passw[7], passh[7]; - size_t filter_passstart[8], padded_passstart[8], passstart[8]; - unsigned i; - - Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); - - if(bpp >= 8) - { - for(i = 0; i < 7; i++) - { - unsigned x, y, b; - size_t bytewidth = bpp / 8; - for(y = 0; y < passh[i]; y++) - for(x = 0; x < passw[i]; x++) - { - size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; - size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth; - for(b = 0; b < bytewidth; b++) - { - out[pixeloutstart + b] = in[pixelinstart + b]; - } - } - } - } - else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ - { - for(i = 0; i < 7; i++) - { - unsigned x, y, b; - unsigned ilinebits = bpp * passw[i]; - unsigned olinebits = bpp * w; - size_t obp, ibp; /*bit pointers (for out and in buffer)*/ - for(y = 0; y < passh[i]; y++) - for(x = 0; x < passw[i]; x++) - { - ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; - obp = (8 * passstart[i]) + (y * ilinebits + x * bpp); - for(b = 0; b < bpp; b++) - { - unsigned char bit = readBitFromReversedStream(&ibp, in); - setBitOfReversedStream(&obp, out, bit); - } - } - } - } -} - -/*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image. -return value is error**/ -static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in, - unsigned w, unsigned h, - const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings) -{ - /* - This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps: - *) if no Adam7: 1) add padding bits (= posible extra bits per scanline if bpp < 8) 2) filter - *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter - */ - unsigned bpp = lodepng_get_bpp(&info_png->color); - unsigned error = 0; - - if(info_png->interlace_method == 0) - { - *outsize = h + (h * ((w * bpp + 7) / 8)); /*image size plus an extra byte per scanline + possible padding bits*/ - *out = (unsigned char*)lodepng_malloc(*outsize); - if(!(*out) && (*outsize)) error = 83; /*alloc fail*/ - - if(!error) - { - /*non multiple of 8 bits per scanline, padding bits needed per scanline*/ - if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) - { - unsigned char* padded = (unsigned char*)lodepng_malloc(h * ((w * bpp + 7) / 8)); - if(!padded) error = 83; /*alloc fail*/ - if(!error) - { - addPaddingBits(padded, in, ((w * bpp + 7) / 8) * 8, w * bpp, h); - error = filter(*out, padded, w, h, &info_png->color, settings); - } - lodepng_free(padded); - } - else - { - /*we can immediatly filter into the out buffer, no other steps needed*/ - error = filter(*out, in, w, h, &info_png->color, settings); - } - } - } - else /*interlace_method is 1 (Adam7)*/ - { - unsigned passw[7], passh[7]; - size_t filter_passstart[8], padded_passstart[8], passstart[8]; - unsigned char* adam7; - - Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); - - *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/ - *out = (unsigned char*)lodepng_malloc(*outsize); - if(!(*out)) error = 83; /*alloc fail*/ - - adam7 = (unsigned char*)lodepng_malloc(passstart[7]); - if(!adam7 && passstart[7]) error = 83; /*alloc fail*/ - - if(!error) - { - unsigned i; - - Adam7_interlace(adam7, in, w, h, bpp); - for(i = 0; i < 7; i++) - { - if(bpp < 8) - { - unsigned char* padded = (unsigned char*)lodepng_malloc(padded_passstart[i + 1] - padded_passstart[i]); - if(!padded) ERROR_BREAK(83); /*alloc fail*/ - addPaddingBits(padded, &adam7[passstart[i]], - ((passw[i] * bpp + 7) / 8) * 8, passw[i] * bpp, passh[i]); - error = filter(&(*out)[filter_passstart[i]], padded, - passw[i], passh[i], &info_png->color, settings); - lodepng_free(padded); - } - else - { - error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]], - passw[i], passh[i], &info_png->color, settings); - } - - if(error) break; - } - } - - lodepng_free(adam7); - } - - return error; -} - -/* -palette must have 4 * palettesize bytes allocated, and given in format RGBARGBARGBARGBA... -returns 0 if the palette is opaque, -returns 1 if the palette has a single color with alpha 0 ==> color key -returns 2 if the palette is semi-translucent. -*/ -static unsigned getPaletteTranslucency(const unsigned char* palette, size_t palettesize) -{ - size_t i, key = 0; - unsigned r = 0, g = 0, b = 0; /*the value of the color with alpha 0, so long as color keying is possible*/ - for(i = 0; i < palettesize; i++) - { - if(!key && palette[4 * i + 3] == 0) - { - r = palette[4 * i + 0]; g = palette[4 * i + 1]; b = palette[4 * i + 2]; - key = 1; - i = (size_t)(-1); /*restart from beginning, to detect earlier opaque colors with key's value*/ - } - else if(palette[4 * i + 3] != 255) return 2; - /*when key, no opaque RGB may have key's RGB*/ - else if(key && r == palette[i * 4 + 0] && g == palette[i * 4 + 1] && b == palette[i * 4 + 2]) return 2; - } - return key; -} - -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS -static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize) -{ - unsigned char* inchunk = data; - while((size_t)(inchunk - data) < datasize) - { - CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk)); - out->allocsize = out->size; /*fix the allocsize again*/ - inchunk = lodepng_chunk_next(inchunk); - } - return 0; -} -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - -unsigned lodepng_encode(unsigned char** out, size_t* outsize, - const unsigned char* image, unsigned w, unsigned h, - LodePNGState* state) -{ - LodePNGInfo info; - ucvector outv; - unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/ - size_t datasize = 0; - - /*provide some proper output values if error will happen*/ - *out = 0; - *outsize = 0; - state->error = 0; - - lodepng_info_init(&info); - lodepng_info_copy(&info, &state->info_png); - - if((info.color.colortype == LCT_PALETTE || state->encoder.force_palette) - && (info.color.palettesize == 0 || info.color.palettesize > 256)) - { - state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/ - return state->error; - } - - if(state->encoder.auto_convert != LAC_NO) - { - state->error = lodepng_auto_choose_color(&info.color, image, w, h, &state->info_raw, - state->encoder.auto_convert); - } - if(state->error) return state->error; - - if(state->encoder.zlibsettings.btype > 2) - { - CERROR_RETURN_ERROR(state->error, 61); /*error: unexisting btype*/ - } - if(state->info_png.interlace_method > 1) - { - CERROR_RETURN_ERROR(state->error, 71); /*error: unexisting interlace mode*/ - } - - state->error = checkColorValidity(info.color.colortype, info.color.bitdepth); - if(state->error) return state->error; /*error: unexisting color type given*/ - state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth); - if(state->error) return state->error; /*error: unexisting color type given*/ - - if(!lodepng_color_mode_equal(&state->info_raw, &info.color)) - { - unsigned char* converted; - size_t size = (w * h * lodepng_get_bpp(&info.color) + 7) / 8; - - converted = (unsigned char*)lodepng_malloc(size); - if(!converted && size) state->error = 83; /*alloc fail*/ - if(!state->error) - { - state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h, 0 /*fix_png*/); - } - if(!state->error) preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); - lodepng_free(converted); - } - else preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); - - ucvector_init(&outv); - while(!state->error) /*while only executed once, to break on error*/ - { -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - size_t i; -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - /*write signature and chunks*/ - writeSignature(&outv); - /*IHDR*/ - addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method); -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - /*unknown chunks between IHDR and PLTE*/ - if(info.unknown_chunks_data[0]) - { - state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]); - if(state->error) break; - } -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - /*PLTE*/ - if(info.color.colortype == LCT_PALETTE) - { - addChunk_PLTE(&outv, &info.color); - } - if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA)) - { - addChunk_PLTE(&outv, &info.color); - } - /*tRNS*/ - if(info.color.colortype == LCT_PALETTE && getPaletteTranslucency(info.color.palette, info.color.palettesize) != 0) - { - addChunk_tRNS(&outv, &info.color); - } - if((info.color.colortype == LCT_GREY || info.color.colortype == LCT_RGB) && info.color.key_defined) - { - addChunk_tRNS(&outv, &info.color); - } -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - /*bKGD (must come between PLTE and the IDAt chunks*/ - if(info.background_defined) addChunk_bKGD(&outv, &info); - /*pHYs (must come before the IDAT chunks)*/ - if(info.phys_defined) addChunk_pHYs(&outv, &info); - - /*unknown chunks between PLTE and IDAT*/ - if(info.unknown_chunks_data[1]) - { - state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]); - if(state->error) break; - } -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - /*IDAT (multiple IDAT chunks must be consecutive)*/ - state->error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings); - if(state->error) break; -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - /*tIME*/ - if(info.time_defined) addChunk_tIME(&outv, &info.time); - /*tEXt and/or zTXt*/ - for(i = 0; i < info.text_num; i++) - { - if(strlen(info.text_keys[i]) > 79) - { - state->error = 66; /*text chunk too large*/ - break; - } - if(strlen(info.text_keys[i]) < 1) - { - state->error = 67; /*text chunk too small*/ - break; - } - if(state->encoder.text_compression) - { - addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings); - } - else - { - addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]); - } - } - /*LodePNG version id in text chunk*/ - if(state->encoder.add_id) - { - unsigned alread_added_id_text = 0; - for(i = 0; i < info.text_num; i++) - { - if(!strcmp(info.text_keys[i], "LodePNG")) - { - alread_added_id_text = 1; - break; - } - } - if(alread_added_id_text == 0) - { - addChunk_tEXt(&outv, "LodePNG", VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ - } - } - /*iTXt*/ - for(i = 0; i < info.itext_num; i++) - { - if(strlen(info.itext_keys[i]) > 79) - { - state->error = 66; /*text chunk too large*/ - break; - } - if(strlen(info.itext_keys[i]) < 1) - { - state->error = 67; /*text chunk too small*/ - break; - } - addChunk_iTXt(&outv, state->encoder.text_compression, - info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i], - &state->encoder.zlibsettings); - } - - /*unknown chunks between IDAT and IEND*/ - if(info.unknown_chunks_data[2]) - { - state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]); - if(state->error) break; - } -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - addChunk_IEND(&outv); - - break; /*this isn't really a while loop; no error happened so break out now!*/ - } - - lodepng_info_cleanup(&info); - lodepng_free(data); - /*instead of cleaning the vector up, give it to the output*/ - *out = outv.data; - *outsize = outv.size; - - return state->error; -} - -unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, - unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) -{ - unsigned error; - LodePNGState state; - lodepng_state_init(&state); - state.info_raw.colortype = colortype; - state.info_raw.bitdepth = bitdepth; - state.info_png.color.colortype = colortype; - state.info_png.color.bitdepth = bitdepth; - lodepng_encode(out, outsize, image, w, h, &state); - error = state.error; - lodepng_state_cleanup(&state); - return error; -} - -unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) -{ - return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8); -} - -unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) -{ - return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8); -} - -#ifdef LODEPNG_COMPILE_DISK -unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, - LodePNGColorType colortype, unsigned bitdepth) -{ - unsigned char* buffer; - size_t buffersize; - unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth); - if(!error) error = lodepng_save_file(buffer, buffersize, filename); - lodepng_free(buffer); - return error; -} - -unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) -{ - return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8); -} - -unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) -{ - return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8); -} -#endif /*LODEPNG_COMPILE_DISK*/ - -void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) -{ - lodepng_compress_settings_init(&settings->zlibsettings); - settings->filter_palette_zero = 1; - settings->filter_strategy = LFS_MINSUM; - settings->auto_convert = LAC_AUTO; - settings->force_palette = 0; - settings->predefined_filters = 0; -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - settings->add_id = 0; - settings->text_compression = 1; -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ -} - -#endif /*LODEPNG_COMPILE_ENCODER*/ -#endif /*LODEPNG_COMPILE_PNG*/ - -#ifdef LODEPNG_COMPILE_ERROR_TEXT -/* -This returns the description of a numerical error code in English. This is also -the documentation of all the error codes. -*/ -const char* lodepng_error_text(unsigned code) -{ - switch(code) - { - case 0: return "no error, everything went ok"; - case 1: return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/ - case 10: return "end of input memory reached without huffman end code"; /*while huffman decoding*/ - case 11: return "error in code tree made it jump outside of huffman tree"; /*while huffman decoding*/ - case 13: return "problem while processing dynamic deflate block"; - case 14: return "problem while processing dynamic deflate block"; - case 15: return "problem while processing dynamic deflate block"; - case 16: return "unexisting code while processing dynamic deflate block"; - case 17: return "end of out buffer memory reached while inflating"; - case 18: return "invalid distance code while inflating"; - case 19: return "end of out buffer memory reached while inflating"; - case 20: return "invalid deflate block BTYPE encountered while decoding"; - case 21: return "NLEN is not ones complement of LEN in a deflate block"; - /*end of out buffer memory reached while inflating: - This can happen if the inflated deflate data is longer than the amount of bytes required to fill up - all the pixels of the image, given the color depth and image dimensions. Something that doesn't - happen in a normal, well encoded, PNG image.*/ - case 22: return "end of out buffer memory reached while inflating"; - case 23: return "end of in buffer memory reached while inflating"; - case 24: return "invalid FCHECK in zlib header"; - case 25: return "invalid compression method in zlib header"; - case 26: return "FDICT encountered in zlib header while it's not used for PNG"; - case 27: return "PNG file is smaller than a PNG header"; - /*Checks the magic file header, the first 8 bytes of the PNG file*/ - case 28: return "incorrect PNG signature, it's no PNG or corrupted"; - case 29: return "first chunk is not the header chunk"; - case 30: return "chunk length too large, chunk broken off at end of file"; - case 31: return "illegal PNG color type or bpp"; - case 32: return "illegal PNG compression method"; - case 33: return "illegal PNG filter method"; - case 34: return "illegal PNG interlace method"; - case 35: return "chunk length of a chunk is too large or the chunk too small"; - case 36: return "illegal PNG filter type encountered"; - case 37: return "illegal bit depth for this color type given"; - case 38: return "the palette is too big"; /*more than 256 colors*/ - case 39: return "more palette alpha values given in tRNS chunk than there are colors in the palette"; - case 40: return "tRNS chunk has wrong size for greyscale image"; - case 41: return "tRNS chunk has wrong size for RGB image"; - case 42: return "tRNS chunk appeared while it was not allowed for this color type"; - case 43: return "bKGD chunk has wrong size for palette image"; - case 44: return "bKGD chunk has wrong size for greyscale image"; - case 45: return "bKGD chunk has wrong size for RGB image"; - /*Is the palette too small?*/ - case 46: return "a value in indexed image is larger than the palette size (bitdepth = 8)"; - /*Is the palette too small?*/ - case 47: return "a value in indexed image is larger than the palette size (bitdepth < 8)"; - /*the input data is empty, maybe a PNG file doesn't exist or is in the wrong path*/ - case 48: return "empty input or file doesn't exist"; - case 49: return "jumped past memory while generating dynamic huffman tree"; - case 50: return "jumped past memory while generating dynamic huffman tree"; - case 51: return "jumped past memory while inflating huffman block"; - case 52: return "jumped past memory while inflating"; - case 53: return "size of zlib data too small"; - case 54: return "repeat symbol in tree while there was no value symbol yet"; - /*jumped past tree while generating huffman tree, this could be when the - tree will have more leaves than symbols after generating it out of the - given lenghts. They call this an oversubscribed dynamic bit lengths tree in zlib.*/ - case 55: return "jumped past tree while generating huffman tree"; - case 56: return "given output image colortype or bitdepth not supported for color conversion"; - case 57: return "invalid CRC encountered (checking CRC can be disabled)"; - case 58: return "invalid ADLER32 encountered (checking ADLER32 can be disabled)"; - case 59: return "requested color conversion not supported"; - case 60: return "invalid window size given in the settings of the encoder (must be 0-32768)"; - case 61: return "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)"; - /*LodePNG leaves the choice of RGB to greyscale conversion formula to the user.*/ - case 62: return "conversion from color to greyscale not supported"; - case 63: return "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk"; /*(2^31-1)*/ - /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/ - case 64: return "the length of the END symbol 256 in the Huffman tree is 0"; - case 66: return "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes"; - case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte"; - case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors"; - case 69: return "unknown chunk type with 'critical' flag encountered by the decoder"; - case 71: return "unexisting interlace mode given to encoder (must be 0 or 1)"; - case 72: return "while decoding, unexisting compression method encountering in zTXt or iTXt chunk (it must be 0)"; - case 73: return "invalid tIME chunk size"; - case 74: return "invalid pHYs chunk size"; - /*length could be wrong, or data chopped off*/ - case 75: return "no null termination char found while decoding text chunk"; - case 76: return "iTXt chunk too short to contain required bytes"; - case 77: return "integer overflow in buffer size"; - case 78: return "failed to open file for reading"; /*file doesn't exist or couldn't be opened for reading*/ - case 79: return "failed to open file for writing"; - case 80: return "tried creating a tree of 0 symbols"; - case 81: return "lazy matching at pos 0 is impossible"; - case 82: return "color conversion to palette requested while a color isn't in palette"; - case 83: return "memory allocation failed"; - case 84: return "given image too small to contain all pixels to be encoded"; - case 85: return "internal color conversion bug"; - case 86: return "impossible offset in lz77 encoding (internal bug)"; - case 87: return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined"; - case 88: return "invalid filter strategy given for LodePNGEncoderSettings.filter_strategy"; - case 89: return "text chunk keyword too short or long: must have size 1-79"; - /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/ - case 90: return "windowsize must be a power of two"; - } - return "unknown error code"; -} -#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ - -/* ////////////////////////////////////////////////////////////////////////// */ -/* ////////////////////////////////////////////////////////////////////////// */ -/* // C++ Wrapper // */ -/* ////////////////////////////////////////////////////////////////////////// */ -/* ////////////////////////////////////////////////////////////////////////// */ - -#ifdef LODEPNG_COMPILE_CPP -namespace lodepng -{ - -#ifdef LODEPNG_COMPILE_DISK -void load_file(std::vector& buffer, const std::string& filename) -{ - std::ifstream file(filename.c_str(), std::ios::in|std::ios::binary|std::ios::ate); - - /*get filesize*/ - std::streamsize size = 0; - if(file.seekg(0, std::ios::end).good()) size = file.tellg(); - if(file.seekg(0, std::ios::beg).good()) size -= file.tellg(); - - /*read contents of the file into the vector*/ - buffer.resize(size_t(size)); - if(size > 0) file.read((char*)(&buffer[0]), size); -} - -/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ -void save_file(const std::vector& buffer, const std::string& filename) -{ - std::ofstream file(filename.c_str(), std::ios::out|std::ios::binary); - file.write(buffer.empty() ? 0 : (char*)&buffer[0], std::streamsize(buffer.size())); -} -#endif //LODEPNG_COMPILE_DISK - -#ifdef LODEPNG_COMPILE_ZLIB -#ifdef LODEPNG_COMPILE_DECODER -unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, - const LodePNGDecompressSettings& settings) -{ - unsigned char* buffer = 0; - size_t buffersize = 0; - unsigned error = zlib_decompress(&buffer, &buffersize, in, insize, &settings); - if(buffer) - { - out.insert(out.end(), &buffer[0], &buffer[buffersize]); - lodepng_free(buffer); - } - return error; -} - -unsigned decompress(std::vector& out, const std::vector& in, - const LodePNGDecompressSettings& settings) -{ - return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings); -} -#endif //LODEPNG_COMPILE_DECODER - -#ifdef LODEPNG_COMPILE_ENCODER -unsigned compress(std::vector& out, const unsigned char* in, size_t insize, - const LodePNGCompressSettings& settings) -{ - unsigned char* buffer = 0; - size_t buffersize = 0; - unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings); - if(buffer) - { - out.insert(out.end(), &buffer[0], &buffer[buffersize]); - lodepng_free(buffer); - } - return error; -} - -unsigned compress(std::vector& out, const std::vector& in, - const LodePNGCompressSettings& settings) -{ - return compress(out, in.empty() ? 0 : &in[0], in.size(), settings); -} -#endif //LODEPNG_COMPILE_ENCODER -#endif //LODEPNG_COMPILE_ZLIB - - -#ifdef LODEPNG_COMPILE_PNG - -State::State() -{ - lodepng_state_init(this); -} - -State::State(const State& other) -{ - lodepng_state_init(this); - lodepng_state_copy(this, &other); -} - -State::~State() -{ - lodepng_state_cleanup(this); -} - -State& State::operator=(const State& other) -{ - lodepng_state_copy(this, &other); - return *this; -} - -#ifdef LODEPNG_COMPILE_DECODER - -unsigned decode(std::vector& out, unsigned& w, unsigned& h, const unsigned char* in, - size_t insize, LodePNGColorType colortype, unsigned bitdepth) -{ - unsigned char* buffer; - unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth); - if(buffer && !error) - { - State state; - state.info_raw.colortype = colortype; - state.info_raw.bitdepth = bitdepth; - size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); - out.insert(out.end(), &buffer[0], &buffer[buffersize]); - lodepng_free(buffer); - } - return error; -} - -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - const std::vector& in, LodePNGColorType colortype, unsigned bitdepth) -{ - return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth); -} - -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - State& state, - const unsigned char* in, size_t insize) -{ - unsigned char* buffer = NULL; - unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize); - if(buffer && !error) - { - size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); - out.insert(out.end(), &buffer[0], &buffer[buffersize]); - } - lodepng_free(buffer); - return error; -} - -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - State& state, - const std::vector& in) -{ - return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size()); -} - -#ifdef LODEPNG_COMPILE_DISK -unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::string& filename, - LodePNGColorType colortype, unsigned bitdepth) -{ - std::vector buffer; - load_file(buffer, filename); - return decode(out, w, h, buffer, colortype, bitdepth); -} -#endif //LODEPNG_COMPILE_DECODER -#endif //LODEPNG_COMPILE_DISK - -#ifdef LODEPNG_COMPILE_ENCODER -unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, - LodePNGColorType colortype, unsigned bitdepth) -{ - unsigned char* buffer; - size_t buffersize; - unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth); - if(buffer) - { - out.insert(out.end(), &buffer[0], &buffer[buffersize]); - lodepng_free(buffer); - } - return error; -} - -unsigned encode(std::vector& out, - const std::vector& in, unsigned w, unsigned h, - LodePNGColorType colortype, unsigned bitdepth) -{ - if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; - return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); -} - -unsigned encode(std::vector& out, - const unsigned char* in, unsigned w, unsigned h, - State& state) -{ - unsigned char* buffer; - size_t buffersize; - unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state); - if(buffer) - { - out.insert(out.end(), &buffer[0], &buffer[buffersize]); - lodepng_free(buffer); - } - return error; -} - -unsigned encode(std::vector& out, - const std::vector& in, unsigned w, unsigned h, - State& state) -{ - if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84; - return encode(out, in.empty() ? 0 : &in[0], w, h, state); -} - -#ifdef LODEPNG_COMPILE_DISK -unsigned encode(const std::string& filename, - const unsigned char* in, unsigned w, unsigned h, - LodePNGColorType colortype, unsigned bitdepth) -{ - std::vector buffer; - unsigned error = encode(buffer, in, w, h, colortype, bitdepth); - if(!error) save_file(buffer, filename); - return error; -} - -unsigned encode(const std::string& filename, - const std::vector& in, unsigned w, unsigned h, - LodePNGColorType colortype, unsigned bitdepth) -{ - if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; - return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); -} -#endif //LODEPNG_COMPILE_DISK -#endif //LODEPNG_COMPILE_ENCODER -#endif //LODEPNG_COMPILE_PNG -} //namespace lodepng -#endif /*LODEPNG_COMPILE_CPP*/ diff --git a/lib/lodepng/lodepng.h b/lib/lodepng/lodepng.h deleted file mode 100644 index c497a5c608..0000000000 --- a/lib/lodepng/lodepng.h +++ /dev/null @@ -1,1716 +0,0 @@ -/* -LodePNG version 20131222 - -Copyright (c) 2005-2013 Lode Vandevenne - -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. -*/ - -#ifndef LODEPNG_H -#define LODEPNG_H - -#include /*for size_t*/ - -#ifdef __cplusplus -#include -#include -#endif /*__cplusplus*/ - -/* -The following #defines are used to create code sections. They can be disabled -to disable code sections, which can give faster compile time and smaller binary. -The "NO_COMPILE" defines are designed to be used to pass as defines to the -compiler command to disable them without modifying this header, e.g. --DLODEPNG_NO_COMPILE_ZLIB for gcc. -*/ -/*deflate & zlib. If disabled, you must specify alternative zlib functions in -the custom_zlib field of the compress and decompress settings*/ -#ifndef LODEPNG_NO_COMPILE_ZLIB -#define LODEPNG_COMPILE_ZLIB -#endif -/*png encoder and png decoder*/ -#ifndef LODEPNG_NO_COMPILE_PNG -#define LODEPNG_COMPILE_PNG -#endif -/*deflate&zlib decoder and png decoder*/ -#ifndef LODEPNG_NO_COMPILE_DECODER -#define LODEPNG_COMPILE_DECODER -#endif -/*deflate&zlib encoder and png encoder*/ -#ifndef LODEPNG_NO_COMPILE_ENCODER -#define LODEPNG_COMPILE_ENCODER -#endif -/*the optional built in harddisk file loading and saving functions*/ -#ifndef LODEPNG_NO_COMPILE_DISK -#define LODEPNG_COMPILE_DISK -#endif -/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ -#ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS -#define LODEPNG_COMPILE_ANCILLARY_CHUNKS -#endif -/*ability to convert error numerical codes to English text string*/ -#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT -#define LODEPNG_COMPILE_ERROR_TEXT -#endif -/*Compile the default allocators (C's free, malloc and realloc). If you disable this, -you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your -source files with custom allocators.*/ -#ifndef LODEPNG_NO_COMPILE_ALLOCATORS -#define LODEPNG_COMPILE_ALLOCATORS -#endif -/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ -#ifdef __cplusplus -#ifndef LODEPNG_NO_COMPILE_CPP -#define LODEPNG_COMPILE_CPP -#endif -#endif - -#ifdef LODEPNG_COMPILE_PNG -/*The PNG color types (also used for raw).*/ -typedef enum LodePNGColorType -{ - LCT_GREY = 0, /*greyscale: 1,2,4,8,16 bit*/ - LCT_RGB = 2, /*RGB: 8,16 bit*/ - LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ - LCT_GREY_ALPHA = 4, /*greyscale with alpha: 8,16 bit*/ - LCT_RGBA = 6 /*RGB with alpha: 8,16 bit*/ -} LodePNGColorType; - -#ifdef LODEPNG_COMPILE_DECODER -/* -Converts PNG data in memory to raw pixel data. -out: Output parameter. Pointer to buffer that will contain the raw pixel data. - After decoding, its size is w * h * (bytes per pixel) bytes larger than - initially. Bytes per pixel depends on colortype and bitdepth. - Must be freed after usage with free(*out). - Note: for 16-bit per channel colors, uses big endian format like PNG does. -w: Output parameter. Pointer to width of pixel data. -h: Output parameter. Pointer to height of pixel data. -in: Memory buffer with the PNG file. -insize: size of the in buffer. -colortype: the desired color type for the raw output image. See explanation on PNG color types. -bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. -Return value: LodePNG error code (0 means no error). -*/ -unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, - const unsigned char* in, size_t insize, - LodePNGColorType colortype, unsigned bitdepth); - -/*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ -unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, - const unsigned char* in, size_t insize); - -/*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ -unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, - const unsigned char* in, size_t insize); - -#ifdef LODEPNG_COMPILE_DISK -/* -Load PNG from disk, from file with given name. -Same as the other decode functions, but instead takes a filename as input. -*/ -unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, - const char* filename, - LodePNGColorType colortype, unsigned bitdepth); - -/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/ -unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, - const char* filename); - -/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/ -unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, - const char* filename); -#endif /*LODEPNG_COMPILE_DISK*/ -#endif /*LODEPNG_COMPILE_DECODER*/ - - -#ifdef LODEPNG_COMPILE_ENCODER -/* -Converts raw pixel data into a PNG image in memory. The colortype and bitdepth - of the output PNG image cannot be chosen, they are automatically determined - by the colortype, bitdepth and content of the input pixel data. - Note: for 16-bit per channel colors, needs big endian format like PNG does. -out: Output parameter. Pointer to buffer that will contain the PNG image data. - Must be freed after usage with free(*out). -outsize: Output parameter. Pointer to the size in bytes of the out buffer. -image: The raw pixel data to encode. The size of this buffer should be - w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. -w: width of the raw pixel data in pixels. -h: height of the raw pixel data in pixels. -colortype: the color type of the raw input image. See explanation on PNG color types. -bitdepth: the bit depth of the raw input image. See explanation on PNG color types. -Return value: LodePNG error code (0 means no error). -*/ -unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, - const unsigned char* image, unsigned w, unsigned h, - LodePNGColorType colortype, unsigned bitdepth); - -/*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ -unsigned lodepng_encode32(unsigned char** out, size_t* outsize, - const unsigned char* image, unsigned w, unsigned h); - -/*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ -unsigned lodepng_encode24(unsigned char** out, size_t* outsize, - const unsigned char* image, unsigned w, unsigned h); - -#ifdef LODEPNG_COMPILE_DISK -/* -Converts raw pixel data into a PNG file on disk. -Same as the other encode functions, but instead takes a filename as output. -NOTE: This overwrites existing files without warning! -*/ -unsigned lodepng_encode_file(const char* filename, - const unsigned char* image, unsigned w, unsigned h, - LodePNGColorType colortype, unsigned bitdepth); - -/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/ -unsigned lodepng_encode32_file(const char* filename, - const unsigned char* image, unsigned w, unsigned h); - -/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/ -unsigned lodepng_encode24_file(const char* filename, - const unsigned char* image, unsigned w, unsigned h); -#endif /*LODEPNG_COMPILE_DISK*/ -#endif /*LODEPNG_COMPILE_ENCODER*/ - - -#ifdef LODEPNG_COMPILE_CPP -namespace lodepng -{ -#ifdef LODEPNG_COMPILE_DECODER -/*Same as lodepng_decode_memory, but decodes to an std::vector.*/ -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - const unsigned char* in, size_t insize, - LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - const std::vector& in, - LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); -#ifdef LODEPNG_COMPILE_DISK -/* -Converts PNG file from disk to raw pixel data in memory. -Same as the other decode functions, but instead takes a filename as input. -*/ -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - const std::string& filename, - LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); -#endif //LODEPNG_COMPILE_DISK -#endif //LODEPNG_COMPILE_DECODER - -#ifdef LODEPNG_COMPILE_ENCODER -/*Same as lodepng_encode_memory, but encodes to an std::vector.*/ -unsigned encode(std::vector& out, - const unsigned char* in, unsigned w, unsigned h, - LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); -unsigned encode(std::vector& out, - const std::vector& in, unsigned w, unsigned h, - LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); -#ifdef LODEPNG_COMPILE_DISK -/* -Converts 32-bit RGBA raw pixel data into a PNG file on disk. -Same as the other encode functions, but instead takes a filename as output. -NOTE: This overwrites existing files without warning! -*/ -unsigned encode(const std::string& filename, - const unsigned char* in, unsigned w, unsigned h, - LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); -unsigned encode(const std::string& filename, - const std::vector& in, unsigned w, unsigned h, - LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); -#endif //LODEPNG_COMPILE_DISK -#endif //LODEPNG_COMPILE_ENCODER -} //namespace lodepng -#endif /*LODEPNG_COMPILE_CPP*/ -#endif /*LODEPNG_COMPILE_PNG*/ - -#ifdef LODEPNG_COMPILE_ERROR_TEXT -/*Returns an English description of the numerical error code.*/ -const char* lodepng_error_text(unsigned code); -#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ - -#ifdef LODEPNG_COMPILE_DECODER -/*Settings for zlib decompression*/ -typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; -struct LodePNGDecompressSettings -{ - unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ - - /*use custom zlib decoder instead of built in one (default: null)*/ - unsigned (*custom_zlib)(unsigned char**, size_t*, - const unsigned char*, size_t, - const LodePNGDecompressSettings*); - /*use custom deflate decoder instead of built in one (default: null) - if custom_zlib is used, custom_deflate is ignored since only the built in - zlib function will call custom_deflate*/ - unsigned (*custom_inflate)(unsigned char**, size_t*, - const unsigned char*, size_t, - const LodePNGDecompressSettings*); - - const void* custom_context; /*optional custom settings for custom functions*/ -}; - -extern const LodePNGDecompressSettings lodepng_default_decompress_settings; -void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); -#endif /*LODEPNG_COMPILE_DECODER*/ - -#ifdef LODEPNG_COMPILE_ENCODER -/* -Settings for zlib compression. Tweaking these settings tweaks the balance -between speed and compression ratio. -*/ -typedef struct LodePNGCompressSettings LodePNGCompressSettings; -struct LodePNGCompressSettings /*deflate = compress*/ -{ - /*LZ77 related settings*/ - unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ - unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ - unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Typical value: 2048.*/ - unsigned minmatch; /*mininum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ - unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ - unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ - - /*use custom zlib encoder instead of built in one (default: null)*/ - unsigned (*custom_zlib)(unsigned char**, size_t*, - const unsigned char*, size_t, - const LodePNGCompressSettings*); - /*use custom deflate encoder instead of built in one (default: null) - if custom_zlib is used, custom_deflate is ignored since only the built in - zlib function will call custom_deflate*/ - unsigned (*custom_deflate)(unsigned char**, size_t*, - const unsigned char*, size_t, - const LodePNGCompressSettings*); - - const void* custom_context; /*optional custom settings for custom functions*/ -}; - -extern const LodePNGCompressSettings lodepng_default_compress_settings; -void lodepng_compress_settings_init(LodePNGCompressSettings* settings); -#endif /*LODEPNG_COMPILE_ENCODER*/ - -#ifdef LODEPNG_COMPILE_PNG -/* -Color mode of an image. Contains all information required to decode the pixel -bits to RGBA colors. This information is the same as used in the PNG file -format, and is used both for PNG and raw image data in LodePNG. -*/ -typedef struct LodePNGColorMode -{ - /*header (IHDR)*/ - LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ - unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ - - /* - palette (PLTE and tRNS) - - Dynamically allocated with the colors of the palette, including alpha. - When encoding a PNG, to store your colors in the palette of the LodePNGColorMode, first use - lodepng_palette_clear, then for each color use lodepng_palette_add. - If you encode an image without alpha with palette, don't forget to put value 255 in each A byte of the palette. - - When decoding, by default you can ignore this palette, since LodePNG already - fills the palette colors in the pixels of the raw RGBA output. - - The palette is only supported for color type 3. - */ - unsigned char* palette; /*palette in RGBARGBA... order. When allocated, must be either 0, or have size 1024*/ - size_t palettesize; /*palette size in number of colors (amount of bytes is 4 * palettesize)*/ - - /* - transparent color key (tRNS) - - This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. - For greyscale PNGs, r, g and b will all 3 be set to the same. - - When decoding, by default you can ignore this information, since LodePNG sets - pixels with this key to transparent already in the raw RGBA output. - - The color key is only supported for color types 0 and 2. - */ - unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ - unsigned key_r; /*red/greyscale component of color key*/ - unsigned key_g; /*green component of color key*/ - unsigned key_b; /*blue component of color key*/ -} LodePNGColorMode; - -/*init, cleanup and copy functions to use with this struct*/ -void lodepng_color_mode_init(LodePNGColorMode* info); -void lodepng_color_mode_cleanup(LodePNGColorMode* info); -/*return value is error code (0 means no error)*/ -unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); - -void lodepng_palette_clear(LodePNGColorMode* info); -/*add 1 color to the palette*/ -unsigned lodepng_palette_add(LodePNGColorMode* info, - unsigned char r, unsigned char g, unsigned char b, unsigned char a); - -/*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ -unsigned lodepng_get_bpp(const LodePNGColorMode* info); -/*get the amount of color channels used, based on colortype in the struct. -If a palette is used, it counts as 1 channel.*/ -unsigned lodepng_get_channels(const LodePNGColorMode* info); -/*is it a greyscale type? (only colortype 0 or 4)*/ -unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); -/*has it got an alpha channel? (only colortype 2 or 6)*/ -unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); -/*has it got a palette? (only colortype 3)*/ -unsigned lodepng_is_palette_type(const LodePNGColorMode* info); -/*only returns true if there is a palette and there is a value in the palette with alpha < 255. -Loops through the palette to check this.*/ -unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); -/* -Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. -Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). -Returns false if the image can only have opaque pixels. -In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, -or if "key_defined" is true. -*/ -unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); -/*Returns the byte size of a raw image buffer with given width, height and color mode*/ -size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); - -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS -/*The information of a Time chunk in PNG.*/ -typedef struct LodePNGTime -{ - unsigned year; /*2 bytes used (0-65535)*/ - unsigned month; /*1-12*/ - unsigned day; /*1-31*/ - unsigned hour; /*0-23*/ - unsigned minute; /*0-59*/ - unsigned second; /*0-60 (to allow for leap seconds)*/ -} LodePNGTime; -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - -/*Information about the PNG image, except pixels, width and height.*/ -typedef struct LodePNGInfo -{ - /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ - unsigned compression_method;/*compression method of the original file. Always 0.*/ - unsigned filter_method; /*filter method of the original file*/ - unsigned interlace_method; /*interlace method of the original file*/ - LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ - -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - /* - suggested background color chunk (bKGD) - This color uses the same color mode as the PNG (except alpha channel), which can be 1-bit to 16-bit. - - For greyscale PNGs, r, g and b will all 3 be set to the same. When encoding - the encoder writes the red one. For palette PNGs: When decoding, the RGB value - will be stored, not a palette index. But when encoding, specify the index of - the palette in background_r, the other two are then ignored. - - The decoder does not use this background color to edit the color of pixels. - */ - unsigned background_defined; /*is a suggested background color given?*/ - unsigned background_r; /*red component of suggested background color*/ - unsigned background_g; /*green component of suggested background color*/ - unsigned background_b; /*blue component of suggested background color*/ - - /* - non-international text chunks (tEXt and zTXt) - - The char** arrays each contain num strings. The actual messages are in - text_strings, while text_keys are keywords that give a short description what - the actual text represents, e.g. Title, Author, Description, or anything else. - - A keyword is minimum 1 character and maximum 79 characters long. It's - discouraged to use a single line length longer than 79 characters for texts. - - Don't allocate these text buffers yourself. Use the init/cleanup functions - correctly and use lodepng_add_text and lodepng_clear_text. - */ - size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ - char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ - char** text_strings; /*the actual text*/ - - /* - international text chunks (iTXt) - Similar to the non-international text chunks, but with additional strings - "langtags" and "transkeys". - */ - size_t itext_num; /*the amount of international texts in this PNG*/ - char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ - char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ - char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ - char** itext_strings; /*the actual international text - UTF-8 string*/ - - /*time chunk (tIME)*/ - unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ - LodePNGTime time; - - /*phys chunk (pHYs)*/ - unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ - unsigned phys_x; /*pixels per unit in x direction*/ - unsigned phys_y; /*pixels per unit in y direction*/ - unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ - - /* - unknown chunks - There are 3 buffers, one for each position in the PNG where unknown chunks can appear - each buffer contains all unknown chunks for that position consecutively - The 3 buffers are the unknown chunks between certain critical chunks: - 0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND - Do not allocate or traverse this data yourself. Use the chunk traversing functions declared - later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. - */ - unsigned char* unknown_chunks_data[3]; - size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ -} LodePNGInfo; - -/*init, cleanup and copy functions to use with this struct*/ -void lodepng_info_init(LodePNGInfo* info); -void lodepng_info_cleanup(LodePNGInfo* info); -/*return value is error code (0 means no error)*/ -unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); - -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS -void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ -unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ - -void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ -unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, - const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - -/* -Converts raw buffer from one color type to another color type, based on -LodePNGColorMode structs to describe the input and output color type. -See the reference manual at the end of this header file to see which color conversions are supported. -return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) -The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel -of the output color type (lodepng_get_bpp) -The fix_png value works as described in struct LodePNGDecoderSettings. -Note: for 16-bit per channel colors, uses big endian format like PNG does. -*/ -unsigned lodepng_convert(unsigned char* out, const unsigned char* in, - LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, - unsigned w, unsigned h, unsigned fix_png); - -#ifdef LODEPNG_COMPILE_DECODER -/* -Settings for the decoder. This contains settings for the PNG and the Zlib -decoder, but not the Info settings from the Info structs. -*/ -typedef struct LodePNGDecoderSettings -{ - LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ - - unsigned ignore_crc; /*ignore CRC checksums*/ - /* - The fix_png setting, if 1, makes the decoder tolerant towards some PNG images - that do not correctly follow the PNG specification. This only supports errors - that are fixable, were found in images that are actually used on the web, and - are silently tolerated by other decoders as well. Currently only one such fix - is implemented: if a palette index is out of bounds given the palette size, - interpret it as opaque black. - By default this value is 0, which makes it stop with an error on such images. - */ - unsigned fix_png; - unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ - -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ - /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ - unsigned remember_unknown_chunks; -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ -} LodePNGDecoderSettings; - -void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); -#endif /*LODEPNG_COMPILE_DECODER*/ - -#ifdef LODEPNG_COMPILE_ENCODER -/*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/ -typedef enum LodePNGFilterStrategy -{ - /*every filter at zero*/ - LFS_ZERO, - /*Use filter that gives minumum sum, as described in the official PNG filter heuristic.*/ - LFS_MINSUM, - /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending - on the image, this is better or worse than minsum.*/ - LFS_ENTROPY, - /* - Brute-force-search PNG filters by compressing each filter for each scanline. - Experimental, very slow, and only rarely gives better compression than MINSUM. - */ - LFS_BRUTE_FORCE, - /*use predefined_filters buffer: you specify the filter type for each scanline*/ - LFS_PREDEFINED -} LodePNGFilterStrategy; - -/*automatically use color type with less bits per pixel if losslessly possible. Default: LAC_AUTO*/ -typedef enum LodePNGAutoConvert -{ - LAC_NO, /*use color type user requested*/ - LAC_ALPHA, /*use color type user requested, but if only opaque pixels and RGBA or grey+alpha, use RGB or grey*/ - LAC_AUTO, /*use PNG color type that can losslessly represent the uncompressed image the smallest possible*/ - /* - like AUTO, but do not choose 1, 2 or 4 bit per pixel types. - sometimes a PNG image compresses worse if less than 8 bits per pixels. - */ - LAC_AUTO_NO_NIBBLES, - /* - like AUTO, but never choose palette color type. For small images, encoding - the palette may take more bytes than what is gained. Note that AUTO also - already prevents encoding the palette for extremely small images, but that may - not be sufficient because due to the compression it cannot predict when to - switch. - */ - LAC_AUTO_NO_PALETTE, - LAC_AUTO_NO_NIBBLES_NO_PALETTE -} LodePNGAutoConvert; - - -/* -Automatically chooses color type that gives smallest amount of bits in the -output image, e.g. grey if there are only greyscale pixels, palette if there -are less than 256 colors, ... -The auto_convert parameter allows limiting it to not use palette, ... -*/ -unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, - const unsigned char* image, unsigned w, unsigned h, - const LodePNGColorMode* mode_in, - LodePNGAutoConvert auto_convert); - -/*Settings for the encoder.*/ -typedef struct LodePNGEncoderSettings -{ - LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ - - LodePNGAutoConvert auto_convert; /*how to automatically choose output PNG color type, if at all*/ - - /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than - 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to - completely follow the official PNG heuristic, filter_palette_zero must be true and - filter_strategy must be LFS_MINSUM*/ - unsigned filter_palette_zero; - /*Which filter strategy to use when not using zeroes due to filter_palette_zero. - Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ - LodePNGFilterStrategy filter_strategy; - /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with - the same length as the amount of scanlines in the image, and each value must <= 5. You - have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero - must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ - const unsigned char* predefined_filters; - - /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). - If colortype is 3, PLTE is _always_ created.*/ - unsigned force_palette; -#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - /*add LodePNG identifier and version as a text chunk, for debugging*/ - unsigned add_id; - /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ - unsigned text_compression; -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ -} LodePNGEncoderSettings; - -void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); -#endif /*LODEPNG_COMPILE_ENCODER*/ - - -#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) -/*The settings, state and information for extended encoding and decoding.*/ -typedef struct LodePNGState -{ -#ifdef LODEPNG_COMPILE_DECODER - LodePNGDecoderSettings decoder; /*the decoding settings*/ -#endif /*LODEPNG_COMPILE_DECODER*/ -#ifdef LODEPNG_COMPILE_ENCODER - LodePNGEncoderSettings encoder; /*the encoding settings*/ -#endif /*LODEPNG_COMPILE_ENCODER*/ - LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ - LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ - unsigned error; -#ifdef LODEPNG_COMPILE_CPP - //For the lodepng::State subclass. - virtual ~LodePNGState(){} -#endif -} LodePNGState; - -/*init, cleanup and copy functions to use with this struct*/ -void lodepng_state_init(LodePNGState* state); -void lodepng_state_cleanup(LodePNGState* state); -void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); -#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ - -#ifdef LODEPNG_COMPILE_DECODER -/* -Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and -getting much more information about the PNG image and color mode. -*/ -unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, - LodePNGState* state, - const unsigned char* in, size_t insize); - -/* -Read the PNG header, but not the actual data. This returns only the information -that is in the header chunk of the PNG, such as width, height and color type. The -information is placed in the info_png field of the LodePNGState. -*/ -unsigned lodepng_inspect(unsigned* w, unsigned* h, - LodePNGState* state, - const unsigned char* in, size_t insize); -#endif /*LODEPNG_COMPILE_DECODER*/ - - -#ifdef LODEPNG_COMPILE_ENCODER -/*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ -unsigned lodepng_encode(unsigned char** out, size_t* outsize, - const unsigned char* image, unsigned w, unsigned h, - LodePNGState* state); -#endif /*LODEPNG_COMPILE_ENCODER*/ - -/* -The lodepng_chunk functions are normally not needed, except to traverse the -unknown chunks stored in the LodePNGInfo struct, or add new ones to it. -It also allows traversing the chunks of an encoded PNG file yourself. - -PNG standard chunk naming conventions: -First byte: uppercase = critical, lowercase = ancillary -Second byte: uppercase = public, lowercase = private -Third byte: must be uppercase -Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy -*/ - -/*get the length of the data of the chunk. Total chunk length has 12 bytes more.*/ -unsigned lodepng_chunk_length(const unsigned char* chunk); - -/*puts the 4-byte type in null terminated string*/ -void lodepng_chunk_type(char type[5], const unsigned char* chunk); - -/*check if the type is the given type*/ -unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); - -/*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ -unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); - -/*0: public, 1: private (see PNG standard)*/ -unsigned char lodepng_chunk_private(const unsigned char* chunk); - -/*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ -unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); - -/*get pointer to the data of the chunk, where the input points to the header of the chunk*/ -unsigned char* lodepng_chunk_data(unsigned char* chunk); -const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); - -/*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ -unsigned lodepng_chunk_check_crc(const unsigned char* chunk); - -/*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ -void lodepng_chunk_generate_crc(unsigned char* chunk); - -/*iterate to next chunks. don't use on IEND chunk, as there is no next chunk then*/ -unsigned char* lodepng_chunk_next(unsigned char* chunk); -const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk); - -/* -Appends chunk to the data in out. The given chunk should already have its chunk header. -The out variable and outlength are updated to reflect the new reallocated buffer. -Returns error code (0 if it went ok) -*/ -unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk); - -/* -Appends new chunk to out. The chunk to append is given by giving its length, type -and data separately. The type is a 4-letter string. -The out variable and outlength are updated to reflect the new reallocated buffer. -Returne error code (0 if it went ok) -*/ -unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, - const char* type, const unsigned char* data); - - -/*Calculate CRC32 of buffer*/ -unsigned lodepng_crc32(const unsigned char* buf, size_t len); -#endif /*LODEPNG_COMPILE_PNG*/ - - -#ifdef LODEPNG_COMPILE_ZLIB -/* -This zlib part can be used independently to zlib compress and decompress a -buffer. It cannot be used to create gzip files however, and it only supports the -part of zlib that is required for PNG, it does not support dictionaries. -*/ - -#ifdef LODEPNG_COMPILE_DECODER -/*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ -unsigned lodepng_inflate(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, - const LodePNGDecompressSettings* settings); - -/* -Decompresses Zlib data. Reallocates the out buffer and appends the data. The -data must be according to the zlib specification. -Either, *out must be NULL and *outsize must be 0, or, *out must be a valid -buffer and *outsize its size in bytes. out must be freed by user after usage. -*/ -unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, - const LodePNGDecompressSettings* settings); -#endif /*LODEPNG_COMPILE_DECODER*/ - -#ifdef LODEPNG_COMPILE_ENCODER -/* -Compresses data with Zlib. Reallocates the out buffer and appends the data. -Zlib adds a small header and trailer around the deflate data. -The data is output in the format of the zlib specification. -Either, *out must be NULL and *outsize must be 0, or, *out must be a valid -buffer and *outsize its size in bytes. out must be freed by user after usage. -*/ -unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, - const LodePNGCompressSettings* settings); - -/* -Find length-limited Huffman code for given frequencies. This function is in the -public interface only for tests, it's used internally by lodepng_deflate. -*/ -unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, - size_t numcodes, unsigned maxbitlen); - -/*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ -unsigned lodepng_deflate(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, - const LodePNGCompressSettings* settings); - -#endif /*LODEPNG_COMPILE_ENCODER*/ -#endif /*LODEPNG_COMPILE_ZLIB*/ - -#ifdef LODEPNG_COMPILE_DISK -/* -Load a file from disk into buffer. The function allocates the out buffer, and -after usage you should free it. -out: output parameter, contains pointer to loaded buffer. -outsize: output parameter, size of the allocated out buffer -filename: the path to the file to load -return value: error code (0 means ok) -*/ -unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); - -/* -Save a file from buffer to disk. Warning, if it exists, this function overwrites -the file without warning! -buffer: the buffer to write -buffersize: size of the buffer to write -filename: the path to the file to save to -return value: error code (0 means ok) -*/ -unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); -#endif /*LODEPNG_COMPILE_DISK*/ - -#ifdef LODEPNG_COMPILE_CPP -//The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. -namespace lodepng -{ -#ifdef LODEPNG_COMPILE_PNG -class State : public LodePNGState -{ - public: - State(); - State(const State& other); - virtual ~State(); - State& operator=(const State& other); -}; - -#ifdef LODEPNG_COMPILE_DECODER -//Same as other lodepng::decode, but using a State for more settings and information. -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - State& state, - const unsigned char* in, size_t insize); -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - State& state, - const std::vector& in); -#endif /*LODEPNG_COMPILE_DECODER*/ - -#ifdef LODEPNG_COMPILE_ENCODER -//Same as other lodepng::encode, but using a State for more settings and information. -unsigned encode(std::vector& out, - const unsigned char* in, unsigned w, unsigned h, - State& state); -unsigned encode(std::vector& out, - const std::vector& in, unsigned w, unsigned h, - State& state); -#endif /*LODEPNG_COMPILE_ENCODER*/ - -#ifdef LODEPNG_COMPILE_DISK -/* -Load a file from disk into an std::vector. If the vector is empty, then either -the file doesn't exist or is an empty file. -*/ -void load_file(std::vector& buffer, const std::string& filename); - -/* -Save the binary data in an std::vector to a file on disk. The file is overwritten -without warning. -*/ -void save_file(const std::vector& buffer, const std::string& filename); -#endif //LODEPNG_COMPILE_DISK -#endif //LODEPNG_COMPILE_PNG - -#ifdef LODEPNG_COMPILE_ZLIB -#ifdef LODEPNG_COMPILE_DECODER -//Zlib-decompress an unsigned char buffer -unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, - const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); - -//Zlib-decompress an std::vector -unsigned decompress(std::vector& out, const std::vector& in, - const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); -#endif //LODEPNG_COMPILE_DECODER - -#ifdef LODEPNG_COMPILE_ENCODER -//Zlib-compress an unsigned char buffer -unsigned compress(std::vector& out, const unsigned char* in, size_t insize, - const LodePNGCompressSettings& settings = lodepng_default_compress_settings); - -//Zlib-compress an std::vector -unsigned compress(std::vector& out, const std::vector& in, - const LodePNGCompressSettings& settings = lodepng_default_compress_settings); -#endif //LODEPNG_COMPILE_ENCODER -#endif //LODEPNG_COMPILE_ZLIB -} //namespace lodepng -#endif /*LODEPNG_COMPILE_CPP*/ - -/* -TODO: -[.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often -[.] check compatibility with vareous compilers - done but needs to be redone for every newer version -[X] converting color to 16-bit per channel types -[ ] read all public PNG chunk types (but never let the color profile and gamma ones touch RGB values) -[ ] make sure encoder generates no chunks with size > (2^31)-1 -[ ] partial decoding (stream processing) -[X] let the "isFullyOpaque" function check color keys and transparent palettes too -[X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" -[ ] don't stop decoding on errors like 69, 57, 58 (make warnings) -[ ] make option to choose if the raw image with non multiple of 8 bits per scanline should have padding bits or not -[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes -*/ - -#endif /*LODEPNG_H inclusion guard*/ - -/* -LodePNG Documentation ---------------------- - -0. table of contents --------------------- - - 1. about - 1.1. supported features - 1.2. features not supported - 2. C and C++ version - 3. security - 4. decoding - 5. encoding - 6. color conversions - 6.1. PNG color types - 6.2. color conversions - 6.3. padding bits - 6.4. A note about 16-bits per channel and endianness - 7. error values - 8. chunks and PNG editing - 9. compiler support - 10. examples - 10.1. decoder C++ example - 10.2. decoder C example - 11. changes - 12. contact information - - -1. about --------- - -PNG is a file format to store raster images losslessly with good compression, -supporting different color types and alpha channel. - -LodePNG is a PNG codec according to the Portable Network Graphics (PNG) -Specification (Second Edition) - W3C Recommendation 10 November 2003. - -The specifications used are: - -*) Portable Network Graphics (PNG) Specification (Second Edition): - http://www.w3.org/TR/2003/REC-PNG-20031110 -*) RFC 1950 ZLIB Compressed Data Format version 3.3: - http://www.gzip.org/zlib/rfc-zlib.html -*) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: - http://www.gzip.org/zlib/rfc-deflate.html - -The most recent version of LodePNG can currently be found at -http://lodev.org/lodepng/ - -LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds -extra functionality. - -LodePNG exists out of two files: --lodepng.h: the header file for both C and C++ --lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage - -If you want to start using LodePNG right away without reading this doc, get the -examples from the LodePNG website to see how to use it in code, or check the -smaller examples in chapter 13 here. - -LodePNG is simple but only supports the basic requirements. To achieve -simplicity, the following design choices were made: There are no dependencies -on any external library. There are functions to decode and encode a PNG with -a single function call, and extended versions of these functions taking a -LodePNGState struct allowing to specify or get more information. By default -the colors of the raw image are always RGB or RGBA, no matter what color type -the PNG file uses. To read and write files, there are simple functions to -convert the files to/from buffers in memory. - -This all makes LodePNG suitable for loading textures in games, demos and small -programs, ... It's less suitable for full fledged image editors, loading PNGs -over network (it requires all the image data to be available before decoding can -begin), life-critical systems, ... - -1.1. supported features ------------------------ - -The following features are supported by the decoder: - -*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, - or the same color type as the PNG -*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image -*) Adam7 interlace and deinterlace for any color type -*) loading the image from harddisk or decoding it from a buffer from other sources than harddisk -*) support for alpha channels, including RGBA color model, translucent palettes and color keying -*) zlib decompression (inflate) -*) zlib compression (deflate) -*) CRC32 and ADLER32 checksums -*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. -*) the following chunks are supported (generated/interpreted) by both encoder and decoder: - IHDR: header information - PLTE: color palette - IDAT: pixel data - IEND: the final chunk - tRNS: transparency for palettized images - tEXt: textual information - zTXt: compressed textual information - iTXt: international textual information - bKGD: suggested background color - pHYs: physical dimensions - tIME: modification time - -1.2. features not supported ---------------------------- - -The following features are _not_ supported: - -*) some features needed to make a conformant PNG-Editor might be still missing. -*) partial loading/stream processing. All data must be available and is processed in one call. -*) The following public chunks are not supported but treated as unknown chunks by LodePNG - cHRM, gAMA, iCCP, sRGB, sBIT, hIST, sPLT - Some of these are not supported on purpose: LodePNG wants to provide the RGB values - stored in the pixels, not values modified by system dependent gamma or color models. - - -2. C and C++ version --------------------- - -The C version uses buffers allocated with alloc that you need to free() -yourself. You need to use init and cleanup functions for each struct whenever -using a struct from the C version to avoid exploits and memory leaks. - -The C++ version has extra functions with std::vectors in the interface and the -lodepng::State class which is a LodePNGState with constructor and destructor. - -These files work without modification for both C and C++ compilers because all -the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers -ignore it, and the C code is made to compile both with strict ISO C90 and C++. - -To use the C++ version, you need to rename the source file to lodepng.cpp -(instead of lodepng.c), and compile it with a C++ compiler. - -To use the C version, you need to rename the source file to lodepng.c (instead -of lodepng.cpp), and compile it with a C compiler. - - -3. Security ------------ - -Even if carefully designed, it's always possible that LodePNG contains possible -exploits. If you discover one, please let me know, and it will be fixed. - -When using LodePNG, care has to be taken with the C version of LodePNG, as well -as the C-style structs when working with C++. The following conventions are used -for all C-style structs: - --if a struct has a corresponding init function, always call the init function when making a new one --if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks --if a struct has a corresponding copy function, use the copy function instead of "=". - The destination must also be inited already. - - -4. Decoding ------------ - -Decoding converts a PNG compressed image to a raw pixel buffer. - -Most documentation on using the decoder is at its declarations in the header -above. For C, simple decoding can be done with functions such as -lodepng_decode32, and more advanced decoding can be done with the struct -LodePNGState and lodepng_decode. For C++, all decoding can be done with the -various lodepng::decode functions, and lodepng::State can be used for advanced -features. - -When using the LodePNGState, it uses the following fields for decoding: -*) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here -*) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get -*) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use - -LodePNGInfo info_png --------------------- - -After decoding, this contains extra information of the PNG image, except the actual -pixels, width and height because these are already gotten directly from the decoder -functions. - -It contains for example the original color type of the PNG image, text comments, -suggested background color, etc... More details about the LodePNGInfo struct are -at its declaration documentation. - -LodePNGColorMode info_raw -------------------------- - -When decoding, here you can specify which color type you want -the resulting raw image to be. If this is different from the colortype of the -PNG, then the decoder will automatically convert the result. This conversion -always works, except if you want it to convert a color PNG to greyscale or to -a palette with missing colors. - -By default, 32-bit color is used for the result. - -LodePNGDecoderSettings decoder ------------------------------- - -The settings can be used to ignore the errors created by invalid CRC and Adler32 -chunks, and to disable the decoding of tEXt chunks. - -There's also a setting color_convert, true by default. If false, no conversion -is done, the resulting data will be as it was in the PNG (after decompression) -and you'll have to puzzle the colors of the pixels together yourself using the -color type information in the LodePNGInfo. - - -5. Encoding ------------ - -Encoding converts a raw pixel buffer to a PNG compressed image. - -Most documentation on using the encoder is at its declarations in the header -above. For C, simple encoding can be done with functions such as -lodepng_encode32, and more advanced decoding can be done with the struct -LodePNGState and lodepng_encode. For C++, all encoding can be done with the -various lodepng::encode functions, and lodepng::State can be used for advanced -features. - -Like the decoder, the encoder can also give errors. However it gives less errors -since the encoder input is trusted, the decoder input (a PNG image that could -be forged by anyone) is not trusted. - -When using the LodePNGState, it uses the following fields for encoding: -*) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. -*) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has -*) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use - -LodePNGInfo info_png --------------------- - -When encoding, you use this the opposite way as when decoding: for encoding, -you fill in the values you want the PNG to have before encoding. By default it's -not needed to specify a color type for the PNG since it's automatically chosen, -but it's possible to choose it yourself given the right settings. - -The encoder will not always exactly match the LodePNGInfo struct you give, -it tries as close as possible. Some things are ignored by the encoder. The -encoder uses, for example, the following settings from it when applicable: -colortype and bitdepth, text chunks, time chunk, the color key, the palette, the -background color, the interlace method, unknown chunks, ... - -When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk. -If the palette contains any colors for which the alpha channel is not 255 (so -there are translucent colors in the palette), it'll add a tRNS chunk. - -LodePNGColorMode info_raw -------------------------- - -You specify the color type of the raw image that you give to the input here, -including a possible transparent color key and palette you happen to be using in -your raw image data. - -By default, 32-bit color is assumed, meaning your input has to be in RGBA -format with 4 bytes (unsigned chars) per pixel. - -LodePNGEncoderSettings encoder ------------------------------- - -The following settings are supported (some are in sub-structs): -*) auto_convert: when this option is enabled, the encoder will -automatically choose the smallest possible color mode (including color key) that -can encode the colors of all pixels without information loss. -*) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, - 2 = dynamic huffman tree (best compression). Should be 2 for proper - compression. -*) use_lz77: whether or not to use LZ77 for compressed block types. Should be - true for proper compression. -*) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value - 2048 by default, but can be set to 32768 for better, but slow, compression. -*) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE - chunk if force_palette is true. This can used as suggested palette to convert - to by viewers that don't support more than 256 colors (if those still exist) -*) add_id: add text chunk "Encoder: LodePNG " to the image. -*) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. - zTXt chunks use zlib compression on the text. This gives a smaller result on - large texts but a larger result on small texts (such as a single program name). - It's all tEXt or all zTXt though, there's no separate setting per text yet. - - -6. color conversions --------------------- - -An important thing to note about LodePNG, is that the color type of the PNG, and -the color type of the raw image, are completely independent. By default, when -you decode a PNG, you get the result as a raw image in the color type you want, -no matter whether the PNG was encoded with a palette, greyscale or RGBA color. -And if you encode an image, by default LodePNG will automatically choose the PNG -color type that gives good compression based on the values of colors and amount -of colors in the image. It can be configured to let you control it instead as -well, though. - -To be able to do this, LodePNG does conversions from one color mode to another. -It can convert from almost any color type to any other color type, except the -following conversions: RGB to greyscale is not supported, and converting to a -palette when the palette doesn't have a required color is not supported. This is -not supported on purpose: this is information loss which requires a color -reduction algorithm that is beyong the scope of a PNG encoder (yes, RGB to grey -is easy, but there are multiple ways if you want to give some channels more -weight). - -By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB -color, no matter what color type the PNG has. And by default when encoding, -LodePNG automatically picks the best color model for the output PNG, and expects -the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control -the color format of the images yourself, you can skip this chapter. - -6.1. PNG color types --------------------- - -A PNG image can have many color types, ranging from 1-bit color to 64-bit color, -as well as palettized color modes. After the zlib decompression and unfiltering -in the PNG image is done, the raw pixel data will have that color type and thus -a certain amount of bits per pixel. If you want the output raw image after -decoding to have another color type, a conversion is done by LodePNG. - -The PNG specification gives the following color types: - -0: greyscale, bit depths 1, 2, 4, 8, 16 -2: RGB, bit depths 8 and 16 -3: palette, bit depths 1, 2, 4 and 8 -4: greyscale with alpha, bit depths 8 and 16 -6: RGBA, bit depths 8 and 16 - -Bit depth is the amount of bits per pixel per color channel. So the total amount -of bits per pixel is: amount of channels * bitdepth. - -6.2. color conversions ----------------------- - -As explained in the sections about the encoder and decoder, you can specify -color types and bit depths in info_png and info_raw to change the default -behaviour. - -If, when decoding, you want the raw image to be something else than the default, -you need to set the color type and bit depth you want in the LodePNGColorMode, -or the parameters of the simple function of LodePNG you're using. - -If, when encoding, you use another color type than the default in the input -image, you need to specify its color type and bit depth in the LodePNGColorMode -of the raw image, or use the parameters of the simplefunction of LodePNG you're -using. - -If, when encoding, you don't want LodePNG to choose the output PNG color type -but control it yourself, you need to set auto_convert in the encoder settings -to LAC_NONE, and specify the color type you want in the LodePNGInfo of the -encoder. - -If you do any of the above, LodePNG may need to do a color conversion, which -follows the rules below, and may sometimes not be allowed. - -To avoid some confusion: --the decoder converts from PNG to raw image --the encoder converts from raw image to PNG --the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image --the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG --when encoding, the color type in LodePNGInfo is ignored if auto_convert - is enabled, it is automatically generated instead --when decoding, the color type in LodePNGInfo is set by the decoder to that of the original - PNG image, but it can be ignored since the raw image has the color type you requested instead --if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion - between the color types is done if the color types are supported. If it is not - supported, an error is returned. If the types are the same, no conversion is done. --even though some conversions aren't supported, LodePNG supports loading PNGs from any - colortype and saving PNGs to any colortype, sometimes it just requires preparing - the raw image correctly before encoding. --both encoder and decoder use the same color converter. - -Non supported color conversions: --color to greyscale: no error is thrown, but the result will look ugly because -only the red channel is taken --anything, to palette when that palette does not have that color in it: in this -case an error is thrown - -Supported color conversions: --anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA --any grey or grey+alpha, to grey or grey+alpha --anything to a palette, as long as the palette has the requested colors in it --removing alpha channel --higher to smaller bitdepth, and vice versa - -If you want no color conversion to be done: --In the encoder, you can make it save a PNG with any color type by giving the -raw color mode and LodePNGInfo the same color mode, and setting auto_convert to -LAC_NO. --In the decoder, you can make it store the pixel data in the same color type -as the PNG has, by setting the color_convert setting to false. Settings in -info_raw are then ignored. - -The function lodepng_convert does the color conversion. It is available in the -interface but normally isn't needed since the encoder and decoder already call -it. - -6.3. padding bits ------------------ - -In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines -have a bit amount that isn't a multiple of 8, then padding bits are used so that each -scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. -The raw input image you give to the encoder, and the raw output image you get from the decoder -will NOT have these padding bits, e.g. in the case of a 1-bit image with a width -of 7 pixels, the first pixel of the second scanline will the the 8th bit of the first byte, -not the first bit of a new byte. - -6.4. A note about 16-bits per channel and endianness ----------------------------------------------------- - -LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like -for any other color format. The 16-bit values are stored in big endian (most -significant byte first) in these arrays. This is the opposite order of the -little endian used by x86 CPU's. - -LodePNG always uses big endian because the PNG file format does so internally. -Conversions to other formats than PNG uses internally are not supported by -LodePNG on purpose, there are myriads of formats, including endianness of 16-bit -colors, the order in which you store R, G, B and A, and so on. Supporting and -converting to/from all that is outside the scope of LodePNG. - -This may mean that, depending on your use case, you may want to convert the big -endian output of LodePNG to little endian with a for loop. This is certainly not -always needed, many applications and libraries support big endian 16-bit colors -anyway, but it means you cannot simply cast the unsigned char* buffer to an -unsigned short* buffer on x86 CPUs. - - -7. error values ---------------- - -All functions in LodePNG that return an error code, return 0 if everything went -OK, or a non-zero code if there was an error. - -The meaning of the LodePNG error values can be retrieved with the function -lodepng_error_text: given the numerical error code, it returns a description -of the error in English as a string. - -Check the implementation of lodepng_error_text to see the meaning of each code. - - -8. chunks and PNG editing -------------------------- - -If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG -editor that should follow the rules about handling of unknown chunks, or if your -program is able to read other types of chunks than the ones handled by LodePNG, -then that's possible with the chunk functions of LodePNG. - -A PNG chunk has the following layout: - -4 bytes length -4 bytes type name -length bytes data -4 bytes CRC - -8.1. iterating through chunks ------------------------------ - -If you have a buffer containing the PNG image data, then the first chunk (the -IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the -signature of the PNG and are not part of a chunk. But if you start at byte 8 -then you have a chunk, and can check the following things of it. - -NOTE: none of these functions check for memory buffer boundaries. To avoid -exploits, always make sure the buffer contains all the data of the chunks. -When using lodepng_chunk_next, make sure the returned value is within the -allocated memory. - -unsigned lodepng_chunk_length(const unsigned char* chunk): - -Get the length of the chunk's data. The total chunk length is this length + 12. - -void lodepng_chunk_type(char type[5], const unsigned char* chunk): -unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): - -Get the type of the chunk or compare if it's a certain type - -unsigned char lodepng_chunk_critical(const unsigned char* chunk): -unsigned char lodepng_chunk_private(const unsigned char* chunk): -unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): - -Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). -Check if the chunk is private (public chunks are part of the standard, private ones not). -Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical -chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your -program doesn't handle that type of unknown chunk. - -unsigned char* lodepng_chunk_data(unsigned char* chunk): -const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): - -Get a pointer to the start of the data of the chunk. - -unsigned lodepng_chunk_check_crc(const unsigned char* chunk): -void lodepng_chunk_generate_crc(unsigned char* chunk): - -Check if the crc is correct or generate a correct one. - -unsigned char* lodepng_chunk_next(unsigned char* chunk): -const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): - -Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these -functions do no boundary checking of the allocated data whatsoever, so make sure there is enough -data available in the buffer to be able to go to the next chunk. - -unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk): -unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, - const char* type, const unsigned char* data): - -These functions are used to create new chunks that are appended to the data in *out that has -length *outlength. The append function appends an existing chunk to the new data. The create -function creates a new chunk with the given parameters and appends it. Type is the 4-letter -name of the chunk. - -8.2. chunks in info_png ------------------------ - -The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3 -buffers (each with size) to contain 3 types of unknown chunks: -the ones that come before the PLTE chunk, the ones that come between the PLTE -and the IDAT chunks, and the ones that come after the IDAT chunks. -It's necessary to make the distionction between these 3 cases because the PNG -standard forces to keep the ordering of unknown chunks compared to the critical -chunks, but does not force any other ordering rules. - -info_png.unknown_chunks_data[0] is the chunks before PLTE -info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT -info_png.unknown_chunks_data[2] is the chunks after IDAT - -The chunks in these 3 buffers can be iterated through and read by using the same -way described in the previous subchapter. - -When using the decoder to decode a PNG, you can make it store all unknown chunks -if you set the option settings.remember_unknown_chunks to 1. By default, this -option is off (0). - -The encoder will always encode unknown chunks that are stored in the info_png. -If you need it to add a particular chunk that isn't known by LodePNG, you can -use lodepng_chunk_append or lodepng_chunk_create to the chunk data in -info_png.unknown_chunks_data[x]. - -Chunks that are known by LodePNG should not be added in that way. E.g. to make -LodePNG add a bKGD chunk, set background_defined to true and add the correct -parameters there instead. - - -9. compiler support -------------------- - -No libraries other than the current standard C library are needed to compile -LodePNG. For the C++ version, only the standard C++ library is needed on top. -Add the files lodepng.c(pp) and lodepng.h to your project, include -lodepng.h where needed, and your program can read/write PNG files. - -If performance is important, use optimization when compiling! For both the -encoder and decoder, this makes a large difference. - -Make sure that LodePNG is compiled with the same compiler of the same version -and with the same settings as the rest of the program, or the interfaces with -std::vectors and std::strings in C++ can be incompatible. - -CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. - -*) gcc and g++ - -LodePNG is developed in gcc so this compiler is natively supported. It gives no -warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ -version 4.7.1 on Linux, 32-bit and 64-bit. - -*) Mingw - -The Mingw compiler (a port of gcc) for Windows is fully supported by LodePNG. - -*) Visual Studio 2005 and up, Visual C++ Express Edition 2005 and up - -Visual Studio may give warnings about 'fopen' being deprecated. A multiplatform library -can't support the proposed Visual Studio alternative however, so LodePNG keeps using -fopen. If you don't want to see the deprecated warnings, put this on top of lodepng.h -before the inclusions: -#define _CRT_SECURE_NO_DEPRECATE - -Other than the above warnings, LodePNG should be warning-free with warning -level 3 (W3). Warning level 4 (W4) will give warnings about integer conversions. -I'm not planning to resolve these warnings. To get rid of them, let Visual -Studio use warning level W3 for lodepng.cpp only: right click lodepng.cpp, -Properties, C/C++, General, Warning Level: Level 3 (/W3). - -Visual Studio may want "stdafx.h" files to be included in each source file and -give an error "unexpected end of file while looking for precompiled header". -That is not standard C++ and will not be added to the stock LodePNG. You can -disable it for lodepng.cpp only by right clicking it, Properties, C/C++, -Precompiled Headers, and set it to Not Using Precompiled Headers there. - -*) Visual Studio 6.0 - -LodePNG support for Visual Studio 6.0 is not guaranteed because VS6 doesn't -follow the C++ standard correctly. - -*) Comeau C/C++ - -Vesion 20070107 compiles without problems on the Comeau C/C++ Online Test Drive -at http://www.comeaucomputing.com/tryitout in both C90 and C++ mode. - -*) Compilers on Macintosh - -LodePNG has been reported to work both with the gcc and LLVM for Macintosh, both -for C and C++. - -*) Other Compilers - -If you encounter problems on other compilers, feel free to let me know and I may -try to fix it if the compiler is modern standards complient. - - -10. examples ------------- - -This decoder example shows the most basic usage of LodePNG. More complex -examples can be found on the LodePNG website. - -10.1. decoder C++ example -------------------------- - -#include "lodepng.h" -#include - -int main(int argc, char *argv[]) -{ - const char* filename = argc > 1 ? argv[1] : "test.png"; - - //load and decode - std::vector image; - unsigned width, height; - unsigned error = lodepng::decode(image, width, height, filename); - - //if there's an error, display it - if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; - - //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... -} - -10.2. decoder C example ------------------------ - -#include "lodepng.h" - -int main(int argc, char *argv[]) -{ - unsigned error; - unsigned char* image; - size_t width, height; - const char* filename = argc > 1 ? argv[1] : "test.png"; - - error = lodepng_decode32_file(&image, &width, &height, filename); - - if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error)); - - / * use image here * / - - free(image); - return 0; -} - - -11. changes ------------ - -The version number of LodePNG is the date of the change given in the format -yyyymmdd. - -Some changes aren't backwards compatible. Those are indicated with a (!) -symbol. - -*) 22 dec 2013: Power of two windowsize required for optimization. -*) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. -*) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). -*) 11 mar 2013 (!): Bugfix with custom free. Changed from "my" to "lodepng_" - prefix for the custom allocators and made it possible with a new #define to - use custom ones in your project without needing to change lodepng's code. -*) 28 jan 2013: Bugfix with color key. -*) 27 okt 2012: Tweaks in text chunk keyword length error handling. -*) 8 okt 2012 (!): Added new filter strategy (entropy) and new auto color mode. - (no palette). Better deflate tree encoding. New compression tweak settings. - Faster color conversions while decoding. Some internal cleanups. -*) 23 sep 2012: Reduced warnings in Visual Studio a little bit. -*) 1 sep 2012 (!): Removed #define's for giving custom (de)compression functions - and made it work with function pointers instead. -*) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc - and free functions and toggle #defines from compiler flags. Small fixes. -*) 6 may 2012 (!): Made plugging in custom zlib/deflate functions more flexible. -*) 22 apr 2012 (!): Made interface more consistent, renaming a lot. Removed - redundant C++ codec classes. Reduced amount of structs. Everything changed, - but it is cleaner now imho and functionality remains the same. Also fixed - several bugs and shrinked the implementation code. Made new samples. -*) 6 nov 2011 (!): By default, the encoder now automatically chooses the best - PNG color model and bit depth, based on the amount and type of colors of the - raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color. -*) 9 okt 2011: simpler hash chain implementation for the encoder. -*) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching. -*) 23 aug 2011: tweaked the zlib compression parameters after benchmarking. - A bug with the PNG filtertype heuristic was fixed, so that it chooses much - better ones (it's quite significant). A setting to do an experimental, slow, - brute force search for PNG filter types is added. -*) 17 aug 2011 (!): changed some C zlib related function names. -*) 16 aug 2011: made the code less wide (max 120 characters per line). -*) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors. -*) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled. -*) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman - to optimize long sequences of zeros. -*) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and - LodePNG_InfoColor_canHaveAlpha functions for convenience. -*) 7 nov 2010: added LodePNG_error_text function to get error code description. -*) 30 okt 2010: made decoding slightly faster -*) 26 okt 2010: (!) changed some C function and struct names (more consistent). - Reorganized the documentation and the declaration order in the header. -*) 08 aug 2010: only changed some comments and external samples. -*) 05 jul 2010: fixed bug thanks to warnings in the new gcc version. -*) 14 mar 2010: fixed bug where too much memory was allocated for char buffers. -*) 02 sep 2008: fixed bug where it could create empty tree that linux apps could - read by ignoring the problem but windows apps couldn't. -*) 06 jun 2008: added more error checks for out of memory cases. -*) 26 apr 2008: added a few more checks here and there to ensure more safety. -*) 06 mar 2008: crash with encoding of strings fixed -*) 02 feb 2008: support for international text chunks added (iTXt) -*) 23 jan 2008: small cleanups, and #defines to divide code in sections -*) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. -*) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. -*) 17 jan 2008: ability to encode and decode compressed zTXt chunks added - Also vareous fixes, such as in the deflate and the padding bits code. -*) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved - filtering code of encoder. -*) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A - C++ wrapper around this provides an interface almost identical to before. - Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code - are together in these files but it works both for C and C++ compilers. -*) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks -*) 30 aug 2007: bug fixed which makes this Borland C++ compatible -*) 09 aug 2007: some VS2005 warnings removed again -*) 21 jul 2007: deflate code placed in new namespace separate from zlib code -*) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images -*) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing - invalid std::vector element [0] fixed, and level 3 and 4 warnings removed -*) 02 jun 2007: made the encoder add a tag with version by default -*) 27 may 2007: zlib and png code separated (but still in the same file), - simple encoder/decoder functions added for more simple usage cases -*) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), - moved some examples from here to lodepng_examples.cpp -*) 12 may 2007: palette decoding bug fixed -*) 24 apr 2007: changed the license from BSD to the zlib license -*) 11 mar 2007: very simple addition: ability to encode bKGD chunks. -*) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding - palettized PNG images. Plus little interface change with palette and texts. -*) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. - Fixed a bug where the end code of a block had length 0 in the Huffman tree. -*) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented - and supported by the encoder, resulting in smaller PNGs at the output. -*) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. -*) 24 jan 2007: gave encoder an error interface. Added color conversion from any - greyscale type to 8-bit greyscale with or without alpha. -*) 21 jan 2007: (!) Totally changed the interface. It allows more color types - to convert to and is more uniform. See the manual for how it works now. -*) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: - encode/decode custom tEXt chunks, separate classes for zlib & deflate, and - at last made the decoder give errors for incorrect Adler32 or Crc. -*) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. -*) 29 dec 2006: Added support for encoding images without alpha channel, and - cleaned out code as well as making certain parts faster. -*) 28 dec 2006: Added "Settings" to the encoder. -*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. - Removed some code duplication in the decoder. Fixed little bug in an example. -*) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. - Fixed a bug of the decoder with 16-bit per color. -*) 15 okt 2006: Changed documentation structure -*) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the - given image buffer, however for now it's not compressed. -*) 08 sep 2006: (!) Changed to interface with a Decoder class -*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different - way. Renamed decodePNG to decodePNGGeneric. -*) 29 jul 2006: (!) Changed the interface: image info is now returned as a - struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. -*) 28 jul 2006: Cleaned the code and added new error checks. - Corrected terminology "deflate" into "inflate". -*) 23 jun 2006: Added SDL example in the documentation in the header, this - example allows easy debugging by displaying the PNG and its transparency. -*) 22 jun 2006: (!) Changed way to obtain error value. Added - loadFile function for convenience. Made decodePNG32 faster. -*) 21 jun 2006: (!) Changed type of info vector to unsigned. - Changed position of palette in info vector. Fixed an important bug that - happened on PNGs with an uncompressed block. -*) 16 jun 2006: Internally changed unsigned into unsigned where - needed, and performed some optimizations. -*) 07 jun 2006: (!) Renamed functions to decodePNG and placed them - in LodePNG namespace. Changed the order of the parameters. Rewrote the - documentation in the header. Renamed files to lodepng.cpp and lodepng.h -*) 22 apr 2006: Optimized and improved some code -*) 07 sep 2005: (!) Changed to std::vector interface -*) 12 aug 2005: Initial release (C++, decoder only) - - -12. contact information ------------------------ - -Feel free to contact me with suggestions, problems, comments, ... concerning -LodePNG. If you encounter a PNG image that doesn't work properly with this -decoder, feel free to send it and I'll use it to find and fix the problem. - -My email address is (puzzle the account and domain together with an @ symbol): -Domain: gmail dot com. -Account: lode dot vandevenne. - - -Copyright (c) 2005-2013 Lode Vandevenne -*/ diff --git a/openrct2.exe b/openrct2.exe index 05cc265b46..e5cfa10d40 100644 Binary files a/openrct2.exe and b/openrct2.exe differ diff --git a/pre-build.ps1 b/pre-build.ps1 index 8dadd76d26..3e350d0c26 100644 --- a/pre-build.ps1 +++ b/pre-build.ps1 @@ -1,15 +1,34 @@ +#init +$libversion = 4 $path = Split-Path $Script:MyInvocation.MyCommand.Path -$zip = $path+'\lib\orcalibs.zip' +$zip = $path+'\orctlibs.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 +$libsVFile = $path+'\libversion' +$liburl = 'https://openrct2.website/files/orctlibs-vs.zip' +$libsTest = Test-Path $libs + +#libs version test +$libsVersionTest = Test-Path $libsVFile +$currentVersion = 0 +$needsdownload = $true +if ($libsVersionTest) { + $currentVersion = [IO.File]::ReadAllText($libsVFile) +} +if ($currentVersion -ge $libversion) { + $needsdownload = $false +} + +#download +if (!$libsTest -or $needsdownload) { + if ($libsTest) { + rm $libs -Recurse -Force + } + mkdir $libs + Invoke-WebRequest $liburl -OutFile $path\orctlibs.zip [System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') > $null [System.IO.Compression.ZipFile]::ExtractToDirectory($zip, $libs) - rm $path\lib\orcalibs.zip -Force -ErrorAction SilentlyContinue + rm $path\orctlibs.zip -Force -ErrorAction SilentlyContinue + $libversion | Set-Content $libsVFile +} else { + echo 'All libs up to date' } diff --git a/projects/language/language.vcxproj b/projects/language/language.vcxproj index b37e1107f4..071a041562 100644 --- a/projects/language/language.vcxproj +++ b/projects/language/language.vcxproj @@ -5,14 +5,18 @@ Debug Win32 - - Release with Tests - Win32 - Release Win32 + + Release XP + Win32 + + + Release with Tests + Win32 + {0468FC1E-5881-4DB9-9DDE-1892290B31D9} @@ -22,20 +26,27 @@ Utility true - v120 + v140 MultiByte Utility false - v120 + v140 + true + MultiByte + + + Utility + false + v140_xp true MultiByte Utility false - v120 + v140 true MultiByte @@ -48,6 +59,9 @@ + + + @@ -60,6 +74,10 @@ $(SolutionDir)..\build\$(Configuration)\ $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ + + $(SolutionDir)..\build\$(Configuration)\ + $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ + $(SolutionDir)..\build\Release\ $(SolutionDir)..\obj\$(ProjectName)\Release\ @@ -73,6 +91,9 @@ true + + xcopy /Y "$(SolutionDir)\..\Data\Language\*.*" "$(TargetDir)\Data\Language\" + @@ -91,6 +112,23 @@ xcopy /Y "$(SolutionDir)\..\Data\Language\*.*" "$(TargetDir)\Data\Language\" + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + xcopy /Y "$(SolutionDir)\..\Data\Language\*.*" "$(TargetDir)\Data\Language\" + + Level3 @@ -109,6 +147,7 @@ + diff --git a/projects/language/language.vcxproj.filters b/projects/language/language.vcxproj.filters index 0c3b4d393c..6810d604ae 100644 --- a/projects/language/language.vcxproj.filters +++ b/projects/language/language.vcxproj.filters @@ -37,5 +37,8 @@ Resource Files\Language + + Resource Files\Language + \ No newline at end of file diff --git a/projects/libs/libs.vcxproj b/projects/libs/libs.vcxproj index c1ae556f71..aa57182937 100644 --- a/projects/libs/libs.vcxproj +++ b/projects/libs/libs.vcxproj @@ -5,14 +5,18 @@ Debug Win32 - - Release with Tests - Win32 - Release Win32 + + Release XP + Win32 + + + Release with Tests + Win32 + {074DC930-05C6-4B7F-B5DD-DD237E6E44DB} @@ -22,20 +26,27 @@ StaticLibrary true - v120 + v140 MultiByte StaticLibrary false - v120 + v140 + true + MultiByte + + + StaticLibrary + false + v140_xp true MultiByte StaticLibrary false - v120 + v140 true MultiByte @@ -48,6 +59,9 @@ + + + @@ -55,19 +69,26 @@ $(SolutionDir)..\build\$(Configuration)\ $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ - ..\..\lib\openssl\include;$(IncludePath) + ..\..\lib\libcurl\include;..\..\lib\jansson;..\..\lib\cutest\CuTest.h;..\..\lib\SDL2_ttf\include;$(IncludePath) + ..\..\lib\libcurl\lib;..\..\lib\SDL2_ttf\lib\x86;$(LibraryPath) $(SolutionDir)..\build\$(Configuration)\ $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ - ..\..\lib\libcurl\include;..\..\lib\jansson;..\..\lib\cutest\CuTest.h;$(IncludePath) - ..\..\lib\libcurl\lib;$(LibraryPath) + ..\..\lib\libcurl\include;..\..\lib\jansson;..\..\lib\cutest\CuTest.h;..\..\lib\SDL2_ttf\include;$(IncludePath) + ..\..\lib\libcurl\lib;..\..\lib\SDL2_ttf\lib\x86;$(LibraryPath) + + + $(SolutionDir)..\build\$(Configuration)\ + $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ + ..\..\lib\libcurl\include;..\..\lib\jansson;..\..\lib\cutest\CuTest.h;..\..\lib\SDL2_ttf\include;$(IncludePath) + ..\..\lib\libcurl\lib;..\..\lib\SDL2_ttf\lib\x86;$(LibraryPath) $(SolutionDir)..\build\Release\ $(SolutionDir)..\obj\$(ProjectName)\Release\ - ..\..\lib\libcurl\include;..\..\lib\jansson;..\..\lib\cutest\CuTest.h;$(IncludePath) - ..\..\lib\libcurl\lib;$(LibraryPath) + ..\..\lib\libcurl\include;..\..\lib\jansson;..\..\lib\cutest\CuTest.h;..\..\lib\SDL2_ttf\include;$(IncludePath) + ..\..\lib\libcurl\lib;..\..\lib\SDL2_ttf\lib\x86;$(LibraryPath) @@ -81,6 +102,13 @@ true + + libcurl.lib;Ws2_32.lib;SDL2_ttf.lib;%(AdditionalDependencies) + true + + + Powershell -NonInteractive -ExecutionPolicy "ByPass" -File "$(ProjectDir)../../pre-build.ps1" + @@ -101,7 +129,32 @@ true - libcurl.lib;Ws2_32.lib;%(AdditionalDependencies) + libcurl.lib;Ws2_32.lib;SDL2_ttf.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;SDL2_ttf.lib;%(AdditionalDependencies) Powershell -NonInteractive -ExecutionPolicy "ByPass" -File "$(ProjectDir)../../pre-build.ps1" @@ -126,7 +179,7 @@ true - libcurl.lib;Ws2_32.lib;%(AdditionalDependencies) + libcurl.lib;Ws2_32.lib;SDL2_ttf.lib;%(AdditionalDependencies) Powershell -NonInteractive -ExecutionPolicy "ByPass" -File "$(ProjectDir)../../pre-build.ps1" @@ -134,9 +187,7 @@ - TurnOffAllWarnings - TurnOffAllWarnings - TurnOffAllWarnings + TurnOffAllWarnings @@ -151,9 +202,7 @@ - TurnOffAllWarnings - TurnOffAllWarnings - TurnOffAllWarnings + TurnOffAllWarnings diff --git a/projects/openrct2.sln b/projects/openrct2.sln index 67248e41b4..5667f3043f 100644 --- a/projects/openrct2.sln +++ b/projects/openrct2.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openrct2", "openrct2.vcxproj", "{D24D94F6-2A74-480C-B512-629C306CE92F}" ProjectSection(ProjectDependencies) = postProject @@ -16,6 +16,7 @@ Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release with Tests|Win32 = Release with Tests|Win32 + Release XP|Win32 = Release XP|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution @@ -23,18 +24,24 @@ Global {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 XP|Win32.ActiveCfg = Release XP|Win32 + {D24D94F6-2A74-480C-B512-629C306CE92F}.Release XP|Win32.Build.0 = Release XP|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 XP|Win32.ActiveCfg = Release XP|Win32 + {0468FC1E-5881-4DB9-9DDE-1892290B31D9}.Release XP|Win32.Build.0 = Release XP|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 XP|Win32.ActiveCfg = Release XP|Win32 + {074DC930-05C6-4B7F-B5DD-DD237E6E44DB}.Release XP|Win32.Build.0 = Release XP|Win32 {074DC930-05C6-4B7F-B5DD-DD237E6E44DB}.Release|Win32.ActiveCfg = Release|Win32 {074DC930-05C6-4B7F-B5DD-DD237E6E44DB}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj index 3e8b0c411a..13d1c0ff54 100644 --- a/projects/openrct2.vcxproj +++ b/projects/openrct2.vcxproj @@ -1,5 +1,5 @@  - + @@ -10,72 +10,83 @@ Debug Win32 - - Release with Tests - Win32 - Release Win32 + + Release XP + Win32 + + + Release with Tests + Win32 + + + + + - - - - - - + + + + + - + + + + + + - @@ -86,10 +97,22 @@ + + + + + + + + + + + + @@ -156,12 +179,7 @@ - - - - - - + @@ -178,26 +196,34 @@ + + + + + + + + + + - - - - - - + + + + @@ -206,6 +232,7 @@ + @@ -215,6 +242,7 @@ + @@ -228,6 +256,7 @@ + @@ -264,25 +293,33 @@ {D24D94F6-2A74-480C-B512-629C306CE92F} openrct2 openrct2 + 10.0.10240.0 DynamicLibrary true - v120 + v140 MultiByte DynamicLibrary false - v120 + v140 + true + MultiByte + + + DynamicLibrary + false + v140_xp true MultiByte DynamicLibrary false - v120 + v140 true MultiByte @@ -295,30 +332,36 @@ + + + - $(SolutionDir)..\lodepng;$(SolutionDir)..\sdl\include;$(SolutionDir)..\libspeex;$(IncludePath) - $(SolutionDir)..\sdl\lib\x86;$(LibraryPath) + $(SolutionDir)..\lib;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(SolutionDir)..\lib\libcurl\include;$(SolutionDir)..\lib\jansson;$(SolutionDir)..\lib\cutest;$(SolutionDir)..\lib\SDL2_ttf\include;$(IncludePath) + $(SolutionDir)..\lib\sdl\lib\x86;$(SolutionDir)..\lib\libcurl\lib;$(LibraryPath) $(SolutionDir)..\build\$(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;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(SolutionDir)..\lib\libcurl\include;$(SolutionDir)..\lib\jansson;$(SolutionDir)..\lib\cutest;$(SolutionDir)..\lib\SDL2_ttf\include;$(IncludePath) + $(SolutionDir)..\lib\sdl\lib\x86;$(SolutionDir)..\lib\libcurl\lib;$(LibraryPath) + $(SolutionDir)..\build\$(Configuration)\ + $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ + + + $(SolutionDir)..\lib;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(SolutionDir)..\lib\libcurl\include;$(SolutionDir)..\lib\jansson;$(SolutionDir)..\lib\cutest;$(SolutionDir)..\lib\SDL2_ttf\include;$(IncludePath) $(SolutionDir)..\lib\sdl\lib\x86;$(SolutionDir)..\lib\libcurl\lib;$(LibraryPath) $(SolutionDir)..\build\$(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;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(SolutionDir)..\lib\libcurl\include;$(SolutionDir)..\lib\jansson;$(SolutionDir)..\lib\cutest;$(SolutionDir)..\lib\SDL2_ttf\include;$(IncludePath) $(SolutionDir)..\lib\sdl\lib\x86;$(SolutionDir)..\lib\libcurl\lib;$(LibraryPath) $(SolutionDir)..\build\Release\ $(SolutionDir)..\obj\$(ProjectName)\Release\ - @@ -326,22 +369,27 @@ Disabled true 1Byte - _CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;%(PreprocessorDefinitions) + DEBUG;_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;CURL_STATICLIB;SDL_MAIN_HANDLED;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreaded + true + $(IntDir)fake\%(RelativeDir) + 4013 + false true - winmm.lib;sdl2.lib;Dsound.lib;%(AdditionalDependencies) + winmm.lib;sdl2.lib;%(AdditionalDependencies) - "$(TargetDir)\openrct2.exe" sprite build "$(SolutionDir)\..\Data\g2.dat" "$(SolutionDir)\..\Resources\g2\" -xcopy /YS "$(SolutionDir)\..\Data" "$(TargetDir)\Data" + "$(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 + Full true true @@ -352,20 +400,62 @@ xcopy /YS "$(SolutionDir)\..\Data" "$(TargetDir)\Data" false - _CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;CURL_STATICLIB;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;CURL_STATICLIB;SDL_MAIN_HANDLED;%(PreprocessorDefinitions) $(IntDir)fake\%(RelativeDir) true + Speed true true true - winmm.lib;sdl2.lib;Dsound.lib;%(AdditionalDependencies) + winmm.lib;sdl2.lib;%(AdditionalDependencies) /ignore:4099 %(AdditionalOptions) - "$(TargetDir)\openrct2.exe" sprite build "$(SolutionDir)\..\Data\g2.dat" "$(SolutionDir)\..\Resources\g2\" -xcopy /YS "$(SolutionDir)\..\Data" "$(TargetDir)\Data" + "$(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 + Full + true + true + + + MultiThreaded + 1Byte + 4013 + + + false + DISABLE_NETWORK;DISABLE_HTTP;DISABLE_TWITCH;_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;CURL_STATICLIB;SDL_MAIN_HANDLED;%(PreprocessorDefinitions) + $(IntDir)fake\%(RelativeDir) + true + Speed + + + true + true + true + winmm.lib;sdl2.lib;%(AdditionalDependencies) + /ignore:4099 %(AdditionalOptions) + Windows + + + "$(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. @@ -391,7 +481,7 @@ xcopy /YS "$(SolutionDir)\..\Data" "$(TargetDir)\Data" false - _CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;CURL_STATICLIB;ENABLE_TESTS;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;CURL_STATICLIB;SDL_MAIN_HANDLED;ENABLE_TESTS;%(PreprocessorDefinitions) $(IntDir)fake\%(RelativeDir) true @@ -399,12 +489,12 @@ xcopy /YS "$(SolutionDir)\..\Data" "$(TargetDir)\Data" true true true - winmm.lib;sdl2.lib;Dsound.lib;%(AdditionalDependencies) + winmm.lib;sdl2.lib;%(AdditionalDependencies) /ignore:4099 %(AdditionalOptions) - "$(TargetDir)\openrct2.exe" sprite build "$(SolutionDir)\..\Data\g2.dat" "$(SolutionDir)\..\Resources\g2\" -xcopy /YS "$(SolutionDir)\..\Data" "$(TargetDir)\Data" + "$(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. @@ -419,4 +509,4 @@ xcopy /YS "$(SolutionDir)\..\Data" "$(TargetDir)\Data" - \ No newline at end of file + diff --git a/projects/openrct2.vcxproj.filters b/projects/openrct2.vcxproj.filters index fad60aeef3..d32f0f5439 100644 --- a/projects/openrct2.vcxproj.filters +++ b/projects/openrct2.vcxproj.filters @@ -53,6 +53,9 @@ {c6b9c169-ff2a-41df-9b1c-47d15763c3e2} + + {28a808eb-9017-44cc-939b-f828fd1e2e7d} + @@ -213,9 +216,6 @@ Source\Localisation - - Source\Localisation - Source\Ride @@ -300,7 +300,7 @@ Source\Platform - + Source\Platform @@ -480,6 +480,78 @@ Source\Windows + + Source\Windows + + + Source\Interface + + + Source\Windows + + + Source\Windows + + + Source + + + Source\Localisation + + + Source\Drawing + + + Source\Drawing + + + Source\Localisation + + + Source\Network + + + Source\Windows + + + Source\Windows + + + Source\Interface + + + Source\Windows + + + Source\World + + + Source\World + + + Source\World + + + Source\World + + + Source\Localisation + + + Source\Localisation + + + Source\Ride + + + Source\Platform + + + Source\Windows + + + Source\Interface + @@ -704,5 +776,53 @@ Test\Ride + + Source\Interface + + + Source + + + Source\Drawing + + + Source\Network + + + Source\Interface + + + Source\Core + + + Source\Core + + + Source\Core + + + Source\Core + + + Source\Localisation + + + Source\Core + + + Source\Core + + + Source\Core + + + Source\Core + + + Source\Ride + + + Source\Interface + - \ No newline at end of file + diff --git a/projects/openrct2.vcxproj.user b/projects/openrct2.vcxproj.user index 33fff921b3..e977faccec 100644 --- a/projects/openrct2.vcxproj.user +++ b/projects/openrct2.vcxproj.user @@ -1,20 +1,28 @@  + + false + + + $(TargetDir)\openrct2.exe + WindowsLocalDebugger + $(TargetDir) + $(TargetDir) WindowsLocalDebugger $(TargetDir)\openrct2.exe - - + + + + $(TargetDir) + WindowsLocalDebugger + $(TargetDir)\openrct2.exe + $(TargetDir) WindowsLocalDebugger $(TargetDir)\openrct2.exe - - - - - false \ No newline at end of file diff --git a/projects/resource.h b/projects/resource.h index f70ccbffb2..545b58f6b5 100644 --- a/projects/resource.h +++ b/projects/resource.h @@ -3,7 +3,7 @@ // Used by openrct2.rc // Next default values for new objects -// +// #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 101 diff --git a/readme.md b/readme.md index 3b5b0c0d05..6b395f4abc 100644 --- a/readme.md +++ b/readme.md @@ -5,9 +5,13 @@ An open source clone of RollerCoaster Tycoon 2 built by decompiling the original - [Screenshot 3, high resolution](http://i.imgur.com/yFzNyVu.jpg) - [Screenshot 4, resizable window](http://imgur.com/a/3GDuT) -[![Build Status](https://travis-ci.org/IntelOrca/OpenRCT2.svg)](https://travis-ci.org/IntelOrca/OpenRCT2) +Linux Build: +[![Travis CI](https://travis-ci.org/OpenRCT2/OpenRCT2.svg)](https://travis-ci.org/OpenRCT2/OpenRCT2) +Windows Build: +[![AppVeyor](https://ci.appveyor.com/api/projects/status/fib6re830brysuo2?svg=true)](https://ci.appveyor.com/project/IntelOrca/openrct2) -[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/IntelOrca/OpenRCT2?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +Come talk with us if you have any questions: +[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/OpenRCT2/OpenRCT2?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) # Contents - 1 - [Introduction](#1-introduction) @@ -15,8 +19,8 @@ An open source clone of RollerCoaster Tycoon 2 built by decompiling the original - 1.2 - [Decompiling the game](#12-decompiling-the-game) - 1.3 - [Progress](#13-progress) - 1.4 - [Aim](#14-aim) -- 2 - [Downloading the game / Building the source code](#2-building-the-source-code) - - 2.1 - [Prerequisites](#21-prerequisites) +- 2 - [Downloading the game / Building the source code](#2-downloading-the-game--building-the-source-code) + - 2.1 - [Building Prerequisites](#21-building-prerequisites) - 2.2 - [Compiling and running](#22-compiling-and-running) - 3 - [Contributing](#3-contributing) - 3.1 - [Decompiling](#31-decompiling) @@ -24,7 +28,7 @@ An open source clone of RollerCoaster Tycoon 2 built by decompiling the original - 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) +- 4 - [Licence](#4-licence) # 1 Introduction @@ -39,7 +43,7 @@ The project therefore acts as a patch to RollerCoaster Tycoon 2, allowing each p ## 1.3 Progress Currently, the windowing system, graphics rendering and basic game loop are being decompiled. Decompiling all of the game's procedures is a convenient way of identifying the game's memory structure. SDL2 has been used as a replacement for the operating system calls, allowing for cross-platform support after the dependency on the original game's executable has been removed. -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). +As of 9th September 2015, a vast set of improvements have been added such as improved UI, tools, cheats, localisation and configuration. The entire window system and UI has been implemented, all file format handling such as loading and saving of parks, graphics and tracks, ride logic, game management (e.g. peep generation, awards, cash out) and a lot of the peep logic. What remains is a lot of code to draw the map, the rest of the peep logic, and the entirety of vehicle logic. The rest are small parts around different areas that aren't particularly significant. More information can be found in [changes to original game](https://github.com/OpenRCT2/OpenRCT2/wiki/Changes-to-original-game). ## 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 are many more: @@ -51,49 +55,50 @@ The aim is to completely decompile RollerCoaster Tycoon 2 into C so that cross-p - Improved title sequence - 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 + - 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 couple of third parties offer downloadable precompiled builds. However, building the project is always recommended - -[OpenRCT2.com](https://openrct2.com/download) +Several third party build servers offer precompiled builds and installers of the latest stable and the develop branch. +[OpenRCT2.com](https://openrct2.com/download) [OpenRCT.net](https://openrct.net/builds.php) +[UrsaLabs](https://openrct.ursalabs.co) 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 +## 2.1 Building prerequisites + +OpenRCT2 requires original files of Rollercoaster Tycoon 2 to play. It can be bought at either [Steam](http://store.steampowered.com/app/285330/) or [GOG.com](http://www.gog.com/game/rollercoaster_tycoon_2). + ### Windows: - Windows XP / Vista / 7 / 8 / 10 -- RollerCoaster Tycoon 2 -- 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). +- Visual Studio 2015 (Enterprise / Professional / [Community (Free)](https://www.visualstudio.com/products/visual-studio-community-vs)) +- [Powershell 4.0](http://social.technet.microsoft.com/wiki/contents/articles/21016.how-to-install-windows-powershell-4-0.aspx). -### Max OS X: -- [Homebrew](http://brew.sh) -- RollerCoaster Tycoon 2 +### Mac OS X: +- [Homebrew](http://brew.sh) or [MacPorts](https://www.macports.org/) ### Mac OS X / Linux: - [MinGW-w64](http://mingw-w64.sourceforge.net/) - [Wine](http://www.winehq.org) -- RollerCoaster Tycoon 2 - libsdl2 compiled with MinGW-w64 ## 2.2 Compiling and running ### Windows: 1. Check out the repository. This can be done using [GitHub Windows](https://windows.github.com/) or [other tools](https://help.github.com/articles/which-remote-url-should-i-use). -2. Download the [SDL2 development library for Visual C++]((http://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip)) and copy it to a new directory called "sdl" in the repository. This directory should contain "include". The path should resemble ```\OpenRCT2\lib\sdl\include\```. -3. Open the solution in the projects directory (**openrct2.sln**) with Visual Studio. -4. [Select the 'Release' configuration](http://msdn.microsoft.com/en-us/library/wx0123s5.aspx) and click Build -> Rebuild Solution. The dropdown menu to enable the 'release' configuration is towards the top of the VS Express window, near the "TEST" menu. -5. Start debugging. Press the "Local Windows Debugger" button with a green "play" icon next to it. If Visual Studio shows a warning about *openrct2.exe* not having debug information, press Continue. -6. When OpenRCT2 is run for the first time, it creates a settings file in `My Documents/OpenRCT2`. If it can't find the original installation of RCT2, you will need to edit `config.ini` in that folder and change the value of `game_path` to where RCT2 is installed. -7. If the game crashes, you may need to press the red, square Stop button along the top of VS Express to stop the program. +2. Open the solution in the projects directory (**openrct2.sln**) with Visual Studio. +3. [Select the 'Release' configuration](http://msdn.microsoft.com/en-us/library/wx0123s5.aspx) and click Build -> Rebuild Solution. The dropdown menu to enable the 'release' configuration is towards the top of the VS Express window, near the "TEST" menu. +4. Start debugging. Press the "Local Windows Debugger" button with a green "play" icon next to it. If Visual Studio shows a warning about *openrct2.exe* not having debug information, press Continue. +5. When OpenRCT2 is run for the first time, it creates a settings file in `My Documents/OpenRCT2`. If it can't find the original installation of RCT2, you will need to edit `config.ini` in that folder and change the value of `game_path` to where RCT2 is installed. +6. If the game crashes, you may need to press the red, square Stop button along the top of VS Express to stop the program. + +Alternatively, to simply build the project you can just execute ``build.bat`` within VS2015 Native Tools Command prompt or Github Windows prompt. ### Mac OS X: -Providing Homebrew is installed, OpenRCT2's dependencies and Wine can be installed automatically through `install.sh`. +Providing Homebrew or MacPorts are installed (but not both!), OpenRCT2's dependencies and Wine can be installed automatically through `install.sh`. ``` bash install.sh bash build.sh @@ -101,12 +106,14 @@ wine openrct2.exe ``` ### Linux: -As the easiest approach depends on your distribution, please take a look at the [wiki](https://github.com/IntelOrca/OpenRCT2/wiki). +As the easiest approach depends on your distribution, please take a look at the [wiki](https://github.com/OpenRCT2/OpenRCT2/wiki). # 3 Contributing OpenRCT2 uses the [gitflow workflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow). If you are implementing a new feature or logic from the original game, please branch off and perform pull requests to **develop**. If you are fixing a bug for the next release, please branch off and perform pull requests to the correct release branch. **master** only contains tagged releases, you should never branch off this. +Please read our [contributing guidelines](https://github.com/OpenRCT2/OpenRCT2/blob/develop/CONTRIBUTING.md) for information. + ## 3.1 Decompiling Experience with reverse engineering and x86 assembly is necessary to decompile the original game. [IDA 5.0](https://www.hex-rays.com/products/ida/support/download_freeware.shtml) is currently being used to disassemble and analyze the game. You are welcome to contribute to the process by taking an undecompiled procedure, disassembling it, and rewriting it in C. For more information and the latest IDA database, contact IntelOrca. @@ -131,14 +138,14 @@ While decompilation is an ongoing process, this does not prohibit changes being ## 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 +# 4 Licence **OpenRCT2** is licensed under the GNU General Public License version 3. # 5 More information -- [GitHub](https://github.com/IntelOrca/OpenRCT2) +- [GitHub](https://github.com/OpenRCT2/OpenRCT2) +- [Forums](https://openrct2.org/forums/) - [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) +- [OpenRCT2.com](https://openrct2.com) +- [OpenRCT.net](https://openrct.net) +- [rct subreddit](http://www.reddit.com/r/rct/) +- [openrct2 subreddit](http://www.reddit.com/r/openrct2/) diff --git a/resources/g2/29.png b/resources/g2/29.png new file mode 100644 index 0000000000..a95bea0673 Binary files /dev/null and b/resources/g2/29.png differ diff --git a/resources/g2/30.png b/resources/g2/30.png new file mode 100644 index 0000000000..4038923eaf Binary files /dev/null and b/resources/g2/30.png differ diff --git a/resources/g2/31.png b/resources/g2/31.png new file mode 100644 index 0000000000..06b5f195c9 Binary files /dev/null and b/resources/g2/31.png differ diff --git a/resources/g2/32.png b/resources/g2/32.png new file mode 100644 index 0000000000..84d69e2337 Binary files /dev/null and b/resources/g2/32.png differ diff --git a/resources/g2/33.png b/resources/g2/33.png new file mode 100644 index 0000000000..c6d2c04941 Binary files /dev/null and b/resources/g2/33.png differ diff --git a/resources/g2/34.png b/resources/g2/34.png new file mode 100644 index 0000000000..992c5bdad4 Binary files /dev/null and b/resources/g2/34.png differ diff --git a/resources/g2/35.png b/resources/g2/35.png new file mode 100644 index 0000000000..fffe5fa9f0 Binary files /dev/null and b/resources/g2/35.png differ diff --git a/resources/g2/36.png b/resources/g2/36.png new file mode 100644 index 0000000000..c83d1eba74 Binary files /dev/null and b/resources/g2/36.png differ diff --git a/resources/g2/37.png b/resources/g2/37.png new file mode 100644 index 0000000000..f4579749ea Binary files /dev/null and b/resources/g2/37.png differ diff --git a/resources/g2/38.png b/resources/g2/38.png new file mode 100644 index 0000000000..fa1dd09956 Binary files /dev/null and b/resources/g2/38.png differ diff --git a/resources/g2/39.png b/resources/g2/39.png new file mode 100644 index 0000000000..d47ffca2e2 Binary files /dev/null and b/resources/g2/39.png differ diff --git a/resources/g2/40.png b/resources/g2/40.png new file mode 100644 index 0000000000..1f1778adae Binary files /dev/null and b/resources/g2/40.png differ diff --git a/resources/g2/41.png b/resources/g2/41.png new file mode 100644 index 0000000000..1aab1c2aad Binary files /dev/null and b/resources/g2/41.png differ diff --git a/resources/g2/42.png b/resources/g2/42.png new file mode 100644 index 0000000000..303ef490ee Binary files /dev/null and b/resources/g2/42.png differ diff --git a/resources/g2/43.png b/resources/g2/43.png new file mode 100644 index 0000000000..1bedcf6fd3 Binary files /dev/null and b/resources/g2/43.png differ diff --git a/resources/g2/44.png b/resources/g2/44.png new file mode 100644 index 0000000000..075dae7638 Binary files /dev/null and b/resources/g2/44.png differ diff --git a/resources/g2/45.png b/resources/g2/45.png new file mode 100644 index 0000000000..16f8ca9e62 Binary files /dev/null and b/resources/g2/45.png differ diff --git a/resources/g2/46.png b/resources/g2/46.png new file mode 100644 index 0000000000..995693fab8 Binary files /dev/null and b/resources/g2/46.png differ diff --git a/resources/g2/47.png b/resources/g2/47.png new file mode 100644 index 0000000000..4dac4d418e Binary files /dev/null and b/resources/g2/47.png differ diff --git a/resources/g2/48.png b/resources/g2/48.png new file mode 100644 index 0000000000..9cb20f7ecf Binary files /dev/null and b/resources/g2/48.png differ diff --git a/resources/g2/49.png b/resources/g2/49.png new file mode 100644 index 0000000000..08c8af888d Binary files /dev/null and b/resources/g2/49.png differ diff --git a/resources/g2/50.png b/resources/g2/50.png new file mode 100644 index 0000000000..94f060add9 Binary files /dev/null and b/resources/g2/50.png differ diff --git a/resources/g2/51.png b/resources/g2/51.png new file mode 100644 index 0000000000..21ee9e0ddd Binary files /dev/null and b/resources/g2/51.png differ diff --git a/resources/g2/52.png b/resources/g2/52.png new file mode 100644 index 0000000000..5fd0252a14 Binary files /dev/null and b/resources/g2/52.png differ diff --git a/resources/g2/53.png b/resources/g2/53.png new file mode 100644 index 0000000000..66382d7ee6 Binary files /dev/null and b/resources/g2/53.png differ diff --git a/resources/g2/54.png b/resources/g2/54.png new file mode 100644 index 0000000000..cd8625707e Binary files /dev/null and b/resources/g2/54.png differ diff --git a/resources/g2/55.png b/resources/g2/55.png new file mode 100644 index 0000000000..76d67d4a47 Binary files /dev/null and b/resources/g2/55.png differ diff --git a/resources/g2/56.png b/resources/g2/56.png new file mode 100644 index 0000000000..17e96bbd20 Binary files /dev/null and b/resources/g2/56.png differ diff --git a/resources/g2/57.png b/resources/g2/57.png new file mode 100644 index 0000000000..6a1c64c248 Binary files /dev/null and b/resources/g2/57.png differ diff --git a/resources/g2/58.png b/resources/g2/58.png new file mode 100644 index 0000000000..38dab8711a Binary files /dev/null and b/resources/g2/58.png differ diff --git a/resources/g2/59.png b/resources/g2/59.png new file mode 100644 index 0000000000..df84145706 Binary files /dev/null and b/resources/g2/59.png differ diff --git a/src/addresses.c b/src/addresses.c new file mode 100644 index 0000000000..0e9f4d3a89 --- /dev/null +++ b/src/addresses.c @@ -0,0 +1,208 @@ +#include "addresses.h" + +#if defined(__GNUC__) +#define DISABLE_OPT __attribute__((noinline,optimize("O0"))) +#else +#define DISABLE_OPT +#endif // defined(__GNUC__) + +int DISABLE_OPT RCT2_CALLPROC_X(int address, int _eax, int _ebx, int _ecx, int _edx, int _esi, int _edi, int _ebp) +{ + int result; + #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] + lahf + pop ebp + pop ebp + /* Load result with flags */ + mov result, eax + } + #else + __asm__ volatile ( "\ + \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\ + lahf \n\ + add $4, %%esp \n\ + pop %%ebp \n\ + pop %%ebx \n\ + /* Load result with flags */ \n\ + mov %%eax, %[result] \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), [result] "+m" (result) + : + : "eax","ecx","edx","esi","edi","memory" + ); + #endif + // lahf only modifies ah, zero out the rest + return result & 0xFF00; +} + +int DISABLE_OPT RCT2_CALLFUNC_X(int address, int *_eax, int *_ebx, int *_ecx, int *_edx, int *_esi, int *_edi, int *_ebp) +{ + int result; + #ifdef _MSC_VER + __asm { + // Store C's base pointer + push ebp + push ebx + // Store address to call + push address + + // Set all registers to the input values + mov eax, [_eax] + mov eax, [eax] + mov ebx, [_ebx] + mov ebx, [ebx] + mov ecx, [_ecx] + mov ecx, [ecx] + mov edx, [_edx] + mov edx, [edx] + mov esi, [_esi] + mov esi, [esi] + mov edi, [_edi] + mov edi, [edi] + mov ebp, [_ebp] + mov ebp, [ebp] + + // Call function + call [esp] + + // Store output eax + push eax + push ebp + push ebx + mov ebp, [esp + 20] + mov ebx, [esp + 16] + + // Get resulting ecx, edx, esi, edi registers + + mov eax, [_edi] + mov [eax], edi + mov eax, [_esi] + mov [eax], esi + mov eax, [_edx] + mov [eax], edx + mov eax, [_ecx] + mov [eax], ecx + + // Pop ebx reg into ecx + pop ecx + mov eax, [_ebx] + mov[eax], ecx + + // Pop ebp reg into ecx + pop ecx + mov eax, [_ebp] + mov[eax], ecx + + pop eax + // Get resulting eax register + mov ecx, [_eax] + mov [ecx], eax + + // Save flags as return in eax + lahf + // Pop address + pop ebp + + pop ebx + pop ebp + /* Load result with flags */ + mov result, eax + } + #else + __asm__ volatile ( "\ + \n\ + /* Store C's base pointer*/ \n\ + push %%ebp \n\ + push %%ebx \n\ + \n\ + /* Store %[address] to call*/ \n\ + push %[address] \n\ + \n\ + /* Set all registers to the input values*/ \n\ + mov %[_eax], %%eax \n\ + mov (%%eax), %%eax \n\ + mov %[_ebx], %%ebx \n\ + mov (%%ebx), %%ebx \n\ + mov %[_ecx], %%ecx \n\ + mov (%%ecx), %%ecx \n\ + mov %[_edx], %%edx \n\ + mov (%%edx), %%edx \n\ + mov %[_esi], %%esi \n\ + mov (%%esi), %%esi \n\ + mov %[_edi], %%edi \n\ + mov (%%edi), %%edi \n\ + mov %[_ebp], %%ebp \n\ + mov (%%ebp), %%ebp \n\ + \n\ + /* Call function*/ \n\ + call *(%%esp) \n\ + \n\ + /* Store output eax */ \n\ + push %%eax \n\ + push %%ebp \n\ + push %%ebx \n\ + mov 20(%%esp), %%ebp \n\ + mov 16(%%esp), %%ebx \n\ + /* Get resulting ecx, edx, esi, edi registers*/ \n\ + mov %[_edi], %%eax \n\ + mov %%edi, (%%eax) \n\ + mov %[_esi], %%eax \n\ + mov %%esi, (%%eax) \n\ + mov %[_edx], %%eax \n\ + mov %%edx, (%%eax) \n\ + mov %[_ecx], %%eax \n\ + mov %%ecx, (%%eax) \n\ + /* Pop ebx reg into ecx*/ \n\ + pop %%ecx \n\ + mov %[_ebx], %%eax \n\ + mov %%ecx, (%%eax) \n\ + \n\ + /* Pop ebp reg into ecx */\n\ + pop %%ecx \n\ + mov %[_ebp], %%eax \n\ + mov %%ecx, (%%eax) \n\ + \n\ + pop %%eax \n\ + /* Get resulting eax register*/ \n\ + mov %[_eax], %%ecx \n\ + mov %%eax, (%%ecx) \n\ + \n\ + /* Save flags as return in eax*/ \n\ + lahf \n\ + /* Pop address*/ \n\ + pop %%ebp \n\ + \n\ + pop %%ebx \n\ + pop %%ebp \n\ + /* Load result with flags */ \n\ + mov %%eax, %[result] \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), [result] "+m" (result) + + : + : "eax","ecx","edx","esi","edi","memory" + ); + #endif + // lahf only modifies ah, zero out the rest + return result & 0xFF00; +} diff --git a/src/addresses.h b/src/addresses.h index e74cede5f2..7f2622284e 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -1,9 +1,9 @@ /***************************************************************************** * Copyright (c) 2014 Ted John, Kevin Burke, Matthias Lanzinger * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * + * * This file is part of OpenRCT2. - * + * * OpenRCT2 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -27,6 +27,7 @@ #define RCT2_ADDRESS(address, type) ((type*)(address)) #define RCT2_GLOBAL(address, type) (*((type*)(address))) +#ifdef _WIN32 #define RCT2_CALLPROC(address) (((void(*)())(address))()) #define RCT2_CALLFUNC(address, returnType) (((returnType(*)())(address))()) @@ -36,6 +37,16 @@ #define RCT2_CALLFUNC_4(address, returnType, a1, a2, a3, a4, v1, v2, v3, v4) (((returnType(*)(a1, a2, a3, a4))(address))(v1, v2, v3, v4)) #define RCT2_CALLFUNC_5(address, returnType, a1, a2, a3, a4, a5, v1, v2, v3, v4, v5) (((returnType(*)(a1, a2, a3, a4, a5))(address))(v1, v2, v3, v4, v5)) #define RCT2_CALLFUNC_6(address, returnType, a1, a2, a3, a4, a5, a6, v1, v2, v3, v4, v5, v6) (((returnType(*)(a1, a2, a3, a4, a5, a6))(address))(v1, v2, v3, v4, v5, v6)) +#else +#define RCT2_CALLPROC(address) +#define RCT2_CALLFUNC(address, returnType) +#define RCT2_CALLFUNC_1(address, returnType, a1, v1) +#define RCT2_CALLFUNC_2(address, returnType, a1, a2, v1, v2) +#define RCT2_CALLFUNC_3(address, returnType, a1, a2, a3, v1, v2, v3) +#define RCT2_CALLFUNC_4(address, returnType, a1, a2, a3, a4, v1, v2, v3, v4) +#define RCT2_CALLFUNC_5(address, returnType, a1, a2, a3, a4, a5, v1, v2, v3, v4, v5) +#define RCT2_CALLFUNC_6(address, returnType, a1, a2, a3, a4, a5, a6, v1, v2, v3, v4, v5, v6) +#endif // _WIN32 #define RCT2_CALLPROC_1(address, a1, v1) RCT2_CALLFUNC_1(address, void, a1, v1) #define RCT2_CALLPROC_2(address, a1, a2, v1, v2) RCT2_CALLFUNC_2(address, void, a1, a2, v1, v2) @@ -55,30 +66,19 @@ #define RCT2_ADDRESS_EASTEREGG_NAMES 0x00988C20 -#define RCT2_ADDRESS_RIDE_PROPERTIES 0x00997C9D +// An array of pointers to the start of a way to +// translate between scroll positions for drawing +#define RCT2_ADDRESS_SCROLLING_MODE_POSITIONS 0x00992FB8 + #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 -// #define RCT2_ADDRESS_NUM_SCENARIOS 0x009AA008 - #define RCT2_ADDRESS_APP_PATH 0x009AA214 -#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 #define RCT2_ADDRESS_CONFIG_KEYBOARD_SHORTCUTS 0x009AAC7A @@ -158,6 +158,10 @@ #define RCT2_ADDRESS_VEHICLE_SOUND_LIST 0x009AF288 +#define RCT2_ADDRESS_DRAW_SCROLL_LIST 0x009C3840 + +#define RCT2_ADDRESS_DRAW_SCROLL_NEXT_ID 0x009D7A80 + #define RCT2_ADDRESS_INPUT_FLAGS 0x009DE518 #define RCT2_ADDRESS_CURENT_CURSOR 0x009DE51C #define RCT2_ADDRESS_INPUT_STATE 0x009DE51D @@ -185,6 +189,8 @@ #define RCT2_ADDRESS_CURRENT_SCROLL_AREA 0x009DE548 #define RCT2_ADDRESS_CURRENT_SCROLL_ID 0x009DE54C +#define RCT2_ADDRESS_TICKS_SINCE_DRAG_START 0x009DE540 + #define RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE 0x009DE550 #define RCT2_ADDRESS_PICKEDUP_PEEP_X 0x009DE554 #define RCT2_ADDRESS_PICKEDUP_PEEP_Y 0x009DE556 @@ -193,8 +199,15 @@ #define RCT2_ADDRESS_CURSOR_OVER_WINDOWNUMBER 0x009DE55E #define RCT2_ADDRESS_CURSOR_OVER_WIDGETINDEX 0x009DE560 +// Of type viewport interaction +#define RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE 0x009DE570 + +#define RCT2_ADDRESS_LAST_TICK_COUNT 0x009DE580 + #define RCT2_ADDRESS_PALETTE_EFFECT_FRAME_NO 0x009DE584 +#define RCT2_ADDRESS_TICKS_SINCE_LAST_UPDATE 0x009DE588 + // Flags: // 0x1 Enable selection // 0x2 Enable construct selection, see CONSTRUCT_PATH_* @@ -218,6 +231,12 @@ #define RCT2_ADDRESS_MAP_ARROW_Z 0x009DEA4C #define RCT2_ADDRESS_MAP_ARROW_DIRECTION 0x009DEA4E +#define RCT2_ADDRESS_COMMAND_MAP_X 0x009DEA5E +#define RCT2_ADDRESS_COMMAND_MAP_Y 0x009DEA60 +#define RCT2_ADDRESS_COMMAND_MAP_Z 0x009DEA62 + +//Counts how many ticks the current screen has been open for +#define RCT2_ADDRESS_SCREEN_AGE 0x009DEA66 #define RCT2_ADDRESS_SCREEN_FLAGS 0x009DEA68 #define RCT2_ADDRESS_SCREENSHOT_COUNTDOWN 0x009DEA6D // Note: not only the zeroth bit can be set to control pause @@ -230,19 +249,12 @@ #define RCT2_ADDRESS_WINDOW_DPI 0x009DEA74 +#define RCT2_ADDRESS_WINDOW_UPDATE_TICKS 0x009DEB7C + #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 -#define RCT2_ADDRESS_SOUND_EFFECTS_MAPPING 0x009E2B94 -#define RCT2_ADDRESS_SOUNDLIST_BEGIN 0x009E2B98 -#define RCT2_ADDRESS_SOUNDLIST_END 0x009E2B9C -#define RCT2_ADDRESS_DIRECTSOUND 0x009E2BA0 -#define RCT2_ADDRESS_DSOUND_DEVICES_COUNTER 0x009E2BAC - #define RCT2_ADDRESS_CMDLINE 0x009E2D98 #define RCT2_ADDRESS_MOUSE_WRITE_INDEX 0x009E2DE4 @@ -256,6 +268,12 @@ #define RCT2_ADDRESS_SELECTED_TERRAIN_EDGE 0x009E2E24 #define RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE 0x009E2E25 +#define RCT2_ADDRESS_PARK_ENTRANCE_GHOST_X 0x009E32CC +#define RCT2_ADDRESS_PARK_ENTRANCE_GHOST_Y 0x009E32CE +#define RCT2_ADDRESS_PARK_ENTRANCE_GHOST_DIRECTION 0x009E32D1 +#define RCT2_ADDRESS_PARK_ENTRANCE_GHOST_EXISTS 0x009E32D2 +#define RCT2_ADDRESS_PARK_ENTRANCE_GHOST_PRICE 0x009E32D3 + #define RCT2_ADDRESS_G1_ELEMENTS 0x009EBD28 //Every pixel changed by rain is stored. @@ -265,6 +283,8 @@ #define RCT2_ADDRESS_UNCOMPLETED_RESEARCH_TYPES 0x00EE787C +#define RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER 0x00F1AD60 + #define RCT2_ADDRESS_MAP_IMAGE_DATA 0x00F1AD68 // No longer used @@ -298,10 +318,17 @@ // 1 if custom objects installed, 0 otherwise #define RCT2_ADDRESS_CUSTOM_OBJECTS_INSTALLED 0x00F42BDA +#define RCT2_ADDRESS_SELECTED_OBJECTS_FILE_SIZE 0x00F4340D + #define RCT2_ADDRESS_VOLUME_ADJUST_ZOOM 0x00F438AC #define RCT2_ADDRESS_STAFF_HIGHLIGHTED_INDEX 0x00F43908 +// Each character is painted onto a drawing surface +// any coloured pixels are marked in this bitmap +// 8 x 8 in size. +#define RCT2_ADDRESS_CHARACTER_BITMAP 0x00F4393C + #define RCT2_ADDRESS_TRACK_PREVIEW_ROTATION 0x00F440AE #define RCT2_ADDRESS_TRACK_PREVIEW_X_MIN 0x00F440F9 @@ -318,14 +345,27 @@ #define RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE 0x00F44152 +#define RCT2_ADDRESS_ABOVE_GROUND_FLAGS 0x00F441D4 #define RCT2_ADDRESS_TRACK_LIST 0x00F441EC +#define RCT2_ADDRESS_SCENERY_COST 0x00F64EB4 +#define RCT2_ADDRESS_SCENERY_MAP_ELEMENT 0x00F64EBC +#define RCT2_ADDRESS_SCENERY_ROTATION 0x00F64EC0 +#define RCT2_ADDRESS_GHOST_SCENERY_X 0x00F64EC4 +#define RCT2_ADDRESS_GHOST_SCENERY_Y 0x00F64EC6 +#define RCT2_ADDRESS_GHOST_SCENERY_Z 0x00F64F09 +#define RCT2_ADDRESS_SCENERY_MAP_ELEMENT_TYPE 0x00F64F0C +#define RCT2_ADDRESS_GHOST_SCENERY_TYPE 0x00F64F0D +#define RCT2_ADDRESS_SCENERY_TARGET_PATH_INCLINE 0x00F64F0F +#define RCT2_ADDRESS_GHOST_SCENERY_PATH_OBJECT_TYPE 0x00F64EAC #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_SELECTED_OBJECT 0x00F64EDA +#define RCT2_ADDRESS_SCENERY_TARGET_PATH_TYPE 0x00F64F10 +#define RCT2_ADDRESS_GHOST_SCENERY_WALL_ROTATION 0x00F64F11 #define RCT2_ADDRESS_SCENERY_TOOL_CTRL_PRESSED 0x00F64F12 #define RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED 0x00F64F13 @@ -336,6 +376,7 @@ #define RCT2_ADDRESS_SCENARIO_SRAND_0 0x00F663B0 #define RCT2_ADDRESS_SCENARIO_SRAND_1 0x00F663B4 #define RCT2_ADDRESS_MAP_ELEMENTS 0x00F663B8 +#define RCT2_ADDRESS_MAP_ELEMENTS_END 0x010E53B8 #define RCT2_ADDRESS_SPRITE_LIST 0x010E63BC #define RCT2_ADDRESS_SPRITES_NEXT_INDEX 0x013573BC @@ -344,6 +385,11 @@ #define RCT2_ADDRESS_SPRITES_START_MISC 0x013573C2 #define RCT2_ADDRESS_SPRITES_START_LITTER 0x013573C4 +#define RCT2_ADDRESS_SPRITES_COUNT_VEHICLE 0x013573CA +#define RCT2_ADDRESS_SPRITES_COUNT_PEEP 0x013573CC +#define RCT2_ADDRESS_SPRITES_COUNT_MISC 0x013573CE +#define RCT2_ADDRESS_SPRITES_COUNT_LITTER 0x013573D0 + #define RCT2_ADDRESS_PARK_NAME 0x013573D4 #define RCT2_ADDRESS_PARK_NAME_ARGS 0x013573D8 #define RCT2_ADDRESS_INITIAL_CASH 0x013573DC @@ -386,9 +432,11 @@ #define RCT2_ADDRESS_PEEP_SPAWNS 0x013573F2 +#define RCT2_ADDRESS_GUEST_CHANGE_MODIFIER 0x013573FE #define RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL 0x013573FF #define RCT2_ADDRESS_EXPENDITURE_TABLE 0x01357848 +#define RCT2_ADDRESS_LAST_GUESTS_IN_PARK 0x01357BC8 #define RCT2_ADDRESS_HANDYMAN_COLOUR 0x01357BCD #define RCT2_ADDRESS_MECHANIC_COLOUR 0x01357BCE #define RCT2_ADDRESS_SECURITY_COLOUR 0x01357BCF @@ -425,12 +473,16 @@ #define RCT2_ADDRESS_RIDE_LIST 0x013628F8 #define RCT2_ADDRESS_RIDE_COUNT 0x013587C8 #define RCT2_ADDRESS_RIDE_FLAGS 0x0097CF40 + +//How many ticks the scenario has existed for +#define RCT2_ADDRESS_SAVED_AGE 0x01388698 #define RCT2_ADDRESS_SAVED_VIEW_X 0x0138869A #define RCT2_ADDRESS_SAVED_VIEW_Y 0x0138869C #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_STAFF_PATROL_AREAS 0x013B0E72 #define RCT2_ADDRESS_CLIMATE 0x013CA746 #define RCT2_ADDRESS_CURRENT_WEATHER 0x013CA74A @@ -451,10 +503,10 @@ #define RCT2_ADDRESS_CURRENT_FONT_FLAGS 0x013CE9A2 #define RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS 0x013CE9A4 +#define RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT 0x0140E9A4 #define RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT 0x0141E9AC #define RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE 0x0141E9AE -#define RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID 0x0141E9AE #define RCT2_ADDRESS_CURRENT_ROTATION 0x0141E9E0 #define RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS 0x0141E9E4 @@ -463,6 +515,7 @@ #define RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER 0x0141ED68 +// This value is always 4 times the actual type #define RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE 0x0141F56C #define RCT2_ADDRESS_WATER_RAISE_COST 0x0141F738 @@ -481,7 +534,7 @@ #define RCT2_ADDRESS_NEW_WINDOW_PTR 0x014234B8 #define RCT2_ADDRESS_VIEWPORT_LIST 0x014234BC -// Null Terminated list of active viewport pointers. +// Null Terminated list of active viewport pointers. // This is also the end of RCT2_ADDRESS_VIEWPORT_LIST. #define RCT2_ADDRESS_ACTIVE_VIEWPORT_PTR_ARRAY 0x01423570 @@ -557,9 +610,9 @@ #define RCT2_ADDRESS_INPUT_QUEUE 0x01424340 -#define RCT2_ADDRESS_AUDIO_INFO 0x01425B40 +#define RCT2_ADDRESS_PALETTE 0x01424680 -#define RCT2_ADDRESS_SOUND_CHANNEL_LIST 0x014262E0 +#define RCT2_ADDRESS_AUDIO_INFO 0x01425B40 #define RCT2_ADDRESS_COMMON_FORMAT_ARGS 0x013CE952 @@ -582,6 +635,7 @@ #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 +#define RCT2_ADDRESS_NAUSEA_THRESHOLDS 0x00982390 //uint16 #pragma endregion @@ -596,48 +650,7 @@ *P = Parity flag *All other bits are undefined. */ -static int RCT2_CALLPROC_X(int address, int _eax, int _ebx, int _ecx, int _edx, int _esi, int _edi, int _ebp) -{ - #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] - lahf - pop ebp - 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\ - lahf \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 -} +int RCT2_CALLPROC_X(int address, int _eax, int _ebx, int _ecx, int _edx, int _esi, int _edi, int _ebp); static int RCT2_CALLPROC_EBPSAFE(int address) { @@ -655,147 +668,64 @@ static int RCT2_CALLPROC_EBPSAFE(int address) *P = Parity flag *All other bits are undefined. */ -static int RCT2_CALLFUNC_X(int address, int *_eax, int *_ebx, int *_ecx, int *_edx, int *_esi, int *_edi, int *_ebp) +int RCT2_CALLFUNC_X(int address, int *_eax, int *_ebx, int *_ecx, int *_edx, int *_esi, int *_edi, int *_ebp); + +typedef struct { + union { + int eax; + short ax; + struct { + char al; + char ah; + }; + }; + union { + int ebx; + short bx; + struct { + char bl; + char bh; + }; + }; + union { + int ecx; + short cx; + struct { + char cl; + char ch; + }; + }; + union { + int edx; + short dx; + struct { + char dl; + char dh; + }; + }; + union { + int esi; + short si; + }; + union { + int edi; + short di; + }; + union { + int ebp; + short bp; + }; +} registers; + +static int RCT2_CALLFUNC_Y(int address, registers *inOut) { - #ifdef _MSC_VER - __asm { - // Store C's base pointer - push ebp - push ebx - // Store address to call - push address + return RCT2_CALLFUNC_X(address, &inOut->eax, &inOut->ebx, &inOut->ecx, &inOut->edx, &inOut->esi, &inOut->edi, &inOut->ebp); +} - // Set all registers to the input values - mov eax, [_eax] - mov eax, [eax] - mov ebx, [_ebx] - mov ebx, [ebx] - mov ecx, [_ecx] - mov ecx, [ecx] - mov edx, [_edx] - mov edx, [edx] - mov esi, [_esi] - mov esi, [esi] - mov edi, [_edi] - mov edi, [edi] - mov ebp, [_ebp] - mov ebp, [ebp] - - // Call function - call [esp] - - // Store output eax - push eax - push ebp - push ebx - mov ebp, [esp + 20] - mov ebx, [esp + 16] - - // Get resulting ecx, edx, esi, edi registers - - mov eax, [_edi] - mov [eax], edi - mov eax, [_esi] - mov [eax], esi - mov eax, [_edx] - mov [eax], edx - mov eax, [_ecx] - mov [eax], ecx - - // Pop ebx reg into ecx - pop ecx - mov eax, [_ebx] - mov[eax], ecx - - // Pop ebp reg into ecx - pop ecx - mov eax, [_ebp] - mov[eax], ecx - - pop eax - // Get resulting eax register - mov ecx, [_eax] - mov [ecx], eax - - // Save flags as return in eax - lahf - // Pop address - pop ebp - - pop ebx - pop ebp - } - #else - __asm__ ( "\ - \n\ - /* Store C's base pointer*/ \n\ - push ebp \n\ - push ebx \n\ - \n\ - /* Store %[address] to call*/ \n\ - push %[address] \n\ - \n\ - /* Set all registers to the input values*/ \n\ - mov eax, [%[_eax]] \n\ - mov eax, [eax] \n\ - mov ebx, [%[_ebx]] \n\ - mov ebx, [ebx] \n\ - mov ecx, [%[_ecx]] \n\ - mov ecx, [ecx] \n\ - mov edx, [%[_edx]] \n\ - mov edx, [edx] \n\ - mov esi, [%[_esi]] \n\ - mov esi, [esi] \n\ - mov edi, [%[_edi]] \n\ - mov edi, [edi] \n\ - mov ebp, [%[_ebp]] \n\ - mov ebp, [ebp] \n\ - \n\ - /* Call function*/ \n\ - call [esp] \n\ - \n\ - /* Store output eax */ \n\ - push eax \n\ - push ebp \n\ - push ebx \n\ - mov ebp, [esp + 20] \n\ - mov ebx, [esp + 16] \n\ - /* Get resulting ecx, edx, esi, edi registers*/ \n\ - mov eax, [%[_edi]] \n\ - mov [eax], edi \n\ - mov eax, [%[_esi]] \n\ - mov [eax], esi \n\ - mov eax, [%[_edx]] \n\ - mov [eax], edx \n\ - mov eax, [%[_ecx]] \n\ - mov [eax], ecx \n\ - /* Pop ebx reg into ecx*/ \n\ - pop ecx \n\ - mov eax, [%[_ebx]] \n\ - mov [eax], ecx \n\ - \n\ - /* Pop ebp reg into ecx */\n\ - pop ecx \n\ - mov eax, [%[_ebp]] \n\ - mov [eax], ecx \n\ - \n\ - pop eax \n\ - /* Get resulting eax register*/ \n\ - mov ecx, [%[_eax]] \n\ - mov [ecx], eax \n\ - \n\ - /* Save flags as return in eax*/ \n\ - lahf \n\ - /* Pop address*/ \n\ - pop ebp \n\ - \n\ - pop ebx \n\ - pop ebp \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 +static int RCT2_CALLFUNC_Z(int address, const registers *in, registers *out) +{ + *out = *in; + return RCT2_CALLFUNC_Y(address, out); } #endif diff --git a/src/audio/audio.c b/src/audio/audio.c index 2e69cbff2d..cc91211127 100644 --- a/src/audio/audio.c +++ b/src/audio/audio.c @@ -8,1877 +8,332 @@ * 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 "../interface/viewport.h" #include "../interface/window.h" +#include "../localisation/language.h" #include "../platform/platform.h" +#include "../ride/ride.h" #include "../world/map.h" #include "../world/sprite.h" #include "audio.h" #include "mixer.h" +#include "../openrct2.h" +#include "../util/util.h" + +typedef struct rct_audio_params { + bool in_range; + int volume; + int pan; +} rct_audio_params; -int gAudioDeviceCount; audio_device *gAudioDevices = NULL; +int gAudioDeviceCount; +void *gCrowdSoundChannel = 0; +bool gGameSoundsOff = false; +void *gRainSoundChannel = 0; +rct_ride_music gRideMusicList[AUDIO_MAX_RIDE_MUSIC]; +rct_ride_music_info *gRideMusicInfoList[NUM_DEFAULT_MUSIC_TRACKS]; +rct_ride_music_params gRideMusicParamsList[AUDIO_MAX_RIDE_MUSIC]; +rct_ride_music_params *gRideMusicParamsListEnd; +void *gTitleMusicChannel = 0; rct_vehicle_sound gVehicleSoundList[AUDIO_MAX_VEHICLE_SOUNDS]; rct_vehicle_sound_params gVehicleSoundParamsList[AUDIO_MAX_VEHICLE_SOUNDS]; rct_vehicle_sound_params *gVehicleSoundParamsListEnd; -rct_ride_music gRideMusicList[AUDIO_MAX_RIDE_MUSIC]; -rct_ride_music_params gRideMusicParamsList[AUDIO_MAX_RIDE_MUSIC]; -rct_ride_music_params *gRideMusicParamsListEnd; -void *gCrowdSoundChannel = 0; -void *gTitleMusicChannel = 0; -void audio_init(int i) +rct_audio_params audio_get_params_from_location(int soundId, const rct_xyz16 *location); +void audio_stop_channel(void **channel); + +void audio_init() { - if (SDL_Init(SDL_INIT_AUDIO) < 0) { + int result = SDL_Init(SDL_INIT_AUDIO); + if (result >= 0) + return; + log_fatal("SDL_Init %s", SDL_GetError()); exit(-1); } -} void audio_quit() { SDL_QuitSubSystem(SDL_INIT_AUDIO); } -/** - * Populates audio devices. - */ -void audio_get_devices() +void audio_populate_devices() { - int i; - if (gAudioDevices != NULL) free(gAudioDevices); gAudioDeviceCount = SDL_GetNumAudioDevices(SDL_FALSE); - if (gAudioDeviceCount > 0) { + if (gAudioDeviceCount <= 0) + return; + gAudioDeviceCount++; gAudioDevices = malloc(gAudioDeviceCount * sizeof(audio_device)); + safe_strncpy(gAudioDevices[0].name, language_get_string(5510), AUDIO_DEVICE_NAME_SIZE); - strcpy(gAudioDevices[0].name, "Default sound device"); - for (i = 1; i < gAudioDeviceCount; i++) { - const char *utf8_name = SDL_GetAudioDeviceName(i - 1, SDL_FALSE); - if (utf8_name == NULL) - utf8_name = "(UNKNOWN)"; + for (int i = 1; i < gAudioDeviceCount; i++) { + const char *utf8Name = SDL_GetAudioDeviceName(i - 1, SDL_FALSE); + if (utf8Name == NULL) + utf8Name = language_get_string(5511); - strcpy(gAudioDevices[i].name, utf8_name); + safe_strncpy(gAudioDevices[i].name, utf8Name, AUDIO_DEVICE_NAME_SIZE); } } + +int audio_play_sound_panned(int soundId, int pan, sint16 x, sint16 y, sint16 z) +{ + if (pan == AUDIO_PLAY_AT_LOCATION) + return audio_play_sound_at_location(soundId, x, y, z); + + return audio_play_sound(soundId, 0, pan); } -/** -* -* rct2: 0x00401000 -*/ -void audio_timefunc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2, int channel) +int audio_play_sound_at_location(int soundId, sint16 x, sint16 y, sint16 z) { - rct_sound_channel* sound_channel = &RCT2_ADDRESS(0x014262E0, rct_sound_channel)[channel]; - DWORD status; - DWORD dwCurrentPlayCursor; - DWORD dwCurrentWriteCursor; - uint32 var1; - int var2; - int bufferlost = 0; - char* buf1; - int buf1size; - char* buf2; - int buf2size; - sound_channel->dsbuffer->lpVtbl->GetStatus(sound_channel->dsbuffer, &status); - if (status & DSBSTATUS_BUFFERLOST) { - if (FAILED(sound_channel->dsbuffer->lpVtbl->Restore(sound_channel->dsbuffer))) { - return; - } - sound_channel->playpos = 0; - bufferlost = 1; - } - sound_channel->dsbuffer->lpVtbl->GetCurrentPosition(sound_channel->dsbuffer, &dwCurrentPlayCursor, &dwCurrentWriteCursor); - if (dwCurrentPlayCursor != sound_channel->playpos || bufferlost) { - if (sound_channel->var_168 && !sound_channel->var_15C) { - if (!sound_channel->stopped) { - sound_channel->stopped = 1; - if (!sound_channel->var_4) { - LPDIRECTSOUNDBUFFER dsbuffer = RCT2_ADDRESS(RCT2_ADDRESS_DSOUND_BUFFERS, LPDIRECTSOUNDBUFFER)[channel]; - sound_channel->playing = 0; - if (dsbuffer) { - dsbuffer->lpVtbl->Stop(dsbuffer); - dsbuffer->lpVtbl->Release(dsbuffer); - RCT2_ADDRESS(RCT2_ADDRESS_DSOUND_BUFFERS, LPDIRECTSOUNDBUFFER)[channel] = 0; - } - if (sound_channel->hmmio) { - sound_channel_free(&sound_channel->hmmio, &sound_channel->hmem); - } - } - } - return; - } - if (dwCurrentPlayCursor >= sound_channel->playpos) { - var1 = dwCurrentPlayCursor - sound_channel->playpos; - } else { - var1 = dwCurrentPlayCursor + sound_channel->bufsize - sound_channel->playpos; - } - if (bufferlost) { - var2 = 2 * sound_channel->bufsize / 6; - } else { - var2 = var1; - } - sound_channel->var_158 += var1; - if (sound_channel->var_168) { - uint32 var3 = sound_channel->var_15C; - uint32* var4 = &sound_channel->var_15C; - if (var3) { - if (var1 <= var3) { - *var4 = var3 - var1; - } else { - *var4 = 0; - } - if (SUCCEEDED(sound_channel->dsbuffer->lpVtbl->Lock(sound_channel->dsbuffer, sound_channel->playpos, var2, (LPVOID*)&buf1, (LPDWORD)&buf1size, (LPVOID*)&buf2, (LPDWORD)&buf2size, 0))) { - uint16 var5 = -(sound_channel->mmckinfo1.cksize != 8); - var5 &= 0x80; - memset(buf1, var5 + 128, buf1size); - if (buf2 && buf2size) { - uint16 var5 = -(sound_channel->mmckinfo1.cksize != 8); - var5 &= 0x80; - memset(buf2, var5 + 128, buf2size); - } - sound_channel->dsbuffer->lpVtbl->Unlock(sound_channel->dsbuffer, buf1, buf1size, buf2, buf2size); - sound_channel->playpos += var2; - if (sound_channel->playpos >= sound_channel->bufsize) { - sound_channel->playpos = sound_channel->playpos - sound_channel->bufsize; - } - return; - } - // TimeFunc() could not lock DirectSoundBuffer - return; - } - } - if (FAILED(sound_channel->dsbuffer->lpVtbl->Lock(sound_channel->dsbuffer, sound_channel->playpos, var2, (LPVOID*)&buf1, (LPDWORD)&buf1size, (LPVOID*)&buf2, (LPDWORD)&buf2size, 0))) { - // TimeFunc() could not lock DirectSoundBuffer - return; - } - if (buf1size) { - if (sound_channel->stopped) { - uint16 var5 = -(sound_channel->mmckinfo1.cksize != 8); - var5 &= 0x80; - memset(buf1, var5 + 128, buf1size); - goto label49; - } - } - int var7; - mmio_read(sound_channel->hmmio, buf1size, buf1, &sound_channel->mmckinfo1, &var7); - if (var7 < buf1size) { - if (!sound_channel->var_164) { - int s = sound_channel->mmckinfo1.cksize; - int t = buf1size - var7; - int v; - if (s == 8) { - v = 128; - } else { - if (s != 16) { - goto label42; - } - v = 0; - } - memset(&buf1[var7], v, t); - label42: - sound_channel->var_168 = 1; - if (dwCurrentPlayCursor <= sound_channel->playpos) { - sound_channel->var_15C = sound_channel->playpos - dwCurrentPlayCursor; - } else { - sound_channel->var_15C = sound_channel->playpos + sound_channel->bufsize - dwCurrentPlayCursor; - } - goto label49; - } - char* v21 = buf1; - int v38 = buf1size; - do { - v38 -= var7; - v21 += var7; - sub_40153B(channel); - mmio_read(sound_channel->hmmio, v38, v21, &sound_channel->mmckinfo1, &var7); - } while(var7 < v38); - } - label49: - if (buf2size == 0 || sound_channel->stopped != 0) { - if(buf2 != 0 && buf2size != 0 && sound_channel->stopped != 0) { - int var5 = -(sound_channel->mmckinfo1.cksize != 8); - var5 &= 0x80; - memset(buf2, var5 + 128, buf2size); - } - goto label68; - } - mmio_read(sound_channel->hmmio, buf2size, buf2, &sound_channel->mmckinfo1, &var7); - if (var7 >= buf2size) { - label68: - sound_channel->dsbuffer->lpVtbl->Unlock(sound_channel->dsbuffer, buf1, buf1size, buf2, buf2size); - sound_channel->playpos += var2; - if (sound_channel->playpos >= sound_channel->bufsize) { - sound_channel->playpos -= sound_channel->bufsize; - } - if (bufferlost != 0) { - sound_channel->dsbuffer->lpVtbl->Play(sound_channel->dsbuffer, 0, 0, DSBPLAY_LOOPING); - } - return; - } - if (sound_channel->var_164 != 0) { - char* v26 = buf2; - int v27 = buf2size; - do { - v26 += var7; - v27 -= var7; - sub_40153B(channel); - mmio_read(sound_channel->hmmio, v27, v26, &sound_channel->mmckinfo1, &var7); - } while(var7 < v27); - goto label68; - } - int s = buf2size - var7; - int v; - if (sound_channel->hmem == (HGLOBAL)8) { - v = 128; - } else { - if (sound_channel->hmem != (HGLOBAL)16) { - goto label58; - } - v = 0; - } - memset(&buf2[var7], v, s); - label58: - sound_channel->var_168 = 1; - if (dwCurrentPlayCursor <= sound_channel->playpos) { - sound_channel->var_15C = sound_channel->playpos - dwCurrentPlayCursor; - } else { - sound_channel->var_15C = sound_channel->playpos + sound_channel->bufsize - dwCurrentPlayCursor; - } - goto label68; - } -} - -/** -* -* rct2: 0x004014DF -*/ -int CALLBACK audio_timer_callback(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) -{ - if (_InterlockedExchange(&RCT2_GLOBAL(0x009E1AAC, LONG), 1) == 0) { - for (int i = 0; i < 4; i++) { - rct_sound_channel* sound_channel = &RCT2_ADDRESS(RCT2_ADDRESS_SOUND_CHANNEL_LIST, rct_sound_channel)[i]; - if(sound_channel->playing){ - audio_timefunc(uTimerID, uMsg, dwUser, dw1, dw2, i); - } - } - return _InterlockedExchange(&RCT2_GLOBAL(0x009E1AAC, LONG), 0); - } - return 0; -} - -/** -* -* rct2: 0x0040153B -*/ -int sub_40153B(int channel) -{ - rct_sound_channel* sound_channel = &RCT2_ADDRESS(0x014262E0, rct_sound_channel)[channel]; - if (sound_channel->var_4) { - if (sound_channel->hmmio) { - sound_channel_free(&sound_channel->hmmio, &sound_channel->hmem); - } - if (mmio_open_channel(channel, sound_channel->filename, sound_channel->var_110)) { - return 0; - } - sound_channel->var_164 = sound_channel->var_114; - sound_channel->var_118 = sound_channel->var_110; - sound_channel->var_4 = 0; - } else { - int result = mmio_seek(&sound_channel->hmmio, &sound_channel->mmckinfo1, &sound_channel->mmckinfo2, sound_channel->var_118); - sound_channel->var_158 = sound_channel->var_118; - if (result) { - return 0; - } - } - return 1; -} - -/** -* -* rct2: 0x004015E7 -*/ -int sub_4015E7(int channel) -{ - char* buf1; - int buf1size; - char* buf2; - int buf2size; - int read; - int zero = 0; - rct_sound_channel* sound_channel = &RCT2_ADDRESS(0x014262E0, rct_sound_channel)[channel]; - LPDIRECTSOUNDBUFFER dsbuffer = RCT2_ADDRESS(RCT2_ADDRESS_DSOUND_BUFFERS, LPDIRECTSOUNDBUFFER)[channel]; - int result = dsbuffer->lpVtbl->Lock(dsbuffer, 0, sound_channel->bufsize, (LPVOID*)&buf1, (LPDWORD)&buf1size, (LPVOID*)&buf2, (LPDWORD)&buf2size, 0); - if (SUCCEEDED(result)) { - if (buf1size) { - mmio_read(sound_channel->hmmio, buf1size, buf1, &sound_channel->mmckinfo1, &read); - int r = read; - if (read < buf1size) { - if (sound_channel->var_164) { - char* b = buf1; - int d = buf1size; - do { - d -= r; - b += r; - sub_40153B(channel); - mmio_read(sound_channel->hmmio, d, b, &sound_channel->mmckinfo1, &read); - r = read; - } while(read < d); - } else { - sound_channel->var_168 = 1; - sound_channel->var_15C = read; - LPWAVEFORMATEX waveformat = sound_channel->hmem; - uint16 v = ((waveformat->nBlockAlign != 8) - 1) & 0x80; - memset(&buf1[read], v, buf1size - r); - } - } - } - result = dsbuffer->lpVtbl->Unlock(dsbuffer, buf1, buf1size, buf2, zero); - sound_channel->var_158 = 0; - sound_channel->playpos = 0; - } - return result; -} - -/** -* -* rct2: 0x004016FF -*/ -int sound_channel_load_file(int channel, const char* filename, int offset) -{ - rct_sound_channel* sound_channel = &RCT2_ADDRESS(0x014262E0, rct_sound_channel)[channel]; - sound_channel->hmem; - sound_channel->hmmio; - if (mmio_open(filename, &sound_channel->hmmio, &sound_channel->hmem, &sound_channel->mmckinfo2)) { - return -100; - } - if (*(uint16*)sound_channel->hmem != 1) { - sound_channel_free(&sound_channel->hmmio, &sound_channel->hmem); - return -101; - } - if (mmio_seek(&sound_channel->hmmio, &sound_channel->mmckinfo1, &sound_channel->mmckinfo2, offset)) { - sound_channel_free(&sound_channel->hmmio, &sound_channel->hmem); - return -103; - } - sound_channel->bufsize = 120 * *((uint32*)sound_channel->hmem + 2) / 100; - DSBUFFERDESC bufferdesc; - memset(&bufferdesc, 0, sizeof(bufferdesc)); - bufferdesc.dwFlags = RCT2_GLOBAL(0x009E1AA8, uint32) | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY; - bufferdesc.dwBufferBytes = sound_channel->bufsize; - bufferdesc.lpwfxFormat = sound_channel->hmem; - bufferdesc.dwSize = sizeof(bufferdesc); - int ret = RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->CreateSoundBuffer(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), &bufferdesc, &RCT2_ADDRESS(RCT2_ADDRESS_DSOUND_BUFFERS, LPDIRECTSOUNDBUFFER)[channel], 0); - if (FAILED(ret)) { - return -102; - } - sound_channel->dsbuffer = RCT2_ADDRESS(RCT2_ADDRESS_DSOUND_BUFFERS, LPDIRECTSOUNDBUFFER)[channel]; - sound_channel->var_168 = 0; - sound_channel->var_15C = 0; - sound_channel->var_164 = 1; - sub_4015E7(channel); - sound_channel->var_158 = offset; - sound_channel->stopped = 0; - return 0; -} - -/** -* -* rct2: 0x00401822 -*/ -int mmio_open_channel(int channel, char* filename, LONG offset) -{ - rct_sound_channel* sound_channel = &RCT2_ADDRESS(0x014262E0, rct_sound_channel)[channel]; - LPMMCKINFO v4 = &sound_channel->mmckinfo2; - HMMIO* v5 = &sound_channel->hmmio; - if (mmio_open(filename, &sound_channel->hmmio, &sound_channel->hmem, &sound_channel->mmckinfo2)) { - return -100; - } - if (*(uint16*)sound_channel->hmem != 1) { - sound_channel_free(&sound_channel->hmmio, &sound_channel->hmem); - return -101; - } - if (mmio_seek(&sound_channel->hmmio, &sound_channel->mmckinfo1, &sound_channel->mmckinfo2, offset)) { - sound_channel_free(&sound_channel->hmmio, &sound_channel->hmem); - return -103; - } - sound_channel->var_158 = offset; - return 0; -} - -/** -* -* rct2: 0x004018A6 -*/ -int audio_create_timer() -{ - if (RCT2_GLOBAL(0x009E1AA4, int)) { + if (gGameSoundsOff) return 0; - } - for (int i = 0; i < 4; i++) { - rct_sound_channel* sound_channel = &RCT2_ADDRESS(RCT2_ADDRESS_SOUND_CHANNEL_LIST, rct_sound_channel)[i]; - sound_channel->playing = 0; - } - RCT2_GLOBAL(0x009E1AA0, MMRESULT) = timeSetEvent(50, 10, (LPTIMECALLBACK)audio_timer_callback, 0, TIME_PERIODIC); - if (!RCT2_GLOBAL(0x009E1AA0, MMRESULT)) { - return 0; - } - RCT2_GLOBAL(0x009E1AA4, int) = 1; - return 1; + + rct_xyz16 location; + location.x = x; + location.y = y; + location.z = z; + + rct_audio_params params = audio_get_params_from_location(soundId, &location); + if (!params.in_range) + return soundId; + + return audio_play_sound(soundId, params.volume, params.pan); } /** -* -* rct2: 0x004018F0 +* Returns the audio parameters to use when playing the specified sound at a virtual location. +* @param soundId The sound effect to be played. +* @param location The location at which the sound effect is to be played. +* @return The audio parameters to be used when playing this sound effect. */ -int audio_remove_timer() +rct_audio_params audio_get_params_from_location(int soundId, const rct_xyz16 *location) { - for (int i = 0; i < 4; i++) { - sound_channel_stop(i); - } - if (RCT2_GLOBAL(0x009E1AA4, int)) { - timeKillEvent(RCT2_GLOBAL(0x009E1AA0, MMRESULT)); - timeEndPeriod(50); - while (_InterlockedExchange(&RCT2_GLOBAL(0x009E1AAC, LONG), 1) != 1) { - Sleep(100); - } - int result = _InterlockedExchange(&RCT2_GLOBAL(0x009E1AAC, LONG), 0); - RCT2_GLOBAL(0x009E1AA4, int) = 0; - return result; - } - return 0; -} + int volumeDown = 0; + rct_audio_params params; + params.in_range = true; -/** -* -* rct2: 0x0040194E -*/ -int sound_channel_load_file2(int channel, const char* filename, int offset) -{ - if (!RCT2_GLOBAL(0x009E1AA4, int)) { - return 0; - } - if (sound_channel_is_playing(channel)) { - sound_channel_stop(channel); - } - if (SUCCEEDED(sound_channel_load_file(channel, filename, offset))) { - RCT2_ADDRESS(RCT2_ADDRESS_SOUND_CHANNEL_LIST, rct_sound_channel)[channel].var_4 = 0; - return 1; - } - return 0; -} + rct_map_element *element = map_get_surface_element_at(location->x / 32, location->y / 32); + if (element && (element->base_height * 8) - 5 > location->z) + volumeDown = 10; -/** -* -* rct2: 0x00401999 -*/ -int sound_channel_play(int channel, int a2, int volume, int pan, int frequency) -{ - rct_sound_channel* sound_channel = &RCT2_ADDRESS(RCT2_ADDRESS_SOUND_CHANNEL_LIST, rct_sound_channel)[channel]; - sound_channel->var_164 = a2; - sound_channel_set_frequency(channel, frequency); - sound_channel_set_pan(channel, pan); - sound_channel_set_volume(channel, volume); - LPDIRECTSOUNDBUFFER dsbuffer = RCT2_ADDRESS(RCT2_ADDRESS_DSOUND_BUFFERS, LPDIRECTSOUNDBUFFER)[channel]; - dsbuffer->lpVtbl->SetCurrentPosition(dsbuffer, 0); - dsbuffer->lpVtbl->Play(dsbuffer, 0, 0, DSBPLAY_LOOPING); - sound_channel->playing = 1; - return 1; -} - -/** -* -* rct2: 0x00401A05 -*/ -int sound_channel_stop(int channel) -{ - rct_sound_channel* sound_channel = &RCT2_ADDRESS(RCT2_ADDRESS_SOUND_CHANNEL_LIST, rct_sound_channel)[channel]; - sound_channel->playing = 0; - sound_channel->stopped = 1; - while (_InterlockedExchange(&RCT2_GLOBAL(0x009E1AAC, LONG), 1) != 1) { - Sleep(10); - } - if (sound_channel->hmmio) { - sound_channel_free(&sound_channel->hmmio, &sound_channel->hmem); - } - - LPDIRECTSOUNDBUFFER dsbuffer = RCT2_ADDRESS(RCT2_ADDRESS_DSOUND_BUFFERS, LPDIRECTSOUNDBUFFER)[channel]; - if (dsbuffer) { - dsbuffer->lpVtbl->Stop(dsbuffer); - dsbuffer->lpVtbl->Release(dsbuffer); - RCT2_ADDRESS(RCT2_ADDRESS_DSOUND_BUFFERS, LPDIRECTSOUNDBUFFER)[channel] = 0; - } - _InterlockedExchange(&RCT2_GLOBAL(0x009E1AAC, LONG), 0); - return 1; -} - -/** -* -* rct2: 0x00401A93 -*/ -int sound_channel_set_frequency(int channel, int frequency) -{ - LPDIRECTSOUNDBUFFER dsbuffer = RCT2_ADDRESS(RCT2_ADDRESS_DSOUND_BUFFERS, LPDIRECTSOUNDBUFFER)[channel]; - if (dsbuffer) { - if (SUCCEEDED(dsbuffer->lpVtbl->SetFrequency(dsbuffer, frequency))) - return 1; - - } - return 0; -} - -/** -* -* rct2: 0x00401AB3 -*/ -int sound_channel_set_pan(int channel, int pan) -{ - LPDIRECTSOUNDBUFFER dsbuffer = RCT2_ADDRESS(RCT2_ADDRESS_DSOUND_BUFFERS, LPDIRECTSOUNDBUFFER)[channel]; - if (dsbuffer) { - if (SUCCEEDED(dsbuffer->lpVtbl->SetPan(dsbuffer, pan))) - return 1; - - } - return 0; -} - -/** -* -* rct2: 0x00401AD3 -*/ -int sound_channel_set_volume(int channel, int volume) -{ - LPDIRECTSOUNDBUFFER dsbuffer = RCT2_ADDRESS(RCT2_ADDRESS_DSOUND_BUFFERS, LPDIRECTSOUNDBUFFER)[channel]; - if (dsbuffer) { - if (SUCCEEDED(dsbuffer->lpVtbl->SetVolume(dsbuffer, volume))) - return 1; - - } - return 0; -} - -/** -* -* rct2: 0x00401AF3 -*/ -void sub_401AF3(int channel, const char* filename, int a3, int a4) -{ - rct_sound_channel* sound_channel = &RCT2_ADDRESS(RCT2_ADDRESS_SOUND_CHANNEL_LIST, rct_sound_channel)[channel]; - sound_channel->var_4 = 1; - memcpy(sound_channel->filename, filename, sizeof(sound_channel->filename)); - sound_channel->var_10C = 0; - sound_channel->var_110 = a4; - sound_channel->var_114 = a3; - sound_channel->var_164 = 1; -} - -/** -* -* rct2: 0x00401B46 -*/ -int sub_401B46(int channel) -{ - rct_sound_channel* sound_channel = &RCT2_ADDRESS(RCT2_ADDRESS_SOUND_CHANNEL_LIST, rct_sound_channel)[channel]; - if (sound_channel->stopped) { - return 0; - } else { - return sound_channel->var_158; - } -} - -/** -* -* rct2: 0x00401B63 -*/ -int sound_channel_is_playing(int channel) -{ - if (RCT2_ADDRESS(RCT2_ADDRESS_SOUND_CHANNEL_LIST, rct_sound_channel)[channel].playing) { - return RCT2_ADDRESS(RCT2_ADDRESS_SOUND_CHANNEL_LIST, rct_sound_channel)[channel].stopped == 0; - } else { - return 0; - } -} - -/** -* -* rct2: 0x00404BD2 -*/ -int audio_release() -{ - sound_stop_all(); - if (RCT2_GLOBAL(0x009E2BA4, LPDIRECTSOUND3DBUFFER)) { - RCT2_GLOBAL(0x009E2BA4, LPDIRECTSOUND3DBUFFER)->lpVtbl->Release(RCT2_GLOBAL(0x009E2BA4, LPDIRECTSOUND3DBUFFER)); - RCT2_GLOBAL(0x009E2BA4, LPDIRECTSOUND3DBUFFER) = 0; - } - if (RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER)) { - RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER)->lpVtbl->Release(RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER)); - RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER) = 0; - } - int result = 0; - if (RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)) { - result = RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->Release(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)); - RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND) = 0; - } - return result; -} - -/** -* -* rct2: 0x00404C1A -*/ -int map_sound_effects(const char* filename) -{ - if (RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, LPVOID)) { - return 0; - } else { - RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, LPVOID) = map_file(filename, 0, 0); - return RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, LPVOID) != 0; - } -} - -/** -* -* rct2: 0x00404C45 -*/ -int unmap_sound_effects() -{ - if (RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, LPVOID)) { - sound_stop_all(); - unmap_file(RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, LPVOID)); - RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, LPVOID) = 0; - return 1; - } - return 0; -} - -/** -* -* rct2: 0x00404C6D -*/ -int sound_prepare(int sound_id, rct_sound *sound, int channels, int software) -{ - DSBUFFERDESC bufferdesc; - char* buffer = 0; - memset(&bufferdesc, 0, sizeof(bufferdesc)); - bufferdesc.dwSize = sizeof(bufferdesc); - rct_sound* tempsound = sound_begin(); - if (tempsound) { - int wasduplicated = 0; - while (!tempsound->dsbuffer || tempsound->id != sound_id || !sound_duplicate(sound, tempsound)) { - tempsound = sound_next(tempsound); - if (!tempsound) { - wasduplicated = 1; - break; - } - } - if (!wasduplicated) { - return 1; - } - } - rct_sound_effect* sound_effect = sound_get_effect(sound_id); - if (sound_effect) { - if (sound_effect_loadvars(sound_effect, &bufferdesc.lpwfxFormat, &buffer, &bufferdesc.dwBufferBytes)) { - if (channels == 0){ - bufferdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STATIC; - } - else if (channels == 2) { - bufferdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRL3D | DSBCAPS_STATIC; - } 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; - } - sound->dsbuffer->lpVtbl->Release(sound->dsbuffer); - sound->dsbuffer = 0; - } - sound->dsbuffer = 0; - } - } - return 0; -} - -/** -* -* rct2: 0x00404D99 -*/ -int sound_duplicate(rct_sound* newsound, rct_sound* sound) -{ - if (FAILED(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->DuplicateSoundBuffer(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), sound->dsbuffer, &newsound->dsbuffer))) { - return 0; - } else { - newsound->id = sound->id; - newsound->has_caps = sound->has_caps; - newsound->var_0C = sound->var_0C; - sound_add(newsound); - return 1; - } -} - -/** -* -* rct2: 0x00404DD8 -*/ -int sound_stop(rct_sound* sound) -{ - if (sound->dsbuffer) { - sound->dsbuffer->lpVtbl->Release(sound->dsbuffer); - sound->dsbuffer = 0; - return sound_remove(sound) ? 1 : 0; - } - return 0; -} - -/** -* -* rct2: 0x00404DF5 -*/ -int sound_stop_all() -{ - int result = 0; - while (RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_BEGIN, rct_sound*)) { - result = sound_stop(RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_BEGIN, rct_sound*)); - } - return result; -} - -/** -* -* rct2: 0x00404E0D -*/ -void sound_bufferlost_check() -{ - rct_sound* sound = RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_BEGIN, rct_sound*); - while (sound && sound != RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_END, rct_sound*)) { - DWORD status; - if (SUCCEEDED(sound->dsbuffer->lpVtbl->GetStatus(sound->dsbuffer, &status))) { - if (status & DSBSTATUS_BUFFERLOST) { - sound_bufferlost_restore(sound); - } - } - sound = sound->next; - } -} - -/** -* -* rct2: 0x00404E53 -*/ -int sound_is_playing(rct_sound* sound){ - if (sound->dsbuffer) { - DWORD status; - if (SUCCEEDED(sound->dsbuffer->lpVtbl->GetStatus(sound->dsbuffer, &status))) { - if (status & DSBSTATUS_PLAYING || status & DSBSTATUS_LOOPING) - return 1; - - } - } - return 0; -} - -/** -* -* rct2: 0x00404E7F -*/ -int sound_play(rct_sound* sound, int looping, int volume, int pan, int frequency) -{ - if (sound->dsbuffer) { - sound_set_frequency(sound, frequency); - sound_set_pan(sound, pan); - sound_set_volume(sound, volume); - DWORD playflags; - if (looping) { - if (looping != 1) - return 1; - - playflags = DSBPLAY_LOOPING; - } else { - playflags = 0; - } - if (SUCCEEDED(sound->dsbuffer->lpVtbl->Play(sound->dsbuffer, 0, 0, playflags))) - return 1; - - } - return 0; -} - -/** -* -* rct2: 0x00404ED7 -*/ -int sound_set_frequency(rct_sound* sound, int frequency) -{ - if (sound->dsbuffer) { - if (SUCCEEDED(sound->dsbuffer->lpVtbl->SetFrequency(sound->dsbuffer, frequency))) - return 1; - - } - return 0; -} - -/** -* -* rct2: 0x00404EF2 -*/ -int sound_set_pan(rct_sound* sound, int pan) -{ - if (sound->dsbuffer) { - if (SUCCEEDED(sound->dsbuffer->lpVtbl->SetPan(sound->dsbuffer, pan))) - return 1; - - } - return 0; -} - -/** -* -* rct2: 0x00404F0D -*/ -int sound_set_volume(rct_sound* sound, int volume) -{ - if (sound->dsbuffer) { - if (SUCCEEDED(sound->dsbuffer->lpVtbl->SetVolume(sound->dsbuffer, volume))) - return 1; - - } - return 0; -} - -/** -* -* rct2: 0x000404F28 -*/ -int sound_load3dparameters() -{ - if (SUCCEEDED(RCT2_GLOBAL(0x009E2BA4, LPDIRECTSOUND3DBUFFER)->lpVtbl->GetAllParameters(RCT2_GLOBAL(0x009E2BA4, LPDIRECTSOUND3DBUFFER), &RCT2_GLOBAL(0x009A6084, DS3DBUFFER)))) { - return 1; - } - return 0; -} - -/** -* -* rct2: 0x00404F3F -*/ -int sound_load3dposition() -{ - /*if (SUCCEEDED(RCT2_GLOBAL(0x009E2BA4, LPDIRECTSOUND3DBUFFER)->lpVtbl->GetPosition(RCT2_GLOBAL(0x009E2BA4, LPDIRECTSOUND3DBUFFER), &RCT2_GLOBAL(0x009A6084, D3DVECTOR), 1))) { - return 1; - }*/ - return 0; -} - -/** -* -* rct2: 0x00404F85 -*/ -BOOL CALLBACK dsound_enum_callback_count(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext) -{ - RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES_COUNTER, int)++; - return 1; -} - -/** -* -* rct2: 0x00404F91 -*/ -int dsound_count_devices() -{ - RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES_COUNTER, int) = 0; - if (SUCCEEDED(DirectSoundEnumerate(dsound_enum_callback_count, 0))) { - return RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES_COUNTER, int); - } - return 0; -} - -/** -* -* rct2: 0x00404FB1 -*/ -BOOL CALLBACK dsound_enum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext) -{ - if (lpGuid) { - memcpy(&RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES, rct_dsdevice*)[RCT2_GLOBAL(0x01425B54, int)].guid, lpGuid, sizeof(GUID)); - } else { - memset(&RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES, rct_dsdevice*)[RCT2_GLOBAL(0x01425B54, int)].guid, 0, sizeof(GUID)); - } - strcpy(RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES, rct_dsdevice*)[RCT2_GLOBAL(0x01425B54, int)].desc, lpcstrDescription); - strcpy(RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES, rct_dsdevice*)[RCT2_GLOBAL(0x01425B54, int)].drvname, lpcstrModule); - RCT2_GLOBAL(0x01425B54, int)++; - return 1; -} - -/** -* -* rct2: 0x00405054 -*/ -int sound_effect_loadvars(rct_sound_effect* sound_effect, LPWAVEFORMATEX* waveformat, char** data, DWORD* buffersize) -{ - *buffersize = sound_effect->size; - *waveformat = &sound_effect->format; - *data = (char*)&sound_effect->data; - return 1; -} - -/** -* -* rct2: 0x00405076 -*/ -int sound_fill_buffer(LPDIRECTSOUNDBUFFER dsbuffer, char* src, DWORD size) -{ - LPVOID buf; - LPVOID buf2; - DWORD buf2size; - if (SUCCEEDED(dsbuffer->lpVtbl->Lock(dsbuffer, 0, size, &buf, &size, &buf2, &buf2size, 0))) { - memset(buf, 0, size); - memcpy(buf, src, size); - if (buf2size) { - memcpy(buf2, &src[size], buf2size); - } - dsbuffer->lpVtbl->Unlock(dsbuffer, buf, size, buf2, buf2size); - return 1; - } - return 0; -} - -/** -* -* rct2: 0x00405103 -*/ -rct_sound* sound_begin() -{ - return RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_BEGIN, rct_sound*); -} - -/** -* -* rct2: 0x00405109 -*/ -rct_sound* sound_next(rct_sound* sound) -{ - if (RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_END, rct_sound*) == sound) { - return 0; - } else { - return sound->next; - } -} - -/** -* -* rct2: 0x0040511C -*/ -rct_sound* sound_add(rct_sound* sound) -{ - if (RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_BEGIN, rct_sound*)) { - RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_END, rct_sound*)->next = sound; - } else { - RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_BEGIN, rct_sound*) = sound; - } - RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_END, rct_sound*) = sound; - sound->next = 0; - return sound; -} - -/** -* -* rct2: 0x00405143 -*/ -rct_sound* sound_remove(rct_sound* sound) -{ - rct_sound* result = RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_BEGIN, rct_sound*); - if (sound == result) { - if (sound == RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_END, rct_sound*)) { - RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_END, rct_sound*) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_BEGIN, rct_sound*) = 0; - } - result = sound->next; - RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_BEGIN, rct_sound*) = result; - } else { - while (result->next != sound) - result = result->next; - - if (sound == RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_END, rct_sound*)) { - RCT2_GLOBAL(RCT2_ADDRESS_SOUNDLIST_END, rct_sound*) = result; - result->next = 0; - } else - result->next = sound->next; - - } - sound->next = 0; - return result; -} - -/** -* -* rct2: 0x00405199 -*/ -int sound_bufferlost_restore(rct_sound* sound) -{ - DWORD buffersize = 0; - LPWAVEFORMATEX waveformat = 0; - char* data = 0; - if (sound) { - if (SUCCEEDED(sound->dsbuffer->lpVtbl->Restore(sound->dsbuffer))) { - rct_sound_effect* sound_effect = sound_get_effect(sound->id); - if (sound_effect != 0) { - return sound_effect_loadvars(sound_effect, &waveformat, &data, &buffersize) && sound_fill_buffer(sound->dsbuffer, data, buffersize); - } - } - } - return 0; -} - -/** -* -* rct2: 0x00405206 -*/ -rct_sound_effect* sound_get_effect(uint16 sound_id) -{ - if (RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, LPVOID) && sound_id < RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, uint32*)[0]) { - return (rct_sound_effect*)(RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, int) + RCT2_GLOBAL(RCT2_ADDRESS_SOUND_EFFECTS_MAPPING, uint32*)[sound_id + 1]); - } - return 0; -} - -/** -* -* rct2: 0x00405222 -*/ -MMRESULT mmio_open(const char* filename, HMMIO* hmmio, HGLOBAL* hmem, LPMMCKINFO mmckinfo) -{ - HGLOBAL* hmemold; - HGLOBAL hmemold2; - HMMIO hmmio1; - MMRESULT result; - MMCKINFO mmckinfo1; - WAVEFORMATEX waveformat; - - hmemold = hmem; - *hmem = 0; - hmmio1 = mmioOpenA((char*)filename, 0, MMIO_ALLOCBUF); - if (hmmio1) { - result = mmioDescend(hmmio1, mmckinfo, 0, 0); - if (result != MMSYSERR_NOERROR) { - goto label20; - } - if (mmckinfo->ckid != 1179011410/*RIFF*/ || mmckinfo->fccType != 1163280727/*WAVE*/) { - result = 57601; - goto label20; - } - mmckinfo1.ckid = 544501094/*fmt*/; - result = mmioDescend(hmmio1, &mmckinfo1, mmckinfo, MMIO_FINDCHUNK); - if (result != MMSYSERR_NOERROR) { - goto label20; - } - if (mmckinfo1.cksize < 16) { - label19: - result = 57601; - goto label20; - } - if (mmioRead(hmmio1, (HPSTR)&waveformat, 16) == 16) { - if (waveformat.wFormatTag == 1) { - //strcpy(audio_info.var_0, "\x01"); - hmem = 0; - label11: - hmemold2 = GlobalAlloc(0, (SIZE_T)(hmem + 18)); - *hmemold = hmemold2; - if (!hmemold2) { - result = 57344; - goto label20; - } - memcpy(hmemold2, &waveformat, 16); - *((uint16*)*hmemold + 8) = (uint16)hmem; - if (!hmem || mmioRead(hmmio1, (char*)*hmemold + 18, (LONG)hmem) == (LONG)hmem) { - result = mmioAscend(hmmio1, &mmckinfo1, 0); - if (!result) { - goto label24; - } - goto label20; - } - goto label19; - } - if (mmioRead(hmmio1, (HPSTR)&hmem, 2) == 2) { - goto label11; - } - } - result = 57602; - goto label20; - } - result = 57600; - label20: - if (*hmemold) { - GlobalFree(*hmemold); - *hmemold = 0; - } - if (hmmio1) { - mmioClose(hmmio1, 0); - hmmio1 = 0; - } - label24: - *hmmio = hmmio1; - return result; -} - -/** -* -* rct2: 0x00405383 -*/ -MMRESULT mmio_read(HMMIO hmmio, uint32 size, char* buffer, LPMMCKINFO mmckinfo, int* read) -{ - MMIOINFO mmioinfo; - MMRESULT result; - result = mmioGetInfo(hmmio, &mmioinfo, 0); - if (result != 0) { - *read = 0; - return 1; - } - int size2 = size; - if (size > mmckinfo->cksize) { - size2 = mmckinfo->cksize; - } - int v8 = 0; - mmckinfo->cksize -= size2; - if (size2) { - while (1) { - HPSTR p = mmioinfo.pchEndRead; - if (mmioinfo.pchNext == mmioinfo.pchEndRead) { - result = mmioAdvance(hmmio, &mmioinfo, 0); - if (result != 0) { - *read = 0; - return result; - } - p = mmioinfo.pchEndRead; - if (mmioinfo.pchNext == mmioinfo.pchEndRead) { - break; - } - } - int q = p - mmioinfo.pchNext; - if (size2 - v8 < p - mmioinfo.pchNext) { - q = size2 - v8; - } - memcpy(&buffer[v8], mmioinfo.pchNext, q); - mmioinfo.pchNext += q; - v8 += q; - if (v8 >= size2) { - result = mmioSetInfo(hmmio, &mmioinfo, 0); - if (result != 0) { - *read = 0; - return result; - } else { - *read = size2; - return result; - } - } - } - *read = 0; - return 57603; - } - result = mmioSetInfo(hmmio, &mmioinfo, 0); - if (result != 0) { - *read = 0; - return result; - } else { - *read = size2; - return result; - } -} - -/** -* -* rct2: 0x00405436 -*/ -void sound_channel_free(HMMIO* hmmio, HGLOBAL* hmem) -{ - if(*hmem) - { - GlobalFree(*hmem); - *hmem = 0; - } - if(*hmmio) - { - mmioClose(*hmmio, 0); - *hmmio = 0; - } -} - -/** -* -* rct2: 0x00405465 -*/ -MMRESULT mmio_seek(HMMIO* hmmio, LPMMCKINFO mmckinfo1, LPMMCKINFO mmckinfo2, int offset) -{ - mmioSeek(*hmmio, mmckinfo2->dwDataOffset + 4, SEEK_SET); - mmckinfo1->ckid = 1635017060/*DATA*/; - MMRESULT result = mmioDescend(*hmmio, mmckinfo1, mmckinfo2, MMIO_FINDCHUNK); - if (!result) { - mmioSeek(*hmmio, offset, SEEK_CUR); - return 0; - } - return result; -} - -/** -* -* rct2: 0x004067F9 -*/ -LPVOID map_file(LPCSTR lpFileName, DWORD dwCreationDisposition, DWORD dwNumberOfBytesToMap) -{ - DWORD dwDesiredAccess; - DWORD dwDesiredAccessmap; - DWORD flProtect; - HANDLE filehandle; - HANDLE filemaphandle; - LPVOID address = 0; - if (dwCreationDisposition) { - if (dwCreationDisposition == CREATE_NEW) { - dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; - dwDesiredAccessmap = FILE_MAP_WRITE; - flProtect = PAGE_READWRITE; - dwCreationDisposition = OPEN_ALWAYS; - } - } else { - dwDesiredAccess = GENERIC_READ; - flProtect = PAGE_READONLY; - dwDesiredAccessmap = FILE_MAP_READ; - dwCreationDisposition = OPEN_EXISTING; - } - filehandle = CreateFileA(lpFileName, dwDesiredAccess, 0, 0, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, 0); - if (filehandle != INVALID_HANDLE_VALUE) { - filemaphandle = CreateFileMappingA(filehandle, 0, flProtect, 0, dwNumberOfBytesToMap, 0); - CloseHandle(filehandle); - if (filemaphandle) { - address = MapViewOfFile(filemaphandle, dwDesiredAccessmap, 0, 0, dwNumberOfBytesToMap); - CloseHandle(filemaphandle); - } - } - return address; -} - -/** -* -* rct2: 0x004068A0 -*/ -int unmap_file(LPCVOID base) -{ - if (base) { - return UnmapViewOfFile(base); - } - return 0; -} - -/** -* -* rct2: 0x00404932 -*/ -int dsound_create_primary_buffer(int a, int device, int channels, int samples, int bits) -{ - rct_dsdevice* dsdevice = 0; - if (device) { - if (device > RCT2_GLOBAL(RCT2_ADDRESS_NUM_DSOUND_DEVICES, int)) { - return 0; - } - dsdevice = &RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES, rct_dsdevice*)[device]; - } - memset(&RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX), 0, sizeof(WAVEFORMATEX)); - RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).wFormatTag = 1; - RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).nChannels = channels; - RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).nSamplesPerSec = samples; - RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).nAvgBytesPerSec = samples * RCT2_GLOBAL(0x01425B4C, uint16); - RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).nBlockAlign = bits * channels / 8; - RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).wBitsPerSample = bits; - RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).cbSize = 0; - DSBUFFERDESC bufferdesc; - memset(&bufferdesc, 0, sizeof(bufferdesc)); - bufferdesc.dwSize = sizeof(bufferdesc); - if (a) { - if (a != 1) { - return 0; - } - bufferdesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER; - if (RCT2_GLOBAL(0x009E2B90, uint32)) { - bufferdesc.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER; - } - 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), 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; - return 0; - } - if (SUCCEEDED(RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER)->lpVtbl->QueryInterface(RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER), &RCT2_GLOBAL(0x009A4444, IID) /* IID_IDirectSound3DBuffer */, (void**)&RCT2_GLOBAL(0x009E2BA4, LPDIRECTSOUND3DBUFFER)))) { - // doesn't seem to ever make it here, below doesn't make sense and is probably remnants of unused 3d sound tests - memset(&RCT2_GLOBAL(0x009A6084, DS3DBUFFER), 0, sizeof(RCT2_GLOBAL(0x009A6084, DS3DBUFFER))); - RCT2_GLOBAL(0x009A6084, DS3DBUFFER).dwSize = sizeof(RCT2_GLOBAL(0x009A6084, DS3DBUFFER)); - - if (sound_load3dparameters()) { - RCT2_GLOBAL(0x009A6084, DS3DBUFFER).vPosition.x = 0.0f; - } - RCT2_GLOBAL(0x009A6084, DS3DBUFFER).vPosition.y = 0.0f; - RCT2_GLOBAL(0x009A6084, DS3DBUFFER).vPosition.x = -1.0f; - RCT2_GLOBAL(0x009A6084, DS3DBUFFER).flMaxDistance = 9.8999996f; - RCT2_GLOBAL(0x009A6084, DS3DBUFFER).flMinDistance = 0.25f; - if (sound_load3dposition()) { - if (SUCCEEDED(RCT2_GLOBAL(0x009E2BA4, LPDIRECTSOUND3DBUFFER)->lpVtbl->SetMinDistance(RCT2_GLOBAL(0x009E2BA4, LPDIRECTSOUND3DBUFFER), RCT2_GLOBAL(0x009A6084, DS3DBUFFER).flMinDistance, 1))) { - if (sound_load3dparameters()) { - return 1; - } - } - } - RCT2_GLOBAL(0x009E2BA4, LPDIRECTSOUND3DBUFFER)->lpVtbl->Release(RCT2_GLOBAL(0x009E2BA4, LPDIRECTSOUND3DBUFFER)); - RCT2_GLOBAL(0x009E2BA4, LPDIRECTSOUND3DBUFFER) = 0; - RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER)->lpVtbl->Release(RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER)); - 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; - } else { - RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER)->lpVtbl->Release(RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER)); - 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; - } - } - bufferdesc.dwFlags = DSBCAPS_PRIMARYBUFFER; - if (RCT2_GLOBAL(0x009E2B90, uint32)) { - bufferdesc.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_PRIMARYBUFFER; - } - 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), 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; - } - RCT2_GLOBAL(0x01425B60, DSCAPS).dwSize = sizeof(DSCAPS); - RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->GetCaps(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), &RCT2_GLOBAL(0x01425B60, DSCAPS)); - if (FAILED(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND)->lpVtbl->CreateSoundBuffer(RCT2_GLOBAL(RCT2_ADDRESS_DIRECTSOUND, LPDIRECTSOUND), &bufferdesc, &RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER), 0))) { - RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER)->lpVtbl->Release(RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER)); - 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; - } - WAVEFORMATEX waveformat1, waveformat2; - RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER)->lpVtbl->GetFormat(RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER), &waveformat1, sizeof(WAVEFORMATEX), 0); - RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER)->lpVtbl->SetFormat(RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER), &RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX)); - RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER)->lpVtbl->GetFormat(RCT2_GLOBAL(0x009E2BA8, LPDIRECTSOUNDBUFFER), &waveformat2, sizeof(WAVEFORMATEX), 0); - return 1; -} - -/** -* -* rct2: 0x0040502E -*/ -int get_dsound_devices() -{ - RCT2_GLOBAL(RCT2_ADDRESS_NUM_DSOUND_DEVICES, uint32) = dsound_count_devices(); - RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES, rct_dsdevice*) = malloc(RCT2_GLOBAL(RCT2_ADDRESS_NUM_DSOUND_DEVICES, uint32) * sizeof(rct_dsdevice)); - if (RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES, rct_dsdevice*)) { - RCT2_GLOBAL(0x01425B54, int) = 0; - DirectSoundEnumerate(dsound_enum_callback, 0); - return RCT2_GLOBAL(0x01425B54, int); - } - return 0; -} - -/** -* -* rct2: 0x006BB76E -* -* @param sound_id (eax) -* @param ebx (ebx) -* @param x (cx) -* @param y (dx) -* @param z (bp) -*/ -int sound_play_panned(int sound_id, int ebx, sint16 x, sint16 y, sint16 z) -{ - int result = 0; - if (RCT2_GLOBAL(0x009AF59D, uint8) & 1) { - RCT2_GLOBAL(0x00F438AD, uint8) = 0; - int volume = 0; - if (ebx == 0x8001) { - 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; - } - } - sint16 v11; - sint16 v12; - switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) { - case 0: - v11 = y - x; - v12 = ((y + x) / 2) - z; - break; - case 1: - v11 = -x - y; - v12 = ((y - x) / 2) - z; - break; - case 2: - v11 = x - y; - v12 = ((-y - x) / 2) - z; - break; - case 3: - v11 = y + x; - v12 = ((x - y) / 2) - z; - break; - } - rct_window* window = RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); - while (1) { + uint8 rotation = get_current_rotation(); + rct_xy16 pos2 = coordinate_3d_to_2d(location, rotation); + rct_window *window = RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); + while (true) { window--; - if (window < RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_LIST, rct_window)) { + if (window < RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_LIST, rct_window)) break; + + rct_viewport *viewport = window->viewport; + if (!viewport || !(viewport->flags & VIEWPORT_FLAG_SOUND_ON)) + continue; + + sint16 vy = pos2.y - viewport->view_y; + sint16 vx = pos2.x - viewport->view_x; + params.pan = viewport->x + (vx >> viewport->zoom); + params.volume = RCT2_ADDRESS(0x0099282C, int)[soundId] + ((-1024 * viewport->zoom - 1) << volumeDown) + 1; + + if (vy < 0 || vy >= viewport->view_height || vx < 0 || vx >= viewport->view_width || params.volume < -10000) { + params.in_range = false; + return params; } - rct_viewport* viewport = window->viewport; - if (viewport && viewport->flags & VIEWPORT_FLAG_SOUND_ON) { - sint16 v15 = v12 - viewport->view_y; - sint16 v16 = v11 - viewport->view_x; - ebx = viewport->x + (v16 >> viewport->zoom); - volume = RCT2_ADDRESS(0x0099282C, int)[sound_id] + ((-1024 * viewport->zoom - 1) << RCT2_GLOBAL(0x00F438AD, uint8)) + 1; - if (v15 < 0 || v15 >= viewport->view_height || v16 < 0 || v16 >= viewport->view_width || volume < -10000) { - return sound_id; } + + return params; } + +int audio_play_sound(int soundId, int volume, int pan) +{ + if (gGameSoundsOff) + return 0; + + int mixerPan = 0; + if (pan != AUDIO_PLAY_AT_CENTRE) { + int x2 = pan << 16; + uint16 screenWidth = max(64, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16)); + mixerPan = ((x2 / screenWidth) - 0x8000) >> 4; } - } - int i = 0; - rct_other_sound* other_sound = &RCT2_ADDRESS(0x009AF484, rct_other_sound)[i]; - while (other_sound->id != 0xFFFF) { - i++; - other_sound = &RCT2_ADDRESS(0x009AF484, rct_other_sound)[i]; - 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 == (sint16)0x8000) { - pan = 0; - } else { - int x2 = ebx << 16; - uint16 screenwidth = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); - if (screenwidth < 64) { - screenwidth = 64; - } - pan = ((x2 / screenwidth) - 0x8000) >> 4; - } - if (!RCT2_GLOBAL(0x009AAC6D, uint8)) { - pan = 0; - } -#ifdef USE_MIXER - Mixer_Play_Effect(sound_id, MIXER_LOOP_NONE, DStoMixerVolume(volume), DStoMixerPan(pan), 1, 1); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_prepare(sound_id, &other_sound->sound, 1, RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, uint32)); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - RCT2_GLOBAL(0x014241BC, uint32) = 1; - result = sound_play(&other_sound->sound, 0, volume, pan, 0); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - } - return result; + + Mixer_Play_Effect(soundId, MIXER_LOOP_NONE, DStoMixerVolume(volume), DStoMixerPan(mixerPan), 1, 1); + return 0; } -/** -* -* rct2: 0x006BB991 -*/ -void stop_completed_sounds() +void audio_start_title_music() { - if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) != -1) { - for (int i = 0; i < 7; i++) { - rct_other_sound* other_sound = &RCT2_ADDRESS(0x009AF484, rct_other_sound)[i]; - if (other_sound->id != (uint16)-1) { - RCT2_GLOBAL(0x014241BC, uint32) = 1; - int isplaying = sound_is_playing(&other_sound->sound); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - if (!isplaying) { - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_stop(&other_sound->sound); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - other_sound->id = (uint16)-1; - } - } - } - } -} - -/** -* -* rct2: 0x006BD0F8 -*/ -void start_title_music() -{ - int musicPathId; - switch (gConfigSound.title_music) { - default: + if (gGameSoundsOff || !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO)) { + audio_stop_title_music(); return; + } + + if (gTitleMusicChannel) + return; + + int pathId; + switch (gConfigSound.title_music) { case 1: - musicPathId = PATH_ID_CSS50; + pathId = PATH_ID_CSS50; break; case 2: - musicPathId = PATH_ID_CSS17; + pathId = PATH_ID_CSS17; break; case 3: - if (rand() & 1) - musicPathId = PATH_ID_CSS50; + if (util_rand() & 1) + pathId = PATH_ID_CSS50; else - musicPathId = PATH_ID_CSS17; + pathId = PATH_ID_CSS17; break; + default: + return; } - 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(musicPathId, MIXER_LOOP_INFINITE, true); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - 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; - sound_channel_play(3, 1, 0, 0, 0); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - } -#endif - RCT2_GLOBAL(0x009AF600, uint8) = 1; - } - } else { - if (RCT2_GLOBAL(0x009AF600, uint8)) { - stop_title_music(); - } - } + gTitleMusicChannel = Mixer_Play_Music(pathId, MIXER_LOOP_INFINITE, true); } -/** -* -* rct2: 0x006BCAE5 -*/ -void stop_other_sounds() +void audio_stop_ride_music() { - if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) != -1) { - if (RCT2_GLOBAL(0x009AF5A8, uint32) != 1) { - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_stop(RCT2_GLOBAL(0x009AF5AC, rct_sound*)); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - RCT2_GLOBAL(0x009AF5A8, uint32) = 1; - } - if (RCT2_GLOBAL(0x009AF5C0, uint32) != 8) { - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_stop(RCT2_GLOBAL(0x009AF5C4, rct_sound*)); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - RCT2_GLOBAL(0x009AF5C0, uint32) = 8; - } - if (RCT2_GLOBAL(0x009AF5D8, uint32) != 8) { - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_stop(RCT2_GLOBAL(0x009AF5DC, rct_sound*)); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - RCT2_GLOBAL(0x009AF5D8, uint32) = 8; - } + for (int i = 0; i < AUDIO_MAX_RIDE_MUSIC; i++) { + rct_ride_music *rideMusic = &gRideMusicList[i]; + if (rideMusic->ride_id == (uint8)-1) + continue; + + if (rideMusic->sound_channel) + Mixer_Stop_Channel(rideMusic->sound_channel); + + rideMusic->ride_id = -1; } } -/** -* -* rct2: 0x006BCA9F -*/ -void stop_ride_music() +void audio_stop_crowd_sound() { - if ((RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0))) { - for (int i = 0; i < AUDIO_MAX_RIDE_MUSIC; i++) { - rct_ride_music* ride_music = &gRideMusicList[i];//&RCT2_ADDRESS(0x009AF46C, rct_ride_music)[i]; - if (ride_music->rideid != (uint8)-1) { -#ifdef USE_MIXER - Mixer_Stop_Channel(ride_music->sound_channel); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_channel_stop(i); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - ride_music->rideid = -1; - } - } - } + audio_stop_channel(&gCrowdSoundChannel); } -/** -* -* rct2: 0x006BD07F -*/ -void stop_crowd_sound() +void audio_stop_title_music() { - if ((RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0))) { - if (RCT2_GLOBAL(0x009AF5FC, uint32) != 1) { -#ifdef USE_MIXER - if (gCrowdSoundChannel) { - Mixer_Stop_Channel(gCrowdSoundChannel); - gCrowdSoundChannel = 0; - } -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_channel_stop(2); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - RCT2_GLOBAL(0x009AF5FC, uint32) = 1; - } - } + audio_stop_channel(&gTitleMusicChannel); } -/** -* -* rct2: 0x006BD0BD -*/ -void stop_title_music() +void audio_stop_rain_sound() { - if (RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0)) { - if (RCT2_GLOBAL(0x009AF600, uint8) != 0) { -#ifdef USE_MIXER - if (gTitleMusicChannel) { - Mixer_Stop_Channel(gTitleMusicChannel); - gTitleMusicChannel = 0; - } -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_channel_stop(3); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - } - } - RCT2_GLOBAL(0x009AF600, uint8) = 0; + audio_stop_channel(&gRainSoundChannel); } /** -* -* rct2: 0x006BA8E0 +* Stops the specified audio channel from playing. +* @param channel The channel to stop. */ -void audio_init1() +void audio_stop_channel(void **channel) { - int devicenum = 0; - if (RCT2_GLOBAL(0x009AAC5C, uint8)) { - rct_dsdevice* dsdevice = &RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES, rct_dsdevice*)[0]; - while (dsdevice->guid.Data1 != RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_GUID, GUID).Data1 || - dsdevice->guid.Data2 != RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_GUID, GUID).Data2 || - dsdevice->guid.Data3 != RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_GUID, GUID).Data3 || - memcmp(dsdevice->guid.Data4, RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_GUID, GUID).Data4, sizeof(dsdevice->guid.Data4)) != 0) { - dsdevice++; - devicenum++; - if (devicenum >= RCT2_GLOBAL(RCT2_ADDRESS_NUM_DSOUND_DEVICES, int)) { - devicenum = 0; - break; - } - } - } - audio_init2(devicenum); - int m = 0; - do { - rct_ride_music_info* ride_music_info = ride_music_info_list[m]; - const char* path = get_file_path(ride_music_info->pathid); - 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->length = 0; - } - } - m++; - } while(m + 1 < 0x2E); + if (!*channel) + return; + + Mixer_Stop_Channel(*channel); + *channel = 0; } -/** -* -* rct2: 0x006BA9B5 -*/ -void audio_init2(int device) +void audio_init_ride_sounds_and_info() +{ + int deviceNum = 0; + audio_init_ride_sounds(deviceNum); + + for (int m = 0; m < countof(gRideMusicInfoList); m++) { + rct_ride_music_info *rideMusicInfo = gRideMusicInfoList[m]; + const utf8 *path = get_file_path(rideMusicInfo->path_id); + SDL_RWops *file = SDL_RWFromFile(path, "rb"); + if (file == NULL) + continue; + + uint32 head; + SDL_RWread(file, &head, sizeof(head), 1); + SDL_RWclose(file); + RCT2_GLOBAL(0x014241BC, uint32) = 0; + if (head == 0x78787878) + rideMusicInfo->length = 0; + } +} + +void audio_init_ride_sounds(int device) { audio_close(); - for (int i = 0; i < AUDIO_MAX_VEHICLE_SOUNDS/*7*/; i++) { - rct_vehicle_sound* vehicle_sound = &gVehicleSoundList[i]; - //rct_vehicle_sound* vehicle_sound = &RCT2_ADDRESS(RCT2_ADDRESS_VEHICLE_SOUND_LIST, rct_vehicle_sound)[i]; - vehicle_sound->id = 0xFFFF; - } - for (int i = 0; i < 7; i++) { - rct_other_sound* other_sound = &RCT2_ADDRESS(0x009AF484, rct_other_sound)[i]; - other_sound->id = 0xFFFF; - } - RCT2_GLOBAL(0x014241BC, uint32) = 1; - int successdsound = dsound_create_primary_buffer(0, device, 2, 22050, 16); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - if (!successdsound) { - return; - } - const char * filepath = get_file_path(2); - RCT2_GLOBAL(0x014241BC, uint32) = 1; - int successmap = map_sound_effects(filepath); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - if (!successmap) { - RCT2_GLOBAL(0x014241BC, uint32) = 1; - audio_release(); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - return; + for (int i = 0; i < AUDIO_MAX_VEHICLE_SOUNDS; i++) { + rct_vehicle_sound *vehicleSound = &gVehicleSoundList[i]; + vehicleSound->id = -1; } + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) = 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_default(); - RCT2_GLOBAL(0x014241BC, uint32) = 1; - int successtimer = audio_create_timer(); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - if (successtimer) { - RCT2_GLOBAL(0x009AF284, uint32) |= (1 << 0); - for (int i = 0; i < AUDIO_MAX_RIDE_MUSIC; i++) { - rct_ride_music* ride_music = &gRideMusicList[i];//&RCT2_ADDRESS(0x009AF46C, rct_ride_music)[i]; - ride_music->rideid = -1; - } - } - - // Used by original code for directsound - if (!(RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & 1 << 4)) { - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) |= 1 << 4; - } - - // 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(); + for (int i = 0; i < AUDIO_MAX_RIDE_MUSIC; i++) { + rct_ride_music *rideMusic = &gRideMusicList[i]; + rideMusic->ride_id = -1; } } -/** -* -* rct2: 0x006BAB21 -*/ void audio_close() { - if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) != -1) { - stop_other_sounds(); - stop_crowd_sound(); - stop_title_music(); - if (RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0)) { - stop_ride_music(); - RCT2_GLOBAL(0x014241BC, uint32) = 1; - audio_remove_timer(); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - } - RCT2_GLOBAL(0x014241BC, uint32) = 1; - unmap_sound_effects(); - audio_release(); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) = -1; + audio_stop_crowd_sound(); + audio_stop_title_music(); + audio_stop_ride_music(); + audio_stop_rain_sound(); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) = -1; +} + +void audio_toggle_all_sounds(){ + gConfigSound.sound = !gConfigSound.sound; + if (gConfigSound.sound) + audio_unpause_sounds(); + else { + audio_stop_title_music(); + audio_pause_sounds(); } } -/* 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() +void audio_pause_sounds() { - // 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(); - } - gConfigSound.sound = 0; + gGameSoundsOff = true; + audio_stop_vehicle_sounds(); + audio_stop_ride_music(); + audio_stop_crowd_sound(); + audio_stop_rain_sound(); } -/** -* -* rct2: 0x006BABD8 -*/ -void unpause_sounds() +void audio_unpause_sounds() { - // When all sound code is reversed replace with gConfigSound.sound - RCT2_GLOBAL(0x009AF59C, uint8) = 0; - gConfigSound.sound = 1; + gGameSoundsOff = false; } -/** -* -* rct2: 0x006BABDF -*/ -void stop_vehicle_sounds() +void audio_stop_vehicle_sounds() { - if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, sint32) != -1) { - for (int i = 0; i < countof(gVehicleSoundList)/*7*/; i++) { - rct_vehicle_sound* vehicle_sound = &gVehicleSoundList[i]; - //rct_vehicle_sound* vehicle_sound = &RCT2_ADDRESS(RCT2_ADDRESS_VEHICLE_SOUND_LIST, rct_vehicle_sound)[i]; - if (vehicle_sound->id != 0xFFFF) { - if (vehicle_sound->sound1_id != 0xFFFF) { -#ifdef USE_MIXER - Mixer_Stop_Channel(vehicle_sound->sound1_channel); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_stop(&vehicle_sound->sound1); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - } - if (vehicle_sound->sound2_id != 0xFFFF) { -#ifdef USE_MIXER - Mixer_Stop_Channel(vehicle_sound->sound2_channel); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_stop(&vehicle_sound->sound2); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - } - } - vehicle_sound->id = 0xFFFF; - } + if (gOpenRCT2Headless || RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, sint32) == -1) + return; + + for (int i = 0; i < countof(gVehicleSoundList); i++) { + rct_vehicle_sound *vehicleSound = &gVehicleSoundList[i]; + if (vehicleSound->id == 0xFFFF) + continue; + + if (vehicleSound->sound1_id != 0xFFFF) + Mixer_Stop_Channel(vehicleSound->sound1_channel); + + if (vehicleSound->sound2_id != 0xFFFF) + Mixer_Stop_Channel(vehicleSound->sound2_channel); + + vehicleSound->id = 0xFFFF; } } diff --git a/src/audio/audio.h b/src/audio/audio.h index 037206227a..3bfde4a2f5 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -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 . *****************************************************************************/ @@ -24,206 +24,67 @@ #include "../common.h" #include "../world/sprite.h" -typedef struct { - char name[256]; +#define AUDIO_DEVICE_NAME_SIZE 256 +#define AUDIO_MAX_RIDE_MUSIC 2 +#define AUDIO_MAX_VEHICLE_SOUNDS 14 +#define NUM_DEFAULT_MUSIC_TRACKS 46 +#define AUDIO_PLAY_AT_CENTRE 0x8000 +#define AUDIO_PLAY_AT_LOCATION 0x8001 + +typedef struct audio_device { + char name[AUDIO_DEVICE_NAME_SIZE]; } audio_device; -extern int gAudioDeviceCount; -extern audio_device *gAudioDevices; +typedef struct rct_ride_music { + uint8 ride_id; + uint8 tune_id; + sint16 volume; + sint16 pan; + uint16 frequency; + void* sound_channel; +} rct_ride_music; -#define AUDIO_MAX_VEHICLE_SOUNDS 14 -#define AUDIO_MAX_RIDE_MUSIC 2 +typedef struct rct_ride_music_info { + uint32 length; + uint32 offset; + uint8 path_id; + uint8 var_9; +} rct_ride_music_info; -void audio_init(); -void audio_quit(); -void audio_get_devices(); +typedef struct rct_ride_music_params { + uint8 ride_id; + uint8 tune_id; + sint32 offset; + sint16 volume; + sint16 pan; + uint16 frequency; +} rct_ride_music_params; -#include - -/** - * Represents a single directsound device. - */ -typedef struct { - GUID guid; - CHAR desc[256]; - CHAR drvname[256]; -} rct_dsdevice; - -/** - * Represents a prepared sound. - */ -typedef struct rct_sound { - LPDIRECTSOUNDBUFFER dsbuffer; +typedef struct rct_vehicle_sound { uint16 id; - uint16 var_8; - int has_caps; - int var_0C; - struct rct_sound* next; -} rct_sound; - -typedef struct { - uint32 playing; // 0x000 - uint32 var_4; - char filename[MAX_PATH]; // 0x008 - uint32 var_10C; - uint32 var_110; - uint32 var_114; - uint32 var_118; - HGLOBAL hmem; // 0x11C - HMMIO hmmio; // 0x120 - MMCKINFO mmckinfo1; // 0x124 - MMCKINFO mmckinfo2; // 0x138 - LPDIRECTSOUNDBUFFER dsbuffer; // 0x14C - uint32 bufsize; // 0x150 - uint32 playpos; // 0x154 - uint32 var_158; - uint32 var_15C; - uint32 stopped; // 0x160 - uint32 var_164; - uint32 var_168; -} rct_sound_channel; - -typedef struct { - uint32 size; - WAVEFORMATEX format; - uint8* data; -} rct_sound_effect; - -typedef struct { - uint16 id; - sint16 volume; // 0x02 - rct_sound sound1; // 0x04 - uint16 sound1_id; // 0x18 - sint16 sound1_volume; // 0x1A - sint16 sound1_pan; // 0x1C + sint16 volume; + uint16 sound1_id; + sint16 sound1_volume; + sint16 sound1_pan; uint16 sound1_freq; - rct_sound sound2; // 0x20 - uint16 sound2_id; // 0x34 - sint16 sound2_volume; // 0x36 - sint16 sound2_pan; // 0x38 - uint16 sound2_freq; // 0x3A - // added to openrct2: + uint16 sound2_id; + sint16 sound2_volume; + sint16 sound2_pan; + uint16 sound2_freq; void* sound1_channel; void* sound2_channel; } rct_vehicle_sound; -typedef struct { +typedef struct rct_vehicle_sound_params { uint16 id; - sint16 panx; // 0x2 - sint16 pany; // 0x4 - uint16 frequency; // 0x6 - sint16 volume; // 0x8 - uint16 var_A; // 0xA + sint16 pan_x; + sint16 pan_y; + uint16 frequency; + sint16 volume; + uint16 var_A; } rct_vehicle_sound_params; -typedef struct { - uint16 id; - rct_sound sound; -} rct_other_sound; - -typedef struct { - uint8 rideid; - uint8 tuneid; - sint32 offset; //0x2 - sint16 volume; //0x6 - sint16 pan; //0x8 - uint16 freq; //0xA -} rct_ride_music_params; - -typedef struct { - uint8 rideid; - uint8 tuneid; - sint16 volume; //0x2 - sint16 pan; //0x4 - uint16 freq; //0x6 - // added to openrct2: - void* sound_channel; -} rct_ride_music; - -typedef struct { - 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; -extern rct_ride_music gRideMusicList[AUDIO_MAX_RIDE_MUSIC]; -extern rct_ride_music_params gRideMusicParamsList[AUDIO_MAX_RIDE_MUSIC]; -extern rct_ride_music_params *gRideMusicParamsListEnd; -extern void *gCrowdSoundChannel; -extern void *gTitleMusicChannel; - -void audio_timefunc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2, int channel); -int CALLBACK audio_timer_callback(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2); -int sub_40153B(int channel); -int sub_4015E7(int channel); -int sound_channel_load_file(int channel, const char* filename, int offset); -int mmio_open_channel(int channel, char* filename, LONG offset); -int audio_create_timer(); -int audio_remove_timer(); -int sound_channel_load_file2(int channel, const char* filename, int offset); -int sound_channel_play(int channel, int a2, int volume, int pan, int frequency); -int sound_channel_stop(int channel); -int sound_channel_set_frequency(int channel, int frequency); -int sound_channel_set_pan(int channel, int pan); -int sound_channel_set_volume(int channel, int volume); -void sub_401AF3(int channel, const char* filename, int a3, int a4); -int sub_401B46(int channel); -int sound_channel_is_playing(int channel); -int audio_release(); -int map_sound_effects(const char* filename); -int unmap_sound_effects(); -int sound_prepare(int sound_id, rct_sound *sound, int channels, int software); -int sound_duplicate(rct_sound* newsound, rct_sound* sound); -int sound_stop(rct_sound *sound); -int sound_stop_all(); -void sound_bufferlost_check(); -int sound_is_playing(rct_sound* sound); -int sound_play(rct_sound* sound, int looping, int volume, int pan, int frequency); -int sound_set_frequency(rct_sound* sound, int frequency); -int sound_set_pan(rct_sound* sound, int pan); -int sound_set_volume(rct_sound* sound, int volume); -int sound_load3dparameters(); -int sound_load3dposition(); -BOOL CALLBACK dsound_enum_callback_count(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext); -int dsound_count_devices(); -BOOL CALLBACK dsound_enum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext); -int sound_effect_loadvars(rct_sound_effect* sound_effect, LPWAVEFORMATEX* waveformat, char** data, DWORD* buffersize); -int sound_fill_buffer(LPDIRECTSOUNDBUFFER dsbuffer, char* src, DWORD size); -rct_sound* sound_begin(); -rct_sound* sound_next(rct_sound* sound); -rct_sound* sound_add(rct_sound* sound); -rct_sound* sound_remove(rct_sound* sound); -int sound_bufferlost_restore(rct_sound* sound); -rct_sound_effect* sound_get_effect(uint16 sound_id); -MMRESULT mmio_open(const char* filename, HMMIO* hmmio, HGLOBAL* hmem, LPMMCKINFO mmckinfo); -MMRESULT mmio_read(HMMIO hmmio, uint32 size, char* buffer, LPMMCKINFO mmckinfo, int* read); -void sound_channel_free(HMMIO* hmmio, HGLOBAL* hmem); -MMRESULT mmio_seek(HMMIO* hmmio, LPMMCKINFO mmckinfo1, LPMMCKINFO mmckinfo2, int offset); -LPVOID map_file(LPCSTR lpFileName, DWORD dwCreationDisposition, DWORD dwNumberOfBytesToMap); -int unmap_file(LPCVOID base); -int dsound_create_primary_buffer(int a, int device, int channels, int samples, int bits); -int get_dsound_devices(); -int sound_play_panned(int sound_id, int ebx, sint16 x, sint16 y, sint16 z); -void stop_completed_sounds(); -void start_title_music(); -void stop_other_sounds(); -void stop_ride_music(); -void stop_crowd_sound(); -void stop_title_music(); -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(); - -typedef enum { +typedef enum RCT2_SOUND { SOUND_LIFT_1 = 0, SOUND_TRACK_FRICTION_1 = 1, SOUND_LIFT_2 = 2, @@ -290,4 +151,123 @@ typedef enum { SOUND_MAXID } RCT2_SOUND; +extern audio_device *gAudioDevices; +extern int gAudioDeviceCount; +extern void *gCrowdSoundChannel; +extern bool gGameSoundsOff; +extern void *gRainSoundChannel; +extern rct_ride_music gRideMusicList[AUDIO_MAX_RIDE_MUSIC]; +extern rct_ride_music_info *gRideMusicInfoList[NUM_DEFAULT_MUSIC_TRACKS]; +extern rct_ride_music_params gRideMusicParamsList[AUDIO_MAX_RIDE_MUSIC]; +extern rct_ride_music_params *gRideMusicParamsListEnd; +extern void *gTitleMusicChannel; +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; + +/** +* Deregisters the audio device. +* rct2: 0x006BAB21 +*/ +void audio_close(); +/* +* Initialises the audio subsystem. +*/ +void audio_init(); +/** +* Loads the ride sounds and info. +* rct2: 0x006BA8E0 +*/ +void audio_init_ride_sounds_and_info(); +/** +* Loads the ride sounds. +* rct2: 0x006BA9B5 +*/ +void audio_init_ride_sounds(int device); +/** +* Temporarily stops playing sounds until audio_unpause_sounds() is called. +* rct2: 0x006BABB4 +*/ +void audio_pause_sounds(); +/** +* Plays the specified sound. +* @param soundId The sound effect to play. +* @param volume The volume at which the sound effect should be played. +* @param pan The pan at which the sound effect should be played. If set to anything other than AUDIO_PLAY_AT_CENTRE, plays the +* sound at a position relative to the centre of the viewport. +* @return 0 if the sound was not out of range; otherwise, soundId. +*/ +int audio_play_sound(int soundId, int volume, int pan); +/** +* Plays the specified sound at a virtual location. +* @param soundId The sound effect to play. +* @param x The x coordinate of the location. +* @param y The y coordinate of the location. +* @param z The z coordinate of the location. +* @return 0 if the sound was not out of range; otherwise, soundId. +*/ +int audio_play_sound_at_location(int soundId, sint16 x, sint16 y, sint16 z); +/** +* rct2: 0x006BB76E +* @deprecated Use audio_play_sound_at_location or audio_play_sound instead. +* Plays the specified sound effect at a location specified by the pan parameter. +* @param soundId (eax) The sound effect to play. +* @param pan (ebx) If set to AUDIO_PLAY_AT_LOCATION, play the sound at the specified location; if set to AUDIO_PLAY_AT_CENTRE, +* play the sound at the centre of the viewport; if set to anything else, use the value of pan as a relative position to the +* centre of the viewport. +* @param x (cx) The x coordinate of the location. +* @param y (dx) The y coordinate of the location. +* @param z (bp) The z coordinate of the location. +* @return 0 if the sound was not out of range; otherwise, soundId. +*/ +int audio_play_sound_panned(int soundId, int pan, sint16 x, sint16 y, sint16 z); +/** +* Populates the gAudioDevices array with the available audio devices. +*/ +void audio_populate_devices(); +/** +* Terminates the audio subsystem. +* This appears to be unused. +*/ +void audio_quit(); +/** +* Starts playing the title music. +* rct2: 0x006BD0F8 +*/ +void audio_start_title_music(); +/** +* Stops the crowd sound effect from playing. +* rct2: 0x006BD07F +*/ +void audio_stop_crowd_sound(); +/** +* Stops the rain sound effect from playing. +*/ +void audio_stop_rain_sound(); +/** +* Stops ride music from playing. +* rct2: 0x006BCA9F +*/ +void audio_stop_ride_music(); +/** +* Stops the title music from playing. +* rct2: 0x006BD0BD +*/ +void audio_stop_title_music(); +/** +* Stops vehicle sounds from playing. +* rct2: 0x006BABDF +*/ +void audio_stop_vehicle_sounds(); +/** +* Toggles whether all sounds should be played. +* rct2: 0x006BAB8A +*/ +void audio_toggle_all_sounds(); +/** +* Resumes playing sounds that had been paused by a call to audio_pause_sounds(). +* rct2: 0x006BABD8 +*/ +void audio_unpause_sounds(); + #endif diff --git a/src/audio/mixer.cpp b/src/audio/mixer.cpp index 6f242f933b..1edda91bc7 100644 --- a/src/audio/mixer.cpp +++ b/src/audio/mixer.cpp @@ -8,26 +8,25 @@ * 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 - extern "C" { #include "../config.h" #include "../platform/platform.h" - #include "audio.h" #include "../localisation/localisation.h" + #include "../openrct2.h" + #include "audio.h" } #include "mixer.h" +#include Mixer gMixer; @@ -90,11 +89,8 @@ 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(utf8filename, "rb"); + SDL_RWops* rw = SDL_RWFromFile(filename, "rb"); if (rw == NULL) { log_verbose("Error loading %s", filename); return false; @@ -118,15 +114,12 @@ bool Source_Sample::LoadWAV(const char* filename) return true; } -bool Source_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(utf8filename, "rb"); + SDL_RWops* rw = SDL_RWFromFile(filename, "rb"); if (rw == NULL) { log_verbose("Unable to load %s", filename); return false; @@ -145,11 +138,20 @@ bool Source_Sample::LoadCSS1(const char* filename, unsigned int offset) Uint32 soundsize; SDL_RWread(rw, &soundsize, sizeof(soundsize), 1); length = soundsize; - WAVEFORMATEX waveformat; + struct WaveFormatEx + { + Uint16 encoding; + Uint16 channels; + Uint32 frequency; + Uint32 byterate; + Uint16 blockalign; + Uint16 bitspersample; + Uint16 extrasize; + } waveformat; SDL_RWread(rw, &waveformat, sizeof(waveformat), 1); - format.freq = waveformat.nSamplesPerSec; + format.freq = waveformat.frequency; format.format = AUDIO_S16LSB; - format.channels = waveformat.nChannels; + format.channels = waveformat.channels; data = new (std::nothrow) uint8[length]; if (!data) { log_verbose("Unable to allocate data"); @@ -198,14 +200,6 @@ bool Source_Sample::Convert(AudioFormat format) return false; } -Source_SampleStream::Source_SampleStream() -{ - length = 0; - rw = NULL; - buffer = 0; - buffersize = 0; -} - Source_SampleStream::~Source_SampleStream() { Unload(); @@ -269,15 +263,24 @@ bool Source_SampleStream::LoadWAV(SDL_RWops* rw) return false; } Uint64 chunkstart = SDL_RWtell(rw); - PCMWAVEFORMAT waveformat; + struct WaveFormat + { + Uint16 encoding; + Uint16 channels; + Uint32 frequency; + Uint32 byterate; + Uint16 blockalign; + Uint16 bitspersample; + } waveformat; SDL_RWread(rw, &waveformat, sizeof(waveformat), 1); SDL_RWseek(rw, chunkstart + fmtchunk_size, RW_SEEK_SET); - if (waveformat.wf.wFormatTag != WAVE_FORMAT_PCM) { + const Uint16 pcmformat = 0x0001; + if (waveformat.encoding != pcmformat) { log_verbose("Not in proper format"); return false; } - format.freq = waveformat.wf.nSamplesPerSec; - switch (waveformat.wBitsPerSample) { + format.freq = waveformat.frequency; + switch (waveformat.bitspersample) { case 8: format.format = AUDIO_U8; break; @@ -289,7 +292,7 @@ bool Source_SampleStream::LoadWAV(SDL_RWops* rw) return false; break; } - format.channels = waveformat.wf.nChannels; + format.channels = waveformat.channels; const Uint32 DATA = 0x61746164; Uint32 datachunk_size = FindChunk(rw, DATA); if (!datachunk_size) { @@ -339,18 +342,9 @@ void Source_SampleStream::Unload() Channel::Channel() { - resampler = 0; SetRate(1); SetVolume(SDL_MIX_MAXVOLUME); - oldvolume = 0; - oldvolume_l = 0; - oldvolume_r = 0; SetPan(0.5f); - done = true; - stopping = false; - source = 0; - deletesourceondone = false; - group = MIXER_GROUP_NONE; } Channel::~Channel() @@ -400,7 +394,7 @@ void Channel::SetPan(float pan) if (pan < 0) { Channel::pan = 0; } - double decibels = (abs(Channel::pan - 0.5) * 2.0) * 100.0; + double decibels = (std::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; @@ -439,6 +433,7 @@ void Channel::SetGroup(int group) Mixer::Mixer() { effectbuffer = 0; + volume = 1; for (int i = 0; i < countof(css1sources); i++) { css1sources[i] = 0; } @@ -535,20 +530,20 @@ void Mixer::Stop(Channel& channel) Unlock(); } -bool Mixer::LoadMusic(int pathid) +bool Mixer::LoadMusic(int pathId) { - if (pathid >= countof(musicsources)) { + if (pathId >= countof(musicsources)) { return false; } - if (!musicsources[pathid]) { - const char* filename = get_file_path(pathid); + if (!musicsources[pathId]) { + const char* filename = get_file_path(pathId); Source_Sample* source_sample = new Source_Sample; if (source_sample->LoadWAV(filename)) { - musicsources[pathid] = source_sample; + musicsources[pathId] = source_sample; return true; } else { delete source_sample; - musicsources[pathid] = &source_null; + musicsources[pathId] = &source_null; return false; } } else { @@ -556,6 +551,11 @@ bool Mixer::LoadMusic(int pathid) } } +void Mixer::SetVolume(float volume) +{ + Mixer::volume = volume; +} + void SDLCALL Mixer::Callback(void* arg, uint8* stream, int length) { Mixer* mixer = (Mixer*)arg; @@ -574,7 +574,7 @@ void SDLCALL Mixer::Callback(void* arg, uint8* stream, int length) void Mixer::MixChannel(Channel& channel, uint8* data, int length) { - if (channel.source && channel.source->Length() > 0 && !channel.done) { + if (channel.source && channel.source->Length() > 0 && !channel.done && gConfigSound.sound) { AudioFormat streamformat = channel.source->Format(); int loaded = 0; SDL_AudioCVT cvt; @@ -662,7 +662,8 @@ void Mixer::MixChannel(Channel& channel, uint8* data, int length) mixlength = length - loaded; } - float volumeadjust = (gConfigSound.master_volume / 100.0f); + float volumeadjust = volume; + volumeadjust *= (gConfigSound.master_volume / 100.0f); if (channel.group == MIXER_GROUP_MUSIC) { volumeadjust *= (gConfigSound.music_volume / 100.0f); } @@ -721,10 +722,17 @@ void Mixer::MixChannel(Channel& channel, uint8* data, int length) void Mixer::EffectPanS16(Channel& channel, sint16* data, int length) { + const float dt = 1.0f / (length * 2); + float left_volume = channel.oldvolume_l; + float right_volume = channel.oldvolume_r; + const float d_left = dt * (channel.volume_l - channel.oldvolume_l); + const float d_right = dt * (channel.volume_r - channel.oldvolume_r); + for (int i = 0; i < length * 2; i += 2) { - 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)); + data[i] = (sint16)(data[i] * left_volume); + data[i + 1] = (sint16)(data[i + 1] * right_volume); + left_volume += d_left; + right_volume += d_right; } } @@ -784,11 +792,18 @@ bool Mixer::Convert(SDL_AudioCVT& cvt, const uint8* data, unsigned long length, void Mixer_Init(const char* device) { + if (gOpenRCT2Headless) return; + gMixer.Init(device); } void* Mixer_Play_Effect(int id, int loop, int volume, float pan, double rate, int deleteondone) { + if (gOpenRCT2Headless) return 0; + + if (!gConfigSound.sound) { + return 0; + } if (id >= countof(gMixer.css1sources)) { return 0; } @@ -805,11 +820,15 @@ void* Mixer_Play_Effect(int id, int loop, int volume, float pan, double rate, in void Mixer_Stop_Channel(void* channel) { + if (gOpenRCT2Headless) return; + gMixer.Stop(*(Channel*)channel); } void Mixer_Channel_Volume(void* channel, int volume) { + if (gOpenRCT2Headless) return; + gMixer.Lock(); ((Channel*)channel)->SetVolume(volume); gMixer.Unlock(); @@ -817,6 +836,8 @@ void Mixer_Channel_Volume(void* channel, int volume) void Mixer_Channel_Pan(void* channel, float pan) { + if (gOpenRCT2Headless) return; + gMixer.Lock(); ((Channel*)channel)->SetPan(pan); gMixer.Unlock(); @@ -824,6 +845,8 @@ void Mixer_Channel_Pan(void* channel, float pan) void Mixer_Channel_Rate(void* channel, double rate) { + if (gOpenRCT2Headless) return; + gMixer.Lock(); ((Channel*)channel)->SetRate(rate); gMixer.Unlock(); @@ -831,33 +854,43 @@ void Mixer_Channel_Rate(void* channel, double rate) int Mixer_Channel_IsPlaying(void* channel) { + if (gOpenRCT2Headless) return false; + return ((Channel*)channel)->IsPlaying(); } unsigned long Mixer_Channel_GetOffset(void* channel) { + if (gOpenRCT2Headless) return 0; + return ((Channel*)channel)->GetOffset(); } int Mixer_Channel_SetOffset(void* channel, unsigned long offset) { + if (gOpenRCT2Headless) return 0; + return ((Channel*)channel)->SetOffset(offset); } void Mixer_Channel_SetGroup(void* channel, int group) { + if (gOpenRCT2Headless) return; + ((Channel*)channel)->SetGroup(group); } -void* Mixer_Play_Music(int pathid, int loop, int streaming) +void* Mixer_Play_Music(int pathId, int loop, int streaming) { + if (gOpenRCT2Headless) return 0; + + if (!gConfigSound.sound) { + return 0; + } if (streaming) { - const char* filename = get_file_path(pathid); + const utf8 *filename = get_file_path(pathId); - utf8 utf8filename[512]; - win1252_to_utf8(utf8filename, filename, sizeof(utf8filename)); - - SDL_RWops* rw = SDL_RWFromFile(utf8filename, "rb"); + SDL_RWops* rw = SDL_RWFromFile(filename, "rb"); if (rw == NULL) { return 0; } @@ -875,8 +908,8 @@ void* Mixer_Play_Music(int pathid, int loop, int streaming) return 0; } } else { - if (gMixer.LoadMusic(pathid)) { - Channel* channel = gMixer.Play(*gMixer.musicsources[pathid], MIXER_LOOP_INFINITE, false, false); + if (gMixer.LoadMusic(pathId)) { + Channel* channel = gMixer.Play(*gMixer.musicsources[pathId], MIXER_LOOP_INFINITE, false, false); if (channel) { channel->SetGroup(MIXER_GROUP_MUSIC); } @@ -884,4 +917,11 @@ void* Mixer_Play_Music(int pathid, int loop, int streaming) } } return 0; -} \ No newline at end of file +} + +void Mixer_SetVolume(float volume) +{ + if (gOpenRCT2Headless) return; + + gMixer.SetVolume(volume); +} diff --git a/src/audio/mixer.h b/src/audio/mixer.h index 679f7ef0af..4b2aeccbac 100644 --- a/src/audio/mixer.h +++ b/src/audio/mixer.h @@ -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,10 +21,15 @@ #ifndef _MIXER_H_ #define _MIXER_H_ +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus #include "../common.h" #include - -#define USE_MIXER +#include "../platform/platform.h" +#ifdef __cplusplus +} +#endif // __cplusplus #define MIXER_LOOP_NONE 0 #define MIXER_LOOP_INFINITE -1 @@ -100,7 +105,7 @@ protected: class Source_SampleStream : public Source { public: - Source_SampleStream(); + Source_SampleStream() = default; ~Source_SampleStream(); bool LoadWAV(SDL_RWops* rw); @@ -108,10 +113,10 @@ private: Uint32 FindChunk(SDL_RWops* rw, Uint32 wanted_id); void Unload(); - SDL_RWops* rw; - Uint64 databegin; - uint8* buffer; - unsigned long buffersize; + SDL_RWops* rw = nullptr; + Uint64 databegin = 0; + uint8* buffer = nullptr; + unsigned long buffersize = 0; protected: unsigned long Read(unsigned long offset, const uint8** data, unsigned long length); @@ -134,21 +139,21 @@ public: friend class Mixer; private: - int loop; - unsigned long offset; - 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; - Source* source; + int loop = 0; + unsigned long offset = 0; + double rate = 0; + int volume = 1; + float volume_l = 0.f, volume_r = 0.f; + float oldvolume_l = 0.f, oldvolume_r = 0.f; + float pan = 0; + bool done = true; + bool deleteondone = false; + bool deletesourceondone = false; + bool stopping = false; + int oldvolume = 0; + int group = MIXER_GROUP_NONE; + SpeexResamplerState* resampler = nullptr; + Source* source = nullptr; }; class Mixer @@ -162,6 +167,7 @@ public: Channel* Play(Source& source, int loop, bool deleteondone, bool deletesourceondone); void Stop(Channel& channel); bool LoadMusic(int pathid); + void SetVolume(float volume); Source* css1sources[SOUND_MAXID]; Source* musicsources[PATH_ID_END]; @@ -180,12 +186,20 @@ private: uint8* effectbuffer; std::list channels; Source_Null source_null; + float volume; }; extern "C" { #endif +#ifndef DSBPAN_LEFT +#define DSBPAN_LEFT -10000 +#endif +#ifndef DSBPAN_RIGHT +#define DSBPAN_RIGHT 10000 +#endif + void Mixer_Init(const char* device); void* Mixer_Play_Effect(int id, int loop, int volume, float pan, double rate, int deleteondone); void Mixer_Stop_Channel(void* channel); @@ -196,7 +210,8 @@ int Mixer_Channel_IsPlaying(void* channel); unsigned long Mixer_Channel_GetOffset(void* channel); int Mixer_Channel_SetOffset(void* channel, unsigned long offset); void Mixer_Channel_SetGroup(void* channel, int group); -void* Mixer_Play_Music(int pathid, int loop, int streaming); +void* Mixer_Play_Music(int pathId, int loop, int streaming); +void Mixer_SetVolume(float volume); 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; }; @@ -206,4 +221,4 @@ static double DStoMixerRate(int frequency) { return (double)frequency / 22050; } } #endif -#endif \ No newline at end of file +#endif diff --git a/src/cheats.c b/src/cheats.c new file mode 100644 index 0000000000..c6ced49833 --- /dev/null +++ b/src/cheats.c @@ -0,0 +1,16 @@ +#include "cheats.h" + +bool gCheatsSandboxMode = false; +bool gCheatsDisableClearanceChecks = false; +bool gCheatsDisableSupportLimits = false; +bool gCheatsShowAllOperatingModes = false; +bool gCheatsShowVehiclesFromOtherTrackTypes = false; + +void cheats_reset() +{ + gCheatsSandboxMode = false; + gCheatsDisableClearanceChecks = false; + gCheatsDisableSupportLimits = false; + gCheatsShowAllOperatingModes = false; + gCheatsShowVehiclesFromOtherTrackTypes = false; +} diff --git a/src/cheats.h b/src/cheats.h index 2ef58d5260..ab46cfb676 100644 --- a/src/cheats.h +++ b/src/cheats.h @@ -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,5 +21,14 @@ #ifndef _CHEATS_H_ #define _CHEATS_H_ -int gSandboxMode; +#include "common.h" + +extern bool gCheatsSandboxMode; +extern bool gCheatsDisableClearanceChecks; +extern bool gCheatsDisableSupportLimits; +extern bool gCheatsShowAllOperatingModes; +extern bool gCheatsShowVehiclesFromOtherTrackTypes; + +void cheats_reset(); + #endif diff --git a/src/cmdline.c b/src/cmdline.c index c964e26e20..58b233db03 100644 --- a/src/cmdline.c +++ b/src/cmdline.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 @@ -23,6 +23,7 @@ #include "addresses.h" #include "cmdline.h" #include "interface/screenshot.h" +#include "network/network.h" #include "openrct2.h" #include "platform/platform.h" #include "util/util.h" @@ -45,7 +46,14 @@ typedef int (*cmdline_action)(const char **argv, int argc); int gExitCode = 0; +#ifndef DISABLE_NETWORK +int gNetworkStart = NETWORK_MODE_NONE; +char gNetworkStartHost[128]; +int gNetworkStartPort = NETWORK_DEFAULT_PORT; +#endif // DISABLE_NETWORK + static void print_launch_information(); +static void print_version(); static int cmdline_call_action(const char **argv, int argc); static const char *const usage[] = { @@ -63,14 +71,20 @@ static const char *const usage[] = { */ int cmdline_run(const char **argv, int argc) { - // - int version = 0, verbose = 0, width = 0, height = 0; + // + int version = 0, headless = 0, verbose = 0, width = 0, height = 0, port = 0; + char *server = NULL; + char *userDataPath = NULL; argparse_option_t options[] = { OPT_HELP(), OPT_BOOLEAN('v', "version", &version, "show version information and exit"), + OPT_BOOLEAN(0, "headless", &headless, "run OpenRCT2 headless"), 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_STRING(0, "server", &server, "server to connect to"), + OPT_INTEGER(0, "port", &port, "port"), + OPT_STRING(0, "user-data-path", &userDataPath, "path to the user data directory (containing config.ini)"), OPT_END() }; @@ -79,45 +93,92 @@ int cmdline_run(const char **argv, int argc) argc = argparse_parse(&argparse, argc, argv); if (version) { - printf("%s v%s\n", OPENRCT2_NAME, OPENRCT2_VERSION); - printf("%s (%s)\n", OPENRCT2_PLATFORM, OPENRCT2_ARCHITECTURE); - printf("%s\n", OPENRCT2_TIMESTAMP); + print_version(); return 0; } + if (headless) + gOpenRCT2Headless = true; + if (verbose) _log_levels[DIAGNOSTIC_LEVEL_VERBOSE] = 1; - if (argc != 0) { - gExitCode = cmdline_call_action(argv, argc); - if (gExitCode != 0) - return 0; + if (userDataPath != NULL) { + safe_strncpy(gCustomUserDataPath, userDataPath, sizeof(gCustomUserDataPath)); } - print_launch_information(); +#ifndef DISABLE_NETWORK + if (port != 0) { + gNetworkStart = NETWORK_MODE_SERVER; + gNetworkStartPort = port; + } + + if (server != NULL) { + gNetworkStart = NETWORK_MODE_CLIENT; + safe_strncpy(gNetworkStartHost, server, sizeof(gNetworkStartHost)); + } +#endif // DISABLE_NETWORK + + if (argc != 0) { + // see comment next to cmdline_call_action for expected return codes + gExitCode = cmdline_call_action(argv, argc); + if (gExitCode < 0) { + // action failed, don't change exit code + // and don't start the game + return 0; + } else if (gExitCode > 0) { + // action successful, but don't start the game + // change exit code to success + gExitCode = 0; + return 0; + } + // start the game, so far exit code means success. + } + + // Headless mode requires a park to open + if (gOpenRCT2Headless) { + if (str_is_null_or_empty(gOpenRCT2StartupActionPath)) { + printf("You must specify a park to open in headless mode.\n"); + gExitCode = -1; + return 0; + } + } + + if (verbose) { + print_launch_information(); + } return 1; } static void print_launch_information() { - char buffer[32]; + char buffer[256]; time_t timer; tm_t* tmInfo; - // Print version information - printf("Starting %s v%s\n", OPENRCT2_NAME, OPENRCT2_VERSION); - printf(" %s (%s)\n", OPENRCT2_PLATFORM, OPENRCT2_ARCHITECTURE); - printf(" %s\n\n", OPENRCT2_TIMESTAMP); + // Print name and version information + openrct2_write_full_version_info(buffer, sizeof(buffer)); + printf("%s\n", buffer); + printf("%s (%s)\n", OPENRCT2_PLATFORM, OPENRCT2_ARCHITECTURE); + printf("@ %s\n\n", OPENRCT2_TIMESTAMP); // Print current time time(&timer); tmInfo = localtime(&timer); strftime(buffer, sizeof(buffer), "%Y/%m/%d %H:%M:%S", tmInfo); - printf("Time: %s\n", buffer); + printf("VERBOSE: time is %s\n", buffer); // TODO Print other potential information (e.g. user, hardware) } +static void print_version() +{ + char buffer[256]; + openrct2_write_full_version_info(buffer, sizeof(buffer)); + printf("%s\n", buffer); + printf("%s (%s)\n", OPENRCT2_PLATFORM, OPENRCT2_ARCHITECTURE); +} + static int cmdline_for_intro(const char **argv, int argc) { gOpenRCT2StartupAction = STARTUP_ACTION_INTRO; @@ -128,7 +189,7 @@ static int cmdline_for_edit(const char **argv, int argc) { gOpenRCT2StartupAction = STARTUP_ACTION_EDIT; if (argc >= 1) - strcpy(gOpenRCT2StartupActionPath, argv[0]); + safe_strncpy(gOpenRCT2StartupActionPath, argv[0], 512); return 0; } @@ -139,7 +200,7 @@ static int cmdline_for_none(const char **argv, int argc) if (platform_file_exists(argv[0])) { gOpenRCT2StartupAction = STARTUP_ACTION_OPEN; - strcpy(gOpenRCT2StartupActionPath, argv[0]); + safe_strncpy(gOpenRCT2StartupActionPath, argv[0], 512); return 0; } else { fprintf(stderr, "error: %s does not exist\n", argv[0]); @@ -147,6 +208,7 @@ static int cmdline_for_none(const char **argv, int argc) } } +// see comment next to cmdline_call_action for expected return codes struct { const char *firstArg; cmdline_action action; } cmdline_table[] = { { "intro", cmdline_for_intro }, { "edit", cmdline_for_edit }, @@ -160,6 +222,19 @@ struct { const char *firstArg; cmdline_action action; } cmdline_table[] = { #endif }; +/** + * This function delegates starting the game to different handlers, if found. + * + * Three cases of return values are supported: + * - result < 0 means failure, will exit with error code + * This case is useful when user provided wrong arguments or the requested + * action failed + * - result > 0 means success, won't start game, will exit program with success code + * This case is useful when you want to do some batch action and signalize + * success to the user. + * - result == 0 means success, will launch the game. + * This is default when ran with no arguments. + */ static int cmdline_call_action(const char **argv, int argc) { for (int i = 0; i < countof(cmdline_table); i++) { @@ -170,4 +245,4 @@ static int cmdline_call_action(const char **argv, int argc) } return cmdline_for_none(argv, argc); -} \ No newline at end of file +} diff --git a/src/cmdline.h b/src/cmdline.h index b86393f047..91e2e33bc4 100644 --- a/src/cmdline.h +++ b/src/cmdline.h @@ -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 . *****************************************************************************/ @@ -28,6 +28,10 @@ extern int gExitCode; int sprite_mode; +extern int gNetworkStart; +extern char gNetworkStartHost[128]; +extern int gNetworkStartPort; + int cmdline_run(const char **argv, int argc); int cmdline_for_sprite(const char **argv, int argc); diff --git a/src/cmdline_sprite.c b/src/cmdline_sprite.c index 12691d8709..789a86fa0a 100644 --- a/src/cmdline_sprite.c +++ b/src/cmdline_sprite.c @@ -1,9 +1,29 @@ +/***************************************************************************** + * Copyright (c) 2015 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 #include "cmdline.h" #include "drawing/drawing.h" #include "platform/platform.h" #include "util/util.h" +#include "openrct2.h" #define MODE_DEFAULT 0 #define MODE_CLOSEST 1 @@ -50,16 +70,16 @@ void sprite_entries_make_relative() spriteFileEntries[i].offset -= (int)spriteFileData; } -bool sprite_file_open(const char *path) +bool sprite_file_open(const utf8 *path) { - FILE *file; + SDL_RWops *file; - file = fopen(path, "rb"); + file = SDL_RWFromFile(path, "rb"); if (file == NULL) return false; - if (fread(&spriteFileHeader, sizeof(rct_sprite_file_header), 1, file) != 1) { - fclose(file); + if (SDL_RWread(file, &spriteFileHeader, sizeof(rct_sprite_file_header), 1) != 1) { + SDL_RWclose(file); return false; } @@ -67,32 +87,32 @@ bool sprite_file_open(const char *path) int entryTableSize = spriteFileHeader.num_entries * sizeof(rct_g1_element); spriteFileEntries = malloc(entryTableSize); - if (fread(spriteFileEntries, entryTableSize, 1, file) != 1) { - fclose(file); + if (SDL_RWread(file, spriteFileEntries, entryTableSize, 1) != 1) { + SDL_RWclose(file); return false; } spriteFileData = malloc(spriteFileHeader.total_size); - if (fread(spriteFileData, spriteFileHeader.total_size, 1, file) != 1) { - fclose(file); + if (SDL_RWread(file, spriteFileData, spriteFileHeader.total_size, 1) != 1) { + SDL_RWclose(file); return false; } sprite_entries_make_absolute(); } - fclose(file); + SDL_RWclose(file); return true; } bool sprite_file_save(const char *path) { - FILE *file = fopen(path, "wb"); + SDL_RWops *file = SDL_RWFromFile(path, "wb"); if (file == NULL) return false; - - if (fwrite(&spriteFileHeader, sizeof(rct_sprite_file_header), 1, file) != 1) { - fclose(file); + + if (SDL_RWwrite(file, &spriteFileHeader, sizeof(rct_sprite_file_header), 1) != 1) { + SDL_RWclose(file); return false; } @@ -101,21 +121,21 @@ bool sprite_file_save(const char *path) int entryTableSize = spriteFileHeader.num_entries * sizeof(rct_g1_element); - if (fwrite(spriteFileEntries, entryTableSize, 1, file) != 1) { + if (SDL_RWwrite(file, spriteFileEntries, entryTableSize, 1) != 1) { sprite_entries_make_absolute(); - fclose(file); + SDL_RWclose(file); return false; } else { sprite_entries_make_absolute(); } - if (fwrite(spriteFileData, spriteFileHeader.total_size, 1, file) != 1) { - fclose(file); + if (SDL_RWwrite(file, spriteFileData, spriteFileHeader.total_size, 1) != 1) { + SDL_RWclose(file); return false; } } - fclose(file); + SDL_RWclose(file); return true; } @@ -168,6 +188,7 @@ bool sprite_file_export(int spriteIndex, const char *outPath) pngError = lodepng_encode(&pngData, &pngSize, pixels, spriteHeader->width, spriteHeader->height, &pngState); if (pngError != 0) { + free(pngData); fprintf(stderr, "Error creating PNG data, %u: %s", pngError, lodepng_error_text(pngError)); return false; } else { @@ -219,7 +240,7 @@ int get_closest_palette_index(sint16 *colour){ } int get_palette_index(sint16 *colour) -{ +{ if (is_transparent_pixel(colour)) return -1; @@ -248,6 +269,7 @@ bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **ou pngError = lodepng_decode_file(&pixels, &width, &height, path, LCT_RGBA, 8); if (pngError != 0) { + free(pixels); fprintf(stderr, "Error creating PNG data, %u: %s", pngError, lodepng_error_text(pngError)); return false; } @@ -259,16 +281,18 @@ bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **ou } uint8 *buffer = malloc((height * 2) + (width * height * 16)); + memset(buffer, 0, (height * 2) + (width * height * 16)); uint16 *yOffsets = (uint16*)buffer; // A larger range is needed for proper dithering sint16 *src = malloc(height * width * 4 * 2); + sint16 *src_orig = src; 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; @@ -286,7 +310,7 @@ bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **ou 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))){ @@ -374,6 +398,7 @@ bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **ou } } free(pixels); + free(src_orig); int bufferLength = (int)(dst - buffer); buffer = realloc(buffer, bufferLength); @@ -393,6 +418,7 @@ bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **ou int cmdline_for_sprite(const char **argv, int argc) { + gOpenRCT2Headless = true; if (argc == 0) return -1; @@ -408,8 +434,8 @@ int cmdline_for_sprite(const char **argv, int argc) return -1; } - printf("sprites: %d\n", spriteFileHeader.num_entries); - printf("data size: %d\n", spriteFileHeader.total_size); + printf("sprites: %lu\n", spriteFileHeader.num_entries); + printf("data size: %lu\n", spriteFileHeader.total_size); sprite_file_close(); return 1; @@ -433,7 +459,7 @@ int cmdline_for_sprite(const char **argv, int argc) 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); + printf("data offset: 0x%lX\n", (uint32)g1->offset); sprite_file_close(); return 1; @@ -473,7 +499,7 @@ int cmdline_for_sprite(const char **argv, int argc) } const char *spriteFilePath = argv[1]; - char outputPath[_MAX_PATH]; + char outputPath[MAX_PATH]; if (!sprite_file_open(spriteFilePath)) { fprintf(stderr, "Unable to open input sprite file.\n"); @@ -488,11 +514,11 @@ int cmdline_for_sprite(const char **argv, int argc) int maxIndex = (int)spriteFileHeader.num_entries; int numbers = (int)floor(log(maxIndex)); - - strncpy(outputPath, argv[2], _MAX_PATH); + + safe_strncpy(outputPath, argv[2], MAX_PATH); int pathLen = strlen(outputPath); - if (pathLen >= _MAX_PATH - numbers - 5){ + if (pathLen >= MAX_PATH - numbers - 5){ fprintf(stderr, "Path too long.\n"); return -1; } @@ -500,7 +526,7 @@ int cmdline_for_sprite(const char **argv, int argc) for (int x = 0; x < numbers; x++){ outputPath[pathLen + x] = '0'; } - strncpy(outputPath + pathLen + numbers, ".png", _MAX_PATH); + safe_strncpy(outputPath + pathLen + numbers, ".png", MAX_PATH); for (int spriteIndex = 0; spriteIndex < maxIndex; spriteIndex++){ @@ -561,7 +587,7 @@ int cmdline_for_sprite(const char **argv, int argc) 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)); @@ -573,7 +599,7 @@ int cmdline_for_sprite(const char **argv, int argc) 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; @@ -592,7 +618,7 @@ int cmdline_for_sprite(const char **argv, int argc) bool silent = (argc >= 4 && strcmp(argv[3], "silent") == 0); bool fileExists = true; - FILE *file; + SDL_RWops *file; spriteFileHeader.num_entries = 0; spriteFileHeader.total_size = 0; @@ -602,14 +628,14 @@ int cmdline_for_sprite(const char **argv, int argc) int i = 0; do { // Create image path - strcpy(imagePath, resourcePath); + safe_strncpy(imagePath, resourcePath, MAX_PATH); 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"); + file = SDL_RWFromFile(imagePath, "r"); if (file != NULL) { - fclose(file); + SDL_RWclose(file); rct_g1_element spriteElement; uint8 *buffer; int bufferLength; @@ -648,7 +674,7 @@ int cmdline_for_sprite(const char **argv, int argc) } while (file != NULL); - fprintf(stderr, "Finished\n", imagePath); + fprintf(stderr, "Finished\n"); return 1; } else { fprintf(stderr, "Unknown sprite command."); @@ -673,7 +699,7 @@ static rct_sprite_file_palette_entry _standardPalette[256] = { { 0, 0, 0, 255 }, { 0, 0, 0, 255 }, - // + // { 35, 35, 23, 255 }, { 51, 51, 35, 255 }, { 67, 67, 47, 255 }, @@ -866,9 +892,9 @@ static rct_sprite_file_palette_entry _standardPalette[256] = { { 207, 207, 131, 255 }, { 231, 231, 171, 255 }, { 255, 255, 207, 255 }, - + // 203 - 214 (Secondary remap) - { 27, 0, 63, 255 }, + { 27, 0, 63, 255 }, { 51, 0, 103, 255 }, { 63, 11, 123, 255 }, { 79, 23, 143, 255 }, diff --git a/src/common.h b/src/common.h index b8c710cf63..b488f7c8e7 100644 --- a/src/common.h +++ b/src/common.h @@ -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 @@ -17,13 +17,21 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ - + #ifndef _COMMON_H_ #define _COMMON_H_ #include "diagnostic.h" #include "rct2.h" -#define SafeFree(x) if ((x) != NULL) { free(x); (x) = NULL; } +#define SafeFree(x) do { free(x); (x) = NULL; } while (0) -#endif \ No newline at end of file +#define SafeDelete(x) do { delete (x); (x) = nullptr; } while (0) +#define SafeDeleteArray(x) do { delete[] (x); (x) = nullptr; } while (0) + +#ifndef interface + #define interface struct +#endif +#define abstract = 0 + +#endif diff --git a/src/config.c b/src/config.c index cf7651288e..e21031a26d 100644 --- a/src/config.c +++ b/src/config.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 @@ -20,11 +20,13 @@ #include "addresses.h" #include "config.h" +#include "interface/themes.h" +#include "interface/title_sequences.h" #include "localisation/language.h" #include "localisation/localisation.h" -#include "util/util.h" -#include "interface/themes.h" +#include "network/network.h" #include "openrct2.h" +#include "util/util.h" // Magic number for original game cfg file static const int MagicNumber = 0x0003113A; @@ -122,20 +124,29 @@ config_enum_definition _currencyEnum[] = { { "NLG", CURRENCY_GUILDERS }, { "SEK", CURRENCY_KRONA }, { "EUR", CURRENCY_EUROS }, + { "KRW", CURRENCY_WON }, + { "RUB", CURRENCY_ROUBLE }, 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 }, + { "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 }, + { "pt-BR", LANGUAGE_PORTUGUESE_BR }, + { "zh-Hant",LANGUAGE_CHINESE_TRADITIONAL }, + { "zh-Hans",LANGUAGE_CHINESE_SIMPLIFIED }, + { "fi-FI", LANGUAGE_FINNISH }, + { "ko", LANGUAGE_KOREAN }, + { "ru-RU", LANGUAGE_RUSSIAN }, + { "cz-CZ", LANGUAGE_CZECH }, END_OF_ENUM }; @@ -151,7 +162,7 @@ config_enum_definition _dateFormatEnum[] = { 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, autosave_frequency), "autosave", CONFIG_VALUE_TYPE_UINT8, AUTOSAVE_EVERY_5MINUTES, 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 }, @@ -173,29 +184,43 @@ config_property_definition _generalDefinitions[] = { { 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, uncap_fps), "uncap_fps", 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, handymen_mow_default), "handymen_mow_default", 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 }, + { offsetof(general_configuration, invert_viewport_drag), "invert_viewport_drag", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(general_configuration, load_save_sort), "load_save_sort", CONFIG_VALUE_TYPE_UINT8, SORT_NAME_ASCENDING, NULL }, + { offsetof(general_configuration, minimize_fullscreen_focus_loss), "minimize_fullscreen_focus_loss",CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, + { offsetof(general_configuration, day_night_cycle), "day_night_cycle", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(general_configuration, upper_case_banners), "upper_case_banners", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(general_configuration, allow_loading_with_incorrect_checksum),"allow_loading_with_incorrect_checksum", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(general_configuration, steam_overlay_pause), "steam_overlay_pause", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, + { offsetof(general_configuration, window_scale), "window_scale", CONFIG_VALUE_TYPE_FLOAT, { .value_float = 1.0f }, 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, toolbar_show_news), "toolbar_show_news", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(interface_configuration, select_by_track_type), "select_by_track_type", 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 }, + { offsetof(interface_configuration, current_theme_preset), "current_theme", CONFIG_VALUE_TYPE_STRING, { .value_string = "*RCT2" }, NULL }, + { offsetof(interface_configuration, current_title_sequence_preset), "current_title_sequence", CONFIG_VALUE_TYPE_STRING, { .value_string = "*OPENRCT2" },NULL }, + { offsetof(interface_configuration, object_selection_filter_flags), "object_selection_filter_flags",CONFIG_VALUE_TYPE_UINT32, 0x7EF, 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, audio_focus), "audio_focus", CONFIG_VALUE_TYPE_BOOLEAN, false, 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 }, + { offsetof(sound_configuration, device), "audio_device", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL }, }; config_property_definition _cheatDefinitions[] = { @@ -204,6 +229,8 @@ config_property_definition _cheatDefinitions[] = { { 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 }, + { offsetof(cheat_configuration, ignore_ride_intensity), "ignore_ride_intensity", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(cheat_configuration, disable_vandalism), "disable_vandalism", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, }; config_property_definition _twitchDefinitions[] = { @@ -215,12 +242,27 @@ config_property_definition _twitchDefinitions[] = { { offsetof(twitch_configuration, enable_news), "news", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL } }; +config_property_definition _networkDefinitions[] = { + { offsetof(network_configuration, player_name), "player_name", CONFIG_VALUE_TYPE_STRING, {.value_string = "Player" }, NULL }, + { offsetof(network_configuration, default_port), "default_port", CONFIG_VALUE_TYPE_UINT32, NETWORK_DEFAULT_PORT, NULL }, + { offsetof(network_configuration, stay_connected), "stay_connected", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, + { offsetof(network_configuration, advertise), "advertise", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(network_configuration, maxplayers), "maxplayers", CONFIG_VALUE_TYPE_UINT8, 16, NULL }, + { offsetof(network_configuration, server_name), "server_name", CONFIG_VALUE_TYPE_STRING, {.value_string = "Server" }, NULL }, + { offsetof(network_configuration, server_description), "server_description", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, + { offsetof(network_configuration, master_server_url), "master_server_url", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, + { offsetof(network_configuration, provider_name), "provider_name", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, + { offsetof(network_configuration, provider_email), "provider_email", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, NULL }, + { offsetof(network_configuration, provider_website), "provider_website", CONFIG_VALUE_TYPE_STRING, {.value_string = NULL }, 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) } + { &gConfigTwitch, "twitch", _twitchDefinitions, countof(_twitchDefinitions) }, + { &gConfigNetwork, "network", _networkDefinitions, countof(_networkDefinitions) } }; #pragma endregion @@ -230,21 +272,48 @@ interface_configuration gConfigInterface; sound_configuration gConfigSound; cheat_configuration gConfigCheat; twitch_configuration gConfigTwitch; +network_configuration gConfigNetwork; themes_configuration gConfigThemes; +title_sequences_configuration gConfigTitleSequences; 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 void config_save_property_value(SDL_RWops *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 void config_write_enum(SDL_RWops *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(); +static int rwopsreadc(SDL_RWops *file) +{ + int c = 0; + if (SDL_RWread(file, &c, 1, 1) != 1) + c = EOF; + return c; +} + +static void rwopswritec(SDL_RWops *file, char c) +{ + SDL_RWwrite(file, &c, 1, 1); +} + +static void rwopsprintf(SDL_RWops *file, const char *format, ...) +{ + va_list args; + va_start(args, format); + + char buffer[64]; + vsprintf(buffer, format, args); + + SDL_RWwrite(file, buffer, strlen(buffer), 1); + + va_end(args); +} + void config_set_defaults() { int i, j; @@ -253,9 +322,9 @@ void config_set_defaults() 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); + // Special dynamic defaults if (strcmp(property->property_name, "language") == 0){ destValue->value_uint16 = platform_get_locale_language(); if (destValue->value_uint16 == LANGUAGE_UNDEFINED) @@ -271,7 +340,17 @@ void config_set_defaults() destValue->value_uint8 = platform_get_locale_temperature_format(); } else { - memcpy(destValue, &property->default_value, _configValueTypeSize[property->type]); + // Use static default + if (property->type == CONFIG_VALUE_TYPE_STRING) { + // Copy the string to new memory + const utf8 *src = property->default_value.value_string; + const utf8 **dst = (const utf8**)&(destValue->value_string); + if (src != NULL) { + *dst = _strdup(property->default_value.value_string); + } + } else { + memcpy(destValue, &property->default_value, _configValueTypeSize[property->type]); + } } } } @@ -307,14 +386,14 @@ bool config_save_default() bool config_open(const utf8string path) { - FILE *file; - uint8 *lineBuffer; + SDL_RWops *file; + utf8string lineBuffer; size_t lineBufferCapacity; size_t lineLength; int c; config_section_definition *currentSection; - file = fopen(path, "rb"); + file = SDL_RWFromFile(path, "rb"); if (file == NULL) return false; @@ -324,11 +403,11 @@ bool config_open(const utf8string path) lineLength = 0; // Skim UTF-8 byte order mark - fread(lineBuffer, 3, 1, file); + SDL_RWread(file, lineBuffer, 3, 1); if (!utf8_is_bom(lineBuffer)) - fseek(file, 0, SEEK_SET); + SDL_RWseek(file, 0, RW_SEEK_SET); - while ((c = fgetc(file)) != EOF) { + while ((c = rwopsreadc(file)) != EOF) { if (c == '\n' || c == '\r') { lineBuffer[lineLength++] = 0; config_read_properties(¤tSection, (const_utf8string)lineBuffer); @@ -349,17 +428,17 @@ bool config_open(const utf8string path) } free(lineBuffer); - fclose(file); + SDL_RWclose(file); return true; } bool config_save(const utf8string path) { - FILE *file; + SDL_RWops *file; int i, j; value_union *value; - file = fopen(path, "wb"); + file = SDL_RWFromFile(path, "wb"); if (file == NULL) { log_error("Unable to write to config file."); return false; @@ -368,67 +447,67 @@ bool config_save(const utf8string path) 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); + rwopswritec(file, '['); + SDL_RWwrite(file, section->section_name, strlen(section->section_name), 1); + rwopswritec(file, ']'); + rwopswritec(file, '\n'); 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); + SDL_RWwrite(file, property->property_name, strlen(property->property_name), 1); + SDL_RWwrite(file, " = ", 3, 1); 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); + rwopswritec(file, '\n'); } - fputc('\n', file); + rwopswritec(file, '\n'); } - fclose(file); + SDL_RWclose(file); return true; } -static void config_save_property_value(FILE *file, uint8 type, value_union *value) +static void config_save_property_value(SDL_RWops *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); + if (value->value_boolean) SDL_RWwrite(file, "true", 4, 1); + else SDL_RWwrite(file, "false", 5, 1); break; case CONFIG_VALUE_TYPE_UINT8: - fprintf(file, "%u", value->value_uint8); + rwopsprintf(file, "%u", value->value_uint8); break; case CONFIG_VALUE_TYPE_UINT16: - fprintf(file, "%u", value->value_uint16); + rwopsprintf(file, "%u", value->value_uint16); break; case CONFIG_VALUE_TYPE_UINT32: - fprintf(file, "%u", value->value_uint32); + rwopsprintf(file, "%lu", value->value_uint32); break; case CONFIG_VALUE_TYPE_SINT8: - fprintf(file, "%d", value->value_sint8); + rwopsprintf(file, "%d", value->value_sint8); break; case CONFIG_VALUE_TYPE_SINT16: - fprintf(file, "%d", value->value_sint16); + rwopsprintf(file, "%d", value->value_sint16); break; case CONFIG_VALUE_TYPE_SINT32: - fprintf(file, "%d", value->value_sint32); + rwopsprintf(file, "%ld", value->value_sint32); break; case CONFIG_VALUE_TYPE_FLOAT: - fprintf(file, "%.3f", value->value_float); + rwopsprintf(file, "%.3f", value->value_float); break; case CONFIG_VALUE_TYPE_DOUBLE: - fprintf(file, "%.6f", value->value_double); + rwopsprintf(file, "%.6f", value->value_double); break; case CONFIG_VALUE_TYPE_STRING: - fputc('"', file); + rwopswritec(file, '"'); if (value->value_string != NULL) - fwrite(value->value_string, strlen(value->value_string), 1, file); - fputc('"', file); + SDL_RWwrite(file, value->value_string, strlen(value->value_string), 1); + rwopswritec(file, '"'); break; } } @@ -443,8 +522,7 @@ bool config_get_section(const utf8string line, const utf8 **sectionName, int *se if (*ch != '[') return false; *sectionName = ++ch; - while (*ch != 0) { - c = utf8_read(&ch); + while ((c = utf8_get_next(ch, (const utf8**)&ch)) != 0) { if (c == '#') return false; if (c == '[') return false; if (c == ' ') break; @@ -463,12 +541,11 @@ bool config_get_property_name_value(const utf8string line, utf8 **propertyName, ch = line; utf8_skip_whitespace(&ch); - + if (*ch == 0) return false; *propertyName = ch; - while (*ch != 0) { - c = utf8_read(&ch); + while ((c = utf8_get_next(ch, (const utf8**)&ch)) != 0) { if (isspace(c) || c == '=') { *propertyNameSize = ch - *propertyName - 1; break; @@ -492,14 +569,14 @@ bool config_get_property_name_value(const utf8string line, utf8 **propertyName, } *value = ch; - while (*ch != 0) { - c = utf8_read(&ch); + while ((c = utf8_get_next(ch, (const utf8**)&ch)) != 0) { if (isspace(c) || c == '#') { if (!quotes) break; } lastC = c; } *valueSize = ch - *value - 1; + if (quotes) (*valueSize)--; return true; } @@ -509,7 +586,8 @@ config_section_definition *config_get_section_def(const utf8 *name, int size) for (i = 0; i < countof(_sectionDefinitions); i++) { const_utf8string sectionName = _sectionDefinitions[i].section_name; - if (sectionName[size] == 0 && _strnicmp(sectionName, name, size) == 0) + const int sectionNameSize = strnlen(sectionName, size); + if (sectionNameSize == size && sectionName[size] == 0 && _strnicmp(sectionName, name, size) == 0) return &_sectionDefinitions[i]; } @@ -522,8 +600,11 @@ config_property_definition *config_get_property_def(config_section_definition *s 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) + const int propertyNameSize = strnlen(propertyName, size); + if (propertyNameSize == size && propertyName[size] == 0 && _strnicmp(propertyName, name, size) == 0) + { return §ion->property_definitions[i]; + } } return NULL; @@ -603,7 +684,7 @@ static void config_read_properties(config_section_definition **currentSection, c 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) { + if (strlen(enumDefinitions->key) == keySize && _strnicmp(enumDefinitions->key, key, keySize) == 0) { memcpy(dest, &enumDefinitions->value.value_uint32, destSize); return true; } @@ -612,12 +693,12 @@ static bool config_read_enum(void *dest, int destSize, const utf8 *key, int keyS return false; } -static void config_write_enum(FILE *file, uint8 type, value_union *value, config_enum_definition *enumDefinitions) +static void config_write_enum(SDL_RWops *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); + SDL_RWwrite(file, enumDefinitions->key, strlen(enumDefinitions->key), 1); return; } enumDefinitions++; @@ -625,32 +706,12 @@ static void config_write_enum(FILE *file, uint8 type, value_union *value, config 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))) { + if (!isspace(utf8_get_next(*outch, (const utf8**)outch))) { *outch = ch; break; } @@ -660,7 +721,7 @@ static void utf8_skip_whitespace(utf8 **outch) static void utf8_skip_non_whitespace(utf8 **outch) { while (**outch != 0) { - if (isspace(utf8_read(outch))) + if (isspace(utf8_get_next(*outch, (const utf8**)outch))) break; } } @@ -692,13 +753,13 @@ static config_line *_configLines = NULL; * @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) +static bool config_find_rct2_path(utf8 *resultPath) { int i; log_verbose("searching common installation locations."); - const char *searchLocations[] = { + const utf8 *searchLocations[] = { "C:\\Program Files\\Infogrames\\RollerCoaster Tycoon 2", "C:\\Program Files (x86)\\Infogrames\\RollerCoaster Tycoon 2", "C:\\Program Files\\Infogrames Interactive\\RollerCoaster Tycoon 2", @@ -710,8 +771,8 @@ static bool config_find_rct2_path(char *resultPath) }; for (i = 0; i < countof(searchLocations); i++) { - if (platform_directory_exists(searchLocations[i]) ) { - strcpy(resultPath, searchLocations[i]); + if (platform_original_game_data_exists(searchLocations[i])) { + safe_strncpy(resultPath, searchLocations[i], MAX_PATH); return true; } } @@ -721,13 +782,13 @@ static bool config_find_rct2_path(char *resultPath) bool config_find_or_browse_install_directory() { - char path[MAX_PATH]; - char *installPath; + utf8 path[MAX_PATH]; + utf8 *installPath; if (config_find_rct2_path(path)) { SafeFree(gConfigGeneral.game_path); gConfigGeneral.game_path = malloc(strlen(path) + 1); - strcpy(gConfigGeneral.game_path, path); + safe_strncpy(gConfigGeneral.game_path, path, MAX_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"); @@ -750,13 +811,10 @@ bool config_find_or_browse_install_directory() 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_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; @@ -774,151 +832,27 @@ void config_apply_to_old_addresses() 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 +#define SHIFT 0x100 +#define CTRL 0x200 +#define ALT 0x400 + // Current keyboard shortcuts uint16 gShortcutKeys[SHORTCUT_COUNT]; // Default keyboard shortcuts static const uint16 _defaultShortcutKeys[SHORTCUT_COUNT] = { SDL_SCANCODE_BACKSPACE, // SHORTCUT_CLOSE_TOP_MOST_WINDOW - 0x0100 | SDL_SCANCODE_BACKSPACE, // SHORTCUT_CLOSE_ALL_FLOATING_WINDOWS + SHIFT | SDL_SCANCODE_BACKSPACE, // SHORTCUT_CLOSE_ALL_FLOATING_WINDOWS SDL_SCANCODE_ESCAPE, // SHORTCUT_CANCEL_CONSTRUCTION_MODE SDL_SCANCODE_PAUSE, // SHORTCUT_PAUSE_GAME SDL_SCANCODE_PAGEUP, // SHORTCUT_ZOOM_VIEW_OUT SDL_SCANCODE_PAGEDOWN, // SHORTCUT_ZOOM_VIEW_IN - SDL_SCANCODE_RETURN, // SHORTCUT_ROTATE_VIEW + SDL_SCANCODE_RETURN, // SHORTCUT_ROTATE_VIEW_CLOCKWISE + SHIFT | SDL_SCANCODE_RETURN, // SHORTCUT_ROTATE_VIEW_ANTICLOCKWISE SDL_SCANCODE_Z, // SHORTCUT_ROTATE_CONSTRUCTION_OBJECT SDL_SCANCODE_1, // SHORTCUT_UNDERGROUND_VIEW_TOGGLE SDL_SCANCODE_H, // SHORTCUT_REMOVE_BASE_LAND_TOGGLE @@ -943,16 +877,25 @@ static const uint16 _defaultShortcutKeys[SHORTCUT_COUNT] = { SDL_SCANCODE_S, // SHORTCUT_SHOW_STAFF_LIST SDL_SCANCODE_M, // SHORTCUT_SHOW_RECENT_MESSAGES SDL_SCANCODE_TAB, // SHORTCUT_SHOW_MAP - 0x0200 | SDL_SCANCODE_S, // SHORTCUT_SCREENSHOT + CTRL | SDL_SCANCODE_S, // SHORTCUT_SCREENSHOT // New SDL_SCANCODE_MINUS, // SHORTCUT_REDUCE_GAME_SPEED, SDL_SCANCODE_EQUALS, // SHORTCUT_INCREASE_GAME_SPEED, - 0x0200 | 0x0400 | SDL_SCANCODE_C // SHORTCUT_OPEN_CHEAT_WINDOW, + CTRL | ALT | SDL_SCANCODE_C, // SHORTCUT_OPEN_CHEAT_WINDOW, + SDL_SCANCODE_T, // SHORTCUT_REMOVE_TOP_BOTTOM_TOOLBAR_TOGGLE, + SDL_SCANCODE_UP, // SHORTCUT_SCROLL_MAP_UP + SDL_SCANCODE_LEFT, // SHORTCUT_SCROLL_MAP_LEFT + SDL_SCANCODE_DOWN, // SHORTCUT_SCROLL_MAP_DOWN + SDL_SCANCODE_RIGHT, // SHORTCUT_SCROLL_MAP_RIGHT + SDL_SCANCODE_C, // SHORTCUT_OPEN_CHAT_WINDOW + CTRL | SDL_SCANCODE_F10, // SHORTCUT_QUICK_SAVE_GAME }; +#define SHORTCUT_FILE_VERSION 1 + /** - * + * * rct2: 0x006E3604 */ void config_reset_shortcut_keys() @@ -960,7 +903,7 @@ void config_reset_shortcut_keys() memcpy(gShortcutKeys, _defaultShortcutKeys, sizeof(gShortcutKeys)); } -void config_shortcut_keys_get_path(char *outPath) +void config_shortcut_keys_get_path(utf8 *outPath) { platform_get_user_directory(outPath, NULL); strcat(outPath, "hotkeys.cfg"); @@ -968,16 +911,22 @@ void config_shortcut_keys_get_path(char *outPath) bool config_shortcut_keys_load() { - char path[MAX_PATH]; - FILE *file; - int result; + utf8 path[MAX_PATH]; + SDL_RWops *file; + bool result; + uint16 version; config_shortcut_keys_get_path(path); - file = fopen(path, "rb"); + file = SDL_RWFromFile(path, "rb"); if (file != NULL) { - result = fread(gShortcutKeys, sizeof(gShortcutKeys), 1, file) == 1; - fclose(file); + result = SDL_RWread(file, &version, sizeof(version), 1) == 1; + if (result && version == SHORTCUT_FILE_VERSION) { + result = SDL_RWread(file, gShortcutKeys, sizeof(gShortcutKeys), 1) == 1; + } else { + result = false; + } + SDL_RWclose(file); } else { result = false; } @@ -987,16 +936,21 @@ bool config_shortcut_keys_load() bool config_shortcut_keys_save() { - char path[MAX_PATH]; - FILE *file; - int result; + const uint16 version = SHORTCUT_FILE_VERSION; + + utf8 path[MAX_PATH]; + SDL_RWops *file; + bool result; config_shortcut_keys_get_path(path); - file = fopen(path, "wb"); + file = SDL_RWFromFile(path, "wb"); if (file != NULL) { - result = fwrite(gShortcutKeys, sizeof(gShortcutKeys), 1, file) == 1; - fclose(file); + result = SDL_RWwrite(file, &version, sizeof(version), 1) == 1; + if (result) { + result = SDL_RWwrite(file, gShortcutKeys, sizeof(gShortcutKeys), 1) == 1; + } + SDL_RWclose(file); } else { result = false; } @@ -1065,7 +1019,7 @@ void themes_set_default() gConfigThemes.presets = malloc(sizeof(theme_preset) * gConfigThemes.num_presets); // Set RCT2 theme - strcpy(gConfigThemes.presets[0].name, language_get_string(2741)); + safe_strncpy(gConfigThemes.presets[0].name, language_get_string(2741), THEME_PRESET_NAME_SIZE); gConfigThemes.presets[0].windows = malloc(sizeof(theme_window) * gNumThemeWindows); // Define the defaults for RCT2 here @@ -1079,7 +1033,7 @@ void themes_set_default() } // Set RCT1 theme - strcpy(gConfigThemes.presets[1].name, language_get_string(2740)); + safe_strncpy(gConfigThemes.presets[1].name, language_get_string(2740), THEME_PRESET_NAME_SIZE); gConfigThemes.presets[1].windows = malloc(sizeof(theme_window) * gNumThemeWindows); // Define the defaults for RCT1 here @@ -1138,7 +1092,7 @@ void themes_load_presets() 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"); @@ -1151,14 +1105,14 @@ bool themes_save_preset(int preset) bool themes_open(const_utf8string path) { - FILE *file; - uint8 *lineBuffer; + SDL_RWops *file; + utf8string lineBuffer; size_t lineBufferCapacity; size_t lineLength; int c, preset; theme_section_definition *currentSection; - file = fopen(path, "rb"); + file = SDL_RWFromFile(path, "rb"); if (file == NULL) return false; @@ -1173,7 +1127,7 @@ bool themes_open(const_utf8string path) 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)); + safe_strncpy(gConfigThemes.presets[preset].name, path_get_filename(path), THEME_PRESET_NAME_SIZE); path_remove_extension(gConfigThemes.presets[preset].name); gConfigThemes.presets[preset].windows = malloc(sizeof(theme_window) * gNumThemeWindows); gConfigThemes.presets[preset].features.rct1_ride_lights = false; @@ -1190,11 +1144,11 @@ bool themes_open(const_utf8string path) 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); + SDL_RWread(file, lineBuffer, 3, 1); + if (!(lineBuffer[0] == (utf8)0xEF && lineBuffer[1] == (utf8)0xBB && lineBuffer[2] == (utf8)0xBF)) + SDL_RWseek(file, 0, SEEK_SET); - while ((c = fgetc(file)) != EOF) { + while ((c = rwopsreadc(file)) != EOF) { if (c == '\n' || c == '\r') { lineBuffer[lineLength++] = 0; themes_read_properties(&gConfigThemes.presets[preset], ¤tSection, (utf8string)lineBuffer); @@ -1216,17 +1170,17 @@ bool themes_open(const_utf8string path) } free(lineBuffer); - fclose(file); + SDL_RWclose(file); return true; } static bool themes_save(const_utf8string path, int preset) { - FILE *file; + SDL_RWops *file; int i, j; value_union *value; - file = fopen(path, "wb"); + file = SDL_RWFromFile(path, "wb"); if (file == NULL) { log_error("Unable to write to theme file."); return false; @@ -1236,16 +1190,16 @@ static bool themes_save(const_utf8string path, int preset) 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); + rwopswritec(file, '['); + SDL_RWwrite(file, section->section_name, strlen(section->section_name), 1); + rwopswritec(file, ']'); + rwopswritec(file, '\n'); 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); + SDL_RWwrite(file, property->property_name, strlen(property->property_name), 1); + SDL_RWwrite(file, " = ", 3, 1); value = (value_union*)((size_t)&gConfigThemes.presets[preset] + (size_t)section->offset + (size_t)property->offset); @@ -1253,24 +1207,24 @@ static bool themes_save(const_utf8string path, int preset) 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); + rwopswritec(file, '\n'); } + rwopswritec(file, '\n'); + } 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); + + rwopswritec(file, '['); + SDL_RWwrite(file, gThemeWindowDefinitions[i].section_name, strlen(gThemeWindowDefinitions[i].section_name), 1); + rwopswritec(file, ']'); + rwopswritec(file, '\n'); 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); + SDL_RWwrite(file, property->property_name, strlen(property->property_name), 1); + SDL_RWwrite(file, " = ", 3, 1); value = (value_union*)((size_t)gConfigThemes.presets[preset].windows + (size_t)(sizeof(theme_window) * i) + (size_t)property->offset); @@ -1278,11 +1232,11 @@ static bool themes_save(const_utf8string path, int preset) config_write_enum(file, property->type, value, property->enum_definitions); else config_save_property_value(file, property->type, value); - fputc('\n', file); - } + rwopswritec(file, '\n'); + } } - fclose(file); + SDL_RWclose(file); return true; } @@ -1297,8 +1251,7 @@ static void themes_read_properties(theme_preset *theme, theme_section_definition int sectionNameSize; if (config_get_section(ch, §ionName, §ionNameSize)) *currentSection = themes_get_section_def((utf8string)sectionName, sectionNameSize); - } - else { + } else { if (*currentSection != NULL) { utf8 *propertyName, *value; int propertyNameSize, valueSize; @@ -1395,4 +1348,252 @@ static theme_property_definition *themes_get_property_def(theme_section_definiti return NULL; } +#pragma endregion + +#pragma region Title Sequences + +static void title_sequence_open(const char *path, const char *customName); + +void title_sequences_set_default() +{ + char path[MAX_PATH]; + char sep = platform_get_path_separator(); + + platform_get_user_directory(path, "title sequences"); + platform_ensure_directory_exists(path); + + gConfigTitleSequences.presets = malloc(0); + gConfigTitleSequences.num_presets = 0; + + // Load OpenRCT2 title sequence + sprintf(path, "%s%c%s%c%s%c%s%c", gExePath, sep, "data", sep, "title", sep, "rct2", sep); + title_sequence_open(path, language_get_string(5308)); + + // Load OpenRCT2 title sequence + sprintf(path, "%s%c%s%c%s%c%s%c", gExePath, sep, "data", sep, "title", sep, "openrct2", sep); + title_sequence_open(path, language_get_string(5309)); +} + +void title_sequences_load_presets() +{ + utf8 path[MAX_PATH], titleDir[MAX_PATH]; + int dirEnumHandle, i; + + // Find all directories in the title sequences folder + platform_get_user_directory(path, "title sequences"); + dirEnumHandle = platform_enumerate_directories_begin(path); + while (platform_enumerate_directories_next(dirEnumHandle, titleDir)) { + platform_get_user_directory(path, "title sequences"); + strcat(path, titleDir); + title_sequence_open(path, NULL); + } + platform_enumerate_directories_end(dirEnumHandle); + + // Check which title sequence is the current one + if (_stricmp(gConfigInterface.current_title_sequence_preset, "*RCT2") == 0) { + gCurrentTitleSequence = 0; + } + else if (_stricmp(gConfigInterface.current_title_sequence_preset, "*OPENRCT2") == 0) { + gCurrentTitleSequence = 1; + } + else { + for (i = TITLE_SEQUENCE_DEFAULT_PRESETS; i < gConfigTitleSequences.num_presets; i++) { + if (_stricmp(gConfigInterface.current_title_sequence_preset, gConfigTitleSequences.presets[i].name) == 0) { + gCurrentTitleSequence = i; + break; + } + } + if (i == gConfigTitleSequences.num_presets) { + gCurrentTitleSequence = 0; + } + } + gCurrentPreviewTitleSequence = gCurrentTitleSequence; +} + +static void title_sequence_open(const char *path, const char *customName) +{ + utf8 titlePath[MAX_PATH], scriptPath[MAX_PATH]; + file_info fileInfo; + SDL_RWops *file; + int fileEnumHandle, i, preset; + char parts[3 * 128], *token, *part1, *part2; + char separator = platform_get_path_separator(); + + // Check for the script file + safe_strncpy(scriptPath, path, MAX_PATH); + strcat(scriptPath, "script.txt"); + if (!platform_file_exists(scriptPath)) { + // No script file, title sequence is invalid + return; + } + + // Check if the preset is already loaded + // No nead to read the first two presets as they're hardcoded in + for (preset = 0; preset < gConfigTitleSequences.num_presets; preset++) { + if (_stricmp(path, gConfigTitleSequences.presets[preset].name) == 0) { + return; + } + } + // Otherwise allocate one + if (preset == gConfigTitleSequences.num_presets) { + gConfigTitleSequences.num_presets++; + gConfigTitleSequences.presets = realloc(gConfigTitleSequences.presets, sizeof(title_sequence) * (size_t)gConfigTitleSequences.num_presets); + + if (customName == NULL) { + char nameBuffer[MAX_PATH], *name; + safe_strncpy(nameBuffer, path, MAX_PATH); + name = nameBuffer + strlen(nameBuffer) - 1; + while (*name == '\\' || *name == '/') { + *name = 0; + name--; + } + while (*(name - 1) != '\\' && *(name - 1) != '/') { + name--; + } + safe_strncpy(gConfigTitleSequences.presets[preset].name, name, TITLE_SEQUENCE_NAME_SIZE); + gConfigTitleSequences.presets[preset].path[0] = 0; + } + else { + safe_strncpy(gConfigTitleSequences.presets[preset].name, customName, TITLE_SEQUENCE_NAME_SIZE); + safe_strncpy(gConfigTitleSequences.presets[preset].path, path, MAX_PATH); + } + + gConfigTitleSequences.presets[preset].saves = malloc(0); + gConfigTitleSequences.presets[preset].commands = malloc(0); + gConfigTitleSequences.presets[preset].num_saves = 0; + gConfigTitleSequences.presets[preset].num_commands = 0; + } + + // Get the save file list + safe_strncpy(titlePath, path, MAX_PATH); + strcat(titlePath, "*.sv6"); + fileEnumHandle = platform_enumerate_files_begin(titlePath); + while (platform_enumerate_files_next(fileEnumHandle, &fileInfo)) { + gConfigTitleSequences.presets[preset].num_saves++; + gConfigTitleSequences.presets[preset].saves = realloc(gConfigTitleSequences.presets[preset].saves, sizeof(char[TITLE_SEQUENCE_MAX_SAVE_LENGTH]) * (size_t)gConfigTitleSequences.presets[preset].num_saves); + safe_strncpy(gConfigTitleSequences.presets[preset].saves[gConfigTitleSequences.presets[preset].num_saves - 1], fileInfo.path, TITLE_SEQUENCE_MAX_SAVE_LENGTH); + gConfigTitleSequences.presets[preset].saves[gConfigTitleSequences.presets[preset].num_saves - 1][TITLE_SEQUENCE_MAX_SAVE_LENGTH - 1] = '\0'; + } + platform_enumerate_files_end(fileEnumHandle); + safe_strncpy(titlePath, path, MAX_PATH); + strcat(titlePath, "*.sc6"); + fileEnumHandle = platform_enumerate_files_begin(titlePath); + while (platform_enumerate_files_next(fileEnumHandle, &fileInfo)) { + gConfigTitleSequences.presets[preset].num_saves++; + gConfigTitleSequences.presets[preset].saves = realloc(gConfigTitleSequences.presets[preset].saves, sizeof(char[TITLE_SEQUENCE_MAX_SAVE_LENGTH]) * (size_t)gConfigTitleSequences.presets[preset].num_saves); + safe_strncpy(gConfigTitleSequences.presets[preset].saves[gConfigTitleSequences.presets[preset].num_saves - 1], fileInfo.path, TITLE_SEQUENCE_MAX_SAVE_LENGTH); + gConfigTitleSequences.presets[preset].saves[gConfigTitleSequences.presets[preset].num_saves - 1][TITLE_SEQUENCE_MAX_SAVE_LENGTH - 1] = '\0'; + } + platform_enumerate_files_end(fileEnumHandle); + + // Load the script file + file = SDL_RWFromFile(scriptPath, "r"); + sint64 fileSize = SDL_RWsize(file); + do { + title_script_get_line(file, parts); + + token = &parts[0 * 128]; + part1 = &parts[1 * 128]; + part2 = &parts[2 * 128]; + title_command command = { 0 }; + command.command = 0xFF; + + if (token[0] != 0) { + if (_stricmp(token, "LOAD") == 0) { + command.command = TITLE_SCRIPT_LOAD; + command.saveIndex = 0xFF; + for (i = 0; i < gConfigTitleSequences.presets[preset].num_saves && command.saveIndex == 0xFF; i++) { + if (_stricmp(part1, gConfigTitleSequences.presets[preset].saves[i]) == 0) + command.saveIndex = i; + } + } else if (_stricmp(token, "LOCATION") == 0) { + command.command = TITLE_SCRIPT_LOCATION; + command.x = atoi(part1) & 0xFF; + command.y = atoi(part2) & 0xFF; + } else if (_stricmp(token, "ROTATE") == 0) { + command.command = TITLE_SCRIPT_ROTATE; + command.rotations = atoi(part1) & 0xFF; + } else if (_stricmp(token, "ZOOM") == 0) { + command.command = TITLE_SCRIPT_ZOOM; + command.zoom = atoi(part1) & 0xFF; + } else if (_stricmp(token, "SPEED") == 0) { + command.command = TITLE_SCRIPT_SPEED; + command.speed = max(1, min(4, atoi(part1) & 0xFF)); + } else if (_stricmp(token, "WAIT") == 0) { + command.command = TITLE_SCRIPT_WAIT; + command.seconds = atoi(part1) & 0xFF; + } else if (_stricmp(token, "RESTART") == 0) { + command.command = TITLE_SCRIPT_RESTART; + } else if (_stricmp(token, "END") == 0) { + command.command = TITLE_SCRIPT_END; + } else if (_stricmp(token, "LOADMM") == 0) { + command.command = TITLE_SCRIPT_LOADMM; + } + } + if (command.command != 0xFF) { + gConfigTitleSequences.presets[preset].num_commands++; + gConfigTitleSequences.presets[preset].commands = realloc(gConfigTitleSequences.presets[preset].commands, sizeof(title_command) * (size_t)gConfigTitleSequences.presets[preset].num_commands); + gConfigTitleSequences.presets[preset].commands[gConfigTitleSequences.presets[preset].num_commands - 1] = command; + } + } while (SDL_RWtell(file) < fileSize); + SDL_RWclose(file); +} + +void title_sequence_save_preset_script(int preset) +{ + utf8 path[MAX_PATH]; + SDL_RWops *file; + int i; + char separator = platform_get_path_separator(); + + + platform_get_user_directory(path, "title sequences"); + strcat(path, path_get_filename(gConfigTitleSequences.presets[preset].name)); + strncat(path, &separator, 1); + strcat(path, "script.txt"); + + file = SDL_RWFromFile(path, "wb"); + if (file == NULL) { + log_error("Unable to write to script file."); + return; + } + + for (i = 0; i < gConfigTitleSequences.presets[preset].num_commands; i++) { + title_command *command = &gConfigTitleSequences.presets[preset].commands[i]; + switch (command->command) { + case TITLE_SCRIPT_LOAD: + if (command->saveIndex == 0xFF) + rwopsprintf(file, "LOAD \r\n"); + else + rwopsprintf(file, "LOAD %s\r\n", gConfigTitleSequences.presets[preset].saves[command->saveIndex]); + break; + case TITLE_SCRIPT_LOCATION: + rwopsprintf(file, "LOCATION %i %i\r\n", command->x, command->y); + break; + case TITLE_SCRIPT_ROTATE: + rwopsprintf(file, "ROTATE %i\r\n", command->rotations); + break; + case TITLE_SCRIPT_ZOOM: + rwopsprintf(file, "ZOOM %i\r\n", command->zoom); + break; + case TITLE_SCRIPT_SPEED: + rwopsprintf(file, "SPEED %i\r\n", command->speed); + break; + case TITLE_SCRIPT_WAIT: + rwopsprintf(file, "WAIT %i\r\n\r\n", command->seconds); + break; + case TITLE_SCRIPT_RESTART: + rwopsprintf(file, "RESTART\r\n"); + break; + case TITLE_SCRIPT_END: + rwopsprintf(file, "END\r\n"); + break; + + } + } + + SDL_RWclose(file); +} + + #pragma endregion diff --git a/src/config.h b/src/config.h index d9fcd3ae62..951727ca21 100644 --- a/src/config.h +++ b/src/config.h @@ -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 . *****************************************************************************/ @@ -39,7 +39,8 @@ enum { SHORTCUT_PAUSE_GAME, SHORTCUT_ZOOM_VIEW_OUT, SHORTCUT_ZOOM_VIEW_IN, - SHORTCUT_ROTATE_VIEW, + SHORTCUT_ROTATE_VIEW_CLOCKWISE, + SHORTCUT_ROTATE_VIEW_ANTICLOCKWISE, SHORTCUT_ROTATE_CONSTRUCTION_OBJECT, SHORTCUT_UNDERGROUND_VIEW_TOGGLE, SHORTCUT_REMOVE_BASE_LAND_TOGGLE, @@ -70,6 +71,13 @@ enum { SHORTCUT_REDUCE_GAME_SPEED, SHORTCUT_INCREASE_GAME_SPEED, SHORTCUT_OPEN_CHEAT_WINDOW, + SHORTCUT_REMOVE_TOP_BOTTOM_TOOLBAR_TOGGLE, + SHORTCUT_SCROLL_MAP_UP, + SHORTCUT_SCROLL_MAP_LEFT, + SHORTCUT_SCROLL_MAP_DOWN, + SHORTCUT_SCROLL_MAP_RIGHT, + SHORTCUT_OPEN_CHAT_WINDOW, + SHORTCUT_QUICK_SAVE_GAME, SHORTCUT_COUNT }; @@ -90,11 +98,11 @@ enum { }; enum { - AUTOSAVE_EVERY_WEEK, - AUTOSAVE_EVERY_2_WEEKS, - AUTOSAVE_EVERY_MONTH, - AUTOSAVE_EVERY_4_MONTHS, - AUTOSAVE_EVERY_YEAR, + AUTOSAVE_EVERY_MINUTE, + AUTOSAVE_EVERY_5MINUTES, + AUTOSAVE_EVERY_15MINUTES, + AUTOSAVE_EVERY_30MINUTES, + AUTOSAVE_EVERY_HOUR, AUTOSAVE_NEVER }; @@ -112,6 +120,13 @@ enum { TITLE_SEQUENCE_RANDOM }; +enum { + SORT_NAME_ASCENDING, + SORT_NAME_DESCENDING, + SORT_DATE_ASCENDING, + SORT_DATE_DESCENDING, +}; + typedef struct { uint8 play_intro; uint8 confirmation_prompt; @@ -138,29 +153,43 @@ typedef struct { uint8 window_snap_proximity; uint8 autosave_frequency; uint8 hardware_display; + uint8 uncap_fps; uint8 test_unfinished_tracks; uint8 no_test_crashes; uint8 date_format; uint8 auto_staff_placement; + uint8 handymen_mow_default; utf8string last_run_version; - uint8 title_sequence; + uint8 invert_viewport_drag; + uint8 load_save_sort; + uint8 minimize_fullscreen_focus_loss; + uint8 day_night_cycle; + uint8 upper_case_banners; + uint8 allow_loading_with_incorrect_checksum; + uint8 steam_overlay_pause; + float window_scale; } general_configuration; typedef struct { uint8 toolbar_show_finances; uint8 toolbar_show_research; uint8 toolbar_show_cheats; - uint8 allow_subtype_switching; + uint8 toolbar_show_news; + uint8 select_by_track_type; uint8 console_small_font; utf8string current_theme_preset; + utf8string current_title_sequence_preset; + uint32 object_selection_filter_flags; } interface_configuration; typedef struct { uint8 title_music; uint8 sound; uint8 ride_music; + uint8 audio_focus; uint8 master_volume; uint8 music_volume; + utf8string device; } sound_configuration; typedef struct { @@ -169,6 +198,8 @@ typedef struct { uint8 disable_all_breakdowns; uint8 unlock_all_prices; uint8 build_in_pause_mode; + uint8 ignore_ride_intensity; + uint8 disable_vandalism; } cheat_configuration; typedef struct { @@ -180,6 +211,20 @@ typedef struct { uint8 enable_news; } twitch_configuration; +typedef struct { + utf8string player_name; + uint32 default_port; + uint8 stay_connected; + uint8 advertise; + uint8 maxplayers; + utf8string server_name; + utf8string server_description; + utf8string master_server_url; + utf8string provider_name; + utf8string provider_email; + utf8string provider_website; +} network_configuration; + typedef struct theme_window { uint8 colours[6]; @@ -194,9 +239,10 @@ typedef struct { uint8 rct1_scenario_font; } theme_features; +#define THEME_PRESET_NAME_SIZE 256 typedef struct theme_preset { - char name[256]; + char name[THEME_PRESET_NAME_SIZE]; theme_window *windows; // Add structures for any other settings here @@ -209,6 +255,39 @@ typedef struct { uint16 num_presets; } themes_configuration; +#define TITLE_SEQUENCE_MAX_SAVE_LENGTH 51 + +typedef struct { + uint8 command; + union { + uint8 saveIndex; // LOAD (this index is internal only) + uint8 x; // LOCATION + uint8 rotations; // ROTATE (counter-clockwise) + uint8 zoom; // ZOOM + uint8 speed; // SPEED + uint8 seconds; // WAIT + }; + uint8 y; // LOCATION +} title_command; + +#define TITLE_SEQUENCE_NAME_SIZE 256 + +typedef struct { + char name[TITLE_SEQUENCE_NAME_SIZE]; + char path[MAX_PATH]; // Needed for non-modifiable presets + char (*saves)[TITLE_SEQUENCE_MAX_SAVE_LENGTH]; + title_command *commands; + uint8 num_saves; + uint16 num_commands; + +} title_sequence; + +typedef struct { + title_sequence *presets; + uint16 num_presets; + +} title_sequences_configuration; + typedef struct { uint8 key; uint8 modifier; @@ -219,7 +298,9 @@ extern interface_configuration gConfigInterface; extern sound_configuration gConfigSound; extern cheat_configuration gConfigCheat; extern twitch_configuration gConfigTwitch; +extern network_configuration gConfigNetwork; extern themes_configuration gConfigThemes; +extern title_sequences_configuration gConfigTitleSequences; extern uint16 gShortcutKeys[SHORTCUT_COUNT]; @@ -239,4 +320,8 @@ void themes_set_default(); void themes_load_presets(); bool themes_save_preset(int preset); +void title_sequences_set_default(); +void title_sequences_load_presets(); +void title_sequence_save_preset_script(int preset); + #endif diff --git a/src/core/Exception.hpp b/src/core/Exception.hpp new file mode 100644 index 0000000000..ac3d25d2ad --- /dev/null +++ b/src/core/Exception.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include "../common.h" + +class Exception : public std::exception { +public: + Exception() : std::exception() { } + Exception(const char *message) : std::exception() { + _message = message; + } + virtual ~Exception() { } + + const char *what() const throw() override { return _message; } + const char *GetMessage() const { return _message; } + +private: + const char *_message; +}; diff --git a/src/core/FileStream.hpp b/src/core/FileStream.hpp new file mode 100644 index 0000000000..e7b91d37d8 --- /dev/null +++ b/src/core/FileStream.hpp @@ -0,0 +1,94 @@ +#pragma once + +#include +#include "../common.h" +#include "IStream.hpp" + +enum { + FILE_MODE_OPEN, + FILE_MODE_WRITE +}; + +/** + * A stream for reading and writing to files. Wraps an SDL_RWops, SDL2's cross platform file stream. + */ +class FileStream : public IStream { +private: + SDL_RWops *_file; + bool _canRead; + bool _canWrite; + bool _disposed; + +public: + FileStream(const utf8 *path, int fileMode) { + const char *mode; + switch (fileMode) { + case FILE_MODE_OPEN: + mode = "rb"; + _canRead = true; + _canWrite = false; + break; + case FILE_MODE_WRITE: + mode = "wb"; + _canRead = false; + _canWrite = true; + break; + default: + throw; + } + + _file = SDL_RWFromFile(path, mode); + if (_file == NULL) { + throw IOException(SDL_GetError()); + } + + _disposed = false; + } + + ~FileStream() { + Dispose(); + } + + void Dispose() override { + if (!_disposed) { + _disposed = true; + SDL_RWclose(_file); + } + } + + bool CanRead() const override { return _canRead; } + bool CanWrite() const override { return _canWrite; } + + sint64 GetLength() const override { return SDL_RWsize(_file); } + sint64 GetPosition() const override { return SDL_RWtell(_file); } + + void SetPosition(sint64 position) override { + Seek(position, STREAM_SEEK_BEGIN); + } + + void Seek(sint64 offset, int origin) override { + switch (origin) { + case STREAM_SEEK_BEGIN: + SDL_RWseek(_file, offset, RW_SEEK_SET); + break; + case STREAM_SEEK_CURRENT: + SDL_RWseek(_file, offset, RW_SEEK_CUR); + break; + case STREAM_SEEK_END: + SDL_RWseek(_file, offset, RW_SEEK_END); + break; + } + } + + void Read(void *buffer, int length) override { + if (SDL_RWread(_file, buffer, length, 1) != 1) { + throw IOException("Attempted to read past end of file."); + } + } + + void Write(const void *buffer, int length) override { + if (SDL_RWwrite(_file, buffer, length, 1) != 1) { + throw IOException("Unable to write to file."); + } + } +}; diff --git a/src/core/IDisposable.hpp b/src/core/IDisposable.hpp new file mode 100644 index 0000000000..e0cfb58726 --- /dev/null +++ b/src/core/IDisposable.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "../common.h" + +/** + * Represents an object that can be disposed. So things can explicitly close resources before the destructor kicks in. + */ +interface IDisposable { + virtual void Dispose() abstract; +}; diff --git a/src/core/IStream.hpp b/src/core/IStream.hpp new file mode 100644 index 0000000000..00911cc6aa --- /dev/null +++ b/src/core/IStream.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include "../common.h" +#include "Exception.hpp" +#include "IDisposable.hpp" + +enum { + STREAM_SEEK_BEGIN, + STREAM_SEEK_CURRENT, + STREAM_SEEK_END +}; + +/** + * Represents a stream that can be read or written to. Implemented by types such as FileStream, NetworkStream or MemoryStream. + */ +interface IStream : public IDisposable { + /////////////////////////////////////////////////////////////////////////// + // Interface methods + /////////////////////////////////////////////////////////////////////////// + // virtual ~IStream() abstract; + + virtual bool CanRead() const abstract; + virtual bool CanWrite() const abstract; + + virtual sint64 GetLength() const abstract; + virtual sint64 GetPosition() const abstract; + virtual void SetPosition(sint64 position) abstract; + virtual void Seek(sint64 offset, int origin) abstract; + + virtual void Read(void *buffer, int length) abstract; + virtual void Write(const void *buffer, int length) abstract; + + /////////////////////////////////////////////////////////////////////////// + // Helper methods + /////////////////////////////////////////////////////////////////////////// + + /** + * Reads the size of the given type from the stream directly into the given address. + */ + template + void Read(T *value) { + Read(value, sizeof(T)); + } + + /** + * Writes the size of the given type to the stream directly from the given address. + */ + template + void Write(const T *value) { + Write(value, sizeof(T)); + } + + /** + * Reads the given type from the stream. Use this only for small types (e.g. sint8, sint64, double) + */ + template + T ReadValue() { + T buffer; + Read(&buffer); + return buffer; + } + + /** + * Writes the given type to the stream. Use this only for small types (e.g. sint8, sint64, double) + */ + template + void WriteValue(const T value) { + Write(&value); + } +}; + +class IOException : public Exception { +public: + IOException(const char *message) : Exception(message) { } +}; diff --git a/src/core/Math.hpp b/src/core/Math.hpp new file mode 100644 index 0000000000..939159db08 --- /dev/null +++ b/src/core/Math.hpp @@ -0,0 +1,23 @@ +#pragma once + +/** + * Common mathematical functions. + */ +namespace Math { + + template + T Min(T a, T b) { + return a < b ? a : b; + } + + template + T Max(T a, T b) { + return a > b ? a : b; + } + + template + T Clamp(T low, T x, T high) { + return Min(Max(low, x), high); + } + +} diff --git a/src/core/Memory.hpp b/src/core/Memory.hpp new file mode 100644 index 0000000000..52cacc5286 --- /dev/null +++ b/src/core/Memory.hpp @@ -0,0 +1,66 @@ +#pragma once + +/** + * Utility methods for memory management. Typically helpers and wrappers around the C standard library. + */ +namespace Memory { + template + T *Allocate() { + return (T*)malloc(sizeof(T)); + } + + template + T *Allocate(size_t size) { + return (T*)malloc(size); + } + + template + T *AllocateArray(size_t count) { + return (T*)malloc(count * sizeof(T)); + } + + template + T *Reallocate(T *ptr, size_t size) { + if (ptr == NULL) + return (T*)malloc(size); + else + return (T*)realloc((void*)ptr, size); + } + + template + T *ReallocateArray(T *ptr, size_t count) { + if (ptr == NULL) + return (T*)malloc(count * sizeof(T)); + else + return (T*)realloc((void*)ptr, count * sizeof(T)); + } + + template + void Free(T *ptr) { + free((void*)ptr); + } + + template + T *Copy(T *dst, const T *src, size_t size) { + if (size == 0) return (T*)dst; + return (T*)memcpy((void*)dst, (const void*)src, size); + } + + template + T *CopyArray(T *dst, const T *src, size_t count) { + if (count == 0) return (T*)dst; + return (T*)memcpy((void*)dst, (const void*)src, count * sizeof(T)); + } + + template + T *Duplicate(const T *src, size_t size) { + T *result = Allocate(size); + return Copy(result, src, size); + } + + template + T *DuplicateArray(const T *src, size_t count) { + T *result = AllocateArray(count); + return CopyArray(result, src, count); + } +} diff --git a/src/core/StringBuilder.hpp b/src/core/StringBuilder.hpp new file mode 100644 index 0000000000..b92f4001b0 --- /dev/null +++ b/src/core/StringBuilder.hpp @@ -0,0 +1,135 @@ +#pragma once + +#include "../common.h" +#include "../localisation/localisation.h" +#include "Math.hpp" +#include "Memory.hpp" + +/** + * Class for constructing strings efficiently. A buffer is automatically allocated and reallocated when characters or strings + * are appended. Use GetString to copy the current state of the string builder to a new fire-and-forget string. + */ +class StringBuilder final { +public: + StringBuilder() { + _buffer = NULL; + _capacity = 0; + _length = 0; + } + + StringBuilder(int capacity) : StringBuilder() { + EnsureCapacity(capacity); + } + + ~StringBuilder() { + if (_buffer != NULL) Memory::Free(_buffer); + } + + /** + * Appends the given character to the current string. + */ + void Append(int codepoint) { + int codepointLength = utf8_get_codepoint_length(codepoint); + EnsureCapacity(_length + codepointLength + 1); + utf8_write_codepoint(_buffer + _length, codepoint); + _length += codepointLength; + _buffer[_length] = 0; + } + + /** + * Appends the given string to the current string. + */ + void Append(const utf8 *text) { + int textLength = strlen(text); + Append(text, textLength); + } + + /** + * Appends the given string of the given length to the current string. Essentially used to ignore null terminators or copy + * the data faster as the length is already known. + * @param text Pointer to the UTF-8 text to append. + * @param textLength Number of bytes to copy. (Can be used to append single bytes rather than codepoints) + */ + void Append(const utf8 *text, int textLength) { + EnsureCapacity(_length + textLength + 1); + Memory::Copy(_buffer + _length, text, textLength); + _length += textLength; + _buffer[_length] = 0; + } + + /** + * Appends the string of a given StringBuilder to the current string. + */ + void Append(const StringBuilder *sb) { + Append(sb->GetBuffer(), sb->GetLength()); + } + + /** + * Clears the current string, but preserves the allocated memory for another string. + */ + void Clear() { + _length = 0; + if (_capacity >= 1) { + _buffer[_length] = 0; + } + } + + /** + * Like Clear, only will guarantee freeing of the underlying buffer. + */ + void Reset() { + _length = 0; + _capacity = 0; + if (_buffer != NULL) { + Memory::Free(_buffer); + } + } + + /** + * Returns the current string buffer as a new fire-and-forget string. + */ + utf8 *GetString() const { + // If buffer is null, length should be 0 which will create a new one byte memory block containing a null terminator + utf8 *result = Memory::AllocateArray(_length + 1); + Memory::CopyArray(result, _buffer, _length); + result[_length] = 0; + return result; + } + + /** + * Gets the current state of the StringBuilder. Warning: this represents the StringBuilder's current working buffer and will + * be deallocated when the StringBuilder is destructed. + */ + const utf8 *GetBuffer() const { + // buffer may be null, so return an immutable empty string + if (_buffer == NULL) return ""; + return _buffer; + } + + /** + * Gets the amount of allocated memory for the string buffer. + */ + size_t GetCapacity() const { return _capacity; } + + /** + * Gets the length of the current string. + */ + size_t GetLength() const { return _length; } + +private: + utf8 *_buffer; + size_t _capacity; + size_t _length; + + void EnsureCapacity(size_t capacity) + { + if (_capacity > capacity) return; + + _capacity = Math::Max((size_t)8, _capacity); + while (_capacity < capacity) { + _capacity *= 2; + } + + _buffer = Memory::ReallocateArray(_buffer, _capacity); + } +}; diff --git a/src/core/StringReader.hpp b/src/core/StringReader.hpp new file mode 100644 index 0000000000..196470cc87 --- /dev/null +++ b/src/core/StringReader.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include "../common.h" +#include "../localisation/localisation.h" +#include "../util/util.h" + +interface IStringReader { + virtual bool TryPeek(int *outCodepoint) abstract; + virtual bool TryRead(int *outCodepoint) abstract; + virtual void Skip() abstract; + virtual bool CanRead() const abstract; +}; + +class UTF8StringReader final : public IStringReader { +public: + UTF8StringReader(const utf8 *text) { + // Skip UTF-8 byte order mark + if (strlen(text) >= 3 && utf8_is_bom(text)) { + text += 3; + } + + _text = text; + _current = text; + } + + bool TryPeek(int *outCodepoint) override { + if (_current == NULL) return false; + + int codepoint = utf8_get_next(_current, NULL); + *outCodepoint = codepoint; + return true; + } + + bool TryRead(int *outCodepoint) override { + if (_current == NULL) return false; + + int codepoint = utf8_get_next(_current, &_current); + *outCodepoint = codepoint; + if (codepoint == 0) { + _current = NULL; + return false; + } + return true; + } + + void Skip() override { + int codepoint; + TryRead(&codepoint); + } + + bool CanRead() const override { + return _current != NULL; + } + +private: + const utf8 *_text; + const utf8 *_current; +}; diff --git a/src/cursors.h b/src/cursors.h index 19b19a2448..b3714cfaa1 100644 --- a/src/cursors.h +++ b/src/cursors.h @@ -174,12 +174,12 @@ extern unsigned char entrance_down_cursor_mask[32 * 4]; 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 +#define HAND_OPEN_CURSOR_HOTX 5 +#define HAND_OPEN_CURSOR_HOTY 1 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 +#define HAND_CLOSED_CURSOR_HOTX 5 +#define HAND_CLOSED_CURSOR_HOTY 1 #endif \ No newline at end of file diff --git a/src/diagnostic.c b/src/diagnostic.c index d2d06d5f7d..4d756348a8 100644 --- a/src/diagnostic.c +++ b/src/diagnostic.c @@ -79,4 +79,4 @@ void diagnostic_log_with_location(int diagnosticLevel, const char *file, const c // Line terminator fprintf(stream, "\n"); -} \ No newline at end of file +} diff --git a/src/diagnostic.h b/src/diagnostic.h index 21029db312..00c03bd154 100644 --- a/src/diagnostic.h +++ b/src/diagnostic.h @@ -30,6 +30,49 @@ enum { DIAGNOSTIC_LEVEL_COUNT }; +/* + * Compile-time debug levels. + * + * When compiling, just add -DDEBUG={0,1,2,3} (where 0 means disabled) + * Regardless of DEBUG value, a set of defines will be created: + * - DEBUG_LEVEL_1 + * - DEBUG_LEVEL_2 + * - DEBUG_LEVEL_3 + * which you would use like so: + * + * #if DEBUG_LEVEL_1 + * (... some debug code ...) + * #if DEBUG_LEVEL_2 + * (... more debug code ...) + * #endif // DEBUG_LEVEL_2 + * #endif // DEBUG_LEVEL_1 + * + * The defines will be either 0 or 1 so compiler will complain about undefined + * macro if you forget to include the file, which would not happen if we were + * only checking whether the define is present or not. + */ + +#if defined(DEBUG) + #if DEBUG > 0 + #define DEBUG_LEVEL_1 1 + #if DEBUG > 1 + #define DEBUG_LEVEL_2 1 + #if DEBUG > 2 + #define DEBUG_LEVEL_3 1 + #else + #define DEBUG_LEVEL_3 0 + #endif // DEBUG > 2 + #else + #define DEBUG_LEVEL_3 0 + #define DEBUG_LEVEL_2 0 + #endif // DEBUG > 1 + #endif // DEBUG > 0 +#else + #define DEBUG_LEVEL_3 0 + #define DEBUG_LEVEL_2 0 + #define DEBUG_LEVEL_1 0 +#endif // defined(DEBUG) + extern int _log_levels[DIAGNOSTIC_LEVEL_COUNT]; void diagnostic_log(int diagnosticLevel, const char *format, ...); @@ -57,4 +100,4 @@ void diagnostic_log_with_location(int diagnosticLevel, const char *file, const c #endif -#endif \ No newline at end of file +#endif diff --git a/src/drawing/drawing.c b/src/drawing/drawing.c index b26c79ad60..51ddca2b61 100644 --- a/src/drawing/drawing.c +++ b/src/drawing/drawing.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 . *****************************************************************************/ @@ -31,13 +31,14 @@ int gLastDrawStringX; int gLastDrawStringY; -uint8 _screenDirtyBlocks[5120]; +uint8* _screenDirtyBlocks = NULL; +int _screenDirtyBlocksSize = 0; #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 -const uint8 peep_palette[0x100] = { +const uint8 peep_palette[0x100] = { 0x00, 0xF3, 0xF4, 0xF5, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, @@ -110,7 +111,7 @@ static void gfx_draw_dirty_blocks(int x, int y, int columns, int rows); void gfx_clear(rct_drawpixelinfo *dpi, int colour) { int y, w, h; - char* ptr; + uint8* ptr; w = dpi->width >> dpi->zoom_level; h = dpi->height >> dpi->zoom_level; @@ -137,8 +138,8 @@ void gfx_transpose_palette(int pal, unsigned char product) { rct_g1_element g1 = g1Elements[pal]; int width = g1.width; - int x = g1.x_offset; - uint8* dest_pointer = (uint8*)&(RCT2_ADDRESS(0x01424680, uint8)[x * 4]); + int x = g1.x_offset; + uint8* dest_pointer = (uint8*)&(RCT2_ADDRESS(RCT2_ADDRESS_PALETTE, uint8)[x * 4]); uint8* source_pointer = g1.offset; for (; width > 0; width--) { @@ -148,7 +149,7 @@ void gfx_transpose_palette(int pal, unsigned char product) source_pointer += 3; dest_pointer += 4; } - platform_update_palette((char*)0x01424680, 10, 236); + platform_update_palette((uint8*)RCT2_ADDRESS_PALETTE, 10, 236); } /* rct2: 0x006837E3 */ @@ -164,7 +165,7 @@ void load_palette(){ 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* dest_pointer = (uint8*)&(RCT2_ADDRESS(RCT2_ADDRESS_PALETTE, uint8)[x * 4]); uint8* source_pointer = g1.offset; for (; width > 0; width--) { @@ -174,75 +175,7 @@ void load_palette(){ source_pointer += 3; dest_pointer += 4; } - platform_update_palette((char*)0x01424680, 10, 236); -} - -/** -* -* rct2: 0x006EC9CE -* @param x (ax) -* @param y (cx) -* @param base_height (di) -* @param clearance_height (si) -*/ -void gfx_invalidate_tile_if_zoomed(int x, int y, int base_height, int clearance_height) -{ - x += 16; - y += 16; - int left, top, right, bottom; - switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) { - case 0: - left = (-x + y) - 32; - right = (-x + y) + 32; - top = ((y + x) / 2) - 32 - clearance_height; - bottom = ((y + x) / 2) + 32 - base_height; - break; - case 1: - left = (-x - y) - 32; - right = (-x - y) + 32; - top = ((y - x) / 2) - 32 - clearance_height; - bottom = ((y - x) / 2) + 32 - base_height; - break; - case 2: - left = (x - y) - 32; - right = (x - y) + 32; - top = ((-y - x) / 2) - 32 - clearance_height; - bottom = ((-y - x) / 2) + 32 - base_height; - break; - case 3: - left = (x + y) - 32; - right = (x + y) + 32; - top = ((-y + x) / 2) - 32 - clearance_height; - bottom = ((-y + x) / 2) + 32 - base_height; - break; - } - for (rct_viewport** viewport_p = RCT2_ADDRESS(RCT2_ADDRESS_ACTIVE_VIEWPORT_PTR_ARRAY, rct_viewport*); *viewport_p; ++viewport_p) - { - rct_viewport* viewport = *viewport_p; - if (viewport->zoom < 1) { - if (right > viewport->view_x && bottom > viewport->view_y && left < viewport->view_x + viewport->view_width) { - if (left < viewport->view_x) { - left = viewport->view_x; - } - if (right > viewport->view_x + viewport->view_width) { - right = viewport->view_x + viewport->view_width; - } - if (top < viewport->view_y + viewport->view_height) { - if (top < viewport->view_y) { - top = viewport->view_y; - } - if (bottom > viewport->view_y + viewport->view_height) { - bottom = viewport->view_y + viewport->view_height; - } - left = ((left - viewport->view_x) >> viewport->zoom) + viewport->x; - top = ((top - viewport->view_y) >> viewport->zoom) + viewport->y; - right = ((right - viewport->view_x) >> viewport->zoom) + viewport->x; - bottom = ((bottom - viewport->view_y) >> viewport->zoom) + viewport->y; - gfx_set_dirty_blocks(left, top, right, bottom); - } - } - } - } + platform_update_palette((uint8*)RCT2_ADDRESS_PALETTE, 10, 236); } /** @@ -251,28 +184,42 @@ void gfx_invalidate_tile_if_zoomed(int x, int y, int base_height, int clearance_ */ void gfx_invalidate_screen() { - int width = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); - int height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16); + int width = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); + int height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16); gfx_set_dirty_blocks(0, 0, width, height); } +uint8* gfx_get_dirty_blocks() +{ + int size = RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, uint32) * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_ROWS, uint32); + if (_screenDirtyBlocksSize != size) { + if (_screenDirtyBlocks) { + _screenDirtyBlocks = realloc(_screenDirtyBlocks, size); + } else { + _screenDirtyBlocks = malloc(size); + } + _screenDirtyBlocksSize = size; + } + return _screenDirtyBlocks; +} + /** - * + * * rct2: 0x006E732D * left (ax) * top (bx) * right (dx) * bottom (bp) */ -void gfx_set_dirty_blocks(int left, int top, int right, int bottom) +void gfx_set_dirty_blocks(sint16 left, sint16 top, sint16 right, sint16 bottom) { int x, y; - uint8 *screenDirtyBlocks = RCT2_ADDRESS(0x00EDE408, uint8); + uint8 *screenDirtyBlocks = gfx_get_dirty_blocks(); left = max(left, 0); top = max(top, 0); - right = min(right, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16)); - bottom = min(bottom, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16)); + right = min(right, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16)); + bottom = min(bottom, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16)); if (left >= right) return; @@ -289,7 +236,7 @@ void gfx_set_dirty_blocks(int left, int top, int right, int bottom) for (y = top; y <= bottom; y++) for (x = left; x <= right; x++) - screenDirtyBlocks[y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) + x] = 0xFF; + screenDirtyBlocks[y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, uint32) + x] = 0xFF; } /** @@ -298,26 +245,26 @@ void gfx_set_dirty_blocks(int left, int top, int right, int bottom) */ void gfx_draw_all_dirty_blocks() { - int x, y, xx, yy, columns, rows; - uint8 *screenDirtyBlocks = RCT2_ADDRESS(0x00EDE408, uint8); + unsigned int x, y, xx, yy, columns, rows; + uint8 *screenDirtyBlocks = gfx_get_dirty_blocks(); - for (x = 0; x < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32); x++) { - for (y = 0; y < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_ROWS, sint32); y++) { - if (screenDirtyBlocks[y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) + x] == 0) + for (x = 0; x < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, uint32); x++) { + for (y = 0; y < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_ROWS, uint32); y++) { + if (screenDirtyBlocks[y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, uint32) + x] == 0) continue; // Determine columns - for (xx = x; xx < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32); xx++) - if (screenDirtyBlocks[y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) + xx] == 0) + for (xx = x; xx < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, uint32); xx++) + if (screenDirtyBlocks[y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, uint32) + xx] == 0) break; columns = xx - x; // Check rows - for (yy = y; yy < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_ROWS, sint32); yy++) + for (yy = y; yy < RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_ROWS, uint32); yy++) for (xx = x; xx < x + columns; xx++) - if (screenDirtyBlocks[yy * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) + xx] == 0) + if (screenDirtyBlocks[yy * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, uint32) + xx] == 0) goto endRowCheck; - + endRowCheck: rows = yy - y; gfx_draw_dirty_blocks(x, y, columns, rows); @@ -328,18 +275,18 @@ void gfx_draw_all_dirty_blocks() static void gfx_draw_dirty_blocks(int x, int y, int columns, int rows) { int left, top, right, bottom; - uint8 *screenDirtyBlocks = RCT2_ADDRESS(0x00EDE408, uint8); + uint8 *screenDirtyBlocks = gfx_get_dirty_blocks(); // Unset dirty blocks for (top = y; top < y + rows; top++) for (left = x; left < x + columns; left++) - screenDirtyBlocks[top * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, sint32) + left] = 0; + screenDirtyBlocks[top * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, uint32) + left] = 0; // Determine region in pixels - left = max(0, x * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_WIDTH, sint16)); - top = max(0, y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_HEIGHT, sint16)); - right = min(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16), left + (columns * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_WIDTH, sint16))); - bottom = min(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16), top + (rows * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_HEIGHT, sint16))); + left = max(0, x * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_WIDTH, uint16)); + top = max(0, y * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_HEIGHT, uint16)); + right = min(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16), left + (columns * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_WIDTH, uint16))); + bottom = min(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16), top + (rows * RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_HEIGHT, uint16))); if (right <= left || bottom <= top) return; @@ -348,8 +295,8 @@ static void gfx_draw_dirty_blocks(int x, int y, int columns, int rows) } /** - * - * rct2: 0x006E7499 + * + * rct2: 0x006E7499 * left (ax) * top (bx) * right (dx) @@ -361,9 +308,6 @@ void gfx_redraw_screen_rect(short left, short top, short right, short bottom) rct_drawpixelinfo *screenDPI = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); rct_drawpixelinfo *windowDPI = RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_DPI, rct_drawpixelinfo); - // Unsure what this does - RCT2_CALLPROC_X(0x00683326, left, top, right - 1, bottom - 1, 0, 0, 0); - windowDPI->bits = screenDPI->bits + left + ((screenDPI->width + screenDPI->pitch) * top); windowDPI->x = left; windowDPI->y = top; @@ -491,7 +435,7 @@ void gfx_draw_rain(int left, int top, int width, int height, sint32 x_start, sin //Store colour and position *pixel_store++ = (x_pixel_offset << 8) | current_pixel; - + } } } @@ -507,29 +451,16 @@ void gfx_draw_rain(int left, int top, int width, int height, sint32 x_start, sin * * rct2: 0x006843DC */ -void redraw_peep_and_rain() +void redraw_rain() { if (RCT2_GLOBAL(0x009ABDF2, uint32) != 0) { - int sprite = RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32); - if (sprite != -1) { - sprite = sprite & 0x7FFFF; - - 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; - int bottom = top + g1_elements->height; - - gfx_set_dirty_blocks(left, top, right, bottom); - } - int rain_no_pixels = RCT2_GLOBAL(RCT2_ADDRESS_NO_RAIN_PIXELS, uint32); if (rain_no_pixels == 0) { return; } rct_window *window = window_get_main(); uint32 numPixels = window->width * window->height; - + uint32 *rain_pixels = rainPixels; if (rain_pixels) { uint8 *screen_pixels = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo)->bits; @@ -546,4 +477,102 @@ void redraw_peep_and_rain() } } RCT2_GLOBAL(RCT2_ADDRESS_NO_RAIN_PIXELS, uint32) = 0; -} \ No newline at end of file +} + +void gfx_invalidate_pickedup_peep() +{ + if (RCT2_GLOBAL(0x009ABDF2, uint32) != 0) { + int sprite = RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32); + if (sprite != -1) { + sprite = sprite & 0x7FFFF; + + 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; + int bottom = top + g1_elements->height; + + gfx_set_dirty_blocks(left, top, right, bottom); + } + } +} + +void gfx_draw_pickedup_peep() +{ + if (RCT2_GLOBAL(0x009ABDF2, uint8) == 0) + return; + + // Draw picked-up peep + if (RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, uint32) != 0xFFFFFFFF) { + gfx_draw_sprite( + (rct_drawpixelinfo*)RCT2_ADDRESS_SCREEN_DPI, + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, uint32), + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_Y, sint16), 0 + ); + } +} + +/** + * Draws the given colour image masked out by the given mask image. This can currently only cope with bitmap formatted mask and + * colour images. Presumebly the original game never used RLE images for masking. Colour 0 represents transparent. + * + * rct2: 0x00681DE2 + */ +void gfx_draw_sprite_raw_masked(rct_drawpixelinfo *dpi, int x, int y, int maskImage, int colourImage) +{ + int left, top, right, bottom, width, height; + rct_g1_element *imgMask = &g1Elements[maskImage & 0x7FFFF]; + rct_g1_element *imgColour = &g1Elements[colourImage & 0x7FFFF]; + + assert(imgMask->flags & 1); + assert(imgColour->flags & 1); + + if (dpi->zoom_level != 0) { + // TODO implement other zoom levels (probably not used though) + assert(false); + return; + } + + width = min(imgMask->width, imgColour->width); + height = min(imgMask->height, imgColour->height); + + x += imgMask->x_offset; + y += imgMask->y_offset; + + left = max(dpi->x, x); + top = max(dpi->y, y); + right = min(dpi->x + dpi->width, x + width); + bottom = min(dpi->y + dpi->height, y + height); + + width = right - left; + height = bottom - top; + if (width < 0 || height < 0) + return; + + int skipX = left - x; + int skipY = top - y; + + uint8 *maskSrc = imgMask->offset + (skipY * imgMask->width) + skipX; + uint8 *colourSrc = imgColour->offset + (skipY * imgColour->width) + skipX; + uint8 *dst = dpi->bits + (left - dpi->x) + ((top - dpi->y) * (dpi->width + dpi->pitch)); + + int maskWrap = imgMask->width - width; + int colourWrap = imgColour->width - width; + int dstWrap = ((dpi->width + dpi->pitch) - width); + for (int y = top; y < bottom; y++) { + for (int x = left; x < right; x++) { + uint8 colour = (*colourSrc) & (*maskSrc); + if (colour != 0) { + *dst = colour; + } + + maskSrc++; + colourSrc++; + dst++; + } + maskSrc += maskWrap; + colourSrc += colourWrap; + dst += dstWrap; + } +} diff --git a/src/drawing/drawing.h b/src/drawing/drawing.h index 80f3713e1a..69d8c85c3a 100644 --- a/src/drawing/drawing.h +++ b/src/drawing/drawing.h @@ -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,10 +22,11 @@ #define _DRAWING_H_ #include "../common.h" +#include "font.h" // Size: 0x10 typedef struct { - char* bits; // 0x00 + uint8* bits; // 0x00 short x; // 0x04 short y; // 0x06 short width; // 0x08 @@ -57,6 +58,17 @@ enum{ IMAGE_TYPE_UNKNOWN = (1<<3) }; +typedef struct { + uint32 num_entries; + uint32 total_size; +} rct_g1_header; + +typedef struct { + rct_g1_header header; + rct_g1_element *elements; + void *data; +} rct_gx; + extern const uint16 palette_to_g1_offset[]; extern const uint8 peep_palette[]; extern uint8 text_palette[]; @@ -65,13 +77,13 @@ extern int gLastDrawStringX; extern int gLastDrawStringY; extern rct_g1_element *g1Elements; +extern rct_gx g2; -// +// 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_set_dirty_blocks(sint16 left, sint16 top, sint16 right, sint16 bottom); void gfx_draw_all_dirty_blocks(); void gfx_redraw_screen_rect(short left, short top, short right, short bottom); -void gfx_invalidate_tile_if_zoomed(int x, int y, int base_height, int clearance_height); void gfx_invalidate_screen(); // palette @@ -82,6 +94,8 @@ void load_palette(); void gfx_draw_rain(int left, int top, int width, int height, sint32 x_start, sint32 y_start); void gfx_clear(rct_drawpixelinfo *dpi, int colour); void gfx_draw_pixel(rct_drawpixelinfo *dpi, int x, int y, int colour); +void gfx_invalidate_pickedup_peep(); +void gfx_draw_pickedup_peep(); // line void gfx_draw_line(rct_drawpixelinfo *dpi, int x1, int y1, int x2, int y2, int colour); @@ -95,12 +109,12 @@ 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_rle_sprite_to_buffer(const uint8* source_bits_pointer, uint8* dest_bits_pointer, const uint8* palette_pointer, const 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); void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint8* palette_pointer, uint8* unknown_pointer); +void gfx_draw_sprite_raw_masked(rct_drawpixelinfo *dpi, int x, int y, int maskImage, int colourImage); // string -void gfx_load_character_widths(); int clip_text(char *buffer, int width); int gfx_wrap_string(char* buffer, int width, int* num_lines, int* font_height); int gfx_get_string_width(char *buffer); @@ -110,6 +124,7 @@ void gfx_draw_string_left(rct_drawpixelinfo *dpi, int format, void *args, int co void gfx_draw_string_left_clipped(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y, int width); int gfx_draw_string_left_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int y, int width, int format, int colour); void draw_string_left_underline(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y); +void gfx_draw_string_left_centred(rct_drawpixelinfo *dpi, rct_string_id format, void *args, int colour, int x, int y); void gfx_draw_string_centred(rct_drawpixelinfo *dpi, int format, int x, int y, int colour, void *args); void gfx_draw_string_centred_clipped(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y, int width); void draw_string_centred_underline(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y); @@ -117,9 +132,20 @@ int gfx_draw_string_centred_wrapped(rct_drawpixelinfo *dpi, void *args, int x, i void draw_string_centred_raw(rct_drawpixelinfo *dpi, int x, int y, int numLines, char *text); void gfx_draw_string_right(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y); void draw_string_right_underline(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y); +int string_get_height_raw(char *buffer); +void gfx_draw_string_centred_wrapped_partial(rct_drawpixelinfo *dpi, int x, int y, int width, int colour, rct_string_id format, void *args, int ticks); +void gfx_draw_string_with_y_offsets(rct_drawpixelinfo *dpi, const utf8 *text, int colour, int x, int y, const sint8 *yOffsets, bool forceSpriteFont); +int gfx_clip_string(char* buffer, int width); + +bool ttf_initialise(); +void ttf_dispose(); // rain void update_rain_animation(); -void redraw_peep_and_rain(); +void redraw_rain(); + +// scrolling text +void scrolling_text_initialise_bitmaps(); +int scrolling_text_setup(rct_string_id stringId, uint16 scroll, uint16 scrollingMode); #endif diff --git a/src/drawing/font.c b/src/drawing/font.c new file mode 100644 index 0000000000..47003f4bef --- /dev/null +++ b/src/drawing/font.c @@ -0,0 +1,203 @@ +#include "../addresses.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "drawing.h" +#include "font.h" + +static const int SpriteFontLineHeight[] = { 6, 10, 10, 18 }; + +static uint8 *_spriteFontCharacterWidths = (uint8*)RCT2_ADDRESS_FONT_CHAR_WIDTH; + +TTFFontSetDescriptor *gCurrentTTFFontSet; + +/** + * + * rct2: 0x006C19AC + */ +void font_sprite_initialise_characters() +{ + uint8* pCharacterWidth = _spriteFontCharacterWidths; + for (int fontSize = 0; fontSize < FONT_SIZE_COUNT; fontSize++) { + int glyphOffset = fontSize * FONT_SPRITE_GLYPH_COUNT; + for (uint8 glyphIndex = 0; glyphIndex < FONT_SPRITE_GLYPH_COUNT; glyphIndex++) { + rct_g1_element g1 = g1Elements[glyphIndex + SPR_CHAR_START + glyphOffset]; + + int width = fontSize == FONT_SIZE_BIG ? g1.width + 1 : g1.width - 1; + if (glyphIndex >= (FORMAT_ARGUMENT_CODE_START - 32) && glyphIndex < (FORMAT_COLOUR_CODE_END - 32)) { + width = 0; + } + *pCharacterWidth++ = (uint8)width; + } + } + + scrolling_text_initialise_bitmaps(); + + for (int i = 0; i < 32; i++) { + rct_g1_element* g1 = &g1Elements[0x606 + i]; + uint8* unknown_pointer = RCT2_ADDRESS(0x009C3852, uint8) + 0xA12 * i; + g1->offset = unknown_pointer; + g1->width = 64; + g1->height = 40; + *((uint16*)unknown_pointer) = 0xFFFF; + *((uint32*)(unknown_pointer + 0x0E)) = 0; + } +} + +int font_sprite_get_codepoint_offset(int codepoint) +{ + switch (codepoint) { + case FORMAT_ENDQUOTES: return 34 - 32; + + case FORMAT_AMINUSCULE: return 159 - 32; + case FORMAT_UP: return 160 - 32; + case FORMAT_SYMBOL_i: return 160 - 32; + case FORMAT_CENT: return 162 - 32; + case FORMAT_POUND: return 163 - 32; + + case FORMAT_YEN: return 165 - 32; + + + + case FORMAT_COPYRIGHT: return 169 - 32; + case FORMAT_DOWN: return 170 - 32; + case FORMAT_LEFTGUILLEMET: return 171 - 32; + case FORMAT_TICK: return 172 - 32; + case FORMAT_CROSS: return 173 - 32; + + case FORMAT_RIGHT: return 175 - 32; + case FORMAT_DEGREE: return 176 - 32; + case FORMAT_SYMBOL_RAILWAY: return 177 - 32; + case FORMAT_SQUARED: return 178 - 32; + + case FORMAT_OPENQUOTES: return 180 - 32; + case FORMAT_EURO: return 181 - 32; + case FORMAT_SYMBOL_ROAD: return 182 - 32; + case FORMAT_SYMBOL_FLAG: return 183 - 32; + case FORMAT_APPROX: return 184 - 32; + case FORMAT_POWERNEGATIVEONE: return 185 - 32; + case FORMAT_BULLET: return 186 - 32; + case FORMAT_RIGHTGUILLEMET: return 187 - 32; + case FORMAT_SMALLUP: return 188 - 32; + case FORMAT_SMALLDOWN: return 189 - 32; + case FORMAT_LEFT: return 190 - 32; + case FORMAT_INVERTEDQUESTION: return 191 - 32; + default: + if (codepoint < 32 || codepoint >= 256) codepoint = '?'; + return codepoint - 32; + } +} + +int font_sprite_get_codepoint_width(int fontSpriteBase, int codepoint) +{ + return _spriteFontCharacterWidths[fontSpriteBase + font_sprite_get_codepoint_offset(codepoint)]; +} + +int font_sprite_get_codepoint_sprite(int fontSpriteBase, int codepoint) +{ + return SPR_CHAR_START + ((IMAGE_TYPE_USE_PALETTE << 28) | (fontSpriteBase + font_sprite_get_codepoint_offset(codepoint))); +} + +int font_get_size_from_sprite_base(uint16 spriteBase) +{ + switch (spriteBase) { + case FONT_SPRITE_BASE_TINY: + return 0; + case FONT_SPRITE_BASE_SMALL: + return 1; + default: + case FONT_SPRITE_BASE_MEDIUM: + return 2; + case FONT_SPRITE_BASE_BIG: + return 3; + } +} + +int font_get_line_height(int fontSpriteBase) +{ + int fontSize = font_get_size_from_sprite_base(fontSpriteBase); + if (gUseTrueTypeFont) { + return gCurrentTTFFontSet->size[fontSize].line_height; + } else { + return SpriteFontLineHeight[fontSize]; + } +} + +int font_get_line_height_small(int fontSpriteBase) +{ + return font_get_line_height(fontSpriteBase) / 2; +} + +bool font_supports_string_sprite(const utf8 *text) +{ + const utf8 *src = text; + + uint32 codepoint; + while ((codepoint = utf8_get_next(src, &src)) != 0) { + bool supported = false; + switch (codepoint) { + case FORMAT_ENDQUOTES: + case FORMAT_AMINUSCULE: + case FORMAT_UP: + case FORMAT_SYMBOL_i: + case FORMAT_CENT: + case FORMAT_POUND: + case FORMAT_YEN: + case FORMAT_COPYRIGHT: + case FORMAT_DOWN: + case FORMAT_LEFTGUILLEMET: + case FORMAT_TICK: + case FORMAT_CROSS: + case FORMAT_RIGHT: + case FORMAT_DEGREE: + case FORMAT_SYMBOL_RAILWAY: + case FORMAT_SQUARED: + case FORMAT_OPENQUOTES: + case FORMAT_EURO: + case FORMAT_SYMBOL_ROAD: + case FORMAT_SYMBOL_FLAG: + case FORMAT_APPROX: + case FORMAT_POWERNEGATIVEONE: + case FORMAT_BULLET: + case FORMAT_RIGHTGUILLEMET: + case FORMAT_SMALLUP: + case FORMAT_SMALLDOWN: + case FORMAT_LEFT: + case FORMAT_INVERTEDQUESTION: + supported = true; + break; + default: + if (codepoint >= 32 && codepoint < 256) { + supported = true; + } + break; + } + if (!supported) { + return false; + } + } + return true; +} + +bool font_supports_string_ttf(const utf8 *text, int fontSize) +{ + const utf8 *src = text; + const TTF_Font *font = gCurrentTTFFontSet->size[fontSize].font; + + uint32 codepoint; + while ((codepoint = utf8_get_next(src, &src)) != 0) { + bool supported = TTF_GlyphIsProvided(font, (uint16)codepoint); + if (!supported) { + return false; + } + } + return true; +} + +bool font_supports_string(const utf8 *text, int fontSize) +{ + if (gUseTrueTypeFont) { + return font_supports_string_ttf(text, fontSize); + } else { + return font_supports_string_sprite(text); + } +} diff --git a/src/drawing/font.h b/src/drawing/font.h new file mode 100644 index 0000000000..de7abc298b --- /dev/null +++ b/src/drawing/font.h @@ -0,0 +1,50 @@ +#ifndef _DRAWING_FONT_H_ +#define _DRAWING_FONT_H_ + +#include +#include "../common.h" + +enum { + FONT_SIZE_TINY = 2, + FONT_SIZE_SMALL = 0, + FONT_SIZE_MEDIUM = 1, + FONT_SIZE_BIG = 3, + FONT_SIZE_COUNT = 4 +}; + +enum { + FONT_SPRITE_GLYPH_COUNT = 224, + + FONT_SPRITE_BASE_TINY = 448, + FONT_SPRITE_BASE_SMALL = 0, + FONT_SPRITE_BASE_MEDIUM = 224, + FONT_SPRITE_BASE_BIG = 672 +}; + +typedef struct { + const utf8 *filename; + int ptSize; + int offset_x; + int offset_y; + int line_height; + TTF_Font *font; +} TTFFontDescriptor; + +typedef struct { + TTFFontDescriptor size[FONT_SIZE_COUNT]; +} TTFFontSetDescriptor; + +extern TTFFontSetDescriptor *gCurrentTTFFontSet; + +void font_sprite_initialise_characters(); +int font_sprite_get_codepoint_offset(int codepoint); +int font_sprite_get_codepoint_width(int fontSpriteBase, int codepoint); +int font_sprite_get_codepoint_sprite(int fontSpriteBase, int codepoint); +int font_get_size_from_sprite_base(uint16 spriteBase); +int font_get_line_height(int fontSpriteBase); +int font_get_line_height_small(int fontSpriteBase); +bool font_supports_string_sprite(const utf8 *text); +bool font_supports_string_ttf(const utf8 *text, int fontSize); +bool font_supports_string(const utf8 *text, int fontSize); + +#endif diff --git a/src/drawing/line.c b/src/drawing/line.c index 28bfbe7db6..c4697f7dea 100644 --- a/src/drawing/line.c +++ b/src/drawing/line.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 . *****************************************************************************/ @@ -53,13 +53,13 @@ void gfx_draw_line_on_buffer(rct_drawpixelinfo *dpi, char colour, int y, int x, if (no_pixels <= 0)return; } - char* bits_pointer; + uint8* bits_pointer; //Get the buffer we are drawing to and move to the first coordinate. bits_pointer = dpi->bits + y*(dpi->pitch + dpi->width) + x; //Draw the line to the specified colour for (; no_pixels > 0; --no_pixels, ++bits_pointer){ - *((uint8*)bits_pointer) = colour; + *bits_pointer = colour; } } @@ -147,4 +147,4 @@ void gfx_draw_line(rct_drawpixelinfo *dpi, int x1, int y1, int x2, int y2, int c } } return; -} \ No newline at end of file +} diff --git a/src/drawing/rain.c b/src/drawing/rain.c index b1660e5fb6..7aaed208a8 100644 --- a/src/drawing/rain.c +++ b/src/drawing/rain.c @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2014 + * Copyright (c) 2014 * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. * * This file is part of OpenRCT2. @@ -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 . *****************************************************************************/ @@ -105,7 +105,7 @@ static void draw_rain_window(rct_window* original_w, short left, short right, sh draw_rain_window(original_w, left, w_right, top, bottom, draw_rain_func); left = w_right; - draw_rain_window(original_w, left, right, top, bottom, draw_rain_func); + draw_rain_window(original_w, left, right, top, bottom, draw_rain_func); return; } @@ -113,7 +113,7 @@ static void draw_rain_window(rct_window* original_w, short left, short right, sh draw_rain_window(original_w, left, right, top, w->y, draw_rain_func); top = w->y; - draw_rain_window(original_w, left, right, top, bottom, draw_rain_func); + draw_rain_window(original_w, left, right, top, bottom, draw_rain_func); return; } @@ -122,7 +122,7 @@ static void draw_rain_window(rct_window* original_w, short left, short right, sh draw_rain_window(original_w, left, right, top, w_bottom, draw_rain_func); top = w_bottom; - draw_rain_window(original_w, left, right, top, bottom, draw_rain_func); + draw_rain_window(original_w, left, right, top, bottom, draw_rain_func); return; } } @@ -147,7 +147,7 @@ static void draw_rain_animation(uint32 draw_rain_func) } /** - * + * * rct2: 0x00684218 */ void update_rain_animation() @@ -155,16 +155,6 @@ void update_rain_animation() if (RCT2_GLOBAL(0x009ABDF2, uint8) == 0) return; - // Draw picked-up peep - if (RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, uint32) != 0xFFFFFFFF) { - gfx_draw_sprite( - (rct_drawpixelinfo*)RCT2_ADDRESS_SCREEN_DPI, - RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, uint32), - RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_X, sint16), - RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_Y, sint16), 0 - ); - } - // Get rain draw function and draw rain uint32 draw_rain_func = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RAIN_LEVEL, uint8); if (draw_rain_func > 0 && !(RCT2_GLOBAL(0x009DEA6F, uint8) & 1)) @@ -177,8 +167,8 @@ void update_rain_animation() */ static void draw_light_rain(int left, int top, int width, int height) { - int x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) + 8; - int y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 3) + 7; + int x_start = -(int)RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) + 8; + int y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) * 3) + 7; y_start = -y_start; x_start += left; @@ -186,8 +176,8 @@ static void draw_light_rain(int left, int top, int width, int height) gfx_draw_rain(left, top, width, height, x_start, y_start); - x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) + 0x18; - y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 4) + 0x0D; + x_start = -(int)RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) + 0x18; + y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) * 4) + 0x0D; y_start = -y_start; x_start += left; @@ -201,8 +191,8 @@ static void draw_light_rain(int left, int top, int width, int height) */ static void draw_heavy_rain(int left, int top, int width, int height) { - int x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int); - int y_start = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 5; + int x_start = -(int)RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32); + int y_start = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) * 5; y_start = -y_start; x_start += left; @@ -210,8 +200,8 @@ static void draw_heavy_rain(int left, int top, int width, int height) gfx_draw_rain(left, top, width, height, x_start, y_start); - x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) + 0x10; - y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 6) + 5; + x_start = -(int)RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) + 0x10; + y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) * 6) + 5; y_start = -y_start; x_start += left; @@ -219,8 +209,8 @@ static void draw_heavy_rain(int left, int top, int width, int height) gfx_draw_rain(left, top, width, height, x_start, y_start); - x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) + 8; - y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 3) + 7; + x_start = -(int)RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) + 8; + y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) * 3) + 7; y_start = -y_start; x_start += left; @@ -228,8 +218,8 @@ static void draw_heavy_rain(int left, int top, int width, int height) gfx_draw_rain(left, top, width, height, x_start, y_start); - x_start = -RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) + 0x18; - y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) * 4) + 0x0D; + x_start = -(int)RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) + 0x18; + y_start = (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) * 4) + 0x0D; y_start = -y_start; x_start += left; diff --git a/src/drawing/rect.c b/src/drawing/rect.c index 297dafd849..ab68699560 100644 --- a/src/drawing/rect.c +++ b/src/drawing/rect.c @@ -8,18 +8,20 @@ * 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 "../common.h" +#include "../interface/colour.h" +#include "../platform/platform.h" #include "drawing.h" /** @@ -41,7 +43,7 @@ void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bot top_ = top; bottom_ = bottom; dpi_ = dpi; - + if ((left > right) || (top > bottom) || (dpi->x > right) || (left >= (dpi->x + dpi->width)) || (bottom < dpi->y) || (top >= (dpi->y + dpi->height))) return; @@ -51,7 +53,7 @@ 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){ + if (start_x < 0){ cross_pattern ^= start_x; start_x = 0; } @@ -64,7 +66,7 @@ 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){ + if (start_y < 0){ cross_pattern ^= start_y; start_y = 0; } @@ -79,14 +81,14 @@ void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bot // 00678B2E 00678BE5 //Cross hatching uint8* dest_pointer = (start_y * (dpi->width + dpi->pitch)) + start_x + dpi->bits; - + uint32 ecx; for (int i = 0; i < height; ++i) { uint8* next_dest_pointer = dest_pointer + dpi->width + dpi->pitch; ecx = cross_pattern; // Rotate right ecx = (ecx >> 1) | (ecx << (sizeof(ecx) * CHAR_BIT - 1)); - ecx = (ecx & 0xFFFF0000) | width; + ecx = (ecx & 0xFFFF0000) | width; // Fill every other pixel with the colour for (; (ecx & 0xFFFF) > 0; ecx--) { ecx = ecx ^ 0x80000000; @@ -97,7 +99,7 @@ void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bot } cross_pattern ^= 1; dest_pointer = next_dest_pointer; - + } return; } @@ -125,7 +127,7 @@ void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bot if (colour & 0x4000000){ //0x4000000 // 00678B8A 00678E38 - char* dest_pointer; + uint8* dest_pointer; dest_pointer = start_y * (dpi->width + dpi->pitch) + start_x + dpi->bits; //The pattern loops every 15 lines this is which @@ -141,8 +143,8 @@ void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bot pattern_pointer = RCT2_ADDRESS(0x0097FEFC,uint16*)[colour >> 28]; // or possibly uint8)[esi*4] ? for (int no_lines = height; no_lines > 0; no_lines--) { - char* next_dest_pointer = dest_pointer + dpi->width + dpi->pitch; - uint16 pattern = pattern_pointer[pattern_y]; + uint8* next_dest_pointer = dest_pointer + dpi->width + dpi->pitch; + uint16 pattern = pattern_pointer[pattern_y]; for (int no_pixels = width; no_pixels > 0; --no_pixels) { if (pattern & (1 << pattern_x)) @@ -167,7 +169,7 @@ void gfx_fill_rect(rct_drawpixelinfo *dpi, int left, int top, int right, int bot left -= dpi->x;//0x4 if ( left < 0 ){ RCT2_GLOBAL(0xEDF824,sint32) -= left; - left = 0; + left = 0; } right -= dpi->x; right++; @@ -281,13 +283,13 @@ void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, short left, short top, short ri } } else { if (flags & 0x80) { - shadow = RCT2_ADDRESS(0x0141FC46, uint8)[colour * 8]; - fill = RCT2_ADDRESS(0x0141FC48, uint8)[colour * 8]; - hilight = RCT2_ADDRESS(0x0141FC4A, uint8)[colour * 8]; + shadow = ColourMapA[colour].dark; + fill = ColourMapA[colour].mid_light; + hilight = ColourMapA[colour].lighter; } else { - shadow = RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]; - fill = RCT2_ADDRESS(0x0141FC49, uint8)[colour * 8]; - hilight = RCT2_ADDRESS(0x0141FC4B, uint8)[colour * 8]; + shadow = ColourMapA[colour].mid_dark; + fill = ColourMapA[colour].light; + hilight = ColourMapA[colour].lighter; } if (flags & no_border) { @@ -302,9 +304,9 @@ void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, short left, short top, short ri if (!(flags & no_fill)) { if (!(flags & 0x40)) { if (flags & 0x04) { - fill = RCT2_ADDRESS(0x0141FC49, uint8)[0]; + fill = ColourMapA[COLOUR_BLACK].light; } else { - fill = RCT2_ADDRESS(0x0141FC4A, uint8)[colour * 8]; + fill = ColourMapA[colour].lighter; } } gfx_fill_rect(dpi, left+1, top+1, right-1, bottom-1, fill); @@ -318,10 +320,10 @@ void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, short left, short top, short ri if (!(flags & no_fill)) { if (flags & 0x04) { - fill = RCT2_ADDRESS(0x0141FC49, uint8)[0]; + fill = ColourMapA[COLOUR_BLACK].light; } gfx_fill_rect(dpi, left+1, top+1, right-1, bottom-1, fill); } } } -} \ No newline at end of file +} diff --git a/src/drawing/scrolling_text.c b/src/drawing/scrolling_text.c new file mode 100644 index 0000000000..72a7293d7f --- /dev/null +++ b/src/drawing/scrolling_text.c @@ -0,0 +1,281 @@ +#include "../addresses.h" +#include "../config.h" +#include "../interface/colour.h" +#include "../localisation/localisation.h" +#include "drawing.h" + +/* size: 0xA12 */ +typedef struct { + rct_string_id string_id; // 0x00 + uint32 string_args_0; // 0x02 + uint32 string_args_1; // 0x06 + uint16 position; // 0x0A + uint16 mode; // 0x0C + uint32 id; // 0x0E + uint8 bitmap[64 * 8 * 5]; // 0x12 +} rct_draw_scroll_text; + +rct_draw_scroll_text *gDrawScrollTextList = RCT2_ADDRESS(RCT2_ADDRESS_DRAW_SCROLL_LIST, rct_draw_scroll_text); +uint8 *gCharacterBitmaps = RCT2_ADDRESS(RCT2_ADDRESS_CHARACTER_BITMAP, uint8); + +void scrolling_text_set_bitmap_for_sprite(utf8 *text, int scroll, uint8 *bitmap, sint16 *scrollPositionOffsets); +void scrolling_text_set_bitmap_for_ttf(utf8 *text, int scroll, uint8 *bitmap, sint16 *scrollPositionOffsets); + +void scrolling_text_initialise_bitmaps() +{ + uint8 drawingSurface[64]; + rct_drawpixelinfo dpi = { + .bits = (uint8 *)&drawingSurface, + .x = 0, + .y = 0, + .width = 8, + .height = 8, + .pitch = 0, + .zoom_level = 0 + }; + + + for (int i = 0; i < 224; i++) { + memset(drawingSurface, 0, sizeof(drawingSurface)); + gfx_draw_sprite(&dpi, i + 0x10D5, -1, 0, 0); + + for (int x = 0; x < 8; x++) { + uint8 val = 0; + for (int y = 0; y < 8; y++) { + val >>= 1; + if (dpi.bits[x + y * 8] == 1) { + val |= 0x80; + } + } + gCharacterBitmaps[i * 8 + x] = val; + } + + } +} + +static uint8 *font_sprite_get_codepoint_bitmap(int codepoint) +{ + return &gCharacterBitmaps[font_sprite_get_codepoint_offset(codepoint) * 8]; +} + + +static int scrolling_text_get_matching_or_oldest(rct_string_id stringId, uint16 scroll, uint16 scrollingMode) +{ + uint32 oldestId = 0xFFFFFFFF; + int scrollIndex = -1; + rct_draw_scroll_text* oldestScroll = NULL; + for (int i = 0; i < 32; i++) { + rct_draw_scroll_text *scrollText = &gDrawScrollTextList[i]; + if (oldestId >= scrollText->id) { + oldestId = scrollText->id; + scrollIndex = i; + oldestScroll = scrollText; + } + + // If exact match return the matching index + if ( + scrollText->string_id == stringId && + scrollText->string_args_0 == RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) && + scrollText->string_args_1 == RCT2_GLOBAL(0x13CE956, uint32) && + scrollText->position == scroll && + scrollText->mode == scrollingMode + ) { + scrollText->id = RCT2_GLOBAL(RCT2_ADDRESS_DRAW_SCROLL_NEXT_ID, uint32); + return i + 0x606; + } + } + return scrollIndex; +} + +static uint8 scrolling_text_get_colour(uint32 character) +{ + int colour = character & 0x7F; + if (colour & (1 << 7)) { + return ColourMapA[colour].light; + } else { + return ColourMapA[colour].mid_dark; + } +} + +static void scrolling_text_format(utf8 *dst, rct_draw_scroll_text *scrollText) +{ + if (gConfigGeneral.upper_case_banners) { + format_string_to_upper(dst, scrollText->string_id, &scrollText->string_args_0); + } else { + format_string(dst, scrollText->string_id, &scrollText->string_args_0); + } +} + +/** + * + * rct2: 0x006C42D9 + * @param stringId (ax) + * @param scroll (cx) + * @param scrollingMode (bp) + * @returns ebx + */ +int scrolling_text_setup(rct_string_id stringId, uint16 scroll, uint16 scrollingMode) +{ + rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + + if (dpi->zoom_level != 0) return 0x626; + + RCT2_GLOBAL(RCT2_ADDRESS_DRAW_SCROLL_NEXT_ID, uint32)++; + + int scrollIndex = scrolling_text_get_matching_or_oldest(stringId, scroll, scrollingMode); + if (scrollIndex >= 0x606) return scrollIndex; + + // Setup scrolling text + rct_draw_scroll_text* scrollText = &gDrawScrollTextList[scrollIndex]; + scrollText->string_id = stringId; + scrollText->string_args_0 = RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32); + scrollText->string_args_1 = RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 4, uint32); + scrollText->position = scroll; + scrollText->mode = scrollingMode; + scrollText->id = RCT2_GLOBAL(RCT2_ADDRESS_DRAW_SCROLL_NEXT_ID, uint32); + + // Create the string to draw + utf8 scrollString[256]; + scrolling_text_format(scrollString, scrollText); + + sint16* scrollingModePositions = RCT2_ADDRESS(RCT2_ADDRESS_SCROLLING_MODE_POSITIONS, sint16*)[scrollingMode]; + + memset(scrollText->bitmap, 0, 320 * 8); + if (gUseTrueTypeFont) { + scrolling_text_set_bitmap_for_ttf(scrollString, scroll, scrollText->bitmap, scrollingModePositions); + } else { + scrolling_text_set_bitmap_for_sprite(scrollString, scroll, scrollText->bitmap, scrollingModePositions); + } + + return scrollIndex + 0x606; +} + +void scrolling_text_set_bitmap_for_sprite(utf8 *text, int scroll, uint8 *bitmap, sint16 *scrollPositionOffsets) +{ + uint8 characterColour = scrolling_text_get_colour(RCT2_GLOBAL(0x013CE959, uint8)); + + utf8 *ch = text; + while (true) { + uint32 codepoint = utf8_get_next(ch, (const utf8**)&ch); + + // If at the end of the string loop back to the start + if (codepoint == 0) { + ch = text; + continue; + } + + // Set any change in colour + if (codepoint <= FORMAT_COLOUR_CODE_END && codepoint >= FORMAT_COLOUR_CODE_START){ + codepoint -= FORMAT_COLOUR_CODE_START; + characterColour = RCT2_GLOBAL(0x009FF048, uint8*)[codepoint * 4]; + continue; + } + + // If another type of control character ignore + if (codepoint < 32) continue; + + int characterWidth = font_sprite_get_codepoint_width(FONT_SPRITE_BASE_TINY, codepoint); + uint8 *characterBitmap = font_sprite_get_codepoint_bitmap(codepoint); + for (; characterWidth != 0; characterWidth--, characterBitmap++) { + // Skip any none displayed columns + if (scroll != 0) { + scroll--; + continue; + } + + sint16 scrollPosition = *scrollPositionOffsets; + if (scrollPosition == -1) return; + if (scrollPosition > -1) { + uint8 *dst = &bitmap[scrollPosition]; + for (uint8 char_bitmap = *characterBitmap; char_bitmap != 0; char_bitmap >>= 1){ + if (char_bitmap & 1) *dst = characterColour; + + // Jump to next row + dst += 64; + } + } + scrollPositionOffsets++; + } + } +} + +TTFFontDescriptor *ttf_get_font_from_sprite_base(uint16 spriteBase); +SDL_Surface *_ttf_surface_cache_get_or_add(TTF_Font *font, const utf8 *text); + +void scrolling_text_set_bitmap_for_ttf(utf8 *text, int scroll, uint8 *bitmap, sint16 *scrollPositionOffsets) +{ + TTFFontDescriptor *fontDesc = ttf_get_font_from_sprite_base(FONT_SPRITE_BASE_TINY); + if (fontDesc->font == NULL) { + scrolling_text_set_bitmap_for_sprite(text, scroll, bitmap, scrollPositionOffsets); + return; + } + + // Currently only supports one colour + uint8 colour = 0; + + utf8 *dstCh = text; + utf8 *ch = text; + int codepoint; + while ((codepoint = utf8_get_next(ch, (const utf8**)&ch)) != 0) { + if (utf8_is_format_code(codepoint)) { + if (codepoint >= FORMAT_COLOUR_CODE_START && codepoint <= FORMAT_COLOUR_CODE_END) { + colour = (uint8)codepoint; + } + } else { + dstCh = utf8_write_codepoint(dstCh, codepoint); + } + } + *dstCh = 0; + + if (colour == 0) { + colour = scrolling_text_get_colour(RCT2_GLOBAL(0x013CE959, uint8)); + } else { + colour = RCT2_GLOBAL(0x009FF048, uint8*)[(colour - FORMAT_COLOUR_CODE_START) * 4]; + } + + SDL_Surface *surface = _ttf_surface_cache_get_or_add(fontDesc->font, text); + if (surface == NULL) { + return; + } + + if (SDL_MUSTLOCK(surface) && SDL_LockSurface(surface) == -1) { + return; + } + + int pitch = surface->pitch; + int width = surface->w; + int height = surface->h; + uint8 *src = surface->pixels; + + // Offset + height -= 3; + src += 3 * pitch; + height = min(height, 8); + + int x = 0; + while (true) { + // Skip any none displayed columns + if (scroll == 0) { + sint16 scrollPosition = *scrollPositionOffsets; + if (scrollPosition == -1) return; + if (scrollPosition > -1) { + uint8 *dst = &bitmap[scrollPosition]; + + for (int y = 0; y < height; y++) { + if (src[y * pitch + x] != 0) *dst = colour; + + // Jump to next row + dst += 64; + } + } + scrollPositionOffsets++; + } else { + scroll--; + } + + x++; + if (x >= width) x = 0; + } + + if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface); +} diff --git a/src/drawing/sprite.c b/src/drawing/sprite.c index 024675facd..aaa09f1cd2 100644 --- a/src/drawing/sprite.c +++ b/src/drawing/sprite.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 . *****************************************************************************/ @@ -25,50 +25,39 @@ #include "../platform/platform.h" #include "../openrct2.h" -typedef struct { - uint32 num_entries; - uint32 total_size; -} rct_g1_header; - 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 */ int gfx_load_g1() { log_verbose("loading g1 graphics"); - FILE *file; + SDL_RWops *file; rct_g1_header header; unsigned int i; - file = fopen(get_file_path(PATH_ID_G1), "rb"); + file = SDL_RWFromFile(get_file_path(PATH_ID_G1), "rb"); if (file != NULL) { - if (fread(&header, 8, 1, file) == 1) { + if (SDL_RWread(file, &header, 8, 1) == 1) { // number of elements is stored in g1.dat, but because the entry headers are static, this can't be variable until // made into a dynamic array header.num_entries = 29294; // Read element headers - fread(g1Elements, header.num_entries * sizeof(rct_g1_element), 1, file); + SDL_RWread(file, g1Elements, header.num_entries * sizeof(rct_g1_element), 1); // Read element data _g1Buffer = rct2_malloc(header.total_size); - fread(_g1Buffer, header.total_size, 1, file); + SDL_RWread(file, _g1Buffer, header.total_size, 1); - fclose(file); + SDL_RWclose(file); // Fix entry data offsets for (i = 0; i < header.num_entries; i++) @@ -77,7 +66,7 @@ int gfx_load_g1() // Successful return 1; } - fclose(file); + SDL_RWclose(file); } // Unsuccessful @@ -89,23 +78,23 @@ int gfx_load_g2() { log_verbose("loading g2 graphics"); - FILE *file; + SDL_RWops *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"); + file = SDL_RWFromFile(path, "rb"); if (file != NULL) { - if (fread(&g2.header, 8, 1, file) == 1) { + if (SDL_RWread(file, &g2.header, 8, 1) == 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); + SDL_RWread(file, g2.elements, g2.header.num_entries * sizeof(rct_g1_element), 1); // Read element data g2.data = malloc(g2.header.total_size); - fread(g2.data, g2.header.total_size, 1, file); + SDL_RWread(file, g2.data, g2.header.total_size, 1); - fclose(file); + SDL_RWclose(file); // Fix entry data offsets for (i = 0; i < g2.header.num_entries; i++) @@ -114,7 +103,7 @@ int gfx_load_g2() // Successful return 1; } - fclose(file); + SDL_RWclose(file); } // Unsuccessful @@ -143,17 +132,20 @@ 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){ uint16 zoom_level = dest_dpi->zoom_level; uint8 zoom_amount = 1 << zoom_level; + uint32 dest_line_width = (dest_dpi->width / zoom_amount) + dest_dpi->pitch; + uint32 source_line_width = source_image->width * zoom_amount; //Requires use of palette? if (image_type & IMAGE_TYPE_USE_PALETTE){ + assert(palette_pointer != NULL); //Mix with another image?? and colour adjusted if (unknown_pointer!= NULL){ //Not tested. I can't actually work out when this code runs. unknown_pointer += source_pointer - source_image->offset;// RCT2_GLOBAL(0x9E3CE0, uint32); for (; height > 0; height -= zoom_amount){ - uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_unknown_pointer = unknown_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; + uint8* next_source_pointer = source_pointer + source_line_width; + uint8* next_unknown_pointer = unknown_pointer + source_line_width; + uint8* next_dest_pointer = dest_pointer + dest_line_width; for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, unknown_pointer += zoom_amount, dest_pointer++){ uint8 pixel = *source_pointer; @@ -172,8 +164,8 @@ void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, ui //image colour adjusted? for (; height > 0; height -= zoom_amount){ - uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; + uint8* next_source_pointer = source_pointer + source_line_width; + uint8* next_dest_pointer = dest_pointer + dest_line_width; for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++){ uint8 pixel = *source_pointer; pixel = palette_pointer[pixel]; @@ -191,9 +183,10 @@ void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, ui //Mix with background. It only uses source pointer for //telling if it needs to be drawn not for colour. if (image_type & IMAGE_TYPE_MIX_BACKGROUND){//Not tested + assert(palette_pointer != NULL); for (; height > 0; height -= zoom_amount){ - uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; + uint8* next_source_pointer = source_pointer + source_line_width; + uint8* next_dest_pointer = dest_pointer + dest_line_width; for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++){ uint8 pixel = *source_pointer; @@ -213,8 +206,8 @@ void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, ui //Basic bitmap no fancy stuff if (!(source_image->flags & G1_FLAG_BMP)){//Not tested for (; height > 0; height -= zoom_amount){ - uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; + uint8* next_source_pointer = source_pointer + source_line_width; + uint8* next_dest_pointer = dest_pointer + dest_line_width; for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++, source_pointer += zoom_amount){ *dest_pointer = *source_pointer; @@ -230,9 +223,9 @@ void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, ui unknown_pointer += source_pointer - source_image->offset; for (; height > 0; height -= zoom_amount){ - uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_unknown_pointer = unknown_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; + uint8* next_source_pointer = source_pointer + source_line_width; + uint8* next_unknown_pointer = unknown_pointer + source_line_width; + uint8* next_dest_pointer = dest_pointer + dest_line_width; for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++, source_pointer += zoom_amount, unknown_pointer += zoom_amount){ uint8 pixel = *source_pointer; @@ -249,8 +242,8 @@ void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, ui //Basic bitmap with no draw pixels for (; height > 0; height -= zoom_amount){ - uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount); - uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch; + uint8* next_source_pointer = source_pointer + source_line_width; + uint8* next_dest_pointer = dest_pointer + dest_line_width; for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++, source_pointer += zoom_amount){ uint8 pixel = *source_pointer; @@ -269,16 +262,17 @@ void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, ui * This function copies the sprite data onto the screen * rct2: 0x0067AA18 */ -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_rle_sprite_to_buffer(const uint8* source_bits_pointer, uint8* dest_bits_pointer, const uint8* palette_pointer, const 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; + int line_width = (dpi->width >> zoom_level) + dpi->pitch; + + if (source_y_start < 0){ + source_y_start += zoom_amount; + next_dest_pointer += line_width; height -= zoom_amount; } @@ -287,13 +281,13 @@ void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_point //The first part of the source pointer is a list of offsets to different lines //This will move the pointer to the correct source line. - next_source_pointer = source_bits_pointer + ((uint16*)source_bits_pointer)[y]; + const uint8 *next_source_pointer = source_bits_pointer + ((uint16*)source_bits_pointer)[y]; uint8 last_data_line = 0; //For every data section in the line while (!last_data_line){ - uint8* source_pointer = next_source_pointer; + const uint8* source_pointer = next_source_pointer; uint8* dest_pointer = next_dest_pointer; int no_pixels = *source_pointer++; @@ -320,7 +314,7 @@ void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_point if (x_start > 0){ //Since the start is positive //We need to move the drawing surface to the correct position - dest_pointer += x_start / zoom_amount; + dest_pointer += x_start >> zoom_level; } else{ //If the start is negative we require to remove part of the image. @@ -360,7 +354,7 @@ void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_point else if (image_type & IMAGE_TYPE_MIX_BACKGROUND){//In the .exe these are all unraveled loops //Doesnt use source pointer ??? mix with background only? //Not Tested - + for (; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++){ uint8 pixel = *dest_pointer; pixel = palette_pointer[pixel]; @@ -369,21 +363,26 @@ void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_point } else { - for (; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++){ - *dest_pointer = *source_pointer; + if (zoom_amount == 1) { + memcpy(dest_pointer, source_pointer, no_pixels); + } + else { + for (; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++) { + *dest_pointer = *source_pointer; + } } } } //Add a line to the drawing surface pointer - next_dest_pointer += dpi->width / zoom_amount + dpi->pitch; + next_dest_pointer += line_width; } } /** * * rct2: 0x0067A28E - * image_id (ebx) + * image_id (ebx) * image_id as below * 0b_111X_XXXX_XXXX_XXXX_XXXX_XXXX_XXXX_XXXX image_type * 0b_XXX1_11XX_XXXX_XXXX_XXXX_XXXX_XXXX_XXXX image_sub_type (unknown pointer) @@ -453,7 +452,7 @@ void gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32 uint32 top_offset = palette_to_g1_offset[top_type]; //RCT2_ADDRESS(0x97FCBC, uint32)[top_type]; 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]; @@ -480,7 +479,7 @@ void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, in { int image_element = image_id & 0x7FFFF; int image_type = (image_id & 0xE0000000) >> 28; - + rct_g1_element* g1_source; if (image_element < SPR_G2_BEGIN) { g1_source = &g1Elements[image_element]; @@ -506,9 +505,8 @@ void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, in return; } - //Its used super often so we will define it to a seperate variable. + //Its used super often so we will define it to a separate variable. int zoom_level = dpi->zoom_level; - int zoom_amount = 1 << zoom_level; int zoom_mask = 0xFFFFFFFF << zoom_level; if (zoom_level && g1_source->flags & G1_FLAG_RLE_COMPRESSION){ @@ -562,8 +560,8 @@ void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, in //If the image no longer has anything to draw if (height <= 0)return; - dest_start_y /= zoom_amount; - dest_end_y /= zoom_amount; + dest_start_y >>= zoom_level; + dest_end_y >>= zoom_level; //This will be the width of the drawn image int width = g1_source->width; @@ -601,13 +599,13 @@ void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, in if (width <= 0)return; } - dest_start_x /= zoom_amount; - dest_end_x /= zoom_amount; + dest_start_x >>= zoom_level; + dest_end_x >>= zoom_level; uint8* dest_pointer = (uint8*)dpi->bits; //Move the pointer to the start point of the destination - dest_pointer += ((dpi->width / zoom_amount) + dpi->pitch)*dest_start_y + dest_start_x; - + dest_pointer += ((dpi->width >> zoom_level) + dpi->pitch) * dest_start_y + dest_start_x; + if (g1_source->flags & G1_FLAG_RLE_COMPRESSION){ //We have to use a different method to move the source pointer for //rle encoded sprites so that will be handled within this function @@ -653,11 +651,10 @@ void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, in eax = 0; memcpy((char*)new_source_pointer, (char*)source_pointer, ecx); new_source_pointer += ecx; - source_pointer += ecx; source_pointer = (uint8*)ebx; } source_pointer = new_source_pointer_start + g1_source->width*source_start_y + source_start_x; gfx_bmp_sprite_to_buffer(palette_pointer, unknown_pointer, source_pointer, dest_pointer, g1_source, dpi, height, width, image_type); free(new_source_pointer_start); return; -} \ No newline at end of file +} diff --git a/src/drawing/string.c b/src/drawing/string.c index 3acb688e86..cda6348f9c 100644 --- a/src/drawing/string.c +++ b/src/drawing/string.c @@ -8,156 +8,85 @@ * 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/colour.h" #include "../localisation/localisation.h" #include "../sprites.h" +#include "../world/map.h" +#include "../platform/platform.h" #include "drawing.h" +static int ttf_get_string_width(const utf8 *text); +static void ttf_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, int y); + +static bool _ttfInitialised = false; + +#define TTF_SURFACE_CACHE_SIZE 256 +#define TTF_GETWIDTH_CACHE_SIZE 1024 + +typedef struct { + SDL_Surface *surface; + TTF_Font *font; + utf8 *text; + uint32 lastUseTick; +} ttf_cache_entry; + +static ttf_cache_entry _ttfSurfaceCache[TTF_SURFACE_CACHE_SIZE] = { 0 }; +static int _ttfSurfaceCacheCount = 0; +static int _ttfSurfaceCacheHitCount = 0; +static int _ttfSurfaceCacheMissCount = 0; + +typedef struct { + uint32 width; + TTF_Font *font; + utf8 *text; + uint32 lastUseTick; +} ttf_getwidth_cache_entry; + +static ttf_getwidth_cache_entry _ttfGetWidthCache[TTF_GETWIDTH_CACHE_SIZE] = { 0 }; +static int _ttfGetWidthCacheCount = 0; +static int _ttfGetWidthCacheHitCount = 0; +static int _ttfGetWidthCacheMissCount = 0; + /** * - * rct2: 0x006C19AC + * rct2: 0x006C23B1 */ -void gfx_load_character_widths(){ +int gfx_get_string_width_new_lined(utf8 *text) +{ + utf8 *ch = text; + utf8 *firstCh = text; + utf8 *nextCh; + utf8 backup; + int codepoint; - 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 = g1Elements[c + SPR_CHAR_START + char_set_offset]; - int width; - - if (char_set_offset == 0xE0*3) width = g1.width + 1; - else width = g1.width - 1; - - if (c >= (FORMAT_ARGUMENT_CODE_START - 0x20) && c < (FORMAT_COLOUR_CODE_END - 0x20)){ - width = 0; - } - *char_width_pointer = (uint8)width; + int width = 0; + int maxWidth = 0; + while ((codepoint = utf8_get_next(ch, (const utf8**)&nextCh)) != 0) { + if (codepoint == FORMAT_NEWLINE || codepoint == FORMAT_NEWLINE_SMALLER) { + backup = *nextCh; + *nextCh = 0; + maxWidth = max(maxWidth, gfx_get_string_width(firstCh)); + *nextCh = backup; + firstCh = nextCh; } - + ch = nextCh; } - - uint8 drawing_surface[0x40]; - rct_drawpixelinfo dpi = { - .bits = (char*)&drawing_surface, - .width = 8, - .height = 8, - .x = 0, - .y = 0, - .pitch = 0, - .zoom_level = 0}; + maxWidth = max(maxWidth, gfx_get_string_width(firstCh)); - - for (int i = 0; i < 0xE0; ++i){ - memset(drawing_surface, 0, sizeof(drawing_surface)); - gfx_draw_sprite(&dpi, i + 0x10D5, -1, 0, 0); - - for (int x = 0; x < 8; ++x){ - uint8 val = 0; - for (int y = 0; y < 8; ++y){ - val >>= 1; - if (dpi.bits[x + y * 8]==1){ - val |= 0x80; - } - } - RCT2_ADDRESS(0xF4393C, uint8)[i * 8 + x] = val; - } - - } - - for (int i = 0; i < 0x20; ++i){ - rct_g1_element* g1 = &g1Elements[0x606 + i]; - uint8* unknown_pointer = RCT2_ADDRESS(0x9C3852, uint8) + 0xa12 * i; - g1->offset = unknown_pointer; - g1->width = 0x40; - g1->height = 0x28; - *((uint16*)unknown_pointer) = 0xFFFF; - *((uint32*)(unknown_pointer + 0x0E)) = 0; - } + return maxWidth; } - -/* rct2: 0x006C23B1 */ -int gfx_get_string_width_new_lined(char* buffer){ - // Current font sprites - uint16* current_font_sprite_base; - // Width of string - int width = 0, max_width = 0, no_lines = 1; - rct_g1_element g1_element; - - current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); - - for (uint8* curr_char = (uint8*)buffer; *curr_char != (uint8)0; curr_char++) { - - if (*curr_char >= 0x20) { - width += RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[*current_font_sprite_base + (*curr_char - 0x20)]; - continue; - } - switch (*curr_char) { - case FORMAT_MOVE_X: - curr_char++; - width = *curr_char; - break; - case FORMAT_ADJUST_PALETTE: - case 3: - case 4: - curr_char++; - break; - case FORMAT_NEWLINE: - case FORMAT_NEWLINE_SMALLER: - no_lines++; - max_width = max(max_width, width); - width = 0; - break; - case FORMAT_TINYFONT: - *current_font_sprite_base = 0x1C0; - break; - case FORMAT_BIGFONT: - *current_font_sprite_base = 0x2A0; - break; - case FORMAT_MEDIUMFONT: - *current_font_sprite_base = 0x0E0; - break; - case FORMAT_SMALLFONT: - *current_font_sprite_base = 0; - break; - case FORMAT_OUTLINE: - case FORMAT_OUTLINE_OFF: - case FORMAT_WINDOW_COLOUR_1: - case FORMAT_WINDOW_COLOUR_2: - case FORMAT_WINDOW_COLOUR_3: - case 0x10: - continue; - case FORMAT_INLINE_SPRITE: - g1_element = g1Elements[*((uint32*)(curr_char + 1)) & 0x7FFFF]; - width += g1_element.width; - curr_char += 4; - break; - default: - if (*curr_char <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y - curr_char += 2; - continue; - } - curr_char += 4;//never happens? - break; - } - } - - if (width > max_width) - return width; - return max_width; -} - - /** * Return the width of the string in buffer * @@ -166,68 +95,7 @@ int gfx_get_string_width_new_lined(char* buffer){ */ int gfx_get_string_width(char* buffer) { - // Current font sprites - uint16* current_font_sprite_base; - // Width of string - int width; - rct_g1_element g1_element; - - current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); - width = 0; - - for (uint8* curr_char = (uint8*)buffer; *curr_char != (uint8)0; curr_char++) { - - if (*curr_char >= 0x20) { - width += RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[*current_font_sprite_base + (*curr_char - 0x20)]; - continue; - } - switch(*curr_char) { - case FORMAT_MOVE_X: - curr_char++; - width = *curr_char; - break; - case FORMAT_ADJUST_PALETTE: - case 3: - case 4: - curr_char++; - break; - case FORMAT_NEWLINE: - case FORMAT_NEWLINE_SMALLER: - continue; - case FORMAT_TINYFONT: - *current_font_sprite_base = 0x1C0; - break; - case FORMAT_BIGFONT: - *current_font_sprite_base = 0x2A0; - break; - case FORMAT_MEDIUMFONT: - *current_font_sprite_base = 0x0E0; - break; - case FORMAT_SMALLFONT: - *current_font_sprite_base = 0; - break; - case FORMAT_OUTLINE: - case FORMAT_OUTLINE_OFF: - case FORMAT_WINDOW_COLOUR_1: - case FORMAT_WINDOW_COLOUR_2: - case FORMAT_WINDOW_COLOUR_3: - case 0x10: - continue; - case FORMAT_INLINE_SPRITE: - g1_element = g1Elements[*((uint32*)(curr_char + 1)) & 0x7FFFF]; - width += g1_element.width; - curr_char += 4; - break; - default: - if (*curr_char <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y - curr_char += 2; - continue; - } - curr_char += 4;//never happens? - break; - } - } - return width; + return ttf_get_string_width(buffer); } /** @@ -237,96 +105,51 @@ int gfx_get_string_width(char* buffer) * buffer (esi) * width (edi) */ -int gfx_clip_string(char* buffer, int width) +int gfx_clip_string(utf8 *text, int width) { - // Location of font sprites - uint16 current_font_sprite_base; - // Width the string has to fit into - unsigned int max_width; - // Character to change to ellipsis - unsigned char* last_char; - // Width of the string, including ellipsis - - unsigned int clipped_width; - - rct_g1_element g1_element; + int clippedWidth; if (width < 6) { - *buffer = 0; + *text = 0; return 0; } - - current_font_sprite_base = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); - max_width = width - (3 * RCT2_ADDRESS(0x141E9F6, uint8)[current_font_sprite_base]); - clipped_width = 0; - last_char = buffer; - - for (unsigned char* curr_char = buffer; *curr_char != (uint8)0; curr_char++) { - if (*curr_char < 0x20) { - switch (*curr_char) { - case FORMAT_MOVE_X: - curr_char++; - clipped_width = *curr_char; - continue; - case FORMAT_ADJUST_PALETTE: - case 3: - case 4: - curr_char++; - continue; - case FORMAT_NEWLINE: - case FORMAT_NEWLINE_SMALLER: - continue; - case FORMAT_TINYFONT: - current_font_sprite_base = 0x1C0; - break; - case FORMAT_BIGFONT: - current_font_sprite_base = 0x2A0; - break; - case FORMAT_MEDIUMFONT: - current_font_sprite_base = 0x0E0; - break; - case FORMAT_SMALLFONT: - current_font_sprite_base = 0; - break; - case FORMAT_OUTLINE: - case FORMAT_OUTLINE_OFF: - case FORMAT_WINDOW_COLOUR_1: - case FORMAT_WINDOW_COLOUR_2: - case FORMAT_WINDOW_COLOUR_3: - case 0x10: - continue; - case FORMAT_INLINE_SPRITE: - g1_element = g1Elements[*((uint32*)(curr_char + 1)) & 0x7FFFF]; - clipped_width += g1_element.width; - curr_char += 4; - continue; - default: - if (*curr_char <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y - curr_char += 2; - continue; - } - curr_char += 4;//never happens? - continue; - } - max_width = width - (3 * RCT2_ADDRESS(0x141E9F6, uint8)[current_font_sprite_base]); - } - - clipped_width += RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[current_font_sprite_base + (*curr_char - 0x20)]; - - if ((int)clipped_width > width) { -// *((uint32*)last_char) = '...'; - strcpy(last_char-3, "..."); - clipped_width = width; - return clipped_width; - } - if (clipped_width <= max_width) { - last_char = curr_char+1; - } + clippedWidth = gfx_get_string_width(text); + if (clippedWidth <= width) { + return clippedWidth; } - return clipped_width; -} + utf8 backup[4]; + utf8 *ch = text; + utf8 *nextCh = text; + utf8 *clipCh = text; + int codepoint; + while ((codepoint = utf8_get_next(ch, (const utf8**)&nextCh)) != 0) { + if (utf8_is_format_code(codepoint)) { + ch = nextCh; + ch += utf8_get_format_code_arg_length(codepoint); + continue; + } + + for (int i = 0; i < 4; i++) { backup[i] = nextCh[i]; }; + for (int i = 0; i < 3; i++) { nextCh[i] = '.'; } + nextCh[3] = 0; + + int queryWidth = gfx_get_string_width(text); + if (queryWidth < width) { + clipCh = nextCh; + clippedWidth = queryWidth; + } else { + for (int i = 0; i < 3; i++) { clipCh[i] = '.'; } + clipCh[3] = 0; + return clippedWidth; + } + + for (int i = 0; i < 4; i++) { nextCh[i] = backup[i]; }; + ch = nextCh; + } + return gfx_get_string_width(text); +} /** * Wrap the text in buffer to width, returns width of longest line. @@ -341,123 +164,76 @@ int gfx_clip_string(char* buffer, int width) * num_lines (edi) - out * font_height (ebx) - out */ -int gfx_wrap_string(char* buffer, int width, int* num_lines, int* font_height) +int gfx_wrap_string(utf8 *text, int width, int *outNumLines, int *outFontHeight) { - unsigned int line_width = 0; - unsigned int max_width = 0; - rct_g1_element g1_element; - - *num_lines = 0; - *font_height = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + int lineWidth = 0; + int maxWidth = 0; + *outNumLines = 0; // Pointer to the start of the current word - unsigned char* curr_word = NULL; + utf8 *currentWord = NULL; + // Width of line up to current word - unsigned int curr_width; + int currentWidth; - for (unsigned char* curr_char = buffer; *curr_char != (uint8)0; curr_char++) { - - // Remember start of current word and line width up to this word - if (*curr_char == ' ') { - curr_word = curr_char; - curr_width = line_width; - } - - // 5 is RCT2 new line? - if (*curr_char != 5) { - if (*curr_char < ' ') { - switch(*curr_char) { - case FORMAT_MOVE_X: - case FORMAT_ADJUST_PALETTE: - case 3: - case 4: - curr_char++; - continue; - case FORMAT_NEWLINE: - case FORMAT_NEWLINE_SMALLER: - continue; - case FORMAT_TINYFONT: - *font_height = 0x1C0; - continue; - case FORMAT_BIGFONT: - *font_height = 0x2A0; - continue; - case FORMAT_MEDIUMFONT: - *font_height = 0xE0; - continue; - case FORMAT_SMALLFONT: - *font_height = 0; - continue; - case FORMAT_OUTLINE: - case FORMAT_OUTLINE_OFF: - case FORMAT_WINDOW_COLOUR_1: - case FORMAT_WINDOW_COLOUR_2: - case FORMAT_WINDOW_COLOUR_3: - case 0x10: - continue; - case FORMAT_INLINE_SPRITE: - g1_element = g1Elements[*((uint32*)(curr_char + 1)) & 0x7FFFF]; - line_width += g1_element.width; - curr_char += 4; - break; - default: - if (*curr_char <= 0x16) { - curr_char += 2; - continue; - } - curr_char += 4; - continue; - } - } - - line_width += RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[*font_height + (*curr_char - 0x20)]; - - if ((int)line_width <= width) { - continue; - } - if (curr_word == 0) { - curr_char--; - unsigned char* old_char = curr_char; - unsigned char swap_char = 0; - unsigned char temp; - // Insert NULL at current character - // Aboslutely no guarantee that this won't overrun! - do { - temp = swap_char; - swap_char = *curr_char; - *curr_char = temp; - curr_char++; - } while(swap_char != 0); - - *curr_char = swap_char; - curr_char = old_char; - curr_char++; - *num_lines += 1; - - if (line_width > max_width) { - max_width = line_width; - } - line_width = 0; - curr_word = 0; - continue; - } - curr_char = curr_word; - line_width = curr_width; - } - - *num_lines += 1; - *curr_char = 0; - - if (line_width > max_width) { - max_width = line_width; + utf8 *ch = text; + utf8 *firstCh = text; + utf8 *nextCh; + int codepoint; + int numCharactersOnLine = 0; + while ((codepoint = utf8_get_next(ch, (const utf8**)&nextCh)) != 0) { + if (codepoint == ' ') { + currentWord = ch; + currentWidth = lineWidth; + numCharactersOnLine++; + } else if (codepoint == FORMAT_NEWLINE) { + *ch++ = 0; + maxWidth = max(maxWidth, lineWidth); + (*outNumLines)++; + lineWidth = 0; + currentWord = NULL; + firstCh = ch; + numCharactersOnLine = 0; + continue; + } else if (utf8_is_format_code(codepoint)) { + ch = nextCh; + ch += utf8_get_format_code_arg_length(codepoint); + continue; } - line_width = 0; - curr_word = 0; - } - if (max_width == 0)return line_width; - return max_width; -} + uint8 saveCh = *nextCh; + *nextCh = 0; + lineWidth = gfx_get_string_width(firstCh); + *nextCh = saveCh; + + if (lineWidth <= width || numCharactersOnLine == 0) { + ch = nextCh; + numCharactersOnLine++; + } else if (currentWord == NULL) { + // Single word is longer than line, insert null terminator + ch += utf8_insert_codepoint(ch, 0); + maxWidth = max(maxWidth, lineWidth); + (*outNumLines)++; + lineWidth = 0; + currentWord = NULL; + firstCh = ch; + numCharactersOnLine = 0; + } else { + ch = currentWord; + *ch++ = 0; + + maxWidth = max(maxWidth, currentWidth); + (*outNumLines)++; + lineWidth = 0; + currentWord = NULL; + firstCh = ch; + numCharactersOnLine = 0; + } + } + maxWidth = max(maxWidth, lineWidth); + *outFontHeight = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + return maxWidth == 0 ? lineWidth : maxWidth; +} /** * Draws i formatted text string left aligned at i specified position but clips @@ -501,7 +277,7 @@ void gfx_draw_string_left_clipped(rct_drawpixelinfo* dpi, int format, void* args void gfx_draw_string_centred_clipped(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y, int width) { char* buffer; - short text_width; + int text_width; buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); format_string(buffer, format, args); @@ -512,9 +288,11 @@ void gfx_draw_string_centred_clipped(rct_drawpixelinfo *dpi, int format, void *a text_width = gfx_clip_string(buffer, width); // Draw the text centred - if (text_width <= 0xFFFF) { + if (text_width <= 0xFFFF && text_width >= 0) { x -= (text_width - 1) / 2; gfx_draw_string(dpi, buffer, colour, x, y); + } else { + log_warning("improper text width %d for string %s", text_width, buffer); } } @@ -557,7 +335,7 @@ void gfx_draw_string_right(rct_drawpixelinfo* dpi, int format, void* args, int c void gfx_draw_string_centred(rct_drawpixelinfo *dpi, int format, int x, int y, int colour, void *args) { char* buffer; - short text_width; + int text_width; buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); format_string(buffer, format, args); @@ -568,14 +346,16 @@ void gfx_draw_string_centred(rct_drawpixelinfo *dpi, int format, int x, int y, i text_width = gfx_get_string_width(buffer); // Draw the text centred - if (text_width <= 0xFFFF) { + if (text_width <= 0xFFFF && text_width >= 0) { x -= text_width / 2; gfx_draw_string(dpi, buffer, colour, x, y); + } else { + log_warning("improper text width %d for string %s", text_width, buffer); } } /** - * + * * rct2: 0x006C1E53 * dpi (edi) * args (esi) @@ -606,17 +386,9 @@ int gfx_draw_string_centred_wrapped(rct_drawpixelinfo *dpi, void *args, int x, i // line_width unused here line_width = gfx_wrap_string(buffer, width, &num_lines, &font_height); + line_height = font_get_line_height(font_height); - line_height = 0x0A; - - if (font_height > 0xE0) { - line_height = 6; - if (font_height != 0x1C0) { - line_height = 0x12; - } - } - - if (*buffer == 0x0B) { + if (*buffer == FORMAT_OUTLINE) { line_height = line_height + 1; } @@ -629,15 +401,15 @@ int gfx_draw_string_centred_wrapped(rct_drawpixelinfo *dpi, void *args, int x, i int half_width = gfx_get_string_width(buffer) / 2; gfx_draw_string(dpi, buffer, 0xFE, x - half_width, line_y); - buffer += get_string_length(buffer) + 1; - line_y += line_height; + buffer = get_string_end(buffer) + 1; + line_y += line_height; } return line_y - y; } /** - * + * * rct2: 0x006C2105 * dpi (edi) * args (esi) @@ -650,45 +422,29 @@ int gfx_draw_string_centred_wrapped(rct_drawpixelinfo *dpi, void *args, int x, i int gfx_draw_string_left_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int y, int width, int format, int colour) { // font height might actually be something else - int font_height, line_height, line_width, line_y, num_lines; + int fontSpriteBase, lineHeight, lineY, numLines; // Location of font sprites uint16* current_font_sprite_base = RCT2_ADDRESS(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); - *current_font_sprite_base = 0xE0; + *current_font_sprite_base = FONT_SPRITE_BASE_MEDIUM; char* buffer = RCT2_ADDRESS(0x009C383D, char); - gfx_draw_string(dpi, buffer, colour, dpi->x, dpi->y); - buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); - format_string(buffer, format, args); - *current_font_sprite_base = 0xE0; - - // Line width unused here - line_width = gfx_wrap_string(buffer, width, &num_lines, &font_height); - - line_height = 0x0A; - - if (font_height > 0xE0) { - line_height = 6; - if (font_height != 0x1C0) { - line_height = 0x12; - } - } + *current_font_sprite_base = FONT_SPRITE_BASE_MEDIUM; + gfx_wrap_string(buffer, width, &numLines, &fontSpriteBase); + lineHeight = font_get_line_height(fontSpriteBase); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; - - line_y = y; - - for (int line = 0; line <= num_lines; ++line) { - gfx_draw_string(dpi, buffer, 0xFE, x, line_y); - buffer += get_string_length(buffer) + 1; - line_y += line_height; - } - - return line_y - y; + lineY = y; + for (int line = 0; line <= numLines; ++line) { + gfx_draw_string(dpi, buffer, 0xFE, x, lineY); + buffer = get_string_end(buffer) + 1; + lineY += lineHeight; + } + return lineY - y; } /** @@ -707,10 +463,24 @@ void gfx_draw_string_left(rct_drawpixelinfo *dpi, int format, void *args, int co buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); format_string(buffer, format, args); - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0xE0; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; gfx_draw_string(dpi, buffer, colour, x, y); } +/** + * Draws text that is left aligned and vertically centred. + */ +void gfx_draw_string_left_centred(rct_drawpixelinfo *dpi, rct_string_id format, void *args, int colour, int x, int y) +{ + char* buffer; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + buffer = (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER; + format_string(buffer, format, args); + int height = string_get_height_raw(buffer); + gfx_draw_string(dpi, buffer, colour, x, y - (height / 2)); +} + /** * Changes the palette so that the next character changes colour */ @@ -724,7 +494,7 @@ void colour_char(uint8 colour, uint16* current_font_flags, uint8* palette_pointe if (!(*current_font_flags & 2)) { eax = eax & 0x0FF0000FF; } - // Adjust text palette. Store current colour? + // Adjust text palette. Store current colour? palette_pointer[1] = eax & 0xFF; palette_pointer[2] = (eax >> 8) & 0xFF; palette_pointer[3] = (eax >> 16) & 0xFF; @@ -740,11 +510,11 @@ void colour_char_window(uint8 colour, uint16* current_font_flags,uint8* palette_ int eax; - eax = RCT2_ADDRESS(0x0141FD45, uint8)[colour * 8]; + eax = ColourMapB[colour].b; if (*current_font_flags & 2) { eax |= 0x0A0A00; } - //Adjust text palette. Store current colour? + //Adjust text palette. Store current colour? palette_pointer[1] = eax & 0xFF; palette_pointer[2] = (eax >> 8) & 0xFF; palette_pointer[3] = (eax >> 16) & 0xFF; @@ -752,9 +522,8 @@ void colour_char_window(uint8 colour, uint16* current_font_flags,uint8* palette_ RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)palette_pointer; } - /** - * + * * rct2: 0x00682702 * dpi (edi) * buffer (esi) @@ -764,294 +533,7 @@ void colour_char_window(uint8 colour, uint16* current_font_flags,uint8* palette_ */ void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, int y) { - - int eax, ebx, ebp; - rct_g1_element* g1_element; - - // Maximum length/height of string - int max_x = x; - int max_y = y; - - // - 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; - - // Flag for skipping non-printing characters - int skip_char = 0; - - if (colour != 0xFE) { - - if (x >= dpi->x + dpi->width) - return; - - if (x + 0x280 <= dpi->x) - return; - - if (y >= dpi->y + dpi->height) - return; - - if (y + 0x5A <= dpi->y) { - return; - } - - if (colour != 0xFF) { - - // switch_colour: - *current_font_flags = 0; - if (*current_font_sprite_base < 0) { - *current_font_flags |= 4; - if (*current_font_sprite_base != -1) { - *current_font_flags |= 8; - } - *current_font_sprite_base = 224; - } - if (colour & (1 << 5)) { - *current_font_flags |= 2; - } - colour &= ~(1 << 5); - - if (!(colour & 0x40)) { - ebp = colour; - if (*current_font_flags & 1) { - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } else { - skip_char = 0; - } - } else { - colour_char_window(ebp, current_font_flags, palette_pointer); - } - } else { - *current_font_flags |= 1; - colour &= 0x1F; - - if (*current_font_flags & 4) { - if (*current_font_flags & 8) { - eax = RCT2_ADDRESS(0x0141FC48, uint8)[colour * 8]; - eax = eax << 16; - eax = eax | RCT2_ADDRESS(0x0141FC46, uint8)[colour * 8]; - } else { - eax = RCT2_ADDRESS(0x0141FC49, uint8)[colour * 8]; - eax = eax << 16; - eax = eax | RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]; - } - } else { - eax = RCT2_ADDRESS(0x0141FC4A, uint8)[colour * 8]; - eax = eax << 16; - eax = eax | RCT2_ADDRESS(0x0141FC48, uint8)[colour * 8]; - } - // Adjust text palette. Store current colour? ; - palette_pointer[1] = eax & 0xFF; - palette_pointer[2] = (eax >> 8) & 0xFF; - palette_pointer[3] = (eax >> 16) & 0xFF; - palette_pointer[4] = (eax >> 24) & 0xFF; - RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)palette_pointer; - eax = 0; - } - } - } - - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } - - for (uint8 al = *buffer; al > 0; ++buffer, al = *buffer) { - - // Skip to the next printing character - if (skip_char) { - if (al < 0x20) { - // Control codes - skip_char = 0; - } else if (al >= FORMAT_COLOUR_CODE_START && al <= FORMAT_COLOUR_CODE_END) { - // Colour codes - if (*current_font_flags == 1) { - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } else { - skip_char = 0; - } - continue; - } - colour_char(al - FORMAT_COLOUR_CODE_START, current_font_flags, palette_pointer); - continue; - } else { - continue; - } - } - - // Control codes - switch (al) { - case FORMAT_MOVE_X://Start New Line at start+buffer x, same y. (Overwrite?) - max_x = x + (uint8)*++buffer; - break; - case FORMAT_ADJUST_PALETTE: - al = *++buffer; - if (*current_font_flags & 1) { - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - break; - } - } - - eax = palette_to_g1_offset[al]; //RCT2_ADDRESS(0x097FCBC, uint32)[al * 4]; - g1_element = &g1Elements[eax]; - ebx = g1_element->offset[0xF9] + (1 << 8); - if (!(*current_font_flags & 2)) { - ebx = ebx & 0xFF; - } - - palette_pointer[1] = ebx & 0xff; - palette_pointer[2] = (ebx >> 8) & 0xff; - //Adjust the text palette - memcpy(palette_pointer + 3, &(g1_element->offset[0xF7]), 2); - memcpy(palette_pointer + 5, &(g1_element->offset[0xFA]), 2); - //Set the palette pointer - RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)palette_pointer; - - - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } - break; - case FORMAT_NEWLINE://Start New Line at set y lower - max_x = x; - if (*current_font_sprite_base <= 224) { - max_y += 10; - break; - } - else if (*current_font_sprite_base == 448) { - max_y += 6; - break; - } - max_y += 18; - break; - case FORMAT_NEWLINE_SMALLER://Start New Line at set y lower - max_x = x; - if (*current_font_sprite_base <= 224) { - max_y += 5; - break; - } - else if (*current_font_sprite_base == 448) { - max_y += 3; - break; - } - max_y += 9; - break; - case FORMAT_TINYFONT: - *current_font_sprite_base = 448; - break; - case FORMAT_BIGFONT: - *current_font_sprite_base = 672; - break; - case FORMAT_MEDIUMFONT: - *current_font_sprite_base = 224; - break; - case FORMAT_SMALLFONT: - *current_font_sprite_base = 0; - break; - case FORMAT_OUTLINE: - *current_font_flags |= 2; - break; - case FORMAT_OUTLINE_OFF: - *current_font_flags &= 0x0FFFD; - break; - case FORMAT_WINDOW_COLOUR_1: - ebp = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_1, uint8); - if (*current_font_flags & 1) { - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } - else { - skip_char = 0; - } - break; - } - colour_char_window(ebp, current_font_flags, palette_pointer); - break; - case FORMAT_WINDOW_COLOUR_2: - ebp = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_2, uint8); - if (*current_font_flags & 1) { - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } - else { - skip_char = 0; - } - break; - } - colour_char_window(ebp, current_font_flags, palette_pointer); - break; - case FORMAT_WINDOW_COLOUR_3: - ebp = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_3, uint8); - if (*current_font_flags & 1) { - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } - else { - skip_char = 0; - } - break; - } - colour_char_window(ebp, current_font_flags, palette_pointer); - break; - case FORMAT_NEWLINE_X_Y: //Start new line at specified x,y - max_x = x + *++buffer; - max_y = y + *++buffer; - break; - case FORMAT_INLINE_SPRITE: - buffer += 4; - if (max_x >= dpi->x + dpi->width) { - skip_char = 1; - break; - } - uint32 image_id = *((uint32*)(buffer - 3)); - uint32 image_offset = image_id & 0x7FFFF; - g1_element = &g1Elements[image_offset]; - - gfx_draw_sprite(dpi, image_id, max_x, max_y, 0); - - max_x = max_x + g1_element->width; - break; - default: - // Colour codes - if ((al >= FORMAT_COLOUR_CODE_START) && (al <= FORMAT_COLOUR_CODE_END)){ - - if (*current_font_flags == 1) { - if ((y + 0x13 <= dpi->y) || (dpi->y + dpi->height <= y)) { - skip_char = 1; - } else { - skip_char = 0; - } - continue; - } - colour_char(al - FORMAT_COLOUR_CODE_START, current_font_flags, palette_pointer); - continue; - } - - // Normal Characters - if (max_x >= dpi->x + dpi->width) { - skip_char = 1; - } - if (max_x + 0x1A < dpi->x) { - ebx = al-0x20; - ebx += *current_font_sprite_base; - max_x = max_x + (RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[ebx] & 0xFF); - continue; - } - - 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); - max_x += (RCT2_ADDRESS(RCT2_ADDRESS_FONT_CHAR_WIDTH, uint8)[char_offset] & 0xFF); - continue; - } - } - - gLastDrawStringX = max_x; - gLastDrawStringY = max_y; + ttf_draw_string(dpi, buffer, colour, x, y); } void draw_string_left_underline(rct_drawpixelinfo *dpi, int format, void *args, int colour, int x, int y) @@ -1131,14 +613,742 @@ void draw_string_centred_raw(rct_drawpixelinfo *dpi, int x, int y, int numLines, 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; + y += font_get_line_height(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16)); } -} \ No newline at end of file +} + +int string_get_height_raw(char *buffer) +{ + uint16 fontBase = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + + int height = 0; + if (fontBase <= 224) + height += 10; + else if (fontBase == 448) + height += 6; + + char *ch = buffer; + while (*ch != 0) { + char c = *ch++; + switch (c) { + case FORMAT_NEWLINE: + if (fontBase <= 224) { + height += 10; + break; + } else if (fontBase == 448) { + height += 6; + break; + } + height += 18; + break; + case FORMAT_NEWLINE_SMALLER: + if (fontBase <= 224) { + height += 5; + break; + } else if (fontBase == 448) { + height += 3; + break; + } + height += 9; + break; + case FORMAT_TINYFONT: + fontBase = 448; + break; + case FORMAT_BIGFONT: + fontBase = 672; + break; + case FORMAT_MEDIUMFONT: + fontBase = 224; + break; + case FORMAT_SMALLFONT: + fontBase = 0; + break; + default: + if (c >= 32) continue; + if (c <= 4) { + ch++; + continue; + } + if (c <= 16) continue; + ch += 2; + if (c <= 22) continue; + ch += 2; + break; + } + } + + return height; +} + +/** + * + * rct2: 0x006C1F57 + * + * colour : al + * format : bx + * x : cx + * y : dx + * text : esi + * dpi : edi + * width : bp + * ticks : ebp >> 16 + */ +void gfx_draw_string_centred_wrapped_partial(rct_drawpixelinfo *dpi, int x, int y, int width, int colour, rct_string_id format, void *args, int ticks) +{ + int numLines, fontSpriteBase, lineHeight, lineY; + utf8 *buffer = (utf8*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = FONT_SPRITE_BASE_MEDIUM; + gfx_draw_string(dpi, (char*)0x009C383D, colour, dpi->x, dpi->y); + format_string(buffer, format, args); + + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = FONT_SPRITE_BASE_MEDIUM; + gfx_wrap_string(buffer, width, &numLines, &fontSpriteBase); + lineHeight = font_get_line_height(fontSpriteBase); + + int numCharactersDrawn = 0; + int numCharactersToDraw = ticks; + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; + lineY = y - ((numLines * lineHeight) / 2); + for (int line = 0; line <= numLines; line++) { + int halfWidth = gfx_get_string_width(buffer) / 2; + + utf8 *ch = buffer; + utf8 *nextCh; + int codepoint; + while ((codepoint = utf8_get_next(ch, (const utf8**)&nextCh)) != 0) { + if (!utf8_is_format_code(codepoint)) { + numCharactersDrawn++; + if (numCharactersDrawn > numCharactersToDraw) { + *ch = 0; + break; + } + } + ch = nextCh; + } + + gfx_draw_string(dpi, buffer, 0xFE, x - halfWidth, lineY); + + if (numCharactersDrawn > numCharactersToDraw) { + break; + } + + buffer = get_string_end(buffer) + 1; + lineY += lineHeight; + } +} + +static uint32 _ttf_surface_cache_hash(TTF_Font *font, const utf8 *text) +{ + uint32 hash = ((uint32)font * 23) ^ 0xAAAAAAAA; + for (const utf8 *ch = text; *ch != 0; ch++) { + hash = ror32(hash, 3) ^ (*ch * 13); + } + return hash; +} + +static void _ttf_surface_cache_dispose(ttf_cache_entry *entry) +{ + if (entry->surface != NULL) { + SDL_FreeSurface(entry->surface); + free(entry->text); + + entry->surface = NULL; + entry->font = NULL; + entry->text = NULL; + } +} + +static void _ttf_surface_cache_dispose_all() +{ + for (int i = 0; i < TTF_SURFACE_CACHE_SIZE; i++) { + _ttf_surface_cache_dispose(&_ttfSurfaceCache[i]); + _ttfSurfaceCacheCount--; + } +} + +SDL_Surface *_ttf_surface_cache_get_or_add(TTF_Font *font, const utf8 *text) +{ + ttf_cache_entry *entry; + + uint32 hash = _ttf_surface_cache_hash(font, text); + int index = hash % TTF_SURFACE_CACHE_SIZE; + for (int i = 0; i < TTF_SURFACE_CACHE_SIZE; i++) { + entry = &_ttfSurfaceCache[index]; + + // Check if entry is a hit + if (entry->surface == NULL) break; + if (entry->font == font && strcmp(entry->text, text) == 0) { + _ttfSurfaceCacheHitCount++; + entry->lastUseTick = gCurrentDrawCount; + return entry->surface; + } + + // If entry hasn't been used for a while, replace it + if (entry->lastUseTick < gCurrentDrawCount - 64) { + break; + } + + // Check if next entry is a hit + if (++index >= TTF_SURFACE_CACHE_SIZE) index = 0; + } + + // Cache miss, replace entry with new surface + entry = &_ttfSurfaceCache[index]; + _ttf_surface_cache_dispose(entry); + + SDL_Color c = { 0, 0, 0, 255 }; + SDL_Surface *surface = TTF_RenderUTF8_Solid(font, text, c); + if (surface == NULL) { + return NULL; + } + + _ttfSurfaceCacheMissCount++; + // printf("CACHE HITS: %d MISSES: %d)\n", _ttfSurfaceCacheHitCount, _ttfSurfaceCacheMissCount); + + _ttfSurfaceCacheCount++; + entry->surface = surface; + entry->font = font; + entry->text = _strdup(text); + entry->lastUseTick = gCurrentDrawCount; + return entry->surface; +} + +static void _ttf_getwidth_cache_dispose(ttf_getwidth_cache_entry *entry) +{ + if (entry->text != NULL) { + free(entry->text); + + entry->width = 0; + entry->font = NULL; + entry->text = NULL; + } +} + +static void _ttf_getwidth_cache_dispose_all() +{ + for (int i = 0; i < TTF_GETWIDTH_CACHE_SIZE; i++) { + _ttf_getwidth_cache_dispose(&_ttfGetWidthCache[i]); + _ttfGetWidthCacheCount--; + } +} + +static uint32 _ttf_getwidth_cache_get_or_add(TTF_Font *font, const utf8 *text) +{ + ttf_getwidth_cache_entry *entry; + + uint32 hash = _ttf_surface_cache_hash(font, text); + int index = hash % TTF_GETWIDTH_CACHE_SIZE; + for (int i = 0; i < TTF_GETWIDTH_CACHE_SIZE; i++) { + entry = &_ttfGetWidthCache[index]; + + // Check if entry is a hit + if (entry->text == NULL) break; + if (entry->font == font && strcmp(entry->text, text) == 0) { + _ttfGetWidthCacheHitCount++; + entry->lastUseTick = gCurrentDrawCount; + return entry->width; + } + + // If entry hasn't been used for a while, replace it + if (entry->lastUseTick < gCurrentDrawCount - 64) { + break; + } + + // Check if next entry is a hit + if (++index >= TTF_GETWIDTH_CACHE_SIZE) index = 0; + } + + // Cache miss, replace entry with new width + entry = &_ttfGetWidthCache[index]; + _ttf_getwidth_cache_dispose(entry); + + int width, height; + TTF_SizeUTF8(font, text, &width, &height); + + _ttfGetWidthCacheMissCount++; + + _ttfGetWidthCacheCount++; + entry->width = width; + entry->font = font; + entry->text = _strdup(text); + entry->lastUseTick = gCurrentDrawCount; + return entry->width; +} + +bool ttf_initialise() +{ + if (!_ttfInitialised) { + if (TTF_Init() != 0) { + return false; + } + + for (int i = 0; i < 4; i++) { + TTFFontDescriptor *fontDesc = &(gCurrentTTFFontSet->size[i]); + + utf8 fontPath[MAX_PATH] = "C:\\Windows\\Fonts\\"; + strcat(fontPath, fontDesc->filename); + + fontDesc->font = TTF_OpenFont(fontPath, fontDesc->ptSize); + if (fontDesc->font == NULL) { + log_error("Unable to load '%s'", fontPath); + return false; + } + } + + _ttfInitialised = true; + } + return true; +} + +void ttf_dispose() +{ + if (!_ttfInitialised) + return; + + _ttf_surface_cache_dispose_all(); + _ttf_getwidth_cache_dispose_all(); + + for (int i = 0; i < 4; i++) { + TTFFontDescriptor *fontDesc = &(gCurrentTTFFontSet->size[i]); + if (fontDesc->font != NULL) { + TTF_CloseFont(fontDesc->font); + fontDesc->font = NULL; + } + } + + TTF_Quit(); + _ttfInitialised = false; +} + +TTFFontDescriptor *ttf_get_font_from_sprite_base(uint16 spriteBase) +{ + return &gCurrentTTFFontSet->size[font_get_size_from_sprite_base(spriteBase)]; +} + +enum { + TEXT_DRAW_FLAG_INSET = 1 << 0, + TEXT_DRAW_FLAG_OUTLINE = 1 << 1, + TEXT_DRAW_FLAG_Y_OFFSET_EFFECT = 1 << 29, + TEXT_DRAW_FLAG_TTF = 1 << 30, + TEXT_DRAW_FLAG_NO_DRAW = 1 << 31 +}; + +typedef struct { + int startX; + int startY; + int x; + int y; + int maxX; + int maxY; + int flags; + uint8 palette[8]; + uint16 font_sprite_base; + const sint8 *y_offset; +} text_draw_info; + +static void ttf_draw_character_sprite(rct_drawpixelinfo *dpi, int codepoint, text_draw_info *info) +{ + int characterWidth = font_sprite_get_codepoint_width(info->font_sprite_base, codepoint); + int sprite = font_sprite_get_codepoint_sprite(info->font_sprite_base, codepoint); + + if (!(info->flags & TEXT_DRAW_FLAG_NO_DRAW)) { + RCT2_GLOBAL(0x009ABDA4, uint8*) = (uint8*)&info->palette; + RCT2_GLOBAL(0x00EDF81C, uint32) = (IMAGE_TYPE_USE_PALETTE << 28); + + int x = info->x; + int y = info->y; + if (info->flags & TEXT_DRAW_FLAG_Y_OFFSET_EFFECT) { + y += *info->y_offset++; + } + gfx_draw_sprite_palette_set(dpi, sprite, x, y, info->palette, NULL); + } + + info->x += characterWidth; +} + +static void ttf_draw_string_raw_sprite(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) +{ + const utf8 *ch = text; + int codepoint; + + while (!utf8_is_format_code(codepoint = utf8_get_next(ch, &ch))) { + ttf_draw_character_sprite(dpi, codepoint, info); + }; +} + +static void ttf_draw_string_raw_ttf(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) +{ + if (!_ttfInitialised && !ttf_initialise()) + return; + + TTFFontDescriptor *fontDesc = ttf_get_font_from_sprite_base(info->font_sprite_base); + if (fontDesc->font == NULL) { + ttf_draw_string_raw_sprite(dpi, text, info); + return; + } + + if (info->flags & TEXT_DRAW_FLAG_NO_DRAW) { + info->x += _ttf_getwidth_cache_get_or_add(fontDesc->font, text); + return; + } else { + uint8 colour = info->palette[1]; + SDL_Surface *surface = _ttf_surface_cache_get_or_add(fontDesc->font, text); + if (surface == NULL) + return; + + if (SDL_MUSTLOCK(surface)) { + if (SDL_LockSurface(surface) != 0) { + return; + } + } + + int fontSize = font_get_size_from_sprite_base(info->font_sprite_base); + int drawX = info->x + fontDesc->offset_x; + int drawY = info->y + fontDesc->offset_y; + int width = surface->w; + int height = surface->h; + + int overflowX = (dpi->x + dpi->width) - (drawX + width); + int overflowY = (dpi->y + dpi->height) - (drawY + height); + if (overflowX < 0) width += overflowX; + if (overflowY < 0) height += overflowY; + int skipX = drawX - dpi->x; + int skipY = drawY - dpi->y; + info->x += width; + + uint8 *src = surface->pixels; + uint8 *dst = dpi->bits; + + if (skipX < 0) { + width += skipX; + src += -skipX; + skipX = 0; + } + if (skipY < 0) { + height += skipY; + src += (-skipY * surface->pitch); + skipY = 0; + } + + dst += skipX; + dst += skipY * (dpi->width + dpi->pitch); + + int srcScanSkip = surface->pitch - width; + int dstScanSkip = dpi->width + dpi->pitch - width; + for (int yy = 0; yy < height; yy++) { + for (int xx = 0; xx < width; xx++) { + if (*src != 0) { + *dst = colour; + if (info->flags & TEXT_DRAW_FLAG_INSET) { + *(dst + width + dstScanSkip + 1) = info->palette[3]; + } else if (info->flags & TEXT_DRAW_FLAG_OUTLINE) { + *(dst + width + dstScanSkip + 1) = info->palette[3]; + } + } + src++; + dst++; + } + src += srcScanSkip; + dst += dstScanSkip; + } + + if (SDL_MUSTLOCK(surface)) { + SDL_UnlockSurface(surface); + } + } +} + +static void ttf_draw_string_raw(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) +{ + if (info->flags & TEXT_DRAW_FLAG_TTF) { + ttf_draw_string_raw_ttf(dpi, text, info); + } else { + ttf_draw_string_raw_sprite(dpi, text, info); + } +} + +static const utf8 *ttf_process_format_code(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) +{ + const utf8 *nextCh; + int codepoint; + + codepoint = utf8_get_next(text, &nextCh); + switch (codepoint) { + case FORMAT_MOVE_X: + info->x = info->startX + (uint8)(*nextCh++); + break; + case FORMAT_ADJUST_PALETTE: + { + uint16 eax = palette_to_g1_offset[*nextCh++]; + rct_g1_element *g1Element = &g1Elements[eax]; + uint32 ebx = g1Element->offset[249] + 256; + if (!(info->flags & TEXT_DRAW_FLAG_OUTLINE)) { + ebx = ebx & 0xFF; + } + info->palette[1] = ebx & 0xFF; + info->palette[2] = (ebx >> 8) & 0xFF; + + // Adjust the text palette + memcpy(info->palette + 3, &(g1Element->offset[247]), 2); + memcpy(info->palette + 5, &(g1Element->offset[250]), 2); + + // Set the palette pointer + RCT2_GLOBAL(0x009ABDA4, uint32) = (uint32)&info->palette; + break; + } + case 3: + case 4: + nextCh++; + break; + case FORMAT_NEWLINE: + info->x = info->startX; + info->y += font_get_line_height(info->font_sprite_base); + break; + case FORMAT_NEWLINE_SMALLER: + info->x = info->startX; + info->y += font_get_line_height_small(info->font_sprite_base); + break; + case FORMAT_TINYFONT: + info->font_sprite_base = 448; + break; + case FORMAT_SMALLFONT: + info->font_sprite_base = 0; + break; + case FORMAT_MEDIUMFONT: + info->font_sprite_base = 224; + break; + case FORMAT_BIGFONT: + info->font_sprite_base = 672; + break; + case FORMAT_OUTLINE: + info->flags |= TEXT_DRAW_FLAG_OUTLINE; + break; + case FORMAT_OUTLINE_OFF: + info->flags &= ~TEXT_DRAW_FLAG_OUTLINE; + break; + case FORMAT_WINDOW_COLOUR_1: + { + uint16 flags = info->flags; + colour_char_window(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_1, uint8), &flags, info->palette); + break; + } + case FORMAT_WINDOW_COLOUR_2: + { + uint16 flags = info->flags; + colour_char_window(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_2, uint8), &flags, info->palette); + break; + } + case FORMAT_WINDOW_COLOUR_3: + { + uint16 flags = info->flags; + colour_char_window(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WINDOW_COLOUR_3, uint8), &flags, info->palette); + break; + } + case 0x10: + break; + case FORMAT_INLINE_SPRITE: + { + uint32 imageId = *((uint32*)(nextCh)); + rct_g1_element *g1Element = &g1Elements[imageId & 0x7FFFF]; + if (!(info->flags & TEXT_DRAW_FLAG_NO_DRAW)) { + gfx_draw_sprite(dpi, imageId, info->x, info->y, 0); + } + info->x += g1Element->width; + nextCh += 4; + break; + } + default: + if (codepoint >= FORMAT_COLOUR_CODE_START && codepoint <= FORMAT_COLOUR_CODE_END) { + uint16 flags = info->flags; + colour_char(codepoint - FORMAT_COLOUR_CODE_START, &flags, info->palette); + } else if (codepoint <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y + nextCh += 2; + } else { + nextCh += 4;//never happens? + } + break; + } + return nextCh; +} + +static const utf8 *ttf_process_glyph_run(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) +{ + utf8 buffer[512]; + const utf8 *ch = text; + const utf8 *lastCh; + int codepoint; + + bool isTTF = info->flags & TEXT_DRAW_FLAG_TTF; + while (!utf8_is_format_code(codepoint = utf8_get_next(ch, &lastCh))) { + if (isTTF && utf8_should_use_sprite_for_codepoint(codepoint)) { + break; + } + ch = lastCh; + } + if (codepoint == 0) { + ttf_draw_string_raw(dpi, text, info); + return ch; + } else { + int length = ch - text; + memcpy(buffer, text, length); + buffer[length] = 0; + ttf_draw_string_raw(dpi, buffer, info); + return ch; + } +} + +static void ttf_process_string(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) +{ + const utf8 *ch = text; + const utf8 *nextCh; + int codepoint; + + bool isTTF = info->flags & TEXT_DRAW_FLAG_TTF; + + while ((codepoint = utf8_get_next(ch, &nextCh)) != 0) { + if (utf8_is_format_code(codepoint)) { + ch = ttf_process_format_code(dpi, ch, info); + } else if (isTTF && utf8_should_use_sprite_for_codepoint(codepoint)) { + ttf_draw_character_sprite(dpi, codepoint, info); + ch = nextCh; + } else { + ch = ttf_process_glyph_run(dpi, ch, info); + } + info->maxX = max(info->maxX, info->x); + info->maxY = max(info->maxY, info->y); + } +} + +static void ttf_process_initial_colour(int colour, text_draw_info *info) +{ + if (colour != 254 && colour != 255) { + info->flags &= ~(1 | 2 | 4 | 8); + if ((sint16)info->font_sprite_base < 0) { + info->flags |= 4; + if ((sint16)info->font_sprite_base != -1) { + info->flags |= 8; + } + info->font_sprite_base = 224; + } + if (colour & (1 << 5)) { + info->flags |= TEXT_DRAW_FLAG_OUTLINE; + } + colour &= ~(1 << 5); + if (!(colour & (1 << 6))) { + if (!(info->flags & 1)) { + uint16 flags = info->flags; + colour_char_window(colour, &flags, (uint8*)&info->palette); + } + } else { + info->flags |= 1; + colour &= 0x1F; + + uint32 eax; + if (info->flags & 4) { + if (info->flags & 8) { + eax = ColourMapA[colour].mid_light; + eax = eax << 16; + eax = eax | ColourMapA[colour].dark; + } else { + eax = ColourMapA[colour].light; + eax = eax << 16; + eax = eax | ColourMapA[colour].mid_dark; + } + } else { + eax = ColourMapA[colour].lighter; + eax = eax << 16; + eax = eax | ColourMapA[colour].mid_light; + } + + // Adjust text palette. Store current colour? ; + info->palette[1] = eax & 0xFF; + info->palette[2] = (eax >> 8) & 0xFF; + info->palette[3] = (eax >> 16) & 0xFF; + info->palette[4] = (eax >> 24) & 0xFF; + RCT2_GLOBAL(0x009ABDA4, uint8*) = (uint8*)&info->palette; + eax = 0; + } + } +} + +static void ttf_draw_string(rct_drawpixelinfo *dpi, char *text, int colour, int x, int y) +{ + if (text == NULL) return; + + text_draw_info info; + info.font_sprite_base = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + info.flags = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16); + info.startX = x; + info.startY = x; + info.x = x; + info.y = y; + + if (gUseTrueTypeFont) info.flags |= TEXT_DRAW_FLAG_TTF; + + memcpy(info.palette, text_palette, sizeof(info.palette)); + ttf_process_initial_colour(colour, &info); + ttf_process_string(dpi, text, &info); + memcpy(text_palette, info.palette, sizeof(info.palette)); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = info.font_sprite_base; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = info.flags; + + gLastDrawStringX = info.x; + gLastDrawStringY = info.y; +} + +static int ttf_get_string_width(const utf8 *text) +{ + text_draw_info info; + info.font_sprite_base = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + info.flags = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16); + info.startX = 0; + info.startY = 0; + info.x = 0; + info.y = 0; + info.maxX = 0; + info.maxY = 0; + + info.flags |= TEXT_DRAW_FLAG_NO_DRAW; + if (gUseTrueTypeFont) info.flags |= TEXT_DRAW_FLAG_TTF; + + ttf_process_string(NULL, text, &info); + + return info.maxX; +} + +/** + * + * rct2: 0x00682F28 + */ +void gfx_draw_string_with_y_offsets(rct_drawpixelinfo *dpi, const utf8 *text, int colour, int x, int y, const sint8 *yOffsets, bool forceSpriteFont) +{ + text_draw_info info; + info.font_sprite_base = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16); + info.flags = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16); + info.startX = x; + info.startY = x; + info.x = x; + info.y = y; + info.y_offset = yOffsets; + + info.flags |= TEXT_DRAW_FLAG_Y_OFFSET_EFFECT; + + if (!forceSpriteFont && gUseTrueTypeFont) { + info.flags |= TEXT_DRAW_FLAG_TTF; + } + + memcpy(info.palette, text_palette, sizeof(info.palette)); + ttf_process_initial_colour(colour, &info); + ttf_process_string(dpi, text, &info); + memcpy(text_palette, info.palette, sizeof(info.palette)); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = info.font_sprite_base; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = info.flags; + + gLastDrawStringX = info.x; + gLastDrawStringY = info.y; +} diff --git a/src/editor.c b/src/editor.c index 58e25e0cbf..7b566001ca 100644 --- a/src/editor.c +++ b/src/editor.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 . *****************************************************************************/ @@ -39,11 +39,13 @@ #include "util/util.h" #include "world/banner.h" #include "world/climate.h" +#include "world/footpath.h" #include "world/map.h" #include "world/park.h" #include "world/scenery.h" #include "world/sprite.h" +void editor_convert_save_to_scenario_callback(int result); 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); @@ -58,8 +60,8 @@ void editor_load() { rct_window *mainWindow; - pause_sounds(); - unpause_sounds(); + audio_pause_sounds(); + audio_unpause_sounds(); object_unload_all(); map_init(150); banner_init(); @@ -68,7 +70,7 @@ void editor_load() reset_sprite_list(); ride_init_all(); window_guest_list_init_vars_a(); - sub_6BD3A4(); + staff_reset_modes(); park_init(); finance_init(); date_reset(); @@ -87,33 +89,9 @@ void editor_load() mainWindow->flags &= ~WF_SCROLLING_TO_LOCATION; load_palette(); gfx_invalidate_screen(); - RCT2_GLOBAL(0x009DEA66, sint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, sint16) = 0; - strcpy((char*)RCT2_ADDRESS_SCENARIO_NAME, language_get_string(2749)); -} - -/** - * - * rct2: 0x0067505F - */ -static int show_convert_saved_game_to_scenario_dialog(char *resultPath) -{ - int result; - char title[256]; - char filename[MAX_PATH]; - char filterName[256]; - - format_string(title, STR_CONVERT_SAVED_GAME_TO_SCENARIO_1038, NULL); - strcpy(filename, RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH, char)); - format_string(filterName, STR_RCT2_SAVED_GAME, NULL); - - pause_sounds(); - result = platform_open_common_file_dialog(1, title, filename, "*.SV6", filterName); - unpause_sounds(); - - if (result) - strcpy(resultPath, filename); - return result; + safe_strncpy((char*)RCT2_ADDRESS_SCENARIO_NAME, language_get_string(2749), 0x40); } /** @@ -122,18 +100,18 @@ static int show_convert_saved_game_to_scenario_dialog(char *resultPath) */ void editor_convert_save_to_scenario() { - rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; - char savedGamePath[MAX_PATH]; - tool_cancel(); - if (!show_convert_saved_game_to_scenario_dialog(savedGamePath)) - return; + window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME, NULL); + gLoadSaveCallback = editor_convert_save_to_scenario_callback; +} - path_set_extension(savedGamePath, ".SV6"); - - // Load the saved game - if (!game_load_save(savedGamePath)) +void editor_convert_save_to_scenario_callback(int result) +{ + if (result != MODAL_RESULT_OK) { return; + } + + rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_NO_MONEY_SCENARIO; @@ -141,8 +119,8 @@ void editor_convert_save_to_scenario() RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_NO_MONEY_SCENARIO; RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_NO_MONEY; - strcpy(s6Info->name, (const char*)RCT2_ADDRESS_SCENARIO_NAME); - strcpy(s6Info->details, (const char*)RCT2_ADDRESS_SCENARIO_DETAILS); + safe_strncpy(s6Info->name, (const char*)RCT2_ADDRESS_SCENARIO_NAME, 64); + safe_strncpy(s6Info->details, (const char*)RCT2_ADDRESS_SCENARIO_DETAILS, 256); 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, sint32); @@ -151,7 +129,7 @@ void editor_convert_save_to_scenario() rct_stex_entry* stex = g_stexEntries[0]; if ((int)stex != 0xFFFFFFFF) { - object_unload(0, &object_entry_groups[OBJECT_TYPE_SCENARIO_TEXT].entries[0]); + object_unload((rct_object_entry*)&object_entry_groups[OBJECT_TYPE_SCENARIO_TEXT].entries[0]); reset_loaded_objects(); format_string(s6Info->details, STR_NO_DETAILS_YET, NULL); @@ -159,13 +137,13 @@ void editor_convert_save_to_scenario() } RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_SCENARIO_EDITOR; - s6Info->var_000 = 4; + s6Info->editor_step = EDITOR_STEP_OBJECTIVE_SELECTION; s6Info->category = SCENARIO_CATEGORY_BUILDYOUROWN; viewport_init_all(); news_item_init_queue(); window_editor_main_open(); editor_finalise_main_view(); - RCT2_GLOBAL(0x009DEA66, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, uint16) = 0; } /** @@ -182,10 +160,10 @@ void trackdesigner_load() banner_init(); reset_park_entrances(); user_string_clear_all(); - reset_sprite_list(); + reset_sprite_list(); ride_init_all(); window_guest_list_init_vars_a(); - sub_6BD3A4(); + staff_reset_modes(); park_init(); finance_init(); date_reset(); @@ -202,7 +180,7 @@ void trackdesigner_load() mainWindow->flags &= ~WF_SCROLLING_TO_LOCATION; load_palette(); gfx_invalidate_screen(); - RCT2_GLOBAL(0x009DEA66, sint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, sint16) = 0; } /** @@ -222,7 +200,7 @@ void trackmanager_load() reset_sprite_list(); ride_init_all(); window_guest_list_init_vars_a(); - sub_6BD3A4(); + staff_reset_modes(); park_init(); finance_init(); date_reset(); @@ -239,7 +217,7 @@ void trackmanager_load() mainWindow->flags &= ~WF_SCROLLING_TO_LOCATION; load_palette(); gfx_invalidate_screen(); - RCT2_GLOBAL(0x009DEA66, sint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, sint16) = 0; } /** @@ -250,22 +228,7 @@ static void set_all_land_owned() { int mapSize = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, sint16); - game_do_command(64, 1, 64, 2, GAME_COMMAND_56, (mapSize - 2) * 32, (mapSize - 2) * 32); -} - -/** - * - * rct2: 0x006BD3A4 - */ -void sub_6BD3A4() -{ - 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(); + game_do_command(64, 1, 64, 2, GAME_COMMAND_SET_LAND_OWNERSHIP, (mapSize - 2) * 32, (mapSize - 2) * 32); } /** @@ -275,7 +238,7 @@ void sub_6BD3A4() void editor_load_landscape(const char *path) { window_close_construction_windows(); - + char *extension = strrchr(path, '.'); if (extension != NULL) { if (_stricmp(extension, ".sv4") == 0) { @@ -309,7 +272,7 @@ static int editor_load_landscape_from_sv4(const char *path) rct1_fix_landscape(); editor_finalise_main_view(); - RCT2_GLOBAL(0x009DEA66, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, uint16) = 0; return 1; } @@ -327,7 +290,7 @@ static int editor_load_landscape_from_sc4(const char *path) rct1_fix_landscape(); editor_finalise_main_view(); - RCT2_GLOBAL(0x009DEA66, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, uint16) = 0; return 1; } @@ -338,16 +301,16 @@ static int editor_load_landscape_from_sc4(const char *path) static int editor_read_s6(const char *path) { int i, j; - FILE *file; + SDL_RWops* rw; rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4; rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; log_verbose("loading landscape, %s", path); - file = fopen(path, "rb"); - if (file != NULL) { - if (!sawyercoding_validate_checksum(file)) { - fclose(file); + rw = SDL_RWFromFile(path, "rb"); + if (rw != NULL) { + if (!sawyercoding_validate_checksum(rw)) { + SDL_RWclose(rw); RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; @@ -356,15 +319,15 @@ static int editor_read_s6(const char *path) } // Read first chunk - sawyercoding_read_chunk(file, (uint8*)s6Header); + sawyercoding_read_chunk(rw, (uint8*)s6Header); if (s6Header->type == S6_TYPE_SCENARIO) { // Read second chunk - sawyercoding_read_chunk(file, (uint8*)s6Info); + sawyercoding_read_chunk(rw, (uint8*)s6Info); - if (s6Info->var_000 == 255) - s6Info->var_000 = 1; + if (s6Info->editor_step == 255) + s6Info->editor_step = EDITOR_STEP_LANDSCAPE_EDITOR; } else { - s6Info->var_000 = 1; + s6Info->editor_step = EDITOR_STEP_LANDSCAPE_EDITOR; s6Info->category = SCENARIO_CATEGORY_BUILDYOUROWN; format_string(s6Info->details, STR_NO_DETAILS_YET, NULL); } @@ -373,50 +336,50 @@ static int editor_read_s6(const char *path) if (s6Header->num_packed_objects > 0) { j = 0; for (i = 0; i < s6Header->num_packed_objects; i++) - j += object_load_packed(file); + j += object_load_packed(rw); if (j > 0) object_list_load(); } - uint8 load_success = object_read_and_load_entries(file); + uint8 load_success = object_read_and_load_entries(rw); // Read flags (16 bytes). Loads: // RCT2_ADDRESS_CURRENT_MONTH_YEAR // RCT2_ADDRESS_CURRENT_MONTH_TICKS // RCT2_ADDRESS_SCENARIO_TICKS - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR); // Read map elements memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, MAX_MAP_ELEMENTS * sizeof(rct_map_element)); - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS); // Read game data, including sprites - sawyercoding_read_chunk(file, (uint8*)0x010E63B8); + sawyercoding_read_chunk(rw, (uint8*)0x010E63B8); if (s6Header->type == S6_TYPE_SCENARIO) { // Read number of guests in park and something else - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_GUESTS_IN_PARK); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_GUESTS_IN_PARK); // Read ? - sawyercoding_read_chunk(file, (uint8*)0x01357BC8); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_LAST_GUESTS_IN_PARK); // Read park rating - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_PARK_RATING); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_PARK_RATING); // Read ? - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES); // Read ? - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_EXPENDITURE); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_EXPENDITURE); // Read ? - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_PARK_VALUE); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_PARK_VALUE); // Read more game data, including research items and rides - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_COMPLETED_COMPANY_VALUE); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_COMPLETED_COMPANY_VALUE); } - fclose(file); + SDL_RWclose(rw); if (!load_success){ log_error("failed to load all entries."); set_load_objects_fail_reason(); @@ -427,30 +390,30 @@ static int editor_read_s6(const char *path) map_update_tile_pointers(); map_remove_all_rides(); - // + // for (i = 0; i < MAX_BANNERS; i++) if (gBanners[i].type == 255) gBanners[i].flags &= ~BANNER_FLAG_2; - // + // rct_ride *ride; FOR_ALL_RIDES(i, ride) user_string_free(ride->name); ride_init_all(); - // + // for (i = 0; i < MAX_SPRITES; i++) { rct_sprite *sprite = &g_sprite_list[i]; user_string_free(sprite->unknown.name_string_idx); } reset_sprite_list(); - sub_6BD3A4(); + staff_reset_modes(); 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, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_LAST_GUESTS_IN_PARK, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_CHANGE_MODIFIER, uint16) = 0; if (s6Header->type != S6_TYPE_SCENARIO) { research_populate_list_random(); research_remove_non_separate_vehicle_types(); @@ -474,9 +437,9 @@ static int editor_read_s6(const char *path) MONEY(100,00) ); - RCT2_GLOBAL(0x013573DC, uint32) = min(RCT2_GLOBAL(0x013573DC, uint32), 100000); - RCT2_CALLPROC_EBPSAFE(0x0069E89B); - sub_69E869(); + RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, uint32) = min(RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, uint32), 100000); + finance_reset_cash_to_initial(); + finance_update_loan_hash(); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) = clamp( MONEY(0,00), @@ -501,7 +464,7 @@ static int editor_read_s6(const char *path) rct_stex_entry* stex = g_stexEntries[0]; if ((int)stex != 0xFFFFFFFF) { - object_unload(0, &object_entry_groups[OBJECT_TYPE_SCENARIO_TEXT].entries[0]); + object_unload((rct_object_entry*)&object_entry_groups[OBJECT_TYPE_SCENARIO_TEXT].entries[0]); reset_loaded_objects(); format_string(s6Info->details, STR_NO_DETAILS_YET, NULL); @@ -513,6 +476,7 @@ static int editor_read_s6(const char *path) news_item_init_queue(); window_editor_main_open(); editor_finalise_main_view(); + game_convert_strings_to_utf8(); return 1; } @@ -575,10 +539,10 @@ static void editor_finalise_main_view() 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; + viewport->zoom = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16) & 0xFF; if (zoom_difference != 0) { if (zoom_difference >= 0) { viewport->view_width <<= zoom_difference; @@ -596,7 +560,112 @@ static void editor_finalise_main_view() reset_all_sprite_quadrant_placements(); scenery_set_default_placement_configuration(); window_new_ride_init_vars(); - RCT2_GLOBAL(0x009DEB7C, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_UPDATE_TICKS, uint16) = 0; load_palette(); gfx_invalidate_screen(); -} \ No newline at end of file +} + +static bool editor_check_object_group_at_least_one_selected(int objectType) +{ + uint32 numObjects = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); + rct_object_entry *entry = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + uint8 *objectFlag = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + for (uint32 i = 0; i < numObjects; i++) { + if ((entry->flags & 0x0F) == objectType && (*objectFlag & 1)) { + return true; + } + entry = object_get_next(entry); + objectFlag++; + } + return false; +} + +/** + * + * rct2: 0x006AB9B8 + */ +int editor_check_object_selection() +{ + bool isTrackDesignerManager = + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER); + + if (!isTrackDesignerManager) { + if (!editor_check_object_group_at_least_one_selected(OBJECT_TYPE_PATHS)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_AT_LEAST_ONE_PATH_OBJECT_MUST_BE_SELECTED; + return OBJECT_TYPE_PATHS; + } + } + + if (!editor_check_object_group_at_least_one_selected(OBJECT_TYPE_RIDE)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_AT_LEAST_ONE_RIDE_OBJECT_MUST_BE_SELECTED; + return OBJECT_TYPE_RIDE; + } + + if (!isTrackDesignerManager) { + if (!editor_check_object_group_at_least_one_selected(OBJECT_TYPE_PARK_ENTRANCE)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_PARK_ENTRANCE_TYPE_MUST_BE_SELECTED; + return OBJECT_TYPE_PARK_ENTRANCE; + } + + if (!editor_check_object_group_at_least_one_selected(OBJECT_TYPE_WATER)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_WATER_TYPE_MUST_BE_SELECTED; + return OBJECT_TYPE_WATER; + } + } + + return -1; +} + +/** + * + * rct2: 0x0066FEAC + */ +bool editor_check_park() +{ + int parkSize = park_calculate_size(); + if (parkSize == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_PARK_MUST_OWN_SOME_LAND; + return false; + } + + for (int i = 0; i < 4; i++) { + if (RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[i] != 0x8000) + break; + + if (i == 3) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_NO_PARK_ENTRANCES; + return false; + } + } + + for (int i = 0; i < 4; i++) { + if (RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[i] == 0x8000) + continue; + + int x = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[i]; + int y = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, uint16)[i]; + int z = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Z, uint16)[i] / 8; + int direction = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_DIRECTION, uint8)[i] ^ 2; + + switch (footpath_is_connected_to_map_edge(x, y, z, direction, 0)) { + case FOOTPATH_SEARCH_NOT_FOUND: + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_PARK_ENTRANCE_WRONG_DIRECTION_OR_NO_PATH; + return false; + case FOOTPATH_SEARCH_INCOMPLETE: + case FOOTPATH_SEARCH_TOO_COMPLEX: + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_PARK_ENTRANCE_PATH_INCOMPLETE_OR_COMPLEX; + return false; + case FOOTPATH_SEARCH_SUCCESS: + // Run the search again and unown the path + footpath_is_connected_to_map_edge(x, y, z, direction, 0x20); + break; + } + } + + if (gPeepSpawns[0].x == 0xFFFF && gPeepSpawns[1].x == 0xFFFF) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_PEEP_SPAWNS_NOT_SET; + return false; + } + + return true; +} diff --git a/src/editor.h b/src/editor.h index 9232dd7c59..83b0f46f8c 100644 --- a/src/editor.h +++ b/src/editor.h @@ -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 . *****************************************************************************/ @@ -43,8 +43,9 @@ void trackdesigner_load(); void trackmanager_load(); void editor_load_landscape(const char *path); -void sub_6BD3A4(); - void editor_open_windows_for_current_step(); +bool editor_check_park(); +int editor_check_object_selection(); + #endif diff --git a/src/game.c b/src/game.c index 1245676d68..65802ea818 100644 --- a/src/game.c +++ b/src/game.c @@ -1,9 +1,9 @@ /***************************************************************************** * 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 @@ -17,7 +17,7 @@ * 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 "config.h" @@ -34,6 +34,7 @@ #include "management/marketing.h" #include "management/news_item.h" #include "management/research.h" +#include "network/network.h" #include "object.h" #include "openrct2.h" #include "peep/peep.h" @@ -58,6 +59,35 @@ #include "world/water.h" int gGameSpeed = 1; +float gDayNightCycle = 0; +bool gInUpdateCode = false; + +GAME_COMMAND_CALLBACK_POINTER* game_command_callback = 0; +GAME_COMMAND_CALLBACK_POINTER* game_command_callback_table[] = { + 0, + game_command_callback_ride_construct_new, + game_command_callback_ride_construct_placed_front, + game_command_callback_ride_construct_placed_back, + game_command_callback_ride_remove_track_piece, +}; + +int game_command_callback_get_index(GAME_COMMAND_CALLBACK_POINTER* callback) +{ + for (int i = 0; i < countof(game_command_callback_table); i++ ) { + if (game_command_callback_table[i] == callback) { + return i; + } + } + return 0; +} + +GAME_COMMAND_CALLBACK_POINTER* game_command_callback_get_callback(int index) +{ + if (index < countof(game_command_callback_table)) { + return game_command_callback_table[index]; + } + return 0; +} void game_increase_game_speed() { @@ -76,7 +106,7 @@ void game_reduce_game_speed() } /** - * + * * rct2: 0x0066B5C0 (part of 0x0066B3E8) */ void game_create_windows() @@ -106,12 +136,12 @@ void update_palette_effects() int xoffset = g1_element.x_offset; xoffset = xoffset * 4; for (int i = 0; i < g1_element.width; i++) { - RCT2_ADDRESS(0x01424680 + xoffset, uint8)[(i * 4) + 0] = -((0xFF - g1_element.offset[(i * 3) + 0]) / 2) - 1; - RCT2_ADDRESS(0x01424680 + xoffset, uint8)[(i * 4) + 1] = -((0xFF - g1_element.offset[(i * 3) + 1]) / 2) - 1; - RCT2_ADDRESS(0x01424680 + xoffset, uint8)[(i * 4) + 2] = -((0xFF - g1_element.offset[(i * 3) + 2]) / 2) - 1; + RCT2_ADDRESS(RCT2_ADDRESS_PALETTE + xoffset, uint8)[(i * 4) + 0] = -((0xFF - g1_element.offset[(i * 3) + 0]) / 2) - 1; + RCT2_ADDRESS(RCT2_ADDRESS_PALETTE + xoffset, uint8)[(i * 4) + 1] = -((0xFF - g1_element.offset[(i * 3) + 1]) / 2) - 1; + RCT2_ADDRESS(RCT2_ADDRESS_PALETTE + xoffset, uint8)[(i * 4) + 2] = -((0xFF - g1_element.offset[(i * 3) + 2]) / 2) - 1; } RCT2_GLOBAL(0x014241BC, uint32) = 2; - platform_update_palette(RCT2_ADDRESS(0x01424680, uint8), 10, 236); + platform_update_palette(RCT2_ADDRESS(RCT2_ADDRESS_PALETTE, uint8), 10, 236); RCT2_GLOBAL(0x014241BC, uint32) = 0; RCT2_GLOBAL(RCT2_ADDRESS_LIGHTNING_ACTIVE, uint8)++; } else { @@ -127,9 +157,9 @@ void update_palette_effects() int xoffset = g1_element.x_offset; xoffset = xoffset * 4; for (int i = 0; i < g1_element.width; i++) { - RCT2_ADDRESS(0x01424680 + xoffset, uint8)[(i * 4) + 0] = g1_element.offset[(i * 3) + 0]; - RCT2_ADDRESS(0x01424680 + xoffset, uint8)[(i * 4) + 1] = g1_element.offset[(i * 3) + 1]; - RCT2_ADDRESS(0x01424680 + xoffset, uint8)[(i * 4) + 2] = g1_element.offset[(i * 3) + 2]; + RCT2_ADDRESS(RCT2_ADDRESS_PALETTE + xoffset, uint8)[(i * 4) + 0] = g1_element.offset[(i * 3) + 0]; + RCT2_ADDRESS(RCT2_ADDRESS_PALETTE + xoffset, uint8)[(i * 4) + 1] = g1_element.offset[(i * 3) + 1]; + RCT2_ADDRESS(RCT2_ADDRESS_PALETTE + xoffset, uint8)[(i * 4) + 2] = g1_element.offset[(i * 3) + 2]; } } @@ -199,11 +229,11 @@ void update_palette_effects() } RCT2_GLOBAL(0x014241BC, uint32) = 2; - platform_update_palette(RCT2_ADDRESS(0x01424680, uint8), 230, 16); + platform_update_palette(RCT2_ADDRESS(RCT2_ADDRESS_PALETTE, uint8), 230, 16); RCT2_GLOBAL(0x014241BC, uint32) = 0; if (RCT2_GLOBAL(RCT2_ADDRESS_LIGHTNING_ACTIVE, uint8) == 2) { RCT2_GLOBAL(0x014241BC, uint32) = 2; - platform_update_palette(RCT2_ADDRESS(0x01424680, uint8), 10, 236); + platform_update_palette(RCT2_ADDRESS(RCT2_ADDRESS_PALETTE, uint8), 10, 236); RCT2_GLOBAL(0x014241BC, uint32) = 0; RCT2_GLOBAL(RCT2_ADDRESS_LIGHTNING_ACTIVE, uint8) = 0; } @@ -219,9 +249,6 @@ void game_update() { int i, numUpdates; - // Handles picked-up peep and rain redraw - redraw_peep_and_rain(); - // 0x006E3AEC // screen_game_process_mouse_input(); screenshot_check(); game_handle_keyboard_input(); @@ -230,38 +257,54 @@ void game_update() if (gGameSpeed > 1) { numUpdates = 1 << (gGameSpeed - 1); } else { - numUpdates = RCT2_GLOBAL(0x009DE588, uint16) / 31; + numUpdates = RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_LAST_UPDATE, uint16) / 31; numUpdates = clamp(1, numUpdates, 4); } + if (network_get_mode() == NETWORK_MODE_CLIENT && network_get_status() == NETWORK_STATUS_CONNECTED && network_get_authstatus() == NETWORK_AUTH_OK) { + if (network_get_server_tick() - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) >= 10) { + // make sure client doesn't fall behind the server too much + numUpdates += 10; + } + } else { + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0) { + numUpdates = 0; + // Update the animation list. Note this does not + // increment the map animation. + map_animation_invalidate_all(); + } + } + // Update the game one or more times - if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0) { - for (i = 0; i < numUpdates; i++) { - game_logic_update(); - start_title_music(); + for (i = 0; i < numUpdates; i++) { + game_logic_update(); + audio_start_title_music(); - if (gGameSpeed > 1) - continue; + if (gGameSpeed > 1) + continue; - // Possibly smooths viewport scrolling, I don't see a difference though - if (RCT2_GLOBAL(0x009E2D74, uint32) == 1) { - RCT2_GLOBAL(0x009E2D74, uint32) = 0; - break; - } else { - 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) & INPUT_FLAG_VIEWPORT_SCROLLING) { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_VIEWPORT_SCROLLING; - break; - } - } else { + // Possibly smooths viewport scrolling, I don't see a difference though + if (RCT2_GLOBAL(0x009E2D74, uint32) == 1) { + RCT2_GLOBAL(0x009E2D74, uint32) = 0; + break; + } else { + 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) & INPUT_FLAG_VIEWPORT_SCROLLING) { + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_VIEWPORT_SCROLLING; break; } + } else { + break; } } } + // Always perform autosave check, even when paused + scenario_autosave_check(); + + network_update(); news_item_update_current(); window_dispatch_update_all(); @@ -272,7 +315,7 @@ void game_update() // 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) + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) % 4 == 0) RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) ^= (1 << 15); // Handle guest map flashing @@ -288,39 +331,35 @@ void game_update() RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) &= ~(1 << 2); window_map_tooltip_update_visibility(); - window_update_all(); - - RCT2_GLOBAL(0x01388698, uint16)++; // Input RCT2_GLOBAL(0x0141F568, uint8) = RCT2_GLOBAL(0x0013CA740, uint8); game_handle_input(); - - 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_default(); - } } void game_logic_update() { - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, sint32)++; - RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, sint32)++; - RCT2_GLOBAL(0x009DEA66, sint16)++; - if (RCT2_GLOBAL(0x009DEA66, sint16) == 0) - RCT2_GLOBAL(0x009DEA66, sint16)--; + /////////////////////////// + gInUpdateCode = true; + /////////////////////////// + network_update(); + if (network_get_mode() == NETWORK_MODE_CLIENT && network_get_status() == NETWORK_STATUS_CONNECTED && network_get_authstatus() == NETWORK_AUTH_OK) { + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) >= network_get_server_tick()) { + // dont run past the server + return; + } + } + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32)++; + RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32)++; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, sint16)++; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, sint16) == 0) + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, sint16)--; sub_68B089(); scenario_update(); climate_update(); map_update_tiles(); - sub_6A876D(); + map_update_path_wide_flags(); peep_update_all(); vehicle_update_all(); sprite_misc_update_all(); @@ -329,12 +368,18 @@ void game_logic_update() research_update(); ride_ratings_update_all(); ride_measurements_update(); + /////////////////////////// + gInUpdateCode = false; + /////////////////////////// + map_animation_invalidate_all(); vehicle_sounds_update(); peep_update_crowd_noise(); climate_update_sound(); editor_open_windows_for_current_step(); + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_AGE, uint16)++; + // Update windows //window_dispatch_update_all(); @@ -352,7 +397,7 @@ void game_logic_update() } /** - * + * * rct2: 0x0069C62C * * @param cost (ebp) @@ -361,20 +406,20 @@ static int game_check_affordability(int cost) { if (cost <= 0)return cost; if (RCT2_GLOBAL(0x141F568, uint8) & 0xF0)return cost; - + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32)&(1 << 8))){ if (cost <= (sint32)(DECRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32))))return cost; } - RCT2_GLOBAL(0x13CE952, uint32) = cost; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) = cost; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 827; return MONEY32_UNDEFINED; } -static uint32 game_do_command_table[58]; -static GAME_COMMAND_POINTER* new_game_command_table[58]; +static GAME_COMMAND_POINTER* new_game_command_table[62]; /** - * + * * rct2: 0x006677F2 * * @param flags (ebx) @@ -410,20 +455,26 @@ int game_do_command_p(int command, int *eax, int *ebx, int *ecx, int *edx, int * // Increment nest count RCT2_GLOBAL(0x009A8C28, uint8)++; - *ebx &= ~GAME_COMMAND_FLAG_APPLY; - - // Primary command - if (game_do_command_table[command] == 0) { - new_game_command_table[command](eax, ebx, ecx, edx, esi, edi, ebp); - } else { - RCT2_CALLFUNC_X(game_do_command_table[command], eax, ebx, ecx, edx, esi, edi, ebp); + // Remove ghost scenery so it doesn't interfere with incoming network command + if ((flags & GAME_COMMAND_FLAG_NETWORKED) && !(flags & GAME_COMMAND_FLAG_GHOST) && + (command == GAME_COMMAND_PLACE_FENCE || + command == GAME_COMMAND_PLACE_SCENERY || + command == GAME_COMMAND_PLACE_LARGE_SCENERY || + command == GAME_COMMAND_PLACE_BANNER || + command == GAME_COMMAND_PLACE_PATH)) { + scenery_remove_ghost_tool_placement(); } + + *ebx &= ~GAME_COMMAND_FLAG_APPLY; + + // First call for validity and price check + new_game_command_table[command](eax, ebx, ecx, edx, esi, edi, ebp); cost = *ebx; if (cost != MONEY32_UNDEFINED) { // Check funds insufficientFunds = 0; - if (RCT2_GLOBAL(0x009A8C28, uint8) == 1 && !(flags & 4) && !(flags & 0x20) && cost != 0) + if (RCT2_GLOBAL(0x009A8C28, uint8) == 1 && !(flags & GAME_COMMAND_FLAG_2) && !(flags & GAME_COMMAND_FLAG_5) && cost != 0) insufficientFunds = game_check_affordability(cost); if (insufficientFunds != MONEY32_UNDEFINED) { @@ -433,18 +484,32 @@ int game_do_command_p(int command, int *eax, int *ebx, int *ecx, int *edx, int * *edi = original_edi; *ebp = original_ebp; - if (!(flags & 1)) { + if (!(flags & GAME_COMMAND_FLAG_APPLY)) { // Decrement nest count RCT2_GLOBAL(0x009A8C28, uint8)--; return cost; } - // Secondary command - if (game_do_command_table[command] == 0) { - new_game_command_table[command](eax, ebx, ecx, edx, esi, edi, ebp); - } else { - RCT2_CALLFUNC_X(game_do_command_table[command], eax, ebx, ecx, edx, esi, edi, ebp); + if (network_get_mode() != NETWORK_MODE_NONE && !(flags & GAME_COMMAND_FLAG_NETWORKED) && !(flags & GAME_COMMAND_FLAG_GHOST) && !(flags & GAME_COMMAND_FLAG_5) && RCT2_GLOBAL(0x009A8C28, uint8) == 1 /* Send only top-level commands */) { + if (command != GAME_COMMAND_LOAD_OR_QUIT) { // Disable these commands over the network + network_send_gamecmd(*eax, *ebx, *ecx, *edx, *esi, *edi, *ebp, game_command_callback_get_index(game_command_callback)); + if (network_get_mode() == NETWORK_MODE_CLIENT) { // Client sent the command to the server, do not run it locally, just return. It will run when server sends it + game_command_callback = 0; + // Decrement nest count + RCT2_GLOBAL(0x009A8C28, uint8)--; + return cost; + } + } } + + // Second call to actually perform the operation + new_game_command_table[command](eax, ebx, ecx, edx, esi, edi, ebp); + + if (game_command_callback) { + game_command_callback(*eax, *ebx, *ecx, *edx, *esi, *edi, *ebp); + game_command_callback = 0; + } + *edx = *ebx; if (*edx != MONEY32_UNDEFINED && *edx < cost) @@ -455,7 +520,7 @@ int game_do_command_p(int command, int *eax, int *ebx, int *ecx, int *edx, int * if (RCT2_GLOBAL(0x009A8C28, uint8) != 0) return cost; - // + // if (!(flags & 0x20)) { // Update money balance finance_payment(cost, RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) / 4); @@ -476,7 +541,7 @@ int game_do_command_p(int command, int *eax, int *ebx, int *ecx, int *edx, int * RCT2_GLOBAL(0x009A8C28, uint8)--; // Show error window - if (RCT2_GLOBAL(0x009A8C28, uint8) == 0 && (flags & 1) && RCT2_GLOBAL(0x0141F568, uint8) == RCT2_GLOBAL(0x013CA740, uint8) && !(flags & 8)) + if (RCT2_GLOBAL(0x009A8C28, uint8) == 0 && (flags & GAME_COMMAND_FLAG_APPLY) && RCT2_GLOBAL(0x0141F568, uint8) == RCT2_GLOBAL(0x013CA740, uint8) && !(flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED)) window_error_open(RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16), RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16)); return MONEY32_UNDEFINED; @@ -486,14 +551,16 @@ 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(); + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint32) & 1) { + audio_pause_sounds(); + audio_unpause_sounds(); + } else { + audio_unpause_sounds(); + } } /** - * + * * rct2: 0x00667C15 */ void game_pause_toggle(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) @@ -505,7 +572,7 @@ void game_pause_toggle(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *ed } /** - * + * * rct2: 0x0066DB5F */ static void game_load_or_quit(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) @@ -535,11 +602,11 @@ static int open_landscape_file_dialog() { int result; format_string((char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, STR_LOAD_LANDSCAPE_DIALOG_TITLE, 0); - strcpy((char*)0x0141EF68, (char*)RCT2_ADDRESS_LANDSCAPES_PATH); + safe_strncpy((char*)0x0141EF68, (char*)RCT2_ADDRESS_LANDSCAPES_PATH, MAX_PATH); format_string((char*)0x0141EE68, STR_RCT2_LANDSCAPE_FILE, 0); - pause_sounds(); + audio_pause_sounds(); result = platform_open_common_file_dialog(1, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68, "*.SV6;*.SV4;*.SC6", (char*)0x0141EE68); - unpause_sounds(); + audio_unpause_sounds(); // window_proc return result; } @@ -552,11 +619,11 @@ static int open_load_game_dialog() { int result; format_string((char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, STR_LOAD_GAME_DIALOG_TITLE, 0); - strcpy((char*)0x0141EF68, (char*)RCT2_ADDRESS_SAVED_GAMES_PATH); + safe_strncpy((char*)0x0141EF68, (char*)RCT2_ADDRESS_SAVED_GAMES_PATH, MAX_PATH); format_string((char*)0x0141EE68, STR_RCT2_SAVED_GAME, 0); - pause_sounds(); + audio_pause_sounds(); result = platform_open_common_file_dialog(1, (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68, "*.SV6", (char*)0x0141EE68); - unpause_sounds(); + audio_unpause_sounds(); // window_proc return result; } @@ -584,52 +651,92 @@ static void load_landscape() strcpy(esi, ".SC6"); break; } - strcpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, (char*)0x0141EF68); + safe_strncpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, (char*)0x0141EF68, MAX_PATH); editor_load_landscape((char*)0x0141EF68); if (1) { gfx_invalidate_screen(); rct2_endupdate(); } else { - RCT2_GLOBAL(0x009DEA66, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, uint16) = 0; rct2_endupdate(); } } } /** - * - * rct2: 0x00675E1B + * Converts all the user strings and news item strings to UTF-8. */ -int game_load_sv6(const char *path) +void game_convert_strings_to_utf8() { - FILE *file; - int i, j; + utf8 buffer[512]; - log_verbose("loading saved game, %s", path); + // User strings + for (int i = 0; i < MAX_USER_STRINGS; i++) { + utf8 *userString = &gUserStrings[i * USER_STRING_MAX_LENGTH]; - 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(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; - return 0; + if (!str_is_null_or_empty(userString)) { + rct2_to_utf8(buffer, userString); + memcpy(userString, buffer, 31); + userString[31] = 0; + } } - if (!sawyercoding_validate_checksum(file)) { - fclose(file); + // News items + for (int i = 0; i < MAX_NEWS_ITEMS; i++) { + rct_news_item *newsItem = news_item_get(i); - log_error("invalid checksum, %s", path); + if (!str_is_null_or_empty(newsItem->text)) { + rct2_to_utf8(buffer, newsItem->text); + memcpy(newsItem->text, buffer, 255); + newsItem->text[255] = 0; + } + } +} + +/** + * Converts all the user strings and news item strings to RCT2 encoding. + */ +void game_convert_strings_to_rct2(rct_s6_data *s6) +{ + char buffer[512]; + + // User strings + for (int i = 0; i < MAX_USER_STRINGS; i++) { + char *userString = &s6->custom_strings[i * USER_STRING_MAX_LENGTH]; + + if (!str_is_null_or_empty(userString)) { + utf8_to_rct2(buffer, userString); + memcpy(userString, buffer, 31); + userString[31] = 0; + } + } + + // News items + for (int i = 0; i < MAX_NEWS_ITEMS; i++) { + rct_news_item *newsItem = &s6->news_items[i]; + + if (!str_is_null_or_empty(newsItem->text)) { + utf8_to_rct2(buffer, newsItem->text); + memcpy(newsItem->text, buffer, 255); + newsItem->text[255] = 0; + } + } +} + +/** + * + * rct2: 0x00675E1B + */ +int game_load_sv6(SDL_RWops* rw) +{ + int i, j; + + if (!sawyercoding_validate_checksum(rw)) { + log_error("invalid checksum"); RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_FILE_CONTAINS_INVALID_DATA; return 0; } @@ -637,36 +744,124 @@ int game_load_sv6(const char *path) rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; // Read first chunk - sawyercoding_read_chunk(file, (uint8*)s6Header); + sawyercoding_read_chunk(rw, (uint8*)s6Header); if (s6Header->type == S6_TYPE_SAVEDGAME) { // Read packed objects if (s6Header->num_packed_objects > 0) { j = 0; for (i = 0; i < s6Header->num_packed_objects; i++) - j += object_load_packed(file); + j += object_load_packed(rw); if (j > 0) object_list_load(); } } - uint8 load_success = object_read_and_load_entries(file); + uint8 load_success = object_read_and_load_entries(rw); // Read flags (16 bytes) - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR); // Read map elements memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, MAX_MAP_ELEMENTS * sizeof(rct_map_element)); - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS); // Read game data, including sprites - sawyercoding_read_chunk(file, (uint8*)0x010E63B8); - - fclose(file); + sawyercoding_read_chunk(rw, (uint8*)0x010E63B8); + + if (!load_success){ + set_load_objects_fail_reason(); + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_5){ + //call 0x0040705E Sets cursor position and something else. Calls maybe wind func 8 probably pointless + RCT2_GLOBAL(0x14241BC, uint32) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_5; + } + + return 0;//This never gets called + } + + // The rest is the same as in scenario_load + reset_loaded_objects(); + map_update_tile_pointers(); + reset_0x69EBE4(); + openrct2_reset_object_tween_locations(); + game_convert_strings_to_utf8(); + game_fix_save_vars(); // OpenRCT2 fix broken save games + + return 1; +} + +// OpenRCT2 workaround to recalculate some values which are saved redundantly in the save to fix corrupted files. +// For example recalculate guest count by looking at all the guests instead of trusting the value in the file. +void game_fix_save_vars() { + + // Recalculates peep count after loading a save to fix corrupted files + rct_peep* peep; + uint16 spriteIndex; + uint16 peepCount = 0; + FOR_ALL_GUESTS(spriteIndex, peep) { + if(!peep->outside_of_park) + peepCount++; + } + + RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16) = peepCount; + + // Fixes broken saves where a surface element could be null + for (int y = 0; y < 256; y++) { + for (int x = 0; x < 256; x++) { + rct_map_element *mapElement = map_get_surface_element_at(x, y); + + if (mapElement == NULL) + { + log_error("Null map element at x = %d and y = %d. Fixing...", x, y); + map_element_insert(x, y, 14, 0); + } + } + } +} + +// Load game state for multiplayer +int game_load_network(SDL_RWops* rw) +{ + int i, j; + + rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4; + rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; + + // Read first chunk + sawyercoding_read_chunk(rw, (uint8*)s6Header); + if (s6Header->type == S6_TYPE_SAVEDGAME) { + // Read packed objects + if (s6Header->num_packed_objects > 0) { + j = 0; + for (i = 0; i < s6Header->num_packed_objects; i++) + j += object_load_packed(rw); + if (j > 0) + object_list_load(); + } + } + + uint8 load_success = object_read_and_load_entries(rw); + + // Read flags (16 bytes) + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR); + + // Read map elements + memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, MAX_MAP_ELEMENTS * sizeof(rct_map_element)); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS); + + // Read game data, including sprites + sawyercoding_read_chunk(rw, (uint8*)0x010E63B8); + + // Read checksum + uint32 checksum; + SDL_RWread(rw, &checksum, sizeof(uint32), 1); + + // Read other data not in normal save files + RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint32) = SDL_ReadLE32(rw); if (!load_success){ set_load_objects_fail_reason(); 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(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_5; @@ -679,23 +874,50 @@ int game_load_sv6(const char *path) reset_loaded_objects(); map_update_tile_pointers(); reset_0x69EBE4(); + openrct2_reset_object_tween_locations(); return 1; } /** - * + * * rct2: 0x00675E1B */ int game_load_save(const char *path) { - rct_window *mainWindow; + log_verbose("loading saved game, %s", path); - if (!game_load_sv6(path)) { - title_load(); - rct2_endupdate(); + safe_strncpy((char*)0x0141EF68, path, MAX_PATH); + safe_strncpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, path, MAX_PATH); + + safe_strncpy(gScenarioSavePath, path, MAX_PATH); + + SDL_RWops* rw = SDL_RWFromFile(path, "rb"); + if (rw == NULL) { + log_error("unable to open %s", path); + RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_FILE_CONTAINS_INVALID_DATA; return 0; } + if (!game_load_sv6(rw)) { + title_load(); + rct2_endupdate(); + SDL_RWclose(rw); + return 0; + } + SDL_RWclose(rw); + + game_load_init(); + if (network_get_mode() == NETWORK_MODE_SERVER) { + network_send_map(); + } + return 1; +} + +void game_load_init() +{ + rct_window *mainWindow; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_PLAYING; viewport_init_all(); game_create_windows(); @@ -704,9 +926,9 @@ int game_load_save(const char *path) mainWindow->viewport_target_sprite = -1; mainWindow->saved_view_x = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, sint16); mainWindow->saved_view_y = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, sint16); - uint8 _cl = (RCT2_GLOBAL(0x0138869E, sint16) & 0xFF) - mainWindow->viewport->zoom; - mainWindow->viewport->zoom = RCT2_GLOBAL(0x0138869E, sint16) & 0xFF; - *((char*)(&RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, sint32))) = RCT2_GLOBAL(0x0138869E, sint16) >> 8; + uint8 _cl = (RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, sint16) & 0xFF) - mainWindow->viewport->zoom; + mainWindow->viewport->zoom = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, sint16) & 0xFF; + *((char*)(&RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, sint32))) = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, sint16) >> 8; if (_cl != 0) { if (_cl < 0) { _cl = -_cl; @@ -724,15 +946,17 @@ int game_load_save(const char *path) reset_all_sprite_quadrant_placements(); scenery_set_default_placement_configuration(); window_new_ride_init_vars(); - RCT2_GLOBAL(0x009DEB7C, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_UPDATE_TICKS, uint16) = 0; if (RCT2_GLOBAL(0x0013587C4, uint32) == 0) // this check is not in scenario play - sub_69E869(); + finance_update_loan_hash(); load_palette(); gfx_invalidate_screen(); + window_update_all(); + + gGameSpeed = 1; scenario_set_filename((char*)0x0135936C); - return 1; } /* @@ -748,7 +972,7 @@ void reset_all_sprite_quadrant_placements() } /** - * + * * rct2: 0x0066DBB7 */ static void load_game() @@ -770,13 +994,13 @@ static void load_game() strcpy(esi, ".SV6"); break; } - strcpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, (char*)0x0141EF68); + safe_strncpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, (char*)0x0141EF68, MAX_PATH); if (game_load_save((char *)0x0141EF68)) { gfx_invalidate_screen(); rct2_endupdate(); } else { - RCT2_GLOBAL(0x009DEA66, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, uint16) = 0; rct2_endupdate(); } } @@ -796,50 +1020,63 @@ static int show_save_game_dialog(char *resultPath) char filterName[256]; format_string(title, STR_SAVE_GAME_1040, NULL); - strcpy(filename, RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH_2, char)); + safe_strncpy(filename, RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH_2, char), MAX_PATH); format_string(filterName, STR_RCT2_SAVED_GAME, NULL); - pause_sounds(); + audio_pause_sounds(); result = platform_open_common_file_dialog(0, title, filename, "*.SV6", filterName); - unpause_sounds(); + audio_unpause_sounds(); if (result) - strcpy(resultPath, filename); + safe_strncpy(resultPath, filename, MAX_PATH); return result; } -char save_game() +void save_game() { - window_loadsave_open(LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME, gScenarioSaveName); - return 0; + if (!gFirstTimeSave) { + log_verbose("Saving to %s", gScenarioSavePath); - char path[256]; + SDL_RWops* rw = SDL_RWFromFile(gScenarioSavePath, "wb+"); + if (rw != NULL) { + scenario_save(rw, 0x80000000); + log_verbose("Saved to %s", gScenarioSavePath); + SDL_RWclose(rw); - if (!show_save_game_dialog(path)) { - gfx_invalidate_screen(); - return 0; - } - - // Ensure path has .SV6 extension - path_set_extension(path, ".SV6"); - - 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; + // Setting screen age to zero, so no prompt will pop up when closing the + // game shortly after saving. + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, uint16) = 0; + } } else { - return 0; + save_game_as(); } } +void save_game_as() +{ + window_loadsave_open(LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME, gScenarioSavePath); +} + void game_autosave() { - char path[MAX_PATH]; + utf8 path[MAX_PATH]; + utf8 backupPath[MAX_PATH]; platform_get_user_directory(path, "save"); - strcat(path, "autosave.sv6"); + safe_strncpy(backupPath, path, MAX_PATH); - scenario_save(path, 0x80000000); + strcat(path, "autosave.sv6"); + strcat(backupPath, "autosave.sv6.bak"); + + if (platform_file_exists(path)) { + platform_file_copy(path, backupPath, true); + } + + SDL_RWops* rw = SDL_RWFromFile(path, "wb+"); + if (rw != NULL) { + scenario_save(rw, 0x80000000); + SDL_RWclose(rw); + } } /** @@ -863,18 +1100,18 @@ void rct2_exit_reason(rct_string_id title, rct_string_id body){ /** - * + * * rct2: 0x006E3879 */ void rct2_exit() { - RCT2_CALLPROC_EBPSAFE(0x006E3879); + //audio_close(); //Post quit message does not work in 0x6e3879 as its windows only. openrct2_finish(); } /** - * + * * rct2: 0x0066DB79 */ void game_load_or_quit_no_save_prompt() @@ -890,7 +1127,7 @@ void game_load_or_quit_no_save_prompt() 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_CALLPROC_EBPSAFE(0x0040705E); Function not required resets cursor position. RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_5; } gGameSpeed = 1; @@ -901,130 +1138,67 @@ void game_load_or_quit_no_save_prompt() } } -#pragma region Game command function table - -static uint32 game_do_command_table[58] = { - 0, - 0x0066397F, - 0, - 0x006C511D, - 0x006C5B69, - 0, - 0x006B3F0F, - 0, - 0, - 0x006B52D4, - 0, // 10 - 0, - 0x006660A8, - 0x0066640B, - 0, - 0, - 0x006E650F, - 0, - 0x006A68AE, - 0, - 0, // use new_game_command_table, original: 0x00663CCD, // 20 - 0,//0x006B53E9, - 0x00698D6C, // text input - 0, - 0, - 0x0068BC01, - 0, - 0, - 0x006C5AE9, - 0, // use new_game_command_table, original: 0x006BEFA1, 29 - 0, // 30 - 0, - 0, - 0, - 0, - 0,//0x006649BD, //buy_land_rights - 0x006666E7, - 0, - 0x006CD8CE, - 0, - 0, // 40 - 0x006E519A, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0x006CDEE4, - 0, // 50 - 0, - 0, - 0, - 0, - 0, - 0x006648E3, - 0 -}; - -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] = { +static GAME_COMMAND_POINTER* new_game_command_table[62] = { game_command_set_ride_appearance, - game_command_emptysub, + game_command_set_land_height, game_pause_toggle, - game_command_emptysub, - game_command_emptysub, + game_command_place_track, + game_command_remove_track, game_load_or_quit, - game_command_emptysub, + game_command_create_ride, game_command_demolish_ride, game_command_set_ride_status, - game_command_emptysub, - game_command_set_ride_name, // 10 + game_command_set_ride_vehicles, + game_command_set_ride_name, game_command_set_ride_setting, - game_command_emptysub, - game_command_emptysub, + game_command_place_ride_entrance_or_exit, + game_command_remove_ride_entrance_or_exit, game_command_remove_scenery, game_command_place_scenery, - game_command_emptysub, + game_command_set_water_height, game_command_place_footpath, - game_command_emptysub, + game_command_place_footpath_from_track, game_command_remove_footpath, - game_command_change_surface_style, // 20 + game_command_change_surface_style, game_command_set_ride_price, - game_command_emptysub, + game_command_set_peep_name, game_command_raise_land, game_command_lower_land, - game_command_emptysub, + game_command_smooth_land, game_command_raise_water, game_command_lower_water, - game_command_emptysub, - game_command_hire_new_staff_member, //game_command_emptysub, - game_command_set_staff_patrol, // 30 + game_command_set_brakes_speed, + game_command_hire_new_staff_member, + game_command_set_staff_patrol, 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_buy_land_rights, + game_command_place_park_entrance, game_command_remove_park_entrance, - game_command_emptysub, + game_command_set_maze_track, game_command_set_park_entrance_fee, - game_command_update_staff_colour, // 40 - game_command_emptysub, + game_command_update_staff_colour, + game_command_place_fence, 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_place_track_design, game_command_start_campaign, - game_command_emptysub, - game_command_place_banner, // 50 + game_command_place_maze_design, + game_command_place_banner, 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 + game_command_set_land_ownership, + game_command_clear_scenery, + game_command_set_banner_name, + game_command_set_sign_name, + game_command_set_banner_style, + game_command_set_sign_style }; - -#pragma endregion diff --git a/src/game.h b/src/game.h index 219689e810..f2ef77a7e0 100644 --- a/src/game.h +++ b/src/game.h @@ -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 @@ -17,79 +17,104 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ - + #ifndef _GAME_H_ #define _GAME_H_ #include "common.h" +#include "platform/platform.h" +#include "scenario.h" enum GAME_COMMAND { GAME_COMMAND_SET_RIDE_APPEARANCE, - GAME_COMMAND_1, - GAME_COMMAND_TOGGLE_PAUSE, // 2 - GAME_COMMAND_3, //Has something to do with ride construction - GAME_COMMAND_4, - GAME_COMMAND_LOAD_OR_QUIT, // 5 - GAME_COMMAND_6, - GAME_COMMAND_7, - GAME_COMMAND_SET_RIDE_STATUS, // 8 - GAME_COMMAND_9, + GAME_COMMAND_SET_LAND_HEIGHT, + GAME_COMMAND_TOGGLE_PAUSE, + GAME_COMMAND_PLACE_TRACK, + GAME_COMMAND_REMOVE_TRACK, + GAME_COMMAND_LOAD_OR_QUIT, + GAME_COMMAND_CREATE_RIDE, + GAME_COMMAND_DEMOLISH_RIDE, + GAME_COMMAND_SET_RIDE_STATUS, + GAME_COMMAND_SET_RIDE_VEHICLES, GAME_COMMAND_SET_RIDE_NAME, GAME_COMMAND_SET_RIDE_SETTING, - GAME_COMMAND_12, - GAME_COMMAND_13, + GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, + GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT, GAME_COMMAND_REMOVE_SCENERY, GAME_COMMAND_PLACE_SCENERY, - GAME_COMMAND_16, - GAME_COMMAND_PLACE_PATH, // 17 - GAME_COMMAND_18, - GAME_COMMAND_REMOVE_PATH, // 19 - GAME_COMMAND_CHANGE_SURFACE_STYLE, //20 + GAME_COMMAND_SET_WATER_HEIGHT, + GAME_COMMAND_PLACE_PATH, + GAME_COMMAND_PLACE_PATH_FROM_TRACK, + GAME_COMMAND_REMOVE_PATH, + GAME_COMMAND_CHANGE_SURFACE_STYLE, GAME_COMMAND_SET_RIDE_PRICE, - GAME_COMMAND_22, //To do with text input + GAME_COMMAND_SET_PEEP_NAME, 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_SET_BRAKES_SPEED, + GAME_COMMAND_HIRE_NEW_STAFF_MEMBER, + GAME_COMMAND_SET_STAFF_PATROL, + GAME_COMMAND_FIRE_STAFF_MEMBER, + GAME_COMMAND_SET_STAFF_ORDER, GAME_COMMAND_SET_PARK_NAME, - GAME_COMMAND_SET_PARK_OPEN, // 34 - GAME_COMMAND_BUY_LAND_RIGHTS, // 35 + GAME_COMMAND_SET_PARK_OPEN, + GAME_COMMAND_BUY_LAND_RIGHTS, 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_SET_MAZE_TRACK, + GAME_COMMAND_SET_PARK_ENTRANCE_FEE, + GAME_COMMAND_SET_STAFF_COLOUR, + GAME_COMMAND_PLACE_FENCE, GAME_COMMAND_REMOVE_FENCE, GAME_COMMAND_PLACE_LARGE_SCENERY, GAME_COMMAND_REMOVE_LARGE_SCENERY, - GAME_COMMAND_SET_CURRENT_LOAN, // 45 - GAME_COMMAND_SET_RESEARCH_FUNDING, // 46 - GAME_COMMAND_PLACE_TRACK, - GAME_COMMAND_START_MARKETING_CAMPAIGN, // 48 - GAME_COMMAND_49, - GAME_COMMAND_PLACE_BANNER, // New banner? (possibly scenery) - GAME_COMMAND_REMOVE_BANNER, // Remove banner - GAME_COMMAND_52, - GAME_COMMAND_53, - GAME_COMMAND_54, - GAME_COMMAND_55, - GAME_COMMAND_56, // Set land owned (possibly does other things) - GAME_COMMAND_CLEAR_SCENERY + GAME_COMMAND_SET_CURRENT_LOAN, + GAME_COMMAND_SET_RESEARCH_FUNDING, + GAME_COMMAND_PLACE_TRACK_DESIGN, + GAME_COMMAND_START_MARKETING_CAMPAIGN, + GAME_COMMAND_PLACE_MAZE_DESIGN, + GAME_COMMAND_PLACE_BANNER, + 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_SET_LAND_OWNERSHIP, + GAME_COMMAND_CLEAR_SCENERY, + GAME_COMMAND_SET_BANNER_NAME, + GAME_COMMAND_SET_SIGN_NAME, + GAME_COMMAND_SET_BANNER_STYLE, + GAME_COMMAND_SET_SIGN_STYLE }; -// If this flag is set, the command is applied, otherwise only the cost is retrieved -#define GAME_COMMAND_FLAG_APPLY (1 << 0) +enum { + GAME_COMMAND_FLAG_APPLY = (1 << 0), // If this flag is set, the command is applied, otherwise only the cost is retrieved + GAME_COMMAND_FLAG_2 = (1 << 2), + GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED = (1 << 3), // Allow while paused + GAME_COMMAND_FLAG_4 = (1 << 4), + GAME_COMMAND_FLAG_5 = (1 << 5), + GAME_COMMAND_FLAG_GHOST = (1 << 6), + GAME_COMMAND_FLAG_7 = (1 << 7), + GAME_COMMAND_FLAG_NETWORKED = (1 << 31) // Game command is coming from network +}; + + + typedef void (GAME_COMMAND_POINTER)(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +typedef void (GAME_COMMAND_CALLBACK_POINTER)(int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp); + +extern GAME_COMMAND_CALLBACK_POINTER* game_command_callback; +int game_command_callback_get_index(GAME_COMMAND_CALLBACK_POINTER* callback); +GAME_COMMAND_CALLBACK_POINTER* game_command_callback_get_callback(int index); + extern int gGameSpeed; +extern float gDayNightCycle; +extern bool gInUpdateCode; void game_increase_game_speed(); void game_reduce_game_speed(); @@ -107,13 +132,19 @@ 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_sv6(SDL_RWops* rw); +int game_load_network(SDL_RWops* rw); int game_load_save(const char *path); +void game_load_init(); 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 save_game(); +void save_game_as(); void rct2_exit(); void rct2_exit_reason(rct_string_id title, rct_string_id body); void game_autosave(); +void game_convert_strings_to_utf8(); +void game_convert_strings_to_rct2(rct_s6_data *s6); +void game_fix_save_vars(); #endif diff --git a/src/hook.c b/src/hook.c index 6c8dd9395a..be83f39dc3 100644 --- a/src/hook.c +++ b/src/hook.c @@ -8,28 +8,35 @@ * 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 +#ifdef _WIN32 + #include +#else + #include +#endif // _WIN32 #include "hook.h" +#include "platform/platform.h" void* g_hooktableaddress = 0; int g_hooktableoffset = 0; int g_maxhooks = 1000; -void hookfunc(int address, int newaddress, int stacksize, int registerargs[], int registersreturned) +void hookfunc(int address, int newaddress, int stacksize, int registerargs[], int registersreturned, int eaxDestinationRegister) { int i = 0; char data[100]; + registersreturned |= eaxDestinationRegister; + int registerssaved = 7; int n = registersreturned; for (; n; registerssaved--) { @@ -90,7 +97,7 @@ void hookfunc(int address, int newaddress, int stacksize, int registerargs[], in data[i++] = 0x00; data[i++] = 0x00; data[i++] = 0x00; - + int sizec = i; data[i++] = 0x8B; // push eax, [esp] - puts eip in eax @@ -134,20 +141,51 @@ void hookfunc(int address, int newaddress, int stacksize, int registerargs[], in if (!(registersreturned & EDI)) { data[i++] = 0x57; // push edi } - + data[i++] = 0x83; // sub esp, x data[i++] = 0xEC; data[i++] = 4 + (stacksize * 4) + rargssize; - data[i++] = 0xEA; // jmp - *((int *)&data[i]) = newaddress; i += 4; - data[i++] = 0x23; - data[i++] = 0x00; + data[i++] = 0xE9; // jmp + *((int *)&data[i]) = (newaddress - address - i - 4); i += 4; data[sizeoffset] = i - sizec; // returnlocation: + switch (eaxDestinationRegister) { + case EBX: + // mov ebx, eax + data[i++] = 0x8B; + data[i++] = 0xD8; + break; + case ECX: + // mov ecx, eax + data[i++] = 0x8B; + data[i++] = 0xC8; + break; + case EDX: + // mov ecx, eax + data[i++] = 0x8B; + data[i++] = 0xD0; + break; + case ESI: + // mov ecx, eax + data[i++] = 0x8B; + data[i++] = 0xF0; + break; + case EDI: + // mov ecx, eax + data[i++] = 0x8B; + data[i++] = 0xF8; + break; + case EBP: + // mov ecx, eax + data[i++] = 0x8B; + data[i++] = 0xE8; + break; + } + data[i++] = 0x83; // sub esp, x data[i++] = 0xEC; data[i++] = (signed char)(stacksize * -4) - rargssize; @@ -173,16 +211,31 @@ void hookfunc(int address, int newaddress, int stacksize, int registerargs[], in if (!(registersreturned & EAX)) { data[i++] = 0x58; // pop eax } - + data[i++] = 0xC3; // retn +#ifdef _WIN32 WriteProcessMemory(GetCurrentProcess(), (LPVOID)address, data, i, 0); +#else + // We own the pages with PROT_WRITE | PROT_EXEC, we can simply just memcpy the data + memcpy((void *)address, data, i); +#endif // _WIN32 } -void addhook(int address, int newaddress, int stacksize, int registerargs[], int registersreturned) +void addhook(int address, int newaddress, int stacksize, int registerargs[], int registersreturned, int eaxDestinationRegister) { if (!g_hooktableaddress) { - g_hooktableaddress = VirtualAllocEx(GetCurrentProcess(), NULL, g_maxhooks * 100, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + size_t size = g_maxhooks * 100; +#ifdef _WIN32 + g_hooktableaddress = VirtualAllocEx(GetCurrentProcess(), NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + g_hooktableaddress = mmap(NULL, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (g_hooktableaddress == MAP_FAILED) + { + perror("mmap"); + exit(1); + } +#endif // _WIN32 } if (g_hooktableoffset > g_maxhooks) { return; @@ -190,12 +243,15 @@ void addhook(int address, int newaddress, int stacksize, int registerargs[], int unsigned int hookaddress = (unsigned int)g_hooktableaddress + (g_hooktableoffset * 100); char data[9]; int i = 0; - data[i++] = 0xEA; // jmp - *((int *)&data[i]) = hookaddress; i += 4; - data[i++] = 0x23; - data[i++] = 0x00; + data[i++] = 0xE9; // jmp + *((int *)&data[i]) = hookaddress - address - i - 4; i += 4; data[i++] = 0xC3; // retn +#ifdef _WIN32 WriteProcessMemory(GetCurrentProcess(), (LPVOID)address, data, i, 0); - hookfunc(hookaddress, newaddress, stacksize, registerargs, registersreturned); +#else + // We own the pages with PROT_WRITE | PROT_EXEC, we can simply just memcpy the data + memcpy((void *)address, data, i); +#endif // _WIN32 + hookfunc(hookaddress, newaddress, stacksize, registerargs, registersreturned, eaxDestinationRegister); g_hooktableoffset++; -} \ No newline at end of file +} diff --git a/src/hook.h b/src/hook.h index fed10792f3..7f2289f059 100644 --- a/src/hook.h +++ b/src/hook.h @@ -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 . *****************************************************************************/ @@ -32,6 +32,6 @@ enum REGISTER_ARGS { END = 0 }; -void addhook(int address, int newaddress, int stacksize, int registerargs[], int registersreturned); +void addhook(int address, int newaddress, int stacksize, int registerargs[], int registersreturned, int eaxDestinationRegister); #endif \ No newline at end of file diff --git a/src/input.c b/src/input.c index dce56db016..68fe6541a9 100644 --- a/src/input.c +++ b/src/input.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,7 @@ #include "cursors.h" #include "game.h" #include "input.h" +#include "interface/chat.h" #include "interface/console.h" #include "interface/keyboard_shortcut.h" #include "interface/viewport.h" @@ -41,11 +42,12 @@ #include "world/map.h" #include "world/sprite.h" #include "world/scenery.h" +#include "openrct2.h" static int _dragX, _dragY; static rct_windowclass _dragWindowClass; static rct_windownumber _dragWindowNumber; -static int _dragWidgetIndex; +static int _dragWidgetIndex, _dragScrollIndex; static int _originalWindowWidth, _originalWindowHeight; typedef struct { @@ -96,7 +98,7 @@ static void sub_6EA2AA(rct_window *w, int widgetIndex, int x, int y, int edi); #pragma region Mouse input /** - * + * * rct2: 0x006EA627 */ void game_handle_input() @@ -128,8 +130,8 @@ void game_handle_input() game_handle_input_mouse(x, y, state); } 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); + x = clamp(0, x, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 1); + y = clamp(0, y, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - 1); game_handle_input_mouse(x, y, state); process_mouse_over(x, y); @@ -142,7 +144,7 @@ void game_handle_input() } /** - * + * * rct2: 0x006E83C7 */ static void game_get_next_input(int *x, int *y, int *state) @@ -163,7 +165,7 @@ static void game_get_next_input(int *x, int *y, int *state) } /** - * + * * rct2: 0x00407074 */ static rct_mouse_data* get_mouse_input() @@ -178,8 +180,85 @@ static rct_mouse_data* get_mouse_input() return &mouse_buffer[read_index]; } +/* rct2: 0x006E957F + */ +static void input_scroll_drag_begin(int x, int y, rct_window* w, rct_widget* widget, int widgetIndex) { + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_SCROLL_RIGHT; + _dragX = x; + _dragY = y; + _dragWindowClass = w->classification; + _dragWindowNumber = w->number; + _dragWidgetIndex = widgetIndex; + RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_DRAG_START, sint16) = 0; + + _dragScrollIndex = window_get_scroll_data_index(w, widgetIndex); + platform_hide_cursor(); +} + +/* Based on (heavily changed) rct2: 0x006E9E0E & 0x006E9ED0 */ +static void input_scroll_drag_continue(int x, int y, rct_window* w) { + uint8 widgetIndex = _dragWidgetIndex; + uint8 scrollIndex = _dragScrollIndex; + + rct_widget* widget = &w->widgets[widgetIndex]; + rct_scroll* scroll = &w->scrolls[scrollIndex]; + + int dx, dy; + dx = x - _dragX; + dy = y - _dragY; + + if (scroll->flags & HSCROLLBAR_VISIBLE) { + sint16 size = widget->right - widget->left - 1; + if (scroll->flags & VSCROLLBAR_VISIBLE) + size -= 11; + size = max(0, scroll->h_right - size); + scroll->h_left = min(max(0, scroll->h_left + dx), size); + } + + if (scroll->flags & VSCROLLBAR_VISIBLE) { + sint16 size = widget->bottom - widget->top - 1; + if (scroll->flags & HSCROLLBAR_VISIBLE) + size -= 11; + size = max(0, scroll->v_bottom - size); + scroll->v_top = min(max(0, scroll->v_top + dy), size); + } + + widget_scroll_update_thumbs(w, widgetIndex); + window_invalidate_by_number(w->classification, w->number); + platform_set_cursor_position(_dragX, _dragY); +} + +/* rct2: 0x006E8ACB*/ +static void input_scroll_right(int x, int y, int state) { + rct_window* w = window_find_by_number( + _dragWindowClass, + _dragWindowNumber + ); + + if (w == NULL) { + platform_show_cursor(); + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESET; + return; + } + + switch (state) { + case 0: + RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_DRAG_START, sint16) += RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_LAST_UPDATE, sint16); + if (x == 0 && y == 0) + return; + RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_DRAG_START, sint16) = 1000; + + input_scroll_drag_continue(x, y, w); + break; + case 4: + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESET; + platform_show_cursor(); + break; + } +} + /** - * + * * rct2: 0x006E8655 */ static void game_handle_input_mouse(int x, int y, int state) @@ -219,7 +298,7 @@ static void game_handle_input_mouse(int x, int y, int state) input_viewport_drag_begin(w, x, y); } else if (widget->type == WWT_SCROLL) { - + input_scroll_drag_begin(x, y, w, widget, widgetIndex); } break; } @@ -245,7 +324,8 @@ static void game_handle_input_mouse(int x, int y, int state) } else if (state == 4) { input_viewport_drag_end(); - if (RCT2_GLOBAL(0x009DE540, sint16) < 500) { + if (RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_DRAG_START, sint16) < 500) { + // If the user pressed the right mouse button for less than 500 ticks, interpret as right click viewport_interaction_right_click(x, y); } } @@ -322,12 +402,12 @@ static void game_handle_input_mouse(int x, int y, int state) input_window_resize_continue(w, x, y); } break; - case 9: - RCT2_CALLPROC_X(0x006E8ACB, x, y, state, widgetIndex, (int)w, (int)widget, 0); + case INPUT_STATE_SCROLL_RIGHT: + input_scroll_right(x, y, state); break; } } - + #pragma region Window positioning / resizing void input_window_position_begin(rct_window *w, int widgetIndex, int x, int y) @@ -407,7 +487,7 @@ static void input_viewport_drag_begin(rct_window *w, int x, int y) RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_VIEWPORT_RIGHT; _dragWindowClass = w->classification; _dragWindowNumber = w->number; - RCT2_GLOBAL(0x009DE540, sint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_DRAG_START, sint16) = 0; platform_get_cursor_position(&_dragX, &_dragY); platform_hide_cursor(); @@ -425,19 +505,30 @@ static void input_viewport_drag_continue() dx = newDragX - _dragX; dy = newDragY - _dragY; w = window_find_by_number(_dragWindowClass, _dragWindowNumber); + assert(w != NULL); viewport = w->viewport; - RCT2_GLOBAL(0x009DE540, sint16) += RCT2_GLOBAL(0x009DE588, sint16); + RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_DRAG_START, sint16) += RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_LAST_UPDATE, sint16); if (viewport == NULL) { platform_show_cursor(); RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESET; } else if (dx != 0 || dy != 0) { - if (!(w->flags & (1 << 2))) { - RCT2_GLOBAL(0x009DE540, sint16) = 1000; + if (!(w->flags & WF_NO_SCROLLING)) { + // User dragged a scrollable viewport + + // If the drag time is less than 500 the "drag" is usually interpreted as a right click. + // As the user moved the mouse, don't interpret it as right click in any case. + RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_DRAG_START, sint16) = 1000; + dx <<= viewport->zoom + 1; dy <<= viewport->zoom + 1; - w->saved_view_x += dx; - w->saved_view_y += dy; + if (gConfigGeneral.invert_viewport_drag){ + w->saved_view_x -= dx; + w->saved_view_y -= dy; + } else { + w->saved_view_x += dx; + w->saved_view_y += dy; + } } } @@ -499,7 +590,7 @@ static void input_scroll_begin(rct_window *w, int widgetIndex, int x, int y) case SCROLL_PART_HSCROLLBAR_RIGHT: scroll->h_left = min(scroll->h_left + 3, widget_width); break; - case SCROLL_PART_HSCROLLBAR_LEFT_TROUGH: + case SCROLL_PART_HSCROLLBAR_LEFT_TROUGH: scroll->h_left = max(scroll->h_left - widget_width , 0); break; case SCROLL_PART_HSCROLLBAR_RIGHT_TROUGH: @@ -528,6 +619,9 @@ static void input_scroll_continue(rct_window *w, int widgetIndex, int state, int { rct_widget *widget; int scroll_part, scroll_id; + int x2, y2; + + assert(w != NULL); widget = &w->widgets[widgetIndex]; if (widgetIndex != RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint32)){ @@ -542,9 +636,9 @@ 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); - + + widget_scroll_get_part(w, widget, x, y, &x2, &y2, &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); @@ -561,6 +655,9 @@ static void input_scroll_continue(rct_window *w, int widgetIndex, int state, int return; } + x = x2; + y = y2; + if (scroll_part != RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_AREA, uint16)){ invalidate_scroll(); return; @@ -568,7 +665,7 @@ static void input_scroll_continue(rct_window *w, int widgetIndex, int state, int switch (scroll_part){ case SCROLL_PART_VIEW: - window_event_tool_drag_call(w, widgetIndex, w->number / 18, y); + window_event_scroll_mousedrag_call(w, scroll_id, x, y); break; case SCROLL_PART_HSCROLLBAR_LEFT: input_scroll_part_update_hleft(w, widgetIndex, scroll_id); @@ -645,6 +742,7 @@ static void input_scroll_part_update_hthumb(rct_window *w, int widgetIndex, int */ static void input_scroll_part_update_vthumb(rct_window *w, int widgetIndex, int y, int scroll_id) { + assert(w != NULL); rct_widget *widget = &w->widgets[widgetIndex]; int newTop; @@ -682,11 +780,13 @@ static void input_scroll_part_update_vthumb(rct_window *w, int widgetIndex, int */ static void input_scroll_part_update_hleft(rct_window *w, int widgetIndex, int scroll_id) { + assert(w != NULL); 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; + else if (w->scrolls[scroll_id].h_left >= 3) + w->scrolls[scroll_id].h_left -= 3; widget_scroll_update_thumbs(w, widgetIndex); widget_invalidate_by_number(w->classification, w->number, widgetIndex); } @@ -698,6 +798,7 @@ static void input_scroll_part_update_hleft(rct_window *w, int widgetIndex, int s */ static void input_scroll_part_update_hright(rct_window *w, int widgetIndex, int scroll_id) { + assert(w != NULL); rct_widget *widget = &w->widgets[widgetIndex]; if (window_find_by_number(w->classification, w->number)) { w->scrolls[scroll_id].flags |= HSCROLLBAR_RIGHT_PRESSED; @@ -721,12 +822,14 @@ static void input_scroll_part_update_hright(rct_window *w, int widgetIndex, int * rct: 0x006E9C37 */ static void input_scroll_part_update_vtop(rct_window *w, int widgetIndex, int scroll_id) -{; +{ + assert(w != NULL); 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; + else if (w->scrolls[scroll_id].v_top >= 3) + w->scrolls[scroll_id].v_top -= 3; widget_scroll_update_thumbs(w, widgetIndex); widget_invalidate_by_number(w->classification, w->number, widgetIndex); } @@ -738,6 +841,7 @@ static void input_scroll_part_update_vtop(rct_window *w, int widgetIndex, int sc */ static void input_scroll_part_update_vbottom(rct_window *w, int widgetIndex, int scroll_id) { + assert(w != NULL); rct_widget *widget = &w->widgets[widgetIndex]; if (window_find_by_number(w->classification, w->number)) { w->scrolls[scroll_id].flags |= VSCROLLBAR_DOWN_PRESSED; @@ -761,7 +865,7 @@ static void input_scroll_part_update_vbottom(rct_window *w, int widgetIndex, int #pragma region Widgets /** - * + * * rct2: 0x006E9253 */ static void input_widget_over(int x, int y, rct_window *w, int widgetIndex) @@ -799,7 +903,7 @@ static void input_widget_over(int x, int y, rct_window *w, int widgetIndex) } /** - * + * * rct2: 0x006E9269 */ static void input_widget_over_change_check(rct_windowclass windowClass, rct_windownumber windowNumber, int widgetIndex) @@ -852,7 +956,7 @@ static void input_widget_over_flatbutton_invalidate() } /** - * + * * rct2: 0x006E95F9 */ static void input_widget_left(int x, int y, rct_window *w, int widgetIndex) @@ -917,7 +1021,7 @@ static void input_widget_left(int x, int y, rct_window *w, int widgetIndex) break; default: if (widget_is_enabled(w, widgetIndex) && !widget_is_disabled(w, widgetIndex)) { - sound_play_panned(SOUND_CLICK_1, w->x + (widget->left + widget->right) / 2, 0, 0, 0); + audio_play_sound_panned(SOUND_CLICK_1, w->x + (widget->left + widget->right) / 2, 0, 0, 0); // Set new cursor down widget RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, rct_windowclass) = windowClass; @@ -937,7 +1041,7 @@ 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) @@ -947,10 +1051,10 @@ void process_mouse_over(int x, int y) int widgetId; int cursorId; - int eax, ebx, ecx, edx, esi, edi, ebp; + int ebx, esi, edi, ebp; cursorId = CURSOR_ARROW; - RCT2_GLOBAL(0x9A9808, sint16) = -1; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS, sint16) = -1; window = window_find_from_point(x, y); if (window != NULL) { @@ -979,7 +1083,8 @@ void process_mouse_over(int x, int y) ebx = ebx & 0xFFFFFF00; edi = cursorId; esi = (int)subWindow; - RCT2_CALLFUNC_X(subWindow->event_handlers[WE_UNKNOWN_0E], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + // Not sure what this is for, no windows actually implement a handler + // RCT2_CALLFUNC_X(subWindow->event_handlers[WE_UNKNOWN_0E], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); cursorId = edi; if ((ebx & 0xFF) != 0) { @@ -1009,14 +1114,19 @@ void process_mouse_over(int x, int y) RCT2_GLOBAL(0x9DE558, uint16) = x; RCT2_GLOBAL(0x9DE55A, uint16) = y; int output_scroll_area, scroll_id; - widget_scroll_get_part(window, window->widgets, x, y, &x, &y, &output_scroll_area, &scroll_id); + int scroll_x, scroll_y; + widget_scroll_get_part(window, &window->widgets[widgetId], x, y, &scroll_x, &scroll_y, &output_scroll_area, &scroll_id); cursorId = scroll_id; if (output_scroll_area != SCROLL_PART_VIEW) { cursorId = CURSOR_ARROW; break; } - //Fall through to default + // Same as default but with scroll_x/y + cursorId = window_event_cursor_call(window, widgetId, scroll_x, scroll_y); + if (cursorId == -1) + cursorId = CURSOR_ARROW; + break; default: cursorId = window_event_cursor_call(window, widgetId, x, y); if (cursorId == -1) @@ -1052,7 +1162,7 @@ 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) @@ -1103,13 +1213,17 @@ void input_state_widget_pressed(int x, int y, int state, int widgetIndex, rct_wi if (w->classification == WC_DROPDOWN) { dropdown_index = dropdown_index_from_point(x, y, w); - if (dropdown_index == -1)goto dropdown_cleanup; + if (dropdown_index == -1) { + goto dropdown_cleanup; + } - // _dropdown_unknown?? highlighted? - if (dropdown_index < 32 && RCT2_GLOBAL(0x009DED34, sint32) & (1 << dropdown_index))goto dropdown_cleanup; + if (dropdown_index < 64 && gDropdownItemsDisabled & (1ULL << dropdown_index)) { + goto dropdown_cleanup; + } - // gDropdownItemsFormat[dropdown_index] will not work until all windows that use dropdown decompiled - if (RCT2_ADDRESS(0x9DEBA4, uint16)[dropdown_index] == 0)goto dropdown_cleanup; + if (gDropdownItemsFormat[dropdown_index] == 0) { + goto dropdown_cleanup; + } } else { if (cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) @@ -1153,7 +1267,7 @@ void input_state_widget_pressed(int x, int y, int state, int widgetIndex, rct_wi break; int mid_point_x = (widget->left + widget->right) / 2 + w->x; - sound_play_panned(5, mid_point_x, 0, 0, 0); + audio_play_sound_panned(5, mid_point_x, 0, 0, 0); if (cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) break; @@ -1183,15 +1297,25 @@ void input_state_widget_pressed(int x, int y, int state, int widgetIndex, rct_wi if (dropdown_index == -1) return; - // _dropdown_unknown?? highlighted? - if (dropdown_index < 32 && RCT2_GLOBAL(0x009DED34, sint32) & (1 << dropdown_index))return; + if (gDropdownIsColour && gDropdownLastColourHover != dropdown_index) { + gDropdownLastColourHover = dropdown_index; + window_tooltip_close(); + window_tooltip_show(STR_COLOUR_NAMES_START + dropdown_index, x, y); + } - // gDropdownItemsFormat[dropdown_index] will not work until all windows that use dropdown decompiled - if (RCT2_ADDRESS(0x9DEBA4, uint16)[dropdown_index] == 0)return; + if (dropdown_index < 64 && gDropdownItemsDisabled & (1ULL << dropdown_index)) { + return; + } - // _dropdown_highlighted_index - RCT2_GLOBAL(0x009DEBA2, sint16) = dropdown_index; + if (gDropdownItemsFormat[dropdown_index] == 0) { + return; + } + + gDropdownHighlightedIndex = dropdown_index; window_invalidate_by_class(WC_DROPDOWN); + } else { + gDropdownLastColourHover = -1; + window_tooltip_close(); } } @@ -1202,7 +1326,7 @@ static void input_update_tooltip(rct_window *w, int widgetIndex, int x, int y) (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); + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_LAST_UPDATE, uint16); int bp = 2000; if (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, uint16) >= 1) @@ -1216,13 +1340,14 @@ static void input_update_tooltip(rct_window *w, int widgetIndex, int x, int y) } } else { - if (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) != w->classification || - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) != w->number || + if (((w != NULL) && + (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); + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) += RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_LAST_UPDATE, uint16); if (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) < 8000) return; window_close_by_class(WC_TOOLTIP); @@ -1236,7 +1361,7 @@ static void input_update_tooltip(rct_window *w, int widgetIndex, int x, int y) #pragma region Keyboard input /** - * + * * rct2: 0x006E3B43 */ void title_handle_keyboard_input() @@ -1244,21 +1369,39 @@ void title_handle_keyboard_input() rct_window *w; int key; - // 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 (gOpenRCT2Headless) { + return; + } + + if (!gConsoleOpen) { + // 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; + } } while ((key = get_next_key()) != 0) { 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); @@ -1272,7 +1415,7 @@ void title_handle_keyboard_input() } /** - * + * * rct2: 0x006E3B43 */ void game_handle_keyboard_input() @@ -1304,7 +1447,7 @@ void game_handle_keyboard_input() // Handle key input - while ((key = get_next_key()) != 0) { + while (!gOpenRCT2Headless && (key = get_next_key()) != 0) { if (key == 255) continue; @@ -1318,6 +1461,9 @@ void game_handle_keyboard_input() } else if (gConsoleOpen) { console_input(key); continue; + } else if (gChatOpen) { + chat_input(key); + continue; } key |= RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) << 8; @@ -1331,10 +1477,9 @@ void game_handle_keyboard_input() } else { w = window_find_by_class(WC_TEXTINPUT); - if (w != NULL){ - ((void(*)(int, rct_window*))w->event_handlers[WE_TEXT_INPUT])(key, w); - } - else if (!gUsingWidgetTextBox) { + if (w != NULL) { + window_text_input_key(w, key); + } else if (!gUsingWidgetTextBox) { keyboard_shortcut_handle(key); } } @@ -1403,7 +1548,7 @@ static void sub_6EA2AA(rct_window *w, int widgetIndex, int x, int y, int edi) int numLines, fontHeight; gfx_wrap_string(buffer, width + 1, &numLines, &fontHeight); - RCT2_GLOBAL(0x01420044, uint16) = numLines; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TEXT_HEIGHT, uint16) = numLines; tooltipWindow->widgets[0].right = width + 3; tooltipWindow->widgets[0].bottom = ((numLines + 1) * 10) + 4; @@ -1414,7 +1559,7 @@ static void sub_6EA2AA(rct_window *w, int widgetIndex, int x, int y, int edi) } /** - * + * * rct2: 0x00406CD2 */ int get_next_key() @@ -1455,7 +1600,7 @@ void sub_6ED990(char cursor_id){ /** - * + * * rct2: 0x006E876D */ void invalidate_scroll() @@ -1504,7 +1649,7 @@ void game_handle_edge_scroll() mainWindow = window_get_main(); if (mainWindow == NULL) return; - if ((mainWindow->flags & WF_2) || (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 9)) + if ((mainWindow->flags & WF_NO_SCROLLING) || (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 9)) return; if (mainWindow->viewport == NULL) return; @@ -1547,7 +1692,7 @@ void game_handle_key_scroll() mainWindow = window_get_main(); if (mainWindow == NULL) return; - if ((mainWindow->flags & WF_2) || (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 9)) + if ((mainWindow->flags & WF_NO_SCROLLING) || (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 9)) return; if (mainWindow->viewport == NULL) return; @@ -1560,17 +1705,42 @@ void game_handle_key_scroll() scrollX = 0; scrollY = 0; - // Scroll left / right - if (gKeysState[SDL_SCANCODE_LEFT]) - scrollX = -1; - else if (gKeysState[SDL_SCANCODE_RIGHT]) - scrollX = 1; + for (int shortcutId = SHORTCUT_SCROLL_MAP_UP; shortcutId <= SHORTCUT_SCROLL_MAP_RIGHT; shortcutId++) { + const int SHIFT = 0x100; + const int CTRL = 0x200; + const int ALT = 0x400; - // Scroll up / down - if (gKeysState[SDL_SCANCODE_UP]) - scrollY = -1; - else if (gKeysState[SDL_SCANCODE_DOWN]) - scrollY = 1; + uint16 shortcutKey = gShortcutKeys[shortcutId]; + uint8 scancode = shortcutKey & 0xFF; + + if (shortcutKey == 0xFFFF) continue; + if (!gKeysState[scancode]) continue; + + if (shortcutKey & SHIFT) { + if (!gKeysState[SDL_SCANCODE_LSHIFT] && !gKeysState[SDL_SCANCODE_RSHIFT]) continue; + } + if (shortcutKey & CTRL) { + if (!gKeysState[SDL_SCANCODE_LCTRL] && !gKeysState[SDL_SCANCODE_RCTRL]) continue; + } + if (shortcutKey & ALT) { + if (!gKeysState[SDL_SCANCODE_LALT] && !gKeysState[SDL_SCANCODE_RALT]) continue; + } + + switch (shortcutId) { + case SHORTCUT_SCROLL_MAP_UP: + scrollY = -1; + break; + case SHORTCUT_SCROLL_MAP_LEFT: + scrollX = -1; + break; + case SHORTCUT_SCROLL_MAP_DOWN: + scrollY = 1; + break; + case SHORTCUT_SCROLL_MAP_RIGHT: + scrollX = 1; + break; + } + } // Scroll viewport if (scrollX != 0) { @@ -1600,4 +1770,4 @@ static void update_cursor_position() // write tutorial cursor position break; } -} \ No newline at end of file +} diff --git a/src/input.h b/src/input.h index 3d36382961..493b0faaa7 100644 --- a/src/input.h +++ b/src/input.h @@ -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 . *****************************************************************************/ diff --git a/src/interface/chat.c b/src/interface/chat.c new file mode 100644 index 0000000000..eb656b22eb --- /dev/null +++ b/src/interface/chat.c @@ -0,0 +1,141 @@ +#include "../addresses.h" +#include "../audio/audio.h" +#include "../audio/mixer.h" +#include "../localisation/localisation.h" +#include "../network/network.h" +#include "../platform/platform.h" +#include "chat.h" +#include "../util/util.h" + +#define CHAT_HISTORY_SIZE 10 +#define CHAT_INPUT_SIZE 256 + +bool gChatOpen = false; +char _chatCurrentLine[CHAT_INPUT_SIZE]; +char _chatHistory[CHAT_HISTORY_SIZE][CHAT_INPUT_SIZE]; +uint32 _chatHistoryTime[CHAT_HISTORY_SIZE]; +unsigned int _chatHistoryIndex = 0; +uint32 _chatCaretTicks = 0; +int _chatLeft; +int _chatTop; +int _chatRight; +int _chatBottom; + +static const char* chat_history_get(unsigned int index); +static uint32 chat_history_get_time(unsigned int index); +static void chat_clear_input(); + +void chat_open() +{ + gChatOpen = true; + platform_start_text_input(_chatCurrentLine, sizeof(_chatCurrentLine)); +} + +void chat_close() +{ + gChatOpen = false; + platform_stop_text_input(); +} + +void chat_toggle() +{ + if (gChatOpen) { + chat_close(); + } else { + chat_open(); + } +} + +void chat_init() +{ + memset(_chatHistory, 0, sizeof(_chatHistory)); + memset(_chatHistoryTime, 0, sizeof(_chatHistoryTime)); +} + +void chat_update() +{ + // Flash the caret + _chatCaretTicks = (_chatCaretTicks + 1) % 30; +} + +void chat_draw() +{ + if (network_get_mode() == NETWORK_MODE_NONE || network_get_status() != NETWORK_STATUS_CONNECTED || network_get_authstatus() != NETWORK_AUTH_OK) { + gChatOpen = false; + return; + } + rct_drawpixelinfo *dpi = (rct_drawpixelinfo*)RCT2_ADDRESS_SCREEN_DPI; + _chatLeft = 10; + _chatTop = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - 40 - ((CHAT_HISTORY_SIZE + 1) * 10); + _chatRight = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 10; + _chatBottom = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - 40; + char lineBuffer[CHAT_INPUT_SIZE + 10]; + char* lineCh = lineBuffer; + int x = _chatLeft; + int y = _chatBottom - (10 * 2); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; + for (int i = 0; i < CHAT_HISTORY_SIZE; i++, y -= 10) { + if (!gChatOpen && SDL_TICKS_PASSED(SDL_GetTicks(), chat_history_get_time(i) + 10000)) { + break; + } + safe_strncpy(lineBuffer, chat_history_get(i), CHAT_INPUT_SIZE + 10); + gfx_set_dirty_blocks(x, y, x + gfx_get_string_width(lineBuffer), y + 12); + gfx_draw_string(dpi, lineBuffer, 255, x, y); + } + if (gChatOpen) { + lineCh = utf8_write_codepoint(lineCh, FORMAT_OUTLINE); + lineCh = utf8_write_codepoint(lineCh, FORMAT_CELADON); + safe_strncpy(lineCh, _chatCurrentLine, CHAT_INPUT_SIZE); + y = _chatBottom - 10; + gfx_set_dirty_blocks(x, y, x + gfx_get_string_width(lineBuffer) + 7, y + 12); + if (_chatCaretTicks < 15) { + int caretX = x + gfx_get_string_width(lineBuffer); + int caretY = y + 10; + + gfx_fill_rect(dpi, caretX, caretY, caretX + 6, caretY + 1, 0x38); + } + gfx_draw_string(dpi, lineBuffer, 255, x, y); + } +} + +void chat_history_add(const char *src) +{ + int index = _chatHistoryIndex % CHAT_HISTORY_SIZE; + memset(_chatHistory[index], 0, CHAT_INPUT_SIZE); + memcpy(_chatHistory[index], src, min(strlen(src), CHAT_INPUT_SIZE - 1)); + _chatHistoryTime[index] = SDL_GetTicks(); + _chatHistoryIndex++; + Mixer_Play_Effect(SOUND_NEWS_ITEM, 0, SDL_MIX_MAXVOLUME, 0, 1.5f, true); +} + +void chat_input(int c) +{ + switch (c) { + case SDL_SCANCODE_RETURN: + if (strlen(_chatCurrentLine) > 0) { + network_send_chat(_chatCurrentLine); + } + chat_clear_input(); + chat_close(); + break; + case SDL_SCANCODE_ESCAPE: + chat_close(); + break; + } +} + +static const char* chat_history_get(unsigned int index) +{ + return _chatHistory[(_chatHistoryIndex + CHAT_HISTORY_SIZE - index - 1) % CHAT_HISTORY_SIZE]; +} + +static uint32 chat_history_get_time(unsigned int index) +{ + return _chatHistoryTime[(_chatHistoryIndex + CHAT_HISTORY_SIZE - index - 1) % CHAT_HISTORY_SIZE]; +} + +static void chat_clear_input() +{ + _chatCurrentLine[0] = 0; +} diff --git a/src/interface/chat.h b/src/interface/chat.h new file mode 100644 index 0000000000..b288558b00 --- /dev/null +++ b/src/interface/chat.h @@ -0,0 +1,21 @@ +#ifndef _CHAT_H_ +#define _CHAT_H_ + +#include "../common.h" +#include "../drawing/drawing.h" + +extern bool gChatOpen; + +void chat_open(); +void chat_close(); +void chat_toggle(); + +void chat_init(); +void chat_update(); +void chat_draw(); + +void chat_history_add(const char *src); +void chat_input(int c); + + +#endif \ No newline at end of file diff --git a/src/interface/colour.c b/src/interface/colour.c new file mode 100644 index 0000000000..7a880c4062 --- /dev/null +++ b/src/interface/colour.c @@ -0,0 +1,25 @@ +#include "../drawing/drawing.h" +#include "colour.h" + +rct_colour_map_a *ColourMapA = (rct_colour_map_a*)0x0141FC44; +rct_colour_map_b *ColourMapB = (rct_colour_map_b*)0x0141FD44; + +void colours_init_maps() +{ + // Get colour maps from g1 + for (int i = 0; i < 32; i++) { + rct_g1_element *g1Element = &g1Elements[4915 + i]; + + uint8 *dstA = (uint8*)&ColourMapA[i]; + uint8 *dstB = (uint8*)&ColourMapB[i]; + for (int j = 0; j < 4; j++) { + dstA[j] = g1Element->offset[0xF5 + j]; + } + for (int j = 0; j < 4; j++) { + dstA[j + 4] = g1Element->offset[0xF9 + j]; + } + for (int j = 0; j < 4; j++) { + dstB[j] = g1Element->offset[0xFD + j]; + } + } +} diff --git a/src/interface/colour.h b/src/interface/colour.h new file mode 100644 index 0000000000..5cb9b3bc84 --- /dev/null +++ b/src/interface/colour.h @@ -0,0 +1,84 @@ +#ifndef _COLOUR_H_ +#define _COLOUR_H_ + +#include "../common.h" + +/** + * Colour IDs as used by the colour dropdown, NOT palette indices. + */ +enum { + COLOUR_BLACK, + COLOUR_GREY, + COLOUR_WHITE, + COLOUR_DARK_PURPLE, + COLOUR_LIGHT_PURPLE, + COLOUR_BRIGHT_PURPLE, + COLOUR_DARK_BLUE, + COLOUR_LIGHT_BLUE, + COLOUR_ICY_BLUE, + COLOUR_TEAL, + COLOUR_AQUAMARINE, + COLOUR_SATURATED_GREEN, + COLOUR_DARK_GREEN, + COLOUR_MOSS_GREEN, + COLOUR_BRIGHT_GREEN, + COLOUR_OLIVE_GREEN, + COLOUR_DARK_OLIVE_GREEN, + COLOUR_BRIGHT_YELLOW, + COLOUR_YELLOW, + COLOUR_DARK_YELLOW, + COLOUR_LIGHT_ORANGE, + COLOUR_DARK_ORANGE, + COLOUR_LIGHT_BROWN, + COLOUR_SATURATED_BROWN, + COLOUR_DARK_BROWN, + COLOUR_SALMON_PINK, + COLOUR_BORDEAUX_RED, + COLOUR_SATURATED_RED, + COLOUR_BRIGHT_RED, + COLOUR_DARK_PINK, + COLOUR_BRIGHT_PINK, + COLOUR_LIGHT_PINK +}; + +/** + * These colours change depending on the current water colours. + */ +enum { + COLOUR_DARK_WATER = 9, + COLOUR_LIGHT_WATER = 10 +}; + +#define COLOUR_FLAG_TRANSLUCENT (1 << 7) +#define TRANSLUCENT(x) ((x) | COLOUR_FLAG_TRANSLUCENT) + +#define NUM_COLOURS 32 + +typedef struct { + uint8 darkest; + uint8 darker; + uint8 dark; + uint8 mid_dark; + uint8 mid_light; + uint8 light; + uint8 lighter; + uint8 lightest; +} rct_colour_map_a; + +typedef struct { + uint8 a; + uint8 b; + uint8 c; + uint8 d; + uint8 e; + uint8 f; + uint8 g; + uint8 h; +} rct_colour_map_b; + +extern rct_colour_map_a *ColourMapA; +extern rct_colour_map_b *ColourMapB; + +void colours_init_maps(); + +#endif \ No newline at end of file diff --git a/src/interface/console.c b/src/interface/console.c index 92a0708383..730e30c94c 100644 --- a/src/interface/console.c +++ b/src/interface/console.c @@ -4,6 +4,7 @@ #include "../addresses.h" #include "../drawing/drawing.h" #include "../localisation/localisation.h" +#include "../localisation/user.h" #include "../platform/platform.h" #include "../world/park.h" #include "../util/sawyercoding.h" @@ -13,10 +14,13 @@ #include "../input.h" #include "../network/twitch.h" #include "../object.h" +#include "../world/banner.h" #include "../world/scenery.h" #include "../management/research.h" +#include "../util/util.h" #include "console.h" #include "window.h" +#include "viewport.h" #define CONSOLE_BUFFER_SIZE 8192 #define CONSOLE_BUFFER_2_SIZE 256 @@ -28,17 +32,17 @@ 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 utf8 _consoleBuffer[CONSOLE_BUFFER_SIZE] = { 0 }; +static utf8 *_consoleBufferPointer = _consoleBuffer; +static utf8 *_consoleViewBufferStart = _consoleBuffer; +static utf8 _consoleCurrentLine[CONSOLE_INPUT_SIZE]; +static utf8 *_consoleCurrentLinePointer = _consoleCurrentLine; static int _consoleCaretTicks; -static char _consolePrintfBuffer[CONSOLE_BUFFER_2_SIZE]; -static char _consoleErrorBuffer[CONSOLE_BUFFER_2_SIZE]; +static utf8 _consolePrintfBuffer[CONSOLE_BUFFER_2_SIZE]; +static utf8 _consoleErrorBuffer[CONSOLE_BUFFER_2_SIZE]; static int _consoleScrollPos = 0; -static char _consoleHistory[CONSOLE_HISTORY_SIZE][CONSOLE_INPUT_SIZE]; +static utf8 _consoleHistory[CONSOLE_HISTORY_SIZE][CONSOLE_INPUT_SIZE]; static int _consoleHistoryIndex = 0; static int _consoleHistoryCount = 0; @@ -46,14 +50,16 @@ 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_history_add(const utf8 *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 console_parse_int(const utf8 *src, bool *valid); +static double console_parse_double(const utf8 *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); +static int cc_variables(const utf8 **argv, int argc); +static int cc_windows(const utf8 **argv, int argc); +static int cc_help(const utf8 **argv, int argc); + +static bool invalidArguments(bool *invalid, bool arguments); #define SET_FLAG(variable, flag, value) {if (value) variable |= flag; else variable &= ~flag;} @@ -85,6 +91,7 @@ void console_init() { _consoleInitialised = true; console_writeline(OPENRCT2_NAME " " OPENRCT2_VERSION); + console_writeline("Type 'help' for a list of available commands. Type 'hide' to hide the console."); console_writeline(""); console_write_prompt(); } @@ -96,7 +103,7 @@ void console_update() _consoleLeft = 0; _consoleTop = 0; - _consoleRight = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); + _consoleRight = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); _consoleBottom = 322; if (gConsoleOpen) { @@ -117,12 +124,7 @@ void console_update() } // Remove unwated characters in console input - unsigned char *ch = (unsigned char*)_consoleCurrentLine; - while (*ch != 0) { - if (*ch < 32 || *ch > 126) - *ch = ' '; - ch++; - } + utf8_remove_format_codes(_consoleCurrentLine); } // Flash the caret @@ -133,33 +135,35 @@ void console_draw(rct_drawpixelinfo *dpi) { if (!gConsoleOpen) return; + + // Set font + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = (gConfigInterface.console_small_font ? FONT_SPRITE_BASE_SMALL : FONT_SPRITE_BASE_MEDIUM); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; + int lineHeight = font_get_line_height(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16)); + int lines = 0; - int maxLines = ((_consoleBottom - 22 - _consoleTop) / 10) - 1; - char *ch = strchr(_consoleBuffer, 0); + int maxLines = ((_consoleBottom - 22 - _consoleTop) / lineHeight) - 1; + utf8 *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]; + utf8 lineBuffer[2 + 256], *lineCh; ch = _consoleViewBufferStart; int currentLine = 0; int drawLines = 0; while (*ch != 0) { // Find line break or null terminator - char *nextLine = ch; + utf8 *nextLine = ch; while (*nextLine != 0 && *nextLine != '\n') { nextLine++; } @@ -169,7 +173,7 @@ void console_draw(rct_drawpixelinfo *dpi) if (*nextLine == '\n') { ch = nextLine + 1; x = _consoleLeft + 4; - //y += 10; + // y += lineHeight; } else { break; @@ -181,10 +185,11 @@ void console_draw(rct_drawpixelinfo *dpi) break; drawLines++; - int lineLength = min(sizeof(lineBuffer) - 1, nextLine - ch); - strncpy(lineBuffer + 1, ch, lineLength); - lineBuffer[0] = FORMAT_GREEN; - lineBuffer[1 + lineLength] = 0; + int lineLength = min(sizeof(lineBuffer) - (size_t)utf8_get_codepoint_length(FORMAT_GREEN), (size_t)(nextLine - ch)); + lineCh = lineBuffer; + lineCh = utf8_write_codepoint(lineCh, FORMAT_GREEN); + strncpy(lineCh, ch, lineLength); + lineCh[lineLength] = 0; gfx_draw_string(dpi, lineBuffer, 255, x, y); @@ -193,16 +198,18 @@ void console_draw(rct_drawpixelinfo *dpi) if (*nextLine == '\n') { ch = nextLine + 1; x = _consoleLeft + 4; - y += 10; + y += lineHeight; } else { break; } } x = _consoleLeft + 4; y = _consoleBottom - 15; + // Draw current line - strcpy(lineBuffer + 1, _consoleCurrentLine); - lineBuffer[0] = FORMAT_GREEN; + lineCh = lineBuffer; + lineCh = utf8_write_codepoint(lineCh, FORMAT_GREEN); + strcpy(lineCh, _consoleCurrentLine); gfx_draw_string(dpi, lineBuffer, 255, x, y); // Draw caret @@ -210,7 +217,7 @@ void console_draw(rct_drawpixelinfo *dpi) memcpy(lineBuffer, _consoleCurrentLine, gTextInputCursorPosition); lineBuffer[gTextInputCursorPosition] = 0; int caretX = x + gfx_get_string_width(lineBuffer); - int caretY = y + 10; + int caretY = y + lineHeight; gfx_fill_rect(dpi, caretX, caretY, caretX + 6, caretY + 1, FORMAT_GREEN); } @@ -269,7 +276,7 @@ static void console_write_prompt() console_write("> "); } -void console_write(const char *src) +void console_write(const utf8 *src) { int charactersRemainingInBuffer = CONSOLE_BUFFER_SIZE - (_consoleBufferPointer - _consoleBuffer) - 1; int charactersToWrite = strlen(src); @@ -283,46 +290,46 @@ void console_write(const char *src) console_update_scroll(); } -void console_writeline(const char *src) +void console_writeline(const utf8 *src) { console_write(src); console_write("\n"); } -void console_writeline_error(const char *src) +void console_writeline_error(const utf8 *src) { strcpy(_consoleErrorBuffer + 1, src); _consoleErrorBuffer[0] = FORMAT_RED; console_writeline(_consoleErrorBuffer); } -void console_writeline_warning(const char *src) +void console_writeline_warning(const utf8 *src) { strcpy(_consoleErrorBuffer + 1, src); _consoleErrorBuffer[0] = FORMAT_YELLOW; console_writeline(_consoleErrorBuffer); } -void console_printf(const char *format, ...) +void console_printf(const utf8 *format, ...) { va_list list; va_start(list, format); - vsprintf(_consolePrintfBuffer, format, list); + va_end(list); console_writeline(_consolePrintfBuffer); } -int console_parse_int(const char *src, bool *valid) { - char *end; +int console_parse_int(const utf8 *src, bool *valid) { + utf8 *end; int value; - value = strtol(src, &end, 10); *valid &= (*end == '\0'); + value = strtol(src, &end, 10); *valid = (*end == '\0'); return value; } -double console_parse_double(const char *src, bool *valid) { - char *end; +double console_parse_double(const utf8 *src, bool *valid) { + utf8 *end; double value; - value = strtod(src, &end); *valid &= (*end == '\0'); + value = strtod(src, &end); *valid = (*end == '\0'); return value; } @@ -347,7 +354,7 @@ void console_scroll(int delta) int speed = 3; int lines = 0; int maxLines = ((_consoleBottom - 22 - _consoleTop) / 10) - 1; - char *ch = strchr(_consoleBuffer, 0); + utf8 *ch = strchr(_consoleBuffer, 0); while (ch > _consoleBuffer) { ch--; if (*ch == '\n') @@ -386,7 +393,7 @@ static void console_clear_input() gTextInputLength = 0; } -static void console_history_add(const char *src) +static void console_history_add(const utf8 *src) { if (_consoleHistoryCount >= CONSOLE_HISTORY_SIZE) { for (int i = 0; i < _consoleHistoryCount - 1; i++) @@ -397,26 +404,26 @@ static void console_history_add(const char *src) _consoleHistoryIndex = _consoleHistoryCount; } -static int cc_clear(const char **argv, int argc) +static int cc_clear(const utf8 **argv, int argc) { console_clear(); return 0; } -static int cc_hide(const char **argv, int argc) +static int cc_hide(const utf8 **argv, int argc) { console_close(); return 0; } -static int cc_echo(const char **argv, int argc) +static int cc_echo(const utf8 **argv, int argc) { if (argc > 0) console_writeline(argv[0]); return 0; } -static int cc_get(const char **argv, int argc) +static int cc_get(const utf8 **argv, int argc) { if (argc > 0) { if (strcmp(argv[0], "park_rating") == 0) { @@ -492,7 +499,7 @@ static int cc_get(const char **argv, int argc) 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" }; + const utf8* 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) { @@ -507,143 +514,193 @@ static int cc_get(const char **argv, int argc) else if (strcmp(argv[0], "no_test_crashes") == 0) { console_printf("no_test_crashes %d", gConfigGeneral.no_test_crashes); } + else if (strcmp(argv[0], "location") == 0) { + rct_window *w = window_get_main(); + if (w != NULL) { + int interactionType; + rct_map_element *mapElement; + rct_xy16 mapCoord = { 0 }; + get_map_coordinates_from_pos(w->viewport->view_width / 2, w->viewport->view_height / 2, VIEWPORT_INTERACTION_MASK_TERRAIN, &mapCoord.x, &mapCoord.y, &interactionType, &mapElement, NULL); + mapCoord.x -= 16; + mapCoord.x /= 32; + mapCoord.y -= 16; + mapCoord.y /= 32; + mapCoord.x++; + mapCoord.y++; + console_printf("location %d %d", mapCoord.x, mapCoord.y); + } + } else { console_writeline_warning("Invalid variable."); } } return 0; } -static int cc_set(const char **argv, int argc) +static int cc_set(const utf8 **argv, int argc) { + int i; if (argc > 1) { - bool int_valid = true, double_valid = true; + int int_val[4]; + bool int_valid[4]; + double double_val[4]; + bool double_valid[4]; + bool invalidArgs = false; - int int_val = console_parse_int(argv[1], &int_valid); - double double_val = console_parse_double(argv[1], &double_valid); + for (i = 0; i < 4; i++) { + if (i + 1 < argc) { + int_val[i] = console_parse_int(argv[i + 1], &int_valid[i]); + double_val[i] = console_parse_double(argv[i + 1], &double_valid[i]); + } + else { + int_val[i] = 0; int_valid[i] = false; + double_val[i] = 0; double_valid[i] = false; + } + } - 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)); + if (strcmp(argv[0], "money") == 0 && invalidArguments(&invalidArgs, double_valid[0])) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, money32) = ENCRYPT_MONEY(MONEY((int)double_val[0], ((int)(double_val[0] * 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)); + else if (strcmp(argv[0], "current_loan") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) = clamp(MONEY(int_val[0] - (int_val[0] % 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)); + else if (strcmp(argv[0], "max_loan") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + RCT2_GLOBAL(RCT2_ADDRESS_MAXIMUM_LOAN, money32) = clamp(MONEY(int_val[0] - (int_val[0] % 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)); + else if (strcmp(argv[0], "guest_initial_cash") == 0 && invalidArguments(&invalidArgs, double_valid[0])) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) = clamp(MONEY((int)double_val[0], ((int)(double_val[0] * 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); + else if (strcmp(argv[0], "guest_initial_happiness") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS, uint8) = calculate_guest_initial_happiness((uint8)int_val[0]); 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; + else if (strcmp(argv[0], "guest_initial_hunger") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_HUNGER, uint8) = (clamp(int_val[0], 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; + else if (strcmp(argv[0], "guest_initial_thirst") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_THIRST, uint8) = (clamp(int_val[0], 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); + else if (strcmp(argv[0], "guest_prefer_less_intense_rides") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_PREF_LESS_INTENSE_RIDES, int_val[0]); 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); + else if (strcmp(argv[0], "guest_prefer_more_intense_rides") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_PREF_MORE_INTENSE_RIDES, int_val[0]); 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); + else if (strcmp(argv[0], "forbid_marketing_campagns") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_FORBID_MARKETING_CAMPAIGN, int_val[0]); 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); + else if (strcmp(argv[0], "forbid_landscape_changes") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_FORBID_LANDSCAPE_CHANGES, int_val[0]); 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); + else if (strcmp(argv[0], "forbid_tree_removal") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_FORBID_TREE_REMOVAL, int_val[0]); 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); + else if (strcmp(argv[0], "forbid_high_construction") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_FORBID_HIGH_CONSTRUCTION, int_val[0]); 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); + else if (strcmp(argv[0], "pay_for_rides") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_PARK_FREE_ENTRY, int_val[0]); 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); + else if (strcmp(argv[0], "no_money") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_NO_MONEY, int_val[0]); 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); + else if (strcmp(argv[0], "difficult_park_rating") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_DIFFICULT_PARK_RATING, int_val[0]); 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); + else if (strcmp(argv[0], "difficult_guest_generation") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_DIFFICULT_GUEST_GENERATION, int_val[0]); 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); + else if (strcmp(argv[0], "park_open") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + SET_FLAG(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), PARK_FLAGS_PARK_OPEN, int_val[0]); 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)); + else if (strcmp(argv[0], "land_rights_cost") == 0 && invalidArguments(&invalidArgs, double_valid[0])) { + RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, money16) = clamp(MONEY((int)double_val[0], ((int)(double_val[0] * 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)); + else if (strcmp(argv[0], "construction_rights_cost") == 0 && invalidArguments(&invalidArgs, double_valid[0])) { + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCTION_RIGHTS_COST, money16) = clamp(MONEY((int)double_val[0], ((int)(double_val[0] * 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); + if (int_valid[0]) { + RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, sint8) = clamp(int_val[0], 0, 3); } else { - char* climate_names[] = { "cool_and_wet", "warm", "hot_and_dry", "cold" }; - for (int i = 0; i < 4; i++) { + utf8* climate_names[] = { "cool_and_wet", "warm", "hot_and_dry", "cold" }; + for (i = 0; i < 4; i++) { if (strcmp(argv[1], climate_names[i]) == 0) { RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, sint8) = i; break; } } } + if (i == 4) + invalidArgs = true; + else console_execute_silent("get climate"); } - else if (strcmp(argv[0], "game_speed") == 0 && int_valid) { - gGameSpeed = clamp(int_val, 1, 8); + else if (strcmp(argv[0], "game_speed") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + gGameSpeed = clamp(int_val[0], 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); + else if (strcmp(argv[0], "console_small_font") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + gConfigInterface.console_small_font = (int_val[0] != 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); + else if (strcmp(argv[0], "test_unfinished_tracks") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + gConfigGeneral.test_unfinished_tracks = (int_val[0] != 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); + else if (strcmp(argv[0], "no_test_crashes") == 0 && invalidArguments(&invalidArgs, int_valid[0])) { + gConfigGeneral.no_test_crashes = (int_val[0] != 0); config_save_default(); console_execute_silent("get no_test_crashes"); } + else if (strcmp(argv[0], "location") == 0 && invalidArguments(&invalidArgs, int_valid[0] && int_valid[1])) { + rct_window *w = window_get_main(); + if (w != NULL) { + int x = (sint16)(int_val[0] * 32 + 16); + int y = (sint16)(int_val[1] * 32 + 16); + int z = map_element_height(x, y); + window_scroll_to_location(w, x, y, z); + w->flags &= ~WF_SCROLLING_TO_LOCATION; + viewport_update_position(w); + console_execute_silent("get location"); + } + } + else if (invalidArgs) { + console_writeline_error("Invalid arguments."); + } else { - console_writeline_error("Invalid variable or value."); + console_writeline_error("Invalid variable."); } gfx_invalidate_screen(); } + else { + console_writeline_error("Value required."); + } return 0; } -static int cc_twitch(const char **argv, int argc) +static int cc_twitch(const utf8 **argv, int argc) { #ifdef DISABLE_TWITCH console_writeline_error("OpenRCT2 build not compiled with Twitch integeration."); @@ -652,6 +709,7 @@ static int cc_twitch(const char **argv, int argc) #endif return 0; } + static void editor_load_selected_objects_console() { uint8 *selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); @@ -675,13 +733,13 @@ static void editor_load_selected_objects_console() } } -static int cc_load_object(const char **argv, int argc) { +static int cc_load_object(const utf8 **argv, int argc) { if (argc > 0) { - char path[260]; + utf8 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); + utf8* last_char = path + strlen(path); strcat(path, ".DAT\0"); rct_object_entry entry; @@ -740,7 +798,7 @@ static int cc_load_object(const char **argv, int argc) { scenery_set_default_placement_configuration(); window_new_ride_init_vars(); - RCT2_GLOBAL(0x009DEB7C, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_UPDATE_TICKS, uint16) = 0; gfx_invalidate_screen(); console_writeline("Object file loaded."); } @@ -761,8 +819,9 @@ static int cc_load_object(const char **argv, int argc) { 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" }; + +static int cc_object_count(const utf8 **argv, int argc) { + const utf8* 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; @@ -776,20 +835,40 @@ static int cc_object_count(const char **argv, int argc) { return 0; } -static int cc_open(const char **argv, int argc) { + +static int cc_reset_user_strings(const utf8 **argv, int argc) +{ + reset_user_strings(); + return 0; +} + +static int cc_fix_banner_count(const utf8 **argv, int argc) +{ + fix_banner_count(); + return 0; +} + +static int cc_open(const utf8 **argv, int argc) { if (argc > 0) { - if (strcmp(argv[0], "object_selection") == 0) { + bool title = (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) != 0; + bool invalidTitle = false; + if (strcmp(argv[0], "object_selection") == 0 && invalidArguments(&invalidTitle, !title)) { // 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) { + } else if (strcmp(argv[0], "inventions_list") == 0 && invalidArguments(&invalidTitle, !title)) { window_editor_inventions_list_open(); + } else if (strcmp(argv[0], "scenario_options") == 0 && invalidArguments(&invalidTitle, !title)) { + window_editor_scenario_options_open(); } else if (strcmp(argv[0], "options") == 0) { window_options_open(); } else if (strcmp(argv[0], "themes") == 0) { window_themes_open(); - } - else { + } else if (strcmp(argv[0], "title_sequences") == 0) { + window_title_editor_open(0); + } else if (invalidTitle) { + console_writeline_error("Cannot open this window in the title screen."); + } else { console_writeline_error("Invalid window."); } } @@ -797,15 +876,15 @@ static int cc_open(const char **argv, int argc) { } -typedef int (*console_command_func)(const char **argv, int argc); +typedef int (*console_command_func)(const utf8 **argv, int argc); typedef struct { - char *command; + utf8 *command; console_command_func func; - char *help; - char *usage; + utf8 *help; + utf8 *usage; } console_command; -char* console_variable_table[] = { +utf8* console_variable_table[] = { "park_rating", "money", "current_loan", @@ -831,13 +910,16 @@ char* console_variable_table[] = { "game_speed", "console_small_font", "test_unfinished_tracks", - "no_test_crashes" + "no_test_crashes", + "location" }; -char* console_window_table[] = { +utf8* console_window_table[] = { "object_selection", "inventions_list", + "scenario_options", "options", - "themes" + "themes", + "title_sequences" }; console_command console_command_table[] = { @@ -852,25 +934,27 @@ console_command console_command_table[] = { { "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\".", + "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" } + { "twitch", cc_twitch, "Twitch API" }, + { "reset_user_strings", cc_reset_user_strings, "Resets all user-defined strings, to fix incorrectly occurring 'Chosen name in use already' errors.", "reset_user_strings" }, + { "fix_banner_count", cc_fix_banner_count, "Fixes incorrectly appearing 'Too many banners' error by marking every banner entry without a map element as null.", "fix_banner_count" } }; -static int cc_windows(const char **argv, int argc) { +static int cc_windows(const utf8 **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) +static int cc_variables(const utf8 **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) +static int cc_help(const utf8 **argv, int argc) { if (argc > 0) { for (int i = 0; i < countof(console_command_table); i++) { @@ -892,20 +976,20 @@ static void console_write_all_commands() console_writeline(console_command_table[i].command); } -void console_execute(const char *src) +void console_execute(const utf8 *src) { console_writeline(src); console_execute_silent(src); } -void console_execute_silent(const char *src) +void console_execute_silent(const utf8 *src) { int argc = 0; int argvCapacity = 8; - char **argv = malloc(argvCapacity * sizeof(char*)); - const char *start = src; - const char *end; + utf8 **argv = malloc(argvCapacity * sizeof(utf8*)); + const utf8 *start = src; + const utf8 *end; bool inQuotes = false; do { while (*start == ' ') @@ -930,13 +1014,13 @@ void console_execute_silent(const char *src) int length = end - start; if (length > 0) { - char *arg = malloc(length + 1); + utf8 *arg = malloc(length + 1); memcpy(arg, start, length); arg[length] = 0; if (argc >= argvCapacity) { argvCapacity *= 2; - argv = realloc(argv, argvCapacity * sizeof(char*)); + argv = realloc(argv, argvCapacity * sizeof(utf8*)); } argv[argc] = arg; argc++; @@ -948,10 +1032,14 @@ void console_execute_silent(const char *src) if (argc == 0) return; + // Aliases for hiding the console + if(strcmp(argv[0],"quit") == 0 || strcmp(argv[0],"exit") == 0) + argv[0]="hide"; + 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); + console_command_table[i].func((const utf8 **)(argv + 1), argc - 1); validCommand = true; break; } @@ -962,7 +1050,19 @@ void console_execute_silent(const char *src) free(argv); if (!validCommand) { - char output[] = { FORMAT_RED, "Unknown command. Type help to list available commands." }; + utf8 output[128]; + utf8 *dst = output; + dst = utf8_write_codepoint(dst, FORMAT_RED); + strcpy(dst, "Unknown command. Type help to list available commands."); console_writeline(output); } -} \ No newline at end of file +} + +static bool invalidArguments(bool *invalid, bool arguments) +{ + if (!arguments) { + *invalid = true; + return false; + } + return true; +} diff --git a/src/interface/console.h b/src/interface/console.h index 3c11077edb..82c7870eac 100644 --- a/src/interface/console.h +++ b/src/interface/console.h @@ -14,13 +14,13 @@ 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_write(const utf8 *src); +void console_writeline(const utf8 *src); +void console_writeline_error(const utf8 *src); +void console_writeline_warning(const utf8 *src); +void console_printf(const utf8 *format, ...); +void console_execute(const utf8 *src); +void console_execute_silent(const utf8 *src); void console_clear(); void console_clear_line(); void console_refresh_caret(); diff --git a/src/interface/graph.c b/src/interface/graph.c index 96917c88af..7e1fc5cb31 100644 --- a/src/interface/graph.c +++ b/src/interface/graph.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 . *****************************************************************************/ @@ -35,7 +35,7 @@ static void graph_draw_months_uint8(rct_drawpixelinfo *dpi, uint8 *history, int for (i = count - 1; i >= 0; i--) { if (history[i] != 0 && history[i] != 255 && yearOver32 % 4 == 0) { // Draw month text - RCT2_GLOBAL(0x013CE952, uint32) = ((yearOver32 / 4) + 8) % 8 + STR_MONTH_SHORT_MAR; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) = ((yearOver32 / 4) + 8) % 8 + STR_MONTH_SHORT_MAR; gfx_draw_string_centred(dpi, 2222, x, y - 10, 0, (void*)0x013CE952); // Draw month mark diff --git a/src/interface/graph.h b/src/interface/graph.h index 82a0f7fa6c..e6c9aee74e 100644 --- a/src/interface/graph.h +++ b/src/interface/graph.h @@ -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 . *****************************************************************************/ diff --git a/src/interface/keyboard_shortcut.c b/src/interface/keyboard_shortcut.c index c2e65483c2..946ab53dcf 100644 --- a/src/interface/keyboard_shortcut.c +++ b/src/interface/keyboard_shortcut.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 @@ -21,7 +21,10 @@ #include "../addresses.h" #include "../config.h" #include "../game.h" +#include "../interface/chat.h" #include "../input.h" +#include "../localisation/localisation.h" +#include "../network/network.h" #include "keyboard_shortcut.h" #include "viewport.h" #include "window.h" @@ -32,7 +35,7 @@ typedef void (*shortcut_action)(); static const shortcut_action shortcut_table[SHORTCUT_COUNT]; /** - * + * * rct2: 0x006E3E91 */ void keyboard_shortcut_set(int key) @@ -55,7 +58,7 @@ void keyboard_shortcut_set(int key) } /** - * + * * rct2: 0x006E3E68 */ void keyboard_shortcut_handle(int key) @@ -71,8 +74,33 @@ void keyboard_shortcut_handle(int key) void keyboard_shortcut_handle_command(int shortcutIndex) { - if (shortcutIndex >= 0 && shortcutIndex < countof(shortcut_table)) - shortcut_table[shortcutIndex](); + if (shortcutIndex >= 0 && shortcutIndex < countof(shortcut_table)) { + shortcut_action action = shortcut_table[shortcutIndex]; + if (action != NULL) { + action(); + } + } +} + +void keyboard_shortcut_format_string(char *buffer, uint16 shortcutKey) +{ + char formatBuffer[256]; + + *buffer = 0; + if (shortcutKey == 0xFFFF) return; + if (shortcutKey & 0x100) { + format_string(formatBuffer, STR_SHIFT_PLUS, NULL); + strcat(buffer, formatBuffer); + } + if (shortcutKey & 0x200) { + format_string(formatBuffer, STR_CTRL_PLUS, NULL); + strcat(buffer, formatBuffer); + } + if (shortcutKey & 0x400) { + format_string(formatBuffer, STR_ALT_PLUS, NULL); + strcat(buffer, formatBuffer); + } + strcat(buffer, SDL_GetScancodeName(shortcutKey & 0xFF)); } #pragma region Shortcut Commands @@ -155,19 +183,16 @@ static void shortcut_zoom_view_in() } } -static void shortcut_rotate_view() +static void shortcut_rotate_view_clockwise() { - rct_window *window; + rct_window* w = window_get_main(); + window_rotate_camera(w, 1); +} - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || RCT2_GLOBAL(0x0141F570, uint8) == 1) { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER)) { - window = window_find_by_class(WC_TOP_TOOLBAR); - if (window != NULL) { - window_invalidate(window); - window_event_mouse_up_call(window, 4); - } - } - } +static void shortcut_rotate_view_anticlockwise() +{ + rct_window* w = window_get_main(); + window_rotate_camera(w, -1); } static void shortcut_rotate_construction_object() @@ -228,6 +253,25 @@ static void shortcut_remove_vertical_land_toggle() toggle_view_flag(VIEWPORT_FLAG_HIDE_VERTICAL); } +static void shortcut_remove_top_bottom_toolbar_toggle() +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) + return; + + if (window_find_by_class(WC_TOP_TOOLBAR) != NULL) { + window_close(window_find_by_class(WC_TOP_TOOLBAR)); + window_close(window_find_by_class(WC_BOTTOM_TOOLBAR)); + } else { + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) == 0) { + window_top_toolbar_open(); + window_game_bottom_toolbar_open(); + } else { + window_top_toolbar_open(); + window_editor_bottom_toolbar_open(); + } + } +} + static void shortcut_see_through_rides_toggle() { toggle_view_flag(VIEWPORT_FLAG_SEETHROUGH_RIDES); @@ -451,6 +495,24 @@ static void shortcut_open_cheat_window() window_cheats_open(); } +static void shortcut_open_chat_window() +{ + chat_toggle(); +} + +static void shortcut_quick_save_game() +{ + // Do a quick save in playing mode and a regular save in Scenario Editor mode. In other cases, don't do anything. + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) == SCREEN_FLAGS_PLAYING) { + tool_cancel(); + save_game(); + } + else 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); + } +} + static const shortcut_action shortcut_table[SHORTCUT_COUNT] = { shortcut_close_top_most_window, shortcut_close_all_floating_windows, @@ -458,7 +520,8 @@ static const shortcut_action shortcut_table[SHORTCUT_COUNT] = { shortcut_pause_game, shortcut_zoom_view_out, shortcut_zoom_view_in, - shortcut_rotate_view, + shortcut_rotate_view_clockwise, + shortcut_rotate_view_anticlockwise, shortcut_rotate_construction_object, shortcut_underground_view_toggle, shortcut_remove_base_land_toggle, @@ -484,9 +547,18 @@ static const shortcut_action shortcut_table[SHORTCUT_COUNT] = { shortcut_show_recent_messages, shortcut_show_map, shortcut_screenshot, + + //new shortcut_reduce_game_speed, shortcut_increase_game_speed, - shortcut_open_cheat_window + shortcut_open_cheat_window, + shortcut_remove_top_bottom_toolbar_toggle, + NULL, + NULL, + NULL, + NULL, + shortcut_open_chat_window, + shortcut_quick_save_game, }; #pragma endregion diff --git a/src/interface/keyboard_shortcut.h b/src/interface/keyboard_shortcut.h index e735a85592..3b9dc2599e 100644 --- a/src/interface/keyboard_shortcut.h +++ b/src/interface/keyboard_shortcut.h @@ -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 . *****************************************************************************/ @@ -24,5 +24,6 @@ void keyboard_shortcut_set(int key); void keyboard_shortcut_handle(int key); void keyboard_shortcut_handle_command(int shortcutIndex); +void keyboard_shortcut_format_string(char *buffer, uint16 shortcutKey); #endif \ No newline at end of file diff --git a/src/interface/screenshot.c b/src/interface/screenshot.c index 5aa010ca5a..79c1ae2ccf 100644 --- a/src/interface/screenshot.c +++ b/src/interface/screenshot.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 . *****************************************************************************/ @@ -38,7 +38,7 @@ static int screenshot_dump_bmp(); static int screenshot_dump_png(); /** - * + * * rct2: 0x006E3AEC */ void screenshot_check() @@ -55,8 +55,8 @@ void screenshot_check() 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) = stringId; - // RCT2_GLOBAL(0x013CE952, uint16) = STR_SCR_BMP; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = stringId; + // RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = STR_SCR_BMP; // RCT2_GLOBAL(0x013CE952 + 2, uint16) = screenshotIndex; RCT2_GLOBAL(0x009A8C29, uint8) |= 1; @@ -66,7 +66,7 @@ void screenshot_check() } RCT2_GLOBAL(0x009A8C29, uint8) &= ~1; - redraw_peep_and_rain(); + redraw_rain(); } } } @@ -83,7 +83,7 @@ static int screenshot_get_next_path(char *path, int format) int i; for (i = 1; i < 1000; i++) { - RCT2_GLOBAL(0x013CE952, uint16) = i; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = i; // Glue together path and filename sprintf(path, "%sSCR%d%s", screenshotPath, i, _screenshot_format_extension[format]); @@ -133,7 +133,7 @@ typedef struct { } BitmapInfoHeader; /** - * + * * rct2: 0x00683D20 */ int screenshot_dump_bmp() @@ -142,8 +142,9 @@ int screenshot_dump_bmp() BitmapInfoHeader info; int i, y, index, width, height, stride; - char *buffer, path[MAX_PATH], *row; - FILE *fp; + char path[MAX_PATH]; + uint8 *buffer, *row; + SDL_RWops *fp; unsigned int bytesWritten; // Get a free screenshot path @@ -151,15 +152,14 @@ int screenshot_dump_bmp() return -1; // Open binary file for writing - if ((fp = fopen(path, "wb")) == NULL){ + if ((fp = SDL_RWFromFile(path, "wb")) == NULL){ return -1; } // Allocate buffer buffer = malloc(0xFFFF); if (buffer == NULL) { - //CloseHandle(hFile); - fclose(fp); + SDL_RWclose(fp); return -1; } @@ -174,10 +174,12 @@ int screenshot_dump_bmp() header.bfSize = height * stride + 1038; header.bfOffBits = 1038; - bytesWritten = fwrite(&header, sizeof(BitmapFileHeader), 1, fp); + bytesWritten = SDL_RWwrite(fp, &header, sizeof(BitmapFileHeader), 1); if (bytesWritten != 1) { - fclose(fp); - free(buffer); + SDL_RWclose(fp); + SafeFree(buffer); + log_error("failed to save screenshot"); + return -1; } // Info header @@ -191,24 +193,28 @@ int screenshot_dump_bmp() info.biYPelsPerMeter = 2520; info.biClrUsed = 246; - bytesWritten=fwrite(&info, sizeof(BitmapInfoHeader), 1, fp); + bytesWritten = SDL_RWwrite(fp, &info, sizeof(BitmapInfoHeader), 1); if (bytesWritten != 1) { - fclose(fp); - free(buffer); + SDL_RWclose(fp); + SafeFree(buffer); + log_error("failed to save screenshot"); + return -1; } // Palette memset(buffer, 0, 246 * 4); for (i = 0; i < 246; i++) { - buffer[i * 4 + 0] = RCT2_ADDRESS(0x01424680, uint8)[i * 4 + 0]; - buffer[i * 4 + 1] = RCT2_ADDRESS(0x01424680, uint8)[i * 4 + 1]; - buffer[i * 4 + 2] = RCT2_ADDRESS(0x01424680, uint8)[i * 4 + 2]; + buffer[i * 4 + 0] = RCT2_ADDRESS(RCT2_ADDRESS_PALETTE, uint8)[i * 4 + 0]; + buffer[i * 4 + 1] = RCT2_ADDRESS(RCT2_ADDRESS_PALETTE, uint8)[i * 4 + 1]; + buffer[i * 4 + 2] = RCT2_ADDRESS(RCT2_ADDRESS_PALETTE, uint8)[i * 4 + 2]; } - bytesWritten = fwrite(buffer, sizeof(char), 246*4, fp); + bytesWritten = SDL_RWwrite(fp, buffer, sizeof(char), 246 * 4); if (bytesWritten != 246*4){ - fclose(fp); - free(buffer); + SDL_RWclose(fp); + SafeFree(buffer); + log_error("failed to save screenshot"); + return -1; } // Image, save upside down @@ -219,14 +225,16 @@ int screenshot_dump_bmp() memset(buffer, 0, stride); memcpy(buffer, row, dpi->width); - bytesWritten=fwrite(buffer, sizeof(char), stride, fp); + bytesWritten = SDL_RWwrite(fp, buffer, sizeof(char), stride); if (bytesWritten != stride){ - fclose(fp); - free(buffer); + SDL_RWclose(fp); + SafeFree(buffer); + log_error("failed to save screenshot"); + return -1; } } - fclose(fp); + SDL_RWclose(fp); free(buffer); return index; @@ -260,9 +268,9 @@ int screenshot_dump_png() padding = dpi->pitch; for (i = 0; i < 256; i++) { - b = RCT2_ADDRESS(0x01424680, uint8)[i * 4 + 0]; - g = RCT2_ADDRESS(0x01424680, uint8)[i * 4 + 1]; - r = RCT2_ADDRESS(0x01424680, uint8)[i * 4 + 2]; + b = RCT2_ADDRESS(RCT2_ADDRESS_PALETTE, uint8)[i * 4 + 0]; + g = RCT2_ADDRESS(RCT2_ADDRESS_PALETTE, uint8)[i * 4 + 1]; + r = RCT2_ADDRESS(RCT2_ADDRESS_PALETTE, uint8)[i * 4 + 2]; lodepng_palette_add(&state.info_raw, r, g, b, a); } @@ -289,11 +297,18 @@ int screenshot_dump_png() log_error("Unable to save screenshot, %u: %s", lodepng_error_text(error)); index = -1; } else { - lodepng_save_file(png, pngSize, path); + SDL_RWops *file = SDL_RWFromFile(path, "wb"); + if (file == NULL) { + log_error("Unable to save screenshot, %s", SDL_GetError()); + index = -1; + } else { + SDL_RWwrite(file, png, pngSize, 1); + SDL_RWclose(file); + } } free(png); - if (pixels != dpi->bits) { + if ((utf8*)pixels != (utf8*)dpi->bits) { free(pixels); } return index; @@ -315,9 +330,9 @@ bool screenshot_write_png(rct_drawpixelinfo *dpi, const char *path) 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]; + b = RCT2_ADDRESS(RCT2_ADDRESS_PALETTE, uint8)[i * 4 + 0]; + g = RCT2_ADDRESS(RCT2_ADDRESS_PALETTE, uint8)[i * 4 + 1]; + r = RCT2_ADDRESS(RCT2_ADDRESS_PALETTE, uint8)[i * 4 + 2]; lodepng_palette_add(&state.info_raw, r, g, b, a); } @@ -327,11 +342,13 @@ bool screenshot_write_png(rct_drawpixelinfo *dpi, const char *path) free(png); return false; } else { - error = lodepng_save_file(png, pngSize, path); - if (error != 0) { + SDL_RWops *file = SDL_RWFromFile(path, "wb"); + if (file == NULL) { free(png); return false; } + SDL_RWwrite(file, png, pngSize, 1); + SDL_RWclose(file); } free(png); @@ -340,7 +357,7 @@ bool screenshot_write_png(rct_drawpixelinfo *dpi, const char *path) void screenshot_giant() { - int originalRotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + int originalRotation = get_current_rotation(); int originalZoom = 0; rct_window *mainWindow = window_get_main(); @@ -443,7 +460,7 @@ int cmdline_for_screenshot(const char **argv, int argc) 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) { @@ -559,4 +576,4 @@ int cmdline_for_screenshot(const char **argv, int argc) } openrct2_dispose(); return 1; -} \ No newline at end of file +} diff --git a/src/interface/screenshot.h b/src/interface/screenshot.h index 0672a135bb..81feb53801 100644 --- a/src/interface/screenshot.h +++ b/src/interface/screenshot.h @@ -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 . *****************************************************************************/ diff --git a/src/interface/themes.c b/src/interface/themes.c index dc22390267..96ef4f6742 100644 --- a/src/interface/themes.c +++ b/src/interface/themes.c @@ -19,6 +19,8 @@ *****************************************************************************/ #include "../localisation/string_ids.h" +#include "../util/util.h" +#include "colour.h" #include "window.h" #include "themes.h" @@ -29,82 +31,83 @@ #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 THEME_DEF_END { 0xFF, { 0, 0, 0, 0, 0, 0 } } + #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) }, + { WC_TOP_TOOLBAR, "top_toolbar", 5245, COLOURS_4(COLOUR_LIGHT_BLUE, COLOUR_DARK_GREEN, COLOUR_DARK_BROWN, COLOUR_GREY ) }, + { WC_BOTTOM_TOOLBAR, "bottom_toolbar", 5246, COLOURS_4(TRANSLUCENT(COLOUR_DARK_GREEN), TRANSLUCENT(COLOUR_DARK_GREEN), COLOUR_BLACK, COLOUR_BRIGHT_GREEN ) }, + { WC_RIDE, "ride", 5203, COLOURS_3(COLOUR_GREY, COLOUR_BORDEAUX_RED, COLOUR_GREY ) }, + { WC_RIDE_CONSTRUCTION, "ride_construction", 5199, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) }, + { WC_RIDE_LIST, "ride_list", 5204, COLOURS_3(COLOUR_GREY, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED ) }, + { WC_SAVE_PROMPT, "save_prompt", 5223, COLOURS_1(TRANSLUCENT(COLOUR_BORDEAUX_RED) ) }, + { WC_CONSTRUCT_RIDE, "new_ride", 5201, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED ) }, + { WC_DEMOLISH_RIDE_PROMPT, "demolish_ride_prompt", 5224, COLOURS_1(TRANSLUCENT(COLOUR_BORDEAUX_RED) ) }, + { WC_SCENERY, "scenery", 5197, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_GREEN, COLOUR_DARK_GREEN ) }, + { WC_OPTIONS, "options", 5219, COLOURS_3(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) }, + { WC_FOOTPATH, "footpath", 5198, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) }, + { WC_LAND, "land", 5193, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) }, + { WC_WATER, "water", 5194, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) }, + { WC_PEEP, "guest", 5205, COLOURS_3(COLOUR_GREY, COLOUR_OLIVE_GREEN, COLOUR_OLIVE_GREEN ) }, + { WC_GUEST_LIST, "guest_list", 5206, COLOURS_3(COLOUR_GREY, COLOUR_OLIVE_GREEN, COLOUR_OLIVE_GREEN ) }, + { WC_STAFF_LIST, "staff_list", 5208, COLOURS_3(COLOUR_GREY, COLOUR_LIGHT_PURPLE, COLOUR_LIGHT_PURPLE ) }, + { WC_FIRE_PROMPT, "staff_fire_prompt", 5225, COLOURS_1(TRANSLUCENT(COLOUR_BORDEAUX_RED) ) }, + { WC_PARK_INFORMATION, "park_information", 5253, COLOURS_3(COLOUR_GREY, COLOUR_DARK_YELLOW, COLOUR_DARK_YELLOW ) }, + { WC_FINANCES, "finances", 5187, COLOURS_3(COLOUR_GREY, COLOUR_DARK_YELLOW, COLOUR_DARK_YELLOW ) }, + { WC_TITLE_MENU, "title_menu", 5249, COLOURS_3(TRANSLUCENT(COLOUR_DARK_GREEN), TRANSLUCENT(COLOUR_DARK_GREEN), TRANSLUCENT(COLOUR_DARK_GREEN) ) }, + { WC_TITLE_EXIT, "title_exit", 5250, COLOURS_3(TRANSLUCENT(COLOUR_DARK_GREEN), TRANSLUCENT(COLOUR_DARK_GREEN), TRANSLUCENT(COLOUR_DARK_GREEN) ) }, + { WC_RECENT_NEWS, "recent_news", 5192, COLOURS_3(COLOUR_GREY, COLOUR_GREY, COLOUR_BLACK ) }, + { WC_SCENARIO_SELECT, "scenario_select", 5252, COLOURS_3(COLOUR_GREY, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED ) }, + { WC_TRACK_DESIGN_LIST, "track_design_list", 5202, COLOURS_3(COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED ) }, + { WC_TRACK_DESIGN_PLACE, "track_design_place", 5200, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) }, + { WC_NEW_CAMPAIGN, "new_campaign", 5188, COLOURS_3(COLOUR_DARK_YELLOW, COLOUR_DARK_YELLOW, COLOUR_DARK_YELLOW ) }, + { WC_KEYBOARD_SHORTCUT_LIST, "keyboard_shortcuts", 5220, COLOURS_3(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) }, + { WC_CHANGE_KEYBOARD_SHORTCUT, "change_keyboard_shortcut", 5221, COLOURS_3(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) }, + { WC_MAP, "map", 5190, COLOURS_2(COLOUR_DARK_GREEN, COLOUR_DARK_BROWN ) }, + { WC_BANNER, "banner", 5209, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) }, + { WC_EDITOR_OBJECT_SELECTION, "editor_object_selection", 5210, COLOURS_3(COLOUR_LIGHT_PURPLE, COLOUR_GREY, COLOUR_GREY ) }, + { WC_EDITOR_INVENTION_LIST, "editor_invention_list", 5211, COLOURS_3(COLOUR_LIGHT_PURPLE, COLOUR_GREY, COLOUR_GREY ) }, + { WC_EDITOR_SCENARIO_OPTIONS, "editor_scenario_options", 5212, COLOURS_3(COLOUR_LIGHT_PURPLE, COLOUR_GREY, COLOUR_GREY ) }, + { WC_EDTIOR_OBJECTIVE_OPTIONS, "editor_objection_options", 5213, COLOURS_3(COLOUR_LIGHT_PURPLE, COLOUR_GREY, COLOUR_GREY ) }, + { WC_MANAGE_TRACK_DESIGN, "manage_track_design", 5215, COLOURS_3(COLOUR_GREY, COLOUR_GREY, COLOUR_GREY ) }, + { WC_TRACK_DELETE_PROMPT, "track_delete_prompt", 5226, COLOURS_3(COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED ) }, + { WC_INSTALL_TRACK, "install_track", 5216, COLOURS_3(COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED ) }, + { WC_CLEAR_SCENERY, "clear_scenery", 5195, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) }, + { WC_CHEATS, "cheats", 5217, COLOURS_3(COLOUR_GREY, COLOUR_DARK_YELLOW, COLOUR_DARK_YELLOW ) }, + { WC_RESEARCH, "research", 5189, COLOURS_3(COLOUR_GREY, COLOUR_DARK_YELLOW, COLOUR_DARK_YELLOW ) }, + { WC_VIEWPORT, "viewport", 5191, COLOURS_3(COLOUR_DARK_BROWN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) }, + { WC_MAPGEN, "map_generation", 5214, COLOURS_3(COLOUR_DARK_GREEN, COLOUR_DARK_BROWN, COLOUR_DARK_BROWN ) }, + { WC_LOADSAVE, "loadsave", 5222, COLOURS_3(COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE, COLOUR_LIGHT_BLUE ) }, + { WC_LOADSAVE_OVERWRITE_PROMPT, "loadsave_overwrite_prompt", 5227, COLOURS_1(TRANSLUCENT(COLOUR_BORDEAUX_RED) ) }, + { WC_TITLE_OPTIONS, "title_options", 5251, COLOURS_3(TRANSLUCENT(COLOUR_DARK_GREEN), TRANSLUCENT(COLOUR_DARK_GREEN), TRANSLUCENT(COLOUR_DARK_GREEN) ) }, + { WC_LAND_RIGHTS, "land_rights", 5196, COLOURS_3(COLOUR_DARK_YELLOW, COLOUR_DARK_YELLOW, COLOUR_DARK_YELLOW ) }, + { WC_THEMES, "themes", 5218, COLOURS_3(COLOUR_GREY, COLOUR_DARK_GREEN, COLOUR_DARK_GREEN ) }, + { WC_STAFF, "staff", 5207, COLOURS_3(COLOUR_GREY, COLOUR_LIGHT_PURPLE, COLOUR_LIGHT_PURPLE ) }, + { WC_EDITOR_TRACK_BOTTOM_TOOLBAR, "editor_track_bottom_toolbar", 5247, COLOURS_3(TRANSLUCENT(COLOUR_LIGHT_BLUE), TRANSLUCENT(COLOUR_LIGHT_BLUE), TRANSLUCENT(COLOUR_LIGHT_BLUE) ) }, + { WC_EDITOR_SCENARIO_BOTTOM_TOOLBAR, "editor_scenario_bottom_toolbar", 5248, COLOURS_3(TRANSLUCENT(COLOUR_LIGHT_BROWN), TRANSLUCENT(COLOUR_LIGHT_BROWN), TRANSLUCENT(COLOUR_MOSS_GREEN) ) }, + { WC_TITLE_EDITOR, "title_sequences", 5433, COLOURS_3(COLOUR_GREY, COLOUR_OLIVE_GREEN, COLOUR_OLIVE_GREEN ) }, }; #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 + { WC_TOP_TOOLBAR, COLOURS_RCT1(COLOUR_GREY, COLOUR_GREY, COLOUR_GREY, COLOUR_GREY, COLOUR_BLACK, COLOUR_BLACK) }, + { WC_BOTTOM_TOOLBAR, COLOURS_RCT1(TRANSLUCENT(COLOUR_GREY), TRANSLUCENT(COLOUR_GREY), COLOUR_BLACK, COLOUR_YELLOW, COLOUR_BLACK, COLOUR_BLACK) }, + { WC_RIDE, COLOURS_RCT1(COLOUR_BORDEAUX_RED, COLOUR_GREY, COLOUR_SATURATED_GREEN, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) }, + { WC_RIDE_LIST, COLOURS_RCT1(COLOUR_BORDEAUX_RED, COLOUR_GREY, COLOUR_GREY, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) }, + { WC_CONSTRUCT_RIDE, COLOURS_RCT1(COLOUR_BORDEAUX_RED, COLOUR_GREY, COLOUR_GREY, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) }, + { WC_PEEP, COLOURS_RCT1(COLOUR_LIGHT_BROWN, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) }, + { WC_GUEST_LIST, COLOURS_RCT1(COLOUR_LIGHT_BROWN, COLOUR_BORDEAUX_RED, COLOUR_BORDEAUX_RED, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) }, + { WC_STAFF_LIST, COLOURS_RCT1(COLOUR_DARK_GREEN, COLOUR_LIGHT_PURPLE, COLOUR_LIGHT_PURPLE, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) }, + { WC_FINANCES, COLOURS_RCT1(COLOUR_LIGHT_PURPLE, COLOUR_GREY, COLOUR_GREY, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) }, + { WC_TITLE_MENU, COLOURS_RCT1(TRANSLUCENT(COLOUR_GREY), TRANSLUCENT(COLOUR_GREY), TRANSLUCENT(COLOUR_GREY), COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) }, + { WC_TITLE_EXIT, COLOURS_RCT1(TRANSLUCENT(COLOUR_GREY), TRANSLUCENT(COLOUR_GREY), TRANSLUCENT(COLOUR_GREY), COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) }, + { WC_NEW_CAMPAIGN, COLOURS_RCT1(COLOUR_LIGHT_PURPLE, COLOUR_LIGHT_PURPLE, COLOUR_GREY, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) }, + { WC_TITLE_OPTIONS, COLOURS_RCT1(TRANSLUCENT(COLOUR_GREY), TRANSLUCENT(COLOUR_GREY), TRANSLUCENT(COLOUR_GREY), COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) }, + { WC_STAFF, COLOURS_RCT1(COLOUR_DARK_GREEN, COLOUR_LIGHT_PURPLE, COLOUR_LIGHT_PURPLE, COLOUR_BLACK, COLOUR_BLACK, COLOUR_BLACK) }, + THEME_DEF_END }; uint16 gCurrentTheme = 0; @@ -155,7 +158,7 @@ void colour_scheme_update(rct_window *window) 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]; @@ -192,11 +195,12 @@ 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); + safe_strncpy(gConfigThemes.presets[preset].name, name, THEME_PRESET_NAME_SIZE); 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]; } + gConfigThemes.presets[preset].features = gConfigThemes.presets[duplicate].features; themes_save_preset(preset); theme_change_preset(preset); } @@ -232,10 +236,10 @@ void theme_rename_preset(int preset, const char *newName) strcat(dest, ".ini"); platform_file_move(src, dest); - strcpy(gConfigThemes.presets[gCurrentTheme].name, newName); + safe_strncpy(gConfigThemes.presets[preset].name, newName, THEME_PRESET_NAME_SIZE); if (preset == gCurrentTheme) { - gConfigInterface.current_theme_preset = gConfigThemes.presets[gCurrentTheme].name; + gConfigInterface.current_theme_preset = gConfigThemes.presets[preset].name; } } } diff --git a/src/interface/title_sequences.c b/src/interface/title_sequences.c new file mode 100644 index 0000000000..5d3b05cbb3 --- /dev/null +++ b/src/interface/title_sequences.c @@ -0,0 +1,366 @@ +/***************************************************************************** +* 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 "title_sequences.h" +#include "../title.h" +#include "../util/util.h" + + +uint16 gCurrentTitleSequence; +uint16 gCurrentPreviewTitleSequence; + +title_command TitleScriptMakeCommand(int command, int parameter1, int parameter2) +{ + title_command titleCommand = { (uint8)command, (uint8)parameter1, (uint8)parameter2 }; + return titleCommand; +} + +bool title_sequence_name_exists(const char *name) +{ + for (int i = 0; i < gConfigTitleSequences.num_presets; i++) { + if (_stricmp(gConfigTitleSequences.presets[i].name, name) == 0) + return true; + } + return false; +} + +bool title_sequence_save_exists(int preset, const char *name) +{ + utf8 newName[MAX_PATH]; + char *extension = (char*)path_get_extension(name); + safe_strncpy(newName, name, MAX_PATH); + if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) + strcat(newName, ".sv6"); + for (int i = 0; i < gConfigTitleSequences.presets[preset].num_saves; i++) { + if (_stricmp(gConfigTitleSequences.presets[preset].saves[i], newName) == 0) + return true; + } + return false; +} + + +void title_sequence_change_preset(int preset) +{ + if (preset >= 0 && preset < gConfigTitleSequences.num_presets) { + switch (preset) { + case 0: + gConfigInterface.current_title_sequence_preset = "*RCT2"; + break; + case 1: + gConfigInterface.current_title_sequence_preset = "*OPENRCT2"; + break; + default: + gConfigInterface.current_title_sequence_preset = gConfigTitleSequences.presets[preset].name; + break; + } + gCurrentPreviewTitleSequence = preset; + } + window_invalidate_all(); + + // Switch to (and restart) this title sequence if it's valid + title_refresh_sequence(); +} + +void title_sequence_create_preset(const char *name) +{ + if (filename_valid_characters(name) && !title_sequence_name_exists(name)) { + int preset = gConfigTitleSequences.num_presets; + gConfigTitleSequences.num_presets++; + gConfigTitleSequences.presets = realloc(gConfigTitleSequences.presets, sizeof(title_sequence) * (size_t)gConfigTitleSequences.num_presets); + safe_strncpy(gConfigTitleSequences.presets[preset].name, name, TITLE_SEQUENCE_NAME_SIZE); + gConfigTitleSequences.presets[preset].path[0] = 0; + + gConfigTitleSequences.presets[preset].saves = malloc(0); + gConfigTitleSequences.presets[preset].commands = malloc(0); + gConfigTitleSequences.presets[preset].num_saves = 0; + gConfigTitleSequences.presets[preset].num_commands = 0; + + // Create the folder + utf8 path[MAX_PATH]; + platform_get_user_directory(path, "title sequences"); + strcat(path, gConfigTitleSequences.presets[preset].name); + platform_file_delete(path); + platform_ensure_directory_exists(path); + + title_sequence_save_preset_script(preset); + gCurrentTitleSequence = preset; + } +} + +void title_sequence_duplicate_preset(int duplicate, const char *name) +{ + if (duplicate >= 0 && duplicate < gConfigTitleSequences.num_presets && filename_valid_characters(name) && !title_sequence_name_exists(name)) { + int preset = gConfigTitleSequences.num_presets; + gConfigTitleSequences.num_presets++; + gConfigTitleSequences.presets = realloc(gConfigTitleSequences.presets, sizeof(title_sequence) * (size_t)gConfigTitleSequences.num_presets); + safe_strncpy(gConfigTitleSequences.presets[preset].name, name, TITLE_SEQUENCE_NAME_SIZE); + gConfigTitleSequences.presets[preset].path[0] = 0; + + size_t savesSize = sizeof(char[TITLE_SEQUENCE_MAX_SAVE_LENGTH]) * gConfigTitleSequences.presets[duplicate].num_saves; + size_t commandsSize = sizeof(title_command) * gConfigTitleSequences.presets[duplicate].num_commands; + gConfigTitleSequences.presets[preset].saves = malloc(savesSize); + gConfigTitleSequences.presets[preset].commands = malloc(commandsSize); + memcpy(gConfigTitleSequences.presets[preset].saves, gConfigTitleSequences.presets[duplicate].saves, savesSize); + memcpy(gConfigTitleSequences.presets[preset].commands, gConfigTitleSequences.presets[duplicate].commands, commandsSize); + gConfigTitleSequences.presets[preset].num_saves = gConfigTitleSequences.presets[duplicate].num_saves; + gConfigTitleSequences.presets[preset].num_commands = gConfigTitleSequences.presets[duplicate].num_commands; + + bool loadmm = false; + for (int i = 0; i < gConfigTitleSequences.presets[preset].num_commands; i++) { + if (gConfigTitleSequences.presets[preset].commands[i].command == TITLE_SCRIPT_LOADMM) { + loadmm = true; + gConfigTitleSequences.presets[preset].commands[i].command = TITLE_SCRIPT_LOAD; + gConfigTitleSequences.presets[preset].commands[i].saveIndex = gConfigTitleSequences.presets[duplicate].num_saves; + } + } + + // Create the folder + utf8 path[MAX_PATH], srcPath[MAX_PATH]; + platform_get_user_directory(path, "title sequences"); + strcat(path, gConfigTitleSequences.presets[preset].name); + platform_file_delete(path); + platform_ensure_directory_exists(path); + + // Copy the saves + char separator = platform_get_path_separator(); + for (int i = 0; i < gConfigTitleSequences.presets[preset].num_saves; i++) { + if (gConfigTitleSequences.presets[duplicate].path[0]) { + safe_strncpy(srcPath, gConfigTitleSequences.presets[duplicate].path, MAX_PATH); + strcat(srcPath, gConfigTitleSequences.presets[duplicate].saves[i]); + } + else { + platform_get_user_directory(srcPath, "title sequences"); + strcat(srcPath, gConfigTitleSequences.presets[duplicate].name); + strncat(srcPath, &separator, 1); + strcat(srcPath, gConfigTitleSequences.presets[duplicate].saves[i]); + } + platform_get_user_directory(path, "title sequences"); + strcat(path, gConfigTitleSequences.presets[preset].name); + strncat(path, &separator, 1); + strcat(path, gConfigTitleSequences.presets[preset].saves[i]); + + platform_file_copy(srcPath, path, false); + } + + if (loadmm) { + title_sequence_add_save(preset, get_file_path(PATH_ID_SIXFLAGS_MAGICMOUNTAIN), "Six Flags Magic Mountain.SC6"); + } + + title_sequence_save_preset_script(preset); + gCurrentTitleSequence = preset; + } +} + +void title_sequence_delete_preset(int preset) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets) { + // Delete the folder + utf8 path[MAX_PATH]; + char separator = platform_get_path_separator(); + platform_get_user_directory(path, "title sequences"); + strcat(path, gConfigTitleSequences.presets[preset].name); + if (!platform_directory_delete(path)) { + log_error("Failed to delete directory: \"%s\"", path); + } + + free(gConfigTitleSequences.presets[preset].saves); + free(gConfigTitleSequences.presets[preset].commands); + + for (int i = preset; i < gConfigTitleSequences.num_presets - 1; i++) { + gConfigTitleSequences.presets[i] = gConfigTitleSequences.presets[i + 1]; + } + gConfigTitleSequences.num_presets--; + gConfigTitleSequences.presets = realloc(gConfigTitleSequences.presets, sizeof(title_sequence) * (size_t)gConfigTitleSequences.num_presets); + + gCurrentTitleSequence--; + if (gCurrentPreviewTitleSequence > preset) + title_sequence_change_preset(gCurrentPreviewTitleSequence - 1); + else if (gCurrentPreviewTitleSequence == preset) + title_sequence_change_preset(0); + } +} + +void title_sequence_rename_preset(int preset, const char *newName) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && filename_valid_characters(newName) && !title_sequence_name_exists(newName)) { + // Rename the folder + utf8 src[MAX_PATH], dest[MAX_PATH]; + platform_get_user_directory(src, "title sequences"); + platform_get_user_directory(dest, "title sequences"); + strcat(src, gConfigTitleSequences.presets[preset].name); + strcat(dest, newName); + platform_file_move(src, dest); + + safe_strncpy(gConfigTitleSequences.presets[preset].name, newName, TITLE_SEQUENCE_NAME_SIZE); + + // Rename the config preset name if needed + if (preset == gCurrentPreviewTitleSequence) { + gConfigInterface.current_title_sequence_preset = gConfigTitleSequences.presets[preset].name; + } + } +} + + +void title_sequence_add_save(int preset, const char *path, const char *newName) +{ + utf8 newPath[MAX_PATH]; + char *extension = (char*)path_get_extension(newName); + safe_strncpy(newPath, newName, MAX_PATH); + if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) + strcat(newPath, ".sv6"); + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && filename_valid_characters(newPath) && !title_sequence_save_exists(preset, newPath) && platform_file_exists(path)) { + // Copy the save file + char separator = platform_get_path_separator(); + platform_get_user_directory(newPath, "title sequences"); + strcat(newPath, gConfigTitleSequences.presets[preset].name); + strncat(newPath, &separator, 1); + strcat(newPath, newName); + // Add the appropriate extension if needed + if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) + strcat(newPath, ".sv6"); + platform_file_copy(path, newPath, false); + + gConfigTitleSequences.presets[preset].num_saves++; + gConfigTitleSequences.presets[preset].saves = realloc(gConfigTitleSequences.presets[preset].saves, sizeof(char[TITLE_SEQUENCE_MAX_SAVE_LENGTH]) * (size_t)gConfigTitleSequences.presets[preset].num_saves); + + safe_strncpy(gConfigTitleSequences.presets[preset].saves[gConfigTitleSequences.presets[preset].num_saves - 1], newName, TITLE_SEQUENCE_MAX_SAVE_LENGTH); + // Add the appropriate extension if needed + if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) + strcat(gConfigTitleSequences.presets[preset].saves[gConfigTitleSequences.presets[preset].num_saves - 1], ".sv6"); + } +} + +void title_sequence_remove_save(int preset, int index) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && index >= 0 && index < gConfigTitleSequences.presets[preset].num_saves) { + // Delete the save file + char separator = platform_get_path_separator(); + utf8 path[MAX_PATH]; + platform_get_user_directory(path, "title sequences"); + strcat(path, gConfigTitleSequences.presets[preset].name); + strncat(path, &separator, 1); + strcat(path, gConfigTitleSequences.presets[preset].saves[index]); + platform_file_delete(path); + + // Remove all references to this save in the commands and decrement save indecies + for (int i = 0; i < gConfigTitleSequences.presets[preset].num_commands; i++) { + if (gConfigTitleSequences.presets[preset].commands[i].command == TITLE_SCRIPT_LOAD) { + if (gConfigTitleSequences.presets[preset].commands[i].saveIndex == index) + gConfigTitleSequences.presets[preset].commands[i].saveIndex = 0xFF; + else if (gConfigTitleSequences.presets[preset].commands[i].saveIndex > index && gConfigTitleSequences.presets[preset].commands[i].saveIndex != 0xFF) + gConfigTitleSequences.presets[preset].commands[i].saveIndex--; + } + } + + for (int i = index; i < gConfigTitleSequences.presets[preset].num_saves - 1; i++) { + safe_strncpy(gConfigTitleSequences.presets[preset].saves[i], gConfigTitleSequences.presets[preset].saves[i + 1], TITLE_SEQUENCE_MAX_SAVE_LENGTH); + } + gConfigTitleSequences.presets[preset].num_saves--; + gConfigTitleSequences.presets[preset].saves = realloc(gConfigTitleSequences.presets[preset].saves, sizeof(char[TITLE_SEQUENCE_MAX_SAVE_LENGTH]) * (size_t)gConfigTitleSequences.presets[preset].num_saves); + title_sequence_save_preset_script(preset); + } +} + +void title_sequence_rename_save(int preset, int index, const char *newName) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && index >= 0 && index < gConfigTitleSequences.presets[preset].num_saves && + filename_valid_characters(newName) && !title_sequence_save_exists(preset, newName)) { + + // Rename the save file + char separator = platform_get_path_separator(); + utf8 src[MAX_PATH], dest[MAX_PATH]; + platform_get_user_directory(src, "title sequences"); + platform_get_user_directory(dest, "title sequences"); + strcat(src, gConfigTitleSequences.presets[preset].name); + strcat(dest, gConfigTitleSequences.presets[preset].name); + strncat(src, &separator, 1); + strncat(dest, &separator, 1); + strcat(src, gConfigTitleSequences.presets[preset].saves[index]); + strcat(dest, newName); + // Add the appropriate extension if needed + char *extension = (char*)path_get_extension(newName); + if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) + strcat(dest, ".sv6"); + platform_file_move(src, dest); + + safe_strncpy(gConfigTitleSequences.presets[preset].saves[index], newName, TITLE_SEQUENCE_MAX_SAVE_LENGTH); + // Add the appropriate extension if needed + if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) + strcat(gConfigTitleSequences.presets[preset].saves[index], ".sv6"); + title_sequence_save_preset_script(preset); + } +} + + +void title_sequence_add_command(int preset, title_command command) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets) { + gConfigTitleSequences.presets[preset].commands = realloc(gConfigTitleSequences.presets[preset].commands, sizeof(title_command) * (size_t)(gConfigTitleSequences.presets[preset].num_commands + 1)); + gConfigTitleSequences.presets[preset].commands[gConfigTitleSequences.presets[preset].num_commands] = command; + gConfigTitleSequences.presets[preset].num_commands++; + title_sequence_save_preset_script(preset); + } +} +void title_sequence_insert_command(int preset, int index, title_command command) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && index >= 0 && index <= gConfigTitleSequences.presets[preset].num_commands) { + gConfigTitleSequences.presets[preset].commands = realloc(gConfigTitleSequences.presets[preset].commands, sizeof(title_command) * (size_t)(gConfigTitleSequences.presets[preset].num_commands + 1)); + for (int i = gConfigTitleSequences.presets[preset].num_commands; i > index; i--) { + gConfigTitleSequences.presets[preset].commands[i] = gConfigTitleSequences.presets[preset].commands[i - 1]; + } + gConfigTitleSequences.presets[preset].commands[index] = command; + gConfigTitleSequences.presets[preset].num_commands++; + title_sequence_save_preset_script(preset); + } +} + +void title_sequence_delete_command(int preset, int index) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && index >= 0 && index < gConfigTitleSequences.presets[preset].num_commands) { + for (int i = index; i < gConfigTitleSequences.presets[preset].num_commands - 1; i++) { + gConfigTitleSequences.presets[preset].commands[i] = gConfigTitleSequences.presets[preset].commands[i + 1]; + } + gConfigTitleSequences.presets[preset].num_commands--; + gConfigTitleSequences.presets[preset].commands = realloc(gConfigTitleSequences.presets[preset].commands, sizeof(title_command) * (size_t)gConfigTitleSequences.presets[preset].num_commands); + title_sequence_save_preset_script(preset); + } +} + +void title_sequence_move_down_command(int preset, int index) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && index >= 0 && index + 1 < gConfigTitleSequences.presets[preset].num_commands) { + title_command command = gConfigTitleSequences.presets[preset].commands[index]; + gConfigTitleSequences.presets[preset].commands[index] = gConfigTitleSequences.presets[preset].commands[index + 1]; + gConfigTitleSequences.presets[preset].commands[index + 1] = command; + title_sequence_save_preset_script(preset); + } +} + +void title_sequence_move_up_command(int preset, int index) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && index > 0 && index < gConfigTitleSequences.presets[preset].num_commands) { + title_command command = gConfigTitleSequences.presets[preset].commands[index]; + gConfigTitleSequences.presets[preset].commands[index] = gConfigTitleSequences.presets[preset].commands[index - 1]; + gConfigTitleSequences.presets[preset].commands[index - 1] = command; + title_sequence_save_preset_script(preset); + } +} diff --git a/src/interface/title_sequences.h b/src/interface/title_sequences.h new file mode 100644 index 0000000000..3c46ebbda2 --- /dev/null +++ b/src/interface/title_sequences.h @@ -0,0 +1,68 @@ +/***************************************************************************** +* 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 _TITLE_SEQUENCES_H_ +#define _TITLE_SEQUENCES_H_ + +#include "../common.h" +#include "window.h" +#include "../config.h" +#include "../title.h" + +#define TITLE_SEQUENCE_DEFAULT_PRESETS 2 + +title_command TitleScriptMakeCommand(int command, int parameter1, int parameter2); + +#define TITLE_WAIT(t) TitleScriptMakeCommand(TITLE_SCRIPT_WAIT, t, 0) +#define TITLE_LOADMM() TitleScriptMakeCommand(TITLE_SCRIPT_LOADMM, 0, 0) +#define TITLE_LOCATION(x, y) TitleScriptMakeCommand(TITLE_SCRIPT_LOCATION, x, y) +#define TITLE_ROTATE(n) TitleScriptMakeCommand(TITLE_SCRIPT_ROTATE, n, 0) +#define TITLE_ZOOM(d) TitleScriptMakeCommand(TITLE_SCRIPT_ZOOM, d, 0) +#define TITLE_RESTART() TitleScriptMakeCommand(TITLE_SCRIPT_RESTART, 0, 0) +#define TITLE_LOAD(i) TitleScriptMakeCommand(TITLE_SCRIPT_LOAD, i, 0) + +// The index of the current title sequence being edited +extern uint16 gCurrentTitleSequence; +// The index of the current title sequence being shown +extern uint16 gCurrentPreviewTitleSequence; + +bool title_sequence_name_exists(const char *name); +bool title_sequence_save_exists(int preset, const char *name); + +// Presets +void title_sequence_change_preset(int preset); +void title_sequence_create_preset(const char *name); +void title_sequence_duplicate_preset(int duplicate, const char *name); +void title_sequence_delete_preset(int preset); +void title_sequence_rename_preset(int preset, const char *newName); + +// Saves +void title_sequence_add_save(int preset, const char *path, const char *newName); +void title_sequence_remove_save(int preset, int index); +void title_sequence_rename_save(int preset, int index, const char *newName); + +// Commands +void title_sequence_add_command(int preset, title_command command); +void title_sequence_insert_command(int preset, int index, title_command command); +void title_sequence_delete_command(int preset, int index); +void title_sequence_move_down_command(int preset, int index); +void title_sequence_move_up_command(int preset, int index); + +#endif \ No newline at end of file diff --git a/src/interface/viewport.c b/src/interface/viewport.c index eaa10bc927..87a52f7c07 100644 --- a/src/interface/viewport.c +++ b/src/interface/viewport.c @@ -22,17 +22,22 @@ #include "../config.h" #include "../drawing/drawing.h" #include "../localisation/localisation.h" +#include "../ride/ride_data.h" +#include "../ride/track_data.h" +#include "../ride/track_paint.h" #include "../sprites.h" #include "../world/map.h" #include "../world/sprite.h" #include "../world/banner.h" +#include "../world/entrance.h" +#include "../world/footpath.h" #include "../world/scenery.h" +#include "colour.h" #include "viewport.h" #include "window.h" #define RCT2_FIRST_VIEWPORT (RCT2_ADDRESS(RCT2_ADDRESS_VIEWPORT_LIST, rct_viewport)) #define RCT2_LAST_VIEWPORT (RCT2_ADDRESS(RCT2_ADDRESS_ACTIVE_VIEWPORT_PTR_ARRAY, rct_viewport) - 1) -#define RCT2_NEW_VIEWPORT (RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_VIEWPORT_PTR_ARRAY, rct_viewport*)) //#define DEBUG_SHOW_DIRTY_BOX @@ -66,13 +71,13 @@ struct paint_struct{ uint8 var_1B; paint_struct* attached_ps; //0x1C paint_struct* var_20; - paint_struct* var_24; + paint_struct* next_quadrant_ps; // 0x24 uint8 sprite_type; //0x28 uint8 var_29; uint16 pad_2A; uint16 map_x; // 0x2C uint16 map_y; // 0x2E - rct_map_element *mapElement; // 0x30 + rct_map_element *mapElement; // 0x30 (or sprite pointer) }; /** @@ -82,27 +87,17 @@ struct paint_struct{ */ void viewport_init_all() { - int i, d; - rct_g1_element *g1_element; - - // Palette from sprites? - d = 0; - for (i = 4915; i < 4947; 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])); - d += 8; - } + colours_init_maps(); // Setting up windows RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*) = g_window_list; RCT2_GLOBAL(0x01423604, sint32) = 0; // Setting up viewports - for (i = 0; i < 9; i++) + for (int i = 0; i < 9; i++) { g_viewport_list[i].width = 0; - RCT2_NEW_VIEWPORT = NULL; + } + RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_VIEWPORT_PTR_ARRAY, rct_viewport*) = NULL; // ? RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, sint32) = 0; @@ -116,6 +111,7 @@ void viewport_init_all() format_string((char*)0x0141FA44, STR_CANCEL, NULL); format_string((char*)0x0141F944, STR_OK, NULL); } + /** * rct:0x006EB0C1 * x : ax @@ -128,24 +124,13 @@ void viewport_init_all() void center_2d_coordinates(int x, int y, int z, int* out_x, int* out_y, rct_viewport* viewport){ int start_x = x; - switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)){ - case 0: - x = y - x; - y = (y + start_x) / 2 - z; - break; - case 1: - x = -y - x; - y = (y - start_x) / 2 - z; - break; - case 2: - x = -y + x; - y = (-y - start_x) / 2 - z; - break; - case 3: - x = y + x; - y = (-y + start_x) / 2 - z; - break; - } + rct_xyz16 coord_3d = { + .x = x, + .y = y, + .z = z + }; + + rct_xy16 coord_2d = coordinate_3d_to_2d(&coord_3d, get_current_rotation()); // If the start location was invalid // propagate the invalid location to the output. @@ -156,8 +141,8 @@ void center_2d_coordinates(int x, int y, int z, int* out_x, int* out_y, rct_view return; } - *out_x = x - viewport->view_width / 2; - *out_y = y - viewport->view_height / 2; + *out_x = coord_2d.x - viewport->view_width / 2; + *out_y = coord_2d.y - viewport->view_height / 2; } /** @@ -264,7 +249,7 @@ void sub_689174(sint16* x, sint16* y, sint16 *z) 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); + uint32 rotation = get_current_rotation(); pos.x += x_corr[rotation] * height; pos.y += y_corr[rotation] * height; } @@ -275,38 +260,181 @@ void sub_689174(sint16* x, sint16* y, sint16 *z) *z = height; } -//void sub_6E7FF3(rct_window* w, rct_viewport* viewport, int x, int y){ -// int zoom = 1 << viewport->zoom; -// if (w >= RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*)){ -// if (viewport != w->viewport){ -// if ((viewport->x + viewport->width > w->x) && -// (w->x + w->width > viewport->x) && -// (viewport->y + viewport->height > w->y) && -// (w->y + w->height > viewport->y)){ -// if (viewport->x < w->x){ -// rct_viewport viewport_bkup; -// memcpy(&viewport_bkup, viewport, sizeof(rct_viewport)); -// -// viewport->width = w->x - viewport->x; -// viewport->view_width = (w->x - viewport->x) * zoom; -// -// sub_6E7FF3(w, viewport, x, y); -// -// viewport->x += viewport->width; -// viewport->view_x += viewport->width*zoom; -// viewport->view_width = (viewport_bkup.width - viewport->width) * zoom; -// viewport->width = viewport_bkup.width - viewport->width; -// -// sub_6E7FF3(w, viewport, x, y); -// -// memcpy(viewport, &viewport_bkup, sizeof(rct_viewport)); -// return; -// }//x6E80C4 -// }//0x6E824a -// } // 0x6e824a -// }//x6e8255 -// -//} +void sub_683326(int left, int top, int right, int bottom) +{ + RCT2_CALLPROC_X(0x00683359, left, top, right, bottom, 0, 0, 0); +} + +/** + * shifts pixels from the region in a direction. Used when a viewport moves; + * consider putting in src/drawing/drawing.c or src/drawing/rect.c + * + * rct2: 0x00683359 + * ax = x + * bx = y; + * cx = width; + * dx = height; + * di = dx; + * si = dy; + */ +void gfx_move_screen_rect(int x, int y, int width, int height, int dx, int dy) +{ + // nothing to do + if (dx == 0 && dy == 0) + return; + + // get screen info + rct_drawpixelinfo *screenDPI = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); + + // adjust for move off screen + // NOTE: when zooming, there can be x, y, dx, dy combinations that go off the + // screen; hence the checks. This code should ultimately not be called when + // zooming because this function is specific to updating the screen on move + int lmargin = min(x - dx, 0); + int rmargin = min(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - (x - dx + width), 0); + int tmargin = min(y - dy, 0); + int bmargin = min(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - (y - dy + height), 0); + x -= lmargin; + y -= tmargin; + width += lmargin + rmargin; + height += tmargin + bmargin; + + sint32 stride = screenDPI->width + screenDPI->pitch; + uint8* to = screenDPI->bits + y * stride + x; + uint8* from = screenDPI->bits + (y - dy) * stride + x - dx; + + if (dy > 0) + { + // if positive dy, reverse directions + to += (height - 1) * stride; + from += (height - 1) * stride; + stride = -stride; + } + + // move bits + for (int i = 0; i < height; i++, to += stride, from += stride) + memmove(to, from, width); +} + +void sub_6E7FF3(rct_window *window, rct_viewport *viewport, int x, int y) +{ + // sub-divide by intersecting windows + if (window < RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*)) + { + // skip current window and non-intersecting windows + if (viewport == window->viewport || + viewport->x + viewport->width <= window->x || + viewport->x >= window->x + window->width || + viewport->y + viewport->height <= window->y || + viewport->y >= window->y + window->height){ + sub_6E7FF3(window + 1, viewport, x, y); + return; + } + + // save viewport + rct_viewport view_copy; + memcpy(&view_copy, viewport, sizeof(rct_viewport)); + + if (viewport->x < window->x) + { + viewport->width = window->x - viewport->x; + viewport->view_width = viewport->width << viewport->zoom; + sub_6E7FF3(window, viewport, x, y); + + viewport->x += viewport->width; + viewport->view_x += viewport->width << viewport->zoom; + viewport->width = view_copy.width - viewport->width; + viewport->view_width = viewport->width << viewport->zoom; + sub_6E7FF3(window, viewport, x, y); + } + else if (viewport->x + viewport->width > window->x + window->width) + { + viewport->width = window->x + window->width - viewport->x; + viewport->view_width = viewport->width << viewport->zoom; + sub_6E7FF3(window, viewport, x, y); + + viewport->x += viewport->width; + viewport->view_x += viewport->width << viewport->zoom; + viewport->width = view_copy.width - viewport->width; + viewport->view_width = viewport->width << viewport->zoom; + sub_6E7FF3(window, viewport, x, y); + } + else if (viewport->y < window->y) + { + viewport->height = window->y - viewport->y; + viewport->view_width = viewport->width << viewport->zoom; + sub_6E7FF3(window, viewport, x, y); + + viewport->y += viewport->height; + viewport->view_y += viewport->height << viewport->zoom; + viewport->height = view_copy.height - viewport->height; + viewport->view_width = viewport->width << viewport->zoom; + sub_6E7FF3(window, viewport, x, y); + } + else if (viewport->y + viewport->height > window->y + window->height) + { + viewport->height = window->y + window->height - viewport->y; + viewport->view_width = viewport->width << viewport->zoom; + sub_6E7FF3(window, viewport, x, y); + + viewport->y += viewport->height; + viewport->view_y += viewport->height << viewport->zoom; + viewport->height = view_copy.height - viewport->height; + viewport->view_width = viewport->width << viewport->zoom; + sub_6E7FF3(window, viewport, x, y); + } + + // restore viewport + memcpy(viewport, &view_copy, sizeof(rct_viewport)); + } + else + { + sint16 left = viewport->x; + sint16 right = viewport->x + viewport->width; + sint16 top = viewport->y; + sint16 bottom = viewport->y + viewport->height; + + // if moved more than the viewport size + if (abs(x) < viewport->width && abs(y) < viewport->height) + { + // update whole block ? + gfx_move_screen_rect(viewport->x, viewport->y, viewport->width, viewport->height, x, y); + + if (x > 0) + { + // draw left + sint16 _right = viewport->x + x; + gfx_redraw_screen_rect(left, top, _right, bottom); + left += x; + } + else if (x < 0) + { + // draw right + sint16 _left = viewport->x + viewport->width + x; + gfx_redraw_screen_rect(_left, top, right, bottom); + right += x; + } + + if (y > 0) + { + // draw top + bottom = viewport->y + y; + gfx_redraw_screen_rect(left, top, right, bottom); + } + else if (y < 0) + { + // draw bottom + top = viewport->y + viewport->height + y; + gfx_redraw_screen_rect(left, top, right, bottom); + } + } + else + { + // redraw whole viewport + gfx_redraw_screen_rect(left, top, right, bottom); + } + } +} void sub_6E7F34(rct_window* w, rct_viewport* viewport, sint16 x_diff, sint16 y_diff){ rct_window* orignal_w = w; @@ -340,7 +468,7 @@ void sub_6E7F34(rct_window* w, rct_viewport* viewport, sint16 x_diff, sint16 y_d } w = orignal_w; - RCT2_CALLPROC_X(0x6E7FF3, 0, 0, 0, x_diff, (int)viewport, (int)w, y_diff); + sub_6E7FF3(w, viewport, x_diff, y_diff); } void sub_6E7DE1(sint16 x, sint16 y, rct_window* w, rct_viewport* viewport){ @@ -361,8 +489,8 @@ void sub_6E7DE1(sint16 x, sint16 y, rct_window* w, rct_viewport* viewport){ if (w->flags & WF_7){ int left = max(viewport->x, 0); int top = max(viewport->y, 0); - int right = min(viewport->x + viewport->width, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16)); - int bottom = min(viewport->y + viewport->height, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16)); + int right = min(viewport->x + viewport->width, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16)); + int bottom = min(viewport->y + viewport->height, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16)); if (left >= right) return; if (top >= bottom) return; @@ -381,7 +509,7 @@ void sub_6E7DE1(sint16 x, sint16 y, rct_window* w, rct_viewport* viewport){ viewport->x = 0; } - int eax = viewport->x + viewport->width - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); + int eax = viewport->x + viewport->width - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); if (eax > 0){ viewport->width -= eax; viewport->view_width -= eax * zoom; @@ -399,7 +527,7 @@ void sub_6E7DE1(sint16 x, sint16 y, rct_window* w, rct_viewport* viewport){ viewport->y = 0; } - eax = viewport->y + viewport->height - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16); + eax = viewport->y + viewport->height - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16); if (eax > 0){ viewport->height -= eax; viewport->view_height -= eax * zoom; @@ -447,22 +575,11 @@ void viewport_update_position(rct_window *window) rct_viewport* viewport = window->viewport; if (!viewport)return; - 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 underground = sprite->unknown.z < height; - - 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); + if (window->viewport_target_sprite != -1) { + viewport_update_sprite_follow(window); return; } - sint16 x = viewport->view_width / 2 + window->saved_view_x; sint16 y = viewport->view_height / 2 + window->saved_view_y; sint16 z; @@ -552,6 +669,23 @@ void viewport_update_position(rct_window *window) sub_6E7DE1(x, y, window, viewport); } +void viewport_update_sprite_follow(rct_window *window) +{ + if (window->viewport_target_sprite != -1 && window->viewport){ + 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 underground = sprite->unknown.z < height; + + viewport_set_underground_flag(underground, window, 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, window->viewport); + } +} + /** * * rct2: 0x00685C02 @@ -606,10 +740,9 @@ void viewport_render(rct_drawpixelinfo *dpi, rct_viewport *viewport, int left, i /** * * rct2: 0x0068615B -* ebp: ebp */ -void sub_0x68615B(int ebp){ - RCT2_GLOBAL(0xEE7888, uint32) = ebp; +void painter_setup(){ + RCT2_GLOBAL(0xEE7888, uint32) = 0x00EE788C; RCT2_GLOBAL(0xF1AD28, uint32) = 0; RCT2_GLOBAL(0xF1AD2C, uint32) = 0; uint8* edi = RCT2_ADDRESS(0xF1A50C, uint8); @@ -649,21 +782,20 @@ void paint_attached_ps(paint_struct* ps, paint_struct* attached_ps, rct_drawpixe } } - if (!(attached_ps->var_0C & 1)){ + if (attached_ps->var_0C & 1) { + gfx_draw_sprite_raw_masked(dpi, x, y, image_id, attached_ps->var_04); + } else { gfx_draw_sprite(dpi, image_id, x, y, ps->var_04); } - else{ - RCT2_CALLPROC_X(0x00681DE2, 0, image_id, x, y, 0, (int)dpi, attached_ps->var_04); - } } } void sub_688485(){ rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); paint_struct* ps = RCT2_GLOBAL(0xEE7884, paint_struct*); - paint_struct* previous_ps = ps->var_24; + paint_struct* previous_ps = ps->next_quadrant_ps; - for (ps = ps->var_24; ps;){ + for (ps = ps->next_quadrant_ps; ps;){ sint16 x = ps->x; sint16 y = ps->y; if (ps->sprite_type == 2){ @@ -702,10 +834,10 @@ void sub_688485(){ } } - if (!(ps->var_1A & 1)) - gfx_draw_sprite(dpi, image_id, x, y, ps->var_04); + if (ps->var_1A & 1) + gfx_draw_sprite_raw_masked(dpi, x, y, image_id, ps->var_04); else - RCT2_CALLPROC_X(0x00681DE2, 0, image_id, x, y, 0, (int)dpi, ps->var_04); + gfx_draw_sprite(dpi, image_id, x, y, ps->var_04); if (ps->var_20 != 0){ ps = ps->var_20; @@ -713,40 +845,79 @@ void sub_688485(){ } paint_attached_ps(ps, ps->attached_ps, dpi); - ps = previous_ps->var_24; + ps = previous_ps->next_quadrant_ps; previous_ps = ps; } } -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: 0x006874B0, 0x00687618, 0x0068778C, 0x00687902, 0x0098199C */ +int sub_98199C(sint8 al, sint8 ah, int image_id, sint8 cl, int height, sint16 length_y, sint16 length_x, uint32 rotation){ + RCT2_CALLPROC_X(RCT2_ADDRESS(0x98199C, uint32_t)[get_current_rotation()], + al | (ah << 8), + image_id, + cl, + height, + length_y, + length_x, + rotation); + return 1; +} + +/* rct2: 0x00686806, 0x006869B2, 0x00686B6F, 0x00686D31, 0x0098197C */ +int sub_98197C(sint8 al, sint8 ah, int image_id, sint8 cl, int height, sint16 length_y, sint16 length_x, uint32 rotation){ + int ebp = ah + RCT2_GLOBAL(0x9DEA56, sint16); + + RCT2_GLOBAL(0xF1AD28, paint_struct*) = 0; RCT2_GLOBAL(0xF1AD2C, uint32) = 0; - edx = (edx >> 16) | (ebp << 16); //Not a paint struct but something similar paint_struct* ps = RCT2_GLOBAL(0xEE7888, paint_struct*); - if ((uint32)ps >= RCT2_GLOBAL(0xEE7880, uint32)) return 1; + if ((uint32)ps >= RCT2_GLOBAL(0xEE7880, uint32))return 1; ps->image_id = image_id; - rct_g1_element *g1Element = &g1Elements[image_id & 0x7FFFF]; + rct_g1_element *g1Element; + uint32 image_element = image_id & 0x7FFFF; - eax = (eax & 0xFF) + RCT2_GLOBAL(0x9DE568, uint16); - ecx = (ecx & 0xFF) + RCT2_GLOBAL(0x9DE56C, uint16); + if (image_element < SPR_G2_BEGIN) { + g1Element = &g1Elements[image_element]; + } + else { + g1Element = &g2.elements[image_element - SPR_G2_BEGIN]; + } - int x = ecx - eax; - int y = (ecx + eax) / 2 - (edx & 0xFFFF); + rct_xyz16 coord_3d = { + .x = al, + .y = cl, + .z = height + }; - ps->x = x; - ps->y = y; + switch (rotation) { + case 0: + rotate_map_coordinates(&coord_3d.x, &coord_3d.y, 0); + break; + case 1: + rotate_map_coordinates(&coord_3d.x, &coord_3d.y, 3); + break; + case 2: + rotate_map_coordinates(&coord_3d.x, &coord_3d.y, 2); + break; + case 3: + rotate_map_coordinates(&coord_3d.x, &coord_3d.y, 1); + break; + } + coord_3d.x += RCT2_GLOBAL(0x9DE568, sint16); + coord_3d.y += RCT2_GLOBAL(0x9DE56C, sint16); - int left = x + g1Element->x_offset; - int bottom = y + g1Element->y_offset; + rct_xy16 map = coordinate_3d_to_2d(&coord_3d, rotation); + + ps->x = map.x; + ps->y = map.y; + + int left = map.x + g1Element->x_offset; + int bottom = map.y + g1Element->y_offset; int right = left + g1Element->width; int top = bottom + g1Element->height; @@ -758,53 +929,202 @@ int sub_0x686806(rct_sprite* sprite, int eax, int image_id, int ecx, int edx){ 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; + if (left > dpi->x + dpi->width)return 1; + if (bottom > dpi->y + dpi->height)return 1; - RCT2_GLOBAL(0x9DE568, uint16); - //686918 not finished + rct_xy16 boundBox = { + .x = length_x, + .y = length_y + }; + rct_xy16 s_unk = { + .x = RCT2_GLOBAL(0x9DEA52, sint16), + .y = RCT2_GLOBAL(0x9DEA54, sint16) + }; + + // Unsure why rots 1 and 3 need to swap + switch (rotation){ + case 0: + boundBox.x--; + boundBox.y--; + rotate_map_coordinates(&s_unk.x, &s_unk.y, 0); + rotate_map_coordinates(&boundBox.x, &boundBox.y, 0); + break; + case 1: + boundBox.x--; + rotate_map_coordinates(&s_unk.x, &s_unk.y, 3); + rotate_map_coordinates(&boundBox.x, &boundBox.y, 3); + break; + case 2: + rotate_map_coordinates(&boundBox.x, &boundBox.y, 2); + rotate_map_coordinates(&s_unk.x, &s_unk.y, 2); + break; + case 3: + boundBox.y--; + rotate_map_coordinates(&boundBox.x, &boundBox.y, 1); + rotate_map_coordinates(&s_unk.x, &s_unk.y, 1); + break; + } + + ps->other_x = boundBox.x + s_unk.x + RCT2_GLOBAL(0x9DE568, sint16); + ps->some_x = RCT2_GLOBAL(0x009DEA56, sint16); + ps->some_y = ebp; + ps->other_y = boundBox.y + s_unk.y + RCT2_GLOBAL(0x009DE56C, sint16); + ps->var_1A = 0; + ps->attached_x = s_unk.x + RCT2_GLOBAL(0x9DE568, sint16); + ps->attached_y = s_unk.y + RCT2_GLOBAL(0x009DE56C, sint16); + ps->attached_ps = NULL; + ps->var_20 = NULL; + ps->sprite_type = RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8); + ps->var_29 = RCT2_GLOBAL(0x9DE571, uint8); + ps->map_x = RCT2_GLOBAL(0x9DE574, uint16); + ps->map_y = RCT2_GLOBAL(0x9DE576, uint16); + ps->mapElement = RCT2_GLOBAL(0x9DE578, rct_map_element*); + + RCT2_GLOBAL(0xF1AD28, paint_struct*) = ps; + + rct_xy16 attach = { + .x = ps->attached_x, + .y = ps->attached_y + }; + + rotate_map_coordinates(&attach.x, &attach.y, rotation); + switch (rotation){ + case 0: + break; + case 1: + case 3: + attach.x += 0x2000; + break; + case 2: + attach.x += 0x4000; + break; + } + + sint16 di = attach.x + attach.y; + + if (di < 0) + di = 0; + + di /= 32; + if (di > 511) + di = 511; + + ps->var_18 = di; + paint_struct* old_ps = RCT2_ADDRESS(0x00F1A50C, paint_struct*)[di]; + RCT2_ADDRESS(0x00F1A50C, paint_struct*)[di] = ps; + ps->next_quadrant_ps = old_ps; + + if ((uint16)di < RCT2_GLOBAL(0x00F1AD0C, uint32)){ + RCT2_GLOBAL(0x00F1AD0C, uint32) = di; + } + + if ((uint16)di > RCT2_GLOBAL(0x00F1AD10, uint32)){ + RCT2_GLOBAL(0x00F1AD10, uint32) = di; + } + + RCT2_GLOBAL(0xEE7888, paint_struct*) += 1; return 0; } +/** + * + * rct2: 0x006D4244 + */ +void viewport_vehicle_paint_setup(rct_vehicle *vehicle, int imageDirection) +{ + rct_ride_type *rideEntry; + const rct_ride_type_vehicle *vehicleEntry; + + int x = vehicle->x; + int y = vehicle->y; + int z = vehicle->z; + + if (vehicle->var_0C & 0x80) { + uint32 ebx = 22965 + vehicle->var_C5; + RCT2_GLOBAL(0x9DEA52, uint16) = 0; + RCT2_GLOBAL(0x9DEA54, uint16) = 0; + RCT2_GLOBAL(0x9DEA56, uint16) = z + 2; + sub_98197C(0, 0, ebx, 0, z, 1, 1, get_current_rotation()); + return; + } + + if (vehicle->ride_subtype == 0xFF) { + vehicleEntry = &CableLiftVehicle; + } else { + rideEntry = GET_RIDE_ENTRY(vehicle->ride_subtype); + vehicleEntry = &rideEntry->vehicles[vehicle->vehicle_type]; + + if (vehicle->update_flags & VEHICLE_UPDATE_FLAG_11) { + vehicleEntry++; + z += 16; + } + } + + uint32 rct2VehiclePtrFormat = ((uint32)vehicleEntry) - offsetof(rct_ride_type, vehicles); + RCT2_GLOBAL(0x00F64DFC, uint32) = rct2VehiclePtrFormat; + switch (vehicleEntry->car_visual) { + case VEHICLE_VISUAL_DEFAULT: RCT2_CALLPROC_X(0x006D45F8, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + case VEHICLE_VISUAL_LAUNCHED_FREEFALL: RCT2_CALLPROC_X(0x006D5FAB, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + case VEHICLE_VISUAL_OBSERVATION_TOWER: RCT2_CALLPROC_X(0x006D6258, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + case VEHICLE_VISUAL_RIVER_RAPIDS: RCT2_CALLPROC_X(0x006D5889, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + case VEHICLE_VISUAL_MINI_GOLF_PLAYER: RCT2_CALLPROC_X(0x006D42F0, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + case VEHICLE_VISUAL_MINI_GOLF_BALL: RCT2_CALLPROC_X(0x006D43C6, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + case VEHICLE_VISUAL_REVERSER: RCT2_CALLPROC_X(0x006D4453, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + case VEHICLE_VISUAL_SPLASH_BOATS_OR_WATER_COASTER: RCT2_CALLPROC_X(0x006D4295, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + case VEHICLE_VISUAL_ROTO_DROP: RCT2_CALLPROC_X(0x006D5DA9, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + case 10: RCT2_CALLPROC_X(0x006D5600, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + case 11: RCT2_CALLPROC_X(0x006D5696, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + case 12: RCT2_CALLPROC_X(0x006D57EE, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + case 13: RCT2_CALLPROC_X(0x006D5783, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + case 14: RCT2_CALLPROC_X(0x006D5701, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + case VEHICLE_VISUAL_VIRGINIA_REEL: RCT2_CALLPROC_X(0x006D5B48, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + case VEHICLE_VISUAL_SUBMARINE: RCT2_CALLPROC_X(0x006D44D5, x, imageDirection, y, z, (int)vehicle, rct2VehiclePtrFormat, 0); break; + } +} /** -* Litter Paint Setup?? + * + * rct2: 0x0068F0FB + */ +void viewport_peep_paint_setup(rct_peep *peep, int imageDirection) +{ + RCT2_CALLPROC_X(0x0068F0FB, peep->x, imageDirection, peep->y, peep->z, (int)peep, 0, 0); +} + +/** + * + * rct2: 0x00672AC9 + */ +void viewport_misc_paint_setup(rct_sprite *misc, int imageDirection) +{ + RCT2_CALLPROC_X(0x00672AC9, misc->unknown.x, imageDirection, misc->unknown.y, misc->unknown.z, (int)misc, 0, 0); +} + +/** +* Litter Paint Setup * rct2: 0x006736FC */ -void sub_0x6736FC(rct_litter* litter, int ebx, int edx){ - rct_drawpixelinfo* dpi; +void viewport_litter_paint_setup(rct_litter *litter, int imageDirection) +{ + rct_drawpixelinfo *dpi; dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); - if (dpi->zoom_level != 0)return; //If zoomed at all no litter drawn + if (dpi->zoom_level != 0) return; // If zoomed at all no litter drawn + + // litter has no sprite direction so remove that + imageDirection >>= 3; + // Some litter types have only 1 direction so remove + // anything that isn't required. + imageDirection &= RCT2_ADDRESS(0x97EF6C, uint32)[litter->type * 2 + 1]; + + uint32 image_id = imageDirection + RCT2_ADDRESS(0x97EF6C, uint32)[litter->type * 2]; - int ebp = litter->var_01; - //push litter - ebx >>= 3; - ebx &= RCT2_ADDRESS(0x97EF6C, uint32)[ebp * 2 + 1]; - ebx += RCT2_ADDRESS(0x97EF6C, uint32)[ebp * 2]; - int ecx = 0; - int edi = 4; - int esi = 4; - int eax = 0xFF00; RCT2_GLOBAL(0x9DEA52, uint16) = 0xFFFC; RCT2_GLOBAL(0x9DEA54, uint16) = 0xFFFC; - RCT2_GLOBAL(0x9DEA56, uint16) = edx + 2; + RCT2_GLOBAL(0x9DEA56, uint16) = litter->z + 2; - switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)){ - case 0: - //0x686806 - break; - case 1: - //0x6869b2 - break; - case 2: - //0x686b6f - break; - case 3: - //0x686d31 - break; - } + sub_98197C(0, 0xFF, image_id, 0, litter->z, 4, 4, get_current_rotation()); } @@ -812,7 +1132,7 @@ void sub_0x6736FC(rct_litter* litter, int ebx, int edx){ * Paint Quadrant * rct2: 0x0069E8B0 */ -void sub_0x69E8B0(uint16 eax, uint16 ecx){ +void sprite_paint_setup(uint16 eax, uint16 ecx){ uint32 _eax = eax, _ecx = ecx; rct_drawpixelinfo* dpi; @@ -821,7 +1141,7 @@ void sub_0x69E8B0(uint16 eax, uint16 ecx){ dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); - if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & 0x4000)return; + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & VIEWPORT_FLAG_INVISIBLE_SPRITES) return; if (dpi->zoom_level > 2) return; @@ -832,7 +1152,7 @@ void sub_0x69E8B0(uint16 eax, uint16 ecx){ 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.next_in_quadrant){ spr = &g_sprite_list[sprite_idx]; dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); @@ -842,376 +1162,786 @@ void sub_0x69E8B0(uint16 eax, uint16 ecx){ if (dpi->x + dpi->width <= spr->unknown.sprite_left)continue; if (spr->unknown.sprite_right <= dpi->x)continue; - int ebx = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); + int image_direction = get_current_rotation(); + image_direction <<= 3; + image_direction += spr->unknown.sprite_direction; + image_direction &= 0x1F; + RCT2_GLOBAL(0x9DE578, uint32) = (uint32)spr; int ebp = spr->unknown.sprite_identifier; - ebx <<= 3; - eax = spr->unknown.x; - ebx += spr->unknown.sprite_direction; - ecx = spr->unknown.y; - ebx &= 0x1F; - RCT2_GLOBAL(0x9DE568, uint16) = spr->unknown.x; - RCT2_GLOBAL(0x9DE570, uint8) = 2; - RCT2_GLOBAL(0x9DE56C, uint16) = spr->unknown.y; - int edx = spr->unknown.z; + + RCT2_GLOBAL(0x9DE568, sint16) = spr->unknown.x; + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8) = VIEWPORT_INTERACTION_ITEM_SPRITE; + RCT2_GLOBAL(0x9DE56C, sint16) = spr->unknown.y; + switch (spr->unknown.sprite_identifier){ case SPRITE_IDENTIFIER_VEHICLE: - RCT2_CALLPROC_X(0x6D4244, eax, ebx, ecx, edx, (int)spr, (int)dpi, ebp); + viewport_vehicle_paint_setup((rct_vehicle*)spr, image_direction); break; case SPRITE_IDENTIFIER_PEEP: - RCT2_CALLPROC_X(0x68F0FB, eax, ebx, ecx, edx, (int)spr, (int)dpi, ebp); + viewport_peep_paint_setup((rct_peep*)spr, image_direction); break; case SPRITE_IDENTIFIER_MISC: - RCT2_CALLPROC_X(0x672AC9, eax, ebx, ecx, edx, (int)spr, (int)dpi, ebp); + viewport_misc_paint_setup(spr, image_direction); break; case SPRITE_IDENTIFIER_LITTER: - RCT2_CALLPROC_X(0x6736FC, eax, ebx, ecx, edx, (int)spr, (int)dpi, ebp); + viewport_litter_paint_setup((rct_litter*)spr, image_direction); + break; + default: + assert(false); break; } } } -/*rct2: 0x006C42D9*/ -int sub_6C42D9(rct_string_id string_id, int scroll, int ebp) +/* rct2: 0x006629BC + * returns al + * ebp : image_id + * ax : unknown + * dx : height + * edi : unknown + */ +bool sub_6629BC(int height, uint16 ax, uint32 image_id, int edi){ + int eax = ax, ebx = 0, ecx = 0, edx = height, esi = 0, _edi = edi, ebp = image_id; + + RCT2_CALLFUNC_X(0x006629BC, &eax, &ebx, &ecx, &edx, &esi, &_edi, &ebp); + + return eax & 0xFF; +} + +/* rct2: 0x0066508C & 0x00665540 */ +void viewport_ride_entrance_exit_paint_setup(uint8 direction, int height, rct_map_element* map_element) { 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; + uint8 is_exit = map_element->properties.entrance.type == ENTRANCE_TYPE_RIDE_EXIT; + + if (RCT2_GLOBAL(0x9DEA6F, uint8_t) & 1){ + if (map_element->properties.entrance.ride_index != RCT2_GLOBAL(0x00F64DE8, uint8)) + return; + } + + rct_ride* ride = GET_RIDE(map_element->properties.entrance.ride_index); + if (ride->entrance_style == RIDE_ENTRANCE_STYLE_NONE) return; + + const rct_ride_entrance_definition *style = &RideEntranceDefinitions[ride->entrance_style]; + + uint8 colour_1, colour_2; + uint32 transparant_image_id = 0, image_id = 0; + if (style->flags & (1 << 30)) { + colour_1 = ride->track_colour_main[0] + 0x70; + transparant_image_id = (colour_1 << 19) | 0x40000000; + } + + colour_1 = ride->track_colour_main[0]; + colour_2 = ride->track_colour_additional[0]; + image_id = (colour_1 << 19) | (colour_2 << 24) | 0xA0000000; + + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8) = VIEWPORT_INTERACTION_ITEM_RIDE; + RCT2_GLOBAL(0x009E32BC, uint32) = 0; + + if (map_element->flags & MAP_ELEMENT_FLAG_GHOST){ + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8) = VIEWPORT_INTERACTION_ITEM_NONE; + image_id = RCT2_ADDRESS(0x993CC4, uint32_t)[RCT2_GLOBAL(0x9AACBF, uint8)]; + RCT2_GLOBAL(0x009E32BC, uint32) = image_id; + if (transparant_image_id) + transparant_image_id = image_id; + } + + if (is_exit){ + image_id |= style->sprite_index + direction + 8; + } + else{ + image_id |= style->sprite_index + direction; + } + // Format modifed to stop repeated code + + // Each entrance is split into 2 images for drawing + // Certain entrance styles have another 2 images to draw for coloured windows + + RCT2_GLOBAL(0x009DEA52, uint16) = 2; + RCT2_GLOBAL(0x009DEA54, uint16) = 2; + RCT2_GLOBAL(0x009DEA56, uint16) = height; + + sint8 ah = is_exit ? 0x23 : 0x33; + + sint16 lengthY = (direction & 1) ? 28 : 2; + sint16 lengthX = (direction & 1) ? 2 : 28; + + sub_98197C(0, ah, image_id, 0, height, lengthY, lengthX, get_current_rotation()); + + if (transparant_image_id){ + if (is_exit){ + transparant_image_id |= style->sprite_index + direction + 24; } - 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; + else{ + transparant_image_id |= style->sprite_index + direction + 16; + } + RCT2_GLOBAL(0x009DEA52, uint16) = 2; + RCT2_GLOBAL(0x009DEA54, uint16) = 2; + RCT2_GLOBAL(0x009DEA56, uint16) = height; + + sub_98199C(0, ah, transparant_image_id, 0, height, lengthY, lengthX, 0); + } + + image_id += 4; + + RCT2_GLOBAL(0x009DEA52, uint16) = (direction & 1) ? 28 : 2; + RCT2_GLOBAL(0x009DEA54, uint16) = (direction & 1) ? 2 : 28; + RCT2_GLOBAL(0x009DEA56, uint16) = height; + + sub_98197C(0, ah, image_id, 0, height, lengthY, lengthX, get_current_rotation()); + + if (transparant_image_id){ + transparant_image_id += 4; + RCT2_GLOBAL(0x009DEA52, uint16) = (direction & 1) ? 28 : 2; + RCT2_GLOBAL(0x009DEA54, uint16) = (direction & 1) ? 2 : 28; + RCT2_GLOBAL(0x009DEA56, uint16) = height; + + sub_98199C(0, ah, transparant_image_id, 0, height, lengthY, lengthX, 0); + } + + uint32 eax = 0xFFFF0600 | ((height / 16) & 0xFF); + if (direction & 1){ + RCT2_ADDRESS(0x009E30B6, uint32)[RCT2_GLOBAL(0x141F56B, uint8) / 2] = eax; + RCT2_GLOBAL(0x141F56B, uint8)++; + } + else{ + RCT2_ADDRESS(0x009E3138, uint32)[RCT2_GLOBAL(0x141F56A, uint8) / 2] = eax; + RCT2_GLOBAL(0x141F56A, uint8)++; + } + + if (!is_exit && + !(map_element->flags & MAP_ELEMENT_FLAG_GHOST) && + map_element->properties.entrance.ride_index != 0xFF){ + + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) = 0; + RCT2_GLOBAL(0x13CE956, uint32) = 0; + + rct_string_id string_id = STR_RIDE_ENTRANCE_CLOSED; + + if (ride->status == RIDE_STATUS_OPEN && + !(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)){ + + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, rct_string_id) = ride->name; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 2, uint32) = ride->name_arguments; + + string_id = STR_RIDE_ENTRANCE_NAME; + } + + utf8 entrance_string[MAX_PATH]; + if (gConfigGeneral.upper_case_banners) { + format_string_to_upper(entrance_string, string_id, RCT2_ADDRESS(RCT2_ADDRESS_COMMON_FORMAT_ARGS, void)); + } else { + format_string(entrance_string, string_id, RCT2_ADDRESS(RCT2_ADDRESS_COMMON_FORMAT_ARGS, void)); + } + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0x1C0; + + uint16 string_width = gfx_get_string_width(entrance_string); + uint16 scroll = (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) / 2) % string_width; + + RCT2_GLOBAL(0x009DEA52, uint16) = 2; + RCT2_GLOBAL(0x009DEA54, uint16) = 2; + RCT2_GLOBAL(0x009DEA56, uint16) = height + style->height; + sub_98199C(0, 0x33, scrolling_text_setup(string_id, scroll, style->scrolling_mode), 0, height + style->height, 0x1C, 0x1C, 0); + } + + image_id = RCT2_GLOBAL(0x009E32BC, uint32); + if (!image_id){ + image_id = 0x20B80000; + } + + if (direction & 1){ + sub_6629BC(height, 0, image_id, 1); + } + else{ + sub_6629BC(height, 0, image_id, 0); + } + + RCT2_GLOBAL(0x141E9B4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9B8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9BC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9CC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D4, uint16) = 0xFFFF; + + height += is_exit ? 40 : 56; + if (RCT2_GLOBAL(0x141E9D8, sint16) < height){ + RCT2_GLOBAL(0x141E9D8, sint16) = height; + RCT2_GLOBAL(0x141E9DA, uint8) = 32; + } +} + +/* rct2: 0x006658ED */ +void viewport_park_entrance_paint_setup(uint8 direction, int height, rct_map_element* map_element){ + if (RCT2_GLOBAL(0x9DEA6F, uint8_t) & 1) + return; + + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8) = VIEWPORT_INTERACTION_ITEM_PARK; + RCT2_GLOBAL(0x009E32BC, uint32) = 0; + uint32 image_id, ghost_id = 0; + if (map_element->flags & MAP_ELEMENT_FLAG_GHOST){ + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8) = VIEWPORT_INTERACTION_ITEM_NONE; + ghost_id = RCT2_ADDRESS(0x993CC4, uint32)[RCT2_GLOBAL(0x9AACBF, uint8)]; + RCT2_GLOBAL(0x009E32BC, uint32) = ghost_id; + } + + rct_path_type* path_entry = g_pathTypeEntries[map_element->properties.entrance.path_type]; + + // Index to which part of the entrance + // Middle, left, right + uint8 part_index = map_element->properties.entrance.index & 0xF; + rct_entrance_type* entrance; + uint8 di = (direction / 2 + part_index / 2) & 1 ? 0x1A : 0x20; + + switch (part_index){ + case 0: + image_id = (path_entry->image + 5 * (1 + (direction & 1))) | ghost_id; + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 2; + RCT2_GLOBAL(0x009DEA56, sint16) = height; + + sub_98197C(0, 0, image_id, 0, height, 0x1C, 32, get_current_rotation()); + + entrance = (rct_entrance_type*)object_entry_groups[OBJECT_TYPE_PARK_ENTRANCE].chunks[0]; + image_id = (entrance->image_id + direction * 3) | ghost_id; + + RCT2_GLOBAL(0x009DEA52, uint16) = 2; + RCT2_GLOBAL(0x009DEA54, uint16) = 2; + RCT2_GLOBAL(0x009DEA56, sint16) = height + 32; + + sub_98197C(0, 0x2F, image_id, 0, height, 0x1C, 0x1C, get_current_rotation()); + + if ((direction + 1) & (1 << 1)) + break; + if (ghost_id != 0) + break; + + rct_string_id park_text_id = 1730; + RCT2_GLOBAL(0x0013CE952, uint32) = 0; + RCT2_GLOBAL(0x0013CE956, uint32) = 0; + + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_OPEN){ + RCT2_GLOBAL(0x0013CE952, rct_string_id) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id); + RCT2_GLOBAL(0x0013CE954, rct_string_id) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME_ARGS, rct_string_id); + + park_text_id = 1731; + } + + utf8 park_name[MAX_PATH]; + if (gConfigGeneral.upper_case_banners) { + format_string_to_upper(park_name, park_text_id, RCT2_ADDRESS(RCT2_ADDRESS_COMMON_FORMAT_ARGS, void)); + } else { + format_string(park_name, park_text_id, RCT2_ADDRESS(RCT2_ADDRESS_COMMON_FORMAT_ARGS, void)); + } + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0x1C0; + uint16 string_width = gfx_get_string_width(park_name); + uint16 scroll = (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) / 2) % string_width; + + if (entrance->scrolling_mode == 0xFF) + break; + + RCT2_GLOBAL(0x009DEA52, uint16) = 2; + RCT2_GLOBAL(0x009DEA54, uint16) = 2; + RCT2_GLOBAL(0x009DEA56, sint16) = height + entrance->text_height; + + sub_98199C(0, 0x2F, scrolling_text_setup(park_text_id, scroll, entrance->scrolling_mode + direction / 2), 0, height + entrance->text_height, 0x1C, 0x1C, 0); + break; + case 1: + case 2: + entrance = (rct_entrance_type*)object_entry_groups[OBJECT_TYPE_PARK_ENTRANCE].chunks[0]; + image_id = (entrance->image_id + part_index + direction * 3) | ghost_id; + + RCT2_GLOBAL(0x009DEA52, uint16) = 3; + RCT2_GLOBAL(0x009DEA54, uint16) = 3; + RCT2_GLOBAL(0x009DEA56, sint16) = height; + + sub_98197C(0, 0x4F, image_id, 0, height, di, 0x1A, get_current_rotation()); + break; + } + + image_id = ghost_id; + if (!image_id){ + image_id = 0x20B80000; + } + + if (direction & 1){ + sub_6629BC(height, 0, image_id, 1); + } + else{ + sub_6629BC(height, 0, image_id, 0); + } + + RCT2_GLOBAL(0x141E9B4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9B8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9BC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9CC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D4, uint16) = 0xFFFF; + + height += 80; + if (RCT2_GLOBAL(0x141E9D8, sint16) < height){ + RCT2_GLOBAL(0x141E9D8, sint16) = height; + RCT2_GLOBAL(0x141E9DA, uint8) = 32; + } +} + +/** + * + * rct2: 0x006C4794 + */ +void viewport_track_paint_setup(uint8 direction, int height, rct_map_element *mapElement) +{ + rct_drawpixelinfo *dpi = RCT2_GLOBAL(0x0140E9A8, rct_drawpixelinfo*); + rct_ride *ride; + int rideIndex, trackType, trackColourScheme, trackSequence; + + rideIndex = mapElement->properties.track.ride_index; + ride = GET_RIDE(rideIndex); + + // HACK Set entrance style to plain if none to stop glitch until entrance track piece is implemented + bool isEntranceStyleNone = false; + if (ride->entrance_style == RIDE_ENTRANCE_STYLE_NONE) { + isEntranceStyleNone = true; + ride->entrance_style = RIDE_ENTRANCE_STYLE_PLAIN; + } + + if (!(RCT2_GLOBAL(0x009DEA6F, uint8) & 1) || rideIndex == RCT2_GLOBAL(0x00F64DE8, uint8)) { + trackType = mapElement->properties.track.type; + trackSequence = mapElement->properties.track.sequence & 0x0F; + trackColourScheme = mapElement->properties.track.colour & 3; + + if ((RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & VIEWPORT_FLAG_TRACK_HEIGHTS) && dpi->zoom_level == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8) = 0; + if (RCT2_ADDRESS(0x00999694, uint32)[trackType] & (1 << trackSequence)) { + uint16 ax = RCT2_GLOBAL(0x0097D21A + (ride->type * 8), uint8); + uint32 ebx = 0x20381689 + (height + 8) / 16; + ebx += RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, uint16); + ebx -= RCT2_GLOBAL(0x01359208, uint16); + RCT2_GLOBAL(0x009DEA52, uint16) = 1000; + RCT2_GLOBAL(0x009DEA54, uint16) = 1000; + RCT2_GLOBAL(0x009DEA56, uint16) = 2047; + sub_98197C(16, 0, ebx, 16, height + ax + 3, 1, 1, get_current_rotation()); + } + } + + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8) = 3; + RCT2_GLOBAL(0x00F44198, uint32) = (ride->track_colour_main[trackColourScheme] << 19) | (ride->track_colour_additional[trackColourScheme] << 24) | 0xA0000000; + RCT2_GLOBAL(0x00F441A0, uint32) = 0x20000000; + RCT2_GLOBAL(0x00F441A4, uint32) = 0x20C00000; + RCT2_GLOBAL(0x00F4419C, uint32) = (ride->track_colour_supports[trackColourScheme] << 19) | 0x20000000; + if (mapElement->type & 0x40) { + RCT2_GLOBAL(0x00F44198, uint32) = 0x21600000; + RCT2_GLOBAL(0x00F4419C, uint32) = 0x21600000; + RCT2_GLOBAL(0x00F441A0, uint32) = 0x21600000; + RCT2_GLOBAL(0x00F441A4, uint32) = 0x21600000; + } + if (mapElement->flags & MAP_ELEMENT_FLAG_GHOST) { + uint32 ghost_id = RCT2_ADDRESS(0x00993CC4, uint32)[RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CONSTRUCTION_MARKER, uint8)]; + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8) = 0; + RCT2_GLOBAL(0x00F44198, uint32) = ghost_id; + RCT2_GLOBAL(0x00F4419C, uint32) = ghost_id; + RCT2_GLOBAL(0x00F441A0, uint32) = ghost_id; + RCT2_GLOBAL(0x00F441A4, uint32) = ghost_id; + } + + TRACK_PAINT_FUNCTION **trackTypeList = (TRACK_PAINT_FUNCTION**)RideTypeTrackPaintFunctionsOld[ride->type]; + if (trackTypeList == NULL) { + trackTypeList = (TRACK_PAINT_FUNCTION**)RideTypeTrackPaintFunctions[ride->type]; + + if (trackTypeList[trackType] != NULL) + trackTypeList[trackType][direction](rideIndex, trackSequence, direction, height, mapElement); + } + else { + uint32 *trackDirectionList = (uint32*)trackTypeList[trackType]; + + // Have to call from this point as it pushes esi and expects callee to pop it + RCT2_CALLPROC_X( + 0x006C4934, + ride->type, + (int)trackDirectionList, + direction, + height, + (int)mapElement, + rideIndex * sizeof(rct_ride), + trackSequence + ); } } - 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; - } + + if (isEntranceStyleNone) { + ride->entrance_style = RIDE_ENTRANCE_STYLE_NONE; + } +} + +/* rct2: 0x00664FD4 */ +void viewport_entrance_paint_setup(uint8 direction, int height, rct_map_element* map_element){ + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8_t) = VIEWPORT_INTERACTION_ITEM_LABEL; + + rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & VIEWPORT_FLAG_PATH_HEIGHTS && + dpi->zoom_level == 0){ + uint32 ebx = + (map_element->properties.entrance.type << 4) | + (map_element->properties.entrance.index & 0xF); + + if (RCT2_ADDRESS(0x0097B974, uint8)[ebx] & 0xF){ + + int z = map_element->base_height * 8 + 3; + uint32 image_id = + z / 16 + + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS,sint16) + + 0x20101689; + + image_id -= RCT2_GLOBAL(0x01359208, sint16); + + RCT2_GLOBAL(0x009DEA52, uint16) = 31; + RCT2_GLOBAL(0x009DEA54, uint16) = 31; + RCT2_GLOBAL(0x009DEA56, sint16) = z; + RCT2_GLOBAL(0x009DEA56, uint16) += 64; + + sub_98197C(16, 0, image_id, 16, height, 1, 1, get_current_rotation()); } } + + switch (map_element->properties.entrance.type){ + case ENTRANCE_TYPE_RIDE_ENTRANCE: + case ENTRANCE_TYPE_RIDE_EXIT: + viewport_ride_entrance_exit_paint_setup(direction, height, map_element); + break; + case ENTRANCE_TYPE_PARK_ENTRANCE: + viewport_park_entrance_paint_setup(direction, height, map_element); + break; + } } /* rct2: 0x006B9CC4 */ -void viewport_banner_paint_setup(uint32_t direction, int edx, rct_map_element* map_element) +void viewport_banner_paint_setup(uint8 direction, int height, rct_map_element* map_element) { rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); - RCT2_GLOBAL(0x9DE570, uint8_t) = 0xC; + + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8_t) = VIEWPORT_INTERACTION_ITEM_BANNER; + if (dpi->zoom_level > 1 || RCT2_GLOBAL(0x9DEA6F, uint8_t) & 1) return; - edx -= 16; + + height -= 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(0x9DEA56, uint16_t) = height + 2; + + RCT2_GLOBAL(0x9DEA52, uint32_t) = RCT2_ADDRESS(0x98D884, uint32)[direction * 2]; + + uint32 base_id = (direction << 1) + banner_scenery->image; + uint32 image_id = base_id; + + if (map_element->flags & MAP_ELEMENT_FLAG_GHOST)//if being placed { - RCT2_GLOBAL(0x9DE570, uint8_t) = 0; - ebx &= 0x7FFFF; - ebx |= RCT2_ADDRESS(0x993CC4, uint32_t)[RCT2_GLOBAL(0x9AACBF, uint8_t)]; + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8_t) = VIEWPORT_INTERACTION_ITEM_NONE; + image_id |= RCT2_ADDRESS(0x993CC4, uint32_t)[RCT2_GLOBAL(0x9AACBF, uint8)]; } - 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)); + else{ + image_id |= + (gBanners[map_element->properties.banner.index].colour << 19) | + 0x20000000; + } + + sub_98197C(0, 0x15, image_id, 0, height, 1, 1, get_current_rotation()); + RCT2_GLOBAL(0x9DEA52, uint32) = RCT2_ADDRESS(0x98D888, uint32)[direction * 2]; + + image_id++; + sub_98197C(0, 0x15, image_id, 0, height, 1, 1, get_current_rotation()); + + // Opposite direction 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; + // If text not showing / ghost + if (direction >= 2 || (map_element->flags & MAP_ELEMENT_FLAG_GHOST)) return; + + uint16 scrollingMode = banner_scenery->banner.scrolling_mode; + scrollingMode += direction; + + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) = 0; RCT2_GLOBAL(0x13CE956, uint32_t) = 0; - rct_string_id string_id = 0xBA5;//no entry + + rct_string_id string_id = STR_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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = gBanners[map_element->properties.banner.index].string_idx; + string_id = STR_BANNER_TEXT; } - 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); + if (gConfigGeneral.upper_case_banners) { + format_string_to_upper(RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char), string_id, RCT2_ADDRESS(RCT2_ADDRESS_COMMON_FORMAT_ARGS, void)); + } else { + format_string(RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char), string_id, RCT2_ADDRESS(RCT2_ADDRESS_COMMON_FORMAT_ARGS, void)); + } + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 0x1C0; + + uint16 string_width = gfx_get_string_width(RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char)); + uint16 scroll = (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) / 2) % string_width; + + sub_98199C(0, 0x15, scrolling_text_setup(string_id, scroll, scrollingMode), 0, height + 22, 1, 1, 0); } -/*rct2: 0x0068B35F*/ -void sub_68B35F(int ax, int cx) +/** + * + * rct2: 0x0068B3FB + */ +static void sub_68B3FB(int x, int y) { - 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)) - { + rct_drawpixelinfo *dpi = RCT2_GLOBAL(0x0140E9A8, rct_drawpixelinfo*); - 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; - } - } - } + 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) = x; + RCT2_GLOBAL(0x9DE56E, uint16_t) = y; + RCT2_GLOBAL(0x9DE574, uint16_t) = x; + RCT2_GLOBAL(0x9DE576, uint16_t) = y; + + rct_map_element* map_element = map_get_first_element_at(x >> 5, y >> 5); + + int dx = 0; + switch (get_current_rotation()) { + case 0: + dx = x + y; + break; + case 1: + x += 32; + dx = y - x; + break; + case 2: + x += 32; + y += 32; + dx = -(x + y); + break; + case 3: + y += 32; + dx = x - y; + break; } - else - { - rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); - int dx; - switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32_t)) + dx >>= 1; + // Display little yellow arrow when building footpaths? + if ((RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & 4) && + RCT2_GLOBAL(0x9DE56A, uint16) == RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_X, uint16) && + RCT2_GLOBAL(0x9DE56E, uint16) == RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_Y, uint16)){ + uint8 arrowRotation = + (get_current_rotation() + + (RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_DIRECTION, uint8) & 3)) & 3; + + uint32 imageId = + arrowRotation + + (RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_DIRECTION, uint8) & 0xFC) + + 0x20900C27; + + int arrowZ = RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_Z, uint16); + + RCT2_GLOBAL(0x9DE568, sint16) = x; + RCT2_GLOBAL(0x9DE56C, sint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8) = VIEWPORT_INTERACTION_ITEM_NONE; + RCT2_GLOBAL(0x9DEA52, uint16) = 0; + RCT2_GLOBAL(0x9DEA54, uint16) = 0; + RCT2_GLOBAL(0x9DEA56, uint16) = arrowZ + 18; + + sub_98197C(0, 0xFF, imageId, 0, arrowZ, 32, 32, get_current_rotation()); + } + int bx = dx + 52; + + if (bx <= dpi->y) + return; + + rct_map_element* element = map_element;//push map_element + + sint16 max_height = 0; + do{ + max_height = max(max_height, element->clearance_height); + } while (!map_element_is_last_for_tile(element++)); + + element--; + + if (map_element_get_type(element) == MAP_ELEMENT_TYPE_SURFACE && + (element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) != 0){ + max_height = (element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) << 1; + } + + max_height *= 8; + + dx -= max_height + 32; + + element = map_element;//pop map_element + dx -= dpi->height; + if (dx >= dpi->y) + return; + + RCT2_GLOBAL(0x9DE568, sint16) = x; + RCT2_GLOBAL(0x9DE56C, sint16) = y; + RCT2_GLOBAL(0x9DE57C, uint16) = 0; + do { + int direction = (map_element->type + get_current_rotation()) & MAP_ELEMENT_DIRECTION_MASK; + int height = 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 0: - dx = ax + cx; + case MAP_ELEMENT_TYPE_SURFACE: + RCT2_CALLPROC_X(0x66062C, 0, 0, direction, height, (int)map_element, 0, 0); break; - case 1: - ax += 32; - dx = cx - ax; + case MAP_ELEMENT_TYPE_PATH: + RCT2_CALLPROC_X(0x6A3590, 0, 0, direction, height, (int)map_element, 0, 0); break; - case 2: - ax += 32; - cx += 32; - dx = -(ax + cx); + case MAP_ELEMENT_TYPE_TRACK: + viewport_track_paint_setup(direction, height, map_element); break; - case 3: - cx += 32; - dx = ax - cx; + case MAP_ELEMENT_TYPE_SCENERY: + RCT2_CALLPROC_X(0x6DFF47, 0, 0, direction, height, (int)map_element, 0, 0); + break; + case MAP_ELEMENT_TYPE_ENTRANCE: + viewport_entrance_paint_setup(direction, height, map_element); + break; + case MAP_ELEMENT_TYPE_FENCE: + RCT2_CALLPROC_X(0x6E44B0, 0, 0, direction, height, (int)map_element, 0, 0); + break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + RCT2_CALLPROC_X(0x6B7F0C, 0, 0, direction, height, (int)map_element, 0, 0); + break; + case MAP_ELEMENT_TYPE_BANNER: + viewport_banner_paint_setup(direction, height, map_element); + 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; } - 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)); + RCT2_GLOBAL(0x9DE574, uint32_t) = dword_9DE574; + } while (!map_element_is_last_for_tile(map_element++)); +} + +/** + * + * rct2: 0x0068B60E + */ +static void viewport_blank_tiles_paint_setup(int x, int y) +{ + rct_drawpixelinfo *dpi = RCT2_GLOBAL(0x0140E9A8, rct_drawpixelinfo*); + + int dx; + switch (get_current_rotation()) { + case 0: + dx = x + y; + break; + case 1: + x += 32; + dx = y - x; + break; + case 2: + x += 32; + y += 32; + dx = -(x + y); + break; + case 3: + y += 32; + dx = x - y; + 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, sint16) = x; + RCT2_GLOBAL(0x9DE56C, sint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8_t) = VIEWPORT_INTERACTION_ITEM_NONE; + RCT2_CALLPROC_X( + (int)RCT2_ADDRESS(0x98196C, uint32_t*)[get_current_rotation()], + 0xFF00, + 3123, + y & 0xFF00, + 16, + 32, + 32, + get_current_rotation() + ); +} + +/** + * + * rct2: 0x0068B2B7 + */ +void sub_68B2B7(int x, int y) +{ + if ( + x < RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) && + y < RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) && + x >= 32 && + y >= 32 + ) { + RCT2_GLOBAL(0x0141E9B4, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9B8, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9BC, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9C0, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9C4, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9C8, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9CC, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9D0, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9D4, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9D8, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9DC, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9DB, uint8) |= 2; + + sub_68B3FB(x, y); + } else { + viewport_blank_tiles_paint_setup(x, y); + } +} + +/** + * + * rct2: 0x0068B35F + */ +void map_element_paint_setup(int x, int y) +{ + rct_drawpixelinfo *dpi = RCT2_GLOBAL(0x0140E9A8, rct_drawpixelinfo*); + if ( + x < RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) && + y < RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) && + x >= 32 && + y >= 32 + ) { + RCT2_GLOBAL(0x0141E9B4, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9B8, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9BC, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9C0, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9C4, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9C8, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9CC, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9D0, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9D4, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9D8, uint32) = 0xFFFF; + RCT2_GLOBAL(0x0141E9DC, uint32) = 0xFFFF; + + sub_68B3FB(x, y); + } else { + viewport_blank_tiles_paint_setup(x, y); } } @@ -1219,140 +1949,108 @@ void sub_68B35F(int ax, int cx) * * rct2: 0x0068B6C2 */ -void sub_0x68B6C2(){ +void viewport_paint_setup() +{ 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)){ + + rct_xy16 mapTile = { + .x = dpi->x & 0xFFE0, + .y = (dpi->y - 16) & 0xFFE0 + }; + + sint16 half_x = mapTile.x >> 1; + + uint16 num_vertical_quadrants = (dpi->height + 2128) >> 5; + + switch (get_current_rotation()){ case 0: - 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; + mapTile.x = mapTile.y - half_x; + mapTile.y = mapTile.y + half_x; 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); + map_element_paint_setup(mapTile.x, mapTile.y); + sprite_paint_setup(mapTile.x, mapTile.y); - mapTile.x -= 32; - mapTile.y += 32; + sprite_paint_setup(mapTile.x - 32, mapTile.y + 32); - sub_0x69E8B0(mapTile.x, mapTile.y); + map_element_paint_setup(mapTile.x, mapTile.y + 32); + sprite_paint_setup(mapTile.x, mapTile.y + 32); 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); + sprite_paint_setup(mapTile.x, mapTile.y); mapTile.y += 32; } break; case 1: - ax = dpi->y; - bx = dpi->x; - ax -= 0x10; - bx &= 0xFFE0; - ax &= 0xFFE0; - bx >>= 1; - cx = ax; - ax = -ax; - ax -= bx; - cx -= bx; - cx -= 0x10; - ax &= 0xFFE0; - cx &= 0xFFE0; - dx = dpi->height; - dx += 0x860; - dx >>= 5; - for (int i = dx; i > 0; i--){ - sub_68B35F(ax, cx); - sub_0x69E8B0(ax, cx); - ax -= 0x20; - cx -= 0x20; - sub_0x69E8B0(ax, cx); - cx += 0x20; - sub_68B35F(ax, cx); - sub_0x69E8B0(ax, cx); - ax += 0x20; - cx += 0x20; - sub_0x69E8B0(ax, cx); - ax -= 0x20; + mapTile.x = -mapTile.y - half_x; + mapTile.y = mapTile.y - half_x - 16; + + mapTile.x &= 0xFFE0; + mapTile.y &= 0xFFE0; + + for (; num_vertical_quadrants > 0; --num_vertical_quadrants){ + map_element_paint_setup(mapTile.x, mapTile.y); + sprite_paint_setup(mapTile.x, mapTile.y); + + sprite_paint_setup(mapTile.x - 32, mapTile.y - 32); + + map_element_paint_setup(mapTile.x - 32, mapTile.y); + sprite_paint_setup(mapTile.x - 32, mapTile.y); + + mapTile.y += 32; + sprite_paint_setup(mapTile.x, mapTile.y); + + mapTile.x -= 32; } break; case 2: - ax = dpi->y; - bx = dpi->x; - ax -= 0x10; - bx &= 0xFFE0; - ax &= 0xFFE0; - bx >>= 1; - ax = -ax; - cx = ax; - ax += bx; - cx -= bx; - ax &= 0xFFE0; - cx &= 0xFFE0; - dx = dpi->height; - dx += 0x860; - dx >>= 5; - for (int i = dx; i > 0; i--){ - sub_68B35F(ax, cx); - sub_0x69E8B0(ax, cx); - ax += 0x20; - cx -= 0x20; - sub_0x69E8B0(ax, cx); - ax -= 0x20; - sub_68B35F(ax, cx); - sub_0x69E8B0(ax, cx); - ax -= 0x20; - cx += 0x20; - sub_0x69E8B0(ax, cx); - cx -= 0x20; + mapTile.x = -mapTile.y + half_x; + mapTile.y = -mapTile.y - half_x; + + mapTile.x &= 0xFFE0; + mapTile.y &= 0xFFE0; + + for (; num_vertical_quadrants > 0; --num_vertical_quadrants){ + map_element_paint_setup(mapTile.x, mapTile.y); + sprite_paint_setup(mapTile.x, mapTile.y); + + sprite_paint_setup(mapTile.x + 32, mapTile.y - 32); + + map_element_paint_setup(mapTile.x, mapTile.y - 32); + sprite_paint_setup(mapTile.x, mapTile.y - 32); + + mapTile.x -= 32; + + sprite_paint_setup(mapTile.x, mapTile.y); + + mapTile.y -= 32; } break; case 3: - ax = dpi->y; - bx = dpi->x; - ax -= 0x10; - bx &= 0xFFE0; - ax &= 0xFFE0; - bx >>= 1; - cx = ax; - ax += bx; - cx = -cx; - cx += bx; - cx -= 0x10; - ax &= 0xFFE0; - cx &= 0xFFE0; - dx = dpi->height; - dx += 0x860; - dx >>= 5; - for (int i = dx; i > 0; i--){ - sub_68B35F(ax, cx); - sub_0x69E8B0(ax, cx); - ax += 0x20; - cx += 0x20; - sub_0x69E8B0(ax, cx); - cx -= 0x20; - sub_68B35F(ax, cx); - sub_0x69E8B0(ax, cx); - ax -= 0x20; - cx -= 0x20; - sub_0x69E8B0(ax, cx); - ax += 0x20; + mapTile.x = mapTile.y + half_x; + mapTile.y = -mapTile.y + half_x - 16; + + mapTile.x &= 0xFFE0; + mapTile.y &= 0xFFE0; + + for (; num_vertical_quadrants > 0; --num_vertical_quadrants){ + map_element_paint_setup(mapTile.x, mapTile.y); + sprite_paint_setup(mapTile.x, mapTile.y); + + sprite_paint_setup(mapTile.x + 32, mapTile.y + 32); + + map_element_paint_setup(mapTile.x + 32, mapTile.y); + sprite_paint_setup(mapTile.x + 32, mapTile.y); + + mapTile.y -= 32; + + sprite_paint_setup(mapTile.x, mapTile.y); + + mapTile.x += 32; } break; } @@ -1365,14 +2063,14 @@ void sub_688217_helper(uint16 ax, uint8 flag) do { ps = ps_next; - ps_next = ps_next->var_24; + ps_next = ps_next->next_quadrant_ps; if (ps_next == NULL) return; } while (ax > ps_next->var_18); RCT2_GLOBAL(0x00F1AD14, paint_struct*) = ps; do { - ps = ps->var_24; + ps = ps->next_quadrant_ps; if (ps == NULL) break; if (ps->var_18 > ax + 1) { @@ -1388,7 +2086,7 @@ void sub_688217_helper(uint16 ax, uint8 flag) while (true) { while (true) { - ps_next = ps->var_24; + ps_next = ps->next_quadrant_ps; if (ps_next == NULL) return; if (ps_next->var_1B & (1 << 7)) return; if (ps_next->var_1B & (1 << 0)) break; @@ -1407,13 +2105,13 @@ void sub_688217_helper(uint16 ax, uint8 flag) while (true) { ps = ps_next; - ps_next = ps_next->var_24; + ps_next = ps_next->next_quadrant_ps; 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)) { + switch (get_current_rotation()) { 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)) @@ -1437,10 +2135,10 @@ void sub_688217_helper(uint16 ax, uint8 flag) } 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_quadrant_ps = ps_next->next_quadrant_ps; + paint_struct *ps_temp = RCT2_GLOBAL(0x00F1AD18, paint_struct*)->next_quadrant_ps; + RCT2_GLOBAL(0x00F1AD18, paint_struct*)->next_quadrant_ps = ps_next; + ps_next->next_quadrant_ps = ps_temp; ps_next = ps; } } @@ -1459,7 +2157,7 @@ void sub_688217() 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; + ps->next_quadrant_ps = NULL; uint32 edi = RCT2_GLOBAL(0x00F1AD0C, uint32); if (edi == -1) return; @@ -1467,10 +2165,10 @@ void sub_688217() do { ps_next = RCT2_GLOBAL(0x00F1A50C + 4 * edi, paint_struct*); if (ps_next != NULL) { - ps->var_24 = ps_next; + ps->next_quadrant_ps = ps_next; do { ps = ps_next; - ps_next = ps_next->var_24; + ps_next = ps_next->next_quadrant_ps; } while (ps_next != NULL); } } while (++edi <= RCT2_GLOBAL(0x00F1AD10, uint32)); @@ -1485,6 +2183,55 @@ void sub_688217() sub_688217_helper(eax & 0xFFFF, 0); } +typedef struct paint_string_struct paint_string_struct; +struct paint_string_struct { + rct_string_id string_id; // 0x00 + paint_string_struct *next; // 0x02 + uint16 x; // 0x06 + uint16 y; // 0x08 + uint8 args[16]; // 0x0A + uint8 *y_offsets; // 0x1A +}; + +static void draw_pixel_info_crop_by_zoom(rct_drawpixelinfo *dpi) +{ + int zoom = dpi->zoom_level; + dpi->zoom_level = 0; + dpi->x >>= zoom; + dpi->y >>= zoom; + dpi->width >>= zoom; + dpi->height >>= zoom; +} + +/** + * + * rct2:0x006860C3 + */ +static void viewport_draw_money_effects() +{ + utf8 buffer[256]; + + paint_string_struct *ps = RCT2_GLOBAL(0x00F1AD20, paint_string_struct*); + if (ps == NULL) + return; + + rct_drawpixelinfo dpi = *(RCT2_GLOBAL(0x0140E9A8, rct_drawpixelinfo*)); + draw_pixel_info_crop_by_zoom(&dpi); + + do { + format_string(buffer, ps->string_id, &ps->args); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = FONT_SPRITE_BASE_MEDIUM; + + bool forceSpriteFont = false; + const currency_descriptor *currencyDesc = &CurrencyDescriptors[gConfigGeneral.currency_format]; + if (gUseTrueTypeFont && font_supports_string_sprite(currencyDesc->symbol_unicode)) { + forceSpriteFont = true; + } + + gfx_draw_string_with_y_offsets(&dpi, buffer, 0, ps->x, ps->y, (sint8 *)ps->y_offsets, forceSpriteFont); + } while ((ps = ps->next) != NULL); +} + /** * * rct2:0x00685CBF @@ -1563,9 +2310,9 @@ void viewport_paint(rct_viewport* viewport, rct_drawpixelinfo* dpi, int left, in dpi2->bits = bits_pointer; dpi2->pitch = pitch; - if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & 0x3001){ + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & (VIEWPORT_FLAG_HIDE_VERTICAL | VIEWPORT_FLAG_HIDE_BASE | VIEWPORT_FLAG_UNDERGROUND_INSIDE)){ uint8 colour = 0x0A; - if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & 0x4000){ + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & VIEWPORT_FLAG_INVISIBLE_SPRITES){ colour = 0; } gfx_clear(dpi2, colour); @@ -1573,69 +2320,26 @@ void viewport_paint(rct_viewport* viewport, rct_drawpixelinfo* dpi, int left, in RCT2_GLOBAL(0xEE7880, uint32) = 0xF1A4CC; RCT2_GLOBAL(0x140E9A8, uint32) = (int)dpi2; int ebp = 0, ebx = 0, esi = 0, ecx = 0; - sub_0x68615B(0xEE788C); //Memory copy - sub_0x68B6C2(); + painter_setup(); + viewport_paint_setup(); sub_688217(); sub_688485(); 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))){ + if ((weather_colour != -1) && (!(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) & VIEWPORT_FLAG_INVISIBLE_SPRITES)) && (!(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 + viewport_draw_money_effects(); } } -/** - * - * 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(sint16 *x, sint16 *y, int *direction) { - sub_688972(*x, *y, x, y, NULL); + screen_get_map_xy(*x, *y, x, y, NULL); if (*x == (sint16)0x8000) return; @@ -1679,7 +2383,7 @@ rct_xy16 screen_coord_to_viewport_coord(rct_viewport *viewport, uint16 x, uint16 rct_xy16 viewport_coord_to_map_coord(int x, int y, int z) { rct_xy16 ret; - switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) { + switch (get_current_rotation()) { case 0: ret.x = -x / 2 + y + z; ret.y = x / 2 + y + z; @@ -1890,27 +2594,52 @@ void store_interaction_info(paint_struct *ps) } /** - * rct2: 0x0068862C + * + * rct2: 0x00679074 + */ +void sub_679074(rct_drawpixelinfo *dpi, int imageId, int x, int y) +{ + RCT2_CALLPROC_X(0x00679074, 0, imageId, x, y, 0, (int)dpi, 0); +} + +/** + * + * rct2: 0x00679023 + */ +void sub_679023(rct_drawpixelinfo *dpi, int imageId, int x, int y) +{ + RCT2_GLOBAL(0x00141F569, uint8) = 0; + imageId &= 0xBFFFFFFF; + if (imageId & 0x20000000) { + RCT2_GLOBAL(0x00EDF81C, uint32) = 0x20000000; + int index = (imageId >> 19) & 0x7F; + if (imageId & 0x80000000) { + index &= 0x1F; + } + int g1Index = RCT2_ADDRESS(0x0097FCBC, uint32)[index]; + RCT2_GLOBAL(0x009ABDA4, uint8*) = g1Elements[g1Index].offset; + } else { + RCT2_GLOBAL(0x00EDF81C, uint32) = 0; + } + sub_679074(dpi, imageId, x, y); +} + +/** + * + * 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) { + while ((ps = ps->next_quadrant_ps) != 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); + sub_679023(dpi, ps->image_id, ps->x, ps->y); store_interaction_info(ps); next_ps = ps->var_20; @@ -1918,13 +2647,12 @@ void sub_68862C() 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); + sub_679023( + dpi, + attached_ps->image_id, + (attached_ps->attached_x + ps->x) & 0xFFFF, + (attached_ps->attached_y + ps->y) & 0xFFFF + ); store_interaction_info(ps); attached_ps = attached_ps->next_attached_ps; @@ -1942,7 +2670,7 @@ void sub_68862C() * flags: edx * x: ax * y: cx - * z: bl + * interactionType: bl * mapElement: edx * viewport: edi */ @@ -1977,8 +2705,8 @@ void get_map_coordinates_from_pos(int screenX, int screenY, int flags, sint16 *x dpi->width = 1; RCT2_GLOBAL(0xEE7880, uint32_t) = 0xF1A4CC; RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*) = dpi; - sub_0x68615B(0xEE788C); - sub_0x68B6C2(); + painter_setup(); + viewport_paint_setup(); sub_688217(); sub_68862C(); } @@ -1988,4 +2716,205 @@ void get_map_coordinates_from_pos(int screenX, int screenY, int flags, sint16 *x 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 +} + +/** + * Left, top, right and bottom represent 2D map coordinates at zoom 0. + */ +void viewport_invalidate(rct_viewport *viewport, int left, int top, int right, int bottom) +{ + int viewportLeft = viewport->view_x; + int viewportTop = viewport->view_y; + int viewportRight = viewport->view_x + viewport->view_width; + int viewportBottom = viewport->view_y + viewport->view_height; + if (right > viewportLeft && bottom > viewportTop) { + left = max(left, viewportLeft); + top = max(top, viewportTop); + right = min(right, viewportRight); + bottom = min(bottom, viewportBottom); + + uint8 zoom = 1 << viewport->zoom; + left -= viewportLeft; + top -= viewportTop; + right -= viewportLeft; + bottom -= viewportTop; + left /= zoom; + top /= zoom; + right /= zoom; + bottom /= zoom; + left += viewport->x; + top += viewport->y; + right += viewport->x; + bottom += viewport->y; + gfx_set_dirty_blocks(left, top, right, bottom); + } +} + +rct_viewport *viewport_find_from_point(int screenX, int screenY) +{ + rct_window *w; + rct_viewport *viewport; + + w = window_find_from_point(screenX, screenY); + if (w == NULL) + return NULL; + + viewport = w->viewport; + if (viewport == NULL) + return NULL; + + if (screenX < viewport->x || screenY < viewport->y) + return NULL; + if (screenX >= viewport->x + viewport->width || screenY >= viewport->y + viewport->height) + return NULL; + + return viewport; +} + +/** + * + * rct2: 0x00688972 + * In: + * screen_x: eax + * screen_y: ebx + * Out: + * x: ax + * y: bx + * map_element: edx ? + * viewport: edi + */ +void screen_get_map_xy(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: 0x006894D4 + */ +void screen_get_map_xy_with_z(sint16 screenX, sint16 screenY, sint16 z, sint16 *mapX, sint16 *mapY) +{ + rct_viewport *viewport = viewport_find_from_point(screenX, screenY); + if (viewport == NULL) { + *mapX = 0x8000; + return; + } + + screenX = viewport->view_x + ((screenX - viewport->x) << viewport->zoom); + screenY = viewport->view_y + ((screenY - viewport->y) << viewport->zoom); + + rct_xy16 mapPosition = viewport_coord_to_map_coord(screenX, screenY + z, 0); + if (mapPosition.x < 0 || mapPosition.x >= (256 * 32) || mapPosition.y < 0 || mapPosition.y >(256 * 32)) { + *mapX = 0x8000; + return; + } + + *mapX = mapPosition.x; + *mapY = mapPosition.y; +} + +/** + * + * rct2: 0x00689604 + */ +void screen_get_map_xy_quadrant(sint16 screenX, sint16 screenY, sint16 *mapX, sint16 *mapY, uint8 *quadrant) +{ + screen_get_map_xy(screenX, screenY, mapX, mapY, NULL); + if (*mapX == (sint16)0x8000) + return; + + *quadrant = map_get_tile_quadrant(*mapX, *mapY); + *mapX = floor2(*mapX, 32); + *mapY = floor2(*mapY, 32); +} + +/** + * + * rct2: 0x0068964B + */ +void screen_get_map_xy_quadrant_with_z(sint16 screenX, sint16 screenY, sint16 z, sint16 *mapX, sint16 *mapY, uint8 *quadrant) +{ + screen_get_map_xy_with_z(screenX, screenY, z, mapX, mapY); + if (*mapX == (sint16)0x8000) + return; + + *quadrant = map_get_tile_quadrant(*mapX, *mapY); + *mapX = floor2(*mapX, 32); + *mapY = floor2(*mapY, 32); +} + +/** + * + * rct2: 0x00689692 + */ +void screen_get_map_xy_side(sint16 screenX, sint16 screenY, sint16 *mapX, sint16 *mapY, uint8 *side) +{ + screen_get_map_xy(screenX, screenY, mapX, mapY, NULL); + if (*mapX == (sint16)0x8000) + return; + + *side = map_get_tile_side(*mapX, *mapY); + *mapX = floor2(*mapX, 32); + *mapY = floor2(*mapY, 32); +} + +/** + * + * rct2: 0x006896DC + */ +void screen_get_map_xy_side_with_z(sint16 screenX, sint16 screenY, sint16 z, sint16 *mapX, sint16 *mapY, uint8 *side) +{ + screen_get_map_xy_with_z(screenX, screenY, z, mapX, mapY); + if (*mapX == (sint16)0x8000) + return; + + *side = map_get_tile_side(*mapX, *mapY); + *mapX = floor2(*mapX, 32); + *mapY = floor2(*mapY, 32); +} + +/** + * Get current viewport rotation. + * + * If an invalid rotation is detected and DEBUG_LEVEL_1 is enabled, an error + * will be reported. + * + * @returns rotation in range 0-3 (inclusive) + */ +uint8 get_current_rotation() +{ + uint32 rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); + uint32 rotation_masked = rotation & 3; +#if DEBUG_LEVEL_1 + if (rotation != rotation_masked) { + log_error("Found wrong rotation %d! Will return %d instead.", rotation, rotation_masked); + } +#endif // DEBUG_LEVEL_1 + return (uint8)rotation_masked; +} diff --git a/src/interface/viewport.h b/src/interface/viewport.h index 7dcf3243fc..b8e4df70fa 100644 --- a/src/interface/viewport.h +++ b/src/interface/viewport.h @@ -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 @@ -56,7 +56,8 @@ enum { VIEWPORT_INTERACTION_ITEM_PARK, VIEWPORT_INTERACTION_ITEM_WALL, VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY, - VIEWPORT_INTERACTION_ITEM_BANNER = 12, + VIEWPORT_INTERACTION_ITEM_LABEL, + VIEWPORT_INTERACTION_ITEM_BANNER, }; @@ -95,6 +96,7 @@ void center_2d_coordinates(int x, int y, int z, int* out_x, int* out_y, rct_view void viewport_create(rct_window *w, int x, int y, int width, int height, int zoom, int center_x, int center_y, int center_z, char flags, sint16 sprite); void viewport_update_pointers(); void viewport_update_position(rct_window *window); +void viewport_update_sprite_follow(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); @@ -102,7 +104,6 @@ void sub_689174(sint16* x, sint16* y, sint16 *z); 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(); @@ -123,4 +124,26 @@ 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); +void viewport_interaction_remove_park_entrance(rct_map_element *mapElement, int x, int y); + +void sub_68B2B7(int x, int y); +void painter_setup(); +void sub_688485(); +void sub_688217(); + +int sub_98197C(sint8 al, sint8 ah, int image_id, sint8 cl, int height, sint16 length_y, sint16 length_x, uint32 rotation); +int sub_98199C(sint8 al, sint8 ah, int image_id, sint8 cl, int height, sint16 length_y, sint16 length_x, uint32 rotation); +bool sub_6629BC(int height, uint16 ax, uint32 image_id, int edi); + +void viewport_invalidate(rct_viewport *viewport, int left, int top, int right, int bottom); + +void screen_get_map_xy(int screenX, int screenY, sint16 *x, sint16 *y, rct_viewport **viewport); +void screen_get_map_xy_with_z(sint16 screenX, sint16 screenY, sint16 z, sint16 *mapX, sint16 *mapY); +void screen_get_map_xy_quadrant(sint16 screenX, sint16 screenY, sint16 *mapX, sint16 *mapY, uint8 *quadrant); +void screen_get_map_xy_quadrant_with_z(sint16 screenX, sint16 screenY, sint16 z, sint16 *mapX, sint16 *mapY, uint8 *quadrant); +void screen_get_map_xy_side(sint16 screenX, sint16 screenY, sint16 *mapX, sint16 *mapY, uint8 *side); +void screen_get_map_xy_side_with_z(sint16 screenX, sint16 screenY, sint16 z, sint16 *mapX, sint16 *mapY, uint8 *side); + +uint8 get_current_rotation(); + #endif diff --git a/src/interface/viewport_interaction.c b/src/interface/viewport_interaction.c index 3e0e049945..b8ef2602e1 100644 --- a/src/interface/viewport_interaction.c +++ b/src/interface/viewport_interaction.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include "../addresses.h" +#include "../editor.h" #include "../game.h" #include "../localisation/localisation.h" #include "../ride/ride.h" @@ -36,7 +37,6 @@ 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); static void viewport_interaction_remove_footpath_item(rct_map_element *mapElement, int x, int y); -static void viewport_interaction_remove_park_entrance(rct_map_element *mapElement, int x, int y); static void viewport_interaction_remove_park_wall(rct_map_element *mapElement, int x, int y); static void viewport_interaction_remove_large_scenery(rct_map_element *mapElement, int x, int y); static rct_peep *viewport_interaction_get_closest_peep(int x, int y, int maxDistance); @@ -56,8 +56,8 @@ int viewport_interaction_get_item_left(int x, int y, viewport_interaction_info * if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TITLE_DEMO | SCREEN_FLAGS_SCENARIO_EDITOR | SCREEN_FLAGS_TRACK_MANAGER)) return info->type = VIEWPORT_INTERACTION_ITEM_NONE; - // - if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) && s6Info->var_000 != 6) + // + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) && s6Info->editor_step != EDITOR_STEP_ROLLERCOASTER_DESIGNER) return info->type = VIEWPORT_INTERACTION_ITEM_NONE; rct_xy16 mapCoord = { 0 }; @@ -162,7 +162,7 @@ int viewport_interaction_left_click(int x, int y) } /** - * + * * rct2: 0x006EDE88 */ int viewport_interaction_get_item_right(int x, int y, viewport_interaction_info *info) @@ -179,8 +179,8 @@ int viewport_interaction_get_item_right(int x, int y, viewport_interaction_info if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TITLE_DEMO | SCREEN_FLAGS_TRACK_MANAGER)) return info->type = VIEWPORT_INTERACTION_ITEM_NONE; - // - if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) && s6Info->var_000 != 6) + // + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) && s6Info->editor_step != EDITOR_STEP_ROLLERCOASTER_DESIGNER) return info->type = VIEWPORT_INTERACTION_ITEM_NONE; rct_xy16 mapCoord = { 0 }; @@ -302,7 +302,7 @@ int viewport_interaction_get_item_right(int x, int y, viewport_interaction_info return info->type; case VIEWPORT_INTERACTION_ITEM_PARK: - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode) + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) break; if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_ENTRANCE) @@ -336,7 +336,7 @@ int viewport_interaction_right_over(int x, int y) } /** - * + * * rct2: 0x006E8A62 */ int viewport_interaction_right_click(int x, int y) @@ -385,7 +385,7 @@ int viewport_interaction_right_click(int x, int y) } /** - * + * * rct2: 0x006E08D2 */ static void viewport_interaction_remove_scenery(rct_map_element *mapElement, int x, int y) @@ -403,7 +403,7 @@ static void viewport_interaction_remove_scenery(rct_map_element *mapElement, int } /** - * + * * rct2: 0x006A614A */ static void viewport_interaction_remove_footpath(rct_map_element *mapElement, int x, int y) @@ -413,7 +413,7 @@ static void viewport_interaction_remove_footpath(rct_map_element *mapElement, in rct_map_element *mapElement2; z = mapElement->base_height; - + w = window_find_by_class(WC_FOOTPATH); if (w != NULL) footpath_provisional_update(); @@ -429,7 +429,7 @@ static void viewport_interaction_remove_footpath(rct_map_element *mapElement, in } /** - * + * * rct2: 0x006A61AB */ static void viewport_interaction_remove_footpath_item(rct_map_element *mapElement, int x, int y) @@ -453,10 +453,10 @@ static void viewport_interaction_remove_footpath_item(rct_map_element *mapElemen } /** - * + * * rct2: 0x00666C0E */ -static void viewport_interaction_remove_park_entrance(rct_map_element *mapElement, int x, int y) +void viewport_interaction_remove_park_entrance(rct_map_element *mapElement, int x, int y) { int rotation = (mapElement->type + 1) & 3; switch (mapElement->properties.entrance.index & 0x0F) { @@ -474,7 +474,7 @@ static void viewport_interaction_remove_park_entrance(rct_map_element *mapElemen } /** - * + * * rct2: 0x006E57A9 */ static void viewport_interaction_remove_park_wall(rct_map_element *mapElement, int x, int y) @@ -485,7 +485,7 @@ static void viewport_interaction_remove_park_wall(rct_map_element *mapElement, i 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) = STR_CANT_REMOVE_THIS; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_REMOVE_THIS; game_do_command( x, GAME_COMMAND_FLAG_APPLY, @@ -499,7 +499,7 @@ static void viewport_interaction_remove_park_wall(rct_map_element *mapElement, i } /** - * + * * rct2: 0x006B88DC */ static void viewport_interaction_remove_large_scenery(rct_map_element *mapElement, int x, int y) @@ -514,14 +514,14 @@ static void viewport_interaction_remove_large_scenery(rct_map_element *mapElemen ((mapElement->properties.scenerymultiple.colour[1] & 0xE0) >> 5); window_sign_open(id); } else { - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1158; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_REMOVE_THIS; game_do_command( - x, - 1 | ((mapElement->type & 0x3) << 8), - y, + x, + 1 | ((mapElement->type & 0x3) << 8), + y, mapElement->base_height | ((mapElement->properties.scenerymultiple.type >> 10) << 8), - GAME_COMMAND_REMOVE_LARGE_SCENERY, - 0, + GAME_COMMAND_REMOVE_LARGE_SCENERY, + 0, 0 ); } @@ -538,7 +538,7 @@ static rct_peep *viewport_interaction_get_closest_peep(int x, int y, int maxDist w = window_find_from_point(x, y); if (w == NULL) return 0; - + viewport = w->viewport; if (viewport == NULL || viewport->zoom >= 2) return 0; @@ -574,7 +574,7 @@ static rct_peep *viewport_interaction_get_closest_peep(int x, int y, int maxDist 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; + int z = 0, 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); diff --git a/src/interface/widget.c b/src/interface/widget.c index 87472e630f..94557fa04e 100644 --- a/src/interface/widget.c +++ b/src/interface/widget.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 . *****************************************************************************/ @@ -26,6 +26,7 @@ #include "window.h" #include "../platform/platform.h" #include "../localisation/localisation.h" +#include "../util/util.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); @@ -48,7 +49,7 @@ static void widget_vscrollbar_draw(rct_drawpixelinfo *dpi, rct_scroll *scroll, i static void widget_draw_image(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); /** - * + * * rct2: 0x006EAF26 */ void widget_scroll_update_thumbs(rct_window *w, int widget_index) @@ -102,7 +103,7 @@ void widget_scroll_update_thumbs(rct_window *w, int widget_index) } /** - * + * * rct2: 0x006EB2A8 */ void widget_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -170,7 +171,7 @@ void widget_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) } /** - * + * * rct2: 0x006EB6CE */ static void widget_frame_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -188,7 +189,7 @@ static void widget_frame_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetI r = w->x + widget->right; b = w->y + widget->bottom; - // + // press = (w->flags & WF_10 ? 0x80 : 0); // Get the colour @@ -210,7 +211,7 @@ static void widget_frame_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetI } /** - * + * * rct2: 0x006EB765 */ static void widget_resize_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -247,7 +248,7 @@ static void widget_resize_draw(rct_drawpixelinfo *dpi, rct_window *w, int widget } /** - * + * * rct2: 0x006EB8E5 */ static void widget_button_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -297,7 +298,7 @@ static void widget_tab_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetInd // Get the widget widget = &w->widgets[widgetIndex]; - // + // if (widget->image == -1) return; @@ -330,7 +331,7 @@ static void widget_tab_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetInd } /** - * + * * rct2: 0x006EB861 */ static void widget_flat_button_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -373,7 +374,7 @@ static void widget_flat_button_draw(rct_drawpixelinfo *dpi, rct_window *w, int w } /** - * + * * rct2: 0x006EBBEB */ static void widget_text_button(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -403,7 +404,7 @@ static void widget_text_button(rct_drawpixelinfo *dpi, rct_window *w, int widget } /** - * + * * rct2: 0x006EBC41 */ static void widget_text_unknown(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -462,7 +463,7 @@ static void widget_text_unknown(rct_drawpixelinfo *dpi, rct_window *w, int widge } /** - * + * * rct2: 0x006EBD52 */ static void widget_text(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -492,7 +493,7 @@ static void widget_text(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) } /** - * + * * rct2: 0x006EBD1F */ static void widget_text_inset(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -518,7 +519,7 @@ static void widget_text_inset(rct_drawpixelinfo *dpi, rct_window *w, int widgetI } /** - * + * * rct2: 0x006EC1A6 */ static void widget_text_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -546,12 +547,12 @@ static void widget_text_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIn gfx_fill_rect_inset(dpi, l, t, r, b, colour, press); // TODO - + gfx_fill_rect(dpi, l, t, r, b, colour); } /** - * + * * rct2: 0x006EB535 */ static void widget_groupbox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -590,28 +591,28 @@ static void widget_groupbox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widg colour = w->colours[widget->colour] & 0x7F; // Border left of text - gfx_fill_rect(dpi, l, t, l + 4, t, RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]); - gfx_fill_rect(dpi, l + 1, t + 1, l + 4, t + 1, RCT2_ADDRESS(0x0141FC4B, uint8)[colour * 8]); + gfx_fill_rect(dpi, l, t, l + 4, t, ColourMapA[colour].mid_dark); + gfx_fill_rect(dpi, l + 1, t + 1, l + 4, t + 1, ColourMapA[colour].lighter); // Border right of text - gfx_fill_rect(dpi, textRight, t, r - 1, t, RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]); - gfx_fill_rect(dpi, textRight, t + 1, r - 2, t + 1, RCT2_ADDRESS(0x0141FC4B, uint8)[colour * 8]); + gfx_fill_rect(dpi, textRight, t, r - 1, t, ColourMapA[colour].mid_dark); + gfx_fill_rect(dpi, textRight, t + 1, r - 2, t + 1, ColourMapA[colour].lighter); // Border right - gfx_fill_rect(dpi, r - 1, t + 1, r - 1, b - 1, RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]); - gfx_fill_rect(dpi, r, t, r, b, RCT2_ADDRESS(0x0141FC4B, uint8)[colour * 8]); + gfx_fill_rect(dpi, r - 1, t + 1, r - 1, b - 1, ColourMapA[colour].mid_dark); + gfx_fill_rect(dpi, r, t, r, b, ColourMapA[colour].lighter); // Border bottom - gfx_fill_rect(dpi, l, b - 1, r - 2, b - 1, RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]); - gfx_fill_rect(dpi, l, b, r - 1, b, RCT2_ADDRESS(0x0141FC4B, uint8)[colour * 8]); + gfx_fill_rect(dpi, l, b - 1, r - 2, b - 1, ColourMapA[colour].mid_dark); + gfx_fill_rect(dpi, l, b, r - 1, b, ColourMapA[colour].lighter); // Border left - gfx_fill_rect(dpi, l, t + 1, l, b - 2, RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]); - gfx_fill_rect(dpi, l + 1, t + 2, l + 1, b - 2, RCT2_ADDRESS(0x0141FC4B, uint8)[colour * 8]); + gfx_fill_rect(dpi, l, t + 1, l, b - 2, ColourMapA[colour].mid_dark); + gfx_fill_rect(dpi, l + 1, t + 2, l + 1, b - 2, ColourMapA[colour].lighter); } /** - * + * * rct2: 0x006EB2F9 */ static void widget_caption_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -632,7 +633,7 @@ static void widget_caption_draw(rct_drawpixelinfo *dpi, rct_window *w, int widge // Get the colour colour = w->colours[widget->colour]; - // + // if (w->var_4B8 != -1) { gfx_draw_sprite(dpi, *((char*)(0x013CA742 + w->var_4B8)) << 19, l + 1, t + 1, 0); if (w->width > 638) @@ -643,15 +644,15 @@ static void widget_caption_draw(rct_drawpixelinfo *dpi, rct_window *w, int widge gfx_draw_sprite(dpi, *((char*)(0x013CA742 + w->var_4B9)) << 19, l + 1 + 638, t + 1, 0); } - // + // press = 0x70; if (w->flags & WF_10) press |= 0x80; gfx_fill_rect_inset(dpi, l, t, r, b, colour, press); - gfx_fill_rect(dpi, r + 1, t, r + 1, b, *((char*)(0x0141FC47 + (colour * 8)))); + gfx_fill_rect(dpi, r + 1, t, r + 1, b, ColourMapA[colour].mid_dark); } else { - // + // press = 0x60; if (w->flags & WF_10) press |= 0x80; @@ -660,7 +661,7 @@ static void widget_caption_draw(rct_drawpixelinfo *dpi, rct_window *w, int widge // 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)))); + gfx_fill_rect(dpi, l + 1, t + 1, r - 1, b - 1, ColourMapA[colour].dark); else gfx_fill_rect(dpi, l + 1, t + 1, r - 1, b - 1, 0x2000000 | 47); } @@ -682,7 +683,7 @@ static void widget_caption_draw(rct_drawpixelinfo *dpi, rct_window *w, int widge } /** - * + * * rct2: 0x006EBB85 */ static void widget_closebox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -726,13 +727,13 @@ static void widget_closebox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widg } /** - * + * * rct2: 0x006EBAD9 */ static void widget_checkbox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) { rct_widget* widget; - int l, t, b; + int l, t, b, yMid; uint8 colour; // Get the widget @@ -742,18 +743,19 @@ static void widget_checkbox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widg l = w->x + widget->left; t = w->y + widget->top; b = w->y + widget->bottom; + yMid = (b + t) / 2; // Get the colour colour = w->colours[widget->colour]; if (widget->type != WWT_24) { // checkbox - gfx_fill_rect_inset(dpi, l, t, l + 9, b - 1, colour, 0x60); + gfx_fill_rect_inset(dpi, l, yMid - 5, l + 9, yMid + 4, colour, 0x60); // fill it when checkbox is pressed if (widget_is_pressed(w, widgetIndex)) { RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; - gfx_draw_string(dpi, (char*)0x009DED72, colour & 0x7F, l, t); + gfx_draw_string(dpi, (char*)CheckBoxMarkString, colour & 0x7F, l, yMid - 5); } } @@ -764,11 +766,12 @@ static void widget_checkbox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widg if (widget_is_disabled(w, widgetIndex)) { colour |= 0x40; } - gfx_draw_string_left(dpi, widget->image, (char*)0x013CE952, colour, l + 14, t); + + gfx_draw_string_left_centred(dpi, (rct_string_id)widget->image, (void*)0x013CE952, colour, l + 14, yMid); } /** - * + * * rct2: 0x006EBD96 */ static void widget_scroll_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -850,17 +853,17 @@ static void widget_hscrollbar_draw(rct_drawpixelinfo *dpi, rct_scroll *scroll, i { 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)))); - gfx_fill_rect(dpi, l + 10, t + 2, r - 10, t + 2, *((char*)(0x0141FC47 + (colour * 8)))); - gfx_fill_rect(dpi, l + 10, t + 3, r - 10, t + 3, *((char*)(0x0141FC4B + (colour * 8)))); - gfx_fill_rect(dpi, l + 10, t + 7, r - 10, t + 7, *((char*)(0x0141FC47 + (colour * 8)))); - gfx_fill_rect(dpi, l + 10, t + 8, r - 10, t + 8, *((char*)(0x0141FC4B + (colour * 8)))); - + gfx_fill_rect(dpi, l + 10, t, r - 10, b, ColourMapA[colour].lighter); + gfx_fill_rect(dpi, l + 10, t, r - 10, b, 0x1000000 | ColourMapA[colour].mid_dark); + gfx_fill_rect(dpi, l + 10, t + 2, r - 10, t + 2, ColourMapA[colour].mid_dark); + gfx_fill_rect(dpi, l + 10, t + 3, r - 10, t + 3, ColourMapA[colour].lighter); + gfx_fill_rect(dpi, l + 10, t + 7, r - 10, t + 7, ColourMapA[colour].mid_dark); + gfx_fill_rect(dpi, l + 10, t + 8, r - 10, t + 8, ColourMapA[colour].lighter); + // Left button gfx_fill_rect_inset(dpi, l, t, l + 9, b, colour, (scroll->flags & HSCROLLBAR_LEFT_PRESSED ? 0x20 : 0)); - gfx_draw_string(dpi, (char*)0x009DED6C, 0, l + 1, t); - + gfx_draw_string(dpi, (char*)BlackLeftArrowString, 0, l + 1, t); + // Thumb gfx_fill_rect_inset(dpi, max(l + 10, l + scroll->h_thumb_left - 1), t, @@ -869,23 +872,23 @@ static void widget_hscrollbar_draw(rct_drawpixelinfo *dpi, rct_scroll *scroll, i // Right button gfx_fill_rect_inset(dpi, r - 9, t, r, b, colour, (scroll->flags & HSCROLLBAR_RIGHT_PRESSED ? 0x20 : 0)); - gfx_draw_string(dpi, (char*)0x009DED6F, 0, r - 6, t); + gfx_draw_string(dpi, (char*)BlackRightArrowString, 0, r - 6, t); } 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)))); - gfx_fill_rect(dpi, l + 2, t + 10, l + 2, b - 10, *((char*)(0x0141FC47 + (colour * 8)))); - gfx_fill_rect(dpi, l + 3, t + 10, l + 3, b - 10, *((char*)(0x0141FC4B + (colour * 8)))); - gfx_fill_rect(dpi, l + 7, t + 10, l + 7, b - 10, *((char*)(0x0141FC47 + (colour * 8)))); - gfx_fill_rect(dpi, l + 8, t + 10, l + 8, b - 10, *((char*)(0x0141FC4B + (colour * 8)))); + gfx_fill_rect(dpi, l, t + 10, r, b - 10, ColourMapA[colour].lighter); + gfx_fill_rect(dpi, l, t + 10, r, b - 10, 0x1000000 | ColourMapA[colour].mid_dark); + gfx_fill_rect(dpi, l + 2, t + 10, l + 2, b - 10, ColourMapA[colour].mid_dark); + gfx_fill_rect(dpi, l + 3, t + 10, l + 3, b - 10, ColourMapA[colour].lighter); + gfx_fill_rect(dpi, l + 7, t + 10, l + 7, b - 10, ColourMapA[colour].mid_dark); + gfx_fill_rect(dpi, l + 8, t + 10, l + 8, b - 10, ColourMapA[colour].lighter); // Up button gfx_fill_rect_inset(dpi, l, t, r, t + 9, colour, (scroll->flags & VSCROLLBAR_UP_PRESSED ? 0x20 : 0)); - gfx_draw_string(dpi, (char*)0x009DED66, 0, l + 1, t - 1); + gfx_draw_string(dpi, (char*)BlackUpArrowString, 0, l + 1, t - 1); // Thumb gfx_fill_rect_inset(dpi, @@ -895,11 +898,11 @@ 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 - 9); + gfx_draw_string(dpi, (char*)BlackDownArrowString, 0, l + 1, b - 9); } /** - * + * * rct2: 0x006EB951 */ static void widget_draw_image(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) @@ -931,7 +934,7 @@ static void widget_draw_image(rct_drawpixelinfo *dpi, rct_window *w, int widgetI if (widget_is_disabled(w, widgetIndex)) { // Draw greyed out (light border bottom right shadow) colour = w->colours[widget->colour]; - colour = RCT2_ADDRESS(0x00141FC4A, uint8)[(colour & 0x7F) * 8] & 0xFF; + colour = ColourMapA[colour & 0x7F].lighter; uint8 palette[256]; memset(palette, colour, 256); @@ -943,7 +946,7 @@ static void widget_draw_image(rct_drawpixelinfo *dpi, rct_window *w, int widgetI // Draw greyed out (dark) colour = w->colours[widget->colour]; - colour = RCT2_ADDRESS(0x00141FC48, uint8)[(colour & 0x7F) * 8] & 0xFF; + colour = ColourMapA[colour & 0x7F].mid_light; memset(palette, colour, 256); palette[0] = 0; @@ -1172,7 +1175,7 @@ static void widget_text_box_draw(rct_drawpixelinfo *dpi, rct_window *w, int widg if (!active) { if (w->widgets[widgetIndex].image != 0) { - strcpy(wrapped_string, (char*)w->widgets[widgetIndex].image); + safe_strncpy(wrapped_string, (char*)w->widgets[widgetIndex].image, 512); gfx_wrap_string(wrapped_string, r - l - 5, &no_lines, &font_height); gfx_draw_string(dpi, wrapped_string, w->colours[1], l + 2, t); } @@ -1180,7 +1183,7 @@ static void widget_text_box_draw(rct_drawpixelinfo *dpi, rct_window *w, int widg } - strcpy(wrapped_string, gTextBoxInput); + safe_strncpy(wrapped_string, gTextBoxInput, 512); // String length needs to add 12 either side of box // +13 for cursor when max length. @@ -1190,7 +1193,7 @@ static void widget_text_box_draw(rct_drawpixelinfo *dpi, rct_window *w, int widg gfx_draw_string(dpi, wrapped_string, w->colours[1], l + 2, t); - int string_length = get_string_length(wrapped_string); + int string_length = get_string_size(wrapped_string) - 1; // Make a copy of the string for measuring the width. char temp_string[512] = { 0 }; @@ -1207,7 +1210,7 @@ static void widget_text_box_draw(rct_drawpixelinfo *dpi, rct_window *w, int widg } if (gTextBoxFrameNo <= 15){ - uint8 colour = RCT2_ADDRESS(0x0141FC48, uint8)[w->colours[1] * 8]; + uint8 colour = ColourMapA[w->colours[1]].mid_light; 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 ad7e4d0b35..8a8c5022c4 100644 --- a/src/interface/widget.h +++ b/src/interface/widget.h @@ -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 . *****************************************************************************/ diff --git a/src/interface/window.c b/src/interface/window.c index 2c210a78ac..bada6d28e9 100644 --- a/src/interface/window.c +++ b/src/interface/window.c @@ -31,6 +31,7 @@ #include "viewport.h" #include "../localisation/string_ids.h" #include "../localisation/localisation.h" +#include "../cursors.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) @@ -46,6 +47,7 @@ char gTextBoxInput[512] = { 0 }; int gMaxTextBoxInputLength = 0; int gTextBoxFrameNo = 0; bool gUsingWidgetTextBox = 0; +bool gLoadSaveTitleSequenceSave = 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 @@ -140,7 +142,7 @@ rct_widget *window_get_scroll_widget(rct_window *w, int scrollIndex) } /** - * + * * rct2: 0x006ED7B0 */ void window_dispatch_update_all() @@ -155,8 +157,15 @@ void window_dispatch_update_all() RCT2_CALLPROC_EBPSAFE(0x006EE411); // handle_text_input } +void window_update_all_viewports() +{ + for (rct_window *w = g_window_list; w < RCT2_NEW_WINDOW; w++) + if (w->viewport != NULL) + viewport_update_position(w); +} + /** - * + * * rct2: 0x006E77A1 */ void window_update_all() @@ -168,15 +177,13 @@ void window_update_all() return; gfx_draw_all_dirty_blocks(); - - for (w = g_window_list; w < RCT2_NEW_WINDOW; w++) - if (w->viewport != NULL) - viewport_update_position(w); + window_update_all_viewports(); + gfx_draw_all_dirty_blocks(); // 1000 tick update - RCT2_GLOBAL(0x009DEB7C, sint16) += RCT2_GLOBAL(0x009DE588, sint16); - if (RCT2_GLOBAL(0x009DEB7C, sint16) >= 1000) { - RCT2_GLOBAL(0x009DEB7C, sint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_UPDATE_TICKS, sint16) += RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_LAST_UPDATE, sint16); + if (RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_UPDATE_TICKS, sint16) >= 1000) { + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_UPDATE_TICKS, sint16) = 0; for (w = RCT2_LAST_WINDOW; w >= g_window_list; w--) window_event_unknown_07_call(w); } @@ -194,7 +201,7 @@ void window_update_all() } /** - * + * * rct2: 0x006E78E3 */ static void window_scroll_wheel_input(rct_window *w, int scrollIndex, int wheel) @@ -202,7 +209,7 @@ static void window_scroll_wheel_input(rct_window *w, int scrollIndex, int wheel) int widgetIndex, size; rct_scroll *scroll; rct_widget *widget; - + scroll = &w->scrolls[scrollIndex]; widget = window_get_scroll_widget(w, scrollIndex); widgetIndex = window_get_widget_index(w, widget); @@ -226,7 +233,7 @@ static void window_scroll_wheel_input(rct_window *w, int scrollIndex, int wheel) } /** - * + * * rct2: 0x006E793B */ static int window_wheel_input(rct_window *w, int wheel) @@ -253,7 +260,7 @@ static int window_wheel_input(rct_window *w, int wheel) } /** - * + * * rct2: 0x006E79FB */ static void window_viewport_wheel_input(rct_window *w, int wheel) @@ -268,7 +275,7 @@ static void window_viewport_wheel_input(rct_window *w, int wheel) } /** - * + * * rct2: 0x006E7868 */ static void window_all_wheel_input() @@ -321,7 +328,7 @@ static void window_all_wheel_input() return; } } - + // Check other scroll views on window if (window_wheel_input(w, wheel)) return; @@ -347,14 +354,14 @@ static void window_all_wheel_input() * @param flags (ch) * @param class (cl) */ -rct_window *window_create(int x, int y, int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags) +rct_window *window_create(int x, int y, int width, int height, rct_window_event_list *event_handlers, rct_windowclass cls, uint16 flags) { rct_window *w; // Check if there are any window slots left if (RCT2_NEW_WINDOW >= &(g_window_list[MAX_NUMBER_WINDOWS])) { // Close least recently used window for (w = g_window_list; w < RCT2_NEW_WINDOW; w++) - if (!(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT | WF_9))) + if (!(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT | WF_NO_AUTO_CLOSE))) break; window_close(w); @@ -390,7 +397,7 @@ rct_window *window_create(int x, int y, int width, int height, uint32 *event_han // Play sounds and flash the window if (!(flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))){ w->flags |= WF_WHITE_BORDER_MASK; - sound_play_panned(SOUND_WINDOW_OPEN, x + (width / 2), 0, 0, 0); + audio_play_sound_panned(SOUND_WINDOW_OPEN, x + (width / 2), 0, 0, 0); } w->number = 0; @@ -423,7 +430,7 @@ rct_window *window_create(int x, int y, int width, int height, uint32 *event_han } /** - * + * * rct2: 0x006EA934 * * @param x (dx) @@ -448,7 +455,7 @@ static bool sub_6EA8EC(int x, int y, int width, int height) } /** - * + * * rct2: 0x006EA934 * * @param x (dx) @@ -466,7 +473,7 @@ static bool sub_6EA934(int x, int y, int width, int height) } /** - * + * * rct2: 0x006EA934 * * @param x (dx) @@ -502,7 +509,7 @@ static bool sub_6EA95D(int x, int y, int width, int height) * @param flags (ch) * @param class (cl) */ -rct_window *window_create_auto_pos(int width, int height, uint32 *event_handlers, rct_windowclass cls, uint16 flags) +rct_window *window_create_auto_pos(int width, int height, rct_window_event_list *event_handlers, rct_windowclass cls, uint16 flags) { rct_window *w; int x, y; @@ -617,14 +624,14 @@ rct_window *window_create_auto_pos(int width, int height, uint32 *event_handlers // Clamp to inside the screen foundSpace: if (x < 0) - x = x; + x = 0; 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) +rct_window *window_create_centred(int width, int height, rct_window_event_list *event_handlers, rct_windowclass cls, uint16 flags) { int x, y; @@ -701,7 +708,7 @@ void window_close_by_class(rct_windowclass cls) void window_close_by_number(rct_windowclass cls, rct_windownumber number) { rct_window* w; - + for (w = g_window_list; w < RCT2_NEW_WINDOW; w++) { if (w->classification == cls && w->number == number) { window_close(w); @@ -737,7 +744,7 @@ rct_window *window_find_by_class(rct_windowclass cls) rct_window *window_find_by_number(rct_windowclass cls, rct_windownumber number) { rct_window *w; - + for (w = g_window_list; w < RCT2_NEW_WINDOW; w++) if (w->classification == cls && w->number == number) return w; @@ -800,7 +807,7 @@ void window_close_all_except_class(rct_windowclass cls) { } /** - * + * * rct2: 0x006EA845 */ rct_window *window_find_from_point(int x, int y) @@ -813,14 +820,14 @@ rct_window *window_find_from_point(int x, int y) if (x < w->x || x >= w->x + w->width || y < w->y || y >= w->y + w->height) continue; - if (w->flags & WF_5) { + if (w->flags & WF_NO_BACKGROUND) { widget_index = window_find_widget_from_point(w, x, y); if (widget_index == -1) continue; widget = &w->widgets[widget_index]; } - + return w; } @@ -828,7 +835,7 @@ rct_window *window_find_from_point(int x, int y) } /** - * + * * rct2: 0x006EA594 * x (ax) * y (bx) @@ -933,6 +940,7 @@ void widget_invalidate(rct_window *w, int widgetIndex) { rct_widget* widget; + assert(w != NULL); widget = &w->widgets[widgetIndex]; if (widget->left == -2) return; @@ -946,7 +954,7 @@ void widget_invalidate(rct_window *w, int widgetIndex) void widget_invalidate_by_class(rct_windowclass cls, int widgetIndex) { rct_window* w; - + for (w = g_window_list; w < RCT2_NEW_WINDOW; w++) if (w->classification == cls) widget_invalidate(w, widgetIndex); @@ -962,7 +970,7 @@ void widget_invalidate_by_class(rct_windowclass cls, int widgetIndex) void widget_invalidate_by_number(rct_windowclass cls, rct_windownumber number, int widgetIndex) { rct_window* w; - + for (w = g_window_list; w < RCT2_NEW_WINDOW; w++) if (w->classification == cls && w->number == number) widget_invalidate(w, widgetIndex); @@ -991,6 +999,8 @@ void window_init_scroll_widgets(rct_window *w) scroll = &w->scrolls[scroll_index]; scroll->flags = 0; + width = 0; + height = 0; window_get_scroll_size(w, scroll_index, &width, &height); scroll->h_left = 0; scroll->h_right = width + 1; @@ -1010,7 +1020,7 @@ void window_init_scroll_widgets(rct_window *w) } /** - * + * * rct2: 0x006EAE4E * * @param w The window (esi). @@ -1023,11 +1033,14 @@ void window_update_scroll_widgets(rct_window *w) widgetIndex = 0; scrollIndex = 0; + assert(w != NULL); for (widget = w->widgets; widget->type != WWT_LAST; widget++, widgetIndex++) { if (widget->type != WWT_SCROLL) continue; scroll = &w->scrolls[scrollIndex]; + width = 0; + height = 0; window_get_scroll_size(w, scrollIndex, &width, &height); if (height == 0){ scroll->v_top = 0; @@ -1062,6 +1075,7 @@ int window_get_scroll_data_index(rct_window *w, int widget_index) int i, result; result = 0; + assert(w != NULL); for (i = 0; i < widget_index; i++) { if (w->widgets[i].type == WWT_SCROLL) result++; @@ -1070,7 +1084,7 @@ int window_get_scroll_data_index(rct_window *w, int widget_index) } /** - * + * * rct2: 0x006ECDA4 */ rct_window *window_bring_to_front(rct_window *w) @@ -1122,7 +1136,7 @@ rct_window *window_bring_to_front_by_class(rct_windowclass cls) } /** - * + * * rct2: 0x006ED78A * cls (cl) * number (dx) @@ -1173,7 +1187,7 @@ void window_push_others_right(rct_window* window) } /** - * + * * rct2: 0x006EE6EA */ void window_push_others_below(rct_window *w1) @@ -1197,7 +1211,7 @@ void window_push_others_below(rct_window *w1) continue; // Check if there is room to push it down - if (w1->y + w1->height + 80 >= RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16)) + if (w1->y + w1->height + 80 >= RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16)) continue; // Invalidate the window's current area @@ -1217,13 +1231,13 @@ void window_push_others_below(rct_window *w1) /** - * + * * rct2: 0x006EE2E4 */ rct_window *window_get_main() { rct_window* w; - + for (w = g_window_list; w < RCT2_NEW_WINDOW; w++) if (w->classification == WC_MAIN_WINDOW) return w; @@ -1232,14 +1246,15 @@ rct_window *window_get_main() } /** - * Based on + * Based on * rct2: 0x696ee9 & 0x66842F & 0x006AF3B3 - * + * */ void window_scroll_to_viewport(rct_window *w) { int x, y, z; rct_window *mainWindow; + assert(w != NULL); // In original checked to make sure x and y were not -1 as well. if (w->viewport == NULL || w->viewport_focus_coordinates.y == -1) return; @@ -1270,6 +1285,13 @@ void window_scroll_to_viewport(rct_window *w) */ void window_scroll_to_location(rct_window *w, int x, int y, int z) { + rct_xyz16 location_3d = { + .x = x, + .y = y, + .z = z + }; + + assert(w != NULL); if (w->viewport) { sint16 height = map_element_height(x, y); if (z < height - 16) { @@ -1283,26 +1305,9 @@ void window_scroll_to_location(rct_window *w, int x, int y, int z) window_invalidate(w); } } - sint16 sx; - sint16 sy; - switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)) { - case 0: - sx = y - x; - sy = ((x + y) / 2) - z; - break; - case 1: - sx = -y - x; - sy = ((-x + y) / 2) - z; - break; - case 2: - sx = -y + x; - sy = ((-x - y) / 2) - z; - break; - case 3: - sx = y + x; - sy = ((x - y) / 2) - z; - break; - } + + rct_xy16 map_coordinate = coordinate_3d_to_2d(&location_3d, get_current_rotation()); + int i = 0; if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO)) { int found = 0; @@ -1335,9 +1340,9 @@ void window_scroll_to_location(rct_window *w, int x, int y, int z) } // rct2: 0x006E7C76 if (w->viewport_target_sprite == -1) { - if (!(w->flags & WF_2)) { - w->saved_view_x = sx - (sint16)(w->viewport->view_width * window_scroll_locations[i][0]); - w->saved_view_y = sy - (sint16)(w->viewport->view_height * window_scroll_locations[i][1]); + if (!(w->flags & WF_NO_SCROLLING)) { + w->saved_view_x = map_coordinate.x - (sint16)(w->viewport->view_width * window_scroll_locations[i][0]); + w->saved_view_y = map_coordinate.y - (sint16)(w->viewport->view_height * window_scroll_locations[i][1]); w->flags |= WF_SCROLLING_TO_LOCATION; } } @@ -1345,7 +1350,7 @@ void window_scroll_to_location(rct_window *w, int x, int y, int z) } /** - * + * * rct2: 0x00688956 */ void sub_688956() @@ -1357,10 +1362,13 @@ void sub_688956() } /** - * + * * rct2: 0x0068881A + * direction can be used to alter the camera rotation: + * 1: clockwise + * -1: anti-clockwise */ -void window_rotate_camera(rct_window *w) +void window_rotate_camera(rct_window *w, int direction) { rct_viewport *viewport = w->viewport; if (viewport == NULL) @@ -1372,20 +1380,21 @@ void window_rotate_camera(rct_window *w) //has something to do with checking if middle of the viewport is obstructed rct_viewport *other; - sub_688972(x, y, &x, &y, &other); + screen_get_map_xy(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? - if (x == (sint16)SPRITE_LOCATION_NULL || other != viewport){ + if (x == SPRITE_LOCATION_NULL || other != viewport) { x = (viewport->view_width >> 1) + viewport->view_x; y = (viewport->view_height >> 1) + viewport->view_y; sub_689174(&x, &y, &z); - } else { + } + else { z = map_element_height(x, y); } - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32) = (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32) + 1) % 4; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32) = (get_current_rotation() + direction) & 3; int new_x, new_y; center_2d_coordinates(x, y, z, &new_x, &new_y, viewport); @@ -1434,7 +1443,7 @@ void window_zoom_set(rct_window *w, int zoomLevel) } /** - * + * * rct2: 0x006887A6 */ void window_zoom_in(rct_window *w) @@ -1443,7 +1452,7 @@ void window_zoom_in(rct_window *w) } /** - * + * * rct2: 0x006887E0 */ void window_zoom_out(rct_window *w) @@ -1452,7 +1461,7 @@ void window_zoom_out(rct_window *w) } /** - * + * * rct2: 0x006EE308 * DEPRECIATED please use the new text_input window. */ @@ -1598,7 +1607,7 @@ static int window_draw_split(rct_window *w, int left, int top, int right, int bo } /** - * + * * rct2: 0x006EB15C * * @param window (esi) @@ -1609,7 +1618,7 @@ void window_draw_widgets(rct_window *w, rct_drawpixelinfo *dpi) rct_widget *widget; int widgetIndex; - if ((w->flags & WF_TRANSPARENT) && !(w->flags & WF_5)) + if ((w->flags & WF_TRANSPARENT) && !(w->flags & WF_NO_BACKGROUND)) gfx_fill_rect(dpi, w->x, w->y, w->x + w->width - 1, w->y + w->height - 1, 0x2000000 | 51); //todo: some code missing here? Between 006EB18C and 006EB260 @@ -1632,7 +1641,7 @@ void window_draw_widgets(rct_window *w, rct_drawpixelinfo *dpi) } /** - * + * * rct2: 0x00685BE1 * * @param dpi (edi) @@ -1722,7 +1731,7 @@ void window_set_resize(rct_window *w, int minWidth, int minHeight, int maxWidth, } /** - * + * * rct2: 0x006EE212 * * @param tool (al) @@ -1754,7 +1763,7 @@ int tool_set(rct_window *w, int widgetIndex, int tool) } /** - * + * * rct2: 0x006EE281 */ void tool_cancel() @@ -1815,211 +1824,180 @@ void window_guest_list_init_vars_b() RCT2_GLOBAL(0x00F1AF20, uint16) = 0; } -static void window_event_call_address(int address, rct_window *w) +void window_event_close_call(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 + if (w->event_handlers->close != NULL) + w->event_handlers->close(w); } -void window_event_close_call(rct_window* w) +void window_event_mouse_up_call(rct_window *w, int widgetIndex) { - window_event_call_address(w->event_handlers[WE_CLOSE], w); + if (w->event_handlers->mouse_up != NULL) + w->event_handlers->mouse_up(w, widgetIndex); } -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_MOUSE_UP], 0, 0, 0, widgetIndex, (int)w, (int)&(w->event_handlers[widgetIndex]), 0); -} - -void window_event_resize_call(rct_window* w) -{ - window_event_call_address(w->event_handlers[WE_RESIZE], w); + if (w->event_handlers->resize != NULL) + w->event_handlers->resize(w); } void window_event_mouse_down_call(rct_window *w, int widgetIndex) { - int address = w->event_handlers[WE_MOUSE_DOWN]; - rct_widget *widget = &w->widgets[widgetIndex]; - - #ifdef _MSC_VER - __asm { - push ebp - push address - push widget - push w - push widgetIndex - mov edi, widget - mov edx, widgetIndex - mov esi, w - call[esp + 12] - add esp, 16 - pop ebp - } - #else - __asm__("\ - push ebp \n\ - push %[address]\n\ - mov edi, %[widget] \n\ - mov eax, %[w] \n\ - mov edx, %[widgetIndex] \n\ - push edi \n\ - push eax \n\ - push edx \n\ - mov esi, %[w] \n\ - call [esp+12] \n\ - add esp, 16 \n\ - pop ebp \n\ - " :[address] "+m" (address), [w] "+m" (w), [widget] "+m" (widget), [widgetIndex] "+m" (widgetIndex): : "eax", "esi", "edx", "edi" - ); - #endif + if (w->event_handlers->mouse_down != NULL) + w->event_handlers->mouse_down(widgetIndex, w, &w->widgets[widgetIndex]); } -void window_event_dropdown_call(rct_window* w, int widgetIndex, int dropdownIndex) +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); + if (w->event_handlers->dropdown != NULL) + w->event_handlers->dropdown(w, widgetIndex, dropdownIndex); } -void window_event_unknown_05_call(rct_window* w) +void window_event_unknown_05_call(rct_window *w) { - window_event_call_address(w->event_handlers[WE_UNKNOWN_05], w); + if (w->event_handlers->unknown_05 != NULL) + w->event_handlers->unknown_05(w); } void window_event_update_call(rct_window *w) { - window_event_call_address(w->event_handlers[WE_UPDATE], w); + if (w->event_handlers->update != NULL) + w->event_handlers->update(w); } -void window_event_unknown_07_call(rct_window* w) +void window_event_unknown_07_call(rct_window *w) { - window_event_call_address(w->event_handlers[WE_UNKNOWN_07], w); + if (w->event_handlers->unknown_07 != NULL) + w->event_handlers->unknown_07(w); } -void window_event_unknown_08_call(rct_window* w) +void window_event_unknown_08_call(rct_window *w) { - window_event_call_address(w->event_handlers[WE_UNKNOWN_08], w); + if (w->event_handlers->unknown_08 != NULL) + w->event_handlers->unknown_08(w); } -void window_event_tool_update_call(rct_window* w, int widgetIndex, int x, int y) +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); + if (w->event_handlers->tool_update != NULL) + w->event_handlers->tool_update(w, widgetIndex, x, y); } -void window_event_tool_down_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) { - RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_DOWN], x, y, 0, widgetIndex, (int)w, 0, 0); + if (w->event_handlers->tool_down != NULL) + w->event_handlers->tool_down(w, widgetIndex, x, y); } -void window_event_tool_drag_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) { - RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_DRAG], x, y, 0, widgetIndex, (int)w, 0, 0); + if (w->event_handlers->tool_drag != NULL) + w->event_handlers->tool_drag(w, widgetIndex, x, y); } -void window_event_tool_up_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) { - RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_UP], x, y, 0, widgetIndex, (int)w, 0, 0); + if (w->event_handlers->tool_up != NULL) + w->event_handlers->tool_up(w, widgetIndex, x, y); } -void window_event_tool_abort_call(rct_window* w, int widgetIndex) +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); + if (w->event_handlers->tool_abort != NULL) + w->event_handlers->tool_abort(w, widgetIndex); } -void window_event_unknown_0E_call(rct_window* w) +void window_event_unknown_0E_call(rct_window *w) { - window_event_call_address(w->event_handlers[WE_UNKNOWN_0E], w); + if (w->event_handlers->unknown_0E != NULL) + w->event_handlers->unknown_0E(w); } -int window_get_scroll_size(rct_window *w, int scrollIndex, int *width, int *height) +void 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); + if (w->event_handlers->get_scroll_size != NULL) { + 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; + w->event_handlers->get_scroll_size(w, scrollIndex, width, height); + } } -void window_event_scroll_mousedown_call(rct_window* w, int scrollIndex, int x, int y) +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); + if (w->event_handlers->scroll_mousedown != NULL) + w->event_handlers->scroll_mousedown(w, scrollIndex, x, y); } -void window_event_unknown_11_call(rct_window* w) +void window_event_scroll_mousedrag_call(rct_window *w, int scrollIndex, int x, int y) { - window_event_call_address(w->event_handlers[WE_UNKNOWN_11], w); + if (w->event_handlers->scroll_mousedrag != NULL) + w->event_handlers->scroll_mousedrag(w, scrollIndex, x, y); } -void window_event_scroll_mouseover_call(rct_window* w, int scrollIndex, int x, int y) +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); + if (w->event_handlers->scroll_mouseover != NULL) + w->event_handlers->scroll_mouseover(w, scrollIndex, x, y); } 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); + if (w->event_handlers->text_input != NULL) + w->event_handlers->text_input(w, widgetIndex, text); } -void window_event_unknown_14_call(rct_window* w) +void window_event_unknown_14_call(rct_window *w) { - window_event_call_address(w->event_handlers[WE_UNKNOWN_14], w); + if (w->event_handlers->unknown_14 != NULL) + w->event_handlers->unknown_14(w); } -void window_event_unknown_15_call(rct_window* w, int scrollIndex, int scrollAreaType) +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); + if (w->event_handlers->unknown_15 != NULL) + w->event_handlers->unknown_15(w, scrollIndex, scrollAreaType); } -rct_string_id window_event_tooltip_call(rct_window* w, int widgetIndex) +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; + rct_string_id result = 0; + if (w->event_handlers->tooltip != NULL) + w->event_handlers->tooltip(w, widgetIndex, &result); + return result; } -int window_event_cursor_call(rct_window* w, int widgetIndex, int x, int y) +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; + int cursorId = CURSOR_ARROW; + if (w->event_handlers->cursor != NULL) + w->event_handlers->cursor(w, widgetIndex, x, y, &cursorId); + return cursorId; } -void window_event_moved_call(rct_window* w, int x, int y) +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); + if (w->event_handlers->moved != NULL) + w->event_handlers->moved(w, x, y); } -void window_event_invalidate_call(rct_window* w) +void window_event_invalidate_call(rct_window *w) { - RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + if (w->event_handlers->invalidate != NULL) + w->event_handlers->invalidate(w); } -void window_event_paint_call(rct_window* w, rct_drawpixelinfo *dpi) +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); + if (w->event_handlers->paint != NULL) + w->event_handlers->paint(w, dpi); } -void window_event_scroll_paint_call(rct_window* w, rct_drawpixelinfo *dpi, int scrollIndex) +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); + if (w->event_handlers->scroll_paint != NULL) + w->event_handlers->scroll_paint(w, dpi, scrollIndex); } /** @@ -2033,7 +2011,7 @@ void window_bubble_list_item(rct_window* w, int item_position){ w->list_item_positions[item_position + 1] = swap; } -/* rct2: 0x006ED710 +/* rct2: 0x006ED710 * Called after a window resize to move windows if they * are going to be out of sight. */ @@ -2167,7 +2145,7 @@ void window_resize_gui_scenario_editor(int width, int height) RCT2_GLOBAL(0x9A998A, uint16) = bottomWind->width - 198; RCT2_GLOBAL(0x9A998C, uint16) = bottomWind->width - 3; } - + } /* Based on rct2: 0x6987ED and another version from window_park */ @@ -2175,7 +2153,7 @@ void window_align_tabs(rct_window *w, uint8 start_tab_id, uint8 end_tab_id) { int i, x = w->widgets[start_tab_id].left; int tab_width = w->widgets[start_tab_id].right - w->widgets[start_tab_id].left; - + for (i = start_tab_id; i <= end_tab_id; i++) { if (!(w->disabled_widgets & (1LL << i))) { w->widgets[i].left = x; @@ -2407,7 +2385,7 @@ void window_move_and_snap(rct_window *w, int newWindowX, int newWindowY, int sna int originalY = w->y; newWindowY = clamp(29, newWindowY, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - 34); - + if (snapProximity > 0) { w->x = newWindowX; w->y = newWindowY; @@ -2447,8 +2425,12 @@ void textinput_cancel() // 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. +#ifdef _WIN32 RCT2_CALLPROC_EBPSAFE(0x0040701D); - if (RCT2_GLOBAL(0x009DEB8C, uint8) != 255) { +#else + log_warning("there should be something called here (0x0040701D)"); +#endif // _WIN32 + if (RCT2_GLOBAL(RCT2_ADDRESS_TEXTINPUT_WINDOWCLASS, uint8) != 255) { RCT2_CALLPROC_EBPSAFE(0x006EE4E2); w = window_find_by_number( RCT2_GLOBAL(RCT2_ADDRESS_TEXTINPUT_WINDOWCLASS, rct_windowclass), @@ -2497,6 +2479,7 @@ void window_cancel_textbox() gCurrentTextBox.window.classification, gCurrentTextBox.window.number ); + window_event_textinput_call(w, gCurrentTextBox.widget_index, NULL); gCurrentTextBox.window.classification = 255; gCurrentTextBox.window.number = 0; platform_stop_text_input(); @@ -2524,4 +2507,4 @@ void window_update_textbox() 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 6196f8fb67..28862b35c9 100644 --- a/src/interface/window.h +++ b/src/interface/window.h @@ -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 . *****************************************************************************/ @@ -27,6 +27,7 @@ #include "../ride/ride.h" #include "../ride/vehicle.h" #include "../world/park.h" +#include "colour.h" struct rct_window; union rct_window_event; @@ -92,17 +93,17 @@ typedef struct { */ typedef struct { uint16 flags; // 0x00 - sint16 h_left; // 0x02 - sint16 h_right; // 0x04 - sint16 h_thumb_left; // 0x06 - sint16 h_thumb_right; // 0x08 - sint16 v_top; // 0x0A - sint16 v_bottom; // 0x0C - sint16 v_thumb_top; // 0x0E - sint16 v_thumb_bottom; // 0x10 + uint16 h_left; // 0x02 + uint16 h_right; // 0x04 + uint16 h_thumb_left; // 0x06 + uint16 h_thumb_right; // 0x08 + uint16 v_top; // 0x0A + uint16 v_bottom; // 0x0C + uint16 v_thumb_top; // 0x0E + uint16 v_thumb_bottom; // 0x10 } rct_scroll; -/** +/** * Viewport focus structure. * size: 0xA * Use sprite.type to work out type. @@ -122,7 +123,7 @@ typedef struct{ uint16 sprite_id; //0x482 uint8 pad_484; uint8 type; //0x485 & VIEWPORT_FOCUS_TYPE_MASK - uint16 pad_486; + uint16 pad_486; uint8 rotation; //0x488 uint8 zoom; //0x489 } sprite_focus; @@ -134,6 +135,36 @@ enum{ }; #define VIEWPORT_FOCUS_Y_MASK 0x3FFF +typedef struct { + void (*close)(struct rct_window*); + void (*mouse_up)(struct rct_window*, int); + void (*resize)(struct rct_window*); + void (*mouse_down)(int, struct rct_window*, rct_widget*); + void (*dropdown)(struct rct_window*, int, int); + void (*unknown_05)(struct rct_window*); + void (*update)(struct rct_window*); + void (*unknown_07)(struct rct_window*); + void (*unknown_08)(struct rct_window*); + void (*tool_update)(struct rct_window*, int, int, int); + void (*tool_down)(struct rct_window*, int, int, int); + void (*tool_drag)(struct rct_window*, int, int, int); + void (*tool_up)(struct rct_window*, int, int, int); + void (*tool_abort)(struct rct_window*, int); + void (*unknown_0E)(struct rct_window*); + void (*get_scroll_size)(struct rct_window*, int, int*, int*); + void (*scroll_mousedown)(struct rct_window*, int, int, int); + void (*scroll_mousedrag)(struct rct_window*, int, int, int); + void (*scroll_mouseover)(struct rct_window*, int, int, int); + void (*text_input)(struct rct_window*, int, char*); + void (*unknown_14)(struct rct_window*); + void (*unknown_15)(struct rct_window*, int, int); + void (*tooltip)(struct rct_window*, int, rct_string_id*); + void (*cursor)(struct rct_window*, int, int, int, int*); + void (*moved)(struct rct_window*, int, int); + void (*invalidate)(struct rct_window*); + void (*paint)(struct rct_window*, rct_drawpixelinfo*); + void (*scroll_paint)(struct rct_window*, rct_drawpixelinfo*, int); +} rct_window_event_list; typedef struct{ sint16 campaign_type; @@ -192,7 +223,7 @@ typedef struct { * size: 0x4C0 */ typedef struct rct_window { - uint32* event_handlers; // 0x000 + rct_window_event_list* event_handlers; // 0x000 rct_viewport* viewport; // 0x004 uint64 enabled_widgets; // 0x008 uint64 disabled_widgets; // 0x010 @@ -256,7 +287,7 @@ typedef enum { WE_RESIZE = 2, WE_MOUSE_DOWN = 3, WE_DROPDOWN = 4, - WE_UNKNOWN_05 = 5, + WE_UNKNOWN_05 = 5, // Unknown 05: Used to update tabs that are not being animated // see window_peep. When the overview tab is not highlighted the // items being carried such as hats/balloons still need to be shown @@ -273,7 +304,7 @@ typedef enum { WE_UNKNOWN_0E = 14, WE_SCROLL_GETSIZE = 15, WE_SCROLL_MOUSEDOWN = 16, - WE_UNKNOWN_11 = 17, + WE_SCROLL_MOUSEDRAG = 17, WE_SCROLL_MOUSEOVER = 18, WE_TEXT_INPUT = 19, WE_UNKNOWN_14 = 20, @@ -299,13 +330,13 @@ typedef enum { WF_STICK_TO_BACK = (1 << 0), WF_STICK_TO_FRONT = (1 << 1), - WF_2 = (1 << 2), + WF_NO_SCROLLING = (1 << 2), // User is unable to scroll this viewport WF_SCROLLING_TO_LOCATION = (1 << 3), WF_TRANSPARENT = (1 << 4), - WF_5 = (1 << 5), + WF_NO_BACKGROUND = (1 << 5), // Instead of half transparency, completely remove the window background WF_7 = (1 << 7), WF_RESIZABLE = (1 << 8), - WF_9 = (1 << 9), + WF_NO_AUTO_CLOSE = (1 << 9), // Don't auto close this window if too many windows are open WF_10 = (1 << 10), WF_WHITE_BORDER_ONE = (1 << 12), WF_WHITE_BORDER_MASK = (1 << 12) | (1 << 13), @@ -351,6 +382,7 @@ enum { INPUT_STATE_VIEWPORT_LEFT = 6, INPUT_STATE_SCROLL_LEFT = 7, INPUT_STATE_RESIZING = 8, + INPUT_STATE_SCROLL_RIGHT = 9 }; enum { @@ -414,12 +446,18 @@ enum { WC_THEMES = 119, WC_TILE_INSPECTOR = 120, WC_CHANGELOG = 121, + WC_TITLE_EDITOR = 122, + WC_TITLE_COMMAND_EDITOR = 123, + WC_CHAT_HOST = 124, + WC_PLAYER_LIST = 125, + WC_NETWORK_STATUS = 126, + WC_SERVER_LIST = 127, + WC_SERVER_START = 128, // 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 { @@ -437,6 +475,7 @@ typedef enum { BTM_TB_DIRTY_FLAG_PARK_RATING = (1 << 4) } BTM_TOOLBAR_DIRTY_FLAGS; +// 000N_TTTL enum { LOADSAVETYPE_LOAD = 0 << 0, LOADSAVETYPE_SAVE = 1 << 0, @@ -445,8 +484,20 @@ enum { LOADSAVETYPE_LANDSCAPE = 1 << 1, LOADSAVETYPE_SCENARIO = 2 << 1, LOADSAVETYPE_TRACK = 3 << 1, + + LOADSAVETYPE_NETWORK = 1 << 4, }; +enum { + MODAL_RESULT_FAIL = -1, + MODAL_RESULT_CANCEL, + MODAL_RESULT_OK +}; + +typedef void (*modal_callback)(int result); + +extern bool gLoadSaveTitleSequenceSave; +extern modal_callback gLoadSaveCallback; // rct2: 0x01420078 extern rct_window* g_window_list; @@ -455,10 +506,11 @@ extern rct_window* g_window_list; extern ride_list_item _window_track_list_item; void window_dispatch_update_all(); +void window_update_all_viewports(); 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); +rct_window *window_create(int x, int y, int width, int height, rct_window_event_list *event_handlers, rct_windowclass cls, uint16 flags); +rct_window *window_create_auto_pos(int width, int height, rct_window_event_list *event_handlers, rct_windowclass cls, uint16 flags); +rct_window *window_create_centred(int width, int height, rct_window_event_list *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); @@ -491,12 +543,13 @@ 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_rotate_camera(rct_window *w, int direction); void window_zoom_set(rct_window *w, int zoomLevel); void window_zoom_in(rct_window *w); void window_zoom_out(rct_window *w); void window_show_textinput(rct_window *w, int widgetIndex, uint16 title, uint16 text, int value); +void window_text_input_key(rct_window* w, int key); void window_draw(rct_window *w, int left, int top, int right, int bottom); void window_draw_widgets(rct_window *w, rct_drawpixelinfo *dpi); @@ -543,7 +596,7 @@ void window_options_open(); void window_shortcut_keys_open(); void window_shortcut_change_open(int selected_key); void window_guest_open(rct_peep* peep); -void window_staff_open(rct_peep* peep); +rct_window *window_staff_open(rct_peep* peep); void window_staff_fire_prompt_open(rct_peep* peep); void window_park_awards_open(); void window_park_entrance_open(); @@ -560,7 +613,13 @@ rct_window *window_ride_open_vehicle(rct_vehicle *vehicle); void window_ride_demolish_prompt_open(int rideIndex); void window_ride_construct(rct_window *w); void window_ride_list_open(); -rct_window * window_construction_open(); +rct_window *window_ride_construction_open(); +rct_window *window_maze_construction_open(); +void ride_construction_toolupdate_entrance_exit(int screenX, int screenY); +void ride_construction_toolupdate_construct(int screenX, int screenY); +void ride_construction_tooldown_construct(int screenX, int screenY); + +void window_maze_construction_update_pressed_widgets(); void window_track_place_open(); rct_window *window_new_ride_open(); rct_window *window_new_ride_open_research(); @@ -569,13 +628,25 @@ void window_banner_open(rct_windownumber number); void window_sign_open(rct_windownumber number); void window_sign_small_open(rct_windownumber number); void window_cheats_open(); +void window_player_list_open(); +void window_network_status_open(const char* text); +void window_network_status_close(); +void window_network_status_open_password(); +void window_server_list_open(); +void window_server_start_open(); + void window_research_open(); +void window_research_development_page_paint(rct_window *w, rct_drawpixelinfo *dpi, int baseWidgetIndex); +void window_research_funding_page_paint(rct_window *w, rct_drawpixelinfo *dpi, int baseWidgetIndex); + void window_scenery_open(); void window_music_credits_open(); void window_publisher_credits_open(); void window_track_manage_open(); void window_viewport_open(); void window_themes_open(); +void window_title_editor_open(int tab); +void window_title_command_editor_open(int command, bool insert); 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); @@ -618,9 +689,9 @@ 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_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_mousedrag_call(rct_window* w, int scrollIndex, int x, int y); 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); @@ -643,148 +714,9 @@ void window_cancel_textbox(); void window_update_textbox_caret(); void window_update_textbox(); +bool land_tool_is_active(); + //Cheat: in-game land ownership editor void toggle_ingame_land_ownership_editor(); -#ifdef _MSC_VER - #define window_get_register(w) \ - __asm mov w, esi - - #define window_widget_get_registers(w, widgetIndex) \ - __asm mov widgetIndex, dx \ - __asm mov w, esi - - #define window_dropdown_get_registers(w, widgetIndex, dropdownIndex) \ - __asm mov dropdownIndex, ax \ - __asm mov widgetIndex, dx \ - __asm mov w, esi - - #define window_text_input_get_registers(w, widgetIndex, result, text) \ - __asm mov widgetIndex, dx \ - __asm mov result, cl \ - __asm mov w, esi \ - __asm mov text, edi - - #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 - - #define window_tool_get_registers(w, widgetIndex, x, y) \ - __asm mov x, ax \ - __asm mov y, bx \ - __asm mov widgetIndex, dx \ - __asm mov w, esi - - #define window_textinput_get_registers(w, widgetIndex, result, text) \ - __asm mov result, cl \ - __asm mov widgetIndex, dx \ - __asm mov w, esi \ - __asm mov text, edi - - #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) ); - - #define window_widget_get_registers(w, widgetIndex) \ - __asm__ ( "mov %["#widgetIndex"], dx " : [widgetIndex] "+m" (widgetIndex) ); \ - __asm__ ( "mov %["#w"], esi " : [w] "+m" (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 %["#w"], esi " : [w] "+m" (w) ); - - #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_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 %["#w"], esi " : [w] "+m" (w) ); - - #define window_textinput_get_registers(w, widgetIndex, result, text) \ - __asm__ ( "mov %[result], cl " : [result] "+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_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 e5d9e09bef..3021a78860 100644 --- a/src/intro.c +++ b/src/intro.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 @@ -17,7 +17,7 @@ * 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 "drawing/drawing.h" @@ -31,15 +31,14 @@ static void screen_intro_process_keyboard_input(); static void screen_intro_skip_part(); static int _sound_playing_flag = 0; ///< Used to test if a sound is currently playing. -static rct_sound _prepared_sound; ///< A prepared sound for playing. static int _tick_counter; ///< Used mainly for timing but also for Y coordinate and fading. // rct2: 0x0068E966 void intro_update() { rct_drawpixelinfo *screenDPI = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); - int screenWidth = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); - int screenHeight = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16); + int screenWidth = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); + int screenHeight = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16); uint8 (*part) = RCT2_ADDRESS(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8); screen_intro_process_mouse_input(); @@ -47,29 +46,10 @@ void intro_update() RCT2_GLOBAL(0x009E2C78, int) = 1; switch ((*part)) { + // Cases 8 and 9 were used for the disclaimer text. There might be some residual occurences. case 8: - // Clear the screen - gfx_clear(screenDPI, 10); - - // Draw the disclaimer text - gfx_draw_string_centred(screenDPI, STR_LICENCE_AGREEMENT_NOTICE_1, screenWidth / 2, 180, 13, 0); - gfx_draw_string_centred(screenDPI, STR_LICENCE_AGREEMENT_NOTICE_2, screenWidth / 2, 195, 13, 0); - - // Set palette thing - gfx_transpose_palette(1532, 255); - - // Reset wait counter - _tick_counter = 0; - - // Move to next part - (*part)++; - break; case 9: - // Wait 320 game ticks, then move to part 1 - _tick_counter++; - if (_tick_counter >= 320) - (*part) = 1; - break; + (*part) = 1; case 1: // Clear the screen gfx_clear(screenDPI, 10); @@ -79,12 +59,12 @@ void intro_update() // Chain lift sound _sound_playing_flag = 0; - if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, sint32) != -1) { + /*if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, sint32) != -1) { // Prepare and play the sound if (sound_prepare(SOUND_LIFT_7, &_prepared_sound, 0, 1)) if (sound_play(&_prepared_sound, 1, 0, 0, 0)) _sound_playing_flag = 1; - } + }*/ // Move to next part (*part)++; @@ -121,7 +101,7 @@ void intro_update() break; case 3: - // + // _tick_counter += 5; // Clear the screen @@ -151,17 +131,17 @@ void intro_update() if (_tick_counter == 259) { // Stop the chain lift sound if (_sound_playing_flag == 1) { - sound_stop(&_prepared_sound); + //sound_stop(&_prepared_sound); _sound_playing_flag = 0; } // Play the track friction sound - if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, sint32) != -1) { + /*if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, sint32) != -1) { // Prepare and play the sound if (sound_prepare(SOUND_TRACK_FRICTION_3, &_prepared_sound, 1, 1)) if (sound_play(&_prepared_sound, 1, -800, 0, 0x3A98)) _sound_playing_flag = 1; - } + }*/ } // Check if logo is off the screen .ish @@ -182,15 +162,15 @@ void intro_update() // Stop the track friction sound if (_sound_playing_flag == 1) { - sound_stop(&_prepared_sound); + //sound_stop(&_prepared_sound); _sound_playing_flag = 0; } // Play long peep scream sound - if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, sint32) != -1) + /*if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, sint32) != -1) if (sound_prepare(SOUND_SCREAM_1, &_prepared_sound, 0, 1)) if (sound_play(&_prepared_sound, 0, 0, 0, 0)) - _sound_playing_flag = 1; + _sound_playing_flag = 1;*/ // Move to the next part (*part)++; @@ -249,7 +229,7 @@ void intro_update() // Stop any playing sound if (_sound_playing_flag == 1) { - sound_stop(&_prepared_sound); + //sound_stop(&_prepared_sound); _sound_playing_flag = 0; } diff --git a/src/intro.h b/src/intro.h index b0f09cb462..b3df910e2c 100644 --- a/src/intro.h +++ b/src/intro.h @@ -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 @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ - + #ifndef _INTRO_H_ #define _INTRO_H_ diff --git a/src/localisation/LanguagePack.cpp b/src/localisation/LanguagePack.cpp new file mode 100644 index 0000000000..5e7d3dd64b --- /dev/null +++ b/src/localisation/LanguagePack.cpp @@ -0,0 +1,496 @@ +extern "C" { + #include "../common.h" + #include "../util/util.h" + #include "localisation.h" + #include "../platform/platform.h" +} + +#include "../core/FileStream.hpp" +#include "../core/Memory.hpp" +#include "../core/StringBuilder.hpp" +#include "LanguagePack.h" +#include + +constexpr rct_string_id ObjectOverrideBase = 0x6000; +constexpr int ObjectOverrideMaxStringCount = 4; + +constexpr rct_string_id ScenarioOverrideBase = 0x7000; +constexpr int ScenarioOverrideMaxStringCount = 3; + +LanguagePack *LanguagePack::FromFile(int id, const utf8 *path) +{ + assert(path != nullptr); + + uint32 fileLength; + utf8 *fileData = nullptr; + + // Load file directly into memory + try { + FileStream fs = FileStream(path, FILE_MODE_OPEN); + + fileLength = (uint32)fs.GetLength(); + fileData = Memory::Allocate(fileLength + 1); + fs.Read(fileData, fileLength); + fileData[fileLength] = '\0'; + + fs.Dispose(); + } catch (Exception ex) { + Memory::Free(fileData); + log_error("Unable to open %s: %s", path, ex.GetMessage()); + return nullptr; + } + + // Parse the memory as text + LanguagePack *result = FromText(id, fileData); + + Memory::Free(fileData); + return result; +} + +LanguagePack *LanguagePack::FromText(int id, const utf8 *text) +{ + return new LanguagePack(id, text); +} + +LanguagePack::LanguagePack(int id, const utf8 *text) +{ + assert(text != nullptr); + + _id = id; + _stringData = nullptr; + _currentGroup = nullptr; + _currentObjectOverride = nullptr; + _currentScenarioOverride = nullptr; + + auto reader = UTF8StringReader(text); + while (reader.CanRead()) { + ParseLine(&reader); + } + + _stringData = _stringDataSB.GetString(); + + size_t stringDataBaseAddress = (size_t)_stringData; + for (size_t i = 0; i < _strings.size(); i++) { + if (_strings[i] != nullptr) + _strings[i] = (utf8*)(stringDataBaseAddress + (size_t)_strings[i]); + } + for (size_t i = 0; i < _objectOverrides.size(); i++) { + for (int j = 0; j < ObjectOverrideMaxStringCount; j++) { + const utf8 **strPtr = &(_objectOverrides[i].strings[j]); + if (*strPtr != nullptr) { + *strPtr = (utf8*)(stringDataBaseAddress + (size_t)*strPtr); + } + } + } + for (size_t i = 0; i < _scenarioOverrides.size(); i++) { + for (int j = 0; j < ScenarioOverrideMaxStringCount; j++) { + const utf8 **strPtr = &(_scenarioOverrides[i].strings[j]); + if (*strPtr != nullptr) { + *strPtr = (utf8*)(stringDataBaseAddress + (size_t)*strPtr); + } + } + } + + // Destruct the string builder to free memory + _stringDataSB = StringBuilder(); +} + +LanguagePack::~LanguagePack() +{ + SafeFree(_stringData); + SafeFree(_currentGroup); +} + +const utf8 *LanguagePack::GetString(int stringId) const { + if (stringId >= ScenarioOverrideBase) { + int offset = stringId - ScenarioOverrideBase; + int ooIndex = offset / ScenarioOverrideMaxStringCount; + int ooStringIndex = offset % ScenarioOverrideMaxStringCount; + + if (_scenarioOverrides.size() > (size_t)ooIndex) { + return _scenarioOverrides[ooIndex].strings[ooStringIndex]; + } else { + return nullptr; + } + }else if (stringId >= ObjectOverrideBase) { + int offset = stringId - ObjectOverrideBase; + int ooIndex = offset / ObjectOverrideMaxStringCount; + int ooStringIndex = offset % ObjectOverrideMaxStringCount; + + if (_objectOverrides.size() > (size_t)ooIndex) { + return _objectOverrides[ooIndex].strings[ooStringIndex]; + } else { + return nullptr; + } + } else { + if (_strings.size() > (size_t)stringId) { + return _strings[stringId]; + } else { + return nullptr; + } + } +} + +rct_string_id LanguagePack::GetObjectOverrideStringId(const char *objectIdentifier, int index) +{ + assert(objectIdentifier != nullptr); + assert(index < ObjectOverrideMaxStringCount); + + int ooIndex = 0; + for (const ObjectOverride &objectOverride : _objectOverrides) { + if (strncmp(objectOverride.name, objectIdentifier, 8) == 0) { + if (objectOverride.strings[index] == nullptr) { + return STR_NONE; + } + return ObjectOverrideBase + (ooIndex * ObjectOverrideMaxStringCount) + index; + } + ooIndex++; + } + + return STR_NONE; +} + +rct_string_id LanguagePack::GetScenarioOverrideStringId(const utf8 *scenarioFilename, int index) +{ + assert(scenarioFilename != nullptr); + assert(index < ScenarioOverrideMaxStringCount); + + int ooIndex = 0; + for (const ScenarioOverride &scenarioOverride : _scenarioOverrides) { + if (_stricmp(scenarioOverride.filename, scenarioFilename) == 0) { + if (scenarioOverride.strings[index] == nullptr) { + return STR_NONE; + } + return ScenarioOverrideBase + (ooIndex * ScenarioOverrideMaxStringCount) + index; + } + ooIndex++; + } + + return STR_NONE; +} + +LanguagePack::ObjectOverride *LanguagePack::GetObjectOverride(const char *objectIdentifier) +{ + assert(objectIdentifier != nullptr); + + for (size_t i = 0; i < _objectOverrides.size(); i++) { + ObjectOverride *oo = &_objectOverrides[i]; + if (strncmp(oo->name, objectIdentifier, 8) == 0) { + return oo; + } + } + return nullptr; +} + +LanguagePack::ScenarioOverride *LanguagePack::GetScenarioOverride(const utf8 *scenarioIdentifier) +{ + assert(scenarioIdentifier != nullptr); + + for (size_t i = 0; i < _scenarioOverrides.size(); i++) { + ScenarioOverride *so = &_scenarioOverrides[i]; + // At this point ScenarioOverrides were not yet rewritten to point at + // strings, but rather still hold offsets from base. + const utf8 *name = _stringDataSB.GetBuffer() + (size_t)so->name; + if (_stricmp(name, scenarioIdentifier) == 0) { + return so; + } + } + return nullptr; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Parsing +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// 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, +// get_string will use those if the same entry in the loaded language is empty. +// +// Unsure at how the original game decides which entries to write resource strings to, but this could affect adding new +// strings for the time being. Further investigation is required. +// +// When reading the language files, the 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. Tokens are written with inside curly braces {TOKEN}. +// Use # at the beginning of a line to leave a comment. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static bool IsWhitespace(int codepoint) +{ + return codepoint == '\t' || codepoint == ' ' || codepoint == '\r' || codepoint == '\n'; +} + +static bool IsNewLine(int codepoint) +{ + return codepoint == '\r' || codepoint == '\n'; +} + +static void SkipWhitespace(IStringReader *reader) +{ + int codepoint; + while (reader->TryPeek(&codepoint)) { + if (IsWhitespace(codepoint)) { + reader->Skip(); + } else { + break; + } + } +} + +static void SkipNewLine(IStringReader *reader) +{ + int codepoint; + while (reader->TryPeek(&codepoint)) { + if (IsNewLine(codepoint)) { + reader->Skip(); + } else { + break; + } + } +} + +static void SkipToEndOfLine(IStringReader *reader) +{ + int codepoint; + while (reader->TryPeek(&codepoint)) { + if (codepoint != '\r' && codepoint != '\n') { + reader->Skip(); + } else { + break; + } + } +} + +void LanguagePack::ParseLine(IStringReader *reader) +{ + SkipWhitespace(reader); + + int codepoint; + if (reader->TryPeek(&codepoint)) { + switch (codepoint) { + case '#': + SkipToEndOfLine(reader); + break; + case '[': + ParseGroupObject(reader); + break; + case '<': + ParseGroupScenario(reader); + break; + case '\r': + case '\n': + break; + default: + ParseString(reader); + break; + } + SkipToEndOfLine(reader); + SkipNewLine(reader); + } +} + +void LanguagePack::ParseGroupObject(IStringReader *reader) +{ + auto sb = StringBuilder(); + int codepoint; + + // Should have already deduced that the next codepoint is a [ + reader->Skip(); + + // Read string up to ] or line end + bool closedCorrectly = false; + while (reader->TryPeek(&codepoint)) { + if (IsNewLine(codepoint)) break; + + reader->Skip(); + if (codepoint == ']') { + closedCorrectly = true; + break; + } + sb.Append(codepoint); + } + + if (closedCorrectly) { + SafeFree(_currentGroup); + + while (sb.GetLength() < 8) { + sb.Append(' '); + } + if (sb.GetLength() == 8) { + _currentGroup = sb.GetString(); + _currentObjectOverride = GetObjectOverride(_currentGroup); + _currentScenarioOverride = nullptr; + if (_currentObjectOverride == nullptr) { + _objectOverrides.push_back(ObjectOverride()); + _currentObjectOverride = &_objectOverrides[_objectOverrides.size() - 1]; + memset(_currentObjectOverride, 0, sizeof(ObjectOverride)); + memcpy(_currentObjectOverride->name, _currentGroup, 8); + } + } + } +} + +void LanguagePack::ParseGroupScenario(IStringReader *reader) +{ + auto sb = StringBuilder(); + int codepoint; + + // Should have already deduced that the next codepoint is a < + reader->Skip(); + + // Read string up to > or line end + bool closedCorrectly = false; + while (reader->TryPeek(&codepoint)) { + if (IsNewLine(codepoint)) break; + + reader->Skip(); + if (codepoint == '>') { + closedCorrectly = true; + break; + } + sb.Append(codepoint); + } + + if (closedCorrectly) { + SafeFree(_currentGroup); + + _currentGroup = sb.GetString(); + _currentObjectOverride = nullptr; + _currentScenarioOverride = GetScenarioOverride(_currentGroup); + if (_currentScenarioOverride == nullptr) { + _scenarioOverrides.push_back(ScenarioOverride()); + _currentScenarioOverride = &_scenarioOverrides[_scenarioOverrides.size() - 1]; + memset(_currentScenarioOverride, 0, sizeof(ScenarioOverride)); + _currentScenarioOverride->filename = sb.GetString(); + } + } +} + +void LanguagePack::ParseString(IStringReader *reader) +{ + auto sb = StringBuilder(); + int codepoint; + + // Parse string identifier + while (reader->TryPeek(&codepoint)) { + if (IsNewLine(codepoint)) { + // Unexpected new line, ignore line entirely + return; + } else if (!IsWhitespace(codepoint) && codepoint != ':') { + reader->Skip(); + sb.Append(codepoint); + } else { + break; + } + } + + SkipWhitespace(reader); + + // Parse a colon + if (!reader->TryPeek(&codepoint) || codepoint != ':') { + // Expected a colon, ignore line entirely + return; + } + reader->Skip(); + + // Validate identifier + const utf8 *identifier = sb.GetBuffer(); + + int stringId; + if (_currentGroup == nullptr) { + if (sscanf(identifier, "STR_%4d", &stringId) != 1) { + // Ignore line entirely + return; + } + } else { + if (strcmp(identifier, "STR_NAME") == 0) { stringId = 0; } + else if (strcmp(identifier, "STR_DESC") == 0) { stringId = 1; } + else if (strcmp(identifier, "STR_CPTY") == 0) { stringId = 2; } + + else if (strcmp(identifier, "STR_SCNR") == 0) { stringId = 0; } + else if (strcmp(identifier, "STR_PARK") == 0) { stringId = 1; } + else if (strcmp(identifier, "STR_DTLS") == 0) { stringId = 2; } + else { + // Ignore line entirely + return; + } + } + + // Rest of the line is the actual string + sb.Clear(); + while (reader->TryPeek(&codepoint) && !IsNewLine(codepoint)) { + if (codepoint == '{') { + uint32 token; + bool isByte; + if (ParseToken(reader, &token, &isByte)) { + if (isByte) { + sb.Append((const utf8*)&token, 1); + } else { + sb.Append((int)token); + } + } else { + // Syntax error or unknown token, ignore line entirely + return; + } + } else { + reader->Skip(); + sb.Append(codepoint); + } + } + + // Append a null terminator for the benefit of the last string + _stringDataSB.Append(0); + + // Get the relative offset to the string (add the base offset when we extract the string properly) + utf8 *relativeOffset = (utf8*)_stringDataSB.GetLength(); + + if (_currentGroup == nullptr) { + // Make sure the list is big enough to contain this string id + while (_strings.size() <= (size_t)stringId) { + _strings.push_back(nullptr); + } + + _strings[stringId] = relativeOffset; + } else { + if (_currentObjectOverride != nullptr) { + _currentObjectOverride->strings[stringId] = relativeOffset; + } else { + _currentScenarioOverride->strings[stringId] = relativeOffset; + } + } + + _stringDataSB.Append(&sb); +} + +bool LanguagePack::ParseToken(IStringReader *reader, uint32 *token, bool *isByte) +{ + auto sb = StringBuilder(); + int codepoint; + + // Skip open brace + reader->Skip(); + + while (reader->TryPeek(&codepoint)) { + if (IsNewLine(codepoint)) return false; + if (IsWhitespace(codepoint)) return false; + + reader->Skip(); + + if (codepoint == '}') break; + + sb.Append(codepoint); + } + + const utf8 *tokenName = sb.GetBuffer(); + *token = format_get_code(tokenName); + *isByte = false; + + // Handle explicit byte values + if (*token == 0) { + int number; + if (sscanf(tokenName, "%d", &number) == 1) { + *token = Math::Clamp(0, number, 255); + *isByte = true; + } + } + + return true; +} diff --git a/src/localisation/LanguagePack.h b/src/localisation/LanguagePack.h new file mode 100644 index 0000000000..871b689401 --- /dev/null +++ b/src/localisation/LanguagePack.h @@ -0,0 +1,77 @@ +#pragma once + +#include + +extern "C" { + #include "../common.h" + #include "../util/util.h" + #include "localisation.h" +} + +#include "../core/StringBuilder.hpp" +#include "../core/StringReader.hpp" + +class LanguagePack final { +public: + static LanguagePack *FromFile(int id, const utf8 *path); + static LanguagePack *FromText(int id, const utf8 *text); + + ~LanguagePack(); + + int GetId() const { return _id; } + int GetCount() const { return _strings.size(); } + + const utf8 *GetString(int stringId) const; + + void SetString(int stringId, const utf8 *str) { + if (_strings.size() >= (size_t)stringId) { + _strings[stringId] = str; + } + } + + rct_string_id GetObjectOverrideStringId(const char *objectIdentifier, int index); + rct_string_id GetScenarioOverrideStringId(const utf8 *scenarioFilename, int index); + +private: + struct ObjectOverride { + char name[8]; + const utf8 *strings[4]; + }; + + struct ScenarioOverride { + const utf8 *filename; + union { + const utf8 *strings[3]; + struct { + const utf8 *name; + const utf8 *park; + const utf8 *details; + }; + }; + }; + + int _id; + utf8 *_stringData; + std::vector _strings; + std::vector _objectOverrides; + std::vector _scenarioOverrides; + + LanguagePack(int id, const utf8 *text); + ObjectOverride *GetObjectOverride(const char *objectIdentifier); + ScenarioOverride *GetScenarioOverride(const utf8 *scenarioFilename); + + /////////////////////////////////////////////////////////////////////////// + // Parsing + /////////////////////////////////////////////////////////////////////////// + StringBuilder _stringDataSB; + utf8 *_currentGroup; + ObjectOverride *_currentObjectOverride; + ScenarioOverride *_currentScenarioOverride; + + void ParseLine(IStringReader *reader); + void ParseGroupObject(IStringReader *reader); + void ParseGroupScenario(IStringReader *reader); + void ParseString(IStringReader *reader); + + bool ParseToken(IStringReader *reader, uint32 *token, bool *isByte); +}; diff --git a/src/localisation/convert.c b/src/localisation/convert.c new file mode 100644 index 0000000000..fb4963bb82 --- /dev/null +++ b/src/localisation/convert.c @@ -0,0 +1,21517 @@ +#include "localisation.h" + +typedef struct { + uint16 code; + uint16 unicode; +} encoding_convert_entry; + +static const encoding_convert_entry GB2312ToUnicodeTable[7445]; +static const encoding_convert_entry Big5ToUnicodeTable[13710]; +static const encoding_convert_entry RCT2ToUnicodeTable[256]; + +int rct2_to_utf8(utf8 *dst, const char *src) +{ + int codepoint; + + utf8 *start = dst; + const char *ch = src; + while (*ch != 0) { + if (*ch == (char)0xFF) { + ch++; + + // Read wide char + uint8 a = *ch++; + uint8 b = *ch++; + codepoint = (a << 8) | b; + } else { + codepoint = (uint8)(*ch++); + codepoint = encoding_convert_rct2_to_unicode(codepoint); + } + + dst = utf8_write_codepoint(dst, codepoint); + } + dst = utf8_write_codepoint(dst, 0); + return dst - start; +} + +int utf8_to_rct2(char *dst, const utf8 *src) +{ + char *start = dst; + const utf8 *ch = src; + int codepoint; + while ((codepoint = utf8_get_next(ch, &ch)) != 0) { + codepoint = encoding_convert_unicode_to_rct2(codepoint); + if (codepoint < 256) { + *dst++ = (char)codepoint; + } else if (codepoint <= 0xFFFF) { + *dst++ = (char)0xFF; + *dst++ = (codepoint >> 8) & 0xFF; + *dst++ = codepoint & 0xFF; + } + } + *dst++ = 0; + return dst - start; +} + +static int encoding_search_compare(const void *pKey, const void *pEntry) +{ + uint16 key = *((uint16*)pKey); + encoding_convert_entry *entry = (encoding_convert_entry*)pEntry; + if (key < entry->code) return -1; + if (key > entry->code) return 1; + return 0; +} + +static wchar_t encoding_convert_x_to_unicode(wchar_t code, const encoding_convert_entry *table, int count) +{ + encoding_convert_entry *entry = bsearch(&code, table, count, sizeof(encoding_convert_entry), encoding_search_compare); + if (entry == NULL) return code; + else return entry->unicode; +} + +wchar_t encoding_convert_unicode_to_rct2(wchar_t unicode) +{ + // Can't do a binary search as its sorted by RCT2 code, not unicode + for (int i = 0; i < countof(RCT2ToUnicodeTable); i++) { + if (RCT2ToUnicodeTable[i].unicode == unicode) return RCT2ToUnicodeTable[i].code; + } + return unicode; +} + +wchar_t encoding_convert_rct2_to_unicode(wchar_t rct2str) +{ + return encoding_convert_x_to_unicode(rct2str, RCT2ToUnicodeTable, countof(RCT2ToUnicodeTable)); +} + +wchar_t encoding_convert_gb2312_to_unicode(wchar_t gb2312) +{ + return encoding_convert_x_to_unicode(gb2312 - 0x8080, GB2312ToUnicodeTable, countof(GB2312ToUnicodeTable)); +} + +wchar_t encoding_convert_big5_to_unicode(wchar_t big5) +{ + return encoding_convert_x_to_unicode(big5, Big5ToUnicodeTable, countof(Big5ToUnicodeTable)); +} + +static const encoding_convert_entry RCT2ToUnicodeTable[256] = { + { 0, 0 }, + { 1, FORMAT_MOVE_X }, + { 2, FORMAT_ADJUST_PALETTE }, + { 3, 3 }, + { 4, 4 }, + { 5, FORMAT_NEWLINE }, + { 6, FORMAT_NEWLINE_SMALLER }, + { 7, FORMAT_TINYFONT }, + { 8, FORMAT_BIGFONT }, + { 9, FORMAT_MEDIUMFONT }, + { 10, FORMAT_SMALLFONT }, + { 11, FORMAT_OUTLINE }, + { 12, FORMAT_OUTLINE_OFF }, + { 13, FORMAT_WINDOW_COLOUR_1 }, + { 14, FORMAT_WINDOW_COLOUR_2 }, + { 15, FORMAT_WINDOW_COLOUR_3 }, + { 16, 16 }, + { 17, FORMAT_NEWLINE_X_Y }, + { 18, 18 }, + { 19, 19 }, + { 20, 20 }, + { 21, 21 }, + { 22, 22 }, + { 23, FORMAT_INLINE_SPRITE }, + { 24, 24 }, + { 25, 25 }, + { 26, 26 }, + { 27, 27 }, + { 28, 28 }, + { 29, 29 }, + { 30, 30 }, + { 31, 31 }, + { 32, 32 }, + { 33, 33 }, + { 34, 34 }, + { 35, 35 }, + { 36, 36 }, + { 37, 37 }, + { 38, 38 }, + { 39, 39 }, + { 40, 40 }, + { 41, 41 }, + { 42, 42 }, + { 43, 43 }, + { 44, 44 }, + { 45, 45 }, + { 46, 46 }, + { 47, 47 }, + { 48, 48 }, + { 49, 49 }, + { 50, 50 }, + { 51, 51 }, + { 52, 52 }, + { 53, 53 }, + { 54, 54 }, + { 55, 55 }, + { 56, 56 }, + { 57, 57 }, + { 58, 58 }, + { 59, 59 }, + { 60, 60 }, + { 61, 61 }, + { 62, 62 }, + { 63, 63 }, + { 64, 64 }, + { 65, 65 }, + { 66, 66 }, + { 67, 67 }, + { 68, 68 }, + { 69, 69 }, + { 70, 70 }, + { 71, 71 }, + { 72, 72 }, + { 73, 73 }, + { 74, 74 }, + { 75, 75 }, + { 76, 76 }, + { 77, 77 }, + { 78, 78 }, + { 79, 79 }, + { 80, 80 }, + { 81, 81 }, + { 82, 82 }, + { 83, 83 }, + { 84, 84 }, + { 85, 85 }, + { 86, 86 }, + { 87, 87 }, + { 88, 88 }, + { 89, 89 }, + { 90, 90 }, + { 91, 91 }, + { 92, 92 }, + { 93, 93 }, + { 94, 94 }, + { 95, 95 }, + { 96, 96 }, + { 97, 97 }, + { 98, 98 }, + { 99, 99 }, + { 100, 100 }, + { 101, 101 }, + { 102, 102 }, + { 103, 103 }, + { 104, 104 }, + { 105, 105 }, + { 106, 106 }, + { 107, 107 }, + { 108, 108 }, + { 109, 109 }, + { 110, 110 }, + { 111, 111 }, + { 112, 112 }, + { 113, 113 }, + { 114, 114 }, + { 115, 115 }, + { 116, 116 }, + { 117, 117 }, + { 118, 118 }, + { 119, 119 }, + { 120, 120 }, + { 121, 121 }, + { 122, 122 }, + { 123, FORMAT_COMMA32 }, + { 124, FORMAT_INT32 }, + { 125, FORMAT_COMMA2DP32 }, + { 126, FORMAT_COMMA16 }, + { 127, FORMAT_UINT16 }, + { 128, FORMAT_CURRENCY2DP }, + { 129, FORMAT_CURRENCY }, + { 130, FORMAT_STRINGID }, + { 131, FORMAT_STRINGID2 }, + { 132, FORMAT_STRING }, + { 133, FORMAT_MONTHYEAR }, + { 134, FORMAT_MONTH }, + { 135, FORMAT_VELOCITY }, + { 136, FORMAT_POP16 }, + { 137, FORMAT_PUSH16 }, + { 138, FORMAT_DURATION }, + { 139, FORMAT_REALTIME }, + { 140, FORMAT_LENGTH }, + { 141, FORMAT_SPRITE }, + { 142, FORMAT_BLACK }, + { 143, FORMAT_GREY }, + { 144, FORMAT_WHITE }, + { 145, FORMAT_RED }, + { 146, FORMAT_GREEN }, + { 147, FORMAT_YELLOW }, + { 148, FORMAT_TOPAZ }, + { 149, FORMAT_CELADON }, + { 150, FORMAT_BABYBLUE }, + { 151, FORMAT_PALELAVENDER }, + { 152, FORMAT_PALEGOLD }, + { 153, FORMAT_LIGHTPINK }, + { 154, FORMAT_PEARLAQUA }, + { 155, FORMAT_PALESILVER }, + { 156, 156 }, + { 157, 157 }, + { 158, 158 }, + { 159, FORMAT_AMINUSCULE }, + { 160, FORMAT_UP }, + { 161, FORMAT_SYMBOL_i }, + { 162, 162 }, + { 163, FORMAT_POUND }, + { 164, 164 }, + { 165, FORMAT_YEN }, + { 166, 166 }, + { 167, 167 }, + { 168, 168 }, + { 169, FORMAT_COPYRIGHT }, + { 170, FORMAT_DOWN }, + { 171, FORMAT_LEFTGUILLEMET }, + { 172, FORMAT_TICK }, + { 173, FORMAT_CROSS }, + { 174, 174 }, + { 175, FORMAT_RIGHT }, + { 176, FORMAT_DEGREE }, + { 177, FORMAT_SYMBOL_RAILWAY }, + { 178, FORMAT_SQUARED }, + { 179, 179 }, + { 180, FORMAT_OPENQUOTES }, + { 181, FORMAT_EURO }, + { 182, FORMAT_SYMBOL_ROAD }, + { 183, FORMAT_SYMBOL_FLAG }, + { 184, FORMAT_APPROX }, + { 185, FORMAT_POWERNEGATIVEONE }, + { 186, FORMAT_BULLET }, + { 187, FORMAT_RIGHTGUILLEMET }, + { 188, FORMAT_SMALLUP }, + { 189, FORMAT_SMALLDOWN }, + { 190, FORMAT_LEFT }, + { 191, FORMAT_INVERTEDQUESTION }, + { 192, 192 }, + { 193, 193 }, + { 194, 194 }, + { 195, 195 }, + { 196, 196 }, + { 197, 197 }, + { 198, 198 }, + { 199, 199 }, + { 200, 200 }, + { 201, 201 }, + { 202, 202 }, + { 203, 203 }, + { 204, 204 }, + { 205, 205 }, + { 206, 206 }, + { 207, 207 }, + { 208, 208 }, + { 209, 209 }, + { 210, 210 }, + { 211, 211 }, + { 212, 212 }, + { 213, 213 }, + { 214, 214 }, + { 215, 215 }, + { 216, 216 }, + { 217, 217 }, + { 218, 218 }, + { 219, 219 }, + { 220, 220 }, + { 221, 221 }, + { 222, 222 }, + { 223, 223 }, + { 224, 224 }, + { 225, 225 }, + { 226, 226 }, + { 227, 227 }, + { 228, 228 }, + { 229, 229 }, + { 230, 230 }, + { 231, 231 }, + { 232, 232 }, + { 233, 233 }, + { 234, 234 }, + { 235, 235 }, + { 236, 236 }, + { 237, 237 }, + { 238, 238 }, + { 239, 239 }, + { 240, 240 }, + { 241, 241 }, + { 242, 242 }, + { 243, 243 }, + { 244, 244 }, + { 245, 245 }, + { 246, 246 }, + { 247, 247 }, + { 248, 248 }, + { 249, 249 }, + { 250, 250 }, + { 251, 251 }, + { 252, 252 }, + { 253, 253 }, + { 254, 254 }, + { 255, 255 } +}; + +static const encoding_convert_entry GB2312ToUnicodeTable[7445] = { + { 8481, 12288 }, + { 8482, 12289 }, + { 8483, 12290 }, + { 8484, 12539 }, + { 8485, 713 }, + { 8486, 711 }, + { 8487, 168 }, + { 8488, 12291 }, + { 8489, 12293 }, + { 8490, 8213 }, + { 8491, 65374 }, + { 8492, 8741 }, + { 8493, 8230 }, + { 8494, 8216 }, + { 8495, 8217 }, + { 8496, 8220 }, + { 8497, 8221 }, + { 8498, 12308 }, + { 8499, 12309 }, + { 8500, 12296 }, + { 8501, 12297 }, + { 8502, 12298 }, + { 8503, 12299 }, + { 8504, 12300 }, + { 8505, 12301 }, + { 8506, 12302 }, + { 8507, 12303 }, + { 8508, 12310 }, + { 8509, 12311 }, + { 8510, 12304 }, + { 8511, 12305 }, + { 8512, 177 }, + { 8513, 215 }, + { 8514, 247 }, + { 8515, 8758 }, + { 8516, 8743 }, + { 8517, 8744 }, + { 8518, 8721 }, + { 8519, 8719 }, + { 8520, 8746 }, + { 8521, 8745 }, + { 8522, 8712 }, + { 8523, 8759 }, + { 8524, 8730 }, + { 8525, 8869 }, + { 8526, 8741 }, + { 8527, 8736 }, + { 8528, 8978 }, + { 8529, 8857 }, + { 8530, 8747 }, + { 8531, 8750 }, + { 8532, 8801 }, + { 8533, 8780 }, + { 8534, 8776 }, + { 8535, 8765 }, + { 8536, 8733 }, + { 8537, 8800 }, + { 8538, 8814 }, + { 8539, 8815 }, + { 8540, 8804 }, + { 8541, 8805 }, + { 8542, 8734 }, + { 8543, 8757 }, + { 8544, 8756 }, + { 8545, 9794 }, + { 8546, 9792 }, + { 8547, 176 }, + { 8548, 8242 }, + { 8549, 8243 }, + { 8550, 8451 }, + { 8551, 65284 }, + { 8552, 164 }, + { 8553, 65504 }, + { 8554, 65505 }, + { 8555, 8240 }, + { 8556, 167 }, + { 8557, 8470 }, + { 8558, 9734 }, + { 8559, 9733 }, + { 8560, 9675 }, + { 8561, 9679 }, + { 8562, 9678 }, + { 8563, 9671 }, + { 8564, 9670 }, + { 8565, 9633 }, + { 8566, 9632 }, + { 8567, 9651 }, + { 8568, 9650 }, + { 8569, 8251 }, + { 8570, 8594 }, + { 8571, 8592 }, + { 8572, 8593 }, + { 8573, 8595 }, + { 8574, 12307 }, + { 8753, 9352 }, + { 8754, 9353 }, + { 8755, 9354 }, + { 8756, 9355 }, + { 8757, 9356 }, + { 8758, 9357 }, + { 8759, 9358 }, + { 8760, 9359 }, + { 8761, 9360 }, + { 8762, 9361 }, + { 8763, 9362 }, + { 8764, 9363 }, + { 8765, 9364 }, + { 8766, 9365 }, + { 8767, 9366 }, + { 8768, 9367 }, + { 8769, 9368 }, + { 8770, 9369 }, + { 8771, 9370 }, + { 8772, 9371 }, + { 8773, 9332 }, + { 8774, 9333 }, + { 8775, 9334 }, + { 8776, 9335 }, + { 8777, 9336 }, + { 8778, 9337 }, + { 8779, 9338 }, + { 8780, 9339 }, + { 8781, 9340 }, + { 8782, 9341 }, + { 8783, 9342 }, + { 8784, 9343 }, + { 8785, 9344 }, + { 8786, 9345 }, + { 8787, 9346 }, + { 8788, 9347 }, + { 8789, 9348 }, + { 8790, 9349 }, + { 8791, 9350 }, + { 8792, 9351 }, + { 8793, 9312 }, + { 8794, 9313 }, + { 8795, 9314 }, + { 8796, 9315 }, + { 8797, 9316 }, + { 8798, 9317 }, + { 8799, 9318 }, + { 8800, 9319 }, + { 8801, 9320 }, + { 8802, 9321 }, + { 8805, 12832 }, + { 8806, 12833 }, + { 8807, 12834 }, + { 8808, 12835 }, + { 8809, 12836 }, + { 8810, 12837 }, + { 8811, 12838 }, + { 8812, 12839 }, + { 8813, 12840 }, + { 8814, 12841 }, + { 8817, 8544 }, + { 8818, 8545 }, + { 8819, 8546 }, + { 8820, 8547 }, + { 8821, 8548 }, + { 8822, 8549 }, + { 8823, 8550 }, + { 8824, 8551 }, + { 8825, 8552 }, + { 8826, 8553 }, + { 8827, 8554 }, + { 8828, 8555 }, + { 8993, 65281 }, + { 8994, 65282 }, + { 8995, 65283 }, + { 8996, 65509 }, + { 8997, 65285 }, + { 8998, 65286 }, + { 8999, 65287 }, + { 9000, 65288 }, + { 9001, 65289 }, + { 9002, 65290 }, + { 9003, 65291 }, + { 9004, 65292 }, + { 9005, 65293 }, + { 9006, 65294 }, + { 9007, 65295 }, + { 9008, 65296 }, + { 9009, 65297 }, + { 9010, 65298 }, + { 9011, 65299 }, + { 9012, 65300 }, + { 9013, 65301 }, + { 9014, 65302 }, + { 9015, 65303 }, + { 9016, 65304 }, + { 9017, 65305 }, + { 9018, 65306 }, + { 9019, 65307 }, + { 9020, 65308 }, + { 9021, 65309 }, + { 9022, 65310 }, + { 9023, 65311 }, + { 9024, 65312 }, + { 9025, 65313 }, + { 9026, 65314 }, + { 9027, 65315 }, + { 9028, 65316 }, + { 9029, 65317 }, + { 9030, 65318 }, + { 9031, 65319 }, + { 9032, 65320 }, + { 9033, 65321 }, + { 9034, 65322 }, + { 9035, 65323 }, + { 9036, 65324 }, + { 9037, 65325 }, + { 9038, 65326 }, + { 9039, 65327 }, + { 9040, 65328 }, + { 9041, 65329 }, + { 9042, 65330 }, + { 9043, 65331 }, + { 9044, 65332 }, + { 9045, 65333 }, + { 9046, 65334 }, + { 9047, 65335 }, + { 9048, 65336 }, + { 9049, 65337 }, + { 9050, 65338 }, + { 9051, 65339 }, + { 9052, 65340 }, + { 9053, 65341 }, + { 9054, 65342 }, + { 9055, 65343 }, + { 9056, 65344 }, + { 9057, 65345 }, + { 9058, 65346 }, + { 9059, 65347 }, + { 9060, 65348 }, + { 9061, 65349 }, + { 9062, 65350 }, + { 9063, 65351 }, + { 9064, 65352 }, + { 9065, 65353 }, + { 9066, 65354 }, + { 9067, 65355 }, + { 9068, 65356 }, + { 9069, 65357 }, + { 9070, 65358 }, + { 9071, 65359 }, + { 9072, 65360 }, + { 9073, 65361 }, + { 9074, 65362 }, + { 9075, 65363 }, + { 9076, 65364 }, + { 9077, 65365 }, + { 9078, 65366 }, + { 9079, 65367 }, + { 9080, 65368 }, + { 9081, 65369 }, + { 9082, 65370 }, + { 9083, 65371 }, + { 9084, 65372 }, + { 9085, 65373 }, + { 9086, 65507 }, + { 9249, 12353 }, + { 9250, 12354 }, + { 9251, 12355 }, + { 9252, 12356 }, + { 9253, 12357 }, + { 9254, 12358 }, + { 9255, 12359 }, + { 9256, 12360 }, + { 9257, 12361 }, + { 9258, 12362 }, + { 9259, 12363 }, + { 9260, 12364 }, + { 9261, 12365 }, + { 9262, 12366 }, + { 9263, 12367 }, + { 9264, 12368 }, + { 9265, 12369 }, + { 9266, 12370 }, + { 9267, 12371 }, + { 9268, 12372 }, + { 9269, 12373 }, + { 9270, 12374 }, + { 9271, 12375 }, + { 9272, 12376 }, + { 9273, 12377 }, + { 9274, 12378 }, + { 9275, 12379 }, + { 9276, 12380 }, + { 9277, 12381 }, + { 9278, 12382 }, + { 9279, 12383 }, + { 9280, 12384 }, + { 9281, 12385 }, + { 9282, 12386 }, + { 9283, 12387 }, + { 9284, 12388 }, + { 9285, 12389 }, + { 9286, 12390 }, + { 9287, 12391 }, + { 9288, 12392 }, + { 9289, 12393 }, + { 9290, 12394 }, + { 9291, 12395 }, + { 9292, 12396 }, + { 9293, 12397 }, + { 9294, 12398 }, + { 9295, 12399 }, + { 9296, 12400 }, + { 9297, 12401 }, + { 9298, 12402 }, + { 9299, 12403 }, + { 9300, 12404 }, + { 9301, 12405 }, + { 9302, 12406 }, + { 9303, 12407 }, + { 9304, 12408 }, + { 9305, 12409 }, + { 9306, 12410 }, + { 9307, 12411 }, + { 9308, 12412 }, + { 9309, 12413 }, + { 9310, 12414 }, + { 9311, 12415 }, + { 9312, 12416 }, + { 9313, 12417 }, + { 9314, 12418 }, + { 9315, 12419 }, + { 9316, 12420 }, + { 9317, 12421 }, + { 9318, 12422 }, + { 9319, 12423 }, + { 9320, 12424 }, + { 9321, 12425 }, + { 9322, 12426 }, + { 9323, 12427 }, + { 9324, 12428 }, + { 9325, 12429 }, + { 9326, 12430 }, + { 9327, 12431 }, + { 9328, 12432 }, + { 9329, 12433 }, + { 9330, 12434 }, + { 9331, 12435 }, + { 9505, 12449 }, + { 9506, 12450 }, + { 9507, 12451 }, + { 9508, 12452 }, + { 9509, 12453 }, + { 9510, 12454 }, + { 9511, 12455 }, + { 9512, 12456 }, + { 9513, 12457 }, + { 9514, 12458 }, + { 9515, 12459 }, + { 9516, 12460 }, + { 9517, 12461 }, + { 9518, 12462 }, + { 9519, 12463 }, + { 9520, 12464 }, + { 9521, 12465 }, + { 9522, 12466 }, + { 9523, 12467 }, + { 9524, 12468 }, + { 9525, 12469 }, + { 9526, 12470 }, + { 9527, 12471 }, + { 9528, 12472 }, + { 9529, 12473 }, + { 9530, 12474 }, + { 9531, 12475 }, + { 9532, 12476 }, + { 9533, 12477 }, + { 9534, 12478 }, + { 9535, 12479 }, + { 9536, 12480 }, + { 9537, 12481 }, + { 9538, 12482 }, + { 9539, 12483 }, + { 9540, 12484 }, + { 9541, 12485 }, + { 9542, 12486 }, + { 9543, 12487 }, + { 9544, 12488 }, + { 9545, 12489 }, + { 9546, 12490 }, + { 9547, 12491 }, + { 9548, 12492 }, + { 9549, 12493 }, + { 9550, 12494 }, + { 9551, 12495 }, + { 9552, 12496 }, + { 9553, 12497 }, + { 9554, 12498 }, + { 9555, 12499 }, + { 9556, 12500 }, + { 9557, 12501 }, + { 9558, 12502 }, + { 9559, 12503 }, + { 9560, 12504 }, + { 9561, 12505 }, + { 9562, 12506 }, + { 9563, 12507 }, + { 9564, 12508 }, + { 9565, 12509 }, + { 9566, 12510 }, + { 9567, 12511 }, + { 9568, 12512 }, + { 9569, 12513 }, + { 9570, 12514 }, + { 9571, 12515 }, + { 9572, 12516 }, + { 9573, 12517 }, + { 9574, 12518 }, + { 9575, 12519 }, + { 9576, 12520 }, + { 9577, 12521 }, + { 9578, 12522 }, + { 9579, 12523 }, + { 9580, 12524 }, + { 9581, 12525 }, + { 9582, 12526 }, + { 9583, 12527 }, + { 9584, 12528 }, + { 9585, 12529 }, + { 9586, 12530 }, + { 9587, 12531 }, + { 9588, 12532 }, + { 9589, 12533 }, + { 9590, 12534 }, + { 9761, 913 }, + { 9762, 914 }, + { 9763, 915 }, + { 9764, 916 }, + { 9765, 917 }, + { 9766, 918 }, + { 9767, 919 }, + { 9768, 920 }, + { 9769, 921 }, + { 9770, 922 }, + { 9771, 923 }, + { 9772, 924 }, + { 9773, 925 }, + { 9774, 926 }, + { 9775, 927 }, + { 9776, 928 }, + { 9777, 929 }, + { 9778, 931 }, + { 9779, 932 }, + { 9780, 933 }, + { 9781, 934 }, + { 9782, 935 }, + { 9783, 936 }, + { 9784, 937 }, + { 9793, 945 }, + { 9794, 946 }, + { 9795, 947 }, + { 9796, 948 }, + { 9797, 949 }, + { 9798, 950 }, + { 9799, 951 }, + { 9800, 952 }, + { 9801, 953 }, + { 9802, 954 }, + { 9803, 955 }, + { 9804, 956 }, + { 9805, 957 }, + { 9806, 958 }, + { 9807, 959 }, + { 9808, 960 }, + { 9809, 961 }, + { 9810, 963 }, + { 9811, 964 }, + { 9812, 965 }, + { 9813, 966 }, + { 9814, 967 }, + { 9815, 968 }, + { 9816, 969 }, + { 10017, 1040 }, + { 10018, 1041 }, + { 10019, 1042 }, + { 10020, 1043 }, + { 10021, 1044 }, + { 10022, 1045 }, + { 10023, 1025 }, + { 10024, 1046 }, + { 10025, 1047 }, + { 10026, 1048 }, + { 10027, 1049 }, + { 10028, 1050 }, + { 10029, 1051 }, + { 10030, 1052 }, + { 10031, 1053 }, + { 10032, 1054 }, + { 10033, 1055 }, + { 10034, 1056 }, + { 10035, 1057 }, + { 10036, 1058 }, + { 10037, 1059 }, + { 10038, 1060 }, + { 10039, 1061 }, + { 10040, 1062 }, + { 10041, 1063 }, + { 10042, 1064 }, + { 10043, 1065 }, + { 10044, 1066 }, + { 10045, 1067 }, + { 10046, 1068 }, + { 10047, 1069 }, + { 10048, 1070 }, + { 10049, 1071 }, + { 10065, 1072 }, + { 10066, 1073 }, + { 10067, 1074 }, + { 10068, 1075 }, + { 10069, 1076 }, + { 10070, 1077 }, + { 10071, 1105 }, + { 10072, 1078 }, + { 10073, 1079 }, + { 10074, 1080 }, + { 10075, 1081 }, + { 10076, 1082 }, + { 10077, 1083 }, + { 10078, 1084 }, + { 10079, 1085 }, + { 10080, 1086 }, + { 10081, 1087 }, + { 10082, 1088 }, + { 10083, 1089 }, + { 10084, 1090 }, + { 10085, 1091 }, + { 10086, 1092 }, + { 10087, 1093 }, + { 10088, 1094 }, + { 10089, 1095 }, + { 10090, 1096 }, + { 10091, 1097 }, + { 10092, 1098 }, + { 10093, 1099 }, + { 10094, 1100 }, + { 10095, 1101 }, + { 10096, 1102 }, + { 10097, 1103 }, + { 10273, 257 }, + { 10274, 225 }, + { 10275, 462 }, + { 10276, 224 }, + { 10277, 275 }, + { 10278, 233 }, + { 10279, 283 }, + { 10280, 232 }, + { 10281, 299 }, + { 10282, 237 }, + { 10283, 464 }, + { 10284, 236 }, + { 10285, 333 }, + { 10286, 243 }, + { 10287, 466 }, + { 10288, 242 }, + { 10289, 363 }, + { 10290, 250 }, + { 10291, 468 }, + { 10292, 249 }, + { 10293, 470 }, + { 10294, 472 }, + { 10295, 474 }, + { 10296, 476 }, + { 10297, 252 }, + { 10298, 234 }, + { 10309, 12549 }, + { 10310, 12550 }, + { 10311, 12551 }, + { 10312, 12552 }, + { 10313, 12553 }, + { 10314, 12554 }, + { 10315, 12555 }, + { 10316, 12556 }, + { 10317, 12557 }, + { 10318, 12558 }, + { 10319, 12559 }, + { 10320, 12560 }, + { 10321, 12561 }, + { 10322, 12562 }, + { 10323, 12563 }, + { 10324, 12564 }, + { 10325, 12565 }, + { 10326, 12566 }, + { 10327, 12567 }, + { 10328, 12568 }, + { 10329, 12569 }, + { 10330, 12570 }, + { 10331, 12571 }, + { 10332, 12572 }, + { 10333, 12573 }, + { 10334, 12574 }, + { 10335, 12575 }, + { 10336, 12576 }, + { 10337, 12577 }, + { 10338, 12578 }, + { 10339, 12579 }, + { 10340, 12580 }, + { 10341, 12581 }, + { 10342, 12582 }, + { 10343, 12583 }, + { 10344, 12584 }, + { 10345, 12585 }, + { 10532, 9472 }, + { 10533, 9473 }, + { 10534, 9474 }, + { 10535, 9475 }, + { 10536, 9476 }, + { 10537, 9477 }, + { 10538, 9478 }, + { 10539, 9479 }, + { 10540, 9480 }, + { 10541, 9481 }, + { 10542, 9482 }, + { 10543, 9483 }, + { 10544, 9484 }, + { 10545, 9485 }, + { 10546, 9486 }, + { 10547, 9487 }, + { 10548, 9488 }, + { 10549, 9489 }, + { 10550, 9490 }, + { 10551, 9491 }, + { 10552, 9492 }, + { 10553, 9493 }, + { 10554, 9494 }, + { 10555, 9495 }, + { 10556, 9496 }, + { 10557, 9497 }, + { 10558, 9498 }, + { 10559, 9499 }, + { 10560, 9500 }, + { 10561, 9501 }, + { 10562, 9502 }, + { 10563, 9503 }, + { 10564, 9504 }, + { 10565, 9505 }, + { 10566, 9506 }, + { 10567, 9507 }, + { 10568, 9508 }, + { 10569, 9509 }, + { 10570, 9510 }, + { 10571, 9511 }, + { 10572, 9512 }, + { 10573, 9513 }, + { 10574, 9514 }, + { 10575, 9515 }, + { 10576, 9516 }, + { 10577, 9517 }, + { 10578, 9518 }, + { 10579, 9519 }, + { 10580, 9520 }, + { 10581, 9521 }, + { 10582, 9522 }, + { 10583, 9523 }, + { 10584, 9524 }, + { 10585, 9525 }, + { 10586, 9526 }, + { 10587, 9527 }, + { 10588, 9528 }, + { 10589, 9529 }, + { 10590, 9530 }, + { 10591, 9531 }, + { 10592, 9532 }, + { 10593, 9533 }, + { 10594, 9534 }, + { 10595, 9535 }, + { 10596, 9536 }, + { 10597, 9537 }, + { 10598, 9538 }, + { 10599, 9539 }, + { 10600, 9540 }, + { 10601, 9541 }, + { 10602, 9542 }, + { 10603, 9543 }, + { 10604, 9544 }, + { 10605, 9545 }, + { 10606, 9546 }, + { 10607, 9547 }, + { 12321, 21834 }, + { 12322, 38463 }, + { 12323, 22467 }, + { 12324, 25384 }, + { 12325, 21710 }, + { 12326, 21769 }, + { 12327, 21696 }, + { 12328, 30353 }, + { 12329, 30284 }, + { 12330, 34108 }, + { 12331, 30702 }, + { 12332, 33406 }, + { 12333, 30861 }, + { 12334, 29233 }, + { 12335, 38552 }, + { 12336, 38797 }, + { 12337, 27688 }, + { 12338, 23433 }, + { 12339, 20474 }, + { 12340, 25353 }, + { 12341, 26263 }, + { 12342, 23736 }, + { 12343, 33018 }, + { 12344, 26696 }, + { 12345, 32942 }, + { 12346, 26114 }, + { 12347, 30414 }, + { 12348, 20985 }, + { 12349, 25942 }, + { 12350, 29100 }, + { 12351, 32753 }, + { 12352, 34948 }, + { 12353, 20658 }, + { 12354, 22885 }, + { 12355, 25034 }, + { 12356, 28595 }, + { 12357, 33453 }, + { 12358, 25420 }, + { 12359, 25170 }, + { 12360, 21485 }, + { 12361, 21543 }, + { 12362, 31494 }, + { 12363, 20843 }, + { 12364, 30116 }, + { 12365, 24052 }, + { 12366, 25300 }, + { 12367, 36299 }, + { 12368, 38774 }, + { 12369, 25226 }, + { 12370, 32793 }, + { 12371, 22365 }, + { 12372, 38712 }, + { 12373, 32610 }, + { 12374, 29240 }, + { 12375, 30333 }, + { 12376, 26575 }, + { 12377, 30334 }, + { 12378, 25670 }, + { 12379, 20336 }, + { 12380, 36133 }, + { 12381, 25308 }, + { 12382, 31255 }, + { 12383, 26001 }, + { 12384, 29677 }, + { 12385, 25644 }, + { 12386, 25203 }, + { 12387, 33324 }, + { 12388, 39041 }, + { 12389, 26495 }, + { 12390, 29256 }, + { 12391, 25198 }, + { 12392, 25292 }, + { 12393, 20276 }, + { 12394, 29923 }, + { 12395, 21322 }, + { 12396, 21150 }, + { 12397, 32458 }, + { 12398, 37030 }, + { 12399, 24110 }, + { 12400, 26758 }, + { 12401, 27036 }, + { 12402, 33152 }, + { 12403, 32465 }, + { 12404, 26834 }, + { 12405, 30917 }, + { 12406, 34444 }, + { 12407, 38225 }, + { 12408, 20621 }, + { 12409, 35876 }, + { 12410, 33502 }, + { 12411, 32990 }, + { 12412, 21253 }, + { 12413, 35090 }, + { 12414, 21093 }, + { 12577, 34180 }, + { 12578, 38649 }, + { 12579, 20445 }, + { 12580, 22561 }, + { 12581, 39281 }, + { 12582, 23453 }, + { 12583, 25265 }, + { 12584, 25253 }, + { 12585, 26292 }, + { 12586, 35961 }, + { 12587, 40077 }, + { 12588, 29190 }, + { 12589, 26479 }, + { 12590, 30865 }, + { 12591, 24754 }, + { 12592, 21329 }, + { 12593, 21271 }, + { 12594, 36744 }, + { 12595, 32972 }, + { 12596, 36125 }, + { 12597, 38049 }, + { 12598, 20493 }, + { 12599, 29384 }, + { 12600, 22791 }, + { 12601, 24811 }, + { 12602, 28953 }, + { 12603, 34987 }, + { 12604, 22868 }, + { 12605, 33519 }, + { 12606, 26412 }, + { 12607, 31528 }, + { 12608, 23849 }, + { 12609, 32503 }, + { 12610, 29997 }, + { 12611, 27893 }, + { 12612, 36454 }, + { 12613, 36856 }, + { 12614, 36924 }, + { 12615, 40763 }, + { 12616, 27604 }, + { 12617, 37145 }, + { 12618, 31508 }, + { 12619, 24444 }, + { 12620, 30887 }, + { 12621, 34006 }, + { 12622, 34109 }, + { 12623, 27605 }, + { 12624, 27609 }, + { 12625, 27606 }, + { 12626, 24065 }, + { 12627, 24199 }, + { 12628, 30201 }, + { 12629, 38381 }, + { 12630, 25949 }, + { 12631, 24330 }, + { 12632, 24517 }, + { 12633, 36767 }, + { 12634, 22721 }, + { 12635, 33218 }, + { 12636, 36991 }, + { 12637, 38491 }, + { 12638, 38829 }, + { 12639, 36793 }, + { 12640, 32534 }, + { 12641, 36140 }, + { 12642, 25153 }, + { 12643, 20415 }, + { 12644, 21464 }, + { 12645, 21342 }, + { 12646, 36776 }, + { 12647, 36777 }, + { 12648, 36779 }, + { 12649, 36941 }, + { 12650, 26631 }, + { 12651, 24426 }, + { 12652, 33176 }, + { 12653, 34920 }, + { 12654, 40150 }, + { 12655, 24971 }, + { 12656, 21035 }, + { 12657, 30250 }, + { 12658, 24428 }, + { 12659, 25996 }, + { 12660, 28626 }, + { 12661, 28392 }, + { 12662, 23486 }, + { 12663, 25672 }, + { 12664, 20853 }, + { 12665, 20912 }, + { 12666, 26564 }, + { 12667, 19993 }, + { 12668, 31177 }, + { 12669, 39292 }, + { 12670, 28851 }, + { 12833, 30149 }, + { 12834, 24182 }, + { 12835, 29627 }, + { 12836, 33760 }, + { 12837, 25773 }, + { 12838, 25320 }, + { 12839, 38069 }, + { 12840, 27874 }, + { 12841, 21338 }, + { 12842, 21187 }, + { 12843, 25615 }, + { 12844, 38082 }, + { 12845, 31636 }, + { 12846, 20271 }, + { 12847, 24091 }, + { 12848, 33334 }, + { 12849, 33046 }, + { 12850, 33162 }, + { 12851, 28196 }, + { 12852, 27850 }, + { 12853, 39539 }, + { 12854, 25429 }, + { 12855, 21340 }, + { 12856, 21754 }, + { 12857, 34917 }, + { 12858, 22496 }, + { 12859, 19981 }, + { 12860, 24067 }, + { 12861, 27493 }, + { 12862, 31807 }, + { 12863, 37096 }, + { 12864, 24598 }, + { 12865, 25830 }, + { 12866, 29468 }, + { 12867, 35009 }, + { 12868, 26448 }, + { 12869, 25165 }, + { 12870, 36130 }, + { 12871, 30572 }, + { 12872, 36393 }, + { 12873, 37319 }, + { 12874, 24425 }, + { 12875, 33756 }, + { 12876, 34081 }, + { 12877, 39184 }, + { 12878, 21442 }, + { 12879, 34453 }, + { 12880, 27531 }, + { 12881, 24813 }, + { 12882, 24808 }, + { 12883, 28799 }, + { 12884, 33485 }, + { 12885, 33329 }, + { 12886, 20179 }, + { 12887, 27815 }, + { 12888, 34255 }, + { 12889, 25805 }, + { 12890, 31961 }, + { 12891, 27133 }, + { 12892, 26361 }, + { 12893, 33609 }, + { 12894, 21397 }, + { 12895, 31574 }, + { 12896, 20391 }, + { 12897, 20876 }, + { 12898, 27979 }, + { 12899, 23618 }, + { 12900, 36461 }, + { 12901, 25554 }, + { 12902, 21449 }, + { 12903, 33580 }, + { 12904, 33590 }, + { 12905, 26597 }, + { 12906, 30900 }, + { 12907, 25661 }, + { 12908, 23519 }, + { 12909, 23700 }, + { 12910, 24046 }, + { 12911, 35815 }, + { 12912, 25286 }, + { 12913, 26612 }, + { 12914, 35962 }, + { 12915, 25600 }, + { 12916, 25530 }, + { 12917, 34633 }, + { 12918, 39307 }, + { 12919, 35863 }, + { 12920, 32544 }, + { 12921, 38130 }, + { 12922, 20135 }, + { 12923, 38416 }, + { 12924, 39076 }, + { 12925, 26124 }, + { 12926, 29462 }, + { 13089, 22330 }, + { 13090, 23581 }, + { 13091, 24120 }, + { 13092, 38271 }, + { 13093, 20607 }, + { 13094, 32928 }, + { 13095, 21378 }, + { 13096, 25950 }, + { 13097, 30021 }, + { 13098, 21809 }, + { 13099, 20513 }, + { 13100, 36229 }, + { 13101, 25220 }, + { 13102, 38046 }, + { 13103, 26397 }, + { 13104, 22066 }, + { 13105, 28526 }, + { 13106, 24034 }, + { 13107, 21557 }, + { 13108, 28818 }, + { 13109, 36710 }, + { 13110, 25199 }, + { 13111, 25764 }, + { 13112, 25507 }, + { 13113, 24443 }, + { 13114, 28552 }, + { 13115, 37108 }, + { 13116, 33251 }, + { 13117, 36784 }, + { 13118, 23576 }, + { 13119, 26216 }, + { 13120, 24561 }, + { 13121, 27785 }, + { 13122, 38472 }, + { 13123, 36225 }, + { 13124, 34924 }, + { 13125, 25745 }, + { 13126, 31216 }, + { 13127, 22478 }, + { 13128, 27225 }, + { 13129, 25104 }, + { 13130, 21576 }, + { 13131, 20056 }, + { 13132, 31243 }, + { 13133, 24809 }, + { 13134, 28548 }, + { 13135, 35802 }, + { 13136, 25215 }, + { 13137, 36894 }, + { 13138, 39563 }, + { 13139, 31204 }, + { 13140, 21507 }, + { 13141, 30196 }, + { 13142, 25345 }, + { 13143, 21273 }, + { 13144, 27744 }, + { 13145, 36831 }, + { 13146, 24347 }, + { 13147, 39536 }, + { 13148, 32827 }, + { 13149, 40831 }, + { 13150, 20360 }, + { 13151, 23610 }, + { 13152, 36196 }, + { 13153, 32709 }, + { 13154, 26021 }, + { 13155, 28861 }, + { 13156, 20805 }, + { 13157, 20914 }, + { 13158, 34411 }, + { 13159, 23815 }, + { 13160, 23456 }, + { 13161, 25277 }, + { 13162, 37228 }, + { 13163, 30068 }, + { 13164, 36364 }, + { 13165, 31264 }, + { 13166, 24833 }, + { 13167, 31609 }, + { 13168, 20167 }, + { 13169, 32504 }, + { 13170, 30597 }, + { 13171, 19985 }, + { 13172, 33261 }, + { 13173, 21021 }, + { 13174, 20986 }, + { 13175, 27249 }, + { 13176, 21416 }, + { 13177, 36487 }, + { 13178, 38148 }, + { 13179, 38607 }, + { 13180, 28353 }, + { 13181, 38500 }, + { 13182, 26970 }, + { 13345, 30784 }, + { 13346, 20648 }, + { 13347, 30679 }, + { 13348, 25616 }, + { 13349, 35302 }, + { 13350, 22788 }, + { 13351, 25571 }, + { 13352, 24029 }, + { 13353, 31359 }, + { 13354, 26941 }, + { 13355, 20256 }, + { 13356, 33337 }, + { 13357, 21912 }, + { 13358, 20018 }, + { 13359, 30126 }, + { 13360, 31383 }, + { 13361, 24162 }, + { 13362, 24202 }, + { 13363, 38383 }, + { 13364, 21019 }, + { 13365, 21561 }, + { 13366, 28810 }, + { 13367, 25462 }, + { 13368, 38180 }, + { 13369, 22402 }, + { 13370, 26149 }, + { 13371, 26943 }, + { 13372, 37255 }, + { 13373, 21767 }, + { 13374, 28147 }, + { 13375, 32431 }, + { 13376, 34850 }, + { 13377, 25139 }, + { 13378, 32496 }, + { 13379, 30133 }, + { 13380, 33576 }, + { 13381, 30913 }, + { 13382, 38604 }, + { 13383, 36766 }, + { 13384, 24904 }, + { 13385, 29943 }, + { 13386, 35789 }, + { 13387, 27492 }, + { 13388, 21050 }, + { 13389, 36176 }, + { 13390, 27425 }, + { 13391, 32874 }, + { 13392, 33905 }, + { 13393, 22257 }, + { 13394, 21254 }, + { 13395, 20174 }, + { 13396, 19995 }, + { 13397, 20945 }, + { 13398, 31895 }, + { 13399, 37259 }, + { 13400, 31751 }, + { 13401, 20419 }, + { 13402, 36479 }, + { 13403, 31713 }, + { 13404, 31388 }, + { 13405, 25703 }, + { 13406, 23828 }, + { 13407, 20652 }, + { 13408, 33030 }, + { 13409, 30209 }, + { 13410, 31929 }, + { 13411, 28140 }, + { 13412, 32736 }, + { 13413, 26449 }, + { 13414, 23384 }, + { 13415, 23544 }, + { 13416, 30923 }, + { 13417, 25774 }, + { 13418, 25619 }, + { 13419, 25514 }, + { 13420, 25387 }, + { 13421, 38169 }, + { 13422, 25645 }, + { 13423, 36798 }, + { 13424, 31572 }, + { 13425, 30249 }, + { 13426, 25171 }, + { 13427, 22823 }, + { 13428, 21574 }, + { 13429, 27513 }, + { 13430, 20643 }, + { 13431, 25140 }, + { 13432, 24102 }, + { 13433, 27526 }, + { 13434, 20195 }, + { 13435, 36151 }, + { 13436, 34955 }, + { 13437, 24453 }, + { 13438, 36910 }, + { 13601, 24608 }, + { 13602, 32829 }, + { 13603, 25285 }, + { 13604, 20025 }, + { 13605, 21333 }, + { 13606, 37112 }, + { 13607, 25528 }, + { 13608, 32966 }, + { 13609, 26086 }, + { 13610, 27694 }, + { 13611, 20294 }, + { 13612, 24814 }, + { 13613, 28129 }, + { 13614, 35806 }, + { 13615, 24377 }, + { 13616, 34507 }, + { 13617, 24403 }, + { 13618, 25377 }, + { 13619, 20826 }, + { 13620, 33633 }, + { 13621, 26723 }, + { 13622, 20992 }, + { 13623, 25443 }, + { 13624, 36424 }, + { 13625, 20498 }, + { 13626, 23707 }, + { 13627, 31095 }, + { 13628, 23548 }, + { 13629, 21040 }, + { 13630, 31291 }, + { 13631, 24764 }, + { 13632, 36947 }, + { 13633, 30423 }, + { 13634, 24503 }, + { 13635, 24471 }, + { 13636, 30340 }, + { 13637, 36460 }, + { 13638, 28783 }, + { 13639, 30331 }, + { 13640, 31561 }, + { 13641, 30634 }, + { 13642, 20979 }, + { 13643, 37011 }, + { 13644, 22564 }, + { 13645, 20302 }, + { 13646, 28404 }, + { 13647, 36842 }, + { 13648, 25932 }, + { 13649, 31515 }, + { 13650, 29380 }, + { 13651, 28068 }, + { 13652, 32735 }, + { 13653, 23265 }, + { 13654, 25269 }, + { 13655, 24213 }, + { 13656, 22320 }, + { 13657, 33922 }, + { 13658, 31532 }, + { 13659, 24093 }, + { 13660, 24351 }, + { 13661, 36882 }, + { 13662, 32532 }, + { 13663, 39072 }, + { 13664, 25474 }, + { 13665, 28359 }, + { 13666, 30872 }, + { 13667, 28857 }, + { 13668, 20856 }, + { 13669, 38747 }, + { 13670, 22443 }, + { 13671, 30005 }, + { 13672, 20291 }, + { 13673, 30008 }, + { 13674, 24215 }, + { 13675, 24806 }, + { 13676, 22880 }, + { 13677, 28096 }, + { 13678, 27583 }, + { 13679, 30857 }, + { 13680, 21500 }, + { 13681, 38613 }, + { 13682, 20939 }, + { 13683, 20993 }, + { 13684, 25481 }, + { 13685, 21514 }, + { 13686, 38035 }, + { 13687, 35843 }, + { 13688, 36300 }, + { 13689, 29241 }, + { 13690, 30879 }, + { 13691, 34678 }, + { 13692, 36845 }, + { 13693, 35853 }, + { 13694, 21472 }, + { 13857, 19969 }, + { 13858, 30447 }, + { 13859, 21486 }, + { 13860, 38025 }, + { 13861, 39030 }, + { 13862, 40718 }, + { 13863, 38189 }, + { 13864, 23450 }, + { 13865, 35746 }, + { 13866, 20002 }, + { 13867, 19996 }, + { 13868, 20908 }, + { 13869, 33891 }, + { 13870, 25026 }, + { 13871, 21160 }, + { 13872, 26635 }, + { 13873, 20375 }, + { 13874, 24683 }, + { 13875, 20923 }, + { 13876, 27934 }, + { 13877, 20828 }, + { 13878, 25238 }, + { 13879, 26007 }, + { 13880, 38497 }, + { 13881, 35910 }, + { 13882, 36887 }, + { 13883, 30168 }, + { 13884, 37117 }, + { 13885, 30563 }, + { 13886, 27602 }, + { 13887, 29322 }, + { 13888, 29420 }, + { 13889, 35835 }, + { 13890, 22581 }, + { 13891, 30585 }, + { 13892, 36172 }, + { 13893, 26460 }, + { 13894, 38208 }, + { 13895, 32922 }, + { 13896, 24230 }, + { 13897, 28193 }, + { 13898, 22930 }, + { 13899, 31471 }, + { 13900, 30701 }, + { 13901, 38203 }, + { 13902, 27573 }, + { 13903, 26029 }, + { 13904, 32526 }, + { 13905, 22534 }, + { 13906, 20817 }, + { 13907, 38431 }, + { 13908, 23545 }, + { 13909, 22697 }, + { 13910, 21544 }, + { 13911, 36466 }, + { 13912, 25958 }, + { 13913, 39039 }, + { 13914, 22244 }, + { 13915, 38045 }, + { 13916, 30462 }, + { 13917, 36929 }, + { 13918, 25479 }, + { 13919, 21702 }, + { 13920, 22810 }, + { 13921, 22842 }, + { 13922, 22427 }, + { 13923, 36530 }, + { 13924, 26421 }, + { 13925, 36346 }, + { 13926, 33333 }, + { 13927, 21057 }, + { 13928, 24816 }, + { 13929, 22549 }, + { 13930, 34558 }, + { 13931, 23784 }, + { 13932, 40517 }, + { 13933, 20420 }, + { 13934, 39069 }, + { 13935, 35769 }, + { 13936, 23077 }, + { 13937, 24694 }, + { 13938, 21380 }, + { 13939, 25212 }, + { 13940, 36943 }, + { 13941, 37122 }, + { 13942, 39295 }, + { 13943, 24681 }, + { 13944, 32780 }, + { 13945, 20799 }, + { 13946, 32819 }, + { 13947, 23572 }, + { 13948, 39285 }, + { 13949, 27953 }, + { 13950, 20108 }, + { 14113, 36144 }, + { 14114, 21457 }, + { 14115, 32602 }, + { 14116, 31567 }, + { 14117, 20240 }, + { 14118, 20047 }, + { 14119, 38400 }, + { 14120, 27861 }, + { 14121, 29648 }, + { 14122, 34281 }, + { 14123, 24070 }, + { 14124, 30058 }, + { 14125, 32763 }, + { 14126, 27146 }, + { 14127, 30718 }, + { 14128, 38034 }, + { 14129, 32321 }, + { 14130, 20961 }, + { 14131, 28902 }, + { 14132, 21453 }, + { 14133, 36820 }, + { 14134, 33539 }, + { 14135, 36137 }, + { 14136, 29359 }, + { 14137, 39277 }, + { 14138, 27867 }, + { 14139, 22346 }, + { 14140, 33459 }, + { 14141, 26041 }, + { 14142, 32938 }, + { 14143, 25151 }, + { 14144, 38450 }, + { 14145, 22952 }, + { 14146, 20223 }, + { 14147, 35775 }, + { 14148, 32442 }, + { 14149, 25918 }, + { 14150, 33778 }, + { 14151, 38750 }, + { 14152, 21857 }, + { 14153, 39134 }, + { 14154, 32933 }, + { 14155, 21290 }, + { 14156, 35837 }, + { 14157, 21536 }, + { 14158, 32954 }, + { 14159, 24223 }, + { 14160, 27832 }, + { 14161, 36153 }, + { 14162, 33452 }, + { 14163, 37210 }, + { 14164, 21545 }, + { 14165, 27675 }, + { 14166, 20998 }, + { 14167, 32439 }, + { 14168, 22367 }, + { 14169, 28954 }, + { 14170, 27774 }, + { 14171, 31881 }, + { 14172, 22859 }, + { 14173, 20221 }, + { 14174, 24575 }, + { 14175, 24868 }, + { 14176, 31914 }, + { 14177, 20016 }, + { 14178, 23553 }, + { 14179, 26539 }, + { 14180, 34562 }, + { 14181, 23792 }, + { 14182, 38155 }, + { 14183, 39118 }, + { 14184, 30127 }, + { 14185, 28925 }, + { 14186, 36898 }, + { 14187, 20911 }, + { 14188, 32541 }, + { 14189, 35773 }, + { 14190, 22857 }, + { 14191, 20964 }, + { 14192, 20315 }, + { 14193, 21542 }, + { 14194, 22827 }, + { 14195, 25975 }, + { 14196, 32932 }, + { 14197, 23413 }, + { 14198, 25206 }, + { 14199, 25282 }, + { 14200, 36752 }, + { 14201, 24133 }, + { 14202, 27679 }, + { 14203, 31526 }, + { 14204, 20239 }, + { 14205, 20440 }, + { 14206, 26381 }, + { 14369, 28014 }, + { 14370, 28074 }, + { 14371, 31119 }, + { 14372, 34993 }, + { 14373, 24343 }, + { 14374, 29995 }, + { 14375, 25242 }, + { 14376, 36741 }, + { 14377, 20463 }, + { 14378, 37340 }, + { 14379, 26023 }, + { 14380, 33071 }, + { 14381, 33105 }, + { 14382, 24220 }, + { 14383, 33104 }, + { 14384, 36212 }, + { 14385, 21103 }, + { 14386, 35206 }, + { 14387, 36171 }, + { 14388, 22797 }, + { 14389, 20613 }, + { 14390, 20184 }, + { 14391, 38428 }, + { 14392, 29238 }, + { 14393, 33145 }, + { 14394, 36127 }, + { 14395, 23500 }, + { 14396, 35747 }, + { 14397, 38468 }, + { 14398, 22919 }, + { 14399, 32538 }, + { 14400, 21648 }, + { 14401, 22134 }, + { 14402, 22030 }, + { 14403, 35813 }, + { 14404, 25913 }, + { 14405, 27010 }, + { 14406, 38041 }, + { 14407, 30422 }, + { 14408, 28297 }, + { 14409, 24178 }, + { 14410, 29976 }, + { 14411, 26438 }, + { 14412, 26577 }, + { 14413, 31487 }, + { 14414, 32925 }, + { 14415, 36214 }, + { 14416, 24863 }, + { 14417, 31174 }, + { 14418, 25954 }, + { 14419, 36195 }, + { 14420, 20872 }, + { 14421, 21018 }, + { 14422, 38050 }, + { 14423, 32568 }, + { 14424, 32923 }, + { 14425, 32434 }, + { 14426, 23703 }, + { 14427, 28207 }, + { 14428, 26464 }, + { 14429, 31705 }, + { 14430, 30347 }, + { 14431, 39640 }, + { 14432, 33167 }, + { 14433, 32660 }, + { 14434, 31957 }, + { 14435, 25630 }, + { 14436, 38224 }, + { 14437, 31295 }, + { 14438, 21578 }, + { 14439, 21733 }, + { 14440, 27468 }, + { 14441, 25601 }, + { 14442, 25096 }, + { 14443, 40509 }, + { 14444, 33011 }, + { 14445, 30105 }, + { 14446, 21106 }, + { 14447, 38761 }, + { 14448, 33883 }, + { 14449, 26684 }, + { 14450, 34532 }, + { 14451, 38401 }, + { 14452, 38548 }, + { 14453, 38124 }, + { 14454, 20010 }, + { 14455, 21508 }, + { 14456, 32473 }, + { 14457, 26681 }, + { 14458, 36319 }, + { 14459, 32789 }, + { 14460, 26356 }, + { 14461, 24218 }, + { 14462, 32697 }, + { 14625, 22466 }, + { 14626, 32831 }, + { 14627, 26775 }, + { 14628, 24037 }, + { 14629, 25915 }, + { 14630, 21151 }, + { 14631, 24685 }, + { 14632, 40858 }, + { 14633, 20379 }, + { 14634, 36524 }, + { 14635, 20844 }, + { 14636, 23467 }, + { 14637, 24339 }, + { 14638, 24041 }, + { 14639, 27742 }, + { 14640, 25329 }, + { 14641, 36129 }, + { 14642, 20849 }, + { 14643, 38057 }, + { 14644, 21246 }, + { 14645, 27807 }, + { 14646, 33503 }, + { 14647, 29399 }, + { 14648, 22434 }, + { 14649, 26500 }, + { 14650, 36141 }, + { 14651, 22815 }, + { 14652, 36764 }, + { 14653, 33735 }, + { 14654, 21653 }, + { 14655, 31629 }, + { 14656, 20272 }, + { 14657, 27837 }, + { 14658, 23396 }, + { 14659, 22993 }, + { 14660, 40723 }, + { 14661, 21476 }, + { 14662, 34506 }, + { 14663, 39592 }, + { 14664, 35895 }, + { 14665, 32929 }, + { 14666, 25925 }, + { 14667, 39038 }, + { 14668, 22266 }, + { 14669, 38599 }, + { 14670, 21038 }, + { 14671, 29916 }, + { 14672, 21072 }, + { 14673, 23521 }, + { 14674, 25346 }, + { 14675, 35074 }, + { 14676, 20054 }, + { 14677, 25296 }, + { 14678, 24618 }, + { 14679, 26874 }, + { 14680, 20851 }, + { 14681, 23448 }, + { 14682, 20896 }, + { 14683, 35266 }, + { 14684, 31649 }, + { 14685, 39302 }, + { 14686, 32592 }, + { 14687, 24815 }, + { 14688, 28748 }, + { 14689, 36143 }, + { 14690, 20809 }, + { 14691, 24191 }, + { 14692, 36891 }, + { 14693, 29808 }, + { 14694, 35268 }, + { 14695, 22317 }, + { 14696, 30789 }, + { 14697, 24402 }, + { 14698, 40863 }, + { 14699, 38394 }, + { 14700, 36712 }, + { 14701, 39740 }, + { 14702, 35809 }, + { 14703, 30328 }, + { 14704, 26690 }, + { 14705, 26588 }, + { 14706, 36330 }, + { 14707, 36149 }, + { 14708, 21053 }, + { 14709, 36746 }, + { 14710, 28378 }, + { 14711, 26829 }, + { 14712, 38149 }, + { 14713, 37101 }, + { 14714, 22269 }, + { 14715, 26524 }, + { 14716, 35065 }, + { 14717, 36807 }, + { 14718, 21704 }, + { 14881, 39608 }, + { 14882, 23401 }, + { 14883, 28023 }, + { 14884, 27686 }, + { 14885, 20133 }, + { 14886, 23475 }, + { 14887, 39559 }, + { 14888, 37219 }, + { 14889, 25000 }, + { 14890, 37039 }, + { 14891, 38889 }, + { 14892, 21547 }, + { 14893, 28085 }, + { 14894, 23506 }, + { 14895, 20989 }, + { 14896, 21898 }, + { 14897, 32597 }, + { 14898, 32752 }, + { 14899, 25788 }, + { 14900, 25421 }, + { 14901, 26097 }, + { 14902, 25022 }, + { 14903, 24717 }, + { 14904, 28938 }, + { 14905, 27735 }, + { 14906, 27721 }, + { 14907, 22831 }, + { 14908, 26477 }, + { 14909, 33322 }, + { 14910, 22741 }, + { 14911, 22158 }, + { 14912, 35946 }, + { 14913, 27627 }, + { 14914, 37085 }, + { 14915, 22909 }, + { 14916, 32791 }, + { 14917, 21495 }, + { 14918, 28009 }, + { 14919, 21621 }, + { 14920, 21917 }, + { 14921, 33655 }, + { 14922, 33743 }, + { 14923, 26680 }, + { 14924, 31166 }, + { 14925, 21644 }, + { 14926, 20309 }, + { 14927, 21512 }, + { 14928, 30418 }, + { 14929, 35977 }, + { 14930, 38402 }, + { 14931, 27827 }, + { 14932, 28088 }, + { 14933, 36203 }, + { 14934, 35088 }, + { 14935, 40548 }, + { 14936, 36154 }, + { 14937, 22079 }, + { 14938, 40657 }, + { 14939, 30165 }, + { 14940, 24456 }, + { 14941, 29408 }, + { 14942, 24680 }, + { 14943, 21756 }, + { 14944, 20136 }, + { 14945, 27178 }, + { 14946, 34913 }, + { 14947, 24658 }, + { 14948, 36720 }, + { 14949, 21700 }, + { 14950, 28888 }, + { 14951, 34425 }, + { 14952, 40511 }, + { 14953, 27946 }, + { 14954, 23439 }, + { 14955, 24344 }, + { 14956, 32418 }, + { 14957, 21897 }, + { 14958, 20399 }, + { 14959, 29492 }, + { 14960, 21564 }, + { 14961, 21402 }, + { 14962, 20505 }, + { 14963, 21518 }, + { 14964, 21628 }, + { 14965, 20046 }, + { 14966, 24573 }, + { 14967, 29786 }, + { 14968, 22774 }, + { 14969, 33899 }, + { 14970, 32993 }, + { 14971, 34676 }, + { 14972, 29392 }, + { 14973, 31946 }, + { 14974, 28246 }, + { 15137, 24359 }, + { 15138, 34382 }, + { 15139, 21804 }, + { 15140, 25252 }, + { 15141, 20114 }, + { 15142, 27818 }, + { 15143, 25143 }, + { 15144, 33457 }, + { 15145, 21719 }, + { 15146, 21326 }, + { 15147, 29502 }, + { 15148, 28369 }, + { 15149, 30011 }, + { 15150, 21010 }, + { 15151, 21270 }, + { 15152, 35805 }, + { 15153, 27088 }, + { 15154, 24458 }, + { 15155, 24576 }, + { 15156, 28142 }, + { 15157, 22351 }, + { 15158, 27426 }, + { 15159, 29615 }, + { 15160, 26707 }, + { 15161, 36824 }, + { 15162, 32531 }, + { 15163, 25442 }, + { 15164, 24739 }, + { 15165, 21796 }, + { 15166, 30186 }, + { 15167, 35938 }, + { 15168, 28949 }, + { 15169, 28067 }, + { 15170, 23462 }, + { 15171, 24187 }, + { 15172, 33618 }, + { 15173, 24908 }, + { 15174, 40644 }, + { 15175, 30970 }, + { 15176, 34647 }, + { 15177, 31783 }, + { 15178, 30343 }, + { 15179, 20976 }, + { 15180, 24822 }, + { 15181, 29004 }, + { 15182, 26179 }, + { 15183, 24140 }, + { 15184, 24653 }, + { 15185, 35854 }, + { 15186, 28784 }, + { 15187, 25381 }, + { 15188, 36745 }, + { 15189, 24509 }, + { 15190, 24674 }, + { 15191, 34516 }, + { 15192, 22238 }, + { 15193, 27585 }, + { 15194, 24724 }, + { 15195, 24935 }, + { 15196, 21321 }, + { 15197, 24800 }, + { 15198, 26214 }, + { 15199, 36159 }, + { 15200, 31229 }, + { 15201, 20250 }, + { 15202, 28905 }, + { 15203, 27719 }, + { 15204, 35763 }, + { 15205, 35826 }, + { 15206, 32472 }, + { 15207, 33636 }, + { 15208, 26127 }, + { 15209, 23130 }, + { 15210, 39746 }, + { 15211, 27985 }, + { 15212, 28151 }, + { 15213, 35905 }, + { 15214, 27963 }, + { 15215, 20249 }, + { 15216, 28779 }, + { 15217, 33719 }, + { 15218, 25110 }, + { 15219, 24785 }, + { 15220, 38669 }, + { 15221, 36135 }, + { 15222, 31096 }, + { 15223, 20987 }, + { 15224, 22334 }, + { 15225, 22522 }, + { 15226, 26426 }, + { 15227, 30072 }, + { 15228, 31293 }, + { 15229, 31215 }, + { 15230, 31637 }, + { 15393, 32908 }, + { 15394, 39269 }, + { 15395, 36857 }, + { 15396, 28608 }, + { 15397, 35749 }, + { 15398, 40481 }, + { 15399, 23020 }, + { 15400, 32489 }, + { 15401, 32521 }, + { 15402, 21513 }, + { 15403, 26497 }, + { 15404, 26840 }, + { 15405, 36753 }, + { 15406, 31821 }, + { 15407, 38598 }, + { 15408, 21450 }, + { 15409, 24613 }, + { 15410, 30142 }, + { 15411, 27762 }, + { 15412, 21363 }, + { 15413, 23241 }, + { 15414, 32423 }, + { 15415, 25380 }, + { 15416, 20960 }, + { 15417, 33034 }, + { 15418, 24049 }, + { 15419, 34015 }, + { 15420, 25216 }, + { 15421, 20864 }, + { 15422, 23395 }, + { 15423, 20238 }, + { 15424, 31085 }, + { 15425, 21058 }, + { 15426, 24760 }, + { 15427, 27982 }, + { 15428, 23492 }, + { 15429, 23490 }, + { 15430, 35745 }, + { 15431, 35760 }, + { 15432, 26082 }, + { 15433, 24524 }, + { 15434, 38469 }, + { 15435, 22931 }, + { 15436, 32487 }, + { 15437, 32426 }, + { 15438, 22025 }, + { 15439, 26551 }, + { 15440, 22841 }, + { 15441, 20339 }, + { 15442, 23478 }, + { 15443, 21152 }, + { 15444, 33626 }, + { 15445, 39050 }, + { 15446, 36158 }, + { 15447, 30002 }, + { 15448, 38078 }, + { 15449, 20551 }, + { 15450, 31292 }, + { 15451, 20215 }, + { 15452, 26550 }, + { 15453, 39550 }, + { 15454, 23233 }, + { 15455, 27516 }, + { 15456, 30417 }, + { 15457, 22362 }, + { 15458, 23574 }, + { 15459, 31546 }, + { 15460, 38388 }, + { 15461, 29006 }, + { 15462, 20860 }, + { 15463, 32937 }, + { 15464, 33392 }, + { 15465, 22904 }, + { 15466, 32516 }, + { 15467, 33575 }, + { 15468, 26816 }, + { 15469, 26604 }, + { 15470, 30897 }, + { 15471, 30839 }, + { 15472, 25315 }, + { 15473, 25441 }, + { 15474, 31616 }, + { 15475, 20461 }, + { 15476, 21098 }, + { 15477, 20943 }, + { 15478, 33616 }, + { 15479, 27099 }, + { 15480, 37492 }, + { 15481, 36341 }, + { 15482, 36145 }, + { 15483, 35265 }, + { 15484, 38190 }, + { 15485, 31661 }, + { 15486, 20214 }, + { 15649, 20581 }, + { 15650, 33328 }, + { 15651, 21073 }, + { 15652, 39279 }, + { 15653, 28176 }, + { 15654, 28293 }, + { 15655, 28071 }, + { 15656, 24314 }, + { 15657, 20725 }, + { 15658, 23004 }, + { 15659, 23558 }, + { 15660, 27974 }, + { 15661, 27743 }, + { 15662, 30086 }, + { 15663, 33931 }, + { 15664, 26728 }, + { 15665, 22870 }, + { 15666, 35762 }, + { 15667, 21280 }, + { 15668, 37233 }, + { 15669, 38477 }, + { 15670, 34121 }, + { 15671, 26898 }, + { 15672, 30977 }, + { 15673, 28966 }, + { 15674, 33014 }, + { 15675, 20132 }, + { 15676, 37066 }, + { 15677, 27975 }, + { 15678, 39556 }, + { 15679, 23047 }, + { 15680, 22204 }, + { 15681, 25605 }, + { 15682, 38128 }, + { 15683, 30699 }, + { 15684, 20389 }, + { 15685, 33050 }, + { 15686, 29409 }, + { 15687, 35282 }, + { 15688, 39290 }, + { 15689, 32564 }, + { 15690, 32478 }, + { 15691, 21119 }, + { 15692, 25945 }, + { 15693, 37237 }, + { 15694, 36735 }, + { 15695, 36739 }, + { 15696, 21483 }, + { 15697, 31382 }, + { 15698, 25581 }, + { 15699, 25509 }, + { 15700, 30342 }, + { 15701, 31224 }, + { 15702, 34903 }, + { 15703, 38454 }, + { 15704, 25130 }, + { 15705, 21163 }, + { 15706, 33410 }, + { 15707, 26708 }, + { 15708, 26480 }, + { 15709, 25463 }, + { 15710, 30571 }, + { 15711, 31469 }, + { 15712, 27905 }, + { 15713, 32467 }, + { 15714, 35299 }, + { 15715, 22992 }, + { 15716, 25106 }, + { 15717, 34249 }, + { 15718, 33445 }, + { 15719, 30028 }, + { 15720, 20511 }, + { 15721, 20171 }, + { 15722, 30117 }, + { 15723, 35819 }, + { 15724, 23626 }, + { 15725, 24062 }, + { 15726, 31563 }, + { 15727, 26020 }, + { 15728, 37329 }, + { 15729, 20170 }, + { 15730, 27941 }, + { 15731, 35167 }, + { 15732, 32039 }, + { 15733, 38182 }, + { 15734, 20165 }, + { 15735, 35880 }, + { 15736, 36827 }, + { 15737, 38771 }, + { 15738, 26187 }, + { 15739, 31105 }, + { 15740, 36817 }, + { 15741, 28908 }, + { 15742, 28024 }, + { 15905, 23613 }, + { 15906, 21170 }, + { 15907, 33606 }, + { 15908, 20834 }, + { 15909, 33550 }, + { 15910, 30555 }, + { 15911, 26230 }, + { 15912, 40120 }, + { 15913, 20140 }, + { 15914, 24778 }, + { 15915, 31934 }, + { 15916, 31923 }, + { 15917, 32463 }, + { 15918, 20117 }, + { 15919, 35686 }, + { 15920, 26223 }, + { 15921, 39048 }, + { 15922, 38745 }, + { 15923, 22659 }, + { 15924, 25964 }, + { 15925, 38236 }, + { 15926, 24452 }, + { 15927, 30153 }, + { 15928, 38742 }, + { 15929, 31455 }, + { 15930, 31454 }, + { 15931, 20928 }, + { 15932, 28847 }, + { 15933, 31384 }, + { 15934, 25578 }, + { 15935, 31350 }, + { 15936, 32416 }, + { 15937, 29590 }, + { 15938, 38893 }, + { 15939, 20037 }, + { 15940, 28792 }, + { 15941, 20061 }, + { 15942, 37202 }, + { 15943, 21417 }, + { 15944, 25937 }, + { 15945, 26087 }, + { 15946, 33276 }, + { 15947, 33285 }, + { 15948, 21646 }, + { 15949, 23601 }, + { 15950, 30106 }, + { 15951, 38816 }, + { 15952, 25304 }, + { 15953, 29401 }, + { 15954, 30141 }, + { 15955, 23621 }, + { 15956, 39545 }, + { 15957, 33738 }, + { 15958, 23616 }, + { 15959, 21632 }, + { 15960, 30697 }, + { 15961, 20030 }, + { 15962, 27822 }, + { 15963, 32858 }, + { 15964, 25298 }, + { 15965, 25454 }, + { 15966, 24040 }, + { 15967, 20855 }, + { 15968, 36317 }, + { 15969, 36382 }, + { 15970, 38191 }, + { 15971, 20465 }, + { 15972, 21477 }, + { 15973, 24807 }, + { 15974, 28844 }, + { 15975, 21095 }, + { 15976, 25424 }, + { 15977, 40515 }, + { 15978, 23071 }, + { 15979, 20518 }, + { 15980, 30519 }, + { 15981, 21367 }, + { 15982, 32482 }, + { 15983, 25733 }, + { 15984, 25899 }, + { 15985, 25225 }, + { 15986, 25496 }, + { 15987, 20500 }, + { 15988, 29237 }, + { 15989, 35273 }, + { 15990, 20915 }, + { 15991, 35776 }, + { 15992, 32477 }, + { 15993, 22343 }, + { 15994, 33740 }, + { 15995, 38055 }, + { 15996, 20891 }, + { 15997, 21531 }, + { 15998, 23803 }, + { 16161, 20426 }, + { 16162, 31459 }, + { 16163, 27994 }, + { 16164, 37089 }, + { 16165, 39567 }, + { 16166, 21888 }, + { 16167, 21654 }, + { 16168, 21345 }, + { 16169, 21679 }, + { 16170, 24320 }, + { 16171, 25577 }, + { 16172, 26999 }, + { 16173, 20975 }, + { 16174, 24936 }, + { 16175, 21002 }, + { 16176, 22570 }, + { 16177, 21208 }, + { 16178, 22350 }, + { 16179, 30733 }, + { 16180, 30475 }, + { 16181, 24247 }, + { 16182, 24951 }, + { 16183, 31968 }, + { 16184, 25179 }, + { 16185, 25239 }, + { 16186, 20130 }, + { 16187, 28821 }, + { 16188, 32771 }, + { 16189, 25335 }, + { 16190, 28900 }, + { 16191, 38752 }, + { 16192, 22391 }, + { 16193, 33499 }, + { 16194, 26607 }, + { 16195, 26869 }, + { 16196, 30933 }, + { 16197, 39063 }, + { 16198, 31185 }, + { 16199, 22771 }, + { 16200, 21683 }, + { 16201, 21487 }, + { 16202, 28212 }, + { 16203, 20811 }, + { 16204, 21051 }, + { 16205, 23458 }, + { 16206, 35838 }, + { 16207, 32943 }, + { 16208, 21827 }, + { 16209, 22438 }, + { 16210, 24691 }, + { 16211, 22353 }, + { 16212, 21549 }, + { 16213, 31354 }, + { 16214, 24656 }, + { 16215, 23380 }, + { 16216, 25511 }, + { 16217, 25248 }, + { 16218, 21475 }, + { 16219, 25187 }, + { 16220, 23495 }, + { 16221, 26543 }, + { 16222, 21741 }, + { 16223, 31391 }, + { 16224, 33510 }, + { 16225, 37239 }, + { 16226, 24211 }, + { 16227, 35044 }, + { 16228, 22840 }, + { 16229, 22446 }, + { 16230, 25358 }, + { 16231, 36328 }, + { 16232, 33007 }, + { 16233, 22359 }, + { 16234, 31607 }, + { 16235, 20393 }, + { 16236, 24555 }, + { 16237, 23485 }, + { 16238, 27454 }, + { 16239, 21281 }, + { 16240, 31568 }, + { 16241, 29378 }, + { 16242, 26694 }, + { 16243, 30719 }, + { 16244, 30518 }, + { 16245, 26103 }, + { 16246, 20917 }, + { 16247, 20111 }, + { 16248, 30420 }, + { 16249, 23743 }, + { 16250, 31397 }, + { 16251, 33909 }, + { 16252, 22862 }, + { 16253, 39745 }, + { 16254, 20608 }, + { 16417, 39304 }, + { 16418, 24871 }, + { 16419, 28291 }, + { 16420, 22372 }, + { 16421, 26118 }, + { 16422, 25414 }, + { 16423, 22256 }, + { 16424, 25324 }, + { 16425, 25193 }, + { 16426, 24275 }, + { 16427, 38420 }, + { 16428, 22403 }, + { 16429, 25289 }, + { 16430, 21895 }, + { 16431, 34593 }, + { 16432, 33098 }, + { 16433, 36771 }, + { 16434, 21862 }, + { 16435, 33713 }, + { 16436, 26469 }, + { 16437, 36182 }, + { 16438, 34013 }, + { 16439, 23146 }, + { 16440, 26639 }, + { 16441, 25318 }, + { 16442, 31726 }, + { 16443, 38417 }, + { 16444, 20848 }, + { 16445, 28572 }, + { 16446, 35888 }, + { 16447, 25597 }, + { 16448, 35272 }, + { 16449, 25042 }, + { 16450, 32518 }, + { 16451, 28866 }, + { 16452, 28389 }, + { 16453, 29701 }, + { 16454, 27028 }, + { 16455, 29436 }, + { 16456, 24266 }, + { 16457, 37070 }, + { 16458, 26391 }, + { 16459, 28010 }, + { 16460, 25438 }, + { 16461, 21171 }, + { 16462, 29282 }, + { 16463, 32769 }, + { 16464, 20332 }, + { 16465, 23013 }, + { 16466, 37226 }, + { 16467, 28889 }, + { 16468, 28061 }, + { 16469, 21202 }, + { 16470, 20048 }, + { 16471, 38647 }, + { 16472, 38253 }, + { 16473, 34174 }, + { 16474, 30922 }, + { 16475, 32047 }, + { 16476, 20769 }, + { 16477, 22418 }, + { 16478, 25794 }, + { 16479, 32907 }, + { 16480, 31867 }, + { 16481, 27882 }, + { 16482, 26865 }, + { 16483, 26974 }, + { 16484, 20919 }, + { 16485, 21400 }, + { 16486, 26792 }, + { 16487, 29313 }, + { 16488, 40654 }, + { 16489, 31729 }, + { 16490, 29432 }, + { 16491, 31163 }, + { 16492, 28435 }, + { 16493, 29702 }, + { 16494, 26446 }, + { 16495, 37324 }, + { 16496, 40100 }, + { 16497, 31036 }, + { 16498, 33673 }, + { 16499, 33620 }, + { 16500, 21519 }, + { 16501, 26647 }, + { 16502, 20029 }, + { 16503, 21385 }, + { 16504, 21169 }, + { 16505, 30782 }, + { 16506, 21382 }, + { 16507, 21033 }, + { 16508, 20616 }, + { 16509, 20363 }, + { 16510, 20432 }, + { 16673, 30178 }, + { 16674, 31435 }, + { 16675, 31890 }, + { 16676, 27813 }, + { 16677, 38582 }, + { 16678, 21147 }, + { 16679, 29827 }, + { 16680, 21737 }, + { 16681, 20457 }, + { 16682, 32852 }, + { 16683, 33714 }, + { 16684, 36830 }, + { 16685, 38256 }, + { 16686, 24265 }, + { 16687, 24604 }, + { 16688, 28063 }, + { 16689, 24088 }, + { 16690, 25947 }, + { 16691, 33080 }, + { 16692, 38142 }, + { 16693, 24651 }, + { 16694, 28860 }, + { 16695, 32451 }, + { 16696, 31918 }, + { 16697, 20937 }, + { 16698, 26753 }, + { 16699, 31921 }, + { 16700, 33391 }, + { 16701, 20004 }, + { 16702, 36742 }, + { 16703, 37327 }, + { 16704, 26238 }, + { 16705, 20142 }, + { 16706, 35845 }, + { 16707, 25769 }, + { 16708, 32842 }, + { 16709, 20698 }, + { 16710, 30103 }, + { 16711, 29134 }, + { 16712, 23525 }, + { 16713, 36797 }, + { 16714, 28518 }, + { 16715, 20102 }, + { 16716, 25730 }, + { 16717, 38243 }, + { 16718, 24278 }, + { 16719, 26009 }, + { 16720, 21015 }, + { 16721, 35010 }, + { 16722, 28872 }, + { 16723, 21155 }, + { 16724, 29454 }, + { 16725, 29747 }, + { 16726, 26519 }, + { 16727, 30967 }, + { 16728, 38678 }, + { 16729, 20020 }, + { 16730, 37051 }, + { 16731, 40158 }, + { 16732, 28107 }, + { 16733, 20955 }, + { 16734, 36161 }, + { 16735, 21533 }, + { 16736, 25294 }, + { 16737, 29618 }, + { 16738, 33777 }, + { 16739, 38646 }, + { 16740, 40836 }, + { 16741, 38083 }, + { 16742, 20278 }, + { 16743, 32666 }, + { 16744, 20940 }, + { 16745, 28789 }, + { 16746, 38517 }, + { 16747, 23725 }, + { 16748, 39046 }, + { 16749, 21478 }, + { 16750, 20196 }, + { 16751, 28316 }, + { 16752, 29705 }, + { 16753, 27060 }, + { 16754, 30827 }, + { 16755, 39311 }, + { 16756, 30041 }, + { 16757, 21016 }, + { 16758, 30244 }, + { 16759, 27969 }, + { 16760, 26611 }, + { 16761, 20845 }, + { 16762, 40857 }, + { 16763, 32843 }, + { 16764, 21657 }, + { 16765, 31548 }, + { 16766, 31423 }, + { 16929, 38534 }, + { 16930, 22404 }, + { 16931, 25314 }, + { 16932, 38471 }, + { 16933, 27004 }, + { 16934, 23044 }, + { 16935, 25602 }, + { 16936, 31699 }, + { 16937, 28431 }, + { 16938, 38475 }, + { 16939, 33446 }, + { 16940, 21346 }, + { 16941, 39045 }, + { 16942, 24208 }, + { 16943, 28809 }, + { 16944, 25523 }, + { 16945, 21348 }, + { 16946, 34383 }, + { 16947, 40065 }, + { 16948, 40595 }, + { 16949, 30860 }, + { 16950, 38706 }, + { 16951, 36335 }, + { 16952, 36162 }, + { 16953, 40575 }, + { 16954, 28510 }, + { 16955, 31108 }, + { 16956, 24405 }, + { 16957, 38470 }, + { 16958, 25134 }, + { 16959, 39540 }, + { 16960, 21525 }, + { 16961, 38109 }, + { 16962, 20387 }, + { 16963, 26053 }, + { 16964, 23653 }, + { 16965, 23649 }, + { 16966, 32533 }, + { 16967, 34385 }, + { 16968, 27695 }, + { 16969, 24459 }, + { 16970, 29575 }, + { 16971, 28388 }, + { 16972, 32511 }, + { 16973, 23782 }, + { 16974, 25371 }, + { 16975, 23402 }, + { 16976, 28390 }, + { 16977, 21365 }, + { 16978, 20081 }, + { 16979, 25504 }, + { 16980, 30053 }, + { 16981, 25249 }, + { 16982, 36718 }, + { 16983, 20262 }, + { 16984, 20177 }, + { 16985, 27814 }, + { 16986, 32438 }, + { 16987, 35770 }, + { 16988, 33821 }, + { 16989, 34746 }, + { 16990, 32599 }, + { 16991, 36923 }, + { 16992, 38179 }, + { 16993, 31657 }, + { 16994, 39585 }, + { 16995, 35064 }, + { 16996, 33853 }, + { 16997, 27931 }, + { 16998, 39558 }, + { 16999, 32476 }, + { 17000, 22920 }, + { 17001, 40635 }, + { 17002, 29595 }, + { 17003, 30721 }, + { 17004, 34434 }, + { 17005, 39532 }, + { 17006, 39554 }, + { 17007, 22043 }, + { 17008, 21527 }, + { 17009, 22475 }, + { 17010, 20080 }, + { 17011, 40614 }, + { 17012, 21334 }, + { 17013, 36808 }, + { 17014, 33033 }, + { 17015, 30610 }, + { 17016, 39314 }, + { 17017, 34542 }, + { 17018, 28385 }, + { 17019, 34067 }, + { 17020, 26364 }, + { 17021, 24930 }, + { 17022, 28459 }, + { 17185, 35881 }, + { 17186, 33426 }, + { 17187, 33579 }, + { 17188, 30450 }, + { 17189, 27667 }, + { 17190, 24537 }, + { 17191, 33725 }, + { 17192, 29483 }, + { 17193, 33541 }, + { 17194, 38170 }, + { 17195, 27611 }, + { 17196, 30683 }, + { 17197, 38086 }, + { 17198, 21359 }, + { 17199, 33538 }, + { 17200, 20882 }, + { 17201, 24125 }, + { 17202, 35980 }, + { 17203, 36152 }, + { 17204, 20040 }, + { 17205, 29611 }, + { 17206, 26522 }, + { 17207, 26757 }, + { 17208, 37238 }, + { 17209, 38665 }, + { 17210, 29028 }, + { 17211, 27809 }, + { 17212, 30473 }, + { 17213, 23186 }, + { 17214, 38209 }, + { 17215, 27599 }, + { 17216, 32654 }, + { 17217, 26151 }, + { 17218, 23504 }, + { 17219, 22969 }, + { 17220, 23194 }, + { 17221, 38376 }, + { 17222, 38391 }, + { 17223, 20204 }, + { 17224, 33804 }, + { 17225, 33945 }, + { 17226, 27308 }, + { 17227, 30431 }, + { 17228, 38192 }, + { 17229, 29467 }, + { 17230, 26790 }, + { 17231, 23391 }, + { 17232, 30511 }, + { 17233, 37274 }, + { 17234, 38753 }, + { 17235, 31964 }, + { 17236, 36855 }, + { 17237, 35868 }, + { 17238, 24357 }, + { 17239, 31859 }, + { 17240, 31192 }, + { 17241, 35269 }, + { 17242, 27852 }, + { 17243, 34588 }, + { 17244, 23494 }, + { 17245, 24130 }, + { 17246, 26825 }, + { 17247, 30496 }, + { 17248, 32501 }, + { 17249, 20885 }, + { 17250, 20813 }, + { 17251, 21193 }, + { 17252, 23081 }, + { 17253, 32517 }, + { 17254, 38754 }, + { 17255, 33495 }, + { 17256, 25551 }, + { 17257, 30596 }, + { 17258, 34256 }, + { 17259, 31186 }, + { 17260, 28218 }, + { 17261, 24217 }, + { 17262, 22937 }, + { 17263, 34065 }, + { 17264, 28781 }, + { 17265, 27665 }, + { 17266, 25279 }, + { 17267, 30399 }, + { 17268, 25935 }, + { 17269, 24751 }, + { 17270, 38397 }, + { 17271, 26126 }, + { 17272, 34719 }, + { 17273, 40483 }, + { 17274, 38125 }, + { 17275, 21517 }, + { 17276, 21629 }, + { 17277, 35884 }, + { 17278, 25720 }, + { 17441, 25721 }, + { 17442, 34321 }, + { 17443, 27169 }, + { 17444, 33180 }, + { 17445, 30952 }, + { 17446, 25705 }, + { 17447, 39764 }, + { 17448, 25273 }, + { 17449, 26411 }, + { 17450, 33707 }, + { 17451, 22696 }, + { 17452, 40664 }, + { 17453, 27819 }, + { 17454, 28448 }, + { 17455, 23518 }, + { 17456, 38476 }, + { 17457, 35851 }, + { 17458, 29279 }, + { 17459, 26576 }, + { 17460, 25287 }, + { 17461, 29281 }, + { 17462, 20137 }, + { 17463, 22982 }, + { 17464, 27597 }, + { 17465, 22675 }, + { 17466, 26286 }, + { 17467, 24149 }, + { 17468, 21215 }, + { 17469, 24917 }, + { 17470, 26408 }, + { 17471, 30446 }, + { 17472, 30566 }, + { 17473, 29287 }, + { 17474, 31302 }, + { 17475, 25343 }, + { 17476, 21738 }, + { 17477, 21584 }, + { 17478, 38048 }, + { 17479, 37027 }, + { 17480, 23068 }, + { 17481, 32435 }, + { 17482, 27670 }, + { 17483, 20035 }, + { 17484, 22902 }, + { 17485, 32784 }, + { 17486, 22856 }, + { 17487, 21335 }, + { 17488, 30007 }, + { 17489, 38590 }, + { 17490, 22218 }, + { 17491, 25376 }, + { 17492, 33041 }, + { 17493, 24700 }, + { 17494, 38393 }, + { 17495, 28118 }, + { 17496, 21602 }, + { 17497, 39297 }, + { 17498, 20869 }, + { 17499, 23273 }, + { 17500, 33021 }, + { 17501, 22958 }, + { 17502, 38675 }, + { 17503, 20522 }, + { 17504, 27877 }, + { 17505, 23612 }, + { 17506, 25311 }, + { 17507, 20320 }, + { 17508, 21311 }, + { 17509, 33147 }, + { 17510, 36870 }, + { 17511, 28346 }, + { 17512, 34091 }, + { 17513, 25288 }, + { 17514, 24180 }, + { 17515, 30910 }, + { 17516, 25781 }, + { 17517, 25467 }, + { 17518, 24565 }, + { 17519, 23064 }, + { 17520, 37247 }, + { 17521, 40479 }, + { 17522, 23615 }, + { 17523, 25423 }, + { 17524, 32834 }, + { 17525, 23421 }, + { 17526, 21870 }, + { 17527, 38218 }, + { 17528, 38221 }, + { 17529, 28037 }, + { 17530, 24744 }, + { 17531, 26592 }, + { 17532, 29406 }, + { 17533, 20957 }, + { 17534, 23425 }, + { 17697, 25319 }, + { 17698, 27870 }, + { 17699, 29275 }, + { 17700, 25197 }, + { 17701, 38062 }, + { 17702, 32445 }, + { 17703, 33043 }, + { 17704, 27987 }, + { 17705, 20892 }, + { 17706, 24324 }, + { 17707, 22900 }, + { 17708, 21162 }, + { 17709, 24594 }, + { 17710, 22899 }, + { 17711, 26262 }, + { 17712, 34384 }, + { 17713, 30111 }, + { 17714, 25386 }, + { 17715, 25062 }, + { 17716, 31983 }, + { 17717, 35834 }, + { 17718, 21734 }, + { 17719, 27431 }, + { 17720, 40485 }, + { 17721, 27572 }, + { 17722, 34261 }, + { 17723, 21589 }, + { 17724, 20598 }, + { 17725, 27812 }, + { 17726, 21866 }, + { 17727, 36276 }, + { 17728, 29228 }, + { 17729, 24085 }, + { 17730, 24597 }, + { 17731, 29750 }, + { 17732, 25293 }, + { 17733, 25490 }, + { 17734, 29260 }, + { 17735, 24472 }, + { 17736, 28227 }, + { 17737, 27966 }, + { 17738, 25856 }, + { 17739, 28504 }, + { 17740, 30424 }, + { 17741, 30928 }, + { 17742, 30460 }, + { 17743, 30036 }, + { 17744, 21028 }, + { 17745, 21467 }, + { 17746, 20051 }, + { 17747, 24222 }, + { 17748, 26049 }, + { 17749, 32810 }, + { 17750, 32982 }, + { 17751, 25243 }, + { 17752, 21638 }, + { 17753, 21032 }, + { 17754, 28846 }, + { 17755, 34957 }, + { 17756, 36305 }, + { 17757, 27873 }, + { 17758, 21624 }, + { 17759, 32986 }, + { 17760, 22521 }, + { 17761, 35060 }, + { 17762, 36180 }, + { 17763, 38506 }, + { 17764, 37197 }, + { 17765, 20329 }, + { 17766, 27803 }, + { 17767, 21943 }, + { 17768, 30406 }, + { 17769, 30768 }, + { 17770, 25256 }, + { 17771, 28921 }, + { 17772, 28558 }, + { 17773, 24429 }, + { 17774, 34028 }, + { 17775, 26842 }, + { 17776, 30844 }, + { 17777, 31735 }, + { 17778, 33192 }, + { 17779, 26379 }, + { 17780, 40527 }, + { 17781, 25447 }, + { 17782, 30896 }, + { 17783, 22383 }, + { 17784, 30738 }, + { 17785, 38713 }, + { 17786, 25209 }, + { 17787, 25259 }, + { 17788, 21128 }, + { 17789, 29749 }, + { 17790, 27607 }, + { 17953, 21860 }, + { 17954, 33086 }, + { 17955, 30130 }, + { 17956, 30382 }, + { 17957, 21305 }, + { 17958, 30174 }, + { 17959, 20731 }, + { 17960, 23617 }, + { 17961, 35692 }, + { 17962, 31687 }, + { 17963, 20559 }, + { 17964, 29255 }, + { 17965, 39575 }, + { 17966, 39128 }, + { 17967, 28418 }, + { 17968, 29922 }, + { 17969, 31080 }, + { 17970, 25735 }, + { 17971, 30629 }, + { 17972, 25340 }, + { 17973, 39057 }, + { 17974, 36139 }, + { 17975, 21697 }, + { 17976, 32856 }, + { 17977, 20050 }, + { 17978, 22378 }, + { 17979, 33529 }, + { 17980, 33805 }, + { 17981, 24179 }, + { 17982, 20973 }, + { 17983, 29942 }, + { 17984, 35780 }, + { 17985, 23631 }, + { 17986, 22369 }, + { 17987, 27900 }, + { 17988, 39047 }, + { 17989, 23110 }, + { 17990, 30772 }, + { 17991, 39748 }, + { 17992, 36843 }, + { 17993, 31893 }, + { 17994, 21078 }, + { 17995, 25169 }, + { 17996, 38138 }, + { 17997, 20166 }, + { 17998, 33670 }, + { 17999, 33889 }, + { 18000, 33769 }, + { 18001, 33970 }, + { 18002, 22484 }, + { 18003, 26420 }, + { 18004, 22275 }, + { 18005, 26222 }, + { 18006, 28006 }, + { 18007, 35889 }, + { 18008, 26333 }, + { 18009, 28689 }, + { 18010, 26399 }, + { 18011, 27450 }, + { 18012, 26646 }, + { 18013, 25114 }, + { 18014, 22971 }, + { 18015, 19971 }, + { 18016, 20932 }, + { 18017, 28422 }, + { 18018, 26578 }, + { 18019, 27791 }, + { 18020, 20854 }, + { 18021, 26827 }, + { 18022, 22855 }, + { 18023, 27495 }, + { 18024, 30054 }, + { 18025, 23822 }, + { 18026, 33040 }, + { 18027, 40784 }, + { 18028, 26071 }, + { 18029, 31048 }, + { 18030, 31041 }, + { 18031, 39569 }, + { 18032, 36215 }, + { 18033, 23682 }, + { 18034, 20062 }, + { 18035, 20225 }, + { 18036, 21551 }, + { 18037, 22865 }, + { 18038, 30732 }, + { 18039, 22120 }, + { 18040, 27668 }, + { 18041, 36804 }, + { 18042, 24323 }, + { 18043, 27773 }, + { 18044, 27875 }, + { 18045, 35755 }, + { 18046, 25488 }, + { 18209, 24688 }, + { 18210, 27965 }, + { 18211, 29301 }, + { 18212, 25190 }, + { 18213, 38030 }, + { 18214, 38085 }, + { 18215, 21315 }, + { 18216, 36801 }, + { 18217, 31614 }, + { 18218, 20191 }, + { 18219, 35878 }, + { 18220, 20094 }, + { 18221, 40660 }, + { 18222, 38065 }, + { 18223, 38067 }, + { 18224, 21069 }, + { 18225, 28508 }, + { 18226, 36963 }, + { 18227, 27973 }, + { 18228, 35892 }, + { 18229, 22545 }, + { 18230, 23884 }, + { 18231, 27424 }, + { 18232, 27465 }, + { 18233, 26538 }, + { 18234, 21595 }, + { 18235, 33108 }, + { 18236, 32652 }, + { 18237, 22681 }, + { 18238, 34103 }, + { 18239, 24378 }, + { 18240, 25250 }, + { 18241, 27207 }, + { 18242, 38201 }, + { 18243, 25970 }, + { 18244, 24708 }, + { 18245, 26725 }, + { 18246, 30631 }, + { 18247, 20052 }, + { 18248, 20392 }, + { 18249, 24039 }, + { 18250, 38808 }, + { 18251, 25772 }, + { 18252, 32728 }, + { 18253, 23789 }, + { 18254, 20431 }, + { 18255, 31373 }, + { 18256, 20999 }, + { 18257, 33540 }, + { 18258, 19988 }, + { 18259, 24623 }, + { 18260, 31363 }, + { 18261, 38054 }, + { 18262, 20405 }, + { 18263, 20146 }, + { 18264, 31206 }, + { 18265, 29748 }, + { 18266, 21220 }, + { 18267, 33465 }, + { 18268, 25810 }, + { 18269, 31165 }, + { 18270, 23517 }, + { 18271, 27777 }, + { 18272, 38738 }, + { 18273, 36731 }, + { 18274, 27682 }, + { 18275, 20542 }, + { 18276, 21375 }, + { 18277, 28165 }, + { 18278, 25806 }, + { 18279, 26228 }, + { 18280, 27696 }, + { 18281, 24773 }, + { 18282, 39031 }, + { 18283, 35831 }, + { 18284, 24198 }, + { 18285, 29756 }, + { 18286, 31351 }, + { 18287, 31179 }, + { 18288, 19992 }, + { 18289, 37041 }, + { 18290, 29699 }, + { 18291, 27714 }, + { 18292, 22234 }, + { 18293, 37195 }, + { 18294, 27845 }, + { 18295, 36235 }, + { 18296, 21306 }, + { 18297, 34502 }, + { 18298, 26354 }, + { 18299, 36527 }, + { 18300, 23624 }, + { 18301, 39537 }, + { 18302, 28192 }, + { 18465, 21462 }, + { 18466, 23094 }, + { 18467, 40843 }, + { 18468, 36259 }, + { 18469, 21435 }, + { 18470, 22280 }, + { 18471, 39079 }, + { 18472, 26435 }, + { 18473, 37275 }, + { 18474, 27849 }, + { 18475, 20840 }, + { 18476, 30154 }, + { 18477, 25331 }, + { 18478, 29356 }, + { 18479, 21048 }, + { 18480, 21149 }, + { 18481, 32570 }, + { 18482, 28820 }, + { 18483, 30264 }, + { 18484, 21364 }, + { 18485, 40522 }, + { 18486, 27063 }, + { 18487, 30830 }, + { 18488, 38592 }, + { 18489, 35033 }, + { 18490, 32676 }, + { 18491, 28982 }, + { 18492, 29123 }, + { 18493, 20873 }, + { 18494, 26579 }, + { 18495, 29924 }, + { 18496, 22756 }, + { 18497, 25880 }, + { 18498, 22199 }, + { 18499, 35753 }, + { 18500, 39286 }, + { 18501, 25200 }, + { 18502, 32469 }, + { 18503, 24825 }, + { 18504, 28909 }, + { 18505, 22764 }, + { 18506, 20161 }, + { 18507, 20154 }, + { 18508, 24525 }, + { 18509, 38887 }, + { 18510, 20219 }, + { 18511, 35748 }, + { 18512, 20995 }, + { 18513, 22922 }, + { 18514, 32427 }, + { 18515, 25172 }, + { 18516, 20173 }, + { 18517, 26085 }, + { 18518, 25102 }, + { 18519, 33592 }, + { 18520, 33993 }, + { 18521, 33635 }, + { 18522, 34701 }, + { 18523, 29076 }, + { 18524, 28342 }, + { 18525, 23481 }, + { 18526, 32466 }, + { 18527, 20887 }, + { 18528, 25545 }, + { 18529, 26580 }, + { 18530, 32905 }, + { 18531, 33593 }, + { 18532, 34837 }, + { 18533, 20754 }, + { 18534, 23418 }, + { 18535, 22914 }, + { 18536, 36785 }, + { 18537, 20083 }, + { 18538, 27741 }, + { 18539, 20837 }, + { 18540, 35109 }, + { 18541, 36719 }, + { 18542, 38446 }, + { 18543, 34122 }, + { 18544, 29790 }, + { 18545, 38160 }, + { 18546, 38384 }, + { 18547, 28070 }, + { 18548, 33509 }, + { 18549, 24369 }, + { 18550, 25746 }, + { 18551, 27922 }, + { 18552, 33832 }, + { 18553, 33134 }, + { 18554, 40131 }, + { 18555, 22622 }, + { 18556, 36187 }, + { 18557, 19977 }, + { 18558, 21441 }, + { 18721, 20254 }, + { 18722, 25955 }, + { 18723, 26705 }, + { 18724, 21971 }, + { 18725, 20007 }, + { 18726, 25620 }, + { 18727, 39578 }, + { 18728, 25195 }, + { 18729, 23234 }, + { 18730, 29791 }, + { 18731, 33394 }, + { 18732, 28073 }, + { 18733, 26862 }, + { 18734, 20711 }, + { 18735, 33678 }, + { 18736, 30722 }, + { 18737, 26432 }, + { 18738, 21049 }, + { 18739, 27801 }, + { 18740, 32433 }, + { 18741, 20667 }, + { 18742, 21861 }, + { 18743, 29022 }, + { 18744, 31579 }, + { 18745, 26194 }, + { 18746, 29642 }, + { 18747, 33515 }, + { 18748, 26441 }, + { 18749, 23665 }, + { 18750, 21024 }, + { 18751, 29053 }, + { 18752, 34923 }, + { 18753, 38378 }, + { 18754, 38485 }, + { 18755, 25797 }, + { 18756, 36193 }, + { 18757, 33203 }, + { 18758, 21892 }, + { 18759, 27733 }, + { 18760, 25159 }, + { 18761, 32558 }, + { 18762, 22674 }, + { 18763, 20260 }, + { 18764, 21830 }, + { 18765, 36175 }, + { 18766, 26188 }, + { 18767, 19978 }, + { 18768, 23578 }, + { 18769, 35059 }, + { 18770, 26786 }, + { 18771, 25422 }, + { 18772, 31245 }, + { 18773, 28903 }, + { 18774, 33421 }, + { 18775, 21242 }, + { 18776, 38902 }, + { 18777, 23569 }, + { 18778, 21736 }, + { 18779, 37045 }, + { 18780, 32461 }, + { 18781, 22882 }, + { 18782, 36170 }, + { 18783, 34503 }, + { 18784, 33292 }, + { 18785, 33293 }, + { 18786, 36198 }, + { 18787, 25668 }, + { 18788, 23556 }, + { 18789, 24913 }, + { 18790, 28041 }, + { 18791, 31038 }, + { 18792, 35774 }, + { 18793, 30775 }, + { 18794, 30003 }, + { 18795, 21627 }, + { 18796, 20280 }, + { 18797, 36523 }, + { 18798, 28145 }, + { 18799, 23072 }, + { 18800, 32453 }, + { 18801, 31070 }, + { 18802, 27784 }, + { 18803, 23457 }, + { 18804, 23158 }, + { 18805, 29978 }, + { 18806, 32958 }, + { 18807, 24910 }, + { 18808, 28183 }, + { 18809, 22768 }, + { 18810, 29983 }, + { 18811, 29989 }, + { 18812, 29298 }, + { 18813, 21319 }, + { 18814, 32499 }, + { 18977, 30465 }, + { 18978, 30427 }, + { 18979, 21097 }, + { 18980, 32988 }, + { 18981, 22307 }, + { 18982, 24072 }, + { 18983, 22833 }, + { 18984, 29422 }, + { 18985, 26045 }, + { 18986, 28287 }, + { 18987, 35799 }, + { 18988, 23608 }, + { 18989, 34417 }, + { 18990, 21313 }, + { 18991, 30707 }, + { 18992, 25342 }, + { 18993, 26102 }, + { 18994, 20160 }, + { 18995, 39135 }, + { 18996, 34432 }, + { 18997, 23454 }, + { 18998, 35782 }, + { 18999, 21490 }, + { 19000, 30690 }, + { 19001, 20351 }, + { 19002, 23630 }, + { 19003, 39542 }, + { 19004, 22987 }, + { 19005, 24335 }, + { 19006, 31034 }, + { 19007, 22763 }, + { 19008, 19990 }, + { 19009, 26623 }, + { 19010, 20107 }, + { 19011, 25325 }, + { 19012, 35475 }, + { 19013, 36893 }, + { 19014, 21183 }, + { 19015, 26159 }, + { 19016, 21980 }, + { 19017, 22124 }, + { 19018, 36866 }, + { 19019, 20181 }, + { 19020, 20365 }, + { 19021, 37322 }, + { 19022, 39280 }, + { 19023, 27663 }, + { 19024, 24066 }, + { 19025, 24643 }, + { 19026, 23460 }, + { 19027, 35270 }, + { 19028, 35797 }, + { 19029, 25910 }, + { 19030, 25163 }, + { 19031, 39318 }, + { 19032, 23432 }, + { 19033, 23551 }, + { 19034, 25480 }, + { 19035, 21806 }, + { 19036, 21463 }, + { 19037, 30246 }, + { 19038, 20861 }, + { 19039, 34092 }, + { 19040, 26530 }, + { 19041, 26803 }, + { 19042, 27530 }, + { 19043, 25234 }, + { 19044, 36755 }, + { 19045, 21460 }, + { 19046, 33298 }, + { 19047, 28113 }, + { 19048, 30095 }, + { 19049, 20070 }, + { 19050, 36174 }, + { 19051, 23408 }, + { 19052, 29087 }, + { 19053, 34223 }, + { 19054, 26257 }, + { 19055, 26329 }, + { 19056, 32626 }, + { 19057, 34560 }, + { 19058, 40653 }, + { 19059, 40736 }, + { 19060, 23646 }, + { 19061, 26415 }, + { 19062, 36848 }, + { 19063, 26641 }, + { 19064, 26463 }, + { 19065, 25101 }, + { 19066, 31446 }, + { 19067, 22661 }, + { 19068, 24246 }, + { 19069, 25968 }, + { 19070, 28465 }, + { 19233, 24661 }, + { 19234, 21047 }, + { 19235, 32781 }, + { 19236, 25684 }, + { 19237, 34928 }, + { 19238, 29993 }, + { 19239, 24069 }, + { 19240, 26643 }, + { 19241, 25332 }, + { 19242, 38684 }, + { 19243, 21452 }, + { 19244, 29245 }, + { 19245, 35841 }, + { 19246, 27700 }, + { 19247, 30561 }, + { 19248, 31246 }, + { 19249, 21550 }, + { 19250, 30636 }, + { 19251, 39034 }, + { 19252, 33308 }, + { 19253, 35828 }, + { 19254, 30805 }, + { 19255, 26388 }, + { 19256, 28865 }, + { 19257, 26031 }, + { 19258, 25749 }, + { 19259, 22070 }, + { 19260, 24605 }, + { 19261, 31169 }, + { 19262, 21496 }, + { 19263, 19997 }, + { 19264, 27515 }, + { 19265, 32902 }, + { 19266, 23546 }, + { 19267, 21987 }, + { 19268, 22235 }, + { 19269, 20282 }, + { 19270, 20284 }, + { 19271, 39282 }, + { 19272, 24051 }, + { 19273, 26494 }, + { 19274, 32824 }, + { 19275, 24578 }, + { 19276, 39042 }, + { 19277, 36865 }, + { 19278, 23435 }, + { 19279, 35772 }, + { 19280, 35829 }, + { 19281, 25628 }, + { 19282, 33368 }, + { 19283, 25822 }, + { 19284, 22013 }, + { 19285, 33487 }, + { 19286, 37221 }, + { 19287, 20439 }, + { 19288, 32032 }, + { 19289, 36895 }, + { 19290, 31903 }, + { 19291, 20723 }, + { 19292, 22609 }, + { 19293, 28335 }, + { 19294, 23487 }, + { 19295, 35785 }, + { 19296, 32899 }, + { 19297, 37240 }, + { 19298, 33948 }, + { 19299, 31639 }, + { 19300, 34429 }, + { 19301, 38539 }, + { 19302, 38543 }, + { 19303, 32485 }, + { 19304, 39635 }, + { 19305, 30862 }, + { 19306, 23681 }, + { 19307, 31319 }, + { 19308, 36930 }, + { 19309, 38567 }, + { 19310, 31071 }, + { 19311, 23385 }, + { 19312, 25439 }, + { 19313, 31499 }, + { 19314, 34001 }, + { 19315, 26797 }, + { 19316, 21766 }, + { 19317, 32553 }, + { 19318, 29712 }, + { 19319, 32034 }, + { 19320, 38145 }, + { 19321, 25152 }, + { 19322, 22604 }, + { 19323, 20182 }, + { 19324, 23427 }, + { 19325, 22905 }, + { 19326, 22612 }, + { 19489, 29549 }, + { 19490, 25374 }, + { 19491, 36427 }, + { 19492, 36367 }, + { 19493, 32974 }, + { 19494, 33492 }, + { 19495, 25260 }, + { 19496, 21488 }, + { 19497, 27888 }, + { 19498, 37214 }, + { 19499, 22826 }, + { 19500, 24577 }, + { 19501, 27760 }, + { 19502, 22349 }, + { 19503, 25674 }, + { 19504, 36138 }, + { 19505, 30251 }, + { 19506, 28393 }, + { 19507, 22363 }, + { 19508, 27264 }, + { 19509, 30192 }, + { 19510, 28525 }, + { 19511, 35885 }, + { 19512, 35848 }, + { 19513, 22374 }, + { 19514, 27631 }, + { 19515, 34962 }, + { 19516, 30899 }, + { 19517, 25506 }, + { 19518, 21497 }, + { 19519, 28845 }, + { 19520, 27748 }, + { 19521, 22616 }, + { 19522, 25642 }, + { 19523, 22530 }, + { 19524, 26848 }, + { 19525, 33179 }, + { 19526, 21776 }, + { 19527, 31958 }, + { 19528, 20504 }, + { 19529, 36538 }, + { 19530, 28108 }, + { 19531, 36255 }, + { 19532, 28907 }, + { 19533, 25487 }, + { 19534, 28059 }, + { 19535, 28372 }, + { 19536, 32486 }, + { 19537, 33796 }, + { 19538, 26691 }, + { 19539, 36867 }, + { 19540, 28120 }, + { 19541, 38518 }, + { 19542, 35752 }, + { 19543, 22871 }, + { 19544, 29305 }, + { 19545, 34276 }, + { 19546, 33150 }, + { 19547, 30140 }, + { 19548, 35466 }, + { 19549, 26799 }, + { 19550, 21076 }, + { 19551, 36386 }, + { 19552, 38161 }, + { 19553, 25552 }, + { 19554, 39064 }, + { 19555, 36420 }, + { 19556, 21884 }, + { 19557, 20307 }, + { 19558, 26367 }, + { 19559, 22159 }, + { 19560, 24789 }, + { 19561, 28053 }, + { 19562, 21059 }, + { 19563, 23625 }, + { 19564, 22825 }, + { 19565, 28155 }, + { 19566, 22635 }, + { 19567, 30000 }, + { 19568, 29980 }, + { 19569, 24684 }, + { 19570, 33300 }, + { 19571, 33094 }, + { 19572, 25361 }, + { 19573, 26465 }, + { 19574, 36834 }, + { 19575, 30522 }, + { 19576, 36339 }, + { 19577, 36148 }, + { 19578, 38081 }, + { 19579, 24086 }, + { 19580, 21381 }, + { 19581, 21548 }, + { 19582, 28867 }, + { 19745, 27712 }, + { 19746, 24311 }, + { 19747, 20572 }, + { 19748, 20141 }, + { 19749, 24237 }, + { 19750, 25402 }, + { 19751, 33351 }, + { 19752, 36890 }, + { 19753, 26704 }, + { 19754, 37230 }, + { 19755, 30643 }, + { 19756, 21516 }, + { 19757, 38108 }, + { 19758, 24420 }, + { 19759, 31461 }, + { 19760, 26742 }, + { 19761, 25413 }, + { 19762, 31570 }, + { 19763, 32479 }, + { 19764, 30171 }, + { 19765, 20599 }, + { 19766, 25237 }, + { 19767, 22836 }, + { 19768, 36879 }, + { 19769, 20984 }, + { 19770, 31171 }, + { 19771, 31361 }, + { 19772, 22270 }, + { 19773, 24466 }, + { 19774, 36884 }, + { 19775, 28034 }, + { 19776, 23648 }, + { 19777, 22303 }, + { 19778, 21520 }, + { 19779, 20820 }, + { 19780, 28237 }, + { 19781, 22242 }, + { 19782, 25512 }, + { 19783, 39059 }, + { 19784, 33151 }, + { 19785, 34581 }, + { 19786, 35114 }, + { 19787, 36864 }, + { 19788, 21534 }, + { 19789, 23663 }, + { 19790, 33216 }, + { 19791, 25302 }, + { 19792, 25176 }, + { 19793, 33073 }, + { 19794, 40501 }, + { 19795, 38464 }, + { 19796, 39534 }, + { 19797, 39548 }, + { 19798, 26925 }, + { 19799, 22949 }, + { 19800, 25299 }, + { 19801, 21822 }, + { 19802, 25366 }, + { 19803, 21703 }, + { 19804, 34521 }, + { 19805, 27964 }, + { 19806, 23043 }, + { 19807, 29926 }, + { 19808, 34972 }, + { 19809, 27498 }, + { 19810, 22806 }, + { 19811, 35916 }, + { 19812, 24367 }, + { 19813, 28286 }, + { 19814, 29609 }, + { 19815, 39037 }, + { 19816, 20024 }, + { 19817, 28919 }, + { 19818, 23436 }, + { 19819, 30871 }, + { 19820, 25405 }, + { 19821, 26202 }, + { 19822, 30358 }, + { 19823, 24779 }, + { 19824, 23451 }, + { 19825, 23113 }, + { 19826, 19975 }, + { 19827, 33109 }, + { 19828, 27754 }, + { 19829, 29579 }, + { 19830, 20129 }, + { 19831, 26505 }, + { 19832, 32593 }, + { 19833, 24448 }, + { 19834, 26106 }, + { 19835, 26395 }, + { 19836, 24536 }, + { 19837, 22916 }, + { 19838, 23041 }, + { 20001, 24013 }, + { 20002, 24494 }, + { 20003, 21361 }, + { 20004, 38886 }, + { 20005, 36829 }, + { 20006, 26693 }, + { 20007, 22260 }, + { 20008, 21807 }, + { 20009, 24799 }, + { 20010, 20026 }, + { 20011, 28493 }, + { 20012, 32500 }, + { 20013, 33479 }, + { 20014, 33806 }, + { 20015, 22996 }, + { 20016, 20255 }, + { 20017, 20266 }, + { 20018, 23614 }, + { 20019, 32428 }, + { 20020, 26410 }, + { 20021, 34074 }, + { 20022, 21619 }, + { 20023, 30031 }, + { 20024, 32963 }, + { 20025, 21890 }, + { 20026, 39759 }, + { 20027, 20301 }, + { 20028, 28205 }, + { 20029, 35859 }, + { 20030, 23561 }, + { 20031, 24944 }, + { 20032, 21355 }, + { 20033, 30239 }, + { 20034, 28201 }, + { 20035, 34442 }, + { 20036, 25991 }, + { 20037, 38395 }, + { 20038, 32441 }, + { 20039, 21563 }, + { 20040, 31283 }, + { 20041, 32010 }, + { 20042, 38382 }, + { 20043, 21985 }, + { 20044, 32705 }, + { 20045, 29934 }, + { 20046, 25373 }, + { 20047, 34583 }, + { 20048, 28065 }, + { 20049, 31389 }, + { 20050, 25105 }, + { 20051, 26017 }, + { 20052, 21351 }, + { 20053, 25569 }, + { 20054, 27779 }, + { 20055, 24043 }, + { 20056, 21596 }, + { 20057, 38056 }, + { 20058, 20044 }, + { 20059, 27745 }, + { 20060, 35820 }, + { 20061, 23627 }, + { 20062, 26080 }, + { 20063, 33436 }, + { 20064, 26791 }, + { 20065, 21566 }, + { 20066, 21556 }, + { 20067, 27595 }, + { 20068, 27494 }, + { 20069, 20116 }, + { 20070, 25410 }, + { 20071, 21320 }, + { 20072, 33310 }, + { 20073, 20237 }, + { 20074, 20398 }, + { 20075, 22366 }, + { 20076, 25098 }, + { 20077, 38654 }, + { 20078, 26212 }, + { 20079, 29289 }, + { 20080, 21247 }, + { 20081, 21153 }, + { 20082, 24735 }, + { 20083, 35823 }, + { 20084, 26132 }, + { 20085, 29081 }, + { 20086, 26512 }, + { 20087, 35199 }, + { 20088, 30802 }, + { 20089, 30717 }, + { 20090, 26224 }, + { 20091, 22075 }, + { 20092, 21560 }, + { 20093, 38177 }, + { 20094, 29306 }, + { 20257, 31232 }, + { 20258, 24687 }, + { 20259, 24076 }, + { 20260, 24713 }, + { 20261, 33181 }, + { 20262, 22805 }, + { 20263, 24796 }, + { 20264, 29060 }, + { 20265, 28911 }, + { 20266, 28330 }, + { 20267, 27728 }, + { 20268, 29312 }, + { 20269, 27268 }, + { 20270, 34989 }, + { 20271, 24109 }, + { 20272, 20064 }, + { 20273, 23219 }, + { 20274, 21916 }, + { 20275, 38115 }, + { 20276, 27927 }, + { 20277, 31995 }, + { 20278, 38553 }, + { 20279, 25103 }, + { 20280, 32454 }, + { 20281, 30606 }, + { 20282, 34430 }, + { 20283, 21283 }, + { 20284, 38686 }, + { 20285, 36758 }, + { 20286, 26247 }, + { 20287, 23777 }, + { 20288, 20384 }, + { 20289, 29421 }, + { 20290, 19979 }, + { 20291, 21414 }, + { 20292, 22799 }, + { 20293, 21523 }, + { 20294, 25472 }, + { 20295, 38184 }, + { 20296, 20808 }, + { 20297, 20185 }, + { 20298, 40092 }, + { 20299, 32420 }, + { 20300, 21688 }, + { 20301, 36132 }, + { 20302, 34900 }, + { 20303, 33335 }, + { 20304, 38386 }, + { 20305, 28046 }, + { 20306, 24358 }, + { 20307, 23244 }, + { 20308, 26174 }, + { 20309, 38505 }, + { 20310, 29616 }, + { 20311, 29486 }, + { 20312, 21439 }, + { 20313, 33146 }, + { 20314, 39301 }, + { 20315, 32673 }, + { 20316, 23466 }, + { 20317, 38519 }, + { 20318, 38480 }, + { 20319, 32447 }, + { 20320, 30456 }, + { 20321, 21410 }, + { 20322, 38262 }, + { 20323, 39321 }, + { 20324, 31665 }, + { 20325, 35140 }, + { 20326, 28248 }, + { 20327, 20065 }, + { 20328, 32724 }, + { 20329, 31077 }, + { 20330, 35814 }, + { 20331, 24819 }, + { 20332, 21709 }, + { 20333, 20139 }, + { 20334, 39033 }, + { 20335, 24055 }, + { 20336, 27233 }, + { 20337, 20687 }, + { 20338, 21521 }, + { 20339, 35937 }, + { 20340, 33831 }, + { 20341, 30813 }, + { 20342, 38660 }, + { 20343, 21066 }, + { 20344, 21742 }, + { 20345, 22179 }, + { 20346, 38144 }, + { 20347, 28040 }, + { 20348, 23477 }, + { 20349, 28102 }, + { 20350, 26195 }, + { 20513, 23567 }, + { 20514, 23389 }, + { 20515, 26657 }, + { 20516, 32918 }, + { 20517, 21880 }, + { 20518, 31505 }, + { 20519, 25928 }, + { 20520, 26964 }, + { 20521, 20123 }, + { 20522, 27463 }, + { 20523, 34638 }, + { 20524, 38795 }, + { 20525, 21327 }, + { 20526, 25375 }, + { 20527, 25658 }, + { 20528, 37034 }, + { 20529, 26012 }, + { 20530, 32961 }, + { 20531, 35856 }, + { 20532, 20889 }, + { 20533, 26800 }, + { 20534, 21368 }, + { 20535, 34809 }, + { 20536, 25032 }, + { 20537, 27844 }, + { 20538, 27899 }, + { 20539, 35874 }, + { 20540, 23633 }, + { 20541, 34218 }, + { 20542, 33455 }, + { 20543, 38156 }, + { 20544, 27427 }, + { 20545, 36763 }, + { 20546, 26032 }, + { 20547, 24571 }, + { 20548, 24515 }, + { 20549, 20449 }, + { 20550, 34885 }, + { 20551, 26143 }, + { 20552, 33125 }, + { 20553, 29481 }, + { 20554, 24826 }, + { 20555, 20852 }, + { 20556, 21009 }, + { 20557, 22411 }, + { 20558, 24418 }, + { 20559, 37026 }, + { 20560, 34892 }, + { 20561, 37266 }, + { 20562, 24184 }, + { 20563, 26447 }, + { 20564, 24615 }, + { 20565, 22995 }, + { 20566, 20804 }, + { 20567, 20982 }, + { 20568, 33016 }, + { 20569, 21256 }, + { 20570, 27769 }, + { 20571, 38596 }, + { 20572, 29066 }, + { 20573, 20241 }, + { 20574, 20462 }, + { 20575, 32670 }, + { 20576, 26429 }, + { 20577, 21957 }, + { 20578, 38152 }, + { 20579, 31168 }, + { 20580, 34966 }, + { 20581, 32483 }, + { 20582, 22687 }, + { 20583, 25100 }, + { 20584, 38656 }, + { 20585, 34394 }, + { 20586, 22040 }, + { 20587, 39035 }, + { 20588, 24464 }, + { 20589, 35768 }, + { 20590, 33988 }, + { 20591, 37207 }, + { 20592, 21465 }, + { 20593, 26093 }, + { 20594, 24207 }, + { 20595, 30044 }, + { 20596, 24676 }, + { 20597, 32110 }, + { 20598, 23167 }, + { 20599, 32490 }, + { 20600, 32493 }, + { 20601, 36713 }, + { 20602, 21927 }, + { 20603, 23459 }, + { 20604, 24748 }, + { 20605, 26059 }, + { 20606, 29572 }, + { 20769, 36873 }, + { 20770, 30307 }, + { 20771, 30505 }, + { 20772, 32474 }, + { 20773, 38772 }, + { 20774, 34203 }, + { 20775, 23398 }, + { 20776, 31348 }, + { 20777, 38634 }, + { 20778, 34880 }, + { 20779, 21195 }, + { 20780, 29071 }, + { 20781, 24490 }, + { 20782, 26092 }, + { 20783, 35810 }, + { 20784, 23547 }, + { 20785, 39535 }, + { 20786, 24033 }, + { 20787, 27529 }, + { 20788, 27739 }, + { 20789, 35757 }, + { 20790, 35759 }, + { 20791, 36874 }, + { 20792, 36805 }, + { 20793, 21387 }, + { 20794, 25276 }, + { 20795, 40486 }, + { 20796, 40493 }, + { 20797, 21568 }, + { 20798, 20011 }, + { 20799, 33469 }, + { 20800, 29273 }, + { 20801, 34460 }, + { 20802, 23830 }, + { 20803, 34905 }, + { 20804, 28079 }, + { 20805, 38597 }, + { 20806, 21713 }, + { 20807, 20122 }, + { 20808, 35766 }, + { 20809, 28937 }, + { 20810, 21693 }, + { 20811, 38409 }, + { 20812, 28895 }, + { 20813, 28153 }, + { 20814, 30416 }, + { 20815, 20005 }, + { 20816, 30740 }, + { 20817, 34578 }, + { 20818, 23721 }, + { 20819, 24310 }, + { 20820, 35328 }, + { 20821, 39068 }, + { 20822, 38414 }, + { 20823, 28814 }, + { 20824, 27839 }, + { 20825, 22852 }, + { 20826, 25513 }, + { 20827, 30524 }, + { 20828, 34893 }, + { 20829, 28436 }, + { 20830, 33395 }, + { 20831, 22576 }, + { 20832, 29141 }, + { 20833, 21388 }, + { 20834, 30746 }, + { 20835, 38593 }, + { 20836, 21761 }, + { 20837, 24422 }, + { 20838, 28976 }, + { 20839, 23476 }, + { 20840, 35866 }, + { 20841, 39564 }, + { 20842, 27523 }, + { 20843, 22830 }, + { 20844, 40495 }, + { 20845, 31207 }, + { 20846, 26472 }, + { 20847, 25196 }, + { 20848, 20335 }, + { 20849, 30113 }, + { 20850, 32650 }, + { 20851, 27915 }, + { 20852, 38451 }, + { 20853, 27687 }, + { 20854, 20208 }, + { 20855, 30162 }, + { 20856, 20859 }, + { 20857, 26679 }, + { 20858, 28478 }, + { 20859, 36992 }, + { 20860, 33136 }, + { 20861, 22934 }, + { 20862, 29814 }, + { 21025, 25671 }, + { 21026, 23591 }, + { 21027, 36965 }, + { 21028, 31377 }, + { 21029, 35875 }, + { 21030, 23002 }, + { 21031, 21676 }, + { 21032, 33280 }, + { 21033, 33647 }, + { 21034, 35201 }, + { 21035, 32768 }, + { 21036, 26928 }, + { 21037, 22094 }, + { 21038, 32822 }, + { 21039, 29239 }, + { 21040, 37326 }, + { 21041, 20918 }, + { 21042, 20063 }, + { 21043, 39029 }, + { 21044, 25494 }, + { 21045, 19994 }, + { 21046, 21494 }, + { 21047, 26355 }, + { 21048, 33099 }, + { 21049, 22812 }, + { 21050, 28082 }, + { 21051, 19968 }, + { 21052, 22777 }, + { 21053, 21307 }, + { 21054, 25558 }, + { 21055, 38129 }, + { 21056, 20381 }, + { 21057, 20234 }, + { 21058, 34915 }, + { 21059, 39056 }, + { 21060, 22839 }, + { 21061, 36951 }, + { 21062, 31227 }, + { 21063, 20202 }, + { 21064, 33008 }, + { 21065, 30097 }, + { 21066, 27778 }, + { 21067, 23452 }, + { 21068, 23016 }, + { 21069, 24413 }, + { 21070, 26885 }, + { 21071, 34433 }, + { 21072, 20506 }, + { 21073, 24050 }, + { 21074, 20057 }, + { 21075, 30691 }, + { 21076, 20197 }, + { 21077, 33402 }, + { 21078, 25233 }, + { 21079, 26131 }, + { 21080, 37009 }, + { 21081, 23673 }, + { 21082, 20159 }, + { 21083, 24441 }, + { 21084, 33222 }, + { 21085, 36920 }, + { 21086, 32900 }, + { 21087, 30123 }, + { 21088, 20134 }, + { 21089, 35028 }, + { 21090, 24847 }, + { 21091, 27589 }, + { 21092, 24518 }, + { 21093, 20041 }, + { 21094, 30410 }, + { 21095, 28322 }, + { 21096, 35811 }, + { 21097, 35758 }, + { 21098, 35850 }, + { 21099, 35793 }, + { 21100, 24322 }, + { 21101, 32764 }, + { 21102, 32716 }, + { 21103, 32462 }, + { 21104, 33589 }, + { 21105, 33643 }, + { 21106, 22240 }, + { 21107, 27575 }, + { 21108, 38899 }, + { 21109, 38452 }, + { 21110, 23035 }, + { 21111, 21535 }, + { 21112, 38134 }, + { 21113, 28139 }, + { 21114, 23493 }, + { 21115, 39278 }, + { 21116, 23609 }, + { 21117, 24341 }, + { 21118, 38544 }, + { 21281, 21360 }, + { 21282, 33521 }, + { 21283, 27185 }, + { 21284, 23156 }, + { 21285, 40560 }, + { 21286, 24212 }, + { 21287, 32552 }, + { 21288, 33721 }, + { 21289, 33828 }, + { 21290, 33829 }, + { 21291, 33639 }, + { 21292, 34631 }, + { 21293, 36814 }, + { 21294, 36194 }, + { 21295, 30408 }, + { 21296, 24433 }, + { 21297, 39062 }, + { 21298, 30828 }, + { 21299, 26144 }, + { 21300, 21727 }, + { 21301, 25317 }, + { 21302, 20323 }, + { 21303, 33219 }, + { 21304, 30152 }, + { 21305, 24248 }, + { 21306, 38605 }, + { 21307, 36362 }, + { 21308, 34553 }, + { 21309, 21647 }, + { 21310, 27891 }, + { 21311, 28044 }, + { 21312, 27704 }, + { 21313, 24703 }, + { 21314, 21191 }, + { 21315, 29992 }, + { 21316, 24189 }, + { 21317, 20248 }, + { 21318, 24736 }, + { 21319, 24551 }, + { 21320, 23588 }, + { 21321, 30001 }, + { 21322, 37038 }, + { 21323, 38080 }, + { 21324, 29369 }, + { 21325, 27833 }, + { 21326, 28216 }, + { 21327, 37193 }, + { 21328, 26377 }, + { 21329, 21451 }, + { 21330, 21491 }, + { 21331, 20305 }, + { 21332, 37321 }, + { 21333, 35825 }, + { 21334, 21448 }, + { 21335, 24188 }, + { 21336, 36802 }, + { 21337, 28132 }, + { 21338, 20110 }, + { 21339, 30402 }, + { 21340, 27014 }, + { 21341, 34398 }, + { 21342, 24858 }, + { 21343, 33286 }, + { 21344, 20313 }, + { 21345, 20446 }, + { 21346, 36926 }, + { 21347, 40060 }, + { 21348, 24841 }, + { 21349, 28189 }, + { 21350, 28180 }, + { 21351, 38533 }, + { 21352, 20104 }, + { 21353, 23089 }, + { 21354, 38632 }, + { 21355, 19982 }, + { 21356, 23679 }, + { 21357, 31161 }, + { 21358, 23431 }, + { 21359, 35821 }, + { 21360, 32701 }, + { 21361, 29577 }, + { 21362, 22495 }, + { 21363, 33419 }, + { 21364, 37057 }, + { 21365, 21505 }, + { 21366, 36935 }, + { 21367, 21947 }, + { 21368, 23786 }, + { 21369, 24481 }, + { 21370, 24840 }, + { 21371, 27442 }, + { 21372, 29425 }, + { 21373, 32946 }, + { 21374, 35465 }, + { 21537, 28020 }, + { 21538, 23507 }, + { 21539, 35029 }, + { 21540, 39044 }, + { 21541, 35947 }, + { 21542, 39533 }, + { 21543, 40499 }, + { 21544, 28170 }, + { 21545, 20900 }, + { 21546, 20803 }, + { 21547, 22435 }, + { 21548, 34945 }, + { 21549, 21407 }, + { 21550, 25588 }, + { 21551, 36757 }, + { 21552, 22253 }, + { 21553, 21592 }, + { 21554, 22278 }, + { 21555, 29503 }, + { 21556, 28304 }, + { 21557, 32536 }, + { 21558, 36828 }, + { 21559, 33489 }, + { 21560, 24895 }, + { 21561, 24616 }, + { 21562, 38498 }, + { 21563, 26352 }, + { 21564, 32422 }, + { 21565, 36234 }, + { 21566, 36291 }, + { 21567, 38053 }, + { 21568, 23731 }, + { 21569, 31908 }, + { 21570, 26376 }, + { 21571, 24742 }, + { 21572, 38405 }, + { 21573, 32792 }, + { 21574, 20113 }, + { 21575, 37095 }, + { 21576, 21248 }, + { 21577, 38504 }, + { 21578, 20801 }, + { 21579, 36816 }, + { 21580, 34164 }, + { 21581, 37213 }, + { 21582, 26197 }, + { 21583, 38901 }, + { 21584, 23381 }, + { 21585, 21277 }, + { 21586, 30776 }, + { 21587, 26434 }, + { 21588, 26685 }, + { 21589, 21705 }, + { 21590, 28798 }, + { 21591, 23472 }, + { 21592, 36733 }, + { 21593, 20877 }, + { 21594, 22312 }, + { 21595, 21681 }, + { 21596, 25874 }, + { 21597, 26242 }, + { 21598, 36190 }, + { 21599, 36163 }, + { 21600, 33039 }, + { 21601, 33900 }, + { 21602, 36973 }, + { 21603, 31967 }, + { 21604, 20991 }, + { 21605, 34299 }, + { 21606, 26531 }, + { 21607, 26089 }, + { 21608, 28577 }, + { 21609, 34468 }, + { 21610, 36481 }, + { 21611, 22122 }, + { 21612, 36896 }, + { 21613, 30338 }, + { 21614, 28790 }, + { 21615, 29157 }, + { 21616, 36131 }, + { 21617, 25321 }, + { 21618, 21017 }, + { 21619, 27901 }, + { 21620, 36156 }, + { 21621, 24590 }, + { 21622, 22686 }, + { 21623, 24974 }, + { 21624, 26366 }, + { 21625, 36192 }, + { 21626, 25166 }, + { 21627, 21939 }, + { 21628, 28195 }, + { 21629, 26413 }, + { 21630, 36711 }, + { 21793, 38113 }, + { 21794, 38392 }, + { 21795, 30504 }, + { 21796, 26629 }, + { 21797, 27048 }, + { 21798, 21643 }, + { 21799, 20045 }, + { 21800, 28856 }, + { 21801, 35784 }, + { 21802, 25688 }, + { 21803, 25995 }, + { 21804, 23429 }, + { 21805, 31364 }, + { 21806, 20538 }, + { 21807, 23528 }, + { 21808, 30651 }, + { 21809, 27617 }, + { 21810, 35449 }, + { 21811, 31896 }, + { 21812, 27838 }, + { 21813, 30415 }, + { 21814, 26025 }, + { 21815, 36759 }, + { 21816, 23853 }, + { 21817, 23637 }, + { 21818, 34360 }, + { 21819, 26632 }, + { 21820, 21344 }, + { 21821, 25112 }, + { 21822, 31449 }, + { 21823, 28251 }, + { 21824, 32509 }, + { 21825, 27167 }, + { 21826, 31456 }, + { 21827, 24432 }, + { 21828, 28467 }, + { 21829, 24352 }, + { 21830, 25484 }, + { 21831, 28072 }, + { 21832, 26454 }, + { 21833, 19976 }, + { 21834, 24080 }, + { 21835, 36134 }, + { 21836, 20183 }, + { 21837, 32960 }, + { 21838, 30260 }, + { 21839, 38556 }, + { 21840, 25307 }, + { 21841, 26157 }, + { 21842, 25214 }, + { 21843, 27836 }, + { 21844, 36213 }, + { 21845, 29031 }, + { 21846, 32617 }, + { 21847, 20806 }, + { 21848, 32903 }, + { 21849, 21484 }, + { 21850, 36974 }, + { 21851, 25240 }, + { 21852, 21746 }, + { 21853, 34544 }, + { 21854, 36761 }, + { 21855, 32773 }, + { 21856, 38167 }, + { 21857, 34071 }, + { 21858, 36825 }, + { 21859, 27993 }, + { 21860, 29645 }, + { 21861, 26015 }, + { 21862, 30495 }, + { 21863, 29956 }, + { 21864, 30759 }, + { 21865, 33275 }, + { 21866, 36126 }, + { 21867, 38024 }, + { 21868, 20390 }, + { 21869, 26517 }, + { 21870, 30137 }, + { 21871, 35786 }, + { 21872, 38663 }, + { 21873, 25391 }, + { 21874, 38215 }, + { 21875, 38453 }, + { 21876, 33976 }, + { 21877, 25379 }, + { 21878, 30529 }, + { 21879, 24449 }, + { 21880, 29424 }, + { 21881, 20105 }, + { 21882, 24596 }, + { 21883, 25972 }, + { 21884, 25327 }, + { 21885, 27491 }, + { 21886, 25919 }, + { 22049, 24103 }, + { 22050, 30151 }, + { 22051, 37073 }, + { 22052, 35777 }, + { 22053, 33437 }, + { 22054, 26525 }, + { 22055, 25903 }, + { 22056, 21553 }, + { 22057, 34584 }, + { 22058, 30693 }, + { 22059, 32930 }, + { 22060, 33026 }, + { 22061, 27713 }, + { 22062, 20043 }, + { 22063, 32455 }, + { 22064, 32844 }, + { 22065, 30452 }, + { 22066, 26893 }, + { 22067, 27542 }, + { 22068, 25191 }, + { 22069, 20540 }, + { 22070, 20356 }, + { 22071, 22336 }, + { 22072, 25351 }, + { 22073, 27490 }, + { 22074, 36286 }, + { 22075, 21482 }, + { 22076, 26088 }, + { 22077, 32440 }, + { 22078, 24535 }, + { 22079, 25370 }, + { 22080, 25527 }, + { 22081, 33267 }, + { 22082, 33268 }, + { 22083, 32622 }, + { 22084, 24092 }, + { 22085, 23769 }, + { 22086, 21046 }, + { 22087, 26234 }, + { 22088, 31209 }, + { 22089, 31258 }, + { 22090, 36136 }, + { 22091, 28825 }, + { 22092, 30164 }, + { 22093, 28382 }, + { 22094, 27835 }, + { 22095, 31378 }, + { 22096, 20013 }, + { 22097, 30405 }, + { 22098, 24544 }, + { 22099, 38047 }, + { 22100, 34935 }, + { 22101, 32456 }, + { 22102, 31181 }, + { 22103, 32959 }, + { 22104, 37325 }, + { 22105, 20210 }, + { 22106, 20247 }, + { 22107, 33311 }, + { 22108, 21608 }, + { 22109, 24030 }, + { 22110, 27954 }, + { 22111, 35788 }, + { 22112, 31909 }, + { 22113, 36724 }, + { 22114, 32920 }, + { 22115, 24090 }, + { 22116, 21650 }, + { 22117, 30385 }, + { 22118, 23449 }, + { 22119, 26172 }, + { 22120, 39588 }, + { 22121, 29664 }, + { 22122, 26666 }, + { 22123, 34523 }, + { 22124, 26417 }, + { 22125, 29482 }, + { 22126, 35832 }, + { 22127, 35803 }, + { 22128, 36880 }, + { 22129, 31481 }, + { 22130, 28891 }, + { 22131, 29038 }, + { 22132, 25284 }, + { 22133, 30633 }, + { 22134, 22065 }, + { 22135, 20027 }, + { 22136, 33879 }, + { 22137, 26609 }, + { 22138, 21161 }, + { 22139, 34496 }, + { 22140, 36142 }, + { 22141, 38136 }, + { 22142, 31569 }, + { 22305, 20303 }, + { 22306, 27880 }, + { 22307, 31069 }, + { 22308, 39547 }, + { 22309, 25235 }, + { 22310, 29226 }, + { 22311, 25341 }, + { 22312, 19987 }, + { 22313, 30742 }, + { 22314, 36716 }, + { 22315, 25776 }, + { 22316, 36186 }, + { 22317, 31686 }, + { 22318, 26729 }, + { 22319, 24196 }, + { 22320, 35013 }, + { 22321, 22918 }, + { 22322, 25758 }, + { 22323, 22766 }, + { 22324, 29366 }, + { 22325, 26894 }, + { 22326, 38181 }, + { 22327, 36861 }, + { 22328, 36184 }, + { 22329, 22368 }, + { 22330, 32512 }, + { 22331, 35846 }, + { 22332, 20934 }, + { 22333, 25417 }, + { 22334, 25305 }, + { 22335, 21331 }, + { 22336, 26700 }, + { 22337, 29730 }, + { 22338, 33537 }, + { 22339, 37196 }, + { 22340, 21828 }, + { 22341, 30528 }, + { 22342, 28796 }, + { 22343, 27978 }, + { 22344, 20857 }, + { 22345, 21672 }, + { 22346, 36164 }, + { 22347, 23039 }, + { 22348, 28363 }, + { 22349, 28100 }, + { 22350, 23388 }, + { 22351, 32043 }, + { 22352, 20180 }, + { 22353, 31869 }, + { 22354, 28371 }, + { 22355, 23376 }, + { 22356, 33258 }, + { 22357, 28173 }, + { 22358, 23383 }, + { 22359, 39683 }, + { 22360, 26837 }, + { 22361, 36394 }, + { 22362, 23447 }, + { 22363, 32508 }, + { 22364, 24635 }, + { 22365, 32437 }, + { 22366, 37049 }, + { 22367, 36208 }, + { 22368, 22863 }, + { 22369, 25549 }, + { 22370, 31199 }, + { 22371, 36275 }, + { 22372, 21330 }, + { 22373, 26063 }, + { 22374, 31062 }, + { 22375, 35781 }, + { 22376, 38459 }, + { 22377, 32452 }, + { 22378, 38075 }, + { 22379, 32386 }, + { 22380, 22068 }, + { 22381, 37257 }, + { 22382, 26368 }, + { 22383, 32618 }, + { 22384, 23562 }, + { 22385, 36981 }, + { 22386, 26152 }, + { 22387, 24038 }, + { 22388, 20304 }, + { 22389, 26590 }, + { 22390, 20570 }, + { 22391, 20316 }, + { 22392, 22352 }, + { 22393, 24231 }, + { 22561, 20109 }, + { 22562, 19980 }, + { 22563, 20800 }, + { 22564, 19984 }, + { 22565, 24319 }, + { 22566, 21317 }, + { 22567, 19989 }, + { 22568, 20120 }, + { 22569, 19998 }, + { 22570, 39730 }, + { 22571, 23404 }, + { 22572, 22121 }, + { 22573, 20008 }, + { 22574, 31162 }, + { 22575, 20031 }, + { 22576, 21269 }, + { 22577, 20039 }, + { 22578, 22829 }, + { 22579, 29243 }, + { 22580, 21358 }, + { 22581, 27664 }, + { 22582, 22239 }, + { 22583, 32996 }, + { 22584, 39319 }, + { 22585, 27603 }, + { 22586, 30590 }, + { 22587, 40727 }, + { 22588, 20022 }, + { 22589, 20127 }, + { 22590, 40720 }, + { 22591, 20060 }, + { 22592, 20073 }, + { 22593, 20115 }, + { 22594, 33416 }, + { 22595, 23387 }, + { 22596, 21868 }, + { 22597, 22031 }, + { 22598, 20164 }, + { 22599, 21389 }, + { 22600, 21405 }, + { 22601, 21411 }, + { 22602, 21413 }, + { 22603, 21422 }, + { 22604, 38757 }, + { 22605, 36189 }, + { 22606, 21274 }, + { 22607, 21493 }, + { 22608, 21286 }, + { 22609, 21294 }, + { 22610, 21310 }, + { 22611, 36188 }, + { 22612, 21350 }, + { 22613, 21347 }, + { 22614, 20994 }, + { 22615, 21000 }, + { 22616, 21006 }, + { 22617, 21037 }, + { 22618, 21043 }, + { 22619, 21055 }, + { 22620, 21056 }, + { 22621, 21068 }, + { 22622, 21086 }, + { 22623, 21089 }, + { 22624, 21084 }, + { 22625, 33967 }, + { 22626, 21117 }, + { 22627, 21122 }, + { 22628, 21121 }, + { 22629, 21136 }, + { 22630, 21139 }, + { 22631, 20866 }, + { 22632, 32596 }, + { 22633, 20155 }, + { 22634, 20163 }, + { 22635, 20169 }, + { 22636, 20162 }, + { 22637, 20200 }, + { 22638, 20193 }, + { 22639, 20203 }, + { 22640, 20190 }, + { 22641, 20251 }, + { 22642, 20211 }, + { 22643, 20258 }, + { 22644, 20324 }, + { 22645, 20213 }, + { 22646, 20261 }, + { 22647, 20263 }, + { 22648, 20233 }, + { 22649, 20267 }, + { 22650, 20318 }, + { 22651, 20327 }, + { 22652, 25912 }, + { 22653, 20314 }, + { 22654, 20317 }, + { 22817, 20319 }, + { 22818, 20311 }, + { 22819, 20274 }, + { 22820, 20285 }, + { 22821, 20342 }, + { 22822, 20340 }, + { 22823, 20369 }, + { 22824, 20361 }, + { 22825, 20355 }, + { 22826, 20367 }, + { 22827, 20350 }, + { 22828, 20347 }, + { 22829, 20394 }, + { 22830, 20348 }, + { 22831, 20396 }, + { 22832, 20372 }, + { 22833, 20454 }, + { 22834, 20456 }, + { 22835, 20458 }, + { 22836, 20421 }, + { 22837, 20442 }, + { 22838, 20451 }, + { 22839, 20444 }, + { 22840, 20433 }, + { 22841, 20447 }, + { 22842, 20472 }, + { 22843, 20521 }, + { 22844, 20556 }, + { 22845, 20467 }, + { 22846, 20524 }, + { 22847, 20495 }, + { 22848, 20526 }, + { 22849, 20525 }, + { 22850, 20478 }, + { 22851, 20508 }, + { 22852, 20492 }, + { 22853, 20517 }, + { 22854, 20520 }, + { 22855, 20606 }, + { 22856, 20547 }, + { 22857, 20565 }, + { 22858, 20552 }, + { 22859, 20558 }, + { 22860, 20588 }, + { 22861, 20603 }, + { 22862, 20645 }, + { 22863, 20647 }, + { 22864, 20649 }, + { 22865, 20666 }, + { 22866, 20694 }, + { 22867, 20742 }, + { 22868, 20717 }, + { 22869, 20716 }, + { 22870, 20710 }, + { 22871, 20718 }, + { 22872, 20743 }, + { 22873, 20747 }, + { 22874, 20189 }, + { 22875, 27709 }, + { 22876, 20312 }, + { 22877, 20325 }, + { 22878, 20430 }, + { 22879, 40864 }, + { 22880, 27718 }, + { 22881, 31860 }, + { 22882, 20846 }, + { 22883, 24061 }, + { 22884, 40649 }, + { 22885, 39320 }, + { 22886, 20865 }, + { 22887, 22804 }, + { 22888, 21241 }, + { 22889, 21261 }, + { 22890, 35335 }, + { 22891, 21264 }, + { 22892, 20971 }, + { 22893, 22809 }, + { 22894, 20821 }, + { 22895, 20128 }, + { 22896, 20822 }, + { 22897, 20147 }, + { 22898, 34926 }, + { 22899, 34980 }, + { 22900, 20149 }, + { 22901, 33044 }, + { 22902, 35026 }, + { 22903, 31104 }, + { 22904, 23348 }, + { 22905, 34819 }, + { 22906, 32696 }, + { 22907, 20907 }, + { 22908, 20913 }, + { 22909, 20925 }, + { 22910, 20924 }, + { 23073, 20935 }, + { 23074, 20886 }, + { 23075, 20898 }, + { 23076, 20901 }, + { 23077, 35744 }, + { 23078, 35750 }, + { 23079, 35751 }, + { 23080, 35754 }, + { 23081, 35764 }, + { 23082, 35765 }, + { 23083, 35767 }, + { 23084, 35778 }, + { 23085, 35779 }, + { 23086, 35787 }, + { 23087, 35791 }, + { 23088, 35790 }, + { 23089, 35794 }, + { 23090, 35795 }, + { 23091, 35796 }, + { 23092, 35798 }, + { 23093, 35800 }, + { 23094, 35801 }, + { 23095, 35804 }, + { 23096, 35807 }, + { 23097, 35808 }, + { 23098, 35812 }, + { 23099, 35816 }, + { 23100, 35817 }, + { 23101, 35822 }, + { 23102, 35824 }, + { 23103, 35827 }, + { 23104, 35830 }, + { 23105, 35833 }, + { 23106, 35836 }, + { 23107, 35839 }, + { 23108, 35840 }, + { 23109, 35842 }, + { 23110, 35844 }, + { 23111, 35847 }, + { 23112, 35852 }, + { 23113, 35855 }, + { 23114, 35857 }, + { 23115, 35858 }, + { 23116, 35860 }, + { 23117, 35861 }, + { 23118, 35862 }, + { 23119, 35865 }, + { 23120, 35867 }, + { 23121, 35864 }, + { 23122, 35869 }, + { 23123, 35871 }, + { 23124, 35872 }, + { 23125, 35873 }, + { 23126, 35877 }, + { 23127, 35879 }, + { 23128, 35882 }, + { 23129, 35883 }, + { 23130, 35886 }, + { 23131, 35887 }, + { 23132, 35890 }, + { 23133, 35891 }, + { 23134, 35893 }, + { 23135, 35894 }, + { 23136, 21353 }, + { 23137, 21370 }, + { 23138, 38429 }, + { 23139, 38434 }, + { 23140, 38433 }, + { 23141, 38449 }, + { 23142, 38442 }, + { 23143, 38461 }, + { 23144, 38460 }, + { 23145, 38466 }, + { 23146, 38473 }, + { 23147, 38484 }, + { 23148, 38495 }, + { 23149, 38503 }, + { 23150, 38508 }, + { 23151, 38514 }, + { 23152, 38516 }, + { 23153, 38536 }, + { 23154, 38541 }, + { 23155, 38551 }, + { 23156, 38576 }, + { 23157, 37015 }, + { 23158, 37019 }, + { 23159, 37021 }, + { 23160, 37017 }, + { 23161, 37036 }, + { 23162, 37025 }, + { 23163, 37044 }, + { 23164, 37043 }, + { 23165, 37046 }, + { 23166, 37050 }, + { 23329, 37048 }, + { 23330, 37040 }, + { 23331, 37071 }, + { 23332, 37061 }, + { 23333, 37054 }, + { 23334, 37072 }, + { 23335, 37060 }, + { 23336, 37063 }, + { 23337, 37075 }, + { 23338, 37094 }, + { 23339, 37090 }, + { 23340, 37084 }, + { 23341, 37079 }, + { 23342, 37083 }, + { 23343, 37099 }, + { 23344, 37103 }, + { 23345, 37118 }, + { 23346, 37124 }, + { 23347, 37154 }, + { 23348, 37150 }, + { 23349, 37155 }, + { 23350, 37169 }, + { 23351, 37167 }, + { 23352, 37177 }, + { 23353, 37187 }, + { 23354, 37190 }, + { 23355, 21005 }, + { 23356, 22850 }, + { 23357, 21154 }, + { 23358, 21164 }, + { 23359, 21165 }, + { 23360, 21182 }, + { 23361, 21759 }, + { 23362, 21200 }, + { 23363, 21206 }, + { 23364, 21232 }, + { 23365, 21471 }, + { 23366, 29166 }, + { 23367, 30669 }, + { 23368, 24308 }, + { 23369, 20981 }, + { 23370, 20988 }, + { 23371, 39727 }, + { 23372, 21430 }, + { 23373, 24321 }, + { 23374, 30042 }, + { 23375, 24047 }, + { 23376, 22348 }, + { 23377, 22441 }, + { 23378, 22433 }, + { 23379, 22654 }, + { 23380, 22716 }, + { 23381, 22725 }, + { 23382, 22737 }, + { 23383, 22313 }, + { 23384, 22316 }, + { 23385, 22314 }, + { 23386, 22323 }, + { 23387, 22329 }, + { 23388, 22318 }, + { 23389, 22319 }, + { 23390, 22364 }, + { 23391, 22331 }, + { 23392, 22338 }, + { 23393, 22377 }, + { 23394, 22405 }, + { 23395, 22379 }, + { 23396, 22406 }, + { 23397, 22396 }, + { 23398, 22395 }, + { 23399, 22376 }, + { 23400, 22381 }, + { 23401, 22390 }, + { 23402, 22387 }, + { 23403, 22445 }, + { 23404, 22436 }, + { 23405, 22412 }, + { 23406, 22450 }, + { 23407, 22479 }, + { 23408, 22439 }, + { 23409, 22452 }, + { 23410, 22419 }, + { 23411, 22432 }, + { 23412, 22485 }, + { 23413, 22488 }, + { 23414, 22490 }, + { 23415, 22489 }, + { 23416, 22482 }, + { 23417, 22456 }, + { 23418, 22516 }, + { 23419, 22511 }, + { 23420, 22520 }, + { 23421, 22500 }, + { 23422, 22493 }, + { 23585, 22539 }, + { 23586, 22541 }, + { 23587, 22525 }, + { 23588, 22509 }, + { 23589, 22528 }, + { 23590, 22558 }, + { 23591, 22553 }, + { 23592, 22596 }, + { 23593, 22560 }, + { 23594, 22629 }, + { 23595, 22636 }, + { 23596, 22657 }, + { 23597, 22665 }, + { 23598, 22682 }, + { 23599, 22656 }, + { 23600, 39336 }, + { 23601, 40729 }, + { 23602, 25087 }, + { 23603, 33401 }, + { 23604, 33405 }, + { 23605, 33407 }, + { 23606, 33423 }, + { 23607, 33418 }, + { 23608, 33448 }, + { 23609, 33412 }, + { 23610, 33422 }, + { 23611, 33425 }, + { 23612, 33431 }, + { 23613, 33433 }, + { 23614, 33451 }, + { 23615, 33464 }, + { 23616, 33470 }, + { 23617, 33456 }, + { 23618, 33480 }, + { 23619, 33482 }, + { 23620, 33507 }, + { 23621, 33432 }, + { 23622, 33463 }, + { 23623, 33454 }, + { 23624, 33483 }, + { 23625, 33484 }, + { 23626, 33473 }, + { 23627, 33449 }, + { 23628, 33460 }, + { 23629, 33441 }, + { 23630, 33450 }, + { 23631, 33439 }, + { 23632, 33476 }, + { 23633, 33486 }, + { 23634, 33444 }, + { 23635, 33505 }, + { 23636, 33545 }, + { 23637, 33527 }, + { 23638, 33508 }, + { 23639, 33551 }, + { 23640, 33543 }, + { 23641, 33500 }, + { 23642, 33524 }, + { 23643, 33490 }, + { 23644, 33496 }, + { 23645, 33548 }, + { 23646, 33531 }, + { 23647, 33491 }, + { 23648, 33553 }, + { 23649, 33562 }, + { 23650, 33542 }, + { 23651, 33556 }, + { 23652, 33557 }, + { 23653, 33504 }, + { 23654, 33493 }, + { 23655, 33564 }, + { 23656, 33617 }, + { 23657, 33627 }, + { 23658, 33628 }, + { 23659, 33544 }, + { 23660, 33682 }, + { 23661, 33596 }, + { 23662, 33588 }, + { 23663, 33585 }, + { 23664, 33691 }, + { 23665, 33630 }, + { 23666, 33583 }, + { 23667, 33615 }, + { 23668, 33607 }, + { 23669, 33603 }, + { 23670, 33631 }, + { 23671, 33600 }, + { 23672, 33559 }, + { 23673, 33632 }, + { 23674, 33581 }, + { 23675, 33594 }, + { 23676, 33587 }, + { 23677, 33638 }, + { 23678, 33637 }, + { 23841, 33640 }, + { 23842, 33563 }, + { 23843, 33641 }, + { 23844, 33644 }, + { 23845, 33642 }, + { 23846, 33645 }, + { 23847, 33646 }, + { 23848, 33712 }, + { 23849, 33656 }, + { 23850, 33715 }, + { 23851, 33716 }, + { 23852, 33696 }, + { 23853, 33706 }, + { 23854, 33683 }, + { 23855, 33692 }, + { 23856, 33669 }, + { 23857, 33660 }, + { 23858, 33718 }, + { 23859, 33705 }, + { 23860, 33661 }, + { 23861, 33720 }, + { 23862, 33659 }, + { 23863, 33688 }, + { 23864, 33694 }, + { 23865, 33704 }, + { 23866, 33722 }, + { 23867, 33724 }, + { 23868, 33729 }, + { 23869, 33793 }, + { 23870, 33765 }, + { 23871, 33752 }, + { 23872, 22535 }, + { 23873, 33816 }, + { 23874, 33803 }, + { 23875, 33757 }, + { 23876, 33789 }, + { 23877, 33750 }, + { 23878, 33820 }, + { 23879, 33848 }, + { 23880, 33809 }, + { 23881, 33798 }, + { 23882, 33748 }, + { 23883, 33759 }, + { 23884, 33807 }, + { 23885, 33795 }, + { 23886, 33784 }, + { 23887, 33785 }, + { 23888, 33770 }, + { 23889, 33733 }, + { 23890, 33728 }, + { 23891, 33830 }, + { 23892, 33776 }, + { 23893, 33761 }, + { 23894, 33884 }, + { 23895, 33873 }, + { 23896, 33882 }, + { 23897, 33881 }, + { 23898, 33907 }, + { 23899, 33927 }, + { 23900, 33928 }, + { 23901, 33914 }, + { 23902, 33929 }, + { 23903, 33912 }, + { 23904, 33852 }, + { 23905, 33862 }, + { 23906, 33897 }, + { 23907, 33910 }, + { 23908, 33932 }, + { 23909, 33934 }, + { 23910, 33841 }, + { 23911, 33901 }, + { 23912, 33985 }, + { 23913, 33997 }, + { 23914, 34000 }, + { 23915, 34022 }, + { 23916, 33981 }, + { 23917, 34003 }, + { 23918, 33994 }, + { 23919, 33983 }, + { 23920, 33978 }, + { 23921, 34016 }, + { 23922, 33953 }, + { 23923, 33977 }, + { 23924, 33972 }, + { 23925, 33943 }, + { 23926, 34021 }, + { 23927, 34019 }, + { 23928, 34060 }, + { 23929, 29965 }, + { 23930, 34104 }, + { 23931, 34032 }, + { 23932, 34105 }, + { 23933, 34079 }, + { 23934, 34106 }, + { 24097, 34134 }, + { 24098, 34107 }, + { 24099, 34047 }, + { 24100, 34044 }, + { 24101, 34137 }, + { 24102, 34120 }, + { 24103, 34152 }, + { 24104, 34148 }, + { 24105, 34142 }, + { 24106, 34170 }, + { 24107, 30626 }, + { 24108, 34115 }, + { 24109, 34162 }, + { 24110, 34171 }, + { 24111, 34212 }, + { 24112, 34216 }, + { 24113, 34183 }, + { 24114, 34191 }, + { 24115, 34169 }, + { 24116, 34222 }, + { 24117, 34204 }, + { 24118, 34181 }, + { 24119, 34233 }, + { 24120, 34231 }, + { 24121, 34224 }, + { 24122, 34259 }, + { 24123, 34241 }, + { 24124, 34268 }, + { 24125, 34303 }, + { 24126, 34343 }, + { 24127, 34309 }, + { 24128, 34345 }, + { 24129, 34326 }, + { 24130, 34364 }, + { 24131, 24318 }, + { 24132, 24328 }, + { 24133, 22844 }, + { 24134, 22849 }, + { 24135, 32823 }, + { 24136, 22869 }, + { 24137, 22874 }, + { 24138, 22872 }, + { 24139, 21263 }, + { 24140, 23586 }, + { 24141, 23589 }, + { 24142, 23596 }, + { 24143, 23604 }, + { 24144, 25164 }, + { 24145, 25194 }, + { 24146, 25247 }, + { 24147, 25275 }, + { 24148, 25290 }, + { 24149, 25306 }, + { 24150, 25303 }, + { 24151, 25326 }, + { 24152, 25378 }, + { 24153, 25334 }, + { 24154, 25401 }, + { 24155, 25419 }, + { 24156, 25411 }, + { 24157, 25517 }, + { 24158, 25590 }, + { 24159, 25457 }, + { 24160, 25466 }, + { 24161, 25486 }, + { 24162, 25524 }, + { 24163, 25453 }, + { 24164, 25516 }, + { 24165, 25482 }, + { 24166, 25449 }, + { 24167, 25518 }, + { 24168, 25532 }, + { 24169, 25586 }, + { 24170, 25592 }, + { 24171, 25568 }, + { 24172, 25599 }, + { 24173, 25540 }, + { 24174, 25566 }, + { 24175, 25550 }, + { 24176, 25682 }, + { 24177, 25542 }, + { 24178, 25534 }, + { 24179, 25669 }, + { 24180, 25665 }, + { 24181, 25611 }, + { 24182, 25627 }, + { 24183, 25632 }, + { 24184, 25612 }, + { 24185, 25638 }, + { 24186, 25633 }, + { 24187, 25694 }, + { 24188, 25732 }, + { 24189, 25709 }, + { 24190, 25750 }, + { 24353, 25722 }, + { 24354, 25783 }, + { 24355, 25784 }, + { 24356, 25753 }, + { 24357, 25786 }, + { 24358, 25792 }, + { 24359, 25808 }, + { 24360, 25815 }, + { 24361, 25828 }, + { 24362, 25826 }, + { 24363, 25865 }, + { 24364, 25893 }, + { 24365, 25902 }, + { 24366, 24331 }, + { 24367, 24530 }, + { 24368, 29977 }, + { 24369, 24337 }, + { 24370, 21343 }, + { 24371, 21489 }, + { 24372, 21501 }, + { 24373, 21481 }, + { 24374, 21480 }, + { 24375, 21499 }, + { 24376, 21522 }, + { 24377, 21526 }, + { 24378, 21510 }, + { 24379, 21579 }, + { 24380, 21586 }, + { 24381, 21587 }, + { 24382, 21588 }, + { 24383, 21590 }, + { 24384, 21571 }, + { 24385, 21537 }, + { 24386, 21591 }, + { 24387, 21593 }, + { 24388, 21539 }, + { 24389, 21554 }, + { 24390, 21634 }, + { 24391, 21652 }, + { 24392, 21623 }, + { 24393, 21617 }, + { 24394, 21604 }, + { 24395, 21658 }, + { 24396, 21659 }, + { 24397, 21636 }, + { 24398, 21622 }, + { 24399, 21606 }, + { 24400, 21661 }, + { 24401, 21712 }, + { 24402, 21677 }, + { 24403, 21698 }, + { 24404, 21684 }, + { 24405, 21714 }, + { 24406, 21671 }, + { 24407, 21670 }, + { 24408, 21715 }, + { 24409, 21716 }, + { 24410, 21618 }, + { 24411, 21667 }, + { 24412, 21717 }, + { 24413, 21691 }, + { 24414, 21695 }, + { 24415, 21708 }, + { 24416, 21721 }, + { 24417, 21722 }, + { 24418, 21724 }, + { 24419, 21673 }, + { 24420, 21674 }, + { 24421, 21668 }, + { 24422, 21725 }, + { 24423, 21711 }, + { 24424, 21726 }, + { 24425, 21787 }, + { 24426, 21735 }, + { 24427, 21792 }, + { 24428, 21757 }, + { 24429, 21780 }, + { 24430, 21747 }, + { 24431, 21794 }, + { 24432, 21795 }, + { 24433, 21775 }, + { 24434, 21777 }, + { 24435, 21799 }, + { 24436, 21802 }, + { 24437, 21863 }, + { 24438, 21903 }, + { 24439, 21941 }, + { 24440, 21833 }, + { 24441, 21869 }, + { 24442, 21825 }, + { 24443, 21845 }, + { 24444, 21823 }, + { 24445, 21840 }, + { 24446, 21820 }, + { 24609, 21815 }, + { 24610, 21846 }, + { 24611, 21877 }, + { 24612, 21878 }, + { 24613, 21879 }, + { 24614, 21811 }, + { 24615, 21808 }, + { 24616, 21852 }, + { 24617, 21899 }, + { 24618, 21970 }, + { 24619, 21891 }, + { 24620, 21937 }, + { 24621, 21945 }, + { 24622, 21896 }, + { 24623, 21889 }, + { 24624, 21919 }, + { 24625, 21886 }, + { 24626, 21974 }, + { 24627, 21905 }, + { 24628, 21883 }, + { 24629, 21983 }, + { 24630, 21949 }, + { 24631, 21950 }, + { 24632, 21908 }, + { 24633, 21913 }, + { 24634, 21994 }, + { 24635, 22007 }, + { 24636, 21961 }, + { 24637, 22047 }, + { 24638, 21969 }, + { 24639, 21995 }, + { 24640, 21996 }, + { 24641, 21972 }, + { 24642, 21990 }, + { 24643, 21981 }, + { 24644, 21956 }, + { 24645, 21999 }, + { 24646, 21989 }, + { 24647, 22002 }, + { 24648, 22003 }, + { 24649, 21964 }, + { 24650, 21965 }, + { 24651, 21992 }, + { 24652, 22005 }, + { 24653, 21988 }, + { 24654, 36756 }, + { 24655, 22046 }, + { 24656, 22024 }, + { 24657, 22028 }, + { 24658, 22017 }, + { 24659, 22052 }, + { 24660, 22051 }, + { 24661, 22014 }, + { 24662, 22016 }, + { 24663, 22055 }, + { 24664, 22061 }, + { 24665, 22104 }, + { 24666, 22073 }, + { 24667, 22103 }, + { 24668, 22060 }, + { 24669, 22093 }, + { 24670, 22114 }, + { 24671, 22105 }, + { 24672, 22108 }, + { 24673, 22092 }, + { 24674, 22100 }, + { 24675, 22150 }, + { 24676, 22116 }, + { 24677, 22129 }, + { 24678, 22123 }, + { 24679, 22139 }, + { 24680, 22140 }, + { 24681, 22149 }, + { 24682, 22163 }, + { 24683, 22191 }, + { 24684, 22228 }, + { 24685, 22231 }, + { 24686, 22237 }, + { 24687, 22241 }, + { 24688, 22261 }, + { 24689, 22251 }, + { 24690, 22265 }, + { 24691, 22271 }, + { 24692, 22276 }, + { 24693, 22282 }, + { 24694, 22281 }, + { 24695, 22300 }, + { 24696, 24079 }, + { 24697, 24089 }, + { 24698, 24084 }, + { 24699, 24081 }, + { 24700, 24113 }, + { 24701, 24123 }, + { 24702, 24124 }, + { 24865, 24119 }, + { 24866, 24132 }, + { 24867, 24148 }, + { 24868, 24155 }, + { 24869, 24158 }, + { 24870, 24161 }, + { 24871, 23692 }, + { 24872, 23674 }, + { 24873, 23693 }, + { 24874, 23696 }, + { 24875, 23702 }, + { 24876, 23688 }, + { 24877, 23704 }, + { 24878, 23705 }, + { 24879, 23697 }, + { 24880, 23706 }, + { 24881, 23708 }, + { 24882, 23733 }, + { 24883, 23714 }, + { 24884, 23741 }, + { 24885, 23724 }, + { 24886, 23723 }, + { 24887, 23729 }, + { 24888, 23715 }, + { 24889, 23745 }, + { 24890, 23735 }, + { 24891, 23748 }, + { 24892, 23762 }, + { 24893, 23780 }, + { 24894, 23755 }, + { 24895, 23781 }, + { 24896, 23810 }, + { 24897, 23811 }, + { 24898, 23847 }, + { 24899, 23846 }, + { 24900, 23854 }, + { 24901, 23844 }, + { 24902, 23838 }, + { 24903, 23814 }, + { 24904, 23835 }, + { 24905, 23896 }, + { 24906, 23870 }, + { 24907, 23860 }, + { 24908, 23869 }, + { 24909, 23916 }, + { 24910, 23899 }, + { 24911, 23919 }, + { 24912, 23901 }, + { 24913, 23915 }, + { 24914, 23883 }, + { 24915, 23882 }, + { 24916, 23913 }, + { 24917, 23924 }, + { 24918, 23938 }, + { 24919, 23961 }, + { 24920, 23965 }, + { 24921, 35955 }, + { 24922, 23991 }, + { 24923, 24005 }, + { 24924, 24435 }, + { 24925, 24439 }, + { 24926, 24450 }, + { 24927, 24455 }, + { 24928, 24457 }, + { 24929, 24460 }, + { 24930, 24469 }, + { 24931, 24473 }, + { 24932, 24476 }, + { 24933, 24488 }, + { 24934, 24493 }, + { 24935, 24501 }, + { 24936, 24508 }, + { 24937, 34914 }, + { 24938, 24417 }, + { 24939, 29357 }, + { 24940, 29360 }, + { 24941, 29364 }, + { 24942, 29367 }, + { 24943, 29368 }, + { 24944, 29379 }, + { 24945, 29377 }, + { 24946, 29390 }, + { 24947, 29389 }, + { 24948, 29394 }, + { 24949, 29416 }, + { 24950, 29423 }, + { 24951, 29417 }, + { 24952, 29426 }, + { 24953, 29428 }, + { 24954, 29431 }, + { 24955, 29441 }, + { 24956, 29427 }, + { 24957, 29443 }, + { 24958, 29434 }, + { 25121, 29435 }, + { 25122, 29463 }, + { 25123, 29459 }, + { 25124, 29473 }, + { 25125, 29450 }, + { 25126, 29470 }, + { 25127, 29469 }, + { 25128, 29461 }, + { 25129, 29474 }, + { 25130, 29497 }, + { 25131, 29477 }, + { 25132, 29484 }, + { 25133, 29496 }, + { 25134, 29489 }, + { 25135, 29520 }, + { 25136, 29517 }, + { 25137, 29527 }, + { 25138, 29536 }, + { 25139, 29548 }, + { 25140, 29551 }, + { 25141, 29566 }, + { 25142, 33307 }, + { 25143, 22821 }, + { 25144, 39143 }, + { 25145, 22820 }, + { 25146, 22786 }, + { 25147, 39267 }, + { 25148, 39271 }, + { 25149, 39272 }, + { 25150, 39273 }, + { 25151, 39274 }, + { 25152, 39275 }, + { 25153, 39276 }, + { 25154, 39284 }, + { 25155, 39287 }, + { 25156, 39293 }, + { 25157, 39296 }, + { 25158, 39300 }, + { 25159, 39303 }, + { 25160, 39306 }, + { 25161, 39309 }, + { 25162, 39312 }, + { 25163, 39313 }, + { 25164, 39315 }, + { 25165, 39316 }, + { 25166, 39317 }, + { 25167, 24192 }, + { 25168, 24209 }, + { 25169, 24203 }, + { 25170, 24214 }, + { 25171, 24229 }, + { 25172, 24224 }, + { 25173, 24249 }, + { 25174, 24245 }, + { 25175, 24254 }, + { 25176, 24243 }, + { 25177, 36179 }, + { 25178, 24274 }, + { 25179, 24273 }, + { 25180, 24283 }, + { 25181, 24296 }, + { 25182, 24298 }, + { 25183, 33210 }, + { 25184, 24516 }, + { 25185, 24521 }, + { 25186, 24534 }, + { 25187, 24527 }, + { 25188, 24579 }, + { 25189, 24558 }, + { 25190, 24580 }, + { 25191, 24545 }, + { 25192, 24548 }, + { 25193, 24574 }, + { 25194, 24581 }, + { 25195, 24582 }, + { 25196, 24554 }, + { 25197, 24557 }, + { 25198, 24568 }, + { 25199, 24601 }, + { 25200, 24629 }, + { 25201, 24614 }, + { 25202, 24603 }, + { 25203, 24591 }, + { 25204, 24589 }, + { 25205, 24617 }, + { 25206, 24619 }, + { 25207, 24586 }, + { 25208, 24639 }, + { 25209, 24609 }, + { 25210, 24696 }, + { 25211, 24697 }, + { 25212, 24699 }, + { 25213, 24698 }, + { 25214, 24642 }, + { 25377, 24682 }, + { 25378, 24701 }, + { 25379, 24726 }, + { 25380, 24730 }, + { 25381, 24749 }, + { 25382, 24733 }, + { 25383, 24707 }, + { 25384, 24722 }, + { 25385, 24716 }, + { 25386, 24731 }, + { 25387, 24812 }, + { 25388, 24763 }, + { 25389, 24753 }, + { 25390, 24797 }, + { 25391, 24792 }, + { 25392, 24774 }, + { 25393, 24794 }, + { 25394, 24756 }, + { 25395, 24864 }, + { 25396, 24870 }, + { 25397, 24853 }, + { 25398, 24867 }, + { 25399, 24820 }, + { 25400, 24832 }, + { 25401, 24846 }, + { 25402, 24875 }, + { 25403, 24906 }, + { 25404, 24949 }, + { 25405, 25004 }, + { 25406, 24980 }, + { 25407, 24999 }, + { 25408, 25015 }, + { 25409, 25044 }, + { 25410, 25077 }, + { 25411, 24541 }, + { 25412, 38579 }, + { 25413, 38377 }, + { 25414, 38379 }, + { 25415, 38385 }, + { 25416, 38387 }, + { 25417, 38389 }, + { 25418, 38390 }, + { 25419, 38396 }, + { 25420, 38398 }, + { 25421, 38403 }, + { 25422, 38404 }, + { 25423, 38406 }, + { 25424, 38408 }, + { 25425, 38410 }, + { 25426, 38411 }, + { 25427, 38412 }, + { 25428, 38413 }, + { 25429, 38415 }, + { 25430, 38418 }, + { 25431, 38421 }, + { 25432, 38422 }, + { 25433, 38423 }, + { 25434, 38425 }, + { 25435, 38426 }, + { 25436, 20012 }, + { 25437, 29247 }, + { 25438, 25109 }, + { 25439, 27701 }, + { 25440, 27732 }, + { 25441, 27740 }, + { 25442, 27722 }, + { 25443, 27811 }, + { 25444, 27781 }, + { 25445, 27792 }, + { 25446, 27796 }, + { 25447, 27788 }, + { 25448, 27752 }, + { 25449, 27753 }, + { 25450, 27764 }, + { 25451, 27766 }, + { 25452, 27782 }, + { 25453, 27817 }, + { 25454, 27856 }, + { 25455, 27860 }, + { 25456, 27821 }, + { 25457, 27895 }, + { 25458, 27896 }, + { 25459, 27889 }, + { 25460, 27863 }, + { 25461, 27826 }, + { 25462, 27872 }, + { 25463, 27862 }, + { 25464, 27898 }, + { 25465, 27883 }, + { 25466, 27886 }, + { 25467, 27825 }, + { 25468, 27859 }, + { 25469, 27887 }, + { 25470, 27902 }, + { 25633, 27961 }, + { 25634, 27943 }, + { 25635, 27916 }, + { 25636, 27971 }, + { 25637, 27976 }, + { 25638, 27911 }, + { 25639, 27908 }, + { 25640, 27929 }, + { 25641, 27918 }, + { 25642, 27947 }, + { 25643, 27981 }, + { 25644, 27950 }, + { 25645, 27957 }, + { 25646, 27930 }, + { 25647, 27983 }, + { 25648, 27986 }, + { 25649, 27988 }, + { 25650, 27955 }, + { 25651, 28049 }, + { 25652, 28015 }, + { 25653, 28062 }, + { 25654, 28064 }, + { 25655, 27998 }, + { 25656, 28051 }, + { 25657, 28052 }, + { 25658, 27996 }, + { 25659, 28000 }, + { 25660, 28028 }, + { 25661, 28003 }, + { 25662, 28186 }, + { 25663, 28103 }, + { 25664, 28101 }, + { 25665, 28126 }, + { 25666, 28174 }, + { 25667, 28095 }, + { 25668, 28128 }, + { 25669, 28177 }, + { 25670, 28134 }, + { 25671, 28125 }, + { 25672, 28121 }, + { 25673, 28182 }, + { 25674, 28075 }, + { 25675, 28172 }, + { 25676, 28078 }, + { 25677, 28203 }, + { 25678, 28270 }, + { 25679, 28238 }, + { 25680, 28267 }, + { 25681, 28338 }, + { 25682, 28255 }, + { 25683, 28294 }, + { 25684, 28243 }, + { 25685, 28244 }, + { 25686, 28210 }, + { 25687, 28197 }, + { 25688, 28228 }, + { 25689, 28383 }, + { 25690, 28337 }, + { 25691, 28312 }, + { 25692, 28384 }, + { 25693, 28461 }, + { 25694, 28386 }, + { 25695, 28325 }, + { 25696, 28327 }, + { 25697, 28349 }, + { 25698, 28347 }, + { 25699, 28343 }, + { 25700, 28375 }, + { 25701, 28340 }, + { 25702, 28367 }, + { 25703, 28303 }, + { 25704, 28354 }, + { 25705, 28319 }, + { 25706, 28514 }, + { 25707, 28486 }, + { 25708, 28487 }, + { 25709, 28452 }, + { 25710, 28437 }, + { 25711, 28409 }, + { 25712, 28463 }, + { 25713, 28470 }, + { 25714, 28491 }, + { 25715, 28532 }, + { 25716, 28458 }, + { 25717, 28425 }, + { 25718, 28457 }, + { 25719, 28553 }, + { 25720, 28557 }, + { 25721, 28556 }, + { 25722, 28536 }, + { 25723, 28530 }, + { 25724, 28540 }, + { 25725, 28538 }, + { 25726, 28625 }, + { 25889, 28617 }, + { 25890, 28583 }, + { 25891, 28601 }, + { 25892, 28598 }, + { 25893, 28610 }, + { 25894, 28641 }, + { 25895, 28654 }, + { 25896, 28638 }, + { 25897, 28640 }, + { 25898, 28655 }, + { 25899, 28698 }, + { 25900, 28707 }, + { 25901, 28699 }, + { 25902, 28729 }, + { 25903, 28725 }, + { 25904, 28751 }, + { 25905, 28766 }, + { 25906, 23424 }, + { 25907, 23428 }, + { 25908, 23445 }, + { 25909, 23443 }, + { 25910, 23461 }, + { 25911, 23480 }, + { 25912, 29999 }, + { 25913, 39582 }, + { 25914, 25652 }, + { 25915, 23524 }, + { 25916, 23534 }, + { 25917, 35120 }, + { 25918, 23536 }, + { 25919, 36423 }, + { 25920, 35591 }, + { 25921, 36790 }, + { 25922, 36819 }, + { 25923, 36821 }, + { 25924, 36837 }, + { 25925, 36846 }, + { 25926, 36836 }, + { 25927, 36841 }, + { 25928, 36838 }, + { 25929, 36851 }, + { 25930, 36840 }, + { 25931, 36869 }, + { 25932, 36868 }, + { 25933, 36875 }, + { 25934, 36902 }, + { 25935, 36881 }, + { 25936, 36877 }, + { 25937, 36886 }, + { 25938, 36897 }, + { 25939, 36917 }, + { 25940, 36918 }, + { 25941, 36909 }, + { 25942, 36911 }, + { 25943, 36932 }, + { 25944, 36945 }, + { 25945, 36946 }, + { 25946, 36944 }, + { 25947, 36968 }, + { 25948, 36952 }, + { 25949, 36962 }, + { 25950, 36955 }, + { 25951, 26297 }, + { 25952, 36980 }, + { 25953, 36989 }, + { 25954, 36994 }, + { 25955, 37000 }, + { 25956, 36995 }, + { 25957, 37003 }, + { 25958, 24400 }, + { 25959, 24407 }, + { 25960, 24406 }, + { 25961, 24408 }, + { 25962, 23611 }, + { 25963, 21675 }, + { 25964, 23632 }, + { 25965, 23641 }, + { 25966, 23409 }, + { 25967, 23651 }, + { 25968, 23654 }, + { 25969, 32700 }, + { 25970, 24362 }, + { 25971, 24361 }, + { 25972, 24365 }, + { 25973, 33396 }, + { 25974, 24380 }, + { 25975, 39739 }, + { 25976, 23662 }, + { 25977, 22913 }, + { 25978, 22915 }, + { 25979, 22925 }, + { 25980, 22953 }, + { 25981, 22954 }, + { 25982, 22947 }, + { 26145, 22935 }, + { 26146, 22986 }, + { 26147, 22955 }, + { 26148, 22942 }, + { 26149, 22948 }, + { 26150, 22994 }, + { 26151, 22962 }, + { 26152, 22959 }, + { 26153, 22999 }, + { 26154, 22974 }, + { 26155, 23045 }, + { 26156, 23046 }, + { 26157, 23005 }, + { 26158, 23048 }, + { 26159, 23011 }, + { 26160, 23000 }, + { 26161, 23033 }, + { 26162, 23052 }, + { 26163, 23049 }, + { 26164, 23090 }, + { 26165, 23092 }, + { 26166, 23057 }, + { 26167, 23075 }, + { 26168, 23059 }, + { 26169, 23104 }, + { 26170, 23143 }, + { 26171, 23114 }, + { 26172, 23125 }, + { 26173, 23100 }, + { 26174, 23138 }, + { 26175, 23157 }, + { 26176, 33004 }, + { 26177, 23210 }, + { 26178, 23195 }, + { 26179, 23159 }, + { 26180, 23162 }, + { 26181, 23230 }, + { 26182, 23275 }, + { 26183, 23218 }, + { 26184, 23250 }, + { 26185, 23252 }, + { 26186, 23224 }, + { 26187, 23264 }, + { 26188, 23267 }, + { 26189, 23281 }, + { 26190, 23254 }, + { 26191, 23270 }, + { 26192, 23256 }, + { 26193, 23260 }, + { 26194, 23305 }, + { 26195, 23319 }, + { 26196, 23318 }, + { 26197, 23346 }, + { 26198, 23351 }, + { 26199, 23360 }, + { 26200, 23573 }, + { 26201, 23580 }, + { 26202, 23386 }, + { 26203, 23397 }, + { 26204, 23411 }, + { 26205, 23377 }, + { 26206, 23379 }, + { 26207, 23394 }, + { 26208, 39541 }, + { 26209, 39543 }, + { 26210, 39544 }, + { 26211, 39546 }, + { 26212, 39551 }, + { 26213, 39549 }, + { 26214, 39552 }, + { 26215, 39553 }, + { 26216, 39557 }, + { 26217, 39560 }, + { 26218, 39562 }, + { 26219, 39568 }, + { 26220, 39570 }, + { 26221, 39571 }, + { 26222, 39574 }, + { 26223, 39576 }, + { 26224, 39579 }, + { 26225, 39580 }, + { 26226, 39581 }, + { 26227, 39583 }, + { 26228, 39584 }, + { 26229, 39586 }, + { 26230, 39587 }, + { 26231, 39589 }, + { 26232, 39591 }, + { 26233, 32415 }, + { 26234, 32417 }, + { 26235, 32419 }, + { 26236, 32421 }, + { 26237, 32424 }, + { 26238, 32425 }, + { 26401, 32429 }, + { 26402, 32432 }, + { 26403, 32446 }, + { 26404, 32448 }, + { 26405, 32449 }, + { 26406, 32450 }, + { 26407, 32457 }, + { 26408, 32459 }, + { 26409, 32460 }, + { 26410, 32464 }, + { 26411, 32468 }, + { 26412, 32471 }, + { 26413, 32475 }, + { 26414, 32480 }, + { 26415, 32481 }, + { 26416, 32488 }, + { 26417, 32491 }, + { 26418, 32494 }, + { 26419, 32495 }, + { 26420, 32497 }, + { 26421, 32498 }, + { 26422, 32525 }, + { 26423, 32502 }, + { 26424, 32506 }, + { 26425, 32507 }, + { 26426, 32510 }, + { 26427, 32513 }, + { 26428, 32514 }, + { 26429, 32515 }, + { 26430, 32519 }, + { 26431, 32520 }, + { 26432, 32523 }, + { 26433, 32524 }, + { 26434, 32527 }, + { 26435, 32529 }, + { 26436, 32530 }, + { 26437, 32535 }, + { 26438, 32537 }, + { 26439, 32540 }, + { 26440, 32539 }, + { 26441, 32543 }, + { 26442, 32545 }, + { 26443, 32546 }, + { 26444, 32547 }, + { 26445, 32548 }, + { 26446, 32549 }, + { 26447, 32550 }, + { 26448, 32551 }, + { 26449, 32554 }, + { 26450, 32555 }, + { 26451, 32556 }, + { 26452, 32557 }, + { 26453, 32559 }, + { 26454, 32560 }, + { 26455, 32561 }, + { 26456, 32562 }, + { 26457, 32563 }, + { 26458, 32565 }, + { 26459, 24186 }, + { 26460, 30079 }, + { 26461, 24027 }, + { 26462, 30014 }, + { 26463, 37013 }, + { 26464, 29582 }, + { 26465, 29585 }, + { 26466, 29614 }, + { 26467, 29602 }, + { 26468, 29599 }, + { 26469, 29647 }, + { 26470, 29634 }, + { 26471, 29649 }, + { 26472, 29623 }, + { 26473, 29619 }, + { 26474, 29632 }, + { 26475, 29641 }, + { 26476, 29640 }, + { 26477, 29669 }, + { 26478, 29657 }, + { 26479, 39036 }, + { 26480, 29706 }, + { 26481, 29673 }, + { 26482, 29671 }, + { 26483, 29662 }, + { 26484, 29626 }, + { 26485, 29682 }, + { 26486, 29711 }, + { 26487, 29738 }, + { 26488, 29787 }, + { 26489, 29734 }, + { 26490, 29733 }, + { 26491, 29736 }, + { 26492, 29744 }, + { 26493, 29742 }, + { 26494, 29740 }, + { 26657, 29723 }, + { 26658, 29722 }, + { 26659, 29761 }, + { 26660, 29788 }, + { 26661, 29783 }, + { 26662, 29781 }, + { 26663, 29785 }, + { 26664, 29815 }, + { 26665, 29805 }, + { 26666, 29822 }, + { 26667, 29852 }, + { 26668, 29838 }, + { 26669, 29824 }, + { 26670, 29825 }, + { 26671, 29831 }, + { 26672, 29835 }, + { 26673, 29854 }, + { 26674, 29864 }, + { 26675, 29865 }, + { 26676, 29840 }, + { 26677, 29863 }, + { 26678, 29906 }, + { 26679, 29882 }, + { 26680, 38890 }, + { 26681, 38891 }, + { 26682, 38892 }, + { 26683, 26444 }, + { 26684, 26451 }, + { 26685, 26462 }, + { 26686, 26440 }, + { 26687, 26473 }, + { 26688, 26533 }, + { 26689, 26503 }, + { 26690, 26474 }, + { 26691, 26483 }, + { 26692, 26520 }, + { 26693, 26535 }, + { 26694, 26485 }, + { 26695, 26536 }, + { 26696, 26526 }, + { 26697, 26541 }, + { 26698, 26507 }, + { 26699, 26487 }, + { 26700, 26492 }, + { 26701, 26608 }, + { 26702, 26633 }, + { 26703, 26584 }, + { 26704, 26634 }, + { 26705, 26601 }, + { 26706, 26544 }, + { 26707, 26636 }, + { 26708, 26585 }, + { 26709, 26549 }, + { 26710, 26586 }, + { 26711, 26547 }, + { 26712, 26589 }, + { 26713, 26624 }, + { 26714, 26563 }, + { 26715, 26552 }, + { 26716, 26594 }, + { 26717, 26638 }, + { 26718, 26561 }, + { 26719, 26621 }, + { 26720, 26674 }, + { 26721, 26675 }, + { 26722, 26720 }, + { 26723, 26721 }, + { 26724, 26702 }, + { 26725, 26722 }, + { 26726, 26692 }, + { 26727, 26724 }, + { 26728, 26755 }, + { 26729, 26653 }, + { 26730, 26709 }, + { 26731, 26726 }, + { 26732, 26689 }, + { 26733, 26727 }, + { 26734, 26688 }, + { 26735, 26686 }, + { 26736, 26698 }, + { 26737, 26697 }, + { 26738, 26665 }, + { 26739, 26805 }, + { 26740, 26767 }, + { 26741, 26740 }, + { 26742, 26743 }, + { 26743, 26771 }, + { 26744, 26731 }, + { 26745, 26818 }, + { 26746, 26990 }, + { 26747, 26876 }, + { 26748, 26911 }, + { 26749, 26912 }, + { 26750, 26873 }, + { 26913, 26916 }, + { 26914, 26864 }, + { 26915, 26891 }, + { 26916, 26881 }, + { 26917, 26967 }, + { 26918, 26851 }, + { 26919, 26896 }, + { 26920, 26993 }, + { 26921, 26937 }, + { 26922, 26976 }, + { 26923, 26946 }, + { 26924, 26973 }, + { 26925, 27012 }, + { 26926, 26987 }, + { 26927, 27008 }, + { 26928, 27032 }, + { 26929, 27000 }, + { 26930, 26932 }, + { 26931, 27084 }, + { 26932, 27015 }, + { 26933, 27016 }, + { 26934, 27086 }, + { 26935, 27017 }, + { 26936, 26982 }, + { 26937, 26979 }, + { 26938, 27001 }, + { 26939, 27035 }, + { 26940, 27047 }, + { 26941, 27067 }, + { 26942, 27051 }, + { 26943, 27053 }, + { 26944, 27092 }, + { 26945, 27057 }, + { 26946, 27073 }, + { 26947, 27082 }, + { 26948, 27103 }, + { 26949, 27029 }, + { 26950, 27104 }, + { 26951, 27021 }, + { 26952, 27135 }, + { 26953, 27183 }, + { 26954, 27117 }, + { 26955, 27159 }, + { 26956, 27160 }, + { 26957, 27237 }, + { 26958, 27122 }, + { 26959, 27204 }, + { 26960, 27198 }, + { 26961, 27296 }, + { 26962, 27216 }, + { 26963, 27227 }, + { 26964, 27189 }, + { 26965, 27278 }, + { 26966, 27257 }, + { 26967, 27197 }, + { 26968, 27176 }, + { 26969, 27224 }, + { 26970, 27260 }, + { 26971, 27281 }, + { 26972, 27280 }, + { 26973, 27305 }, + { 26974, 27287 }, + { 26975, 27307 }, + { 26976, 29495 }, + { 26977, 29522 }, + { 26978, 27521 }, + { 26979, 27522 }, + { 26980, 27527 }, + { 26981, 27524 }, + { 26982, 27538 }, + { 26983, 27539 }, + { 26984, 27533 }, + { 26985, 27546 }, + { 26986, 27547 }, + { 26987, 27553 }, + { 26988, 27562 }, + { 26989, 36715 }, + { 26990, 36717 }, + { 26991, 36721 }, + { 26992, 36722 }, + { 26993, 36723 }, + { 26994, 36725 }, + { 26995, 36726 }, + { 26996, 36728 }, + { 26997, 36727 }, + { 26998, 36729 }, + { 26999, 36730 }, + { 27000, 36732 }, + { 27001, 36734 }, + { 27002, 36737 }, + { 27003, 36738 }, + { 27004, 36740 }, + { 27005, 36743 }, + { 27006, 36747 }, + { 27169, 36749 }, + { 27170, 36750 }, + { 27171, 36751 }, + { 27172, 36760 }, + { 27173, 36762 }, + { 27174, 36558 }, + { 27175, 25099 }, + { 27176, 25111 }, + { 27177, 25115 }, + { 27178, 25119 }, + { 27179, 25122 }, + { 27180, 25121 }, + { 27181, 25125 }, + { 27182, 25124 }, + { 27183, 25132 }, + { 27184, 33255 }, + { 27185, 29935 }, + { 27186, 29940 }, + { 27187, 29951 }, + { 27188, 29967 }, + { 27189, 29969 }, + { 27190, 29971 }, + { 27191, 25908 }, + { 27192, 26094 }, + { 27193, 26095 }, + { 27194, 26096 }, + { 27195, 26122 }, + { 27196, 26137 }, + { 27197, 26482 }, + { 27198, 26115 }, + { 27199, 26133 }, + { 27200, 26112 }, + { 27201, 28805 }, + { 27202, 26359 }, + { 27203, 26141 }, + { 27204, 26164 }, + { 27205, 26161 }, + { 27206, 26166 }, + { 27207, 26165 }, + { 27208, 32774 }, + { 27209, 26207 }, + { 27210, 26196 }, + { 27211, 26177 }, + { 27212, 26191 }, + { 27213, 26198 }, + { 27214, 26209 }, + { 27215, 26199 }, + { 27216, 26231 }, + { 27217, 26244 }, + { 27218, 26252 }, + { 27219, 26279 }, + { 27220, 26269 }, + { 27221, 26302 }, + { 27222, 26331 }, + { 27223, 26332 }, + { 27224, 26342 }, + { 27225, 26345 }, + { 27226, 36146 }, + { 27227, 36147 }, + { 27228, 36150 }, + { 27229, 36155 }, + { 27230, 36157 }, + { 27231, 36160 }, + { 27232, 36165 }, + { 27233, 36166 }, + { 27234, 36168 }, + { 27235, 36169 }, + { 27236, 36167 }, + { 27237, 36173 }, + { 27238, 36181 }, + { 27239, 36185 }, + { 27240, 35271 }, + { 27241, 35274 }, + { 27242, 35275 }, + { 27243, 35276 }, + { 27244, 35278 }, + { 27245, 35279 }, + { 27246, 35280 }, + { 27247, 35281 }, + { 27248, 29294 }, + { 27249, 29343 }, + { 27250, 29277 }, + { 27251, 29286 }, + { 27252, 29295 }, + { 27253, 29310 }, + { 27254, 29311 }, + { 27255, 29316 }, + { 27256, 29323 }, + { 27257, 29325 }, + { 27258, 29327 }, + { 27259, 29330 }, + { 27260, 25352 }, + { 27261, 25394 }, + { 27262, 25520 }, + { 27425, 25663 }, + { 27426, 25816 }, + { 27427, 32772 }, + { 27428, 27626 }, + { 27429, 27635 }, + { 27430, 27645 }, + { 27431, 27637 }, + { 27432, 27641 }, + { 27433, 27653 }, + { 27434, 27655 }, + { 27435, 27654 }, + { 27436, 27661 }, + { 27437, 27669 }, + { 27438, 27672 }, + { 27439, 27673 }, + { 27440, 27674 }, + { 27441, 27681 }, + { 27442, 27689 }, + { 27443, 27684 }, + { 27444, 27690 }, + { 27445, 27698 }, + { 27446, 25909 }, + { 27447, 25941 }, + { 27448, 25963 }, + { 27449, 29261 }, + { 27450, 29266 }, + { 27451, 29270 }, + { 27452, 29232 }, + { 27453, 34402 }, + { 27454, 21014 }, + { 27455, 32927 }, + { 27456, 32924 }, + { 27457, 32915 }, + { 27458, 32956 }, + { 27459, 26378 }, + { 27460, 32957 }, + { 27461, 32945 }, + { 27462, 32939 }, + { 27463, 32941 }, + { 27464, 32948 }, + { 27465, 32951 }, + { 27466, 32999 }, + { 27467, 33000 }, + { 27468, 33001 }, + { 27469, 33002 }, + { 27470, 32987 }, + { 27471, 32962 }, + { 27472, 32964 }, + { 27473, 32985 }, + { 27474, 32973 }, + { 27475, 32983 }, + { 27476, 26384 }, + { 27477, 32989 }, + { 27478, 33003 }, + { 27479, 33009 }, + { 27480, 33012 }, + { 27481, 33005 }, + { 27482, 33037 }, + { 27483, 33038 }, + { 27484, 33010 }, + { 27485, 33020 }, + { 27486, 26389 }, + { 27487, 33042 }, + { 27488, 35930 }, + { 27489, 33078 }, + { 27490, 33054 }, + { 27491, 33068 }, + { 27492, 33048 }, + { 27493, 33074 }, + { 27494, 33096 }, + { 27495, 33100 }, + { 27496, 33107 }, + { 27497, 33140 }, + { 27498, 33113 }, + { 27499, 33114 }, + { 27500, 33137 }, + { 27501, 33120 }, + { 27502, 33129 }, + { 27503, 33148 }, + { 27504, 33149 }, + { 27505, 33133 }, + { 27506, 33127 }, + { 27507, 22605 }, + { 27508, 23221 }, + { 27509, 33160 }, + { 27510, 33154 }, + { 27511, 33169 }, + { 27512, 28373 }, + { 27513, 33187 }, + { 27514, 33194 }, + { 27515, 33228 }, + { 27516, 26406 }, + { 27517, 33226 }, + { 27518, 33211 }, + { 27681, 33217 }, + { 27682, 33190 }, + { 27683, 27428 }, + { 27684, 27447 }, + { 27685, 27449 }, + { 27686, 27459 }, + { 27687, 27462 }, + { 27688, 27481 }, + { 27689, 39121 }, + { 27690, 39122 }, + { 27691, 39123 }, + { 27692, 39125 }, + { 27693, 39129 }, + { 27694, 39130 }, + { 27695, 27571 }, + { 27696, 24384 }, + { 27697, 27586 }, + { 27698, 35315 }, + { 27699, 26000 }, + { 27700, 40785 }, + { 27701, 26003 }, + { 27702, 26044 }, + { 27703, 26054 }, + { 27704, 26052 }, + { 27705, 26051 }, + { 27706, 26060 }, + { 27707, 26062 }, + { 27708, 26066 }, + { 27709, 26070 }, + { 27710, 28800 }, + { 27711, 28828 }, + { 27712, 28822 }, + { 27713, 28829 }, + { 27714, 28859 }, + { 27715, 28864 }, + { 27716, 28855 }, + { 27717, 28843 }, + { 27718, 28849 }, + { 27719, 28904 }, + { 27720, 28874 }, + { 27721, 28944 }, + { 27722, 28947 }, + { 27723, 28950 }, + { 27724, 28975 }, + { 27725, 28977 }, + { 27726, 29043 }, + { 27727, 29020 }, + { 27728, 29032 }, + { 27729, 28997 }, + { 27730, 29042 }, + { 27731, 29002 }, + { 27732, 29048 }, + { 27733, 29050 }, + { 27734, 29080 }, + { 27735, 29107 }, + { 27736, 29109 }, + { 27737, 29096 }, + { 27738, 29088 }, + { 27739, 29152 }, + { 27740, 29140 }, + { 27741, 29159 }, + { 27742, 29177 }, + { 27743, 29213 }, + { 27744, 29224 }, + { 27745, 28780 }, + { 27746, 28952 }, + { 27747, 29030 }, + { 27748, 29113 }, + { 27749, 25150 }, + { 27750, 25149 }, + { 27751, 25155 }, + { 27752, 25160 }, + { 27753, 25161 }, + { 27754, 31035 }, + { 27755, 31040 }, + { 27756, 31046 }, + { 27757, 31049 }, + { 27758, 31067 }, + { 27759, 31068 }, + { 27760, 31059 }, + { 27761, 31066 }, + { 27762, 31074 }, + { 27763, 31063 }, + { 27764, 31072 }, + { 27765, 31087 }, + { 27766, 31079 }, + { 27767, 31098 }, + { 27768, 31109 }, + { 27769, 31114 }, + { 27770, 31130 }, + { 27771, 31143 }, + { 27772, 31155 }, + { 27773, 24529 }, + { 27774, 24528 }, + { 27937, 24636 }, + { 27938, 24669 }, + { 27939, 24666 }, + { 27940, 24679 }, + { 27941, 24641 }, + { 27942, 24665 }, + { 27943, 24675 }, + { 27944, 24747 }, + { 27945, 24838 }, + { 27946, 24845 }, + { 27947, 24925 }, + { 27948, 25001 }, + { 27949, 24989 }, + { 27950, 25035 }, + { 27951, 25041 }, + { 27952, 25094 }, + { 27953, 32896 }, + { 27954, 32895 }, + { 27955, 27795 }, + { 27956, 27894 }, + { 27957, 28156 }, + { 27958, 30710 }, + { 27959, 30712 }, + { 27960, 30720 }, + { 27961, 30729 }, + { 27962, 30743 }, + { 27963, 30744 }, + { 27964, 30737 }, + { 27965, 26027 }, + { 27966, 30765 }, + { 27967, 30748 }, + { 27968, 30749 }, + { 27969, 30777 }, + { 27970, 30778 }, + { 27971, 30779 }, + { 27972, 30751 }, + { 27973, 30780 }, + { 27974, 30757 }, + { 27975, 30764 }, + { 27976, 30755 }, + { 27977, 30761 }, + { 27978, 30798 }, + { 27979, 30829 }, + { 27980, 30806 }, + { 27981, 30807 }, + { 27982, 30758 }, + { 27983, 30800 }, + { 27984, 30791 }, + { 27985, 30796 }, + { 27986, 30826 }, + { 27987, 30875 }, + { 27988, 30867 }, + { 27989, 30874 }, + { 27990, 30855 }, + { 27991, 30876 }, + { 27992, 30881 }, + { 27993, 30883 }, + { 27994, 30898 }, + { 27995, 30905 }, + { 27996, 30885 }, + { 27997, 30932 }, + { 27998, 30937 }, + { 27999, 30921 }, + { 28000, 30956 }, + { 28001, 30962 }, + { 28002, 30981 }, + { 28003, 30964 }, + { 28004, 30995 }, + { 28005, 31012 }, + { 28006, 31006 }, + { 28007, 31028 }, + { 28008, 40859 }, + { 28009, 40697 }, + { 28010, 40699 }, + { 28011, 40700 }, + { 28012, 30449 }, + { 28013, 30468 }, + { 28014, 30477 }, + { 28015, 30457 }, + { 28016, 30471 }, + { 28017, 30472 }, + { 28018, 30490 }, + { 28019, 30498 }, + { 28020, 30489 }, + { 28021, 30509 }, + { 28022, 30502 }, + { 28023, 30517 }, + { 28024, 30520 }, + { 28025, 30544 }, + { 28026, 30545 }, + { 28027, 30535 }, + { 28028, 30531 }, + { 28029, 30554 }, + { 28030, 30568 }, + { 28193, 30562 }, + { 28194, 30565 }, + { 28195, 30591 }, + { 28196, 30605 }, + { 28197, 30589 }, + { 28198, 30592 }, + { 28199, 30604 }, + { 28200, 30609 }, + { 28201, 30623 }, + { 28202, 30624 }, + { 28203, 30640 }, + { 28204, 30645 }, + { 28205, 30653 }, + { 28206, 30010 }, + { 28207, 30016 }, + { 28208, 30030 }, + { 28209, 30027 }, + { 28210, 30024 }, + { 28211, 30043 }, + { 28212, 30066 }, + { 28213, 30073 }, + { 28214, 30083 }, + { 28215, 32600 }, + { 28216, 32609 }, + { 28217, 32607 }, + { 28218, 35400 }, + { 28219, 32616 }, + { 28220, 32628 }, + { 28221, 32625 }, + { 28222, 32633 }, + { 28223, 32641 }, + { 28224, 32638 }, + { 28225, 30413 }, + { 28226, 30437 }, + { 28227, 34866 }, + { 28228, 38021 }, + { 28229, 38022 }, + { 28230, 38023 }, + { 28231, 38027 }, + { 28232, 38026 }, + { 28233, 38028 }, + { 28234, 38029 }, + { 28235, 38031 }, + { 28236, 38032 }, + { 28237, 38036 }, + { 28238, 38039 }, + { 28239, 38037 }, + { 28240, 38042 }, + { 28241, 38043 }, + { 28242, 38044 }, + { 28243, 38051 }, + { 28244, 38052 }, + { 28245, 38059 }, + { 28246, 38058 }, + { 28247, 38061 }, + { 28248, 38060 }, + { 28249, 38063 }, + { 28250, 38064 }, + { 28251, 38066 }, + { 28252, 38068 }, + { 28253, 38070 }, + { 28254, 38071 }, + { 28255, 38072 }, + { 28256, 38073 }, + { 28257, 38074 }, + { 28258, 38076 }, + { 28259, 38077 }, + { 28260, 38079 }, + { 28261, 38084 }, + { 28262, 38088 }, + { 28263, 38089 }, + { 28264, 38090 }, + { 28265, 38091 }, + { 28266, 38092 }, + { 28267, 38093 }, + { 28268, 38094 }, + { 28269, 38096 }, + { 28270, 38097 }, + { 28271, 38098 }, + { 28272, 38101 }, + { 28273, 38102 }, + { 28274, 38103 }, + { 28275, 38105 }, + { 28276, 38104 }, + { 28277, 38107 }, + { 28278, 38110 }, + { 28279, 38111 }, + { 28280, 38112 }, + { 28281, 38114 }, + { 28282, 38116 }, + { 28283, 38117 }, + { 28284, 38119 }, + { 28285, 38120 }, + { 28286, 38122 }, + { 28449, 38121 }, + { 28450, 38123 }, + { 28451, 38126 }, + { 28452, 38127 }, + { 28453, 38131 }, + { 28454, 38132 }, + { 28455, 38133 }, + { 28456, 38135 }, + { 28457, 38137 }, + { 28458, 38140 }, + { 28459, 38141 }, + { 28460, 38143 }, + { 28461, 38147 }, + { 28462, 38146 }, + { 28463, 38150 }, + { 28464, 38151 }, + { 28465, 38153 }, + { 28466, 38154 }, + { 28467, 38157 }, + { 28468, 38158 }, + { 28469, 38159 }, + { 28470, 38162 }, + { 28471, 38163 }, + { 28472, 38164 }, + { 28473, 38165 }, + { 28474, 38166 }, + { 28475, 38168 }, + { 28476, 38171 }, + { 28477, 38173 }, + { 28478, 38174 }, + { 28479, 38175 }, + { 28480, 38178 }, + { 28481, 38186 }, + { 28482, 38187 }, + { 28483, 38185 }, + { 28484, 38188 }, + { 28485, 38193 }, + { 28486, 38194 }, + { 28487, 38196 }, + { 28488, 38198 }, + { 28489, 38199 }, + { 28490, 38200 }, + { 28491, 38204 }, + { 28492, 38206 }, + { 28493, 38207 }, + { 28494, 38210 }, + { 28495, 38197 }, + { 28496, 38212 }, + { 28497, 38213 }, + { 28498, 38214 }, + { 28499, 38217 }, + { 28500, 38220 }, + { 28501, 38222 }, + { 28502, 38223 }, + { 28503, 38226 }, + { 28504, 38227 }, + { 28505, 38228 }, + { 28506, 38230 }, + { 28507, 38231 }, + { 28508, 38232 }, + { 28509, 38233 }, + { 28510, 38235 }, + { 28511, 38238 }, + { 28512, 38239 }, + { 28513, 38237 }, + { 28514, 38241 }, + { 28515, 38242 }, + { 28516, 38244 }, + { 28517, 38245 }, + { 28518, 38246 }, + { 28519, 38247 }, + { 28520, 38248 }, + { 28521, 38249 }, + { 28522, 38250 }, + { 28523, 38251 }, + { 28524, 38252 }, + { 28525, 38255 }, + { 28526, 38257 }, + { 28527, 38258 }, + { 28528, 38259 }, + { 28529, 38202 }, + { 28530, 30695 }, + { 28531, 30700 }, + { 28532, 38601 }, + { 28533, 31189 }, + { 28534, 31213 }, + { 28535, 31203 }, + { 28536, 31211 }, + { 28537, 31238 }, + { 28538, 23879 }, + { 28539, 31235 }, + { 28540, 31234 }, + { 28541, 31262 }, + { 28542, 31252 }, + { 28705, 31289 }, + { 28706, 31287 }, + { 28707, 31313 }, + { 28708, 40655 }, + { 28709, 39333 }, + { 28710, 31344 }, + { 28711, 30344 }, + { 28712, 30350 }, + { 28713, 30355 }, + { 28714, 30361 }, + { 28715, 30372 }, + { 28716, 29918 }, + { 28717, 29920 }, + { 28718, 29996 }, + { 28719, 40480 }, + { 28720, 40482 }, + { 28721, 40488 }, + { 28722, 40489 }, + { 28723, 40490 }, + { 28724, 40491 }, + { 28725, 40492 }, + { 28726, 40498 }, + { 28727, 40497 }, + { 28728, 40502 }, + { 28729, 40504 }, + { 28730, 40503 }, + { 28731, 40505 }, + { 28732, 40506 }, + { 28733, 40510 }, + { 28734, 40513 }, + { 28735, 40514 }, + { 28736, 40516 }, + { 28737, 40518 }, + { 28738, 40519 }, + { 28739, 40520 }, + { 28740, 40521 }, + { 28741, 40523 }, + { 28742, 40524 }, + { 28743, 40526 }, + { 28744, 40529 }, + { 28745, 40533 }, + { 28746, 40535 }, + { 28747, 40538 }, + { 28748, 40539 }, + { 28749, 40540 }, + { 28750, 40542 }, + { 28751, 40547 }, + { 28752, 40550 }, + { 28753, 40551 }, + { 28754, 40552 }, + { 28755, 40553 }, + { 28756, 40554 }, + { 28757, 40555 }, + { 28758, 40556 }, + { 28759, 40561 }, + { 28760, 40557 }, + { 28761, 40563 }, + { 28762, 30098 }, + { 28763, 30100 }, + { 28764, 30102 }, + { 28765, 30112 }, + { 28766, 30109 }, + { 28767, 30124 }, + { 28768, 30115 }, + { 28769, 30131 }, + { 28770, 30132 }, + { 28771, 30136 }, + { 28772, 30148 }, + { 28773, 30129 }, + { 28774, 30128 }, + { 28775, 30147 }, + { 28776, 30146 }, + { 28777, 30166 }, + { 28778, 30157 }, + { 28779, 30179 }, + { 28780, 30184 }, + { 28781, 30182 }, + { 28782, 30180 }, + { 28783, 30187 }, + { 28784, 30183 }, + { 28785, 30211 }, + { 28786, 30193 }, + { 28787, 30204 }, + { 28788, 30207 }, + { 28789, 30224 }, + { 28790, 30208 }, + { 28791, 30213 }, + { 28792, 30220 }, + { 28793, 30231 }, + { 28794, 30218 }, + { 28795, 30245 }, + { 28796, 30232 }, + { 28797, 30229 }, + { 28798, 30233 }, + { 28961, 30235 }, + { 28962, 30268 }, + { 28963, 30242 }, + { 28964, 30240 }, + { 28965, 30272 }, + { 28966, 30253 }, + { 28967, 30256 }, + { 28968, 30271 }, + { 28969, 30261 }, + { 28970, 30275 }, + { 28971, 30270 }, + { 28972, 30259 }, + { 28973, 30285 }, + { 28974, 30302 }, + { 28975, 30292 }, + { 28976, 30300 }, + { 28977, 30294 }, + { 28978, 30315 }, + { 28979, 30319 }, + { 28980, 32714 }, + { 28981, 31462 }, + { 28982, 31352 }, + { 28983, 31353 }, + { 28984, 31360 }, + { 28985, 31366 }, + { 28986, 31368 }, + { 28987, 31381 }, + { 28988, 31398 }, + { 28989, 31392 }, + { 28990, 31404 }, + { 28991, 31400 }, + { 28992, 31405 }, + { 28993, 31411 }, + { 28994, 34916 }, + { 28995, 34921 }, + { 28996, 34930 }, + { 28997, 34941 }, + { 28998, 34943 }, + { 28999, 34946 }, + { 29000, 34978 }, + { 29001, 35014 }, + { 29002, 34999 }, + { 29003, 35004 }, + { 29004, 35017 }, + { 29005, 35042 }, + { 29006, 35022 }, + { 29007, 35043 }, + { 29008, 35045 }, + { 29009, 35057 }, + { 29010, 35098 }, + { 29011, 35068 }, + { 29012, 35048 }, + { 29013, 35070 }, + { 29014, 35056 }, + { 29015, 35105 }, + { 29016, 35097 }, + { 29017, 35091 }, + { 29018, 35099 }, + { 29019, 35082 }, + { 29020, 35124 }, + { 29021, 35115 }, + { 29022, 35126 }, + { 29023, 35137 }, + { 29024, 35174 }, + { 29025, 35195 }, + { 29026, 30091 }, + { 29027, 32997 }, + { 29028, 30386 }, + { 29029, 30388 }, + { 29030, 30684 }, + { 29031, 32786 }, + { 29032, 32788 }, + { 29033, 32790 }, + { 29034, 32796 }, + { 29035, 32800 }, + { 29036, 32802 }, + { 29037, 32805 }, + { 29038, 32806 }, + { 29039, 32807 }, + { 29040, 32809 }, + { 29041, 32808 }, + { 29042, 32817 }, + { 29043, 32779 }, + { 29044, 32821 }, + { 29045, 32835 }, + { 29046, 32838 }, + { 29047, 32845 }, + { 29048, 32850 }, + { 29049, 32873 }, + { 29050, 32881 }, + { 29051, 35203 }, + { 29052, 39032 }, + { 29053, 39040 }, + { 29054, 39043 }, + { 29217, 39049 }, + { 29218, 39052 }, + { 29219, 39053 }, + { 29220, 39055 }, + { 29221, 39060 }, + { 29222, 39066 }, + { 29223, 39067 }, + { 29224, 39070 }, + { 29225, 39071 }, + { 29226, 39073 }, + { 29227, 39074 }, + { 29228, 39077 }, + { 29229, 39078 }, + { 29230, 34381 }, + { 29231, 34388 }, + { 29232, 34412 }, + { 29233, 34414 }, + { 29234, 34431 }, + { 29235, 34426 }, + { 29236, 34428 }, + { 29237, 34427 }, + { 29238, 34472 }, + { 29239, 34445 }, + { 29240, 34443 }, + { 29241, 34476 }, + { 29242, 34461 }, + { 29243, 34471 }, + { 29244, 34467 }, + { 29245, 34474 }, + { 29246, 34451 }, + { 29247, 34473 }, + { 29248, 34486 }, + { 29249, 34500 }, + { 29250, 34485 }, + { 29251, 34510 }, + { 29252, 34480 }, + { 29253, 34490 }, + { 29254, 34481 }, + { 29255, 34479 }, + { 29256, 34505 }, + { 29257, 34511 }, + { 29258, 34484 }, + { 29259, 34537 }, + { 29260, 34545 }, + { 29261, 34546 }, + { 29262, 34541 }, + { 29263, 34547 }, + { 29264, 34512 }, + { 29265, 34579 }, + { 29266, 34526 }, + { 29267, 34548 }, + { 29268, 34527 }, + { 29269, 34520 }, + { 29270, 34513 }, + { 29271, 34563 }, + { 29272, 34567 }, + { 29273, 34552 }, + { 29274, 34568 }, + { 29275, 34570 }, + { 29276, 34573 }, + { 29277, 34569 }, + { 29278, 34595 }, + { 29279, 34619 }, + { 29280, 34590 }, + { 29281, 34597 }, + { 29282, 34606 }, + { 29283, 34586 }, + { 29284, 34622 }, + { 29285, 34632 }, + { 29286, 34612 }, + { 29287, 34609 }, + { 29288, 34601 }, + { 29289, 34615 }, + { 29290, 34623 }, + { 29291, 34690 }, + { 29292, 34594 }, + { 29293, 34685 }, + { 29294, 34686 }, + { 29295, 34683 }, + { 29296, 34656 }, + { 29297, 34672 }, + { 29298, 34636 }, + { 29299, 34670 }, + { 29300, 34699 }, + { 29301, 34643 }, + { 29302, 34659 }, + { 29303, 34684 }, + { 29304, 34660 }, + { 29305, 34649 }, + { 29306, 34661 }, + { 29307, 34707 }, + { 29308, 34735 }, + { 29309, 34728 }, + { 29310, 34770 }, + { 29473, 34758 }, + { 29474, 34696 }, + { 29475, 34693 }, + { 29476, 34733 }, + { 29477, 34711 }, + { 29478, 34691 }, + { 29479, 34731 }, + { 29480, 34789 }, + { 29481, 34732 }, + { 29482, 34741 }, + { 29483, 34739 }, + { 29484, 34763 }, + { 29485, 34771 }, + { 29486, 34749 }, + { 29487, 34769 }, + { 29488, 34752 }, + { 29489, 34762 }, + { 29490, 34779 }, + { 29491, 34794 }, + { 29492, 34784 }, + { 29493, 34798 }, + { 29494, 34838 }, + { 29495, 34835 }, + { 29496, 34814 }, + { 29497, 34826 }, + { 29498, 34843 }, + { 29499, 34849 }, + { 29500, 34873 }, + { 29501, 34876 }, + { 29502, 32566 }, + { 29503, 32578 }, + { 29504, 32580 }, + { 29505, 32581 }, + { 29506, 33296 }, + { 29507, 31482 }, + { 29508, 31485 }, + { 29509, 31496 }, + { 29510, 31491 }, + { 29511, 31492 }, + { 29512, 31509 }, + { 29513, 31498 }, + { 29514, 31531 }, + { 29515, 31503 }, + { 29516, 31559 }, + { 29517, 31544 }, + { 29518, 31530 }, + { 29519, 31513 }, + { 29520, 31534 }, + { 29521, 31537 }, + { 29522, 31520 }, + { 29523, 31525 }, + { 29524, 31524 }, + { 29525, 31539 }, + { 29526, 31550 }, + { 29527, 31518 }, + { 29528, 31576 }, + { 29529, 31578 }, + { 29530, 31557 }, + { 29531, 31605 }, + { 29532, 31564 }, + { 29533, 31581 }, + { 29534, 31584 }, + { 29535, 31598 }, + { 29536, 31611 }, + { 29537, 31586 }, + { 29538, 31602 }, + { 29539, 31601 }, + { 29540, 31632 }, + { 29541, 31654 }, + { 29542, 31655 }, + { 29543, 31672 }, + { 29544, 31660 }, + { 29545, 31645 }, + { 29546, 31656 }, + { 29547, 31621 }, + { 29548, 31658 }, + { 29549, 31644 }, + { 29550, 31650 }, + { 29551, 31659 }, + { 29552, 31668 }, + { 29553, 31697 }, + { 29554, 31681 }, + { 29555, 31692 }, + { 29556, 31709 }, + { 29557, 31706 }, + { 29558, 31717 }, + { 29559, 31718 }, + { 29560, 31722 }, + { 29561, 31756 }, + { 29562, 31742 }, + { 29563, 31740 }, + { 29564, 31759 }, + { 29565, 31766 }, + { 29566, 31755 }, + { 29729, 31775 }, + { 29730, 31786 }, + { 29731, 31782 }, + { 29732, 31800 }, + { 29733, 31809 }, + { 29734, 31808 }, + { 29735, 33278 }, + { 29736, 33281 }, + { 29737, 33282 }, + { 29738, 33284 }, + { 29739, 33260 }, + { 29740, 34884 }, + { 29741, 33313 }, + { 29742, 33314 }, + { 29743, 33315 }, + { 29744, 33325 }, + { 29745, 33327 }, + { 29746, 33320 }, + { 29747, 33323 }, + { 29748, 33336 }, + { 29749, 33339 }, + { 29750, 33331 }, + { 29751, 33332 }, + { 29752, 33342 }, + { 29753, 33348 }, + { 29754, 33353 }, + { 29755, 33355 }, + { 29756, 33359 }, + { 29757, 33370 }, + { 29758, 33375 }, + { 29759, 33384 }, + { 29760, 34942 }, + { 29761, 34949 }, + { 29762, 34952 }, + { 29763, 35032 }, + { 29764, 35039 }, + { 29765, 35166 }, + { 29766, 32669 }, + { 29767, 32671 }, + { 29768, 32679 }, + { 29769, 32687 }, + { 29770, 32688 }, + { 29771, 32690 }, + { 29772, 31868 }, + { 29773, 25929 }, + { 29774, 31889 }, + { 29775, 31901 }, + { 29776, 31900 }, + { 29777, 31902 }, + { 29778, 31906 }, + { 29779, 31922 }, + { 29780, 31932 }, + { 29781, 31933 }, + { 29782, 31937 }, + { 29783, 31943 }, + { 29784, 31948 }, + { 29785, 31949 }, + { 29786, 31944 }, + { 29787, 31941 }, + { 29788, 31959 }, + { 29789, 31976 }, + { 29790, 33390 }, + { 29791, 26280 }, + { 29792, 32703 }, + { 29793, 32718 }, + { 29794, 32725 }, + { 29795, 32741 }, + { 29796, 32737 }, + { 29797, 32742 }, + { 29798, 32745 }, + { 29799, 32750 }, + { 29800, 32755 }, + { 29801, 31992 }, + { 29802, 32119 }, + { 29803, 32166 }, + { 29804, 32174 }, + { 29805, 32327 }, + { 29806, 32411 }, + { 29807, 40632 }, + { 29808, 40628 }, + { 29809, 36211 }, + { 29810, 36228 }, + { 29811, 36244 }, + { 29812, 36241 }, + { 29813, 36273 }, + { 29814, 36199 }, + { 29815, 36205 }, + { 29816, 35911 }, + { 29817, 35913 }, + { 29818, 37194 }, + { 29819, 37200 }, + { 29820, 37198 }, + { 29821, 37199 }, + { 29822, 37220 }, + { 29985, 37218 }, + { 29986, 37217 }, + { 29987, 37232 }, + { 29988, 37225 }, + { 29989, 37231 }, + { 29990, 37245 }, + { 29991, 37246 }, + { 29992, 37234 }, + { 29993, 37236 }, + { 29994, 37241 }, + { 29995, 37260 }, + { 29996, 37253 }, + { 29997, 37264 }, + { 29998, 37261 }, + { 29999, 37265 }, + { 30000, 37282 }, + { 30001, 37283 }, + { 30002, 37290 }, + { 30003, 37293 }, + { 30004, 37294 }, + { 30005, 37295 }, + { 30006, 37301 }, + { 30007, 37300 }, + { 30008, 37306 }, + { 30009, 35925 }, + { 30010, 40574 }, + { 30011, 36280 }, + { 30012, 36331 }, + { 30013, 36357 }, + { 30014, 36441 }, + { 30015, 36457 }, + { 30016, 36277 }, + { 30017, 36287 }, + { 30018, 36284 }, + { 30019, 36282 }, + { 30020, 36292 }, + { 30021, 36310 }, + { 30022, 36311 }, + { 30023, 36314 }, + { 30024, 36318 }, + { 30025, 36302 }, + { 30026, 36303 }, + { 30027, 36315 }, + { 30028, 36294 }, + { 30029, 36332 }, + { 30030, 36343 }, + { 30031, 36344 }, + { 30032, 36323 }, + { 30033, 36345 }, + { 30034, 36347 }, + { 30035, 36324 }, + { 30036, 36361 }, + { 30037, 36349 }, + { 30038, 36372 }, + { 30039, 36381 }, + { 30040, 36383 }, + { 30041, 36396 }, + { 30042, 36398 }, + { 30043, 36387 }, + { 30044, 36399 }, + { 30045, 36410 }, + { 30046, 36416 }, + { 30047, 36409 }, + { 30048, 36405 }, + { 30049, 36413 }, + { 30050, 36401 }, + { 30051, 36425 }, + { 30052, 36417 }, + { 30053, 36418 }, + { 30054, 36433 }, + { 30055, 36434 }, + { 30056, 36426 }, + { 30057, 36464 }, + { 30058, 36470 }, + { 30059, 36476 }, + { 30060, 36463 }, + { 30061, 36468 }, + { 30062, 36485 }, + { 30063, 36495 }, + { 30064, 36500 }, + { 30065, 36496 }, + { 30066, 36508 }, + { 30067, 36510 }, + { 30068, 35960 }, + { 30069, 35970 }, + { 30070, 35978 }, + { 30071, 35973 }, + { 30072, 35992 }, + { 30073, 35988 }, + { 30074, 26011 }, + { 30075, 35286 }, + { 30076, 35294 }, + { 30077, 35290 }, + { 30078, 35292 }, + { 30241, 35301 }, + { 30242, 35307 }, + { 30243, 35311 }, + { 30244, 35390 }, + { 30245, 35622 }, + { 30246, 38739 }, + { 30247, 38633 }, + { 30248, 38643 }, + { 30249, 38639 }, + { 30250, 38662 }, + { 30251, 38657 }, + { 30252, 38664 }, + { 30253, 38671 }, + { 30254, 38670 }, + { 30255, 38698 }, + { 30256, 38701 }, + { 30257, 38704 }, + { 30258, 38718 }, + { 30259, 40832 }, + { 30260, 40835 }, + { 30261, 40837 }, + { 30262, 40838 }, + { 30263, 40839 }, + { 30264, 40840 }, + { 30265, 40841 }, + { 30266, 40842 }, + { 30267, 40844 }, + { 30268, 40702 }, + { 30269, 40715 }, + { 30270, 40717 }, + { 30271, 38585 }, + { 30272, 38588 }, + { 30273, 38589 }, + { 30274, 38606 }, + { 30275, 38610 }, + { 30276, 30655 }, + { 30277, 38624 }, + { 30278, 37518 }, + { 30279, 37550 }, + { 30280, 37576 }, + { 30281, 37694 }, + { 30282, 37738 }, + { 30283, 37834 }, + { 30284, 37775 }, + { 30285, 37950 }, + { 30286, 37995 }, + { 30287, 40063 }, + { 30288, 40066 }, + { 30289, 40069 }, + { 30290, 40070 }, + { 30291, 40071 }, + { 30292, 40072 }, + { 30293, 31267 }, + { 30294, 40075 }, + { 30295, 40078 }, + { 30296, 40080 }, + { 30297, 40081 }, + { 30298, 40082 }, + { 30299, 40084 }, + { 30300, 40085 }, + { 30301, 40090 }, + { 30302, 40091 }, + { 30303, 40094 }, + { 30304, 40095 }, + { 30305, 40096 }, + { 30306, 40097 }, + { 30307, 40098 }, + { 30308, 40099 }, + { 30309, 40101 }, + { 30310, 40102 }, + { 30311, 40103 }, + { 30312, 40104 }, + { 30313, 40105 }, + { 30314, 40107 }, + { 30315, 40109 }, + { 30316, 40110 }, + { 30317, 40112 }, + { 30318, 40113 }, + { 30319, 40114 }, + { 30320, 40115 }, + { 30321, 40116 }, + { 30322, 40117 }, + { 30323, 40118 }, + { 30324, 40119 }, + { 30325, 40122 }, + { 30326, 40123 }, + { 30327, 40124 }, + { 30328, 40125 }, + { 30329, 40132 }, + { 30330, 40133 }, + { 30331, 40134 }, + { 30332, 40135 }, + { 30333, 40138 }, + { 30334, 40139 }, + { 30497, 40140 }, + { 30498, 40141 }, + { 30499, 40142 }, + { 30500, 40143 }, + { 30501, 40144 }, + { 30502, 40147 }, + { 30503, 40148 }, + { 30504, 40149 }, + { 30505, 40151 }, + { 30506, 40152 }, + { 30507, 40153 }, + { 30508, 40156 }, + { 30509, 40157 }, + { 30510, 40159 }, + { 30511, 40162 }, + { 30512, 38780 }, + { 30513, 38789 }, + { 30514, 38801 }, + { 30515, 38802 }, + { 30516, 38804 }, + { 30517, 38831 }, + { 30518, 38827 }, + { 30519, 38819 }, + { 30520, 38834 }, + { 30521, 38836 }, + { 30522, 39601 }, + { 30523, 39600 }, + { 30524, 39607 }, + { 30525, 40536 }, + { 30526, 39606 }, + { 30527, 39610 }, + { 30528, 39612 }, + { 30529, 39617 }, + { 30530, 39616 }, + { 30531, 39621 }, + { 30532, 39618 }, + { 30533, 39627 }, + { 30534, 39628 }, + { 30535, 39633 }, + { 30536, 39749 }, + { 30537, 39747 }, + { 30538, 39751 }, + { 30539, 39753 }, + { 30540, 39752 }, + { 30541, 39757 }, + { 30542, 39761 }, + { 30543, 39144 }, + { 30544, 39181 }, + { 30545, 39214 }, + { 30546, 39253 }, + { 30547, 39252 }, + { 30548, 39647 }, + { 30549, 39649 }, + { 30550, 39654 }, + { 30551, 39663 }, + { 30552, 39659 }, + { 30553, 39675 }, + { 30554, 39661 }, + { 30555, 39673 }, + { 30556, 39688 }, + { 30557, 39695 }, + { 30558, 39699 }, + { 30559, 39711 }, + { 30560, 39715 }, + { 30561, 40637 }, + { 30562, 40638 }, + { 30563, 32315 }, + { 30564, 40578 }, + { 30565, 40583 }, + { 30566, 40584 }, + { 30567, 40587 }, + { 30568, 40594 }, + { 30569, 37846 }, + { 30570, 40605 }, + { 30571, 40607 }, + { 30572, 40667 }, + { 30573, 40668 }, + { 30574, 40669 }, + { 30575, 40672 }, + { 30576, 40671 }, + { 30577, 40674 }, + { 30578, 40681 }, + { 30579, 40679 }, + { 30580, 40677 }, + { 30581, 40682 }, + { 30582, 40687 }, + { 30583, 40738 }, + { 30584, 40748 }, + { 30585, 40751 }, + { 30586, 40761 }, + { 30587, 40759 }, + { 30588, 40765 }, + { 30589, 40766 }, + { 30590, 40772 }, +}; + +static const encoding_convert_entry Big5ToUnicodeTable[13710] = { + { 0xA140, 0x3000 }, + { 0xA141, 0xFF0C }, + { 0xA142, 0x3001 }, + { 0xA143, 0x3002 }, + { 0xA144, 0xFF0E }, + { 0xA145, 0x2022 }, + { 0xA146, 0xFF1B }, + { 0xA147, 0xFF1A }, + { 0xA148, 0xFF1F }, + { 0xA149, 0xFF01 }, + { 0xA14A, 0xFE30 }, + { 0xA14B, 0x2026 }, + { 0xA14C, 0x2025 }, + { 0xA14D, 0xFE50 }, + { 0xA14E, 0xFF64 }, + { 0xA14F, 0xFE52 }, + { 0xA150, 0x00B7 }, + { 0xA151, 0xFE54 }, + { 0xA152, 0xFE55 }, + { 0xA153, 0xFE56 }, + { 0xA154, 0xFE57 }, + { 0xA155, 0xFF5C }, + { 0xA156, 0x2013 }, + { 0xA157, 0xFE31 }, + { 0xA158, 0x2014 }, + { 0xA159, 0xFE33 }, + { 0xA15A, 0xFFFD }, + { 0xA15B, 0xFE34 }, + { 0xA15C, 0xFE4F }, + { 0xA15D, 0xFF08 }, + { 0xA15E, 0xFF09 }, + { 0xA15F, 0xFE35 }, + { 0xA160, 0xFE36 }, + { 0xA161, 0xFF5B }, + { 0xA162, 0xFF5D }, + { 0xA163, 0xFE37 }, + { 0xA164, 0xFE38 }, + { 0xA165, 0x3014 }, + { 0xA166, 0x3015 }, + { 0xA167, 0xFE39 }, + { 0xA168, 0xFE3A }, + { 0xA169, 0x3010 }, + { 0xA16A, 0x3011 }, + { 0xA16B, 0xFE3B }, + { 0xA16C, 0xFE3C }, + { 0xA16D, 0x300A }, + { 0xA16E, 0x300B }, + { 0xA16F, 0xFE3D }, + { 0xA170, 0xFE3E }, + { 0xA171, 0x3008 }, + { 0xA172, 0x3009 }, + { 0xA173, 0xFE3F }, + { 0xA174, 0xFE40 }, + { 0xA175, 0x300C }, + { 0xA176, 0x300D }, + { 0xA177, 0xFE41 }, + { 0xA178, 0xFE42 }, + { 0xA179, 0x300E }, + { 0xA17A, 0x300F }, + { 0xA17B, 0xFE43 }, + { 0xA17C, 0xFE44 }, + { 0xA17D, 0xFE59 }, + { 0xA17E, 0xFE5A }, + { 0xA1A1, 0xFE5B }, + { 0xA1A2, 0xFE5C }, + { 0xA1A3, 0xFE5D }, + { 0xA1A4, 0xFE5E }, + { 0xA1A5, 0x2018 }, + { 0xA1A6, 0x2019 }, + { 0xA1A7, 0x201C }, + { 0xA1A8, 0x201D }, + { 0xA1A9, 0x301D }, + { 0xA1AA, 0x301E }, + { 0xA1AB, 0x2035 }, + { 0xA1AC, 0x2032 }, + { 0xA1AD, 0xFF03 }, + { 0xA1AE, 0xFF06 }, + { 0xA1AF, 0xFF0A }, + { 0xA1B0, 0x203B }, + { 0xA1B1, 0x00A7 }, + { 0xA1B2, 0x3003 }, + { 0xA1B3, 0x25CB }, + { 0xA1B4, 0x25CF }, + { 0xA1B5, 0x25B3 }, + { 0xA1B6, 0x25B2 }, + { 0xA1B7, 0x25CE }, + { 0xA1B8, 0x2606 }, + { 0xA1B9, 0x2605 }, + { 0xA1BA, 0x25C7 }, + { 0xA1BB, 0x25C6 }, + { 0xA1BC, 0x25A1 }, + { 0xA1BD, 0x25A0 }, + { 0xA1BE, 0x25BD }, + { 0xA1BF, 0x25BC }, + { 0xA1C0, 0x32A3 }, + { 0xA1C1, 0x2105 }, + { 0xA1C2, 0x203E }, + { 0xA1C3, 0xFFFD }, + { 0xA1C4, 0xFF3F }, + { 0xA1C5, 0xFFFD }, + { 0xA1C6, 0xFE49 }, + { 0xA1C7, 0xFE4A }, + { 0xA1C8, 0xFE4D }, + { 0xA1C9, 0xFE4E }, + { 0xA1CA, 0xFE4B }, + { 0xA1CB, 0xFE4C }, + { 0xA1CC, 0xFE5F }, + { 0xA1CD, 0xFE60 }, + { 0xA1CE, 0xFE61 }, + { 0xA1CF, 0xFF0B }, + { 0xA1D0, 0xFF0D }, + { 0xA1D1, 0x00D7 }, + { 0xA1D2, 0x00F7 }, + { 0xA1D3, 0x00B1 }, + { 0xA1D4, 0x221A }, + { 0xA1D5, 0xFF1C }, + { 0xA1D6, 0xFF1E }, + { 0xA1D7, 0xFF1D }, + { 0xA1D8, 0x2266 }, + { 0xA1D9, 0x2267 }, + { 0xA1DA, 0x2260 }, + { 0xA1DB, 0x221E }, + { 0xA1DC, 0x2252 }, + { 0xA1DD, 0x2261 }, + { 0xA1DE, 0xFE62 }, + { 0xA1DF, 0xFE63 }, + { 0xA1E0, 0xFE64 }, + { 0xA1E1, 0xFE65 }, + { 0xA1E2, 0xFE66 }, + { 0xA1E3, 0x223C }, + { 0xA1E4, 0x2229 }, + { 0xA1E5, 0x222A }, + { 0xA1E6, 0x22A5 }, + { 0xA1E7, 0x2220 }, + { 0xA1E8, 0x221F }, + { 0xA1E9, 0x22BF }, + { 0xA1EA, 0x33D2 }, + { 0xA1EB, 0x33D1 }, + { 0xA1EC, 0x222B }, + { 0xA1ED, 0x222E }, + { 0xA1EE, 0x2235 }, + { 0xA1EF, 0x2234 }, + { 0xA1F0, 0x2640 }, + { 0xA1F1, 0x2642 }, + { 0xA1F2, 0x2641 }, + { 0xA1F3, 0x2609 }, + { 0xA1F4, 0x2191 }, + { 0xA1F5, 0x2193 }, + { 0xA1F6, 0x2190 }, + { 0xA1F7, 0x2192 }, + { 0xA1F8, 0x2196 }, + { 0xA1F9, 0x2197 }, + { 0xA1FA, 0x2199 }, + { 0xA1FB, 0x2198 }, + { 0xA1FC, 0x2225 }, + { 0xA1FD, 0x2223 }, + { 0xA1FE, 0xFFFD }, + { 0xA240, 0xFFFD }, + { 0xA241, 0xFF0F }, + { 0xA242, 0xFF3C }, + { 0xA243, 0xFF04 }, + { 0xA244, 0x00A5 }, + { 0xA245, 0x3012 }, + { 0xA246, 0x00A2 }, + { 0xA247, 0x00A3 }, + { 0xA248, 0xFF05 }, + { 0xA249, 0xFF20 }, + { 0xA24A, 0x2103 }, + { 0xA24B, 0x2109 }, + { 0xA24C, 0xFE69 }, + { 0xA24D, 0xFE6A }, + { 0xA24E, 0xFE6B }, + { 0xA24F, 0x33D5 }, + { 0xA250, 0x339C }, + { 0xA251, 0x339D }, + { 0xA252, 0x339E }, + { 0xA253, 0x33CE }, + { 0xA254, 0x33A1 }, + { 0xA255, 0x338E }, + { 0xA256, 0x338F }, + { 0xA257, 0x33C4 }, + { 0xA258, 0x00B0 }, + { 0xA259, 0x5159 }, + { 0xA25A, 0x515B }, + { 0xA25B, 0x515E }, + { 0xA25C, 0x515D }, + { 0xA25D, 0x5161 }, + { 0xA25E, 0x5163 }, + { 0xA25F, 0x55E7 }, + { 0xA260, 0x74E9 }, + { 0xA261, 0x7CCE }, + { 0xA262, 0x2581 }, + { 0xA263, 0x2582 }, + { 0xA264, 0x2583 }, + { 0xA265, 0x2584 }, + { 0xA266, 0x2585 }, + { 0xA267, 0x2586 }, + { 0xA268, 0x2587 }, + { 0xA269, 0x2588 }, + { 0xA26A, 0x258F }, + { 0xA26B, 0x258E }, + { 0xA26C, 0x258D }, + { 0xA26D, 0x258C }, + { 0xA26E, 0x258B }, + { 0xA26F, 0x258A }, + { 0xA270, 0x2589 }, + { 0xA271, 0x253C }, + { 0xA272, 0x2534 }, + { 0xA273, 0x252C }, + { 0xA274, 0x2524 }, + { 0xA275, 0x251C }, + { 0xA276, 0x2594 }, + { 0xA277, 0x2500 }, + { 0xA278, 0x2502 }, + { 0xA279, 0x2595 }, + { 0xA27A, 0x250C }, + { 0xA27B, 0x2510 }, + { 0xA27C, 0x2514 }, + { 0xA27D, 0x2518 }, + { 0xA27E, 0x256D }, + { 0xA2A1, 0x256E }, + { 0xA2A2, 0x2570 }, + { 0xA2A3, 0x256F }, + { 0xA2A4, 0x2550 }, + { 0xA2A5, 0x255E }, + { 0xA2A6, 0x256A }, + { 0xA2A7, 0x2561 }, + { 0xA2A8, 0x25E2 }, + { 0xA2A9, 0x25E3 }, + { 0xA2AA, 0x25E5 }, + { 0xA2AB, 0x25E4 }, + { 0xA2AC, 0x2571 }, + { 0xA2AD, 0x2572 }, + { 0xA2AE, 0x2573 }, + { 0xA2AF, 0xFF10 }, + { 0xA2B0, 0xFF11 }, + { 0xA2B1, 0xFF12 }, + { 0xA2B2, 0xFF13 }, + { 0xA2B3, 0xFF14 }, + { 0xA2B4, 0xFF15 }, + { 0xA2B5, 0xFF16 }, + { 0xA2B6, 0xFF17 }, + { 0xA2B7, 0xFF18 }, + { 0xA2B8, 0xFF19 }, + { 0xA2B9, 0x2160 }, + { 0xA2BA, 0x2161 }, + { 0xA2BB, 0x2162 }, + { 0xA2BC, 0x2163 }, + { 0xA2BD, 0x2164 }, + { 0xA2BE, 0x2165 }, + { 0xA2BF, 0x2166 }, + { 0xA2C0, 0x2167 }, + { 0xA2C1, 0x2168 }, + { 0xA2C2, 0x2169 }, + { 0xA2C3, 0x3021 }, + { 0xA2C4, 0x3022 }, + { 0xA2C5, 0x3023 }, + { 0xA2C6, 0x3024 }, + { 0xA2C7, 0x3025 }, + { 0xA2C8, 0x3026 }, + { 0xA2C9, 0x3027 }, + { 0xA2CA, 0x3028 }, + { 0xA2CB, 0x3029 }, + { 0xA2CC, 0xFFFD }, + { 0xA2CD, 0x5344 }, + { 0xA2CE, 0xFFFD }, + { 0xA2CF, 0xFF21 }, + { 0xA2D0, 0xFF22 }, + { 0xA2D1, 0xFF23 }, + { 0xA2D2, 0xFF24 }, + { 0xA2D3, 0xFF25 }, + { 0xA2D4, 0xFF26 }, + { 0xA2D5, 0xFF27 }, + { 0xA2D6, 0xFF28 }, + { 0xA2D7, 0xFF29 }, + { 0xA2D8, 0xFF2A }, + { 0xA2D9, 0xFF2B }, + { 0xA2DA, 0xFF2C }, + { 0xA2DB, 0xFF2D }, + { 0xA2DC, 0xFF2E }, + { 0xA2DD, 0xFF2F }, + { 0xA2DE, 0xFF30 }, + { 0xA2DF, 0xFF31 }, + { 0xA2E0, 0xFF32 }, + { 0xA2E1, 0xFF33 }, + { 0xA2E2, 0xFF34 }, + { 0xA2E3, 0xFF35 }, + { 0xA2E4, 0xFF36 }, + { 0xA2E5, 0xFF37 }, + { 0xA2E6, 0xFF38 }, + { 0xA2E7, 0xFF39 }, + { 0xA2E8, 0xFF3A }, + { 0xA2E9, 0xFF41 }, + { 0xA2EA, 0xFF42 }, + { 0xA2EB, 0xFF43 }, + { 0xA2EC, 0xFF44 }, + { 0xA2ED, 0xFF45 }, + { 0xA2EE, 0xFF46 }, + { 0xA2EF, 0xFF47 }, + { 0xA2F0, 0xFF48 }, + { 0xA2F1, 0xFF49 }, + { 0xA2F2, 0xFF4A }, + { 0xA2F3, 0xFF4B }, + { 0xA2F4, 0xFF4C }, + { 0xA2F5, 0xFF4D }, + { 0xA2F6, 0xFF4E }, + { 0xA2F7, 0xFF4F }, + { 0xA2F8, 0xFF50 }, + { 0xA2F9, 0xFF51 }, + { 0xA2FA, 0xFF52 }, + { 0xA2FB, 0xFF53 }, + { 0xA2FC, 0xFF54 }, + { 0xA2FD, 0xFF55 }, + { 0xA2FE, 0xFF56 }, + { 0xA340, 0xFF57 }, + { 0xA341, 0xFF58 }, + { 0xA342, 0xFF59 }, + { 0xA343, 0xFF5A }, + { 0xA344, 0x0391 }, + { 0xA345, 0x0392 }, + { 0xA346, 0x0393 }, + { 0xA347, 0x0394 }, + { 0xA348, 0x0395 }, + { 0xA349, 0x0396 }, + { 0xA34A, 0x0397 }, + { 0xA34B, 0x0398 }, + { 0xA34C, 0x0399 }, + { 0xA34D, 0x039A }, + { 0xA34E, 0x039B }, + { 0xA34F, 0x039C }, + { 0xA350, 0x039D }, + { 0xA351, 0x039E }, + { 0xA352, 0x039F }, + { 0xA353, 0x03A0 }, + { 0xA354, 0x03A1 }, + { 0xA355, 0x03A3 }, + { 0xA356, 0x03A4 }, + { 0xA357, 0x03A5 }, + { 0xA358, 0x03A6 }, + { 0xA359, 0x03A7 }, + { 0xA35A, 0x03A8 }, + { 0xA35B, 0x03A9 }, + { 0xA35C, 0x03B1 }, + { 0xA35D, 0x03B2 }, + { 0xA35E, 0x03B3 }, + { 0xA35F, 0x03B4 }, + { 0xA360, 0x03B5 }, + { 0xA361, 0x03B6 }, + { 0xA362, 0x03B7 }, + { 0xA363, 0x03B8 }, + { 0xA364, 0x03B9 }, + { 0xA365, 0x03BA }, + { 0xA366, 0x03BB }, + { 0xA367, 0x03BC }, + { 0xA368, 0x03BD }, + { 0xA369, 0x03BE }, + { 0xA36A, 0x03BF }, + { 0xA36B, 0x03C0 }, + { 0xA36C, 0x03C1 }, + { 0xA36D, 0x03C3 }, + { 0xA36E, 0x03C4 }, + { 0xA36F, 0x03C5 }, + { 0xA370, 0x03C6 }, + { 0xA371, 0x03C7 }, + { 0xA372, 0x03C8 }, + { 0xA373, 0x03C9 }, + { 0xA374, 0x3105 }, + { 0xA375, 0x3106 }, + { 0xA376, 0x3107 }, + { 0xA377, 0x3108 }, + { 0xA378, 0x3109 }, + { 0xA379, 0x310A }, + { 0xA37A, 0x310B }, + { 0xA37B, 0x310C }, + { 0xA37C, 0x310D }, + { 0xA37D, 0x310E }, + { 0xA37E, 0x310F }, + { 0xA3A1, 0x3110 }, + { 0xA3A2, 0x3111 }, + { 0xA3A3, 0x3112 }, + { 0xA3A4, 0x3113 }, + { 0xA3A5, 0x3114 }, + { 0xA3A6, 0x3115 }, + { 0xA3A7, 0x3116 }, + { 0xA3A8, 0x3117 }, + { 0xA3A9, 0x3118 }, + { 0xA3AA, 0x3119 }, + { 0xA3AB, 0x311A }, + { 0xA3AC, 0x311B }, + { 0xA3AD, 0x311C }, + { 0xA3AE, 0x311D }, + { 0xA3AF, 0x311E }, + { 0xA3B0, 0x311F }, + { 0xA3B1, 0x3120 }, + { 0xA3B2, 0x3121 }, + { 0xA3B3, 0x3122 }, + { 0xA3B4, 0x3123 }, + { 0xA3B5, 0x3124 }, + { 0xA3B6, 0x3125 }, + { 0xA3B7, 0x3126 }, + { 0xA3B8, 0x3127 }, + { 0xA3B9, 0x3128 }, + { 0xA3BA, 0x3129 }, + { 0xA3BB, 0x02D9 }, + { 0xA3BC, 0x02C9 }, + { 0xA3BD, 0x02CA }, + { 0xA3BE, 0x02C7 }, + { 0xA3BF, 0x02CB }, + { 0xA440, 0x4E00 }, + { 0xA441, 0x4E59 }, + { 0xA442, 0x4E01 }, + { 0xA443, 0x4E03 }, + { 0xA444, 0x4E43 }, + { 0xA445, 0x4E5D }, + { 0xA446, 0x4E86 }, + { 0xA447, 0x4E8C }, + { 0xA448, 0x4EBA }, + { 0xA449, 0x513F }, + { 0xA44A, 0x5165 }, + { 0xA44B, 0x516B }, + { 0xA44C, 0x51E0 }, + { 0xA44D, 0x5200 }, + { 0xA44E, 0x5201 }, + { 0xA44F, 0x529B }, + { 0xA450, 0x5315 }, + { 0xA451, 0x5341 }, + { 0xA452, 0x535C }, + { 0xA453, 0x53C8 }, + { 0xA454, 0x4E09 }, + { 0xA455, 0x4E0B }, + { 0xA456, 0x4E08 }, + { 0xA457, 0x4E0A }, + { 0xA458, 0x4E2B }, + { 0xA459, 0x4E38 }, + { 0xA45A, 0x51E1 }, + { 0xA45B, 0x4E45 }, + { 0xA45C, 0x4E48 }, + { 0xA45D, 0x4E5F }, + { 0xA45E, 0x4E5E }, + { 0xA45F, 0x4E8E }, + { 0xA460, 0x4EA1 }, + { 0xA461, 0x5140 }, + { 0xA462, 0x5203 }, + { 0xA463, 0x52FA }, + { 0xA464, 0x5343 }, + { 0xA465, 0x53C9 }, + { 0xA466, 0x53E3 }, + { 0xA467, 0x571F }, + { 0xA468, 0x58EB }, + { 0xA469, 0x5915 }, + { 0xA46A, 0x5927 }, + { 0xA46B, 0x5973 }, + { 0xA46C, 0x5B50 }, + { 0xA46D, 0x5B51 }, + { 0xA46E, 0x5B53 }, + { 0xA46F, 0x5BF8 }, + { 0xA470, 0x5C0F }, + { 0xA471, 0x5C22 }, + { 0xA472, 0x5C38 }, + { 0xA473, 0x5C71 }, + { 0xA474, 0x5DDD }, + { 0xA475, 0x5DE5 }, + { 0xA476, 0x5DF1 }, + { 0xA477, 0x5DF2 }, + { 0xA478, 0x5DF3 }, + { 0xA479, 0x5DFE }, + { 0xA47A, 0x5E72 }, + { 0xA47B, 0x5EFE }, + { 0xA47C, 0x5F0B }, + { 0xA47D, 0x5F13 }, + { 0xA47E, 0x624D }, + { 0xA4A1, 0x4E11 }, + { 0xA4A2, 0x4E10 }, + { 0xA4A3, 0x4E0D }, + { 0xA4A4, 0x4E2D }, + { 0xA4A5, 0x4E30 }, + { 0xA4A6, 0x4E39 }, + { 0xA4A7, 0x4E4B }, + { 0xA4A8, 0x5C39 }, + { 0xA4A9, 0x4E88 }, + { 0xA4AA, 0x4E91 }, + { 0xA4AB, 0x4E95 }, + { 0xA4AC, 0x4E92 }, + { 0xA4AD, 0x4E94 }, + { 0xA4AE, 0x4EA2 }, + { 0xA4AF, 0x4EC1 }, + { 0xA4B0, 0x4EC0 }, + { 0xA4B1, 0x4EC3 }, + { 0xA4B2, 0x4EC6 }, + { 0xA4B3, 0x4EC7 }, + { 0xA4B4, 0x4ECD }, + { 0xA4B5, 0x4ECA }, + { 0xA4B6, 0x4ECB }, + { 0xA4B7, 0x4EC4 }, + { 0xA4B8, 0x5143 }, + { 0xA4B9, 0x5141 }, + { 0xA4BA, 0x5167 }, + { 0xA4BB, 0x516D }, + { 0xA4BC, 0x516E }, + { 0xA4BD, 0x516C }, + { 0xA4BE, 0x5197 }, + { 0xA4BF, 0x51F6 }, + { 0xA4C0, 0x5206 }, + { 0xA4C1, 0x5207 }, + { 0xA4C2, 0x5208 }, + { 0xA4C3, 0x52FB }, + { 0xA4C4, 0x52FE }, + { 0xA4C5, 0x52FF }, + { 0xA4C6, 0x5316 }, + { 0xA4C7, 0x5339 }, + { 0xA4C8, 0x5348 }, + { 0xA4C9, 0x5347 }, + { 0xA4CA, 0x5345 }, + { 0xA4CB, 0x535E }, + { 0xA4CC, 0x5384 }, + { 0xA4CD, 0x53CB }, + { 0xA4CE, 0x53CA }, + { 0xA4CF, 0x53CD }, + { 0xA4D0, 0x58EC }, + { 0xA4D1, 0x5929 }, + { 0xA4D2, 0x592B }, + { 0xA4D3, 0x592A }, + { 0xA4D4, 0x592D }, + { 0xA4D5, 0x5B54 }, + { 0xA4D6, 0x5C11 }, + { 0xA4D7, 0x5C24 }, + { 0xA4D8, 0x5C3A }, + { 0xA4D9, 0x5C6F }, + { 0xA4DA, 0x5DF4 }, + { 0xA4DB, 0x5E7B }, + { 0xA4DC, 0x5EFF }, + { 0xA4DD, 0x5F14 }, + { 0xA4DE, 0x5F15 }, + { 0xA4DF, 0x5FC3 }, + { 0xA4E0, 0x6208 }, + { 0xA4E1, 0x6236 }, + { 0xA4E2, 0x624B }, + { 0xA4E3, 0x624E }, + { 0xA4E4, 0x652F }, + { 0xA4E5, 0x6587 }, + { 0xA4E6, 0x6597 }, + { 0xA4E7, 0x65A4 }, + { 0xA4E8, 0x65B9 }, + { 0xA4E9, 0x65E5 }, + { 0xA4EA, 0x66F0 }, + { 0xA4EB, 0x6708 }, + { 0xA4EC, 0x6728 }, + { 0xA4ED, 0x6B20 }, + { 0xA4EE, 0x6B62 }, + { 0xA4EF, 0x6B79 }, + { 0xA4F0, 0x6BCB }, + { 0xA4F1, 0x6BD4 }, + { 0xA4F2, 0x6BDB }, + { 0xA4F3, 0x6C0F }, + { 0xA4F4, 0x6C34 }, + { 0xA4F5, 0x706B }, + { 0xA4F6, 0x722A }, + { 0xA4F7, 0x7236 }, + { 0xA4F8, 0x723B }, + { 0xA4F9, 0x7247 }, + { 0xA4FA, 0x7259 }, + { 0xA4FB, 0x725B }, + { 0xA4FC, 0x72AC }, + { 0xA4FD, 0x738B }, + { 0xA4FE, 0x4E19 }, + { 0xA540, 0x4E16 }, + { 0xA541, 0x4E15 }, + { 0xA542, 0x4E14 }, + { 0xA543, 0x4E18 }, + { 0xA544, 0x4E3B }, + { 0xA545, 0x4E4D }, + { 0xA546, 0x4E4F }, + { 0xA547, 0x4E4E }, + { 0xA548, 0x4EE5 }, + { 0xA549, 0x4ED8 }, + { 0xA54A, 0x4ED4 }, + { 0xA54B, 0x4ED5 }, + { 0xA54C, 0x4ED6 }, + { 0xA54D, 0x4ED7 }, + { 0xA54E, 0x4EE3 }, + { 0xA54F, 0x4EE4 }, + { 0xA550, 0x4ED9 }, + { 0xA551, 0x4EDE }, + { 0xA552, 0x5145 }, + { 0xA553, 0x5144 }, + { 0xA554, 0x5189 }, + { 0xA555, 0x518A }, + { 0xA556, 0x51AC }, + { 0xA557, 0x51F9 }, + { 0xA558, 0x51FA }, + { 0xA559, 0x51F8 }, + { 0xA55A, 0x520A }, + { 0xA55B, 0x52A0 }, + { 0xA55C, 0x529F }, + { 0xA55D, 0x5305 }, + { 0xA55E, 0x5306 }, + { 0xA55F, 0x5317 }, + { 0xA560, 0x531D }, + { 0xA561, 0x4EDF }, + { 0xA562, 0x534A }, + { 0xA563, 0x5349 }, + { 0xA564, 0x5361 }, + { 0xA565, 0x5360 }, + { 0xA566, 0x536F }, + { 0xA567, 0x536E }, + { 0xA568, 0x53BB }, + { 0xA569, 0x53EF }, + { 0xA56A, 0x53E4 }, + { 0xA56B, 0x53F3 }, + { 0xA56C, 0x53EC }, + { 0xA56D, 0x53EE }, + { 0xA56E, 0x53E9 }, + { 0xA56F, 0x53E8 }, + { 0xA570, 0x53FC }, + { 0xA571, 0x53F8 }, + { 0xA572, 0x53F5 }, + { 0xA573, 0x53EB }, + { 0xA574, 0x53E6 }, + { 0xA575, 0x53EA }, + { 0xA576, 0x53F2 }, + { 0xA577, 0x53F1 }, + { 0xA578, 0x53F0 }, + { 0xA579, 0x53E5 }, + { 0xA57A, 0x53ED }, + { 0xA57B, 0x53FB }, + { 0xA57C, 0x56DB }, + { 0xA57D, 0x56DA }, + { 0xA57E, 0x5916 }, + { 0xA5A1, 0x592E }, + { 0xA5A2, 0x5931 }, + { 0xA5A3, 0x5974 }, + { 0xA5A4, 0x5976 }, + { 0xA5A5, 0x5B55 }, + { 0xA5A6, 0x5B83 }, + { 0xA5A7, 0x5C3C }, + { 0xA5A8, 0x5DE8 }, + { 0xA5A9, 0x5DE7 }, + { 0xA5AA, 0x5DE6 }, + { 0xA5AB, 0x5E02 }, + { 0xA5AC, 0x5E03 }, + { 0xA5AD, 0x5E73 }, + { 0xA5AE, 0x5E7C }, + { 0xA5AF, 0x5F01 }, + { 0xA5B0, 0x5F18 }, + { 0xA5B1, 0x5F17 }, + { 0xA5B2, 0x5FC5 }, + { 0xA5B3, 0x620A }, + { 0xA5B4, 0x6253 }, + { 0xA5B5, 0x6254 }, + { 0xA5B6, 0x6252 }, + { 0xA5B7, 0x6251 }, + { 0xA5B8, 0x65A5 }, + { 0xA5B9, 0x65E6 }, + { 0xA5BA, 0x672E }, + { 0xA5BB, 0x672C }, + { 0xA5BC, 0x672A }, + { 0xA5BD, 0x672B }, + { 0xA5BE, 0x672D }, + { 0xA5BF, 0x6B63 }, + { 0xA5C0, 0x6BCD }, + { 0xA5C1, 0x6C11 }, + { 0xA5C2, 0x6C10 }, + { 0xA5C3, 0x6C38 }, + { 0xA5C4, 0x6C41 }, + { 0xA5C5, 0x6C40 }, + { 0xA5C6, 0x6C3E }, + { 0xA5C7, 0x72AF }, + { 0xA5C8, 0x7384 }, + { 0xA5C9, 0x7389 }, + { 0xA5CA, 0x74DC }, + { 0xA5CB, 0x74E6 }, + { 0xA5CC, 0x7518 }, + { 0xA5CD, 0x751F }, + { 0xA5CE, 0x7528 }, + { 0xA5CF, 0x7529 }, + { 0xA5D0, 0x7530 }, + { 0xA5D1, 0x7531 }, + { 0xA5D2, 0x7532 }, + { 0xA5D3, 0x7533 }, + { 0xA5D4, 0x758B }, + { 0xA5D5, 0x767D }, + { 0xA5D6, 0x76AE }, + { 0xA5D7, 0x76BF }, + { 0xA5D8, 0x76EE }, + { 0xA5D9, 0x77DB }, + { 0xA5DA, 0x77E2 }, + { 0xA5DB, 0x77F3 }, + { 0xA5DC, 0x793A }, + { 0xA5DD, 0x79BE }, + { 0xA5DE, 0x7A74 }, + { 0xA5DF, 0x7ACB }, + { 0xA5E0, 0x4E1E }, + { 0xA5E1, 0x4E1F }, + { 0xA5E2, 0x4E52 }, + { 0xA5E3, 0x4E53 }, + { 0xA5E4, 0x4E69 }, + { 0xA5E5, 0x4E99 }, + { 0xA5E6, 0x4EA4 }, + { 0xA5E7, 0x4EA6 }, + { 0xA5E8, 0x4EA5 }, + { 0xA5E9, 0x4EFF }, + { 0xA5EA, 0x4F09 }, + { 0xA5EB, 0x4F19 }, + { 0xA5EC, 0x4F0A }, + { 0xA5ED, 0x4F15 }, + { 0xA5EE, 0x4F0D }, + { 0xA5EF, 0x4F10 }, + { 0xA5F0, 0x4F11 }, + { 0xA5F1, 0x4F0F }, + { 0xA5F2, 0x4EF2 }, + { 0xA5F3, 0x4EF6 }, + { 0xA5F4, 0x4EFB }, + { 0xA5F5, 0x4EF0 }, + { 0xA5F6, 0x4EF3 }, + { 0xA5F7, 0x4EFD }, + { 0xA5F8, 0x4F01 }, + { 0xA5F9, 0x4F0B }, + { 0xA5FA, 0x5149 }, + { 0xA5FB, 0x5147 }, + { 0xA5FC, 0x5146 }, + { 0xA5FD, 0x5148 }, + { 0xA5FE, 0x5168 }, + { 0xA640, 0x5171 }, + { 0xA641, 0x518D }, + { 0xA642, 0x51B0 }, + { 0xA643, 0x5217 }, + { 0xA644, 0x5211 }, + { 0xA645, 0x5212 }, + { 0xA646, 0x520E }, + { 0xA647, 0x5216 }, + { 0xA648, 0x52A3 }, + { 0xA649, 0x5308 }, + { 0xA64A, 0x5321 }, + { 0xA64B, 0x5320 }, + { 0xA64C, 0x5370 }, + { 0xA64D, 0x5371 }, + { 0xA64E, 0x5409 }, + { 0xA64F, 0x540F }, + { 0xA650, 0x540C }, + { 0xA651, 0x540A }, + { 0xA652, 0x5410 }, + { 0xA653, 0x5401 }, + { 0xA654, 0x540B }, + { 0xA655, 0x5404 }, + { 0xA656, 0x5411 }, + { 0xA657, 0x540D }, + { 0xA658, 0x5408 }, + { 0xA659, 0x5403 }, + { 0xA65A, 0x540E }, + { 0xA65B, 0x5406 }, + { 0xA65C, 0x5412 }, + { 0xA65D, 0x56E0 }, + { 0xA65E, 0x56DE }, + { 0xA65F, 0x56DD }, + { 0xA660, 0x5733 }, + { 0xA661, 0x5730 }, + { 0xA662, 0x5728 }, + { 0xA663, 0x572D }, + { 0xA664, 0x572C }, + { 0xA665, 0x572F }, + { 0xA666, 0x5729 }, + { 0xA667, 0x5919 }, + { 0xA668, 0x591A }, + { 0xA669, 0x5937 }, + { 0xA66A, 0x5938 }, + { 0xA66B, 0x5984 }, + { 0xA66C, 0x5978 }, + { 0xA66D, 0x5983 }, + { 0xA66E, 0x597D }, + { 0xA66F, 0x5979 }, + { 0xA670, 0x5982 }, + { 0xA671, 0x5981 }, + { 0xA672, 0x5B57 }, + { 0xA673, 0x5B58 }, + { 0xA674, 0x5B87 }, + { 0xA675, 0x5B88 }, + { 0xA676, 0x5B85 }, + { 0xA677, 0x5B89 }, + { 0xA678, 0x5BFA }, + { 0xA679, 0x5C16 }, + { 0xA67A, 0x5C79 }, + { 0xA67B, 0x5DDE }, + { 0xA67C, 0x5E06 }, + { 0xA67D, 0x5E76 }, + { 0xA67E, 0x5E74 }, + { 0xA6A1, 0x5F0F }, + { 0xA6A2, 0x5F1B }, + { 0xA6A3, 0x5FD9 }, + { 0xA6A4, 0x5FD6 }, + { 0xA6A5, 0x620E }, + { 0xA6A6, 0x620C }, + { 0xA6A7, 0x620D }, + { 0xA6A8, 0x6210 }, + { 0xA6A9, 0x6263 }, + { 0xA6AA, 0x625B }, + { 0xA6AB, 0x6258 }, + { 0xA6AC, 0x6536 }, + { 0xA6AD, 0x65E9 }, + { 0xA6AE, 0x65E8 }, + { 0xA6AF, 0x65EC }, + { 0xA6B0, 0x65ED }, + { 0xA6B1, 0x66F2 }, + { 0xA6B2, 0x66F3 }, + { 0xA6B3, 0x6709 }, + { 0xA6B4, 0x673D }, + { 0xA6B5, 0x6734 }, + { 0xA6B6, 0x6731 }, + { 0xA6B7, 0x6735 }, + { 0xA6B8, 0x6B21 }, + { 0xA6B9, 0x6B64 }, + { 0xA6BA, 0x6B7B }, + { 0xA6BB, 0x6C16 }, + { 0xA6BC, 0x6C5D }, + { 0xA6BD, 0x6C57 }, + { 0xA6BE, 0x6C59 }, + { 0xA6BF, 0x6C5F }, + { 0xA6C0, 0x6C60 }, + { 0xA6C1, 0x6C50 }, + { 0xA6C2, 0x6C55 }, + { 0xA6C3, 0x6C61 }, + { 0xA6C4, 0x6C5B }, + { 0xA6C5, 0x6C4D }, + { 0xA6C6, 0x6C4E }, + { 0xA6C7, 0x7070 }, + { 0xA6C8, 0x725F }, + { 0xA6C9, 0x725D }, + { 0xA6CA, 0x767E }, + { 0xA6CB, 0x7AF9 }, + { 0xA6CC, 0x7C73 }, + { 0xA6CD, 0x7CF8 }, + { 0xA6CE, 0x7F36 }, + { 0xA6CF, 0x7F8A }, + { 0xA6D0, 0x7FBD }, + { 0xA6D1, 0x8001 }, + { 0xA6D2, 0x8003 }, + { 0xA6D3, 0x800C }, + { 0xA6D4, 0x8012 }, + { 0xA6D5, 0x8033 }, + { 0xA6D6, 0x807F }, + { 0xA6D7, 0x8089 }, + { 0xA6D8, 0x808B }, + { 0xA6D9, 0x808C }, + { 0xA6DA, 0x81E3 }, + { 0xA6DB, 0x81EA }, + { 0xA6DC, 0x81F3 }, + { 0xA6DD, 0x81FC }, + { 0xA6DE, 0x820C }, + { 0xA6DF, 0x821B }, + { 0xA6E0, 0x821F }, + { 0xA6E1, 0x826E }, + { 0xA6E2, 0x8272 }, + { 0xA6E3, 0x827E }, + { 0xA6E4, 0x866B }, + { 0xA6E5, 0x8840 }, + { 0xA6E6, 0x884C }, + { 0xA6E7, 0x8863 }, + { 0xA6E8, 0x897F }, + { 0xA6E9, 0x9621 }, + { 0xA6EA, 0x4E32 }, + { 0xA6EB, 0x4EA8 }, + { 0xA6EC, 0x4F4D }, + { 0xA6ED, 0x4F4F }, + { 0xA6EE, 0x4F47 }, + { 0xA6EF, 0x4F57 }, + { 0xA6F0, 0x4F5E }, + { 0xA6F1, 0x4F34 }, + { 0xA6F2, 0x4F5B }, + { 0xA6F3, 0x4F55 }, + { 0xA6F4, 0x4F30 }, + { 0xA6F5, 0x4F50 }, + { 0xA6F6, 0x4F51 }, + { 0xA6F7, 0x4F3D }, + { 0xA6F8, 0x4F3A }, + { 0xA6F9, 0x4F38 }, + { 0xA6FA, 0x4F43 }, + { 0xA6FB, 0x4F54 }, + { 0xA6FC, 0x4F3C }, + { 0xA6FD, 0x4F46 }, + { 0xA6FE, 0x4F63 }, + { 0xA740, 0x4F5C }, + { 0xA741, 0x4F60 }, + { 0xA742, 0x4F2F }, + { 0xA743, 0x4F4E }, + { 0xA744, 0x4F36 }, + { 0xA745, 0x4F59 }, + { 0xA746, 0x4F5D }, + { 0xA747, 0x4F48 }, + { 0xA748, 0x4F5A }, + { 0xA749, 0x514C }, + { 0xA74A, 0x514B }, + { 0xA74B, 0x514D }, + { 0xA74C, 0x5175 }, + { 0xA74D, 0x51B6 }, + { 0xA74E, 0x51B7 }, + { 0xA74F, 0x5225 }, + { 0xA750, 0x5224 }, + { 0xA751, 0x5229 }, + { 0xA752, 0x522A }, + { 0xA753, 0x5228 }, + { 0xA754, 0x52AB }, + { 0xA755, 0x52A9 }, + { 0xA756, 0x52AA }, + { 0xA757, 0x52AC }, + { 0xA758, 0x5323 }, + { 0xA759, 0x5373 }, + { 0xA75A, 0x5375 }, + { 0xA75B, 0x541D }, + { 0xA75C, 0x542D }, + { 0xA75D, 0x541E }, + { 0xA75E, 0x543E }, + { 0xA75F, 0x5426 }, + { 0xA760, 0x544E }, + { 0xA761, 0x5427 }, + { 0xA762, 0x5446 }, + { 0xA763, 0x5443 }, + { 0xA764, 0x5433 }, + { 0xA765, 0x5448 }, + { 0xA766, 0x5442 }, + { 0xA767, 0x541B }, + { 0xA768, 0x5429 }, + { 0xA769, 0x544A }, + { 0xA76A, 0x5439 }, + { 0xA76B, 0x543B }, + { 0xA76C, 0x5438 }, + { 0xA76D, 0x542E }, + { 0xA76E, 0x5435 }, + { 0xA76F, 0x5436 }, + { 0xA770, 0x5420 }, + { 0xA771, 0x543C }, + { 0xA772, 0x5440 }, + { 0xA773, 0x5431 }, + { 0xA774, 0x542B }, + { 0xA775, 0x541F }, + { 0xA776, 0x542C }, + { 0xA777, 0x56EA }, + { 0xA778, 0x56F0 }, + { 0xA779, 0x56E4 }, + { 0xA77A, 0x56EB }, + { 0xA77B, 0x574A }, + { 0xA77C, 0x5751 }, + { 0xA77D, 0x5740 }, + { 0xA77E, 0x574D }, + { 0xA7A1, 0x5747 }, + { 0xA7A2, 0x574E }, + { 0xA7A3, 0x573E }, + { 0xA7A4, 0x5750 }, + { 0xA7A5, 0x574F }, + { 0xA7A6, 0x573B }, + { 0xA7A7, 0x58EF }, + { 0xA7A8, 0x593E }, + { 0xA7A9, 0x599D }, + { 0xA7AA, 0x5992 }, + { 0xA7AB, 0x59A8 }, + { 0xA7AC, 0x599E }, + { 0xA7AD, 0x59A3 }, + { 0xA7AE, 0x5999 }, + { 0xA7AF, 0x5996 }, + { 0xA7B0, 0x598D }, + { 0xA7B1, 0x59A4 }, + { 0xA7B2, 0x5993 }, + { 0xA7B3, 0x598A }, + { 0xA7B4, 0x59A5 }, + { 0xA7B5, 0x5B5D }, + { 0xA7B6, 0x5B5C }, + { 0xA7B7, 0x5B5A }, + { 0xA7B8, 0x5B5B }, + { 0xA7B9, 0x5B8C }, + { 0xA7BA, 0x5B8B }, + { 0xA7BB, 0x5B8F }, + { 0xA7BC, 0x5C2C }, + { 0xA7BD, 0x5C40 }, + { 0xA7BE, 0x5C41 }, + { 0xA7BF, 0x5C3F }, + { 0xA7C0, 0x5C3E }, + { 0xA7C1, 0x5C90 }, + { 0xA7C2, 0x5C91 }, + { 0xA7C3, 0x5C94 }, + { 0xA7C4, 0x5C8C }, + { 0xA7C5, 0x5DEB }, + { 0xA7C6, 0x5E0C }, + { 0xA7C7, 0x5E8F }, + { 0xA7C8, 0x5E87 }, + { 0xA7C9, 0x5E8A }, + { 0xA7CA, 0x5EF7 }, + { 0xA7CB, 0x5F04 }, + { 0xA7CC, 0x5F1F }, + { 0xA7CD, 0x5F64 }, + { 0xA7CE, 0x5F62 }, + { 0xA7CF, 0x5F77 }, + { 0xA7D0, 0x5F79 }, + { 0xA7D1, 0x5FD8 }, + { 0xA7D2, 0x5FCC }, + { 0xA7D3, 0x5FD7 }, + { 0xA7D4, 0x5FCD }, + { 0xA7D5, 0x5FF1 }, + { 0xA7D6, 0x5FEB }, + { 0xA7D7, 0x5FF8 }, + { 0xA7D8, 0x5FEA }, + { 0xA7D9, 0x6212 }, + { 0xA7DA, 0x6211 }, + { 0xA7DB, 0x6284 }, + { 0xA7DC, 0x6297 }, + { 0xA7DD, 0x6296 }, + { 0xA7DE, 0x6280 }, + { 0xA7DF, 0x6276 }, + { 0xA7E0, 0x6289 }, + { 0xA7E1, 0x626D }, + { 0xA7E2, 0x628A }, + { 0xA7E3, 0x627C }, + { 0xA7E4, 0x627E }, + { 0xA7E5, 0x6279 }, + { 0xA7E6, 0x6273 }, + { 0xA7E7, 0x6292 }, + { 0xA7E8, 0x626F }, + { 0xA7E9, 0x6298 }, + { 0xA7EA, 0x626E }, + { 0xA7EB, 0x6295 }, + { 0xA7EC, 0x6293 }, + { 0xA7ED, 0x6291 }, + { 0xA7EE, 0x6286 }, + { 0xA7EF, 0x6539 }, + { 0xA7F0, 0x653B }, + { 0xA7F1, 0x6538 }, + { 0xA7F2, 0x65F1 }, + { 0xA7F3, 0x66F4 }, + { 0xA7F4, 0x675F }, + { 0xA7F5, 0x674E }, + { 0xA7F6, 0x674F }, + { 0xA7F7, 0x6750 }, + { 0xA7F8, 0x6751 }, + { 0xA7F9, 0x675C }, + { 0xA7FA, 0x6756 }, + { 0xA7FB, 0x675E }, + { 0xA7FC, 0x6749 }, + { 0xA7FD, 0x6746 }, + { 0xA7FE, 0x6760 }, + { 0xA840, 0x6753 }, + { 0xA841, 0x6757 }, + { 0xA842, 0x6B65 }, + { 0xA843, 0x6BCF }, + { 0xA844, 0x6C42 }, + { 0xA845, 0x6C5E }, + { 0xA846, 0x6C99 }, + { 0xA847, 0x6C81 }, + { 0xA848, 0x6C88 }, + { 0xA849, 0x6C89 }, + { 0xA84A, 0x6C85 }, + { 0xA84B, 0x6C9B }, + { 0xA84C, 0x6C6A }, + { 0xA84D, 0x6C7A }, + { 0xA84E, 0x6C90 }, + { 0xA84F, 0x6C70 }, + { 0xA850, 0x6C8C }, + { 0xA851, 0x6C68 }, + { 0xA852, 0x6C96 }, + { 0xA853, 0x6C92 }, + { 0xA854, 0x6C7D }, + { 0xA855, 0x6C83 }, + { 0xA856, 0x6C72 }, + { 0xA857, 0x6C7E }, + { 0xA858, 0x6C74 }, + { 0xA859, 0x6C86 }, + { 0xA85A, 0x6C76 }, + { 0xA85B, 0x6C8D }, + { 0xA85C, 0x6C94 }, + { 0xA85D, 0x6C98 }, + { 0xA85E, 0x6C82 }, + { 0xA85F, 0x7076 }, + { 0xA860, 0x707C }, + { 0xA861, 0x707D }, + { 0xA862, 0x7078 }, + { 0xA863, 0x7262 }, + { 0xA864, 0x7261 }, + { 0xA865, 0x7260 }, + { 0xA866, 0x72C4 }, + { 0xA867, 0x72C2 }, + { 0xA868, 0x7396 }, + { 0xA869, 0x752C }, + { 0xA86A, 0x752B }, + { 0xA86B, 0x7537 }, + { 0xA86C, 0x7538 }, + { 0xA86D, 0x7682 }, + { 0xA86E, 0x76EF }, + { 0xA86F, 0x77E3 }, + { 0xA870, 0x79C1 }, + { 0xA871, 0x79C0 }, + { 0xA872, 0x79BF }, + { 0xA873, 0x7A76 }, + { 0xA874, 0x7CFB }, + { 0xA875, 0x7F55 }, + { 0xA876, 0x8096 }, + { 0xA877, 0x8093 }, + { 0xA878, 0x809D }, + { 0xA879, 0x8098 }, + { 0xA87A, 0x809B }, + { 0xA87B, 0x809A }, + { 0xA87C, 0x80B2 }, + { 0xA87D, 0x826F }, + { 0xA87E, 0x8292 }, + { 0xA8A1, 0x828B }, + { 0xA8A2, 0x828D }, + { 0xA8A3, 0x898B }, + { 0xA8A4, 0x89D2 }, + { 0xA8A5, 0x8A00 }, + { 0xA8A6, 0x8C37 }, + { 0xA8A7, 0x8C46 }, + { 0xA8A8, 0x8C55 }, + { 0xA8A9, 0x8C9D }, + { 0xA8AA, 0x8D64 }, + { 0xA8AB, 0x8D70 }, + { 0xA8AC, 0x8DB3 }, + { 0xA8AD, 0x8EAB }, + { 0xA8AE, 0x8ECA }, + { 0xA8AF, 0x8F9B }, + { 0xA8B0, 0x8FB0 }, + { 0xA8B1, 0x8FC2 }, + { 0xA8B2, 0x8FC6 }, + { 0xA8B3, 0x8FC5 }, + { 0xA8B4, 0x8FC4 }, + { 0xA8B5, 0x5DE1 }, + { 0xA8B6, 0x9091 }, + { 0xA8B7, 0x90A2 }, + { 0xA8B8, 0x90AA }, + { 0xA8B9, 0x90A6 }, + { 0xA8BA, 0x90A3 }, + { 0xA8BB, 0x9149 }, + { 0xA8BC, 0x91C6 }, + { 0xA8BD, 0x91CC }, + { 0xA8BE, 0x9632 }, + { 0xA8BF, 0x962E }, + { 0xA8C0, 0x9631 }, + { 0xA8C1, 0x962A }, + { 0xA8C2, 0x962C }, + { 0xA8C3, 0x4E26 }, + { 0xA8C4, 0x4E56 }, + { 0xA8C5, 0x4E73 }, + { 0xA8C6, 0x4E8B }, + { 0xA8C7, 0x4E9B }, + { 0xA8C8, 0x4E9E }, + { 0xA8C9, 0x4EAB }, + { 0xA8CA, 0x4EAC }, + { 0xA8CB, 0x4F6F }, + { 0xA8CC, 0x4F9D }, + { 0xA8CD, 0x4F8D }, + { 0xA8CE, 0x4F73 }, + { 0xA8CF, 0x4F7F }, + { 0xA8D0, 0x4F6C }, + { 0xA8D1, 0x4F9B }, + { 0xA8D2, 0x4F8B }, + { 0xA8D3, 0x4F86 }, + { 0xA8D4, 0x4F83 }, + { 0xA8D5, 0x4F70 }, + { 0xA8D6, 0x4F75 }, + { 0xA8D7, 0x4F88 }, + { 0xA8D8, 0x4F69 }, + { 0xA8D9, 0x4F7B }, + { 0xA8DA, 0x4F96 }, + { 0xA8DB, 0x4F7E }, + { 0xA8DC, 0x4F8F }, + { 0xA8DD, 0x4F91 }, + { 0xA8DE, 0x4F7A }, + { 0xA8DF, 0x5154 }, + { 0xA8E0, 0x5152 }, + { 0xA8E1, 0x5155 }, + { 0xA8E2, 0x5169 }, + { 0xA8E3, 0x5177 }, + { 0xA8E4, 0x5176 }, + { 0xA8E5, 0x5178 }, + { 0xA8E6, 0x51BD }, + { 0xA8E7, 0x51FD }, + { 0xA8E8, 0x523B }, + { 0xA8E9, 0x5238 }, + { 0xA8EA, 0x5237 }, + { 0xA8EB, 0x523A }, + { 0xA8EC, 0x5230 }, + { 0xA8ED, 0x522E }, + { 0xA8EE, 0x5236 }, + { 0xA8EF, 0x5241 }, + { 0xA8F0, 0x52BE }, + { 0xA8F1, 0x52BB }, + { 0xA8F2, 0x5352 }, + { 0xA8F3, 0x5354 }, + { 0xA8F4, 0x5353 }, + { 0xA8F5, 0x5351 }, + { 0xA8F6, 0x5366 }, + { 0xA8F7, 0x5377 }, + { 0xA8F8, 0x5378 }, + { 0xA8F9, 0x5379 }, + { 0xA8FA, 0x53D6 }, + { 0xA8FB, 0x53D4 }, + { 0xA8FC, 0x53D7 }, + { 0xA8FD, 0x5473 }, + { 0xA8FE, 0x5475 }, + { 0xA940, 0x5496 }, + { 0xA941, 0x5478 }, + { 0xA942, 0x5495 }, + { 0xA943, 0x5480 }, + { 0xA944, 0x547B }, + { 0xA945, 0x5477 }, + { 0xA946, 0x5484 }, + { 0xA947, 0x5492 }, + { 0xA948, 0x5486 }, + { 0xA949, 0x547C }, + { 0xA94A, 0x5490 }, + { 0xA94B, 0x5471 }, + { 0xA94C, 0x5476 }, + { 0xA94D, 0x548C }, + { 0xA94E, 0x549A }, + { 0xA94F, 0x5462 }, + { 0xA950, 0x5468 }, + { 0xA951, 0x548B }, + { 0xA952, 0x547D }, + { 0xA953, 0x548E }, + { 0xA954, 0x56FA }, + { 0xA955, 0x5783 }, + { 0xA956, 0x5777 }, + { 0xA957, 0x576A }, + { 0xA958, 0x5769 }, + { 0xA959, 0x5761 }, + { 0xA95A, 0x5766 }, + { 0xA95B, 0x5764 }, + { 0xA95C, 0x577C }, + { 0xA95D, 0x591C }, + { 0xA95E, 0x5949 }, + { 0xA95F, 0x5947 }, + { 0xA960, 0x5948 }, + { 0xA961, 0x5944 }, + { 0xA962, 0x5954 }, + { 0xA963, 0x59BE }, + { 0xA964, 0x59BB }, + { 0xA965, 0x59D4 }, + { 0xA966, 0x59B9 }, + { 0xA967, 0x59AE }, + { 0xA968, 0x59D1 }, + { 0xA969, 0x59C6 }, + { 0xA96A, 0x59D0 }, + { 0xA96B, 0x59CD }, + { 0xA96C, 0x59CB }, + { 0xA96D, 0x59D3 }, + { 0xA96E, 0x59CA }, + { 0xA96F, 0x59AF }, + { 0xA970, 0x59B3 }, + { 0xA971, 0x59D2 }, + { 0xA972, 0x59C5 }, + { 0xA973, 0x5B5F }, + { 0xA974, 0x5B64 }, + { 0xA975, 0x5B63 }, + { 0xA976, 0x5B97 }, + { 0xA977, 0x5B9A }, + { 0xA978, 0x5B98 }, + { 0xA979, 0x5B9C }, + { 0xA97A, 0x5B99 }, + { 0xA97B, 0x5B9B }, + { 0xA97C, 0x5C1A }, + { 0xA97D, 0x5C48 }, + { 0xA97E, 0x5C45 }, + { 0xA9A1, 0x5C46 }, + { 0xA9A2, 0x5CB7 }, + { 0xA9A3, 0x5CA1 }, + { 0xA9A4, 0x5CB8 }, + { 0xA9A5, 0x5CA9 }, + { 0xA9A6, 0x5CAB }, + { 0xA9A7, 0x5CB1 }, + { 0xA9A8, 0x5CB3 }, + { 0xA9A9, 0x5E18 }, + { 0xA9AA, 0x5E1A }, + { 0xA9AB, 0x5E16 }, + { 0xA9AC, 0x5E15 }, + { 0xA9AD, 0x5E1B }, + { 0xA9AE, 0x5E11 }, + { 0xA9AF, 0x5E78 }, + { 0xA9B0, 0x5E9A }, + { 0xA9B1, 0x5E97 }, + { 0xA9B2, 0x5E9C }, + { 0xA9B3, 0x5E95 }, + { 0xA9B4, 0x5E96 }, + { 0xA9B5, 0x5EF6 }, + { 0xA9B6, 0x5F26 }, + { 0xA9B7, 0x5F27 }, + { 0xA9B8, 0x5F29 }, + { 0xA9B9, 0x5F80 }, + { 0xA9BA, 0x5F81 }, + { 0xA9BB, 0x5F7F }, + { 0xA9BC, 0x5F7C }, + { 0xA9BD, 0x5FDD }, + { 0xA9BE, 0x5FE0 }, + { 0xA9BF, 0x5FFD }, + { 0xA9C0, 0x5FF5 }, + { 0xA9C1, 0x5FFF }, + { 0xA9C2, 0x600F }, + { 0xA9C3, 0x6014 }, + { 0xA9C4, 0x602F }, + { 0xA9C5, 0x6035 }, + { 0xA9C6, 0x6016 }, + { 0xA9C7, 0x602A }, + { 0xA9C8, 0x6015 }, + { 0xA9C9, 0x6021 }, + { 0xA9CA, 0x6027 }, + { 0xA9CB, 0x6029 }, + { 0xA9CC, 0x602B }, + { 0xA9CD, 0x601B }, + { 0xA9CE, 0x6216 }, + { 0xA9CF, 0x6215 }, + { 0xA9D0, 0x623F }, + { 0xA9D1, 0x623E }, + { 0xA9D2, 0x6240 }, + { 0xA9D3, 0x627F }, + { 0xA9D4, 0x62C9 }, + { 0xA9D5, 0x62CC }, + { 0xA9D6, 0x62C4 }, + { 0xA9D7, 0x62BF }, + { 0xA9D8, 0x62C2 }, + { 0xA9D9, 0x62B9 }, + { 0xA9DA, 0x62D2 }, + { 0xA9DB, 0x62DB }, + { 0xA9DC, 0x62AB }, + { 0xA9DD, 0x62D3 }, + { 0xA9DE, 0x62D4 }, + { 0xA9DF, 0x62CB }, + { 0xA9E0, 0x62C8 }, + { 0xA9E1, 0x62A8 }, + { 0xA9E2, 0x62BD }, + { 0xA9E3, 0x62BC }, + { 0xA9E4, 0x62D0 }, + { 0xA9E5, 0x62D9 }, + { 0xA9E6, 0x62C7 }, + { 0xA9E7, 0x62CD }, + { 0xA9E8, 0x62B5 }, + { 0xA9E9, 0x62DA }, + { 0xA9EA, 0x62B1 }, + { 0xA9EB, 0x62D8 }, + { 0xA9EC, 0x62D6 }, + { 0xA9ED, 0x62D7 }, + { 0xA9EE, 0x62C6 }, + { 0xA9EF, 0x62AC }, + { 0xA9F0, 0x62CE }, + { 0xA9F1, 0x653E }, + { 0xA9F2, 0x65A7 }, + { 0xA9F3, 0x65BC }, + { 0xA9F4, 0x65FA }, + { 0xA9F5, 0x6614 }, + { 0xA9F6, 0x6613 }, + { 0xA9F7, 0x660C }, + { 0xA9F8, 0x6606 }, + { 0xA9F9, 0x6602 }, + { 0xA9FA, 0x660E }, + { 0xA9FB, 0x6600 }, + { 0xA9FC, 0x660F }, + { 0xA9FD, 0x6615 }, + { 0xA9FE, 0x660A }, + { 0xAA40, 0x6607 }, + { 0xAA41, 0x670D }, + { 0xAA42, 0x670B }, + { 0xAA43, 0x676D }, + { 0xAA44, 0x678B }, + { 0xAA45, 0x6795 }, + { 0xAA46, 0x6771 }, + { 0xAA47, 0x679C }, + { 0xAA48, 0x6773 }, + { 0xAA49, 0x6777 }, + { 0xAA4A, 0x6787 }, + { 0xAA4B, 0x679D }, + { 0xAA4C, 0x6797 }, + { 0xAA4D, 0x676F }, + { 0xAA4E, 0x6770 }, + { 0xAA4F, 0x677F }, + { 0xAA50, 0x6789 }, + { 0xAA51, 0x677E }, + { 0xAA52, 0x6790 }, + { 0xAA53, 0x6775 }, + { 0xAA54, 0x679A }, + { 0xAA55, 0x6793 }, + { 0xAA56, 0x677C }, + { 0xAA57, 0x676A }, + { 0xAA58, 0x6772 }, + { 0xAA59, 0x6B23 }, + { 0xAA5A, 0x6B66 }, + { 0xAA5B, 0x6B67 }, + { 0xAA5C, 0x6B7F }, + { 0xAA5D, 0x6C13 }, + { 0xAA5E, 0x6C1B }, + { 0xAA5F, 0x6CE3 }, + { 0xAA60, 0x6CE8 }, + { 0xAA61, 0x6CF3 }, + { 0xAA62, 0x6CB1 }, + { 0xAA63, 0x6CCC }, + { 0xAA64, 0x6CE5 }, + { 0xAA65, 0x6CB3 }, + { 0xAA66, 0x6CBD }, + { 0xAA67, 0x6CBE }, + { 0xAA68, 0x6CBC }, + { 0xAA69, 0x6CE2 }, + { 0xAA6A, 0x6CAB }, + { 0xAA6B, 0x6CD5 }, + { 0xAA6C, 0x6CD3 }, + { 0xAA6D, 0x6CB8 }, + { 0xAA6E, 0x6CC4 }, + { 0xAA6F, 0x6CB9 }, + { 0xAA70, 0x6CC1 }, + { 0xAA71, 0x6CAE }, + { 0xAA72, 0x6CD7 }, + { 0xAA73, 0x6CC5 }, + { 0xAA74, 0x6CF1 }, + { 0xAA75, 0x6CBF }, + { 0xAA76, 0x6CBB }, + { 0xAA77, 0x6CE1 }, + { 0xAA78, 0x6CDB }, + { 0xAA79, 0x6CCA }, + { 0xAA7A, 0x6CAC }, + { 0xAA7B, 0x6CEF }, + { 0xAA7C, 0x6CDC }, + { 0xAA7D, 0x6CD6 }, + { 0xAA7E, 0x6CE0 }, + { 0xAAA1, 0x7095 }, + { 0xAAA2, 0x708E }, + { 0xAAA3, 0x7092 }, + { 0xAAA4, 0x708A }, + { 0xAAA5, 0x7099 }, + { 0xAAA6, 0x722C }, + { 0xAAA7, 0x722D }, + { 0xAAA8, 0x7238 }, + { 0xAAA9, 0x7248 }, + { 0xAAAA, 0x7267 }, + { 0xAAAB, 0x7269 }, + { 0xAAAC, 0x72C0 }, + { 0xAAAD, 0x72CE }, + { 0xAAAE, 0x72D9 }, + { 0xAAAF, 0x72D7 }, + { 0xAAB0, 0x72D0 }, + { 0xAAB1, 0x73A9 }, + { 0xAAB2, 0x73A8 }, + { 0xAAB3, 0x739F }, + { 0xAAB4, 0x73AB }, + { 0xAAB5, 0x73A5 }, + { 0xAAB6, 0x753D }, + { 0xAAB7, 0x759D }, + { 0xAAB8, 0x7599 }, + { 0xAAB9, 0x759A }, + { 0xAABA, 0x7684 }, + { 0xAABB, 0x76C2 }, + { 0xAABC, 0x76F2 }, + { 0xAABD, 0x76F4 }, + { 0xAABE, 0x77E5 }, + { 0xAABF, 0x77FD }, + { 0xAAC0, 0x793E }, + { 0xAAC1, 0x7940 }, + { 0xAAC2, 0x7941 }, + { 0xAAC3, 0x79C9 }, + { 0xAAC4, 0x79C8 }, + { 0xAAC5, 0x7A7A }, + { 0xAAC6, 0x7A79 }, + { 0xAAC7, 0x7AFA }, + { 0xAAC8, 0x7CFE }, + { 0xAAC9, 0x7F54 }, + { 0xAACA, 0x7F8C }, + { 0xAACB, 0x7F8B }, + { 0xAACC, 0x8005 }, + { 0xAACD, 0x80BA }, + { 0xAACE, 0x80A5 }, + { 0xAACF, 0x80A2 }, + { 0xAAD0, 0x80B1 }, + { 0xAAD1, 0x80A1 }, + { 0xAAD2, 0x80AB }, + { 0xAAD3, 0x80A9 }, + { 0xAAD4, 0x80B4 }, + { 0xAAD5, 0x80AA }, + { 0xAAD6, 0x80AF }, + { 0xAAD7, 0x81E5 }, + { 0xAAD8, 0x81FE }, + { 0xAAD9, 0x820D }, + { 0xAADA, 0x82B3 }, + { 0xAADB, 0x829D }, + { 0xAADC, 0x8299 }, + { 0xAADD, 0x82AD }, + { 0xAADE, 0x82BD }, + { 0xAADF, 0x829F }, + { 0xAAE0, 0x82B9 }, + { 0xAAE1, 0x82B1 }, + { 0xAAE2, 0x82AC }, + { 0xAAE3, 0x82A5 }, + { 0xAAE4, 0x82AF }, + { 0xAAE5, 0x82B8 }, + { 0xAAE6, 0x82A3 }, + { 0xAAE7, 0x82B0 }, + { 0xAAE8, 0x82BE }, + { 0xAAE9, 0x82B7 }, + { 0xAAEA, 0x864E }, + { 0xAAEB, 0x8671 }, + { 0xAAEC, 0x521D }, + { 0xAAED, 0x8868 }, + { 0xAAEE, 0x8ECB }, + { 0xAAEF, 0x8FCE }, + { 0xAAF0, 0x8FD4 }, + { 0xAAF1, 0x8FD1 }, + { 0xAAF2, 0x90B5 }, + { 0xAAF3, 0x90B8 }, + { 0xAAF4, 0x90B1 }, + { 0xAAF5, 0x90B6 }, + { 0xAAF6, 0x91C7 }, + { 0xAAF7, 0x91D1 }, + { 0xAAF8, 0x9577 }, + { 0xAAF9, 0x9580 }, + { 0xAAFA, 0x961C }, + { 0xAAFB, 0x9640 }, + { 0xAAFC, 0x963F }, + { 0xAAFD, 0x963B }, + { 0xAAFE, 0x9644 }, + { 0xAB40, 0x9642 }, + { 0xAB41, 0x96B9 }, + { 0xAB42, 0x96E8 }, + { 0xAB43, 0x9752 }, + { 0xAB44, 0x975E }, + { 0xAB45, 0x4E9F }, + { 0xAB46, 0x4EAD }, + { 0xAB47, 0x4EAE }, + { 0xAB48, 0x4FE1 }, + { 0xAB49, 0x4FB5 }, + { 0xAB4A, 0x4FAF }, + { 0xAB4B, 0x4FBF }, + { 0xAB4C, 0x4FE0 }, + { 0xAB4D, 0x4FD1 }, + { 0xAB4E, 0x4FCF }, + { 0xAB4F, 0x4FDD }, + { 0xAB50, 0x4FC3 }, + { 0xAB51, 0x4FB6 }, + { 0xAB52, 0x4FD8 }, + { 0xAB53, 0x4FDF }, + { 0xAB54, 0x4FCA }, + { 0xAB55, 0x4FD7 }, + { 0xAB56, 0x4FAE }, + { 0xAB57, 0x4FD0 }, + { 0xAB58, 0x4FC4 }, + { 0xAB59, 0x4FC2 }, + { 0xAB5A, 0x4FDA }, + { 0xAB5B, 0x4FCE }, + { 0xAB5C, 0x4FDE }, + { 0xAB5D, 0x4FB7 }, + { 0xAB5E, 0x5157 }, + { 0xAB5F, 0x5192 }, + { 0xAB60, 0x5191 }, + { 0xAB61, 0x51A0 }, + { 0xAB62, 0x524E }, + { 0xAB63, 0x5243 }, + { 0xAB64, 0x524A }, + { 0xAB65, 0x524D }, + { 0xAB66, 0x524C }, + { 0xAB67, 0x524B }, + { 0xAB68, 0x5247 }, + { 0xAB69, 0x52C7 }, + { 0xAB6A, 0x52C9 }, + { 0xAB6B, 0x52C3 }, + { 0xAB6C, 0x52C1 }, + { 0xAB6D, 0x530D }, + { 0xAB6E, 0x5357 }, + { 0xAB6F, 0x537B }, + { 0xAB70, 0x539A }, + { 0xAB71, 0x53DB }, + { 0xAB72, 0x54AC }, + { 0xAB73, 0x54C0 }, + { 0xAB74, 0x54A8 }, + { 0xAB75, 0x54CE }, + { 0xAB76, 0x54C9 }, + { 0xAB77, 0x54B8 }, + { 0xAB78, 0x54A6 }, + { 0xAB79, 0x54B3 }, + { 0xAB7A, 0x54C7 }, + { 0xAB7B, 0x54C2 }, + { 0xAB7C, 0x54BD }, + { 0xAB7D, 0x54AA }, + { 0xAB7E, 0x54C1 }, + { 0xABA1, 0x54C4 }, + { 0xABA2, 0x54C8 }, + { 0xABA3, 0x54AF }, + { 0xABA4, 0x54AB }, + { 0xABA5, 0x54B1 }, + { 0xABA6, 0x54BB }, + { 0xABA7, 0x54A9 }, + { 0xABA8, 0x54A7 }, + { 0xABA9, 0x54BF }, + { 0xABAA, 0x56FF }, + { 0xABAB, 0x5782 }, + { 0xABAC, 0x578B }, + { 0xABAD, 0x57A0 }, + { 0xABAE, 0x57A3 }, + { 0xABAF, 0x57A2 }, + { 0xABB0, 0x57CE }, + { 0xABB1, 0x57AE }, + { 0xABB2, 0x5793 }, + { 0xABB3, 0x5955 }, + { 0xABB4, 0x5951 }, + { 0xABB5, 0x594F }, + { 0xABB6, 0x594E }, + { 0xABB7, 0x5950 }, + { 0xABB8, 0x59DC }, + { 0xABB9, 0x59D8 }, + { 0xABBA, 0x59FF }, + { 0xABBB, 0x59E3 }, + { 0xABBC, 0x59E8 }, + { 0xABBD, 0x5A03 }, + { 0xABBE, 0x59E5 }, + { 0xABBF, 0x59EA }, + { 0xABC0, 0x59DA }, + { 0xABC1, 0x59E6 }, + { 0xABC2, 0x5A01 }, + { 0xABC3, 0x59FB }, + { 0xABC4, 0x5B69 }, + { 0xABC5, 0x5BA3 }, + { 0xABC6, 0x5BA6 }, + { 0xABC7, 0x5BA4 }, + { 0xABC8, 0x5BA2 }, + { 0xABC9, 0x5BA5 }, + { 0xABCA, 0x5C01 }, + { 0xABCB, 0x5C4E }, + { 0xABCC, 0x5C4F }, + { 0xABCD, 0x5C4D }, + { 0xABCE, 0x5C4B }, + { 0xABCF, 0x5CD9 }, + { 0xABD0, 0x5CD2 }, + { 0xABD1, 0x5DF7 }, + { 0xABD2, 0x5E1D }, + { 0xABD3, 0x5E25 }, + { 0xABD4, 0x5E1F }, + { 0xABD5, 0x5E7D }, + { 0xABD6, 0x5EA0 }, + { 0xABD7, 0x5EA6 }, + { 0xABD8, 0x5EFA }, + { 0xABD9, 0x5F08 }, + { 0xABDA, 0x5F2D }, + { 0xABDB, 0x5F65 }, + { 0xABDC, 0x5F88 }, + { 0xABDD, 0x5F85 }, + { 0xABDE, 0x5F8A }, + { 0xABDF, 0x5F8B }, + { 0xABE0, 0x5F87 }, + { 0xABE1, 0x5F8C }, + { 0xABE2, 0x5F89 }, + { 0xABE3, 0x6012 }, + { 0xABE4, 0x601D }, + { 0xABE5, 0x6020 }, + { 0xABE6, 0x6025 }, + { 0xABE7, 0x600E }, + { 0xABE8, 0x6028 }, + { 0xABE9, 0x604D }, + { 0xABEA, 0x6070 }, + { 0xABEB, 0x6068 }, + { 0xABEC, 0x6062 }, + { 0xABED, 0x6046 }, + { 0xABEE, 0x6043 }, + { 0xABEF, 0x606C }, + { 0xABF0, 0x606B }, + { 0xABF1, 0x606A }, + { 0xABF2, 0x6064 }, + { 0xABF3, 0x6241 }, + { 0xABF4, 0x62DC }, + { 0xABF5, 0x6316 }, + { 0xABF6, 0x6309 }, + { 0xABF7, 0x62FC }, + { 0xABF8, 0x62ED }, + { 0xABF9, 0x6301 }, + { 0xABFA, 0x62EE }, + { 0xABFB, 0x62FD }, + { 0xABFC, 0x6307 }, + { 0xABFD, 0x62F1 }, + { 0xABFE, 0x62F7 }, + { 0xAC40, 0x62EF }, + { 0xAC41, 0x62EC }, + { 0xAC42, 0x62FE }, + { 0xAC43, 0x62F4 }, + { 0xAC44, 0x6311 }, + { 0xAC45, 0x6302 }, + { 0xAC46, 0x653F }, + { 0xAC47, 0x6545 }, + { 0xAC48, 0x65AB }, + { 0xAC49, 0x65BD }, + { 0xAC4A, 0x65E2 }, + { 0xAC4B, 0x6625 }, + { 0xAC4C, 0x662D }, + { 0xAC4D, 0x6620 }, + { 0xAC4E, 0x6627 }, + { 0xAC4F, 0x662F }, + { 0xAC50, 0x661F }, + { 0xAC51, 0x6628 }, + { 0xAC52, 0x6631 }, + { 0xAC53, 0x6624 }, + { 0xAC54, 0x66F7 }, + { 0xAC55, 0x67FF }, + { 0xAC56, 0x67D3 }, + { 0xAC57, 0x67F1 }, + { 0xAC58, 0x67D4 }, + { 0xAC59, 0x67D0 }, + { 0xAC5A, 0x67EC }, + { 0xAC5B, 0x67B6 }, + { 0xAC5C, 0x67AF }, + { 0xAC5D, 0x67F5 }, + { 0xAC5E, 0x67E9 }, + { 0xAC5F, 0x67EF }, + { 0xAC60, 0x67C4 }, + { 0xAC61, 0x67D1 }, + { 0xAC62, 0x67B4 }, + { 0xAC63, 0x67DA }, + { 0xAC64, 0x67E5 }, + { 0xAC65, 0x67B8 }, + { 0xAC66, 0x67CF }, + { 0xAC67, 0x67DE }, + { 0xAC68, 0x67F3 }, + { 0xAC69, 0x67B0 }, + { 0xAC6A, 0x67D9 }, + { 0xAC6B, 0x67E2 }, + { 0xAC6C, 0x67DD }, + { 0xAC6D, 0x67D2 }, + { 0xAC6E, 0x6B6A }, + { 0xAC6F, 0x6B83 }, + { 0xAC70, 0x6B86 }, + { 0xAC71, 0x6BB5 }, + { 0xAC72, 0x6BD2 }, + { 0xAC73, 0x6BD7 }, + { 0xAC74, 0x6C1F }, + { 0xAC75, 0x6CC9 }, + { 0xAC76, 0x6D0B }, + { 0xAC77, 0x6D32 }, + { 0xAC78, 0x6D2A }, + { 0xAC79, 0x6D41 }, + { 0xAC7A, 0x6D25 }, + { 0xAC7B, 0x6D0C }, + { 0xAC7C, 0x6D31 }, + { 0xAC7D, 0x6D1E }, + { 0xAC7E, 0x6D17 }, + { 0xACA1, 0x6D3B }, + { 0xACA2, 0x6D3D }, + { 0xACA3, 0x6D3E }, + { 0xACA4, 0x6D36 }, + { 0xACA5, 0x6D1B }, + { 0xACA6, 0x6CF5 }, + { 0xACA7, 0x6D39 }, + { 0xACA8, 0x6D27 }, + { 0xACA9, 0x6D38 }, + { 0xACAA, 0x6D29 }, + { 0xACAB, 0x6D2E }, + { 0xACAC, 0x6D35 }, + { 0xACAD, 0x6D0E }, + { 0xACAE, 0x6D2B }, + { 0xACAF, 0x70AB }, + { 0xACB0, 0x70BA }, + { 0xACB1, 0x70B3 }, + { 0xACB2, 0x70AC }, + { 0xACB3, 0x70AF }, + { 0xACB4, 0x70AD }, + { 0xACB5, 0x70B8 }, + { 0xACB6, 0x70AE }, + { 0xACB7, 0x70A4 }, + { 0xACB8, 0x7230 }, + { 0xACB9, 0x7272 }, + { 0xACBA, 0x726F }, + { 0xACBB, 0x7274 }, + { 0xACBC, 0x72E9 }, + { 0xACBD, 0x72E0 }, + { 0xACBE, 0x72E1 }, + { 0xACBF, 0x73B7 }, + { 0xACC0, 0x73CA }, + { 0xACC1, 0x73BB }, + { 0xACC2, 0x73B2 }, + { 0xACC3, 0x73CD }, + { 0xACC4, 0x73C0 }, + { 0xACC5, 0x73B3 }, + { 0xACC6, 0x751A }, + { 0xACC7, 0x752D }, + { 0xACC8, 0x754F }, + { 0xACC9, 0x754C }, + { 0xACCA, 0x754E }, + { 0xACCB, 0x754B }, + { 0xACCC, 0x75AB }, + { 0xACCD, 0x75A4 }, + { 0xACCE, 0x75A5 }, + { 0xACCF, 0x75A2 }, + { 0xACD0, 0x75A3 }, + { 0xACD1, 0x7678 }, + { 0xACD2, 0x7686 }, + { 0xACD3, 0x7687 }, + { 0xACD4, 0x7688 }, + { 0xACD5, 0x76C8 }, + { 0xACD6, 0x76C6 }, + { 0xACD7, 0x76C3 }, + { 0xACD8, 0x76C5 }, + { 0xACD9, 0x7701 }, + { 0xACDA, 0x76F9 }, + { 0xACDB, 0x76F8 }, + { 0xACDC, 0x7709 }, + { 0xACDD, 0x770B }, + { 0xACDE, 0x76FE }, + { 0xACDF, 0x76FC }, + { 0xACE0, 0x7707 }, + { 0xACE1, 0x77DC }, + { 0xACE2, 0x7802 }, + { 0xACE3, 0x7814 }, + { 0xACE4, 0x780C }, + { 0xACE5, 0x780D }, + { 0xACE6, 0x7946 }, + { 0xACE7, 0x7949 }, + { 0xACE8, 0x7948 }, + { 0xACE9, 0x7947 }, + { 0xACEA, 0x79B9 }, + { 0xACEB, 0x79BA }, + { 0xACEC, 0x79D1 }, + { 0xACED, 0x79D2 }, + { 0xACEE, 0x79CB }, + { 0xACEF, 0x7A7F }, + { 0xACF0, 0x7A81 }, + { 0xACF1, 0x7AFF }, + { 0xACF2, 0x7AFD }, + { 0xACF3, 0x7C7D }, + { 0xACF4, 0x7D02 }, + { 0xACF5, 0x7D05 }, + { 0xACF6, 0x7D00 }, + { 0xACF7, 0x7D09 }, + { 0xACF8, 0x7D07 }, + { 0xACF9, 0x7D04 }, + { 0xACFA, 0x7D06 }, + { 0xACFB, 0x7F38 }, + { 0xACFC, 0x7F8E }, + { 0xACFD, 0x7FBF }, + { 0xACFE, 0x8004 }, + { 0xAD40, 0x8010 }, + { 0xAD41, 0x800D }, + { 0xAD42, 0x8011 }, + { 0xAD43, 0x8036 }, + { 0xAD44, 0x80D6 }, + { 0xAD45, 0x80E5 }, + { 0xAD46, 0x80DA }, + { 0xAD47, 0x80C3 }, + { 0xAD48, 0x80C4 }, + { 0xAD49, 0x80CC }, + { 0xAD4A, 0x80E1 }, + { 0xAD4B, 0x80DB }, + { 0xAD4C, 0x80CE }, + { 0xAD4D, 0x80DE }, + { 0xAD4E, 0x80E4 }, + { 0xAD4F, 0x80DD }, + { 0xAD50, 0x81F4 }, + { 0xAD51, 0x8222 }, + { 0xAD52, 0x82E7 }, + { 0xAD53, 0x8303 }, + { 0xAD54, 0x8305 }, + { 0xAD55, 0x82E3 }, + { 0xAD56, 0x82DB }, + { 0xAD57, 0x82E6 }, + { 0xAD58, 0x8304 }, + { 0xAD59, 0x82E5 }, + { 0xAD5A, 0x8302 }, + { 0xAD5B, 0x8309 }, + { 0xAD5C, 0x82D2 }, + { 0xAD5D, 0x82D7 }, + { 0xAD5E, 0x82F1 }, + { 0xAD5F, 0x8301 }, + { 0xAD60, 0x82DC }, + { 0xAD61, 0x82D4 }, + { 0xAD62, 0x82D1 }, + { 0xAD63, 0x82DE }, + { 0xAD64, 0x82D3 }, + { 0xAD65, 0x82DF }, + { 0xAD66, 0x82EF }, + { 0xAD67, 0x8306 }, + { 0xAD68, 0x8650 }, + { 0xAD69, 0x8679 }, + { 0xAD6A, 0x867B }, + { 0xAD6B, 0x867A }, + { 0xAD6C, 0x884D }, + { 0xAD6D, 0x886B }, + { 0xAD6E, 0x8981 }, + { 0xAD6F, 0x89D4 }, + { 0xAD70, 0x8A08 }, + { 0xAD71, 0x8A02 }, + { 0xAD72, 0x8A03 }, + { 0xAD73, 0x8C9E }, + { 0xAD74, 0x8CA0 }, + { 0xAD75, 0x8D74 }, + { 0xAD76, 0x8D73 }, + { 0xAD77, 0x8DB4 }, + { 0xAD78, 0x8ECD }, + { 0xAD79, 0x8ECC }, + { 0xAD7A, 0x8FF0 }, + { 0xAD7B, 0x8FE6 }, + { 0xAD7C, 0x8FE2 }, + { 0xAD7D, 0x8FEA }, + { 0xAD7E, 0x8FE5 }, + { 0xADA1, 0x8FED }, + { 0xADA2, 0x8FEB }, + { 0xADA3, 0x8FE4 }, + { 0xADA4, 0x8FE8 }, + { 0xADA5, 0x90CA }, + { 0xADA6, 0x90CE }, + { 0xADA7, 0x90C1 }, + { 0xADA8, 0x90C3 }, + { 0xADA9, 0x914B }, + { 0xADAA, 0x914A }, + { 0xADAB, 0x91CD }, + { 0xADAC, 0x9582 }, + { 0xADAD, 0x9650 }, + { 0xADAE, 0x964B }, + { 0xADAF, 0x964C }, + { 0xADB0, 0x964D }, + { 0xADB1, 0x9762 }, + { 0xADB2, 0x9769 }, + { 0xADB3, 0x97CB }, + { 0xADB4, 0x97ED }, + { 0xADB5, 0x97F3 }, + { 0xADB6, 0x9801 }, + { 0xADB7, 0x98A8 }, + { 0xADB8, 0x98DB }, + { 0xADB9, 0x98DF }, + { 0xADBA, 0x9996 }, + { 0xADBB, 0x9999 }, + { 0xADBC, 0x4E58 }, + { 0xADBD, 0x4EB3 }, + { 0xADBE, 0x500C }, + { 0xADBF, 0x500D }, + { 0xADC0, 0x5023 }, + { 0xADC1, 0x4FEF }, + { 0xADC2, 0x5026 }, + { 0xADC3, 0x5025 }, + { 0xADC4, 0x4FF8 }, + { 0xADC5, 0x5029 }, + { 0xADC6, 0x5016 }, + { 0xADC7, 0x5006 }, + { 0xADC8, 0x503C }, + { 0xADC9, 0x501F }, + { 0xADCA, 0x501A }, + { 0xADCB, 0x5012 }, + { 0xADCC, 0x5011 }, + { 0xADCD, 0x4FFA }, + { 0xADCE, 0x5000 }, + { 0xADCF, 0x5014 }, + { 0xADD0, 0x5028 }, + { 0xADD1, 0x4FF1 }, + { 0xADD2, 0x5021 }, + { 0xADD3, 0x500B }, + { 0xADD4, 0x5019 }, + { 0xADD5, 0x5018 }, + { 0xADD6, 0x4FF3 }, + { 0xADD7, 0x4FEE }, + { 0xADD8, 0x502D }, + { 0xADD9, 0x502A }, + { 0xADDA, 0x4FFE }, + { 0xADDB, 0x502B }, + { 0xADDC, 0x5009 }, + { 0xADDD, 0x517C }, + { 0xADDE, 0x51A4 }, + { 0xADDF, 0x51A5 }, + { 0xADE0, 0x51A2 }, + { 0xADE1, 0x51CD }, + { 0xADE2, 0x51CC }, + { 0xADE3, 0x51C6 }, + { 0xADE4, 0x51CB }, + { 0xADE5, 0x5256 }, + { 0xADE6, 0x525C }, + { 0xADE7, 0x5254 }, + { 0xADE8, 0x525B }, + { 0xADE9, 0x525D }, + { 0xADEA, 0x532A }, + { 0xADEB, 0x537F }, + { 0xADEC, 0x539F }, + { 0xADED, 0x539D }, + { 0xADEE, 0x53DF }, + { 0xADEF, 0x54E8 }, + { 0xADF0, 0x5510 }, + { 0xADF1, 0x5501 }, + { 0xADF2, 0x5537 }, + { 0xADF3, 0x54FC }, + { 0xADF4, 0x54E5 }, + { 0xADF5, 0x54F2 }, + { 0xADF6, 0x5506 }, + { 0xADF7, 0x54FA }, + { 0xADF8, 0x5514 }, + { 0xADF9, 0x54E9 }, + { 0xADFA, 0x54ED }, + { 0xADFB, 0x54E1 }, + { 0xADFC, 0x5509 }, + { 0xADFD, 0x54EE }, + { 0xADFE, 0x54EA }, + { 0xAE40, 0x54E6 }, + { 0xAE41, 0x5527 }, + { 0xAE42, 0x5507 }, + { 0xAE43, 0x54FD }, + { 0xAE44, 0x550F }, + { 0xAE45, 0x5703 }, + { 0xAE46, 0x5704 }, + { 0xAE47, 0x57C2 }, + { 0xAE48, 0x57D4 }, + { 0xAE49, 0x57CB }, + { 0xAE4A, 0x57C3 }, + { 0xAE4B, 0x5809 }, + { 0xAE4C, 0x590F }, + { 0xAE4D, 0x5957 }, + { 0xAE4E, 0x5958 }, + { 0xAE4F, 0x595A }, + { 0xAE50, 0x5A11 }, + { 0xAE51, 0x5A18 }, + { 0xAE52, 0x5A1C }, + { 0xAE53, 0x5A1F }, + { 0xAE54, 0x5A1B }, + { 0xAE55, 0x5A13 }, + { 0xAE56, 0x59EC }, + { 0xAE57, 0x5A20 }, + { 0xAE58, 0x5A23 }, + { 0xAE59, 0x5A29 }, + { 0xAE5A, 0x5A25 }, + { 0xAE5B, 0x5A0C }, + { 0xAE5C, 0x5A09 }, + { 0xAE5D, 0x5B6B }, + { 0xAE5E, 0x5C58 }, + { 0xAE5F, 0x5BB0 }, + { 0xAE60, 0x5BB3 }, + { 0xAE61, 0x5BB6 }, + { 0xAE62, 0x5BB4 }, + { 0xAE63, 0x5BAE }, + { 0xAE64, 0x5BB5 }, + { 0xAE65, 0x5BB9 }, + { 0xAE66, 0x5BB8 }, + { 0xAE67, 0x5C04 }, + { 0xAE68, 0x5C51 }, + { 0xAE69, 0x5C55 }, + { 0xAE6A, 0x5C50 }, + { 0xAE6B, 0x5CED }, + { 0xAE6C, 0x5CFD }, + { 0xAE6D, 0x5CFB }, + { 0xAE6E, 0x5CEA }, + { 0xAE6F, 0x5CE8 }, + { 0xAE70, 0x5CF0 }, + { 0xAE71, 0x5CF6 }, + { 0xAE72, 0x5D01 }, + { 0xAE73, 0x5CF4 }, + { 0xAE74, 0x5DEE }, + { 0xAE75, 0x5E2D }, + { 0xAE76, 0x5E2B }, + { 0xAE77, 0x5EAB }, + { 0xAE78, 0x5EAD }, + { 0xAE79, 0x5EA7 }, + { 0xAE7A, 0x5F31 }, + { 0xAE7B, 0x5F92 }, + { 0xAE7C, 0x5F91 }, + { 0xAE7D, 0x5F90 }, + { 0xAE7E, 0x6059 }, + { 0xAEA1, 0x6063 }, + { 0xAEA2, 0x6065 }, + { 0xAEA3, 0x6050 }, + { 0xAEA4, 0x6055 }, + { 0xAEA5, 0x606D }, + { 0xAEA6, 0x6069 }, + { 0xAEA7, 0x606F }, + { 0xAEA8, 0x6084 }, + { 0xAEA9, 0x609F }, + { 0xAEAA, 0x609A }, + { 0xAEAB, 0x608D }, + { 0xAEAC, 0x6094 }, + { 0xAEAD, 0x608C }, + { 0xAEAE, 0x6085 }, + { 0xAEAF, 0x6096 }, + { 0xAEB0, 0x6247 }, + { 0xAEB1, 0x62F3 }, + { 0xAEB2, 0x6308 }, + { 0xAEB3, 0x62FF }, + { 0xAEB4, 0x634E }, + { 0xAEB5, 0x633E }, + { 0xAEB6, 0x632F }, + { 0xAEB7, 0x6355 }, + { 0xAEB8, 0x6342 }, + { 0xAEB9, 0x6346 }, + { 0xAEBA, 0x634F }, + { 0xAEBB, 0x6349 }, + { 0xAEBC, 0x633A }, + { 0xAEBD, 0x6350 }, + { 0xAEBE, 0x633D }, + { 0xAEBF, 0x632A }, + { 0xAEC0, 0x632B }, + { 0xAEC1, 0x6328 }, + { 0xAEC2, 0x634D }, + { 0xAEC3, 0x634C }, + { 0xAEC4, 0x6548 }, + { 0xAEC5, 0x6549 }, + { 0xAEC6, 0x6599 }, + { 0xAEC7, 0x65C1 }, + { 0xAEC8, 0x65C5 }, + { 0xAEC9, 0x6642 }, + { 0xAECA, 0x6649 }, + { 0xAECB, 0x664F }, + { 0xAECC, 0x6643 }, + { 0xAECD, 0x6652 }, + { 0xAECE, 0x664C }, + { 0xAECF, 0x6645 }, + { 0xAED0, 0x6641 }, + { 0xAED1, 0x66F8 }, + { 0xAED2, 0x6714 }, + { 0xAED3, 0x6715 }, + { 0xAED4, 0x6717 }, + { 0xAED5, 0x6821 }, + { 0xAED6, 0x6838 }, + { 0xAED7, 0x6848 }, + { 0xAED8, 0x6846 }, + { 0xAED9, 0x6853 }, + { 0xAEDA, 0x6839 }, + { 0xAEDB, 0x6842 }, + { 0xAEDC, 0x6854 }, + { 0xAEDD, 0x6829 }, + { 0xAEDE, 0x68B3 }, + { 0xAEDF, 0x6817 }, + { 0xAEE0, 0x684C }, + { 0xAEE1, 0x6851 }, + { 0xAEE2, 0x683D }, + { 0xAEE3, 0x67F4 }, + { 0xAEE4, 0x6850 }, + { 0xAEE5, 0x6840 }, + { 0xAEE6, 0x683C }, + { 0xAEE7, 0x6843 }, + { 0xAEE8, 0x682A }, + { 0xAEE9, 0x6845 }, + { 0xAEEA, 0x6813 }, + { 0xAEEB, 0x6818 }, + { 0xAEEC, 0x6841 }, + { 0xAEED, 0x6B8A }, + { 0xAEEE, 0x6B89 }, + { 0xAEEF, 0x6BB7 }, + { 0xAEF0, 0x6C23 }, + { 0xAEF1, 0x6C27 }, + { 0xAEF2, 0x6C28 }, + { 0xAEF3, 0x6C26 }, + { 0xAEF4, 0x6C24 }, + { 0xAEF5, 0x6CF0 }, + { 0xAEF6, 0x6D6A }, + { 0xAEF7, 0x6D95 }, + { 0xAEF8, 0x6D88 }, + { 0xAEF9, 0x6D87 }, + { 0xAEFA, 0x6D66 }, + { 0xAEFB, 0x6D78 }, + { 0xAEFC, 0x6D77 }, + { 0xAEFD, 0x6D59 }, + { 0xAEFE, 0x6D93 }, + { 0xAF40, 0x6D6C }, + { 0xAF41, 0x6D89 }, + { 0xAF42, 0x6D6E }, + { 0xAF43, 0x6D5A }, + { 0xAF44, 0x6D74 }, + { 0xAF45, 0x6D69 }, + { 0xAF46, 0x6D8C }, + { 0xAF47, 0x6D8A }, + { 0xAF48, 0x6D79 }, + { 0xAF49, 0x6D85 }, + { 0xAF4A, 0x6D65 }, + { 0xAF4B, 0x6D94 }, + { 0xAF4C, 0x70CA }, + { 0xAF4D, 0x70D8 }, + { 0xAF4E, 0x70E4 }, + { 0xAF4F, 0x70D9 }, + { 0xAF50, 0x70C8 }, + { 0xAF51, 0x70CF }, + { 0xAF52, 0x7239 }, + { 0xAF53, 0x7279 }, + { 0xAF54, 0x72FC }, + { 0xAF55, 0x72F9 }, + { 0xAF56, 0x72FD }, + { 0xAF57, 0x72F8 }, + { 0xAF58, 0x72F7 }, + { 0xAF59, 0x7386 }, + { 0xAF5A, 0x73ED }, + { 0xAF5B, 0x7409 }, + { 0xAF5C, 0x73EE }, + { 0xAF5D, 0x73E0 }, + { 0xAF5E, 0x73EA }, + { 0xAF5F, 0x73DE }, + { 0xAF60, 0x7554 }, + { 0xAF61, 0x755D }, + { 0xAF62, 0x755C }, + { 0xAF63, 0x755A }, + { 0xAF64, 0x7559 }, + { 0xAF65, 0x75BE }, + { 0xAF66, 0x75C5 }, + { 0xAF67, 0x75C7 }, + { 0xAF68, 0x75B2 }, + { 0xAF69, 0x75B3 }, + { 0xAF6A, 0x75BD }, + { 0xAF6B, 0x75BC }, + { 0xAF6C, 0x75B9 }, + { 0xAF6D, 0x75C2 }, + { 0xAF6E, 0x75B8 }, + { 0xAF6F, 0x768B }, + { 0xAF70, 0x76B0 }, + { 0xAF71, 0x76CA }, + { 0xAF72, 0x76CD }, + { 0xAF73, 0x76CE }, + { 0xAF74, 0x7729 }, + { 0xAF75, 0x771F }, + { 0xAF76, 0x7720 }, + { 0xAF77, 0x7728 }, + { 0xAF78, 0x77E9 }, + { 0xAF79, 0x7830 }, + { 0xAF7A, 0x7827 }, + { 0xAF7B, 0x7838 }, + { 0xAF7C, 0x781D }, + { 0xAF7D, 0x7834 }, + { 0xAF7E, 0x7837 }, + { 0xAFA1, 0x7825 }, + { 0xAFA2, 0x782D }, + { 0xAFA3, 0x7820 }, + { 0xAFA4, 0x781F }, + { 0xAFA5, 0x7832 }, + { 0xAFA6, 0x7955 }, + { 0xAFA7, 0x7950 }, + { 0xAFA8, 0x7960 }, + { 0xAFA9, 0x795F }, + { 0xAFAA, 0x7956 }, + { 0xAFAB, 0x795E }, + { 0xAFAC, 0x795D }, + { 0xAFAD, 0x7957 }, + { 0xAFAE, 0x795A }, + { 0xAFAF, 0x79E4 }, + { 0xAFB0, 0x79E3 }, + { 0xAFB1, 0x79E7 }, + { 0xAFB2, 0x79DF }, + { 0xAFB3, 0x79E6 }, + { 0xAFB4, 0x79E9 }, + { 0xAFB5, 0x79D8 }, + { 0xAFB6, 0x7A84 }, + { 0xAFB7, 0x7A88 }, + { 0xAFB8, 0x7AD9 }, + { 0xAFB9, 0x7B06 }, + { 0xAFBA, 0x7B11 }, + { 0xAFBB, 0x7C89 }, + { 0xAFBC, 0x7D21 }, + { 0xAFBD, 0x7D17 }, + { 0xAFBE, 0x7D0B }, + { 0xAFBF, 0x7D0A }, + { 0xAFC0, 0x7D20 }, + { 0xAFC1, 0x7D22 }, + { 0xAFC2, 0x7D14 }, + { 0xAFC3, 0x7D10 }, + { 0xAFC4, 0x7D15 }, + { 0xAFC5, 0x7D1A }, + { 0xAFC6, 0x7D1C }, + { 0xAFC7, 0x7D0D }, + { 0xAFC8, 0x7D19 }, + { 0xAFC9, 0x7D1B }, + { 0xAFCA, 0x7F3A }, + { 0xAFCB, 0x7F5F }, + { 0xAFCC, 0x7F94 }, + { 0xAFCD, 0x7FC5 }, + { 0xAFCE, 0x7FC1 }, + { 0xAFCF, 0x8006 }, + { 0xAFD0, 0x8018 }, + { 0xAFD1, 0x8015 }, + { 0xAFD2, 0x8019 }, + { 0xAFD3, 0x8017 }, + { 0xAFD4, 0x803D }, + { 0xAFD5, 0x803F }, + { 0xAFD6, 0x80F1 }, + { 0xAFD7, 0x8102 }, + { 0xAFD8, 0x80F0 }, + { 0xAFD9, 0x8105 }, + { 0xAFDA, 0x80ED }, + { 0xAFDB, 0x80F4 }, + { 0xAFDC, 0x8106 }, + { 0xAFDD, 0x80F8 }, + { 0xAFDE, 0x80F3 }, + { 0xAFDF, 0x8108 }, + { 0xAFE0, 0x80FD }, + { 0xAFE1, 0x810A }, + { 0xAFE2, 0x80FC }, + { 0xAFE3, 0x80EF }, + { 0xAFE4, 0x81ED }, + { 0xAFE5, 0x81EC }, + { 0xAFE6, 0x8200 }, + { 0xAFE7, 0x8210 }, + { 0xAFE8, 0x822A }, + { 0xAFE9, 0x822B }, + { 0xAFEA, 0x8228 }, + { 0xAFEB, 0x822C }, + { 0xAFEC, 0x82BB }, + { 0xAFED, 0x832B }, + { 0xAFEE, 0x8352 }, + { 0xAFEF, 0x8354 }, + { 0xAFF0, 0x834A }, + { 0xAFF1, 0x8338 }, + { 0xAFF2, 0x8350 }, + { 0xAFF3, 0x8349 }, + { 0xAFF4, 0x8335 }, + { 0xAFF5, 0x8334 }, + { 0xAFF6, 0x834F }, + { 0xAFF7, 0x8332 }, + { 0xAFF8, 0x8339 }, + { 0xAFF9, 0x8336 }, + { 0xAFFA, 0x8317 }, + { 0xAFFB, 0x8340 }, + { 0xAFFC, 0x8331 }, + { 0xAFFD, 0x8328 }, + { 0xAFFE, 0x8343 }, + { 0xB040, 0x8654 }, + { 0xB041, 0x868A }, + { 0xB042, 0x86AA }, + { 0xB043, 0x8693 }, + { 0xB044, 0x86A4 }, + { 0xB045, 0x86A9 }, + { 0xB046, 0x868C }, + { 0xB047, 0x86A3 }, + { 0xB048, 0x869C }, + { 0xB049, 0x8870 }, + { 0xB04A, 0x8877 }, + { 0xB04B, 0x8881 }, + { 0xB04C, 0x8882 }, + { 0xB04D, 0x887D }, + { 0xB04E, 0x8879 }, + { 0xB04F, 0x8A18 }, + { 0xB050, 0x8A10 }, + { 0xB051, 0x8A0E }, + { 0xB052, 0x8A0C }, + { 0xB053, 0x8A15 }, + { 0xB054, 0x8A0A }, + { 0xB055, 0x8A17 }, + { 0xB056, 0x8A13 }, + { 0xB057, 0x8A16 }, + { 0xB058, 0x8A0F }, + { 0xB059, 0x8A11 }, + { 0xB05A, 0x8C48 }, + { 0xB05B, 0x8C7A }, + { 0xB05C, 0x8C79 }, + { 0xB05D, 0x8CA1 }, + { 0xB05E, 0x8CA2 }, + { 0xB05F, 0x8D77 }, + { 0xB060, 0x8EAC }, + { 0xB061, 0x8ED2 }, + { 0xB062, 0x8ED4 }, + { 0xB063, 0x8ECF }, + { 0xB064, 0x8FB1 }, + { 0xB065, 0x9001 }, + { 0xB066, 0x9006 }, + { 0xB067, 0x8FF7 }, + { 0xB068, 0x9000 }, + { 0xB069, 0x8FFA }, + { 0xB06A, 0x8FF4 }, + { 0xB06B, 0x9003 }, + { 0xB06C, 0x8FFD }, + { 0xB06D, 0x9005 }, + { 0xB06E, 0x8FF8 }, + { 0xB06F, 0x9095 }, + { 0xB070, 0x90E1 }, + { 0xB071, 0x90DD }, + { 0xB072, 0x90E2 }, + { 0xB073, 0x9152 }, + { 0xB074, 0x914D }, + { 0xB075, 0x914C }, + { 0xB076, 0x91D8 }, + { 0xB077, 0x91DD }, + { 0xB078, 0x91D7 }, + { 0xB079, 0x91DC }, + { 0xB07A, 0x91D9 }, + { 0xB07B, 0x9583 }, + { 0xB07C, 0x9662 }, + { 0xB07D, 0x9663 }, + { 0xB07E, 0x9661 }, + { 0xB0A1, 0x965B }, + { 0xB0A2, 0x965D }, + { 0xB0A3, 0x9664 }, + { 0xB0A4, 0x9658 }, + { 0xB0A5, 0x965E }, + { 0xB0A6, 0x96BB }, + { 0xB0A7, 0x98E2 }, + { 0xB0A8, 0x99AC }, + { 0xB0A9, 0x9AA8 }, + { 0xB0AA, 0x9AD8 }, + { 0xB0AB, 0x9B25 }, + { 0xB0AC, 0x9B32 }, + { 0xB0AD, 0x9B3C }, + { 0xB0AE, 0x4E7E }, + { 0xB0AF, 0x507A }, + { 0xB0B0, 0x507D }, + { 0xB0B1, 0x505C }, + { 0xB0B2, 0x5047 }, + { 0xB0B3, 0x5043 }, + { 0xB0B4, 0x504C }, + { 0xB0B5, 0x505A }, + { 0xB0B6, 0x5049 }, + { 0xB0B7, 0x5065 }, + { 0xB0B8, 0x5076 }, + { 0xB0B9, 0x504E }, + { 0xB0BA, 0x5055 }, + { 0xB0BB, 0x5075 }, + { 0xB0BC, 0x5074 }, + { 0xB0BD, 0x5077 }, + { 0xB0BE, 0x504F }, + { 0xB0BF, 0x500F }, + { 0xB0C0, 0x506F }, + { 0xB0C1, 0x506D }, + { 0xB0C2, 0x515C }, + { 0xB0C3, 0x5195 }, + { 0xB0C4, 0x51F0 }, + { 0xB0C5, 0x526A }, + { 0xB0C6, 0x526F }, + { 0xB0C7, 0x52D2 }, + { 0xB0C8, 0x52D9 }, + { 0xB0C9, 0x52D8 }, + { 0xB0CA, 0x52D5 }, + { 0xB0CB, 0x5310 }, + { 0xB0CC, 0x530F }, + { 0xB0CD, 0x5319 }, + { 0xB0CE, 0x533F }, + { 0xB0CF, 0x5340 }, + { 0xB0D0, 0x533E }, + { 0xB0D1, 0x53C3 }, + { 0xB0D2, 0x66FC }, + { 0xB0D3, 0x5546 }, + { 0xB0D4, 0x556A }, + { 0xB0D5, 0x5566 }, + { 0xB0D6, 0x5544 }, + { 0xB0D7, 0x555E }, + { 0xB0D8, 0x5561 }, + { 0xB0D9, 0x5543 }, + { 0xB0DA, 0x554A }, + { 0xB0DB, 0x5531 }, + { 0xB0DC, 0x5556 }, + { 0xB0DD, 0x554F }, + { 0xB0DE, 0x5555 }, + { 0xB0DF, 0x552F }, + { 0xB0E0, 0x5564 }, + { 0xB0E1, 0x5538 }, + { 0xB0E2, 0x552E }, + { 0xB0E3, 0x555C }, + { 0xB0E4, 0x552C }, + { 0xB0E5, 0x5563 }, + { 0xB0E6, 0x5533 }, + { 0xB0E7, 0x5541 }, + { 0xB0E8, 0x5557 }, + { 0xB0E9, 0x5708 }, + { 0xB0EA, 0x570B }, + { 0xB0EB, 0x5709 }, + { 0xB0EC, 0x57DF }, + { 0xB0ED, 0x5805 }, + { 0xB0EE, 0x580A }, + { 0xB0EF, 0x5806 }, + { 0xB0F0, 0x57E0 }, + { 0xB0F1, 0x57E4 }, + { 0xB0F2, 0x57FA }, + { 0xB0F3, 0x5802 }, + { 0xB0F4, 0x5835 }, + { 0xB0F5, 0x57F7 }, + { 0xB0F6, 0x57F9 }, + { 0xB0F7, 0x5920 }, + { 0xB0F8, 0x5962 }, + { 0xB0F9, 0x5A36 }, + { 0xB0FA, 0x5A41 }, + { 0xB0FB, 0x5A49 }, + { 0xB0FC, 0x5A66 }, + { 0xB0FD, 0x5A6A }, + { 0xB0FE, 0x5A40 }, + { 0xB140, 0x5A3C }, + { 0xB141, 0x5A62 }, + { 0xB142, 0x5A5A }, + { 0xB143, 0x5A46 }, + { 0xB144, 0x5A4A }, + { 0xB145, 0x5B70 }, + { 0xB146, 0x5BC7 }, + { 0xB147, 0x5BC5 }, + { 0xB148, 0x5BC4 }, + { 0xB149, 0x5BC2 }, + { 0xB14A, 0x5BBF }, + { 0xB14B, 0x5BC6 }, + { 0xB14C, 0x5C09 }, + { 0xB14D, 0x5C08 }, + { 0xB14E, 0x5C07 }, + { 0xB14F, 0x5C60 }, + { 0xB150, 0x5C5C }, + { 0xB151, 0x5C5D }, + { 0xB152, 0x5D07 }, + { 0xB153, 0x5D06 }, + { 0xB154, 0x5D0E }, + { 0xB155, 0x5D1B }, + { 0xB156, 0x5D16 }, + { 0xB157, 0x5D22 }, + { 0xB158, 0x5D11 }, + { 0xB159, 0x5D29 }, + { 0xB15A, 0x5D14 }, + { 0xB15B, 0x5D19 }, + { 0xB15C, 0x5D24 }, + { 0xB15D, 0x5D27 }, + { 0xB15E, 0x5D17 }, + { 0xB15F, 0x5DE2 }, + { 0xB160, 0x5E38 }, + { 0xB161, 0x5E36 }, + { 0xB162, 0x5E33 }, + { 0xB163, 0x5E37 }, + { 0xB164, 0x5EB7 }, + { 0xB165, 0x5EB8 }, + { 0xB166, 0x5EB6 }, + { 0xB167, 0x5EB5 }, + { 0xB168, 0x5EBE }, + { 0xB169, 0x5F35 }, + { 0xB16A, 0x5F37 }, + { 0xB16B, 0x5F57 }, + { 0xB16C, 0x5F6C }, + { 0xB16D, 0x5F69 }, + { 0xB16E, 0x5F6B }, + { 0xB16F, 0x5F97 }, + { 0xB170, 0x5F99 }, + { 0xB171, 0x5F9E }, + { 0xB172, 0x5F98 }, + { 0xB173, 0x5FA1 }, + { 0xB174, 0x5FA0 }, + { 0xB175, 0x5F9C }, + { 0xB176, 0x607F }, + { 0xB177, 0x60A3 }, + { 0xB178, 0x6089 }, + { 0xB179, 0x60A0 }, + { 0xB17A, 0x60A8 }, + { 0xB17B, 0x60CB }, + { 0xB17C, 0x60B4 }, + { 0xB17D, 0x60E6 }, + { 0xB17E, 0x60BD }, + { 0xB1A1, 0x60C5 }, + { 0xB1A2, 0x60BB }, + { 0xB1A3, 0x60B5 }, + { 0xB1A4, 0x60DC }, + { 0xB1A5, 0x60BC }, + { 0xB1A6, 0x60D8 }, + { 0xB1A7, 0x60D5 }, + { 0xB1A8, 0x60C6 }, + { 0xB1A9, 0x60DF }, + { 0xB1AA, 0x60B8 }, + { 0xB1AB, 0x60DA }, + { 0xB1AC, 0x60C7 }, + { 0xB1AD, 0x621A }, + { 0xB1AE, 0x621B }, + { 0xB1AF, 0x6248 }, + { 0xB1B0, 0x63A0 }, + { 0xB1B1, 0x63A7 }, + { 0xB1B2, 0x6372 }, + { 0xB1B3, 0x6396 }, + { 0xB1B4, 0x63A2 }, + { 0xB1B5, 0x63A5 }, + { 0xB1B6, 0x6377 }, + { 0xB1B7, 0x6367 }, + { 0xB1B8, 0x6398 }, + { 0xB1B9, 0x63AA }, + { 0xB1BA, 0x6371 }, + { 0xB1BB, 0x63A9 }, + { 0xB1BC, 0x6389 }, + { 0xB1BD, 0x6383 }, + { 0xB1BE, 0x639B }, + { 0xB1BF, 0x636B }, + { 0xB1C0, 0x63A8 }, + { 0xB1C1, 0x6384 }, + { 0xB1C2, 0x6388 }, + { 0xB1C3, 0x6399 }, + { 0xB1C4, 0x63A1 }, + { 0xB1C5, 0x63AC }, + { 0xB1C6, 0x6392 }, + { 0xB1C7, 0x638F }, + { 0xB1C8, 0x6380 }, + { 0xB1C9, 0x637B }, + { 0xB1CA, 0x6369 }, + { 0xB1CB, 0x6368 }, + { 0xB1CC, 0x637A }, + { 0xB1CD, 0x655D }, + { 0xB1CE, 0x6556 }, + { 0xB1CF, 0x6551 }, + { 0xB1D0, 0x6559 }, + { 0xB1D1, 0x6557 }, + { 0xB1D2, 0x555F }, + { 0xB1D3, 0x654F }, + { 0xB1D4, 0x6558 }, + { 0xB1D5, 0x6555 }, + { 0xB1D6, 0x6554 }, + { 0xB1D7, 0x659C }, + { 0xB1D8, 0x659B }, + { 0xB1D9, 0x65AC }, + { 0xB1DA, 0x65CF }, + { 0xB1DB, 0x65CB }, + { 0xB1DC, 0x65CC }, + { 0xB1DD, 0x65CE }, + { 0xB1DE, 0x665D }, + { 0xB1DF, 0x665A }, + { 0xB1E0, 0x6664 }, + { 0xB1E1, 0x6668 }, + { 0xB1E2, 0x6666 }, + { 0xB1E3, 0x665E }, + { 0xB1E4, 0x66F9 }, + { 0xB1E5, 0x52D7 }, + { 0xB1E6, 0x671B }, + { 0xB1E7, 0x6881 }, + { 0xB1E8, 0x68AF }, + { 0xB1E9, 0x68A2 }, + { 0xB1EA, 0x6893 }, + { 0xB1EB, 0x68B5 }, + { 0xB1EC, 0x687F }, + { 0xB1ED, 0x6876 }, + { 0xB1EE, 0x68B1 }, + { 0xB1EF, 0x68A7 }, + { 0xB1F0, 0x6897 }, + { 0xB1F1, 0x68B0 }, + { 0xB1F2, 0x6883 }, + { 0xB1F3, 0x68C4 }, + { 0xB1F4, 0x68AD }, + { 0xB1F5, 0x6886 }, + { 0xB1F6, 0x6885 }, + { 0xB1F7, 0x6894 }, + { 0xB1F8, 0x689D }, + { 0xB1F9, 0x68A8 }, + { 0xB1FA, 0x689F }, + { 0xB1FB, 0x68A1 }, + { 0xB1FC, 0x6882 }, + { 0xB1FD, 0x6B32 }, + { 0xB1FE, 0x6BBA }, + { 0xB240, 0x6BEB }, + { 0xB241, 0x6BEC }, + { 0xB242, 0x6C2B }, + { 0xB243, 0x6D8E }, + { 0xB244, 0x6DBC }, + { 0xB245, 0x6DF3 }, + { 0xB246, 0x6DD9 }, + { 0xB247, 0x6DB2 }, + { 0xB248, 0x6DE1 }, + { 0xB249, 0x6DCC }, + { 0xB24A, 0x6DE4 }, + { 0xB24B, 0x6DFB }, + { 0xB24C, 0x6DFA }, + { 0xB24D, 0x6E05 }, + { 0xB24E, 0x6DC7 }, + { 0xB24F, 0x6DCB }, + { 0xB250, 0x6DAF }, + { 0xB251, 0x6DD1 }, + { 0xB252, 0x6DAE }, + { 0xB253, 0x6DDE }, + { 0xB254, 0x6DF9 }, + { 0xB255, 0x6DB8 }, + { 0xB256, 0x6DF7 }, + { 0xB257, 0x6DF5 }, + { 0xB258, 0x6DC5 }, + { 0xB259, 0x6DD2 }, + { 0xB25A, 0x6E1A }, + { 0xB25B, 0x6DB5 }, + { 0xB25C, 0x6DDA }, + { 0xB25D, 0x6DEB }, + { 0xB25E, 0x6DD8 }, + { 0xB25F, 0x6DEA }, + { 0xB260, 0x6DF1 }, + { 0xB261, 0x6DEE }, + { 0xB262, 0x6DE8 }, + { 0xB263, 0x6DC6 }, + { 0xB264, 0x6DC4 }, + { 0xB265, 0x6DAA }, + { 0xB266, 0x6DEC }, + { 0xB267, 0x6DBF }, + { 0xB268, 0x6DE6 }, + { 0xB269, 0x70F9 }, + { 0xB26A, 0x7109 }, + { 0xB26B, 0x710A }, + { 0xB26C, 0x70FD }, + { 0xB26D, 0x70EF }, + { 0xB26E, 0x723D }, + { 0xB26F, 0x727D }, + { 0xB270, 0x7281 }, + { 0xB271, 0x731C }, + { 0xB272, 0x731B }, + { 0xB273, 0x7316 }, + { 0xB274, 0x7313 }, + { 0xB275, 0x7319 }, + { 0xB276, 0x7387 }, + { 0xB277, 0x7405 }, + { 0xB278, 0x740A }, + { 0xB279, 0x7403 }, + { 0xB27A, 0x7406 }, + { 0xB27B, 0x73FE }, + { 0xB27C, 0x740D }, + { 0xB27D, 0x74E0 }, + { 0xB27E, 0x74F6 }, + { 0xB2A1, 0x74F7 }, + { 0xB2A2, 0x751C }, + { 0xB2A3, 0x7522 }, + { 0xB2A4, 0x7565 }, + { 0xB2A5, 0x7566 }, + { 0xB2A6, 0x7562 }, + { 0xB2A7, 0x7570 }, + { 0xB2A8, 0x758F }, + { 0xB2A9, 0x75D4 }, + { 0xB2AA, 0x75D5 }, + { 0xB2AB, 0x75B5 }, + { 0xB2AC, 0x75CA }, + { 0xB2AD, 0x75CD }, + { 0xB2AE, 0x768E }, + { 0xB2AF, 0x76D4 }, + { 0xB2B0, 0x76D2 }, + { 0xB2B1, 0x76DB }, + { 0xB2B2, 0x7737 }, + { 0xB2B3, 0x773E }, + { 0xB2B4, 0x773C }, + { 0xB2B5, 0x7736 }, + { 0xB2B6, 0x7738 }, + { 0xB2B7, 0x773A }, + { 0xB2B8, 0x786B }, + { 0xB2B9, 0x7843 }, + { 0xB2BA, 0x784E }, + { 0xB2BB, 0x7965 }, + { 0xB2BC, 0x7968 }, + { 0xB2BD, 0x796D }, + { 0xB2BE, 0x79FB }, + { 0xB2BF, 0x7A92 }, + { 0xB2C0, 0x7A95 }, + { 0xB2C1, 0x7B20 }, + { 0xB2C2, 0x7B28 }, + { 0xB2C3, 0x7B1B }, + { 0xB2C4, 0x7B2C }, + { 0xB2C5, 0x7B26 }, + { 0xB2C6, 0x7B19 }, + { 0xB2C7, 0x7B1E }, + { 0xB2C8, 0x7B2E }, + { 0xB2C9, 0x7C92 }, + { 0xB2CA, 0x7C97 }, + { 0xB2CB, 0x7C95 }, + { 0xB2CC, 0x7D46 }, + { 0xB2CD, 0x7D43 }, + { 0xB2CE, 0x7D71 }, + { 0xB2CF, 0x7D2E }, + { 0xB2D0, 0x7D39 }, + { 0xB2D1, 0x7D3C }, + { 0xB2D2, 0x7D40 }, + { 0xB2D3, 0x7D30 }, + { 0xB2D4, 0x7D33 }, + { 0xB2D5, 0x7D44 }, + { 0xB2D6, 0x7D2F }, + { 0xB2D7, 0x7D42 }, + { 0xB2D8, 0x7D32 }, + { 0xB2D9, 0x7D31 }, + { 0xB2DA, 0x7F3D }, + { 0xB2DB, 0x7F9E }, + { 0xB2DC, 0x7F9A }, + { 0xB2DD, 0x7FCC }, + { 0xB2DE, 0x7FCE }, + { 0xB2DF, 0x7FD2 }, + { 0xB2E0, 0x801C }, + { 0xB2E1, 0x804A }, + { 0xB2E2, 0x8046 }, + { 0xB2E3, 0x812F }, + { 0xB2E4, 0x8116 }, + { 0xB2E5, 0x8123 }, + { 0xB2E6, 0x812B }, + { 0xB2E7, 0x8129 }, + { 0xB2E8, 0x8130 }, + { 0xB2E9, 0x8124 }, + { 0xB2EA, 0x8202 }, + { 0xB2EB, 0x8235 }, + { 0xB2EC, 0x8237 }, + { 0xB2ED, 0x8236 }, + { 0xB2EE, 0x8239 }, + { 0xB2EF, 0x838E }, + { 0xB2F0, 0x839E }, + { 0xB2F1, 0x8398 }, + { 0xB2F2, 0x8378 }, + { 0xB2F3, 0x83A2 }, + { 0xB2F4, 0x8396 }, + { 0xB2F5, 0x83BD }, + { 0xB2F6, 0x83AB }, + { 0xB2F7, 0x8392 }, + { 0xB2F8, 0x838A }, + { 0xB2F9, 0x8393 }, + { 0xB2FA, 0x8389 }, + { 0xB2FB, 0x83A0 }, + { 0xB2FC, 0x8377 }, + { 0xB2FD, 0x837B }, + { 0xB2FE, 0x837C }, + { 0xB340, 0x8386 }, + { 0xB341, 0x83A7 }, + { 0xB342, 0x8655 }, + { 0xB343, 0x5F6A }, + { 0xB344, 0x86C7 }, + { 0xB345, 0x86C0 }, + { 0xB346, 0x86B6 }, + { 0xB347, 0x86C4 }, + { 0xB348, 0x86B5 }, + { 0xB349, 0x86C6 }, + { 0xB34A, 0x86CB }, + { 0xB34B, 0x86B1 }, + { 0xB34C, 0x86AF }, + { 0xB34D, 0x86C9 }, + { 0xB34E, 0x8853 }, + { 0xB34F, 0x889E }, + { 0xB350, 0x8888 }, + { 0xB351, 0x88AB }, + { 0xB352, 0x8892 }, + { 0xB353, 0x8896 }, + { 0xB354, 0x888D }, + { 0xB355, 0x888B }, + { 0xB356, 0x8993 }, + { 0xB357, 0x898F }, + { 0xB358, 0x8A2A }, + { 0xB359, 0x8A1D }, + { 0xB35A, 0x8A23 }, + { 0xB35B, 0x8A25 }, + { 0xB35C, 0x8A31 }, + { 0xB35D, 0x8A2D }, + { 0xB35E, 0x8A1F }, + { 0xB35F, 0x8A1B }, + { 0xB360, 0x8A22 }, + { 0xB361, 0x8C49 }, + { 0xB362, 0x8C5A }, + { 0xB363, 0x8CA9 }, + { 0xB364, 0x8CAC }, + { 0xB365, 0x8CAB }, + { 0xB366, 0x8CA8 }, + { 0xB367, 0x8CAA }, + { 0xB368, 0x8CA7 }, + { 0xB369, 0x8D67 }, + { 0xB36A, 0x8D66 }, + { 0xB36B, 0x8DBE }, + { 0xB36C, 0x8DBA }, + { 0xB36D, 0x8EDB }, + { 0xB36E, 0x8EDF }, + { 0xB36F, 0x9019 }, + { 0xB370, 0x900D }, + { 0xB371, 0x901A }, + { 0xB372, 0x9017 }, + { 0xB373, 0x9023 }, + { 0xB374, 0x901F }, + { 0xB375, 0x901D }, + { 0xB376, 0x9010 }, + { 0xB377, 0x9015 }, + { 0xB378, 0x901E }, + { 0xB379, 0x9020 }, + { 0xB37A, 0x900F }, + { 0xB37B, 0x9022 }, + { 0xB37C, 0x9016 }, + { 0xB37D, 0x901B }, + { 0xB37E, 0x9014 }, + { 0xB3A1, 0x90E8 }, + { 0xB3A2, 0x90ED }, + { 0xB3A3, 0x90FD }, + { 0xB3A4, 0x9157 }, + { 0xB3A5, 0x91CE }, + { 0xB3A6, 0x91F5 }, + { 0xB3A7, 0x91E6 }, + { 0xB3A8, 0x91E3 }, + { 0xB3A9, 0x91E7 }, + { 0xB3AA, 0x91ED }, + { 0xB3AB, 0x91E9 }, + { 0xB3AC, 0x9589 }, + { 0xB3AD, 0x966A }, + { 0xB3AE, 0x9675 }, + { 0xB3AF, 0x9673 }, + { 0xB3B0, 0x9678 }, + { 0xB3B1, 0x9670 }, + { 0xB3B2, 0x9674 }, + { 0xB3B3, 0x9676 }, + { 0xB3B4, 0x9677 }, + { 0xB3B5, 0x966C }, + { 0xB3B6, 0x96C0 }, + { 0xB3B7, 0x96EA }, + { 0xB3B8, 0x96E9 }, + { 0xB3B9, 0x7AE0 }, + { 0xB3BA, 0x7ADF }, + { 0xB3BB, 0x9802 }, + { 0xB3BC, 0x9803 }, + { 0xB3BD, 0x9B5A }, + { 0xB3BE, 0x9CE5 }, + { 0xB3BF, 0x9E75 }, + { 0xB3C0, 0x9E7F }, + { 0xB3C1, 0x9EA5 }, + { 0xB3C2, 0x9EBB }, + { 0xB3C3, 0x50A2 }, + { 0xB3C4, 0x508D }, + { 0xB3C5, 0x5085 }, + { 0xB3C6, 0x5099 }, + { 0xB3C7, 0x5091 }, + { 0xB3C8, 0x5080 }, + { 0xB3C9, 0x5096 }, + { 0xB3CA, 0x5098 }, + { 0xB3CB, 0x509A }, + { 0xB3CC, 0x6700 }, + { 0xB3CD, 0x51F1 }, + { 0xB3CE, 0x5272 }, + { 0xB3CF, 0x5274 }, + { 0xB3D0, 0x5275 }, + { 0xB3D1, 0x5269 }, + { 0xB3D2, 0x52DE }, + { 0xB3D3, 0x52DD }, + { 0xB3D4, 0x52DB }, + { 0xB3D5, 0x535A }, + { 0xB3D6, 0x53A5 }, + { 0xB3D7, 0x557B }, + { 0xB3D8, 0x5580 }, + { 0xB3D9, 0x55A7 }, + { 0xB3DA, 0x557C }, + { 0xB3DB, 0x558A }, + { 0xB3DC, 0x559D }, + { 0xB3DD, 0x5598 }, + { 0xB3DE, 0x5582 }, + { 0xB3DF, 0x559C }, + { 0xB3E0, 0x55AA }, + { 0xB3E1, 0x5594 }, + { 0xB3E2, 0x5587 }, + { 0xB3E3, 0x558B }, + { 0xB3E4, 0x5583 }, + { 0xB3E5, 0x55B3 }, + { 0xB3E6, 0x55AE }, + { 0xB3E7, 0x559F }, + { 0xB3E8, 0x553E }, + { 0xB3E9, 0x55B2 }, + { 0xB3EA, 0x559A }, + { 0xB3EB, 0x55BB }, + { 0xB3EC, 0x55AC }, + { 0xB3ED, 0x55B1 }, + { 0xB3EE, 0x557E }, + { 0xB3EF, 0x5589 }, + { 0xB3F0, 0x55AB }, + { 0xB3F1, 0x5599 }, + { 0xB3F2, 0x570D }, + { 0xB3F3, 0x582F }, + { 0xB3F4, 0x582A }, + { 0xB3F5, 0x5834 }, + { 0xB3F6, 0x5824 }, + { 0xB3F7, 0x5830 }, + { 0xB3F8, 0x5831 }, + { 0xB3F9, 0x5821 }, + { 0xB3FA, 0x581D }, + { 0xB3FB, 0x5820 }, + { 0xB3FC, 0x58F9 }, + { 0xB3FD, 0x58FA }, + { 0xB3FE, 0x5960 }, + { 0xB440, 0x5A77 }, + { 0xB441, 0x5A9A }, + { 0xB442, 0x5A7F }, + { 0xB443, 0x5A92 }, + { 0xB444, 0x5A9B }, + { 0xB445, 0x5AA7 }, + { 0xB446, 0x5B73 }, + { 0xB447, 0x5B71 }, + { 0xB448, 0x5BD2 }, + { 0xB449, 0x5BCC }, + { 0xB44A, 0x5BD3 }, + { 0xB44B, 0x5BD0 }, + { 0xB44C, 0x5C0A }, + { 0xB44D, 0x5C0B }, + { 0xB44E, 0x5C31 }, + { 0xB44F, 0x5D4C }, + { 0xB450, 0x5D50 }, + { 0xB451, 0x5D34 }, + { 0xB452, 0x5D47 }, + { 0xB453, 0x5DFD }, + { 0xB454, 0x5E45 }, + { 0xB455, 0x5E3D }, + { 0xB456, 0x5E40 }, + { 0xB457, 0x5E43 }, + { 0xB458, 0x5E7E }, + { 0xB459, 0x5ECA }, + { 0xB45A, 0x5EC1 }, + { 0xB45B, 0x5EC2 }, + { 0xB45C, 0x5EC4 }, + { 0xB45D, 0x5F3C }, + { 0xB45E, 0x5F6D }, + { 0xB45F, 0x5FA9 }, + { 0xB460, 0x5FAA }, + { 0xB461, 0x5FA8 }, + { 0xB462, 0x60D1 }, + { 0xB463, 0x60E1 }, + { 0xB464, 0x60B2 }, + { 0xB465, 0x60B6 }, + { 0xB466, 0x60E0 }, + { 0xB467, 0x611C }, + { 0xB468, 0x6123 }, + { 0xB469, 0x60FA }, + { 0xB46A, 0x6115 }, + { 0xB46B, 0x60F0 }, + { 0xB46C, 0x60FB }, + { 0xB46D, 0x60F4 }, + { 0xB46E, 0x6168 }, + { 0xB46F, 0x60F1 }, + { 0xB470, 0x610E }, + { 0xB471, 0x60F6 }, + { 0xB472, 0x6109 }, + { 0xB473, 0x6100 }, + { 0xB474, 0x6112 }, + { 0xB475, 0x621F }, + { 0xB476, 0x6249 }, + { 0xB477, 0x63A3 }, + { 0xB478, 0x638C }, + { 0xB479, 0x63CF }, + { 0xB47A, 0x63C0 }, + { 0xB47B, 0x63E9 }, + { 0xB47C, 0x63C9 }, + { 0xB47D, 0x63C6 }, + { 0xB47E, 0x63CD }, + { 0xB4A1, 0x63D2 }, + { 0xB4A2, 0x63E3 }, + { 0xB4A3, 0x63D0 }, + { 0xB4A4, 0x63E1 }, + { 0xB4A5, 0x63D6 }, + { 0xB4A6, 0x63ED }, + { 0xB4A7, 0x63EE }, + { 0xB4A8, 0x6376 }, + { 0xB4A9, 0x63F4 }, + { 0xB4AA, 0x63EA }, + { 0xB4AB, 0x63DB }, + { 0xB4AC, 0x6452 }, + { 0xB4AD, 0x63DA }, + { 0xB4AE, 0x63F9 }, + { 0xB4AF, 0x655E }, + { 0xB4B0, 0x6566 }, + { 0xB4B1, 0x6562 }, + { 0xB4B2, 0x6563 }, + { 0xB4B3, 0x6591 }, + { 0xB4B4, 0x6590 }, + { 0xB4B5, 0x65AF }, + { 0xB4B6, 0x666E }, + { 0xB4B7, 0x6670 }, + { 0xB4B8, 0x6674 }, + { 0xB4B9, 0x6676 }, + { 0xB4BA, 0x666F }, + { 0xB4BB, 0x6691 }, + { 0xB4BC, 0x667A }, + { 0xB4BD, 0x667E }, + { 0xB4BE, 0x6677 }, + { 0xB4BF, 0x66FE }, + { 0xB4C0, 0x66FF }, + { 0xB4C1, 0x671F }, + { 0xB4C2, 0x671D }, + { 0xB4C3, 0x68FA }, + { 0xB4C4, 0x68D5 }, + { 0xB4C5, 0x68E0 }, + { 0xB4C6, 0x68D8 }, + { 0xB4C7, 0x68D7 }, + { 0xB4C8, 0x6905 }, + { 0xB4C9, 0x68DF }, + { 0xB4CA, 0x68F5 }, + { 0xB4CB, 0x68EE }, + { 0xB4CC, 0x68E7 }, + { 0xB4CD, 0x68F9 }, + { 0xB4CE, 0x68D2 }, + { 0xB4CF, 0x68F2 }, + { 0xB4D0, 0x68E3 }, + { 0xB4D1, 0x68CB }, + { 0xB4D2, 0x68CD }, + { 0xB4D3, 0x690D }, + { 0xB4D4, 0x6912 }, + { 0xB4D5, 0x690E }, + { 0xB4D6, 0x68C9 }, + { 0xB4D7, 0x68DA }, + { 0xB4D8, 0x696E }, + { 0xB4D9, 0x68FB }, + { 0xB4DA, 0x6B3E }, + { 0xB4DB, 0x6B3A }, + { 0xB4DC, 0x6B3D }, + { 0xB4DD, 0x6B98 }, + { 0xB4DE, 0x6B96 }, + { 0xB4DF, 0x6BBC }, + { 0xB4E0, 0x6BEF }, + { 0xB4E1, 0x6C2E }, + { 0xB4E2, 0x6C2F }, + { 0xB4E3, 0x6C2C }, + { 0xB4E4, 0x6E2F }, + { 0xB4E5, 0x6E38 }, + { 0xB4E6, 0x6E54 }, + { 0xB4E7, 0x6E21 }, + { 0xB4E8, 0x6E32 }, + { 0xB4E9, 0x6E67 }, + { 0xB4EA, 0x6E4A }, + { 0xB4EB, 0x6E20 }, + { 0xB4EC, 0x6E25 }, + { 0xB4ED, 0x6E23 }, + { 0xB4EE, 0x6E1B }, + { 0xB4EF, 0x6E5B }, + { 0xB4F0, 0x6E58 }, + { 0xB4F1, 0x6E24 }, + { 0xB4F2, 0x6E56 }, + { 0xB4F3, 0x6E6E }, + { 0xB4F4, 0x6E2D }, + { 0xB4F5, 0x6E26 }, + { 0xB4F6, 0x6E6F }, + { 0xB4F7, 0x6E34 }, + { 0xB4F8, 0x6E4D }, + { 0xB4F9, 0x6E3A }, + { 0xB4FA, 0x6E2C }, + { 0xB4FB, 0x6E43 }, + { 0xB4FC, 0x6E1D }, + { 0xB4FD, 0x6E3E }, + { 0xB4FE, 0x6ECB }, + { 0xB540, 0x6E89 }, + { 0xB541, 0x6E19 }, + { 0xB542, 0x6E4E }, + { 0xB543, 0x6E63 }, + { 0xB544, 0x6E44 }, + { 0xB545, 0x6E72 }, + { 0xB546, 0x6E69 }, + { 0xB547, 0x6E5F }, + { 0xB548, 0x7119 }, + { 0xB549, 0x711A }, + { 0xB54A, 0x7126 }, + { 0xB54B, 0x7130 }, + { 0xB54C, 0x7121 }, + { 0xB54D, 0x7136 }, + { 0xB54E, 0x716E }, + { 0xB54F, 0x711C }, + { 0xB550, 0x724C }, + { 0xB551, 0x7284 }, + { 0xB552, 0x7280 }, + { 0xB553, 0x7336 }, + { 0xB554, 0x7325 }, + { 0xB555, 0x7334 }, + { 0xB556, 0x7329 }, + { 0xB557, 0x743A }, + { 0xB558, 0x742A }, + { 0xB559, 0x7433 }, + { 0xB55A, 0x7422 }, + { 0xB55B, 0x7425 }, + { 0xB55C, 0x7435 }, + { 0xB55D, 0x7436 }, + { 0xB55E, 0x7434 }, + { 0xB55F, 0x742F }, + { 0xB560, 0x741B }, + { 0xB561, 0x7426 }, + { 0xB562, 0x7428 }, + { 0xB563, 0x7525 }, + { 0xB564, 0x7526 }, + { 0xB565, 0x756B }, + { 0xB566, 0x756A }, + { 0xB567, 0x75E2 }, + { 0xB568, 0x75DB }, + { 0xB569, 0x75E3 }, + { 0xB56A, 0x75D9 }, + { 0xB56B, 0x75D8 }, + { 0xB56C, 0x75DE }, + { 0xB56D, 0x75E0 }, + { 0xB56E, 0x767B }, + { 0xB56F, 0x767C }, + { 0xB570, 0x7696 }, + { 0xB571, 0x7693 }, + { 0xB572, 0x76B4 }, + { 0xB573, 0x76DC }, + { 0xB574, 0x774F }, + { 0xB575, 0x77ED }, + { 0xB576, 0x785D }, + { 0xB577, 0x786C }, + { 0xB578, 0x786F }, + { 0xB579, 0x7A0D }, + { 0xB57A, 0x7A08 }, + { 0xB57B, 0x7A0B }, + { 0xB57C, 0x7A05 }, + { 0xB57D, 0x7A00 }, + { 0xB57E, 0x7A98 }, + { 0xB5A1, 0x7A97 }, + { 0xB5A2, 0x7A96 }, + { 0xB5A3, 0x7AE5 }, + { 0xB5A4, 0x7AE3 }, + { 0xB5A5, 0x7B49 }, + { 0xB5A6, 0x7B56 }, + { 0xB5A7, 0x7B46 }, + { 0xB5A8, 0x7B50 }, + { 0xB5A9, 0x7B52 }, + { 0xB5AA, 0x7B54 }, + { 0xB5AB, 0x7B4D }, + { 0xB5AC, 0x7B4B }, + { 0xB5AD, 0x7B4F }, + { 0xB5AE, 0x7B51 }, + { 0xB5AF, 0x7C9F }, + { 0xB5B0, 0x7CA5 }, + { 0xB5B1, 0x7D5E }, + { 0xB5B2, 0x7D50 }, + { 0xB5B3, 0x7D68 }, + { 0xB5B4, 0x7D55 }, + { 0xB5B5, 0x7D2B }, + { 0xB5B6, 0x7D6E }, + { 0xB5B7, 0x7D72 }, + { 0xB5B8, 0x7D61 }, + { 0xB5B9, 0x7D66 }, + { 0xB5BA, 0x7D62 }, + { 0xB5BB, 0x7D70 }, + { 0xB5BC, 0x7D73 }, + { 0xB5BD, 0x5584 }, + { 0xB5BE, 0x7FD4 }, + { 0xB5BF, 0x7FD5 }, + { 0xB5C0, 0x800B }, + { 0xB5C1, 0x8052 }, + { 0xB5C2, 0x8085 }, + { 0xB5C3, 0x8155 }, + { 0xB5C4, 0x8154 }, + { 0xB5C5, 0x814B }, + { 0xB5C6, 0x8151 }, + { 0xB5C7, 0x814E }, + { 0xB5C8, 0x8139 }, + { 0xB5C9, 0x8146 }, + { 0xB5CA, 0x813E }, + { 0xB5CB, 0x814C }, + { 0xB5CC, 0x8153 }, + { 0xB5CD, 0x8174 }, + { 0xB5CE, 0x8212 }, + { 0xB5CF, 0x821C }, + { 0xB5D0, 0x83E9 }, + { 0xB5D1, 0x8403 }, + { 0xB5D2, 0x83F8 }, + { 0xB5D3, 0x840D }, + { 0xB5D4, 0x83E0 }, + { 0xB5D5, 0x83C5 }, + { 0xB5D6, 0x840B }, + { 0xB5D7, 0x83C1 }, + { 0xB5D8, 0x83EF }, + { 0xB5D9, 0x83F1 }, + { 0xB5DA, 0x83F4 }, + { 0xB5DB, 0x8457 }, + { 0xB5DC, 0x840A }, + { 0xB5DD, 0x83F0 }, + { 0xB5DE, 0x840C }, + { 0xB5DF, 0x83CC }, + { 0xB5E0, 0x83FD }, + { 0xB5E1, 0x83F2 }, + { 0xB5E2, 0x83CA }, + { 0xB5E3, 0x8438 }, + { 0xB5E4, 0x840E }, + { 0xB5E5, 0x8404 }, + { 0xB5E6, 0x83DC }, + { 0xB5E7, 0x8407 }, + { 0xB5E8, 0x83D4 }, + { 0xB5E9, 0x83DF }, + { 0xB5EA, 0x865B }, + { 0xB5EB, 0x86DF }, + { 0xB5EC, 0x86D9 }, + { 0xB5ED, 0x86ED }, + { 0xB5EE, 0x86D4 }, + { 0xB5EF, 0x86DB }, + { 0xB5F0, 0x86E4 }, + { 0xB5F1, 0x86D0 }, + { 0xB5F2, 0x86DE }, + { 0xB5F3, 0x8857 }, + { 0xB5F4, 0x88C1 }, + { 0xB5F5, 0x88C2 }, + { 0xB5F6, 0x88B1 }, + { 0xB5F7, 0x8983 }, + { 0xB5F8, 0x8996 }, + { 0xB5F9, 0x8A3B }, + { 0xB5FA, 0x8A60 }, + { 0xB5FB, 0x8A55 }, + { 0xB5FC, 0x8A5E }, + { 0xB5FD, 0x8A3C }, + { 0xB5FE, 0x8A41 }, + { 0xB640, 0x8A54 }, + { 0xB641, 0x8A5B }, + { 0xB642, 0x8A50 }, + { 0xB643, 0x8A46 }, + { 0xB644, 0x8A34 }, + { 0xB645, 0x8A3A }, + { 0xB646, 0x8A36 }, + { 0xB647, 0x8A56 }, + { 0xB648, 0x8C61 }, + { 0xB649, 0x8C82 }, + { 0xB64A, 0x8CAF }, + { 0xB64B, 0x8CBC }, + { 0xB64C, 0x8CB3 }, + { 0xB64D, 0x8CBD }, + { 0xB64E, 0x8CC1 }, + { 0xB64F, 0x8CBB }, + { 0xB650, 0x8CC0 }, + { 0xB651, 0x8CB4 }, + { 0xB652, 0x8CB7 }, + { 0xB653, 0x8CB6 }, + { 0xB654, 0x8CBF }, + { 0xB655, 0x8CB8 }, + { 0xB656, 0x8D8A }, + { 0xB657, 0x8D85 }, + { 0xB658, 0x8D81 }, + { 0xB659, 0x8DCE }, + { 0xB65A, 0x8DDD }, + { 0xB65B, 0x8DCB }, + { 0xB65C, 0x8DDA }, + { 0xB65D, 0x8DD1 }, + { 0xB65E, 0x8DCC }, + { 0xB65F, 0x8DDB }, + { 0xB660, 0x8DC6 }, + { 0xB661, 0x8EFB }, + { 0xB662, 0x8EF8 }, + { 0xB663, 0x8EFC }, + { 0xB664, 0x8F9C }, + { 0xB665, 0x902E }, + { 0xB666, 0x9035 }, + { 0xB667, 0x9031 }, + { 0xB668, 0x9038 }, + { 0xB669, 0x9032 }, + { 0xB66A, 0x9036 }, + { 0xB66B, 0x9102 }, + { 0xB66C, 0x90F5 }, + { 0xB66D, 0x9109 }, + { 0xB66E, 0x90FE }, + { 0xB66F, 0x9163 }, + { 0xB670, 0x9165 }, + { 0xB671, 0x91CF }, + { 0xB672, 0x9214 }, + { 0xB673, 0x9215 }, + { 0xB674, 0x9223 }, + { 0xB675, 0x9209 }, + { 0xB676, 0x921E }, + { 0xB677, 0x920D }, + { 0xB678, 0x9210 }, + { 0xB679, 0x9207 }, + { 0xB67A, 0x9211 }, + { 0xB67B, 0x9594 }, + { 0xB67C, 0x958F }, + { 0xB67D, 0x958B }, + { 0xB67E, 0x9591 }, + { 0xB6A1, 0x9593 }, + { 0xB6A2, 0x9592 }, + { 0xB6A3, 0x958E }, + { 0xB6A4, 0x968A }, + { 0xB6A5, 0x968E }, + { 0xB6A6, 0x968B }, + { 0xB6A7, 0x967D }, + { 0xB6A8, 0x9685 }, + { 0xB6A9, 0x9686 }, + { 0xB6AA, 0x968D }, + { 0xB6AB, 0x9672 }, + { 0xB6AC, 0x9684 }, + { 0xB6AD, 0x96C1 }, + { 0xB6AE, 0x96C5 }, + { 0xB6AF, 0x96C4 }, + { 0xB6B0, 0x96C6 }, + { 0xB6B1, 0x96C7 }, + { 0xB6B2, 0x96EF }, + { 0xB6B3, 0x96F2 }, + { 0xB6B4, 0x97CC }, + { 0xB6B5, 0x9805 }, + { 0xB6B6, 0x9806 }, + { 0xB6B7, 0x9808 }, + { 0xB6B8, 0x98E7 }, + { 0xB6B9, 0x98EA }, + { 0xB6BA, 0x98EF }, + { 0xB6BB, 0x98E9 }, + { 0xB6BC, 0x98F2 }, + { 0xB6BD, 0x98ED }, + { 0xB6BE, 0x99AE }, + { 0xB6BF, 0x99AD }, + { 0xB6C0, 0x9EC3 }, + { 0xB6C1, 0x9ECD }, + { 0xB6C2, 0x9ED1 }, + { 0xB6C3, 0x4E82 }, + { 0xB6C4, 0x50AD }, + { 0xB6C5, 0x50B5 }, + { 0xB6C6, 0x50B2 }, + { 0xB6C7, 0x50B3 }, + { 0xB6C8, 0x50C5 }, + { 0xB6C9, 0x50BE }, + { 0xB6CA, 0x50AC }, + { 0xB6CB, 0x50B7 }, + { 0xB6CC, 0x50BB }, + { 0xB6CD, 0x50AF }, + { 0xB6CE, 0x50C7 }, + { 0xB6CF, 0x527F }, + { 0xB6D0, 0x5277 }, + { 0xB6D1, 0x527D }, + { 0xB6D2, 0x52DF }, + { 0xB6D3, 0x52E6 }, + { 0xB6D4, 0x52E4 }, + { 0xB6D5, 0x52E2 }, + { 0xB6D6, 0x52E3 }, + { 0xB6D7, 0x532F }, + { 0xB6D8, 0x55DF }, + { 0xB6D9, 0x55E8 }, + { 0xB6DA, 0x55D3 }, + { 0xB6DB, 0x55E6 }, + { 0xB6DC, 0x55CE }, + { 0xB6DD, 0x55DC }, + { 0xB6DE, 0x55C7 }, + { 0xB6DF, 0x55D1 }, + { 0xB6E0, 0x55E3 }, + { 0xB6E1, 0x55E4 }, + { 0xB6E2, 0x55EF }, + { 0xB6E3, 0x55DA }, + { 0xB6E4, 0x55E1 }, + { 0xB6E5, 0x55C5 }, + { 0xB6E6, 0x55C6 }, + { 0xB6E7, 0x55E5 }, + { 0xB6E8, 0x55C9 }, + { 0xB6E9, 0x5712 }, + { 0xB6EA, 0x5713 }, + { 0xB6EB, 0x585E }, + { 0xB6EC, 0x5851 }, + { 0xB6ED, 0x5858 }, + { 0xB6EE, 0x5857 }, + { 0xB6EF, 0x585A }, + { 0xB6F0, 0x5854 }, + { 0xB6F1, 0x586B }, + { 0xB6F2, 0x584C }, + { 0xB6F3, 0x586D }, + { 0xB6F4, 0x584A }, + { 0xB6F5, 0x5862 }, + { 0xB6F6, 0x5852 }, + { 0xB6F7, 0x584B }, + { 0xB6F8, 0x5967 }, + { 0xB6F9, 0x5AC1 }, + { 0xB6FA, 0x5AC9 }, + { 0xB6FB, 0x5ACC }, + { 0xB6FC, 0x5ABE }, + { 0xB6FD, 0x5ABD }, + { 0xB6FE, 0x5ABC }, + { 0xB740, 0x5AB3 }, + { 0xB741, 0x5AC2 }, + { 0xB742, 0x5AB2 }, + { 0xB743, 0x5D69 }, + { 0xB744, 0x5D6F }, + { 0xB745, 0x5E4C }, + { 0xB746, 0x5E79 }, + { 0xB747, 0x5EC9 }, + { 0xB748, 0x5EC8 }, + { 0xB749, 0x5F12 }, + { 0xB74A, 0x5F59 }, + { 0xB74B, 0x5FAC }, + { 0xB74C, 0x5FAE }, + { 0xB74D, 0x611A }, + { 0xB74E, 0x610F }, + { 0xB74F, 0x6148 }, + { 0xB750, 0x611F }, + { 0xB751, 0x60F3 }, + { 0xB752, 0x611B }, + { 0xB753, 0x60F9 }, + { 0xB754, 0x6101 }, + { 0xB755, 0x6108 }, + { 0xB756, 0x614E }, + { 0xB757, 0x614C }, + { 0xB758, 0x6144 }, + { 0xB759, 0x614D }, + { 0xB75A, 0x613E }, + { 0xB75B, 0x6134 }, + { 0xB75C, 0x6127 }, + { 0xB75D, 0x610D }, + { 0xB75E, 0x6106 }, + { 0xB75F, 0x6137 }, + { 0xB760, 0x6221 }, + { 0xB761, 0x6222 }, + { 0xB762, 0x6413 }, + { 0xB763, 0x643E }, + { 0xB764, 0x641E }, + { 0xB765, 0x642A }, + { 0xB766, 0x642D }, + { 0xB767, 0x643D }, + { 0xB768, 0x642C }, + { 0xB769, 0x640F }, + { 0xB76A, 0x641C }, + { 0xB76B, 0x6414 }, + { 0xB76C, 0x640D }, + { 0xB76D, 0x6436 }, + { 0xB76E, 0x6416 }, + { 0xB76F, 0x6417 }, + { 0xB770, 0x6406 }, + { 0xB771, 0x656C }, + { 0xB772, 0x659F }, + { 0xB773, 0x65B0 }, + { 0xB774, 0x6697 }, + { 0xB775, 0x6689 }, + { 0xB776, 0x6687 }, + { 0xB777, 0x6688 }, + { 0xB778, 0x6696 }, + { 0xB779, 0x6684 }, + { 0xB77A, 0x6698 }, + { 0xB77B, 0x668D }, + { 0xB77C, 0x6703 }, + { 0xB77D, 0x6994 }, + { 0xB77E, 0x696D }, + { 0xB7A1, 0x695A }, + { 0xB7A2, 0x6977 }, + { 0xB7A3, 0x6960 }, + { 0xB7A4, 0x6954 }, + { 0xB7A5, 0x6975 }, + { 0xB7A6, 0x6930 }, + { 0xB7A7, 0x6982 }, + { 0xB7A8, 0x694A }, + { 0xB7A9, 0x6968 }, + { 0xB7AA, 0x696B }, + { 0xB7AB, 0x695E }, + { 0xB7AC, 0x6953 }, + { 0xB7AD, 0x6979 }, + { 0xB7AE, 0x6986 }, + { 0xB7AF, 0x695D }, + { 0xB7B0, 0x6963 }, + { 0xB7B1, 0x695B }, + { 0xB7B2, 0x6B47 }, + { 0xB7B3, 0x6B72 }, + { 0xB7B4, 0x6BC0 }, + { 0xB7B5, 0x6BBF }, + { 0xB7B6, 0x6BD3 }, + { 0xB7B7, 0x6BFD }, + { 0xB7B8, 0x6EA2 }, + { 0xB7B9, 0x6EAF }, + { 0xB7BA, 0x6ED3 }, + { 0xB7BB, 0x6EB6 }, + { 0xB7BC, 0x6EC2 }, + { 0xB7BD, 0x6E90 }, + { 0xB7BE, 0x6E9D }, + { 0xB7BF, 0x6EC7 }, + { 0xB7C0, 0x6EC5 }, + { 0xB7C1, 0x6EA5 }, + { 0xB7C2, 0x6E98 }, + { 0xB7C3, 0x6EBC }, + { 0xB7C4, 0x6EBA }, + { 0xB7C5, 0x6EAB }, + { 0xB7C6, 0x6ED1 }, + { 0xB7C7, 0x6E96 }, + { 0xB7C8, 0x6E9C }, + { 0xB7C9, 0x6EC4 }, + { 0xB7CA, 0x6ED4 }, + { 0xB7CB, 0x6EAA }, + { 0xB7CC, 0x6EA7 }, + { 0xB7CD, 0x6EB4 }, + { 0xB7CE, 0x714E }, + { 0xB7CF, 0x7159 }, + { 0xB7D0, 0x7169 }, + { 0xB7D1, 0x7164 }, + { 0xB7D2, 0x7149 }, + { 0xB7D3, 0x7167 }, + { 0xB7D4, 0x715C }, + { 0xB7D5, 0x716C }, + { 0xB7D6, 0x7166 }, + { 0xB7D7, 0x714C }, + { 0xB7D8, 0x7165 }, + { 0xB7D9, 0x715E }, + { 0xB7DA, 0x7146 }, + { 0xB7DB, 0x7168 }, + { 0xB7DC, 0x7156 }, + { 0xB7DD, 0x723A }, + { 0xB7DE, 0x7252 }, + { 0xB7DF, 0x7337 }, + { 0xB7E0, 0x7345 }, + { 0xB7E1, 0x733F }, + { 0xB7E2, 0x733E }, + { 0xB7E3, 0x746F }, + { 0xB7E4, 0x745A }, + { 0xB7E5, 0x7455 }, + { 0xB7E6, 0x745F }, + { 0xB7E7, 0x745E }, + { 0xB7E8, 0x7441 }, + { 0xB7E9, 0x743F }, + { 0xB7EA, 0x7459 }, + { 0xB7EB, 0x745B }, + { 0xB7EC, 0x745C }, + { 0xB7ED, 0x7576 }, + { 0xB7EE, 0x7578 }, + { 0xB7EF, 0x7600 }, + { 0xB7F0, 0x75F0 }, + { 0xB7F1, 0x7601 }, + { 0xB7F2, 0x75F2 }, + { 0xB7F3, 0x75F1 }, + { 0xB7F4, 0x75FA }, + { 0xB7F5, 0x75FF }, + { 0xB7F6, 0x75F4 }, + { 0xB7F7, 0x75F3 }, + { 0xB7F8, 0x76DE }, + { 0xB7F9, 0x76DF }, + { 0xB7FA, 0x775B }, + { 0xB7FB, 0x776B }, + { 0xB7FC, 0x7766 }, + { 0xB7FD, 0x775E }, + { 0xB7FE, 0x7763 }, + { 0xB840, 0x7779 }, + { 0xB841, 0x776A }, + { 0xB842, 0x776C }, + { 0xB843, 0x775C }, + { 0xB844, 0x7765 }, + { 0xB845, 0x7768 }, + { 0xB846, 0x7762 }, + { 0xB847, 0x77EE }, + { 0xB848, 0x788E }, + { 0xB849, 0x78B0 }, + { 0xB84A, 0x7897 }, + { 0xB84B, 0x7898 }, + { 0xB84C, 0x788C }, + { 0xB84D, 0x7889 }, + { 0xB84E, 0x787C }, + { 0xB84F, 0x7891 }, + { 0xB850, 0x7893 }, + { 0xB851, 0x787F }, + { 0xB852, 0x797A }, + { 0xB853, 0x797F }, + { 0xB854, 0x7981 }, + { 0xB855, 0x842C }, + { 0xB856, 0x79BD }, + { 0xB857, 0x7A1C }, + { 0xB858, 0x7A1A }, + { 0xB859, 0x7A20 }, + { 0xB85A, 0x7A14 }, + { 0xB85B, 0x7A1F }, + { 0xB85C, 0x7A1E }, + { 0xB85D, 0x7A9F }, + { 0xB85E, 0x7AA0 }, + { 0xB85F, 0x7B77 }, + { 0xB860, 0x7BC0 }, + { 0xB861, 0x7B60 }, + { 0xB862, 0x7B6E }, + { 0xB863, 0x7B67 }, + { 0xB864, 0x7CB1 }, + { 0xB865, 0x7CB3 }, + { 0xB866, 0x7CB5 }, + { 0xB867, 0x7D93 }, + { 0xB868, 0x7D79 }, + { 0xB869, 0x7D91 }, + { 0xB86A, 0x7D81 }, + { 0xB86B, 0x7D8F }, + { 0xB86C, 0x7D5B }, + { 0xB86D, 0x7F6E }, + { 0xB86E, 0x7F69 }, + { 0xB86F, 0x7F6A }, + { 0xB870, 0x7F72 }, + { 0xB871, 0x7FA9 }, + { 0xB872, 0x7FA8 }, + { 0xB873, 0x7FA4 }, + { 0xB874, 0x8056 }, + { 0xB875, 0x8058 }, + { 0xB876, 0x8086 }, + { 0xB877, 0x8084 }, + { 0xB878, 0x8171 }, + { 0xB879, 0x8170 }, + { 0xB87A, 0x8178 }, + { 0xB87B, 0x8165 }, + { 0xB87C, 0x816E }, + { 0xB87D, 0x8173 }, + { 0xB87E, 0x816B }, + { 0xB8A1, 0x8179 }, + { 0xB8A2, 0x817A }, + { 0xB8A3, 0x8166 }, + { 0xB8A4, 0x8205 }, + { 0xB8A5, 0x8247 }, + { 0xB8A6, 0x8482 }, + { 0xB8A7, 0x8477 }, + { 0xB8A8, 0x843D }, + { 0xB8A9, 0x8431 }, + { 0xB8AA, 0x8475 }, + { 0xB8AB, 0x8466 }, + { 0xB8AC, 0x846B }, + { 0xB8AD, 0x8449 }, + { 0xB8AE, 0x846C }, + { 0xB8AF, 0x845B }, + { 0xB8B0, 0x843C }, + { 0xB8B1, 0x8435 }, + { 0xB8B2, 0x8461 }, + { 0xB8B3, 0x8463 }, + { 0xB8B4, 0x8469 }, + { 0xB8B5, 0x846D }, + { 0xB8B6, 0x8446 }, + { 0xB8B7, 0x865E }, + { 0xB8B8, 0x865C }, + { 0xB8B9, 0x865F }, + { 0xB8BA, 0x86F9 }, + { 0xB8BB, 0x8713 }, + { 0xB8BC, 0x8708 }, + { 0xB8BD, 0x8707 }, + { 0xB8BE, 0x8700 }, + { 0xB8BF, 0x86FE }, + { 0xB8C0, 0x86FB }, + { 0xB8C1, 0x8702 }, + { 0xB8C2, 0x8703 }, + { 0xB8C3, 0x8706 }, + { 0xB8C4, 0x870A }, + { 0xB8C5, 0x8859 }, + { 0xB8C6, 0x88DF }, + { 0xB8C7, 0x88D4 }, + { 0xB8C8, 0x88D9 }, + { 0xB8C9, 0x88DC }, + { 0xB8CA, 0x88D8 }, + { 0xB8CB, 0x88DD }, + { 0xB8CC, 0x88E1 }, + { 0xB8CD, 0x88CA }, + { 0xB8CE, 0x88D5 }, + { 0xB8CF, 0x88D2 }, + { 0xB8D0, 0x899C }, + { 0xB8D1, 0x89E3 }, + { 0xB8D2, 0x8A6B }, + { 0xB8D3, 0x8A72 }, + { 0xB8D4, 0x8A73 }, + { 0xB8D5, 0x8A66 }, + { 0xB8D6, 0x8A69 }, + { 0xB8D7, 0x8A70 }, + { 0xB8D8, 0x8A87 }, + { 0xB8D9, 0x8A7C }, + { 0xB8DA, 0x8A63 }, + { 0xB8DB, 0x8AA0 }, + { 0xB8DC, 0x8A71 }, + { 0xB8DD, 0x8A85 }, + { 0xB8DE, 0x8A6D }, + { 0xB8DF, 0x8A62 }, + { 0xB8E0, 0x8A6E }, + { 0xB8E1, 0x8A6C }, + { 0xB8E2, 0x8A79 }, + { 0xB8E3, 0x8A7B }, + { 0xB8E4, 0x8A3E }, + { 0xB8E5, 0x8A68 }, + { 0xB8E6, 0x8C62 }, + { 0xB8E7, 0x8C8A }, + { 0xB8E8, 0x8C89 }, + { 0xB8E9, 0x8CCA }, + { 0xB8EA, 0x8CC7 }, + { 0xB8EB, 0x8CC8 }, + { 0xB8EC, 0x8CC4 }, + { 0xB8ED, 0x8CB2 }, + { 0xB8EE, 0x8CC3 }, + { 0xB8EF, 0x8CC2 }, + { 0xB8F0, 0x8CC5 }, + { 0xB8F1, 0x8DE1 }, + { 0xB8F2, 0x8DDF }, + { 0xB8F3, 0x8DE8 }, + { 0xB8F4, 0x8DEF }, + { 0xB8F5, 0x8DF3 }, + { 0xB8F6, 0x8DFA }, + { 0xB8F7, 0x8DEA }, + { 0xB8F8, 0x8DE4 }, + { 0xB8F9, 0x8DE6 }, + { 0xB8FA, 0x8EB2 }, + { 0xB8FB, 0x8F03 }, + { 0xB8FC, 0x8F09 }, + { 0xB8FD, 0x8EFE }, + { 0xB8FE, 0x8F0A }, + { 0xB940, 0x8F9F }, + { 0xB941, 0x8FB2 }, + { 0xB942, 0x904B }, + { 0xB943, 0x904A }, + { 0xB944, 0x9053 }, + { 0xB945, 0x9042 }, + { 0xB946, 0x9054 }, + { 0xB947, 0x903C }, + { 0xB948, 0x9055 }, + { 0xB949, 0x9050 }, + { 0xB94A, 0x9047 }, + { 0xB94B, 0x904F }, + { 0xB94C, 0x904E }, + { 0xB94D, 0x904D }, + { 0xB94E, 0x9051 }, + { 0xB94F, 0x903E }, + { 0xB950, 0x9041 }, + { 0xB951, 0x9112 }, + { 0xB952, 0x9117 }, + { 0xB953, 0x916C }, + { 0xB954, 0x916A }, + { 0xB955, 0x9169 }, + { 0xB956, 0x91C9 }, + { 0xB957, 0x9237 }, + { 0xB958, 0x9257 }, + { 0xB959, 0x9238 }, + { 0xB95A, 0x923D }, + { 0xB95B, 0x9240 }, + { 0xB95C, 0x923E }, + { 0xB95D, 0x925B }, + { 0xB95E, 0x924B }, + { 0xB95F, 0x9264 }, + { 0xB960, 0x9251 }, + { 0xB961, 0x9234 }, + { 0xB962, 0x9249 }, + { 0xB963, 0x924D }, + { 0xB964, 0x9245 }, + { 0xB965, 0x9239 }, + { 0xB966, 0x923F }, + { 0xB967, 0x925A }, + { 0xB968, 0x9598 }, + { 0xB969, 0x9698 }, + { 0xB96A, 0x9694 }, + { 0xB96B, 0x9695 }, + { 0xB96C, 0x96CD }, + { 0xB96D, 0x96CB }, + { 0xB96E, 0x96C9 }, + { 0xB96F, 0x96CA }, + { 0xB970, 0x96F7 }, + { 0xB971, 0x96FB }, + { 0xB972, 0x96F9 }, + { 0xB973, 0x96F6 }, + { 0xB974, 0x9756 }, + { 0xB975, 0x9774 }, + { 0xB976, 0x9776 }, + { 0xB977, 0x9810 }, + { 0xB978, 0x9811 }, + { 0xB979, 0x9813 }, + { 0xB97A, 0x980A }, + { 0xB97B, 0x9812 }, + { 0xB97C, 0x980C }, + { 0xB97D, 0x98FC }, + { 0xB97E, 0x98F4 }, + { 0xB9A1, 0x98FD }, + { 0xB9A2, 0x98FE }, + { 0xB9A3, 0x99B3 }, + { 0xB9A4, 0x99B1 }, + { 0xB9A5, 0x99B4 }, + { 0xB9A6, 0x9AE1 }, + { 0xB9A7, 0x9CE9 }, + { 0xB9A8, 0x9E82 }, + { 0xB9A9, 0x9F0E }, + { 0xB9AA, 0x9F13 }, + { 0xB9AB, 0x9F20 }, + { 0xB9AC, 0x50E7 }, + { 0xB9AD, 0x50EE }, + { 0xB9AE, 0x50E5 }, + { 0xB9AF, 0x50D6 }, + { 0xB9B0, 0x50ED }, + { 0xB9B1, 0x50DA }, + { 0xB9B2, 0x50D5 }, + { 0xB9B3, 0x50CF }, + { 0xB9B4, 0x50D1 }, + { 0xB9B5, 0x50F1 }, + { 0xB9B6, 0x50CE }, + { 0xB9B7, 0x50E9 }, + { 0xB9B8, 0x5162 }, + { 0xB9B9, 0x51F3 }, + { 0xB9BA, 0x5283 }, + { 0xB9BB, 0x5282 }, + { 0xB9BC, 0x5331 }, + { 0xB9BD, 0x53AD }, + { 0xB9BE, 0x55FE }, + { 0xB9BF, 0x5600 }, + { 0xB9C0, 0x561B }, + { 0xB9C1, 0x5617 }, + { 0xB9C2, 0x55FD }, + { 0xB9C3, 0x5614 }, + { 0xB9C4, 0x5606 }, + { 0xB9C5, 0x5609 }, + { 0xB9C6, 0x560D }, + { 0xB9C7, 0x560E }, + { 0xB9C8, 0x55F7 }, + { 0xB9C9, 0x5616 }, + { 0xB9CA, 0x561F }, + { 0xB9CB, 0x5608 }, + { 0xB9CC, 0x5610 }, + { 0xB9CD, 0x55F6 }, + { 0xB9CE, 0x5718 }, + { 0xB9CF, 0x5716 }, + { 0xB9D0, 0x5875 }, + { 0xB9D1, 0x587E }, + { 0xB9D2, 0x5883 }, + { 0xB9D3, 0x5893 }, + { 0xB9D4, 0x588A }, + { 0xB9D5, 0x5879 }, + { 0xB9D6, 0x5885 }, + { 0xB9D7, 0x587D }, + { 0xB9D8, 0x58FD }, + { 0xB9D9, 0x5925 }, + { 0xB9DA, 0x5922 }, + { 0xB9DB, 0x5924 }, + { 0xB9DC, 0x596A }, + { 0xB9DD, 0x5969 }, + { 0xB9DE, 0x5AE1 }, + { 0xB9DF, 0x5AE6 }, + { 0xB9E0, 0x5AE9 }, + { 0xB9E1, 0x5AD7 }, + { 0xB9E2, 0x5AD6 }, + { 0xB9E3, 0x5AD8 }, + { 0xB9E4, 0x5AE3 }, + { 0xB9E5, 0x5B75 }, + { 0xB9E6, 0x5BDE }, + { 0xB9E7, 0x5BE7 }, + { 0xB9E8, 0x5BE1 }, + { 0xB9E9, 0x5BE5 }, + { 0xB9EA, 0x5BE6 }, + { 0xB9EB, 0x5BE8 }, + { 0xB9EC, 0x5BE2 }, + { 0xB9ED, 0x5BE4 }, + { 0xB9EE, 0x5BDF }, + { 0xB9EF, 0x5C0D }, + { 0xB9F0, 0x5C62 }, + { 0xB9F1, 0x5D84 }, + { 0xB9F2, 0x5D87 }, + { 0xB9F3, 0x5E5B }, + { 0xB9F4, 0x5E63 }, + { 0xB9F5, 0x5E55 }, + { 0xB9F6, 0x5E57 }, + { 0xB9F7, 0x5E54 }, + { 0xB9F8, 0x5ED3 }, + { 0xB9F9, 0x5ED6 }, + { 0xB9FA, 0x5F0A }, + { 0xB9FB, 0x5F46 }, + { 0xB9FC, 0x5F70 }, + { 0xB9FD, 0x5FB9 }, + { 0xB9FE, 0x6147 }, + { 0xBA40, 0x613F }, + { 0xBA41, 0x614B }, + { 0xBA42, 0x6177 }, + { 0xBA43, 0x6162 }, + { 0xBA44, 0x6163 }, + { 0xBA45, 0x615F }, + { 0xBA46, 0x615A }, + { 0xBA47, 0x6158 }, + { 0xBA48, 0x6175 }, + { 0xBA49, 0x622A }, + { 0xBA4A, 0x6487 }, + { 0xBA4B, 0x6458 }, + { 0xBA4C, 0x6454 }, + { 0xBA4D, 0x64A4 }, + { 0xBA4E, 0x6478 }, + { 0xBA4F, 0x645F }, + { 0xBA50, 0x647A }, + { 0xBA51, 0x6451 }, + { 0xBA52, 0x6467 }, + { 0xBA53, 0x6434 }, + { 0xBA54, 0x646D }, + { 0xBA55, 0x647B }, + { 0xBA56, 0x6572 }, + { 0xBA57, 0x65A1 }, + { 0xBA58, 0x65D7 }, + { 0xBA59, 0x65D6 }, + { 0xBA5A, 0x66A2 }, + { 0xBA5B, 0x66A8 }, + { 0xBA5C, 0x669D }, + { 0xBA5D, 0x699C }, + { 0xBA5E, 0x69A8 }, + { 0xBA5F, 0x6995 }, + { 0xBA60, 0x69C1 }, + { 0xBA61, 0x69AE }, + { 0xBA62, 0x69D3 }, + { 0xBA63, 0x69CB }, + { 0xBA64, 0x699B }, + { 0xBA65, 0x69B7 }, + { 0xBA66, 0x69BB }, + { 0xBA67, 0x69AB }, + { 0xBA68, 0x69B4 }, + { 0xBA69, 0x69D0 }, + { 0xBA6A, 0x69CD }, + { 0xBA6B, 0x69AD }, + { 0xBA6C, 0x69CC }, + { 0xBA6D, 0x69A6 }, + { 0xBA6E, 0x69C3 }, + { 0xBA6F, 0x69A3 }, + { 0xBA70, 0x6B49 }, + { 0xBA71, 0x6B4C }, + { 0xBA72, 0x6C33 }, + { 0xBA73, 0x6F33 }, + { 0xBA74, 0x6F14 }, + { 0xBA75, 0x6EFE }, + { 0xBA76, 0x6F13 }, + { 0xBA77, 0x6EF4 }, + { 0xBA78, 0x6F29 }, + { 0xBA79, 0x6F3E }, + { 0xBA7A, 0x6F20 }, + { 0xBA7B, 0x6F2C }, + { 0xBA7C, 0x6F0F }, + { 0xBA7D, 0x6F02 }, + { 0xBA7E, 0x6F22 }, + { 0xBAA1, 0x6EFF }, + { 0xBAA2, 0x6EEF }, + { 0xBAA3, 0x6F06 }, + { 0xBAA4, 0x6F31 }, + { 0xBAA5, 0x6F38 }, + { 0xBAA6, 0x6F32 }, + { 0xBAA7, 0x6F23 }, + { 0xBAA8, 0x6F15 }, + { 0xBAA9, 0x6F2B }, + { 0xBAAA, 0x6F2F }, + { 0xBAAB, 0x6F88 }, + { 0xBAAC, 0x6F2A }, + { 0xBAAD, 0x6EEC }, + { 0xBAAE, 0x6F01 }, + { 0xBAAF, 0x6EF2 }, + { 0xBAB0, 0x6ECC }, + { 0xBAB1, 0x6EF7 }, + { 0xBAB2, 0x7194 }, + { 0xBAB3, 0x7199 }, + { 0xBAB4, 0x717D }, + { 0xBAB5, 0x718A }, + { 0xBAB6, 0x7184 }, + { 0xBAB7, 0x7192 }, + { 0xBAB8, 0x723E }, + { 0xBAB9, 0x7292 }, + { 0xBABA, 0x7296 }, + { 0xBABB, 0x7344 }, + { 0xBABC, 0x7350 }, + { 0xBABD, 0x7464 }, + { 0xBABE, 0x7463 }, + { 0xBABF, 0x746A }, + { 0xBAC0, 0x7470 }, + { 0xBAC1, 0x746D }, + { 0xBAC2, 0x7504 }, + { 0xBAC3, 0x7591 }, + { 0xBAC4, 0x7627 }, + { 0xBAC5, 0x760D }, + { 0xBAC6, 0x760B }, + { 0xBAC7, 0x7609 }, + { 0xBAC8, 0x7613 }, + { 0xBAC9, 0x76E1 }, + { 0xBACA, 0x76E3 }, + { 0xBACB, 0x7784 }, + { 0xBACC, 0x777D }, + { 0xBACD, 0x777F }, + { 0xBACE, 0x7761 }, + { 0xBACF, 0x78C1 }, + { 0xBAD0, 0x789F }, + { 0xBAD1, 0x78A7 }, + { 0xBAD2, 0x78B3 }, + { 0xBAD3, 0x78A9 }, + { 0xBAD4, 0x78A3 }, + { 0xBAD5, 0x798E }, + { 0xBAD6, 0x798F }, + { 0xBAD7, 0x798D }, + { 0xBAD8, 0x7A2E }, + { 0xBAD9, 0x7A31 }, + { 0xBADA, 0x7AAA }, + { 0xBADB, 0x7AA9 }, + { 0xBADC, 0x7AED }, + { 0xBADD, 0x7AEF }, + { 0xBADE, 0x7BA1 }, + { 0xBADF, 0x7B95 }, + { 0xBAE0, 0x7B8B }, + { 0xBAE1, 0x7B75 }, + { 0xBAE2, 0x7B97 }, + { 0xBAE3, 0x7B9D }, + { 0xBAE4, 0x7B94 }, + { 0xBAE5, 0x7B8F }, + { 0xBAE6, 0x7BB8 }, + { 0xBAE7, 0x7B87 }, + { 0xBAE8, 0x7B84 }, + { 0xBAE9, 0x7CB9 }, + { 0xBAEA, 0x7CBD }, + { 0xBAEB, 0x7CBE }, + { 0xBAEC, 0x7DBB }, + { 0xBAED, 0x7DB0 }, + { 0xBAEE, 0x7D9C }, + { 0xBAEF, 0x7DBD }, + { 0xBAF0, 0x7DBE }, + { 0xBAF1, 0x7DA0 }, + { 0xBAF2, 0x7DCA }, + { 0xBAF3, 0x7DB4 }, + { 0xBAF4, 0x7DB2 }, + { 0xBAF5, 0x7DB1 }, + { 0xBAF6, 0x7DBA }, + { 0xBAF7, 0x7DA2 }, + { 0xBAF8, 0x7DBF }, + { 0xBAF9, 0x7DB5 }, + { 0xBAFA, 0x7DB8 }, + { 0xBAFB, 0x7DAD }, + { 0xBAFC, 0x7DD2 }, + { 0xBAFD, 0x7DC7 }, + { 0xBAFE, 0x7DAC }, + { 0xBB40, 0x7F70 }, + { 0xBB41, 0x7FE0 }, + { 0xBB42, 0x7FE1 }, + { 0xBB43, 0x7FDF }, + { 0xBB44, 0x805E }, + { 0xBB45, 0x805A }, + { 0xBB46, 0x8087 }, + { 0xBB47, 0x8150 }, + { 0xBB48, 0x8180 }, + { 0xBB49, 0x818F }, + { 0xBB4A, 0x8188 }, + { 0xBB4B, 0x818A }, + { 0xBB4C, 0x817F }, + { 0xBB4D, 0x8182 }, + { 0xBB4E, 0x81E7 }, + { 0xBB4F, 0x81FA }, + { 0xBB50, 0x8207 }, + { 0xBB51, 0x8214 }, + { 0xBB52, 0x821E }, + { 0xBB53, 0x824B }, + { 0xBB54, 0x84C9 }, + { 0xBB55, 0x84BF }, + { 0xBB56, 0x84C6 }, + { 0xBB57, 0x84C4 }, + { 0xBB58, 0x8499 }, + { 0xBB59, 0x849E }, + { 0xBB5A, 0x84B2 }, + { 0xBB5B, 0x849C }, + { 0xBB5C, 0x84CB }, + { 0xBB5D, 0x84B8 }, + { 0xBB5E, 0x84C0 }, + { 0xBB5F, 0x84D3 }, + { 0xBB60, 0x8490 }, + { 0xBB61, 0x84BC }, + { 0xBB62, 0x84D1 }, + { 0xBB63, 0x84CA }, + { 0xBB64, 0x873F }, + { 0xBB65, 0x871C }, + { 0xBB66, 0x873B }, + { 0xBB67, 0x8722 }, + { 0xBB68, 0x8725 }, + { 0xBB69, 0x8734 }, + { 0xBB6A, 0x8718 }, + { 0xBB6B, 0x8755 }, + { 0xBB6C, 0x8737 }, + { 0xBB6D, 0x8729 }, + { 0xBB6E, 0x88F3 }, + { 0xBB6F, 0x8902 }, + { 0xBB70, 0x88F4 }, + { 0xBB71, 0x88F9 }, + { 0xBB72, 0x88F8 }, + { 0xBB73, 0x88FD }, + { 0xBB74, 0x88E8 }, + { 0xBB75, 0x891A }, + { 0xBB76, 0x88EF }, + { 0xBB77, 0x8AA6 }, + { 0xBB78, 0x8A8C }, + { 0xBB79, 0x8A9E }, + { 0xBB7A, 0x8AA3 }, + { 0xBB7B, 0x8A8D }, + { 0xBB7C, 0x8AA1 }, + { 0xBB7D, 0x8A93 }, + { 0xBB7E, 0x8AA4 }, + { 0xBBA1, 0x8AAA }, + { 0xBBA2, 0x8AA5 }, + { 0xBBA3, 0x8AA8 }, + { 0xBBA4, 0x8A98 }, + { 0xBBA5, 0x8A91 }, + { 0xBBA6, 0x8A9A }, + { 0xBBA7, 0x8AA7 }, + { 0xBBA8, 0x8C6A }, + { 0xBBA9, 0x8C8D }, + { 0xBBAA, 0x8C8C }, + { 0xBBAB, 0x8CD3 }, + { 0xBBAC, 0x8CD1 }, + { 0xBBAD, 0x8CD2 }, + { 0xBBAE, 0x8D6B }, + { 0xBBAF, 0x8D99 }, + { 0xBBB0, 0x8D95 }, + { 0xBBB1, 0x8DFC }, + { 0xBBB2, 0x8F14 }, + { 0xBBB3, 0x8F12 }, + { 0xBBB4, 0x8F15 }, + { 0xBBB5, 0x8F13 }, + { 0xBBB6, 0x8FA3 }, + { 0xBBB7, 0x9060 }, + { 0xBBB8, 0x9058 }, + { 0xBBB9, 0x905C }, + { 0xBBBA, 0x9063 }, + { 0xBBBB, 0x9059 }, + { 0xBBBC, 0x905E }, + { 0xBBBD, 0x9062 }, + { 0xBBBE, 0x905D }, + { 0xBBBF, 0x905B }, + { 0xBBC0, 0x9119 }, + { 0xBBC1, 0x9118 }, + { 0xBBC2, 0x911E }, + { 0xBBC3, 0x9175 }, + { 0xBBC4, 0x9178 }, + { 0xBBC5, 0x9177 }, + { 0xBBC6, 0x9174 }, + { 0xBBC7, 0x9278 }, + { 0xBBC8, 0x9280 }, + { 0xBBC9, 0x9285 }, + { 0xBBCA, 0x9298 }, + { 0xBBCB, 0x9296 }, + { 0xBBCC, 0x927B }, + { 0xBBCD, 0x9293 }, + { 0xBBCE, 0x929C }, + { 0xBBCF, 0x92A8 }, + { 0xBBD0, 0x927C }, + { 0xBBD1, 0x9291 }, + { 0xBBD2, 0x95A1 }, + { 0xBBD3, 0x95A8 }, + { 0xBBD4, 0x95A9 }, + { 0xBBD5, 0x95A3 }, + { 0xBBD6, 0x95A5 }, + { 0xBBD7, 0x95A4 }, + { 0xBBD8, 0x9699 }, + { 0xBBD9, 0x969C }, + { 0xBBDA, 0x969B }, + { 0xBBDB, 0x96CC }, + { 0xBBDC, 0x96D2 }, + { 0xBBDD, 0x9700 }, + { 0xBBDE, 0x977C }, + { 0xBBDF, 0x9785 }, + { 0xBBE0, 0x97F6 }, + { 0xBBE1, 0x9817 }, + { 0xBBE2, 0x9818 }, + { 0xBBE3, 0x98AF }, + { 0xBBE4, 0x98B1 }, + { 0xBBE5, 0x9903 }, + { 0xBBE6, 0x9905 }, + { 0xBBE7, 0x990C }, + { 0xBBE8, 0x9909 }, + { 0xBBE9, 0x99C1 }, + { 0xBBEA, 0x9AAF }, + { 0xBBEB, 0x9AB0 }, + { 0xBBEC, 0x9AE6 }, + { 0xBBED, 0x9B41 }, + { 0xBBEE, 0x9B42 }, + { 0xBBEF, 0x9CF4 }, + { 0xBBF0, 0x9CF6 }, + { 0xBBF1, 0x9CF3 }, + { 0xBBF2, 0x9EBC }, + { 0xBBF3, 0x9F3B }, + { 0xBBF4, 0x9F4A }, + { 0xBBF5, 0x5104 }, + { 0xBBF6, 0x5100 }, + { 0xBBF7, 0x50FB }, + { 0xBBF8, 0x50F5 }, + { 0xBBF9, 0x50F9 }, + { 0xBBFA, 0x5102 }, + { 0xBBFB, 0x5108 }, + { 0xBBFC, 0x5109 }, + { 0xBBFD, 0x5105 }, + { 0xBBFE, 0x51DC }, + { 0xBC40, 0x5287 }, + { 0xBC41, 0x5288 }, + { 0xBC42, 0x5289 }, + { 0xBC43, 0x528D }, + { 0xBC44, 0x528A }, + { 0xBC45, 0x52F0 }, + { 0xBC46, 0x53B2 }, + { 0xBC47, 0x562E }, + { 0xBC48, 0x563B }, + { 0xBC49, 0x5639 }, + { 0xBC4A, 0x5632 }, + { 0xBC4B, 0x563F }, + { 0xBC4C, 0x5634 }, + { 0xBC4D, 0x5629 }, + { 0xBC4E, 0x5653 }, + { 0xBC4F, 0x564E }, + { 0xBC50, 0x5657 }, + { 0xBC51, 0x5674 }, + { 0xBC52, 0x5636 }, + { 0xBC53, 0x562F }, + { 0xBC54, 0x5630 }, + { 0xBC55, 0x5880 }, + { 0xBC56, 0x589F }, + { 0xBC57, 0x589E }, + { 0xBC58, 0x58B3 }, + { 0xBC59, 0x589C }, + { 0xBC5A, 0x58AE }, + { 0xBC5B, 0x58A9 }, + { 0xBC5C, 0x58A6 }, + { 0xBC5D, 0x596D }, + { 0xBC5E, 0x5B09 }, + { 0xBC5F, 0x5AFB }, + { 0xBC60, 0x5B0B }, + { 0xBC61, 0x5AF5 }, + { 0xBC62, 0x5B0C }, + { 0xBC63, 0x5B08 }, + { 0xBC64, 0x5BEE }, + { 0xBC65, 0x5BEC }, + { 0xBC66, 0x5BE9 }, + { 0xBC67, 0x5BEB }, + { 0xBC68, 0x5C64 }, + { 0xBC69, 0x5C65 }, + { 0xBC6A, 0x5D9D }, + { 0xBC6B, 0x5D94 }, + { 0xBC6C, 0x5E62 }, + { 0xBC6D, 0x5E5F }, + { 0xBC6E, 0x5E61 }, + { 0xBC6F, 0x5EE2 }, + { 0xBC70, 0x5EDA }, + { 0xBC71, 0x5EDF }, + { 0xBC72, 0x5EDD }, + { 0xBC73, 0x5EE3 }, + { 0xBC74, 0x5EE0 }, + { 0xBC75, 0x5F48 }, + { 0xBC76, 0x5F71 }, + { 0xBC77, 0x5FB7 }, + { 0xBC78, 0x5FB5 }, + { 0xBC79, 0x6176 }, + { 0xBC7A, 0x6167 }, + { 0xBC7B, 0x616E }, + { 0xBC7C, 0x615D }, + { 0xBC7D, 0x6155 }, + { 0xBC7E, 0x6182 }, + { 0xBCA1, 0x617C }, + { 0xBCA2, 0x6170 }, + { 0xBCA3, 0x616B }, + { 0xBCA4, 0x617E }, + { 0xBCA5, 0x61A7 }, + { 0xBCA6, 0x6190 }, + { 0xBCA7, 0x61AB }, + { 0xBCA8, 0x618E }, + { 0xBCA9, 0x61AC }, + { 0xBCAA, 0x619A }, + { 0xBCAB, 0x61A4 }, + { 0xBCAC, 0x6194 }, + { 0xBCAD, 0x61AE }, + { 0xBCAE, 0x622E }, + { 0xBCAF, 0x6469 }, + { 0xBCB0, 0x646F }, + { 0xBCB1, 0x6479 }, + { 0xBCB2, 0x649E }, + { 0xBCB3, 0x64B2 }, + { 0xBCB4, 0x6488 }, + { 0xBCB5, 0x6490 }, + { 0xBCB6, 0x64B0 }, + { 0xBCB7, 0x64A5 }, + { 0xBCB8, 0x6493 }, + { 0xBCB9, 0x6495 }, + { 0xBCBA, 0x64A9 }, + { 0xBCBB, 0x6492 }, + { 0xBCBC, 0x64AE }, + { 0xBCBD, 0x64AD }, + { 0xBCBE, 0x64AB }, + { 0xBCBF, 0x649A }, + { 0xBCC0, 0x64AC }, + { 0xBCC1, 0x6499 }, + { 0xBCC2, 0x64A2 }, + { 0xBCC3, 0x64B3 }, + { 0xBCC4, 0x6575 }, + { 0xBCC5, 0x6577 }, + { 0xBCC6, 0x6578 }, + { 0xBCC7, 0x66AE }, + { 0xBCC8, 0x66AB }, + { 0xBCC9, 0x66B4 }, + { 0xBCCA, 0x66B1 }, + { 0xBCCB, 0x6A23 }, + { 0xBCCC, 0x6A1F }, + { 0xBCCD, 0x69E8 }, + { 0xBCCE, 0x6A01 }, + { 0xBCCF, 0x6A1E }, + { 0xBCD0, 0x6A19 }, + { 0xBCD1, 0x69FD }, + { 0xBCD2, 0x6A21 }, + { 0xBCD3, 0x6A13 }, + { 0xBCD4, 0x6A0A }, + { 0xBCD5, 0x69F3 }, + { 0xBCD6, 0x6A02 }, + { 0xBCD7, 0x6A05 }, + { 0xBCD8, 0x69ED }, + { 0xBCD9, 0x6A11 }, + { 0xBCDA, 0x6B50 }, + { 0xBCDB, 0x6B4E }, + { 0xBCDC, 0x6BA4 }, + { 0xBCDD, 0x6BC5 }, + { 0xBCDE, 0x6BC6 }, + { 0xBCDF, 0x6F3F }, + { 0xBCE0, 0x6F7C }, + { 0xBCE1, 0x6F84 }, + { 0xBCE2, 0x6F51 }, + { 0xBCE3, 0x6F66 }, + { 0xBCE4, 0x6F54 }, + { 0xBCE5, 0x6F86 }, + { 0xBCE6, 0x6F6D }, + { 0xBCE7, 0x6F5B }, + { 0xBCE8, 0x6F78 }, + { 0xBCE9, 0x6F6E }, + { 0xBCEA, 0x6F8E }, + { 0xBCEB, 0x6F7A }, + { 0xBCEC, 0x6F70 }, + { 0xBCED, 0x6F64 }, + { 0xBCEE, 0x6F97 }, + { 0xBCEF, 0x6F58 }, + { 0xBCF0, 0x6ED5 }, + { 0xBCF1, 0x6F6F }, + { 0xBCF2, 0x6F60 }, + { 0xBCF3, 0x6F5F }, + { 0xBCF4, 0x719F }, + { 0xBCF5, 0x71AC }, + { 0xBCF6, 0x71B1 }, + { 0xBCF7, 0x71A8 }, + { 0xBCF8, 0x7256 }, + { 0xBCF9, 0x729B }, + { 0xBCFA, 0x734E }, + { 0xBCFB, 0x7357 }, + { 0xBCFC, 0x7469 }, + { 0xBCFD, 0x748B }, + { 0xBCFE, 0x7483 }, + { 0xBD40, 0x747E }, + { 0xBD41, 0x7480 }, + { 0xBD42, 0x757F }, + { 0xBD43, 0x7620 }, + { 0xBD44, 0x7629 }, + { 0xBD45, 0x761F }, + { 0xBD46, 0x7624 }, + { 0xBD47, 0x7626 }, + { 0xBD48, 0x7621 }, + { 0xBD49, 0x7622 }, + { 0xBD4A, 0x769A }, + { 0xBD4B, 0x76BA }, + { 0xBD4C, 0x76E4 }, + { 0xBD4D, 0x778E }, + { 0xBD4E, 0x7787 }, + { 0xBD4F, 0x778C }, + { 0xBD50, 0x7791 }, + { 0xBD51, 0x778B }, + { 0xBD52, 0x78CB }, + { 0xBD53, 0x78C5 }, + { 0xBD54, 0x78BA }, + { 0xBD55, 0x78CA }, + { 0xBD56, 0x78BE }, + { 0xBD57, 0x78D5 }, + { 0xBD58, 0x78BC }, + { 0xBD59, 0x78D0 }, + { 0xBD5A, 0x7A3F }, + { 0xBD5B, 0x7A3C }, + { 0xBD5C, 0x7A40 }, + { 0xBD5D, 0x7A3D }, + { 0xBD5E, 0x7A37 }, + { 0xBD5F, 0x7A3B }, + { 0xBD60, 0x7AAF }, + { 0xBD61, 0x7AAE }, + { 0xBD62, 0x7BAD }, + { 0xBD63, 0x7BB1 }, + { 0xBD64, 0x7BC4 }, + { 0xBD65, 0x7BB4 }, + { 0xBD66, 0x7BC6 }, + { 0xBD67, 0x7BC7 }, + { 0xBD68, 0x7BC1 }, + { 0xBD69, 0x7BA0 }, + { 0xBD6A, 0x7BCC }, + { 0xBD6B, 0x7CCA }, + { 0xBD6C, 0x7DE0 }, + { 0xBD6D, 0x7DF4 }, + { 0xBD6E, 0x7DEF }, + { 0xBD6F, 0x7DFB }, + { 0xBD70, 0x7DD8 }, + { 0xBD71, 0x7DEC }, + { 0xBD72, 0x7DDD }, + { 0xBD73, 0x7DE8 }, + { 0xBD74, 0x7DE3 }, + { 0xBD75, 0x7DDA }, + { 0xBD76, 0x7DDE }, + { 0xBD77, 0x7DE9 }, + { 0xBD78, 0x7D9E }, + { 0xBD79, 0x7DD9 }, + { 0xBD7A, 0x7DF2 }, + { 0xBD7B, 0x7DF9 }, + { 0xBD7C, 0x7F75 }, + { 0xBD7D, 0x7F77 }, + { 0xBD7E, 0x7FAF }, + { 0xBDA1, 0x7FE9 }, + { 0xBDA2, 0x8026 }, + { 0xBDA3, 0x819B }, + { 0xBDA4, 0x819C }, + { 0xBDA5, 0x819D }, + { 0xBDA6, 0x81A0 }, + { 0xBDA7, 0x819A }, + { 0xBDA8, 0x8198 }, + { 0xBDA9, 0x8517 }, + { 0xBDAA, 0x853D }, + { 0xBDAB, 0x851A }, + { 0xBDAC, 0x84EE }, + { 0xBDAD, 0x852C }, + { 0xBDAE, 0x852D }, + { 0xBDAF, 0x8513 }, + { 0xBDB0, 0x8511 }, + { 0xBDB1, 0x8523 }, + { 0xBDB2, 0x8521 }, + { 0xBDB3, 0x8514 }, + { 0xBDB4, 0x84EC }, + { 0xBDB5, 0x8525 }, + { 0xBDB6, 0x84FF }, + { 0xBDB7, 0x8506 }, + { 0xBDB8, 0x8782 }, + { 0xBDB9, 0x8774 }, + { 0xBDBA, 0x8776 }, + { 0xBDBB, 0x8760 }, + { 0xBDBC, 0x8766 }, + { 0xBDBD, 0x8778 }, + { 0xBDBE, 0x8768 }, + { 0xBDBF, 0x8759 }, + { 0xBDC0, 0x8757 }, + { 0xBDC1, 0x874C }, + { 0xBDC2, 0x8753 }, + { 0xBDC3, 0x885B }, + { 0xBDC4, 0x885D }, + { 0xBDC5, 0x8910 }, + { 0xBDC6, 0x8907 }, + { 0xBDC7, 0x8912 }, + { 0xBDC8, 0x8913 }, + { 0xBDC9, 0x8915 }, + { 0xBDCA, 0x890A }, + { 0xBDCB, 0x8ABC }, + { 0xBDCC, 0x8AD2 }, + { 0xBDCD, 0x8AC7 }, + { 0xBDCE, 0x8AC4 }, + { 0xBDCF, 0x8A95 }, + { 0xBDD0, 0x8ACB }, + { 0xBDD1, 0x8AF8 }, + { 0xBDD2, 0x8AB2 }, + { 0xBDD3, 0x8AC9 }, + { 0xBDD4, 0x8AC2 }, + { 0xBDD5, 0x8ABF }, + { 0xBDD6, 0x8AB0 }, + { 0xBDD7, 0x8AD6 }, + { 0xBDD8, 0x8ACD }, + { 0xBDD9, 0x8AB6 }, + { 0xBDDA, 0x8AB9 }, + { 0xBDDB, 0x8ADB }, + { 0xBDDC, 0x8C4C }, + { 0xBDDD, 0x8C4E }, + { 0xBDDE, 0x8C6C }, + { 0xBDDF, 0x8CE0 }, + { 0xBDE0, 0x8CDE }, + { 0xBDE1, 0x8CE6 }, + { 0xBDE2, 0x8CE4 }, + { 0xBDE3, 0x8CEC }, + { 0xBDE4, 0x8CED }, + { 0xBDE5, 0x8CE2 }, + { 0xBDE6, 0x8CE3 }, + { 0xBDE7, 0x8CDC }, + { 0xBDE8, 0x8CEA }, + { 0xBDE9, 0x8CE1 }, + { 0xBDEA, 0x8D6D }, + { 0xBDEB, 0x8D9F }, + { 0xBDEC, 0x8DA3 }, + { 0xBDED, 0x8E2B }, + { 0xBDEE, 0x8E10 }, + { 0xBDEF, 0x8E1D }, + { 0xBDF0, 0x8E22 }, + { 0xBDF1, 0x8E0F }, + { 0xBDF2, 0x8E29 }, + { 0xBDF3, 0x8E1F }, + { 0xBDF4, 0x8E21 }, + { 0xBDF5, 0x8E1E }, + { 0xBDF6, 0x8EBA }, + { 0xBDF7, 0x8F1D }, + { 0xBDF8, 0x8F1B }, + { 0xBDF9, 0x8F1F }, + { 0xBDFA, 0x8F29 }, + { 0xBDFB, 0x8F26 }, + { 0xBDFC, 0x8F2A }, + { 0xBDFD, 0x8F1C }, + { 0xBDFE, 0x8F1E }, + { 0xBE40, 0x8F25 }, + { 0xBE41, 0x9069 }, + { 0xBE42, 0x906E }, + { 0xBE43, 0x9068 }, + { 0xBE44, 0x906D }, + { 0xBE45, 0x9077 }, + { 0xBE46, 0x9130 }, + { 0xBE47, 0x912D }, + { 0xBE48, 0x9127 }, + { 0xBE49, 0x9131 }, + { 0xBE4A, 0x9187 }, + { 0xBE4B, 0x9189 }, + { 0xBE4C, 0x918B }, + { 0xBE4D, 0x9183 }, + { 0xBE4E, 0x92C5 }, + { 0xBE4F, 0x92BB }, + { 0xBE50, 0x92B7 }, + { 0xBE51, 0x92EA }, + { 0xBE52, 0x92AC }, + { 0xBE53, 0x92E4 }, + { 0xBE54, 0x92C1 }, + { 0xBE55, 0x92B3 }, + { 0xBE56, 0x92BC }, + { 0xBE57, 0x92D2 }, + { 0xBE58, 0x92C7 }, + { 0xBE59, 0x92F0 }, + { 0xBE5A, 0x92B2 }, + { 0xBE5B, 0x95AD }, + { 0xBE5C, 0x95B1 }, + { 0xBE5D, 0x9704 }, + { 0xBE5E, 0x9706 }, + { 0xBE5F, 0x9707 }, + { 0xBE60, 0x9709 }, + { 0xBE61, 0x9760 }, + { 0xBE62, 0x978D }, + { 0xBE63, 0x978B }, + { 0xBE64, 0x978F }, + { 0xBE65, 0x9821 }, + { 0xBE66, 0x982B }, + { 0xBE67, 0x981C }, + { 0xBE68, 0x98B3 }, + { 0xBE69, 0x990A }, + { 0xBE6A, 0x9913 }, + { 0xBE6B, 0x9912 }, + { 0xBE6C, 0x9918 }, + { 0xBE6D, 0x99DD }, + { 0xBE6E, 0x99D0 }, + { 0xBE6F, 0x99DF }, + { 0xBE70, 0x99DB }, + { 0xBE71, 0x99D1 }, + { 0xBE72, 0x99D5 }, + { 0xBE73, 0x99D2 }, + { 0xBE74, 0x99D9 }, + { 0xBE75, 0x9AB7 }, + { 0xBE76, 0x9AEE }, + { 0xBE77, 0x9AEF }, + { 0xBE78, 0x9B27 }, + { 0xBE79, 0x9B45 }, + { 0xBE7A, 0x9B44 }, + { 0xBE7B, 0x9B77 }, + { 0xBE7C, 0x9B6F }, + { 0xBE7D, 0x9D06 }, + { 0xBE7E, 0x9D09 }, + { 0xBEA1, 0x9D03 }, + { 0xBEA2, 0x9EA9 }, + { 0xBEA3, 0x9EBE }, + { 0xBEA4, 0x9ECE }, + { 0xBEA5, 0x58A8 }, + { 0xBEA6, 0x9F52 }, + { 0xBEA7, 0x5112 }, + { 0xBEA8, 0x5118 }, + { 0xBEA9, 0x5114 }, + { 0xBEAA, 0x5110 }, + { 0xBEAB, 0x5115 }, + { 0xBEAC, 0x5180 }, + { 0xBEAD, 0x51AA }, + { 0xBEAE, 0x51DD }, + { 0xBEAF, 0x5291 }, + { 0xBEB0, 0x5293 }, + { 0xBEB1, 0x52F3 }, + { 0xBEB2, 0x5659 }, + { 0xBEB3, 0x566B }, + { 0xBEB4, 0x5679 }, + { 0xBEB5, 0x5669 }, + { 0xBEB6, 0x5664 }, + { 0xBEB7, 0x5678 }, + { 0xBEB8, 0x566A }, + { 0xBEB9, 0x5668 }, + { 0xBEBA, 0x5665 }, + { 0xBEBB, 0x5671 }, + { 0xBEBC, 0x566F }, + { 0xBEBD, 0x566C }, + { 0xBEBE, 0x5662 }, + { 0xBEBF, 0x5676 }, + { 0xBEC0, 0x58C1 }, + { 0xBEC1, 0x58BE }, + { 0xBEC2, 0x58C7 }, + { 0xBEC3, 0x58C5 }, + { 0xBEC4, 0x596E }, + { 0xBEC5, 0x5B1D }, + { 0xBEC6, 0x5B34 }, + { 0xBEC7, 0x5B78 }, + { 0xBEC8, 0x5BF0 }, + { 0xBEC9, 0x5C0E }, + { 0xBECA, 0x5F4A }, + { 0xBECB, 0x61B2 }, + { 0xBECC, 0x6191 }, + { 0xBECD, 0x61A9 }, + { 0xBECE, 0x618A }, + { 0xBECF, 0x61CD }, + { 0xBED0, 0x61B6 }, + { 0xBED1, 0x61BE }, + { 0xBED2, 0x61CA }, + { 0xBED3, 0x61C8 }, + { 0xBED4, 0x6230 }, + { 0xBED5, 0x64C5 }, + { 0xBED6, 0x64C1 }, + { 0xBED7, 0x64CB }, + { 0xBED8, 0x64BB }, + { 0xBED9, 0x64BC }, + { 0xBEDA, 0x64DA }, + { 0xBEDB, 0x64C4 }, + { 0xBEDC, 0x64C7 }, + { 0xBEDD, 0x64C2 }, + { 0xBEDE, 0x64CD }, + { 0xBEDF, 0x64BF }, + { 0xBEE0, 0x64D2 }, + { 0xBEE1, 0x64D4 }, + { 0xBEE2, 0x64BE }, + { 0xBEE3, 0x6574 }, + { 0xBEE4, 0x66C6 }, + { 0xBEE5, 0x66C9 }, + { 0xBEE6, 0x66B9 }, + { 0xBEE7, 0x66C4 }, + { 0xBEE8, 0x66C7 }, + { 0xBEE9, 0x66B8 }, + { 0xBEEA, 0x6A3D }, + { 0xBEEB, 0x6A38 }, + { 0xBEEC, 0x6A3A }, + { 0xBEED, 0x6A59 }, + { 0xBEEE, 0x6A6B }, + { 0xBEEF, 0x6A58 }, + { 0xBEF0, 0x6A39 }, + { 0xBEF1, 0x6A44 }, + { 0xBEF2, 0x6A62 }, + { 0xBEF3, 0x6A61 }, + { 0xBEF4, 0x6A4B }, + { 0xBEF5, 0x6A47 }, + { 0xBEF6, 0x6A35 }, + { 0xBEF7, 0x6A5F }, + { 0xBEF8, 0x6A48 }, + { 0xBEF9, 0x6B59 }, + { 0xBEFA, 0x6B77 }, + { 0xBEFB, 0x6C05 }, + { 0xBEFC, 0x6FC2 }, + { 0xBEFD, 0x6FB1 }, + { 0xBEFE, 0x6FA1 }, + { 0xBF40, 0x6FC3 }, + { 0xBF41, 0x6FA4 }, + { 0xBF42, 0x6FC1 }, + { 0xBF43, 0x6FA7 }, + { 0xBF44, 0x6FB3 }, + { 0xBF45, 0x6FC0 }, + { 0xBF46, 0x6FB9 }, + { 0xBF47, 0x6FB6 }, + { 0xBF48, 0x6FA6 }, + { 0xBF49, 0x6FA0 }, + { 0xBF4A, 0x6FB4 }, + { 0xBF4B, 0x71BE }, + { 0xBF4C, 0x71C9 }, + { 0xBF4D, 0x71D0 }, + { 0xBF4E, 0x71D2 }, + { 0xBF4F, 0x71C8 }, + { 0xBF50, 0x71D5 }, + { 0xBF51, 0x71B9 }, + { 0xBF52, 0x71CE }, + { 0xBF53, 0x71D9 }, + { 0xBF54, 0x71DC }, + { 0xBF55, 0x71C3 }, + { 0xBF56, 0x71C4 }, + { 0xBF57, 0x7368 }, + { 0xBF58, 0x749C }, + { 0xBF59, 0x74A3 }, + { 0xBF5A, 0x7498 }, + { 0xBF5B, 0x749F }, + { 0xBF5C, 0x749E }, + { 0xBF5D, 0x74E2 }, + { 0xBF5E, 0x750C }, + { 0xBF5F, 0x750D }, + { 0xBF60, 0x7634 }, + { 0xBF61, 0x7638 }, + { 0xBF62, 0x763A }, + { 0xBF63, 0x76E7 }, + { 0xBF64, 0x76E5 }, + { 0xBF65, 0x77A0 }, + { 0xBF66, 0x779E }, + { 0xBF67, 0x779F }, + { 0xBF68, 0x77A5 }, + { 0xBF69, 0x78E8 }, + { 0xBF6A, 0x78DA }, + { 0xBF6B, 0x78EC }, + { 0xBF6C, 0x78E7 }, + { 0xBF6D, 0x79A6 }, + { 0xBF6E, 0x7A4D }, + { 0xBF6F, 0x7A4E }, + { 0xBF70, 0x7A46 }, + { 0xBF71, 0x7A4C }, + { 0xBF72, 0x7A4B }, + { 0xBF73, 0x7ABA }, + { 0xBF74, 0x7BD9 }, + { 0xBF75, 0x7C11 }, + { 0xBF76, 0x7BC9 }, + { 0xBF77, 0x7BE4 }, + { 0xBF78, 0x7BDB }, + { 0xBF79, 0x7BE1 }, + { 0xBF7A, 0x7BE9 }, + { 0xBF7B, 0x7BE6 }, + { 0xBF7C, 0x7CD5 }, + { 0xBF7D, 0x7CD6 }, + { 0xBF7E, 0x7E0A }, + { 0xBFA1, 0x7E11 }, + { 0xBFA2, 0x7E08 }, + { 0xBFA3, 0x7E1B }, + { 0xBFA4, 0x7E23 }, + { 0xBFA5, 0x7E1E }, + { 0xBFA6, 0x7E1D }, + { 0xBFA7, 0x7E09 }, + { 0xBFA8, 0x7E10 }, + { 0xBFA9, 0x7F79 }, + { 0xBFAA, 0x7FB2 }, + { 0xBFAB, 0x7FF0 }, + { 0xBFAC, 0x7FF1 }, + { 0xBFAD, 0x7FEE }, + { 0xBFAE, 0x8028 }, + { 0xBFAF, 0x81B3 }, + { 0xBFB0, 0x81A9 }, + { 0xBFB1, 0x81A8 }, + { 0xBFB2, 0x81FB }, + { 0xBFB3, 0x8208 }, + { 0xBFB4, 0x8258 }, + { 0xBFB5, 0x8259 }, + { 0xBFB6, 0x854A }, + { 0xBFB7, 0x8559 }, + { 0xBFB8, 0x8548 }, + { 0xBFB9, 0x8568 }, + { 0xBFBA, 0x8569 }, + { 0xBFBB, 0x8543 }, + { 0xBFBC, 0x8549 }, + { 0xBFBD, 0x856D }, + { 0xBFBE, 0x856A }, + { 0xBFBF, 0x855E }, + { 0xBFC0, 0x8783 }, + { 0xBFC1, 0x879F }, + { 0xBFC2, 0x879E }, + { 0xBFC3, 0x87A2 }, + { 0xBFC4, 0x878D }, + { 0xBFC5, 0x8861 }, + { 0xBFC6, 0x892A }, + { 0xBFC7, 0x8932 }, + { 0xBFC8, 0x8925 }, + { 0xBFC9, 0x892B }, + { 0xBFCA, 0x8921 }, + { 0xBFCB, 0x89AA }, + { 0xBFCC, 0x89A6 }, + { 0xBFCD, 0x8AE6 }, + { 0xBFCE, 0x8AFA }, + { 0xBFCF, 0x8AEB }, + { 0xBFD0, 0x8AF1 }, + { 0xBFD1, 0x8B00 }, + { 0xBFD2, 0x8ADC }, + { 0xBFD3, 0x8AE7 }, + { 0xBFD4, 0x8AEE }, + { 0xBFD5, 0x8AFE }, + { 0xBFD6, 0x8B01 }, + { 0xBFD7, 0x8B02 }, + { 0xBFD8, 0x8AF7 }, + { 0xBFD9, 0x8AED }, + { 0xBFDA, 0x8AF3 }, + { 0xBFDB, 0x8AF6 }, + { 0xBFDC, 0x8AFC }, + { 0xBFDD, 0x8C6B }, + { 0xBFDE, 0x8C6D }, + { 0xBFDF, 0x8C93 }, + { 0xBFE0, 0x8CF4 }, + { 0xBFE1, 0x8E44 }, + { 0xBFE2, 0x8E31 }, + { 0xBFE3, 0x8E34 }, + { 0xBFE4, 0x8E42 }, + { 0xBFE5, 0x8E39 }, + { 0xBFE6, 0x8E35 }, + { 0xBFE7, 0x8F3B }, + { 0xBFE8, 0x8F2F }, + { 0xBFE9, 0x8F38 }, + { 0xBFEA, 0x8F33 }, + { 0xBFEB, 0x8FA8 }, + { 0xBFEC, 0x8FA6 }, + { 0xBFED, 0x9075 }, + { 0xBFEE, 0x9074 }, + { 0xBFEF, 0x9078 }, + { 0xBFF0, 0x9072 }, + { 0xBFF1, 0x907C }, + { 0xBFF2, 0x907A }, + { 0xBFF3, 0x9134 }, + { 0xBFF4, 0x9192 }, + { 0xBFF5, 0x9320 }, + { 0xBFF6, 0x9336 }, + { 0xBFF7, 0x92F8 }, + { 0xBFF8, 0x9333 }, + { 0xBFF9, 0x932F }, + { 0xBFFA, 0x9322 }, + { 0xBFFB, 0x92FC }, + { 0xBFFC, 0x932B }, + { 0xBFFD, 0x9304 }, + { 0xBFFE, 0x931A }, + { 0xC040, 0x9310 }, + { 0xC041, 0x9326 }, + { 0xC042, 0x9321 }, + { 0xC043, 0x9315 }, + { 0xC044, 0x932E }, + { 0xC045, 0x9319 }, + { 0xC046, 0x95BB }, + { 0xC047, 0x96A7 }, + { 0xC048, 0x96A8 }, + { 0xC049, 0x96AA }, + { 0xC04A, 0x96D5 }, + { 0xC04B, 0x970E }, + { 0xC04C, 0x9711 }, + { 0xC04D, 0x9716 }, + { 0xC04E, 0x970D }, + { 0xC04F, 0x9713 }, + { 0xC050, 0x970F }, + { 0xC051, 0x975B }, + { 0xC052, 0x975C }, + { 0xC053, 0x9766 }, + { 0xC054, 0x9798 }, + { 0xC055, 0x9830 }, + { 0xC056, 0x9838 }, + { 0xC057, 0x983B }, + { 0xC058, 0x9837 }, + { 0xC059, 0x982D }, + { 0xC05A, 0x9839 }, + { 0xC05B, 0x9824 }, + { 0xC05C, 0x9910 }, + { 0xC05D, 0x9928 }, + { 0xC05E, 0x991E }, + { 0xC05F, 0x991B }, + { 0xC060, 0x9921 }, + { 0xC061, 0x991A }, + { 0xC062, 0x99ED }, + { 0xC063, 0x99E2 }, + { 0xC064, 0x99F1 }, + { 0xC065, 0x9AB8 }, + { 0xC066, 0x9ABC }, + { 0xC067, 0x9AFB }, + { 0xC068, 0x9AED }, + { 0xC069, 0x9B28 }, + { 0xC06A, 0x9B91 }, + { 0xC06B, 0x9D15 }, + { 0xC06C, 0x9D23 }, + { 0xC06D, 0x9D26 }, + { 0xC06E, 0x9D28 }, + { 0xC06F, 0x9D12 }, + { 0xC070, 0x9D1B }, + { 0xC071, 0x9ED8 }, + { 0xC072, 0x9ED4 }, + { 0xC073, 0x9F8D }, + { 0xC074, 0x9F9C }, + { 0xC075, 0x512A }, + { 0xC076, 0x511F }, + { 0xC077, 0x5121 }, + { 0xC078, 0x5132 }, + { 0xC079, 0x52F5 }, + { 0xC07A, 0x568E }, + { 0xC07B, 0x5680 }, + { 0xC07C, 0x5690 }, + { 0xC07D, 0x5685 }, + { 0xC07E, 0x5687 }, + { 0xC0A1, 0x568F }, + { 0xC0A2, 0x58D5 }, + { 0xC0A3, 0x58D3 }, + { 0xC0A4, 0x58D1 }, + { 0xC0A5, 0x58CE }, + { 0xC0A6, 0x5B30 }, + { 0xC0A7, 0x5B2A }, + { 0xC0A8, 0x5B24 }, + { 0xC0A9, 0x5B7A }, + { 0xC0AA, 0x5C37 }, + { 0xC0AB, 0x5C68 }, + { 0xC0AC, 0x5DBC }, + { 0xC0AD, 0x5DBA }, + { 0xC0AE, 0x5DBD }, + { 0xC0AF, 0x5DB8 }, + { 0xC0B0, 0x5E6B }, + { 0xC0B1, 0x5F4C }, + { 0xC0B2, 0x5FBD }, + { 0xC0B3, 0x61C9 }, + { 0xC0B4, 0x61C2 }, + { 0xC0B5, 0x61C7 }, + { 0xC0B6, 0x61E6 }, + { 0xC0B7, 0x61CB }, + { 0xC0B8, 0x6232 }, + { 0xC0B9, 0x6234 }, + { 0xC0BA, 0x64CE }, + { 0xC0BB, 0x64CA }, + { 0xC0BC, 0x64D8 }, + { 0xC0BD, 0x64E0 }, + { 0xC0BE, 0x64F0 }, + { 0xC0BF, 0x64E6 }, + { 0xC0C0, 0x64EC }, + { 0xC0C1, 0x64F1 }, + { 0xC0C2, 0x64E2 }, + { 0xC0C3, 0x64ED }, + { 0xC0C4, 0x6582 }, + { 0xC0C5, 0x6583 }, + { 0xC0C6, 0x66D9 }, + { 0xC0C7, 0x66D6 }, + { 0xC0C8, 0x6A80 }, + { 0xC0C9, 0x6A94 }, + { 0xC0CA, 0x6A84 }, + { 0xC0CB, 0x6AA2 }, + { 0xC0CC, 0x6A9C }, + { 0xC0CD, 0x6ADB }, + { 0xC0CE, 0x6AA3 }, + { 0xC0CF, 0x6A7E }, + { 0xC0D0, 0x6A97 }, + { 0xC0D1, 0x6A90 }, + { 0xC0D2, 0x6AA0 }, + { 0xC0D3, 0x6B5C }, + { 0xC0D4, 0x6BAE }, + { 0xC0D5, 0x6BDA }, + { 0xC0D6, 0x6C08 }, + { 0xC0D7, 0x6FD8 }, + { 0xC0D8, 0x6FF1 }, + { 0xC0D9, 0x6FDF }, + { 0xC0DA, 0x6FE0 }, + { 0xC0DB, 0x6FDB }, + { 0xC0DC, 0x6FE4 }, + { 0xC0DD, 0x6FEB }, + { 0xC0DE, 0x6FEF }, + { 0xC0DF, 0x6F80 }, + { 0xC0E0, 0x6FEC }, + { 0xC0E1, 0x6FE1 }, + { 0xC0E2, 0x6FE9 }, + { 0xC0E3, 0x6FD5 }, + { 0xC0E4, 0x6FEE }, + { 0xC0E5, 0x6FF0 }, + { 0xC0E6, 0x71E7 }, + { 0xC0E7, 0x71DF }, + { 0xC0E8, 0x71EE }, + { 0xC0E9, 0x71E6 }, + { 0xC0EA, 0x71E5 }, + { 0xC0EB, 0x71ED }, + { 0xC0EC, 0x71EC }, + { 0xC0ED, 0x71F4 }, + { 0xC0EE, 0x71E0 }, + { 0xC0EF, 0x7235 }, + { 0xC0F0, 0x7246 }, + { 0xC0F1, 0x7370 }, + { 0xC0F2, 0x7372 }, + { 0xC0F3, 0x74A9 }, + { 0xC0F4, 0x74B0 }, + { 0xC0F5, 0x74A6 }, + { 0xC0F6, 0x74A8 }, + { 0xC0F7, 0x7646 }, + { 0xC0F8, 0x7642 }, + { 0xC0F9, 0x764C }, + { 0xC0FA, 0x76EA }, + { 0xC0FB, 0x77B3 }, + { 0xC0FC, 0x77AA }, + { 0xC0FD, 0x77B0 }, + { 0xC0FE, 0x77AC }, + { 0xC140, 0x77A7 }, + { 0xC141, 0x77AD }, + { 0xC142, 0x77EF }, + { 0xC143, 0x78F7 }, + { 0xC144, 0x78FA }, + { 0xC145, 0x78F4 }, + { 0xC146, 0x78EF }, + { 0xC147, 0x7901 }, + { 0xC148, 0x79A7 }, + { 0xC149, 0x79AA }, + { 0xC14A, 0x7A57 }, + { 0xC14B, 0x7ABF }, + { 0xC14C, 0x7C07 }, + { 0xC14D, 0x7C0D }, + { 0xC14E, 0x7BFE }, + { 0xC14F, 0x7BF7 }, + { 0xC150, 0x7C0C }, + { 0xC151, 0x7BE0 }, + { 0xC152, 0x7CE0 }, + { 0xC153, 0x7CDC }, + { 0xC154, 0x7CDE }, + { 0xC155, 0x7CE2 }, + { 0xC156, 0x7CDF }, + { 0xC157, 0x7CD9 }, + { 0xC158, 0x7CDD }, + { 0xC159, 0x7E2E }, + { 0xC15A, 0x7E3E }, + { 0xC15B, 0x7E46 }, + { 0xC15C, 0x7E37 }, + { 0xC15D, 0x7E32 }, + { 0xC15E, 0x7E43 }, + { 0xC15F, 0x7E2B }, + { 0xC160, 0x7E3D }, + { 0xC161, 0x7E31 }, + { 0xC162, 0x7E45 }, + { 0xC163, 0x7E41 }, + { 0xC164, 0x7E34 }, + { 0xC165, 0x7E39 }, + { 0xC166, 0x7E48 }, + { 0xC167, 0x7E35 }, + { 0xC168, 0x7E3F }, + { 0xC169, 0x7E2F }, + { 0xC16A, 0x7F44 }, + { 0xC16B, 0x7FF3 }, + { 0xC16C, 0x7FFC }, + { 0xC16D, 0x8071 }, + { 0xC16E, 0x8072 }, + { 0xC16F, 0x8070 }, + { 0xC170, 0x806F }, + { 0xC171, 0x8073 }, + { 0xC172, 0x81C6 }, + { 0xC173, 0x81C3 }, + { 0xC174, 0x81BA }, + { 0xC175, 0x81C2 }, + { 0xC176, 0x81C0 }, + { 0xC177, 0x81BF }, + { 0xC178, 0x81BD }, + { 0xC179, 0x81C9 }, + { 0xC17A, 0x81BE }, + { 0xC17B, 0x81E8 }, + { 0xC17C, 0x8209 }, + { 0xC17D, 0x8271 }, + { 0xC17E, 0x85AA }, + { 0xC1A1, 0x8584 }, + { 0xC1A2, 0x857E }, + { 0xC1A3, 0x859C }, + { 0xC1A4, 0x8591 }, + { 0xC1A5, 0x8594 }, + { 0xC1A6, 0x85AF }, + { 0xC1A7, 0x859B }, + { 0xC1A8, 0x8587 }, + { 0xC1A9, 0x85A8 }, + { 0xC1AA, 0x858A }, + { 0xC1AB, 0x8667 }, + { 0xC1AC, 0x87C0 }, + { 0xC1AD, 0x87D1 }, + { 0xC1AE, 0x87B3 }, + { 0xC1AF, 0x87D2 }, + { 0xC1B0, 0x87C6 }, + { 0xC1B1, 0x87AB }, + { 0xC1B2, 0x87BB }, + { 0xC1B3, 0x87BA }, + { 0xC1B4, 0x87C8 }, + { 0xC1B5, 0x87CB }, + { 0xC1B6, 0x893B }, + { 0xC1B7, 0x8936 }, + { 0xC1B8, 0x8944 }, + { 0xC1B9, 0x8938 }, + { 0xC1BA, 0x893D }, + { 0xC1BB, 0x89AC }, + { 0xC1BC, 0x8B0E }, + { 0xC1BD, 0x8B17 }, + { 0xC1BE, 0x8B19 }, + { 0xC1BF, 0x8B1B }, + { 0xC1C0, 0x8B0A }, + { 0xC1C1, 0x8B20 }, + { 0xC1C2, 0x8B1D }, + { 0xC1C3, 0x8B04 }, + { 0xC1C4, 0x8B10 }, + { 0xC1C5, 0x8C41 }, + { 0xC1C6, 0x8C3F }, + { 0xC1C7, 0x8C73 }, + { 0xC1C8, 0x8CFA }, + { 0xC1C9, 0x8CFD }, + { 0xC1CA, 0x8CFC }, + { 0xC1CB, 0x8CF8 }, + { 0xC1CC, 0x8CFB }, + { 0xC1CD, 0x8DA8 }, + { 0xC1CE, 0x8E49 }, + { 0xC1CF, 0x8E4B }, + { 0xC1D0, 0x8E48 }, + { 0xC1D1, 0x8E4A }, + { 0xC1D2, 0x8F44 }, + { 0xC1D3, 0x8F3E }, + { 0xC1D4, 0x8F42 }, + { 0xC1D5, 0x8F45 }, + { 0xC1D6, 0x8F3F }, + { 0xC1D7, 0x907F }, + { 0xC1D8, 0x907D }, + { 0xC1D9, 0x9084 }, + { 0xC1DA, 0x9081 }, + { 0xC1DB, 0x9082 }, + { 0xC1DC, 0x9080 }, + { 0xC1DD, 0x9139 }, + { 0xC1DE, 0x91A3 }, + { 0xC1DF, 0x919E }, + { 0xC1E0, 0x919C }, + { 0xC1E1, 0x934D }, + { 0xC1E2, 0x9382 }, + { 0xC1E3, 0x9328 }, + { 0xC1E4, 0x9375 }, + { 0xC1E5, 0x934A }, + { 0xC1E6, 0x9365 }, + { 0xC1E7, 0x934B }, + { 0xC1E8, 0x9318 }, + { 0xC1E9, 0x937E }, + { 0xC1EA, 0x936C }, + { 0xC1EB, 0x935B }, + { 0xC1EC, 0x9370 }, + { 0xC1ED, 0x935A }, + { 0xC1EE, 0x9354 }, + { 0xC1EF, 0x95CA }, + { 0xC1F0, 0x95CB }, + { 0xC1F1, 0x95CC }, + { 0xC1F2, 0x95C8 }, + { 0xC1F3, 0x95C6 }, + { 0xC1F4, 0x96B1 }, + { 0xC1F5, 0x96B8 }, + { 0xC1F6, 0x96D6 }, + { 0xC1F7, 0x971C }, + { 0xC1F8, 0x971E }, + { 0xC1F9, 0x97A0 }, + { 0xC1FA, 0x97D3 }, + { 0xC1FB, 0x9846 }, + { 0xC1FC, 0x98B6 }, + { 0xC1FD, 0x9935 }, + { 0xC1FE, 0x9A01 }, + { 0xC240, 0x99FF }, + { 0xC241, 0x9BAE }, + { 0xC242, 0x9BAB }, + { 0xC243, 0x9BAA }, + { 0xC244, 0x9BAD }, + { 0xC245, 0x9D3B }, + { 0xC246, 0x9D3F }, + { 0xC247, 0x9E8B }, + { 0xC248, 0x9ECF }, + { 0xC249, 0x9EDE }, + { 0xC24A, 0x9EDC }, + { 0xC24B, 0x9EDD }, + { 0xC24C, 0x9EDB }, + { 0xC24D, 0x9F3E }, + { 0xC24E, 0x9F4B }, + { 0xC24F, 0x53E2 }, + { 0xC250, 0x5695 }, + { 0xC251, 0x56AE }, + { 0xC252, 0x58D9 }, + { 0xC253, 0x58D8 }, + { 0xC254, 0x5B38 }, + { 0xC255, 0x5F5D }, + { 0xC256, 0x61E3 }, + { 0xC257, 0x6233 }, + { 0xC258, 0x64F4 }, + { 0xC259, 0x64F2 }, + { 0xC25A, 0x64FE }, + { 0xC25B, 0x6506 }, + { 0xC25C, 0x64FA }, + { 0xC25D, 0x64FB }, + { 0xC25E, 0x64F7 }, + { 0xC25F, 0x65B7 }, + { 0xC260, 0x66DC }, + { 0xC261, 0x6726 }, + { 0xC262, 0x6AB3 }, + { 0xC263, 0x6AAC }, + { 0xC264, 0x6AC3 }, + { 0xC265, 0x6ABB }, + { 0xC266, 0x6AB8 }, + { 0xC267, 0x6AC2 }, + { 0xC268, 0x6AAE }, + { 0xC269, 0x6AAF }, + { 0xC26A, 0x6B5F }, + { 0xC26B, 0x6B78 }, + { 0xC26C, 0x6BAF }, + { 0xC26D, 0x7009 }, + { 0xC26E, 0x700B }, + { 0xC26F, 0x6FFE }, + { 0xC270, 0x7006 }, + { 0xC271, 0x6FFA }, + { 0xC272, 0x7011 }, + { 0xC273, 0x700F }, + { 0xC274, 0x71FB }, + { 0xC275, 0x71FC }, + { 0xC276, 0x71FE }, + { 0xC277, 0x71F8 }, + { 0xC278, 0x7377 }, + { 0xC279, 0x7375 }, + { 0xC27A, 0x74A7 }, + { 0xC27B, 0x74BF }, + { 0xC27C, 0x7515 }, + { 0xC27D, 0x7656 }, + { 0xC27E, 0x7658 }, + { 0xC2A1, 0x7652 }, + { 0xC2A2, 0x77BD }, + { 0xC2A3, 0x77BF }, + { 0xC2A4, 0x77BB }, + { 0xC2A5, 0x77BC }, + { 0xC2A6, 0x790E }, + { 0xC2A7, 0x79AE }, + { 0xC2A8, 0x7A61 }, + { 0xC2A9, 0x7A62 }, + { 0xC2AA, 0x7A60 }, + { 0xC2AB, 0x7AC4 }, + { 0xC2AC, 0x7AC5 }, + { 0xC2AD, 0x7C2B }, + { 0xC2AE, 0x7C27 }, + { 0xC2AF, 0x7C2A }, + { 0xC2B0, 0x7C1E }, + { 0xC2B1, 0x7C23 }, + { 0xC2B2, 0x7C21 }, + { 0xC2B3, 0x7CE7 }, + { 0xC2B4, 0x7E54 }, + { 0xC2B5, 0x7E55 }, + { 0xC2B6, 0x7E5E }, + { 0xC2B7, 0x7E5A }, + { 0xC2B8, 0x7E61 }, + { 0xC2B9, 0x7E52 }, + { 0xC2BA, 0x7E59 }, + { 0xC2BB, 0x7F48 }, + { 0xC2BC, 0x7FF9 }, + { 0xC2BD, 0x7FFB }, + { 0xC2BE, 0x8077 }, + { 0xC2BF, 0x8076 }, + { 0xC2C0, 0x81CD }, + { 0xC2C1, 0x81CF }, + { 0xC2C2, 0x820A }, + { 0xC2C3, 0x85CF }, + { 0xC2C4, 0x85A9 }, + { 0xC2C5, 0x85CD }, + { 0xC2C6, 0x85D0 }, + { 0xC2C7, 0x85C9 }, + { 0xC2C8, 0x85B0 }, + { 0xC2C9, 0x85BA }, + { 0xC2CA, 0x85B9 }, + { 0xC2CB, 0x85A6 }, + { 0xC2CC, 0x87EF }, + { 0xC2CD, 0x87EC }, + { 0xC2CE, 0x87F2 }, + { 0xC2CF, 0x87E0 }, + { 0xC2D0, 0x8986 }, + { 0xC2D1, 0x89B2 }, + { 0xC2D2, 0x89F4 }, + { 0xC2D3, 0x8B28 }, + { 0xC2D4, 0x8B39 }, + { 0xC2D5, 0x8B2C }, + { 0xC2D6, 0x8B2B }, + { 0xC2D7, 0x8C50 }, + { 0xC2D8, 0x8D05 }, + { 0xC2D9, 0x8E59 }, + { 0xC2DA, 0x8E63 }, + { 0xC2DB, 0x8E66 }, + { 0xC2DC, 0x8E64 }, + { 0xC2DD, 0x8E5F }, + { 0xC2DE, 0x8E55 }, + { 0xC2DF, 0x8EC0 }, + { 0xC2E0, 0x8F49 }, + { 0xC2E1, 0x8F4D }, + { 0xC2E2, 0x9087 }, + { 0xC2E3, 0x9083 }, + { 0xC2E4, 0x9088 }, + { 0xC2E5, 0x91AB }, + { 0xC2E6, 0x91AC }, + { 0xC2E7, 0x91D0 }, + { 0xC2E8, 0x9394 }, + { 0xC2E9, 0x938A }, + { 0xC2EA, 0x9396 }, + { 0xC2EB, 0x93A2 }, + { 0xC2EC, 0x93B3 }, + { 0xC2ED, 0x93AE }, + { 0xC2EE, 0x93AC }, + { 0xC2EF, 0x93B0 }, + { 0xC2F0, 0x9398 }, + { 0xC2F1, 0x939A }, + { 0xC2F2, 0x9397 }, + { 0xC2F3, 0x95D4 }, + { 0xC2F4, 0x95D6 }, + { 0xC2F5, 0x95D0 }, + { 0xC2F6, 0x95D5 }, + { 0xC2F7, 0x96E2 }, + { 0xC2F8, 0x96DC }, + { 0xC2F9, 0x96D9 }, + { 0xC2FA, 0x96DB }, + { 0xC2FB, 0x96DE }, + { 0xC2FC, 0x9724 }, + { 0xC2FD, 0x97A3 }, + { 0xC2FE, 0x97A6 }, + { 0xC340, 0x97AD }, + { 0xC341, 0x97F9 }, + { 0xC342, 0x984D }, + { 0xC343, 0x984F }, + { 0xC344, 0x984C }, + { 0xC345, 0x984E }, + { 0xC346, 0x9853 }, + { 0xC347, 0x98BA }, + { 0xC348, 0x993E }, + { 0xC349, 0x993F }, + { 0xC34A, 0x993D }, + { 0xC34B, 0x992E }, + { 0xC34C, 0x99A5 }, + { 0xC34D, 0x9A0E }, + { 0xC34E, 0x9AC1 }, + { 0xC34F, 0x9B03 }, + { 0xC350, 0x9B06 }, + { 0xC351, 0x9B4F }, + { 0xC352, 0x9B4E }, + { 0xC353, 0x9B4D }, + { 0xC354, 0x9BCA }, + { 0xC355, 0x9BC9 }, + { 0xC356, 0x9BFD }, + { 0xC357, 0x9BC8 }, + { 0xC358, 0x9BC0 }, + { 0xC359, 0x9D51 }, + { 0xC35A, 0x9D5D }, + { 0xC35B, 0x9D60 }, + { 0xC35C, 0x9EE0 }, + { 0xC35D, 0x9F15 }, + { 0xC35E, 0x9F2C }, + { 0xC35F, 0x5133 }, + { 0xC360, 0x56A5 }, + { 0xC361, 0x58DE }, + { 0xC362, 0x58DF }, + { 0xC363, 0x58E2 }, + { 0xC364, 0x5BF5 }, + { 0xC365, 0x9F90 }, + { 0xC366, 0x5EEC }, + { 0xC367, 0x61F2 }, + { 0xC368, 0x61F7 }, + { 0xC369, 0x61F6 }, + { 0xC36A, 0x61F5 }, + { 0xC36B, 0x6500 }, + { 0xC36C, 0x650F }, + { 0xC36D, 0x66E0 }, + { 0xC36E, 0x66DD }, + { 0xC36F, 0x6AE5 }, + { 0xC370, 0x6ADD }, + { 0xC371, 0x6ADA }, + { 0xC372, 0x6AD3 }, + { 0xC373, 0x701B }, + { 0xC374, 0x701F }, + { 0xC375, 0x7028 }, + { 0xC376, 0x701A }, + { 0xC377, 0x701D }, + { 0xC378, 0x7015 }, + { 0xC379, 0x7018 }, + { 0xC37A, 0x7206 }, + { 0xC37B, 0x720D }, + { 0xC37C, 0x7258 }, + { 0xC37D, 0x72A2 }, + { 0xC37E, 0x7378 }, + { 0xC3A1, 0x737A }, + { 0xC3A2, 0x74BD }, + { 0xC3A3, 0x74CA }, + { 0xC3A4, 0x74E3 }, + { 0xC3A5, 0x7587 }, + { 0xC3A6, 0x7586 }, + { 0xC3A7, 0x765F }, + { 0xC3A8, 0x7661 }, + { 0xC3A9, 0x77C7 }, + { 0xC3AA, 0x7919 }, + { 0xC3AB, 0x79B1 }, + { 0xC3AC, 0x7A6B }, + { 0xC3AD, 0x7A69 }, + { 0xC3AE, 0x7C3E }, + { 0xC3AF, 0x7C3F }, + { 0xC3B0, 0x7C38 }, + { 0xC3B1, 0x7C3D }, + { 0xC3B2, 0x7C37 }, + { 0xC3B3, 0x7C40 }, + { 0xC3B4, 0x7E6B }, + { 0xC3B5, 0x7E6D }, + { 0xC3B6, 0x7E79 }, + { 0xC3B7, 0x7E69 }, + { 0xC3B8, 0x7E6A }, + { 0xC3B9, 0x7F85 }, + { 0xC3BA, 0x7E73 }, + { 0xC3BB, 0x7FB6 }, + { 0xC3BC, 0x7FB9 }, + { 0xC3BD, 0x7FB8 }, + { 0xC3BE, 0x81D8 }, + { 0xC3BF, 0x85E9 }, + { 0xC3C0, 0x85DD }, + { 0xC3C1, 0x85EA }, + { 0xC3C2, 0x85D5 }, + { 0xC3C3, 0x85E4 }, + { 0xC3C4, 0x85E5 }, + { 0xC3C5, 0x85F7 }, + { 0xC3C6, 0x87FB }, + { 0xC3C7, 0x8805 }, + { 0xC3C8, 0x880D }, + { 0xC3C9, 0x87F9 }, + { 0xC3CA, 0x87FE }, + { 0xC3CB, 0x8960 }, + { 0xC3CC, 0x895F }, + { 0xC3CD, 0x8956 }, + { 0xC3CE, 0x895E }, + { 0xC3CF, 0x8B41 }, + { 0xC3D0, 0x8B5C }, + { 0xC3D1, 0x8B58 }, + { 0xC3D2, 0x8B49 }, + { 0xC3D3, 0x8B5A }, + { 0xC3D4, 0x8B4E }, + { 0xC3D5, 0x8B4F }, + { 0xC3D6, 0x8B46 }, + { 0xC3D7, 0x8B59 }, + { 0xC3D8, 0x8D08 }, + { 0xC3D9, 0x8D0A }, + { 0xC3DA, 0x8E7C }, + { 0xC3DB, 0x8E72 }, + { 0xC3DC, 0x8E87 }, + { 0xC3DD, 0x8E76 }, + { 0xC3DE, 0x8E6C }, + { 0xC3DF, 0x8E7A }, + { 0xC3E0, 0x8E74 }, + { 0xC3E1, 0x8F54 }, + { 0xC3E2, 0x8F4E }, + { 0xC3E3, 0x8FAD }, + { 0xC3E4, 0x908A }, + { 0xC3E5, 0x908B }, + { 0xC3E6, 0x91B1 }, + { 0xC3E7, 0x91AE }, + { 0xC3E8, 0x93E1 }, + { 0xC3E9, 0x93D1 }, + { 0xC3EA, 0x93DF }, + { 0xC3EB, 0x93C3 }, + { 0xC3EC, 0x93C8 }, + { 0xC3ED, 0x93DC }, + { 0xC3EE, 0x93DD }, + { 0xC3EF, 0x93D6 }, + { 0xC3F0, 0x93E2 }, + { 0xC3F1, 0x93CD }, + { 0xC3F2, 0x93D8 }, + { 0xC3F3, 0x93E4 }, + { 0xC3F4, 0x93D7 }, + { 0xC3F5, 0x93E8 }, + { 0xC3F6, 0x95DC }, + { 0xC3F7, 0x96B4 }, + { 0xC3F8, 0x96E3 }, + { 0xC3F9, 0x972A }, + { 0xC3FA, 0x9727 }, + { 0xC3FB, 0x9761 }, + { 0xC3FC, 0x97DC }, + { 0xC3FD, 0x97FB }, + { 0xC3FE, 0x985E }, + { 0xC440, 0x9858 }, + { 0xC441, 0x985B }, + { 0xC442, 0x98BC }, + { 0xC443, 0x9945 }, + { 0xC444, 0x9949 }, + { 0xC445, 0x9A16 }, + { 0xC446, 0x9A19 }, + { 0xC447, 0x9B0D }, + { 0xC448, 0x9BE8 }, + { 0xC449, 0x9BE7 }, + { 0xC44A, 0x9BD6 }, + { 0xC44B, 0x9BDB }, + { 0xC44C, 0x9D89 }, + { 0xC44D, 0x9D61 }, + { 0xC44E, 0x9D72 }, + { 0xC44F, 0x9D6A }, + { 0xC450, 0x9D6C }, + { 0xC451, 0x9E92 }, + { 0xC452, 0x9E97 }, + { 0xC453, 0x9E93 }, + { 0xC454, 0x9EB4 }, + { 0xC455, 0x52F8 }, + { 0xC456, 0x56A8 }, + { 0xC457, 0x56B7 }, + { 0xC458, 0x56B6 }, + { 0xC459, 0x56B4 }, + { 0xC45A, 0x56BC }, + { 0xC45B, 0x58E4 }, + { 0xC45C, 0x5B40 }, + { 0xC45D, 0x5B43 }, + { 0xC45E, 0x5B7D }, + { 0xC45F, 0x5BF6 }, + { 0xC460, 0x5DC9 }, + { 0xC461, 0x61F8 }, + { 0xC462, 0x61FA }, + { 0xC463, 0x6518 }, + { 0xC464, 0x6514 }, + { 0xC465, 0x6519 }, + { 0xC466, 0x66E6 }, + { 0xC467, 0x6727 }, + { 0xC468, 0x6AEC }, + { 0xC469, 0x703E }, + { 0xC46A, 0x7030 }, + { 0xC46B, 0x7032 }, + { 0xC46C, 0x7210 }, + { 0xC46D, 0x737B }, + { 0xC46E, 0x74CF }, + { 0xC46F, 0x7662 }, + { 0xC470, 0x7665 }, + { 0xC471, 0x7926 }, + { 0xC472, 0x792A }, + { 0xC473, 0x792C }, + { 0xC474, 0x792B }, + { 0xC475, 0x7AC7 }, + { 0xC476, 0x7AF6 }, + { 0xC477, 0x7C4C }, + { 0xC478, 0x7C43 }, + { 0xC479, 0x7C4D }, + { 0xC47A, 0x7CEF }, + { 0xC47B, 0x7CF0 }, + { 0xC47C, 0x8FAE }, + { 0xC47D, 0x7E7D }, + { 0xC47E, 0x7E7C }, + { 0xC4A1, 0x7E82 }, + { 0xC4A2, 0x7F4C }, + { 0xC4A3, 0x8000 }, + { 0xC4A4, 0x81DA }, + { 0xC4A5, 0x8266 }, + { 0xC4A6, 0x85FB }, + { 0xC4A7, 0x85F9 }, + { 0xC4A8, 0x8611 }, + { 0xC4A9, 0x85FA }, + { 0xC4AA, 0x8606 }, + { 0xC4AB, 0x860B }, + { 0xC4AC, 0x8607 }, + { 0xC4AD, 0x860A }, + { 0xC4AE, 0x8814 }, + { 0xC4AF, 0x8815 }, + { 0xC4B0, 0x8964 }, + { 0xC4B1, 0x89BA }, + { 0xC4B2, 0x89F8 }, + { 0xC4B3, 0x8B70 }, + { 0xC4B4, 0x8B6C }, + { 0xC4B5, 0x8B66 }, + { 0xC4B6, 0x8B6F }, + { 0xC4B7, 0x8B5F }, + { 0xC4B8, 0x8B6B }, + { 0xC4B9, 0x8D0F }, + { 0xC4BA, 0x8D0D }, + { 0xC4BB, 0x8E89 }, + { 0xC4BC, 0x8E81 }, + { 0xC4BD, 0x8E85 }, + { 0xC4BE, 0x8E82 }, + { 0xC4BF, 0x91B4 }, + { 0xC4C0, 0x91CB }, + { 0xC4C1, 0x9418 }, + { 0xC4C2, 0x9403 }, + { 0xC4C3, 0x93FD }, + { 0xC4C4, 0x95E1 }, + { 0xC4C5, 0x9730 }, + { 0xC4C6, 0x98C4 }, + { 0xC4C7, 0x9952 }, + { 0xC4C8, 0x9951 }, + { 0xC4C9, 0x99A8 }, + { 0xC4CA, 0x9A2B }, + { 0xC4CB, 0x9A30 }, + { 0xC4CC, 0x9A37 }, + { 0xC4CD, 0x9A35 }, + { 0xC4CE, 0x9C13 }, + { 0xC4CF, 0x9C0D }, + { 0xC4D0, 0x9E79 }, + { 0xC4D1, 0x9EB5 }, + { 0xC4D2, 0x9EE8 }, + { 0xC4D3, 0x9F2F }, + { 0xC4D4, 0x9F5F }, + { 0xC4D5, 0x9F63 }, + { 0xC4D6, 0x9F61 }, + { 0xC4D7, 0x5137 }, + { 0xC4D8, 0x5138 }, + { 0xC4D9, 0x56C1 }, + { 0xC4DA, 0x56C0 }, + { 0xC4DB, 0x56C2 }, + { 0xC4DC, 0x5914 }, + { 0xC4DD, 0x5C6C }, + { 0xC4DE, 0x5DCD }, + { 0xC4DF, 0x61FC }, + { 0xC4E0, 0x61FE }, + { 0xC4E1, 0x651D }, + { 0xC4E2, 0x651C }, + { 0xC4E3, 0x6595 }, + { 0xC4E4, 0x66E9 }, + { 0xC4E5, 0x6AFB }, + { 0xC4E6, 0x6B04 }, + { 0xC4E7, 0x6AFA }, + { 0xC4E8, 0x6BB2 }, + { 0xC4E9, 0x704C }, + { 0xC4EA, 0x721B }, + { 0xC4EB, 0x72A7 }, + { 0xC4EC, 0x74D6 }, + { 0xC4ED, 0x74D4 }, + { 0xC4EE, 0x7669 }, + { 0xC4EF, 0x77D3 }, + { 0xC4F0, 0x7C50 }, + { 0xC4F1, 0x7E8F }, + { 0xC4F2, 0x7E8C }, + { 0xC4F3, 0x7FBC }, + { 0xC4F4, 0x8617 }, + { 0xC4F5, 0x862D }, + { 0xC4F6, 0x861A }, + { 0xC4F7, 0x8823 }, + { 0xC4F8, 0x8822 }, + { 0xC4F9, 0x8821 }, + { 0xC4FA, 0x881F }, + { 0xC4FB, 0x896A }, + { 0xC4FC, 0x896C }, + { 0xC4FD, 0x89BD }, + { 0xC4FE, 0x8B74 }, + { 0xC540, 0x8B77 }, + { 0xC541, 0x8B7D }, + { 0xC542, 0x8D13 }, + { 0xC543, 0x8E8A }, + { 0xC544, 0x8E8D }, + { 0xC545, 0x8E8B }, + { 0xC546, 0x8F5F }, + { 0xC547, 0x8FAF }, + { 0xC548, 0x91BA }, + { 0xC549, 0x942E }, + { 0xC54A, 0x9433 }, + { 0xC54B, 0x9435 }, + { 0xC54C, 0x943A }, + { 0xC54D, 0x9438 }, + { 0xC54E, 0x9432 }, + { 0xC54F, 0x942B }, + { 0xC550, 0x95E2 }, + { 0xC551, 0x9738 }, + { 0xC552, 0x9739 }, + { 0xC553, 0x9732 }, + { 0xC554, 0x97FF }, + { 0xC555, 0x9867 }, + { 0xC556, 0x9865 }, + { 0xC557, 0x9957 }, + { 0xC558, 0x9A45 }, + { 0xC559, 0x9A43 }, + { 0xC55A, 0x9A40 }, + { 0xC55B, 0x9A3E }, + { 0xC55C, 0x9ACF }, + { 0xC55D, 0x9B54 }, + { 0xC55E, 0x9B51 }, + { 0xC55F, 0x9C2D }, + { 0xC560, 0x9C25 }, + { 0xC561, 0x9DAF }, + { 0xC562, 0x9DB4 }, + { 0xC563, 0x9DC2 }, + { 0xC564, 0x9DB8 }, + { 0xC565, 0x9E9D }, + { 0xC566, 0x9EEF }, + { 0xC567, 0x9F19 }, + { 0xC568, 0x9F5C }, + { 0xC569, 0x9F66 }, + { 0xC56A, 0x9F67 }, + { 0xC56B, 0x513C }, + { 0xC56C, 0x513B }, + { 0xC56D, 0x56C8 }, + { 0xC56E, 0x56CA }, + { 0xC56F, 0x56C9 }, + { 0xC570, 0x5B7F }, + { 0xC571, 0x5DD4 }, + { 0xC572, 0x5DD2 }, + { 0xC573, 0x5F4E }, + { 0xC574, 0x61FF }, + { 0xC575, 0x6524 }, + { 0xC576, 0x6B0A }, + { 0xC577, 0x6B61 }, + { 0xC578, 0x7051 }, + { 0xC579, 0x7058 }, + { 0xC57A, 0x7380 }, + { 0xC57B, 0x74E4 }, + { 0xC57C, 0x758A }, + { 0xC57D, 0x766E }, + { 0xC57E, 0x766C }, + { 0xC5A1, 0x79B3 }, + { 0xC5A2, 0x7C60 }, + { 0xC5A3, 0x7C5F }, + { 0xC5A4, 0x807E }, + { 0xC5A5, 0x807D }, + { 0xC5A6, 0x81DF }, + { 0xC5A7, 0x8972 }, + { 0xC5A8, 0x896F }, + { 0xC5A9, 0x89FC }, + { 0xC5AA, 0x8B80 }, + { 0xC5AB, 0x8D16 }, + { 0xC5AC, 0x8D17 }, + { 0xC5AD, 0x8E91 }, + { 0xC5AE, 0x8E93 }, + { 0xC5AF, 0x8F61 }, + { 0xC5B0, 0x9148 }, + { 0xC5B1, 0x9444 }, + { 0xC5B2, 0x9451 }, + { 0xC5B3, 0x9452 }, + { 0xC5B4, 0x973D }, + { 0xC5B5, 0x973E }, + { 0xC5B6, 0x97C3 }, + { 0xC5B7, 0x97C1 }, + { 0xC5B8, 0x986B }, + { 0xC5B9, 0x9955 }, + { 0xC5BA, 0x9A55 }, + { 0xC5BB, 0x9A4D }, + { 0xC5BC, 0x9AD2 }, + { 0xC5BD, 0x9B1A }, + { 0xC5BE, 0x9C49 }, + { 0xC5BF, 0x9C31 }, + { 0xC5C0, 0x9C3E }, + { 0xC5C1, 0x9C3B }, + { 0xC5C2, 0x9DD3 }, + { 0xC5C3, 0x9DD7 }, + { 0xC5C4, 0x9F34 }, + { 0xC5C5, 0x9F6C }, + { 0xC5C6, 0x9F6A }, + { 0xC5C7, 0x9F94 }, + { 0xC5C8, 0x56CC }, + { 0xC5C9, 0x5DD6 }, + { 0xC5CA, 0x6200 }, + { 0xC5CB, 0x6523 }, + { 0xC5CC, 0x652B }, + { 0xC5CD, 0x652A }, + { 0xC5CE, 0x66EC }, + { 0xC5CF, 0x6B10 }, + { 0xC5D0, 0x74DA }, + { 0xC5D1, 0x7ACA }, + { 0xC5D2, 0x7C64 }, + { 0xC5D3, 0x7C63 }, + { 0xC5D4, 0x7C65 }, + { 0xC5D5, 0x7E93 }, + { 0xC5D6, 0x7E96 }, + { 0xC5D7, 0x7E94 }, + { 0xC5D8, 0x81E2 }, + { 0xC5D9, 0x8638 }, + { 0xC5DA, 0x863F }, + { 0xC5DB, 0x8831 }, + { 0xC5DC, 0x8B8A }, + { 0xC5DD, 0x9090 }, + { 0xC5DE, 0x908F }, + { 0xC5DF, 0x9463 }, + { 0xC5E0, 0x9460 }, + { 0xC5E1, 0x9464 }, + { 0xC5E2, 0x9768 }, + { 0xC5E3, 0x986F }, + { 0xC5E4, 0x995C }, + { 0xC5E5, 0x9A5A }, + { 0xC5E6, 0x9A5B }, + { 0xC5E7, 0x9A57 }, + { 0xC5E8, 0x9AD3 }, + { 0xC5E9, 0x9AD4 }, + { 0xC5EA, 0x9AD1 }, + { 0xC5EB, 0x9C54 }, + { 0xC5EC, 0x9C57 }, + { 0xC5ED, 0x9C56 }, + { 0xC5EE, 0x9DE5 }, + { 0xC5EF, 0x9E9F }, + { 0xC5F0, 0x9EF4 }, + { 0xC5F1, 0x56D1 }, + { 0xC5F2, 0x58E9 }, + { 0xC5F3, 0x652C }, + { 0xC5F4, 0x705E }, + { 0xC5F5, 0x7671 }, + { 0xC5F6, 0x7672 }, + { 0xC5F7, 0x77D7 }, + { 0xC5F8, 0x7F50 }, + { 0xC5F9, 0x7F88 }, + { 0xC5FA, 0x8836 }, + { 0xC5FB, 0x8839 }, + { 0xC5FC, 0x8862 }, + { 0xC5FD, 0x8B93 }, + { 0xC5FE, 0x8B92 }, + { 0xC640, 0x8B96 }, + { 0xC641, 0x8277 }, + { 0xC642, 0x8D1B }, + { 0xC643, 0x91C0 }, + { 0xC644, 0x946A }, + { 0xC645, 0x9742 }, + { 0xC646, 0x9748 }, + { 0xC647, 0x9744 }, + { 0xC648, 0x97C6 }, + { 0xC649, 0x9870 }, + { 0xC64A, 0x9A5F }, + { 0xC64B, 0x9B22 }, + { 0xC64C, 0x9B58 }, + { 0xC64D, 0x9C5F }, + { 0xC64E, 0x9DF9 }, + { 0xC64F, 0x9DFA }, + { 0xC650, 0x9E7C }, + { 0xC651, 0x9E7D }, + { 0xC652, 0x9F07 }, + { 0xC653, 0x9F77 }, + { 0xC654, 0x9F72 }, + { 0xC655, 0x5EF3 }, + { 0xC656, 0x6B16 }, + { 0xC657, 0x7063 }, + { 0xC658, 0x7C6C }, + { 0xC659, 0x7C6E }, + { 0xC65A, 0x883B }, + { 0xC65B, 0x89C0 }, + { 0xC65C, 0x8EA1 }, + { 0xC65D, 0x91C1 }, + { 0xC65E, 0x9472 }, + { 0xC65F, 0x9470 }, + { 0xC660, 0x9871 }, + { 0xC661, 0x995E }, + { 0xC662, 0x9AD6 }, + { 0xC663, 0x9B23 }, + { 0xC664, 0x9ECC }, + { 0xC665, 0x7064 }, + { 0xC666, 0x77DA }, + { 0xC667, 0x8B9A }, + { 0xC668, 0x9477 }, + { 0xC669, 0x97C9 }, + { 0xC66A, 0x9A62 }, + { 0xC66B, 0x9A65 }, + { 0xC66C, 0x7E9C }, + { 0xC66D, 0x8B9C }, + { 0xC66E, 0x8EAA }, + { 0xC66F, 0x91C5 }, + { 0xC670, 0x947D }, + { 0xC671, 0x947E }, + { 0xC672, 0x947C }, + { 0xC673, 0x9C77 }, + { 0xC674, 0x9C78 }, + { 0xC675, 0x9EF7 }, + { 0xC676, 0x8C54 }, + { 0xC677, 0x947F }, + { 0xC678, 0x9E1A }, + { 0xC679, 0x7228 }, + { 0xC67A, 0x9A6A }, + { 0xC67B, 0x9B31 }, + { 0xC67C, 0x9E1B }, + { 0xC67D, 0x9E1E }, + { 0xC67E, 0x7C72 }, + { 0xC6A1, 0x30FE }, + { 0xC6A2, 0x309D }, + { 0xC6A3, 0x309E }, + { 0xC6A4, 0x3005 }, + { 0xC6A5, 0x3041 }, + { 0xC6A6, 0x3042 }, + { 0xC6A7, 0x3043 }, + { 0xC6A8, 0x3044 }, + { 0xC6A9, 0x3045 }, + { 0xC6AA, 0x3046 }, + { 0xC6AB, 0x3047 }, + { 0xC6AC, 0x3048 }, + { 0xC6AD, 0x3049 }, + { 0xC6AE, 0x304A }, + { 0xC6AF, 0x304B }, + { 0xC6B0, 0x304C }, + { 0xC6B1, 0x304D }, + { 0xC6B2, 0x304E }, + { 0xC6B3, 0x304F }, + { 0xC6B4, 0x3050 }, + { 0xC6B5, 0x3051 }, + { 0xC6B6, 0x3052 }, + { 0xC6B7, 0x3053 }, + { 0xC6B8, 0x3054 }, + { 0xC6B9, 0x3055 }, + { 0xC6BA, 0x3056 }, + { 0xC6BB, 0x3057 }, + { 0xC6BC, 0x3058 }, + { 0xC6BD, 0x3059 }, + { 0xC6BE, 0x305A }, + { 0xC6BF, 0x305B }, + { 0xC6C0, 0x305C }, + { 0xC6C1, 0x305D }, + { 0xC6C2, 0x305E }, + { 0xC6C3, 0x305F }, + { 0xC6C4, 0x3060 }, + { 0xC6C5, 0x3061 }, + { 0xC6C6, 0x3062 }, + { 0xC6C7, 0x3063 }, + { 0xC6C8, 0x3064 }, + { 0xC6C9, 0x3065 }, + { 0xC6CA, 0x3066 }, + { 0xC6CB, 0x3067 }, + { 0xC6CC, 0x3068 }, + { 0xC6CD, 0x3069 }, + { 0xC6CE, 0x306A }, + { 0xC6CF, 0x306B }, + { 0xC6D0, 0x306C }, + { 0xC6D1, 0x306D }, + { 0xC6D2, 0x306E }, + { 0xC6D3, 0x306F }, + { 0xC6D4, 0x3070 }, + { 0xC6D5, 0x3071 }, + { 0xC6D6, 0x3072 }, + { 0xC6D7, 0x3073 }, + { 0xC6D8, 0x3074 }, + { 0xC6D9, 0x3075 }, + { 0xC6DA, 0x3076 }, + { 0xC6DB, 0x3077 }, + { 0xC6DC, 0x3078 }, + { 0xC6DD, 0x3079 }, + { 0xC6DE, 0x307A }, + { 0xC6DF, 0x307B }, + { 0xC6E0, 0x307C }, + { 0xC6E1, 0x307D }, + { 0xC6E2, 0x307E }, + { 0xC6E3, 0x307F }, + { 0xC6E4, 0x3080 }, + { 0xC6E5, 0x3081 }, + { 0xC6E6, 0x3082 }, + { 0xC6E7, 0x3083 }, + { 0xC6E8, 0x3084 }, + { 0xC6E9, 0x3085 }, + { 0xC6EA, 0x3086 }, + { 0xC6EB, 0x3087 }, + { 0xC6EC, 0x3088 }, + { 0xC6ED, 0x3089 }, + { 0xC6EE, 0x308A }, + { 0xC6EF, 0x308B }, + { 0xC6F0, 0x308C }, + { 0xC6F1, 0x308D }, + { 0xC6F2, 0x308E }, + { 0xC6F3, 0x308F }, + { 0xC6F4, 0x3090 }, + { 0xC6F5, 0x3091 }, + { 0xC6F6, 0x3092 }, + { 0xC6F7, 0x3093 }, + { 0xC6F8, 0x30A1 }, + { 0xC6F9, 0x30A2 }, + { 0xC6FA, 0x30A3 }, + { 0xC6FB, 0x30A4 }, + { 0xC6FC, 0x30A5 }, + { 0xC6FD, 0x30A6 }, + { 0xC6FE, 0x30A7 }, + { 0xC740, 0x30A8 }, + { 0xC741, 0x30A9 }, + { 0xC742, 0x30AA }, + { 0xC743, 0x30AB }, + { 0xC744, 0x30AC }, + { 0xC745, 0x30AD }, + { 0xC746, 0x30AE }, + { 0xC747, 0x30AF }, + { 0xC748, 0x30B0 }, + { 0xC749, 0x30B1 }, + { 0xC74A, 0x30B2 }, + { 0xC74B, 0x30B3 }, + { 0xC74C, 0x30B4 }, + { 0xC74D, 0x30B5 }, + { 0xC74E, 0x30B6 }, + { 0xC74F, 0x30B7 }, + { 0xC750, 0x30B8 }, + { 0xC751, 0x30B9 }, + { 0xC752, 0x30BA }, + { 0xC753, 0x30BB }, + { 0xC754, 0x30BC }, + { 0xC755, 0x30BD }, + { 0xC756, 0x30BE }, + { 0xC757, 0x30BF }, + { 0xC758, 0x30C0 }, + { 0xC759, 0x30C1 }, + { 0xC75A, 0x30C2 }, + { 0xC75B, 0x30C3 }, + { 0xC75C, 0x30C4 }, + { 0xC75D, 0x30C5 }, + { 0xC75E, 0x30C6 }, + { 0xC75F, 0x30C7 }, + { 0xC760, 0x30C8 }, + { 0xC761, 0x30C9 }, + { 0xC762, 0x30CA }, + { 0xC763, 0x30CB }, + { 0xC764, 0x30CC }, + { 0xC765, 0x30CD }, + { 0xC766, 0x30CE }, + { 0xC767, 0x30CF }, + { 0xC768, 0x30D0 }, + { 0xC769, 0x30D1 }, + { 0xC76A, 0x30D2 }, + { 0xC76B, 0x30D3 }, + { 0xC76C, 0x30D4 }, + { 0xC76D, 0x30D5 }, + { 0xC76E, 0x30D6 }, + { 0xC76F, 0x30D7 }, + { 0xC770, 0x30D8 }, + { 0xC771, 0x30D9 }, + { 0xC772, 0x30DA }, + { 0xC773, 0x30DB }, + { 0xC774, 0x30DC }, + { 0xC775, 0x30DD }, + { 0xC776, 0x30DE }, + { 0xC777, 0x30DF }, + { 0xC778, 0x30E0 }, + { 0xC779, 0x30E1 }, + { 0xC77A, 0x30E2 }, + { 0xC77B, 0x30E3 }, + { 0xC77C, 0x30E4 }, + { 0xC77D, 0x30E5 }, + { 0xC77E, 0x30E6 }, + { 0xC7A1, 0x30E7 }, + { 0xC7A2, 0x30E8 }, + { 0xC7A3, 0x30E9 }, + { 0xC7A4, 0x30EA }, + { 0xC7A5, 0x30EB }, + { 0xC7A6, 0x30EC }, + { 0xC7A7, 0x30ED }, + { 0xC7A8, 0x30EE }, + { 0xC7A9, 0x30EF }, + { 0xC7AA, 0x30F0 }, + { 0xC7AB, 0x30F1 }, + { 0xC7AC, 0x30F2 }, + { 0xC7AD, 0x30F3 }, + { 0xC7AE, 0x30F4 }, + { 0xC7AF, 0x30F5 }, + { 0xC7B0, 0x30F6 }, + { 0xC7B1, 0x0414 }, + { 0xC7B2, 0x0415 }, + { 0xC7B3, 0x0401 }, + { 0xC7B4, 0x0416 }, + { 0xC7B5, 0x0417 }, + { 0xC7B6, 0x0418 }, + { 0xC7B7, 0x0419 }, + { 0xC7B8, 0x041A }, + { 0xC7B9, 0x041B }, + { 0xC7BA, 0x041C }, + { 0xC7BB, 0x0423 }, + { 0xC7BC, 0x0424 }, + { 0xC7BD, 0x0425 }, + { 0xC7BE, 0x0426 }, + { 0xC7BF, 0x0427 }, + { 0xC7C0, 0x0428 }, + { 0xC7C1, 0x0429 }, + { 0xC7C2, 0x042A }, + { 0xC7C3, 0x042B }, + { 0xC7C4, 0x042C }, + { 0xC7C5, 0x042D },{ 0xC7C6, 0x042E }, + { 0xC7C7, 0x042F }, + { 0xC7C8, 0x0430 }, + { 0xC7C9, 0x0431 }, + { 0xC7CA, 0x0432 }, + { 0xC7CB, 0x0433 }, + { 0xC7CC, 0x0434 }, + { 0xC7CD, 0x0435 }, + { 0xC7CE, 0x0451 }, + { 0xC7CF, 0x0436 }, + { 0xC7D0, 0x0437 }, + { 0xC7D1, 0x0438 }, + { 0xC7D2, 0x0439 }, + { 0xC7D3, 0x043A }, + { 0xC7D4, 0x043B }, + { 0xC7D5, 0x043C }, + { 0xC7D6, 0x043D }, + { 0xC7D7, 0x043E }, + { 0xC7D8, 0x043F }, + { 0xC7D9, 0x0440 }, + { 0xC7DA, 0x0441 }, + { 0xC7DB, 0x0442 }, + { 0xC7DC, 0x0443 }, + { 0xC7DD, 0x0444 }, + { 0xC7DE, 0x0445 }, + { 0xC7DF, 0x0446 }, + { 0xC7E0, 0x0447 }, + { 0xC7E1, 0x0448 }, + { 0xC7E2, 0x0449 }, + { 0xC7E3, 0x044A }, + { 0xC7E4, 0x044B }, + { 0xC7E5, 0x044C }, + { 0xC7E6, 0x044D }, + { 0xC7E7, 0x044E }, + { 0xC7E8, 0x044F }, + { 0xC7E9, 0x2460 }, + { 0xC7EA, 0x2461 }, + { 0xC7EB, 0x2462 }, + { 0xC7EC, 0x2463 }, + { 0xC7ED, 0x2464 }, + { 0xC7EE, 0x2465 }, + { 0xC7EF, 0x2466 }, + { 0xC7F0, 0x2467 }, + { 0xC7F1, 0x2468 }, + { 0xC7F2, 0x2469 }, + { 0xC7F3, 0x2474 }, + { 0xC7F4, 0x2475 }, + { 0xC7F5, 0x2476 }, + { 0xC7F6, 0x2477 }, + { 0xC7F7, 0x2478 }, + { 0xC7F8, 0x2479 }, + { 0xC7F9, 0x247A }, + { 0xC7FA, 0x247B }, + { 0xC7FB, 0x247C }, + { 0xC7FC, 0x247D }, + { 0xC940, 0x4E42 }, + { 0xC941, 0x4E5C }, + { 0xC942, 0x51F5 }, + { 0xC943, 0x531A }, + { 0xC944, 0x5382 }, + { 0xC945, 0x4E07 }, + { 0xC946, 0x4E0C }, + { 0xC947, 0x4E47 }, + { 0xC948, 0x4E8D }, + { 0xC949, 0x56D7 }, + { 0xC94A, 0xFA0C }, + { 0xC94B, 0x5C6E }, + { 0xC94C, 0x5F73 }, + { 0xC94D, 0x4E0F }, + { 0xC94E, 0x5187 }, + { 0xC94F, 0x4E0E }, + { 0xC950, 0x4E2E }, + { 0xC951, 0x4E93 }, + { 0xC952, 0x4EC2 }, + { 0xC953, 0x4EC9 }, + { 0xC954, 0x4EC8 }, + { 0xC955, 0x5198 }, + { 0xC956, 0x52FC }, + { 0xC957, 0x536C }, + { 0xC958, 0x53B9 }, + { 0xC959, 0x5720 }, + { 0xC95A, 0x5903 }, + { 0xC95B, 0x592C }, + { 0xC95C, 0x5C10 }, + { 0xC95D, 0x5DFF }, + { 0xC95E, 0x65E1 }, + { 0xC95F, 0x6BB3 }, + { 0xC960, 0x6BCC }, + { 0xC961, 0x6C14 }, + { 0xC962, 0x723F }, + { 0xC963, 0x4E31 }, + { 0xC964, 0x4E3C }, + { 0xC965, 0x4EE8 }, + { 0xC966, 0x4EDC }, + { 0xC967, 0x4EE9 }, + { 0xC968, 0x4EE1 }, + { 0xC969, 0x4EDD }, + { 0xC96A, 0x4EDA }, + { 0xC96B, 0x520C }, + { 0xC96C, 0x531C }, + { 0xC96D, 0x534C }, + { 0xC96E, 0x5722 }, + { 0xC96F, 0x5723 }, + { 0xC970, 0x5917 }, + { 0xC971, 0x592F }, + { 0xC972, 0x5B81 }, + { 0xC973, 0x5B84 }, + { 0xC974, 0x5C12 }, + { 0xC975, 0x5C3B }, + { 0xC976, 0x5C74 }, + { 0xC977, 0x5C73 }, + { 0xC978, 0x5E04 }, + { 0xC979, 0x5E80 }, + { 0xC97A, 0x5E82 }, + { 0xC97B, 0x5FC9 }, + { 0xC97C, 0x6209 }, + { 0xC97D, 0x6250 }, + { 0xC97E, 0x6C15 }, + { 0xC9A1, 0x6C36 }, + { 0xC9A2, 0x6C43 }, + { 0xC9A3, 0x6C3F }, + { 0xC9A4, 0x6C3B }, + { 0xC9A5, 0x72AE }, + { 0xC9A6, 0x72B0 }, + { 0xC9A7, 0x738A }, + { 0xC9A8, 0x79B8 }, + { 0xC9A9, 0x808A }, + { 0xC9AA, 0x961E }, + { 0xC9AB, 0x4F0E }, + { 0xC9AC, 0x4F18 }, + { 0xC9AD, 0x4F2C }, + { 0xC9AE, 0x4EF5 }, + { 0xC9AF, 0x4F14 }, + { 0xC9B0, 0x4EF1 }, + { 0xC9B1, 0x4F00 }, + { 0xC9B2, 0x4EF7 }, + { 0xC9B3, 0x4F08 }, + { 0xC9B4, 0x4F1D }, + { 0xC9B5, 0x4F02 }, + { 0xC9B6, 0x4F05 }, + { 0xC9B7, 0x4F22 }, + { 0xC9B8, 0x4F13 }, + { 0xC9B9, 0x4F04 }, + { 0xC9BA, 0x4EF4 }, + { 0xC9BB, 0x4F12 }, + { 0xC9BC, 0x51B1 }, + { 0xC9BD, 0x5213 }, + { 0xC9BE, 0x5209 }, + { 0xC9BF, 0x5210 }, + { 0xC9C0, 0x52A6 }, + { 0xC9C1, 0x5322 }, + { 0xC9C2, 0x531F }, + { 0xC9C3, 0x534D }, + { 0xC9C4, 0x538A }, + { 0xC9C5, 0x5407 }, + { 0xC9C6, 0x56E1 }, + { 0xC9C7, 0x56DF }, + { 0xC9C8, 0x572E }, + { 0xC9C9, 0x572A }, + { 0xC9CA, 0x5734 }, + { 0xC9CB, 0x593C }, + { 0xC9CC, 0x5980 }, + { 0xC9CD, 0x597C }, + { 0xC9CE, 0x5985 }, + { 0xC9CF, 0x597B }, + { 0xC9D0, 0x597E }, + { 0xC9D1, 0x5977 }, + { 0xC9D2, 0x597F }, + { 0xC9D3, 0x5B56 }, + { 0xC9D4, 0x5C15 }, + { 0xC9D5, 0x5C25 }, + { 0xC9D6, 0x5C7C }, + { 0xC9D7, 0x5C7A }, + { 0xC9D8, 0x5C7B }, + { 0xC9D9, 0x5C7E }, + { 0xC9DA, 0x5DDF }, + { 0xC9DB, 0x5E75 }, + { 0xC9DC, 0x5E84 }, + { 0xC9DD, 0x5F02 }, + { 0xC9DE, 0x5F1A }, + { 0xC9DF, 0x5F74 }, + { 0xC9E0, 0x5FD5 }, + { 0xC9E1, 0x5FD4 }, + { 0xC9E2, 0x5FCF }, + { 0xC9E3, 0x625C }, + { 0xC9E4, 0x625E }, + { 0xC9E5, 0x6264 }, + { 0xC9E6, 0x6261 }, + { 0xC9E7, 0x6266 }, + { 0xC9E8, 0x6262 }, + { 0xC9E9, 0x6259 }, + { 0xC9EA, 0x6260 }, + { 0xC9EB, 0x625A }, + { 0xC9EC, 0x6265 }, + { 0xC9ED, 0x65EF }, + { 0xC9EE, 0x65EE }, + { 0xC9EF, 0x673E }, + { 0xC9F0, 0x6739 }, + { 0xC9F1, 0x6738 }, + { 0xC9F2, 0x673B }, + { 0xC9F3, 0x673A }, + { 0xC9F4, 0x673F }, + { 0xC9F5, 0x673C }, + { 0xC9F6, 0x6733 }, + { 0xC9F7, 0x6C18 }, + { 0xC9F8, 0x6C46 }, + { 0xC9F9, 0x6C52 }, + { 0xC9FA, 0x6C5C }, + { 0xC9FB, 0x6C4F }, + { 0xC9FC, 0x6C4A }, + { 0xC9FD, 0x6C54 }, + { 0xC9FE, 0x6C4B }, + { 0xCA40, 0x6C4C }, + { 0xCA41, 0x7071 }, + { 0xCA42, 0x725E }, + { 0xCA43, 0x72B4 }, + { 0xCA44, 0x72B5 }, + { 0xCA45, 0x738E }, + { 0xCA46, 0x752A }, + { 0xCA47, 0x767F }, + { 0xCA48, 0x7A75 }, + { 0xCA49, 0x7F51 }, + { 0xCA4A, 0x8278 }, + { 0xCA4B, 0x827C }, + { 0xCA4C, 0x8280 }, + { 0xCA4D, 0x827D }, + { 0xCA4E, 0x827F }, + { 0xCA4F, 0x864D }, + { 0xCA50, 0x897E }, + { 0xCA51, 0x9099 }, + { 0xCA52, 0x9097 }, + { 0xCA53, 0x9098 }, + { 0xCA54, 0x909B }, + { 0xCA55, 0x9094 }, + { 0xCA56, 0x9622 }, + { 0xCA57, 0x9624 }, + { 0xCA58, 0x9620 }, + { 0xCA59, 0x9623 }, + { 0xCA5A, 0x4F56 }, + { 0xCA5B, 0x4F3B }, + { 0xCA5C, 0x4F62 }, + { 0xCA5D, 0x4F49 }, + { 0xCA5E, 0x4F53 }, + { 0xCA5F, 0x4F64 }, + { 0xCA60, 0x4F3E }, + { 0xCA61, 0x4F67 }, + { 0xCA62, 0x4F52 }, + { 0xCA63, 0x4F5F }, + { 0xCA64, 0x4F41 }, + { 0xCA65, 0x4F58 }, + { 0xCA66, 0x4F2D }, + { 0xCA67, 0x4F33 }, + { 0xCA68, 0x4F3F }, + { 0xCA69, 0x4F61 }, + { 0xCA6A, 0x518F }, + { 0xCA6B, 0x51B9 }, + { 0xCA6C, 0x521C }, + { 0xCA6D, 0x521E }, + { 0xCA6E, 0x5221 }, + { 0xCA6F, 0x52AD }, + { 0xCA70, 0x52AE }, + { 0xCA71, 0x5309 }, + { 0xCA72, 0x5363 }, + { 0xCA73, 0x5372 }, + { 0xCA74, 0x538E }, + { 0xCA75, 0x538F }, + { 0xCA76, 0x5430 }, + { 0xCA77, 0x5437 }, + { 0xCA78, 0x542A }, + { 0xCA79, 0x5454 }, + { 0xCA7A, 0x5445 }, + { 0xCA7B, 0x5419 }, + { 0xCA7C, 0x541C }, + { 0xCA7D, 0x5425 }, + { 0xCA7E, 0x5418 }, + { 0xCAA1, 0x543D }, + { 0xCAA2, 0x544F }, + { 0xCAA3, 0x5441 }, + { 0xCAA4, 0x5428 }, + { 0xCAA5, 0x5424 }, + { 0xCAA6, 0x5447 }, + { 0xCAA7, 0x56EE }, + { 0xCAA8, 0x56E7 }, + { 0xCAA9, 0x56E5 }, + { 0xCAAA, 0x5741 }, + { 0xCAAB, 0x5745 }, + { 0xCAAC, 0x574C }, + { 0xCAAD, 0x5749 }, + { 0xCAAE, 0x574B }, + { 0xCAAF, 0x5752 }, + { 0xCAB0, 0x5906 }, + { 0xCAB1, 0x5940 }, + { 0xCAB2, 0x59A6 }, + { 0xCAB3, 0x5998 }, + { 0xCAB4, 0x59A0 }, + { 0xCAB5, 0x5997 }, + { 0xCAB6, 0x598E }, + { 0xCAB7, 0x59A2 }, + { 0xCAB8, 0x5990 }, + { 0xCAB9, 0x598F }, + { 0xCABA, 0x59A7 }, + { 0xCABB, 0x59A1 }, + { 0xCABC, 0x5B8E }, + { 0xCABD, 0x5B92 }, + { 0xCABE, 0x5C28 }, + { 0xCABF, 0x5C2A }, + { 0xCAC0, 0x5C8D }, + { 0xCAC1, 0x5C8F }, + { 0xCAC2, 0x5C88 }, + { 0xCAC3, 0x5C8B }, + { 0xCAC4, 0x5C89 }, + { 0xCAC5, 0x5C92 }, + { 0xCAC6, 0x5C8A }, + { 0xCAC7, 0x5C86 }, + { 0xCAC8, 0x5C93 }, + { 0xCAC9, 0x5C95 }, + { 0xCACA, 0x5DE0 }, + { 0xCACB, 0x5E0A }, + { 0xCACC, 0x5E0E }, + { 0xCACD, 0x5E8B }, + { 0xCACE, 0x5E89 }, + { 0xCACF, 0x5E8C }, + { 0xCAD0, 0x5E88 }, + { 0xCAD1, 0x5E8D }, + { 0xCAD2, 0x5F05 }, + { 0xCAD3, 0x5F1D }, + { 0xCAD4, 0x5F78 }, + { 0xCAD5, 0x5F76 }, + { 0xCAD6, 0x5FD2 }, + { 0xCAD7, 0x5FD1 }, + { 0xCAD8, 0x5FD0 }, + { 0xCAD9, 0x5FED }, + { 0xCADA, 0x5FE8 }, + { 0xCADB, 0x5FEE }, + { 0xCADC, 0x5FF3 }, + { 0xCADD, 0x5FE1 }, + { 0xCADE, 0x5FE4 }, + { 0xCADF, 0x5FE3 }, + { 0xCAE0, 0x5FFA }, + { 0xCAE1, 0x5FEF }, + { 0xCAE2, 0x5FF7 }, + { 0xCAE3, 0x5FFB }, + { 0xCAE4, 0x6000 }, + { 0xCAE5, 0x5FF4 }, + { 0xCAE6, 0x623A }, + { 0xCAE7, 0x6283 }, + { 0xCAE8, 0x628C }, + { 0xCAE9, 0x628E }, + { 0xCAEA, 0x628F }, + { 0xCAEB, 0x6294 }, + { 0xCAEC, 0x6287 }, + { 0xCAED, 0x6271 }, + { 0xCAEE, 0x627B }, + { 0xCAEF, 0x627A }, + { 0xCAF0, 0x6270 }, + { 0xCAF1, 0x6281 }, + { 0xCAF2, 0x6288 }, + { 0xCAF3, 0x6277 }, + { 0xCAF4, 0x627D }, + { 0xCAF5, 0x6272 }, + { 0xCAF6, 0x6274 }, + { 0xCAF7, 0x6537 }, + { 0xCAF8, 0x65F0 }, + { 0xCAF9, 0x65F4 }, + { 0xCAFA, 0x65F3 }, + { 0xCAFB, 0x65F2 }, + { 0xCAFC, 0x65F5 }, + { 0xCAFD, 0x6745 }, + { 0xCAFE, 0x6747 }, + { 0xCB40, 0x6759 }, + { 0xCB41, 0x6755 }, + { 0xCB42, 0x674C }, + { 0xCB43, 0x6748 }, + { 0xCB44, 0x675D }, + { 0xCB45, 0x674D }, + { 0xCB46, 0x675A }, + { 0xCB47, 0x674B }, + { 0xCB48, 0x6BD0 }, + { 0xCB49, 0x6C19 }, + { 0xCB4A, 0x6C1A }, + { 0xCB4B, 0x6C78 }, + { 0xCB4C, 0x6C67 }, + { 0xCB4D, 0x6C6B }, + { 0xCB4E, 0x6C84 }, + { 0xCB4F, 0x6C8B }, + { 0xCB50, 0x6C8F }, + { 0xCB51, 0x6C71 }, + { 0xCB52, 0x6C6F }, + { 0xCB53, 0x6C69 }, + { 0xCB54, 0x6C9A }, + { 0xCB55, 0x6C6D }, + { 0xCB56, 0x6C87 }, + { 0xCB57, 0x6C95 }, + { 0xCB58, 0x6C9C }, + { 0xCB59, 0x6C66 }, + { 0xCB5A, 0x6C73 }, + { 0xCB5B, 0x6C65 }, + { 0xCB5C, 0x6C7B }, + { 0xCB5D, 0x6C8E }, + { 0xCB5E, 0x7074 }, + { 0xCB5F, 0x707A }, + { 0xCB60, 0x7263 }, + { 0xCB61, 0x72BF }, + { 0xCB62, 0x72BD }, + { 0xCB63, 0x72C3 }, + { 0xCB64, 0x72C6 }, + { 0xCB65, 0x72C1 }, + { 0xCB66, 0x72BA }, + { 0xCB67, 0x72C5 }, + { 0xCB68, 0x7395 }, + { 0xCB69, 0x7397 }, + { 0xCB6A, 0x7393 }, + { 0xCB6B, 0x7394 }, + { 0xCB6C, 0x7392 }, + { 0xCB6D, 0x753A }, + { 0xCB6E, 0x7539 }, + { 0xCB6F, 0x7594 }, + { 0xCB70, 0x7595 }, + { 0xCB71, 0x7681 }, + { 0xCB72, 0x793D }, + { 0xCB73, 0x8034 }, + { 0xCB74, 0x8095 }, + { 0xCB75, 0x8099 }, + { 0xCB76, 0x8090 }, + { 0xCB77, 0x8092 }, + { 0xCB78, 0x809C }, + { 0xCB79, 0x8290 }, + { 0xCB7A, 0x828F }, + { 0xCB7B, 0x8285 }, + { 0xCB7C, 0x828E }, + { 0xCB7D, 0x8291 }, + { 0xCB7E, 0x8293 }, + { 0xCBA1, 0x828A }, + { 0xCBA2, 0x8283 }, + { 0xCBA3, 0x8284 }, + { 0xCBA4, 0x8C78 }, + { 0xCBA5, 0x8FC9 }, + { 0xCBA6, 0x8FBF }, + { 0xCBA7, 0x909F }, + { 0xCBA8, 0x90A1 }, + { 0xCBA9, 0x90A5 }, + { 0xCBAA, 0x909E }, + { 0xCBAB, 0x90A7 }, + { 0xCBAC, 0x90A0 }, + { 0xCBAD, 0x9630 }, + { 0xCBAE, 0x9628 }, + { 0xCBAF, 0x962F }, + { 0xCBB0, 0x962D }, + { 0xCBB1, 0x4E33 }, + { 0xCBB2, 0x4F98 }, + { 0xCBB3, 0x4F7C }, + { 0xCBB4, 0x4F85 }, + { 0xCBB5, 0x4F7D }, + { 0xCBB6, 0x4F80 }, + { 0xCBB7, 0x4F87 }, + { 0xCBB8, 0x4F76 }, + { 0xCBB9, 0x4F74 }, + { 0xCBBA, 0x4F89 }, + { 0xCBBB, 0x4F84 }, + { 0xCBBC, 0x4F77 }, + { 0xCBBD, 0x4F4C }, + { 0xCBBE, 0x4F97 }, + { 0xCBBF, 0x4F6A }, + { 0xCBC0, 0x4F9A }, + { 0xCBC1, 0x4F79 }, + { 0xCBC2, 0x4F81 }, + { 0xCBC3, 0x4F78 }, + { 0xCBC4, 0x4F90 }, + { 0xCBC5, 0x4F9C }, + { 0xCBC6, 0x4F94 }, + { 0xCBC7, 0x4F9E }, + { 0xCBC8, 0x4F92 }, + { 0xCBC9, 0x4F82 }, + { 0xCBCA, 0x4F95 }, + { 0xCBCB, 0x4F6B }, + { 0xCBCC, 0x4F6E }, + { 0xCBCD, 0x519E }, + { 0xCBCE, 0x51BC }, + { 0xCBCF, 0x51BE }, + { 0xCBD0, 0x5235 }, + { 0xCBD1, 0x5232 }, + { 0xCBD2, 0x5233 }, + { 0xCBD3, 0x5246 }, + { 0xCBD4, 0x5231 }, + { 0xCBD5, 0x52BC }, + { 0xCBD6, 0x530A }, + { 0xCBD7, 0x530B }, + { 0xCBD8, 0x533C }, + { 0xCBD9, 0x5392 }, + { 0xCBDA, 0x5394 }, + { 0xCBDB, 0x5487 }, + { 0xCBDC, 0x547F }, + { 0xCBDD, 0x5481 }, + { 0xCBDE, 0x5491 }, + { 0xCBDF, 0x5482 }, + { 0xCBE0, 0x5488 }, + { 0xCBE1, 0x546B }, + { 0xCBE2, 0x547A }, + { 0xCBE3, 0x547E }, + { 0xCBE4, 0x5465 }, + { 0xCBE5, 0x546C }, + { 0xCBE6, 0x5474 }, + { 0xCBE7, 0x5466 }, + { 0xCBE8, 0x548D }, + { 0xCBE9, 0x546F }, + { 0xCBEA, 0x5461 }, + { 0xCBEB, 0x5460 }, + { 0xCBEC, 0x5498 }, + { 0xCBED, 0x5463 }, + { 0xCBEE, 0x5467 }, + { 0xCBEF, 0x5464 }, + { 0xCBF0, 0x56F7 }, + { 0xCBF1, 0x56F9 }, + { 0xCBF2, 0x576F }, + { 0xCBF3, 0x5772 }, + { 0xCBF4, 0x576D }, + { 0xCBF5, 0x576B }, + { 0xCBF6, 0x5771 }, + { 0xCBF7, 0x5770 }, + { 0xCBF8, 0x5776 }, + { 0xCBF9, 0x5780 }, + { 0xCBFA, 0x5775 }, + { 0xCBFB, 0x577B }, + { 0xCBFC, 0x5773 }, + { 0xCBFD, 0x5774 }, + { 0xCBFE, 0x5762 }, + { 0xCC40, 0x5768 }, + { 0xCC41, 0x577D }, + { 0xCC42, 0x590C }, + { 0xCC43, 0x5945 }, + { 0xCC44, 0x59B5 }, + { 0xCC45, 0x59BA }, + { 0xCC46, 0x59CF }, + { 0xCC47, 0x59CE }, + { 0xCC48, 0x59B2 }, + { 0xCC49, 0x59CC }, + { 0xCC4A, 0x59C1 }, + { 0xCC4B, 0x59B6 }, + { 0xCC4C, 0x59BC }, + { 0xCC4D, 0x59C3 }, + { 0xCC4E, 0x59D6 }, + { 0xCC4F, 0x59B1 }, + { 0xCC50, 0x59BD }, + { 0xCC51, 0x59C0 }, + { 0xCC52, 0x59C8 }, + { 0xCC53, 0x59B4 }, + { 0xCC54, 0x59C7 }, + { 0xCC55, 0x5B62 }, + { 0xCC56, 0x5B65 }, + { 0xCC57, 0x5B93 }, + { 0xCC58, 0x5B95 }, + { 0xCC59, 0x5C44 }, + { 0xCC5A, 0x5C47 }, + { 0xCC5B, 0x5CAE }, + { 0xCC5C, 0x5CA4 }, + { 0xCC5D, 0x5CA0 }, + { 0xCC5E, 0x5CB5 }, + { 0xCC5F, 0x5CAF }, + { 0xCC60, 0x5CA8 }, + { 0xCC61, 0x5CAC }, + { 0xCC62, 0x5C9F }, + { 0xCC63, 0x5CA3 }, + { 0xCC64, 0x5CAD }, + { 0xCC65, 0x5CA2 }, + { 0xCC66, 0x5CAA }, + { 0xCC67, 0x5CA7 }, + { 0xCC68, 0x5C9D }, + { 0xCC69, 0x5CA5 }, + { 0xCC6A, 0x5CB6 }, + { 0xCC6B, 0x5CB0 }, + { 0xCC6C, 0x5CA6 }, + { 0xCC6D, 0x5E17 }, + { 0xCC6E, 0x5E14 }, + { 0xCC6F, 0x5E19 }, + { 0xCC70, 0x5F28 }, + { 0xCC71, 0x5F22 }, + { 0xCC72, 0x5F23 }, + { 0xCC73, 0x5F24 }, + { 0xCC74, 0x5F54 }, + { 0xCC75, 0x5F82 }, + { 0xCC76, 0x5F7E }, + { 0xCC77, 0x5F7D }, + { 0xCC78, 0x5FDE }, + { 0xCC79, 0x5FE5 }, + { 0xCC7A, 0x602D }, + { 0xCC7B, 0x6026 }, + { 0xCC7C, 0x6019 }, + { 0xCC7D, 0x6032 }, + { 0xCC7E, 0x600B }, + { 0xCCA1, 0x6034 }, + { 0xCCA2, 0x600A }, + { 0xCCA3, 0x6017 }, + { 0xCCA4, 0x6033 }, + { 0xCCA5, 0x601A }, + { 0xCCA6, 0x601E }, + { 0xCCA7, 0x602C }, + { 0xCCA8, 0x6022 }, + { 0xCCA9, 0x600D }, + { 0xCCAA, 0x6010 }, + { 0xCCAB, 0x602E }, + { 0xCCAC, 0x6013 }, + { 0xCCAD, 0x6011 }, + { 0xCCAE, 0x600C }, + { 0xCCAF, 0x6009 }, + { 0xCCB0, 0x601C }, + { 0xCCB1, 0x6214 }, + { 0xCCB2, 0x623D }, + { 0xCCB3, 0x62AD }, + { 0xCCB4, 0x62B4 }, + { 0xCCB5, 0x62D1 }, + { 0xCCB6, 0x62BE }, + { 0xCCB7, 0x62AA }, + { 0xCCB8, 0x62B6 }, + { 0xCCB9, 0x62CA }, + { 0xCCBA, 0x62AE }, + { 0xCCBB, 0x62B3 }, + { 0xCCBC, 0x62AF }, + { 0xCCBD, 0x62BB }, + { 0xCCBE, 0x62A9 }, + { 0xCCBF, 0x62B0 }, + { 0xCCC0, 0x62B8 }, + { 0xCCC1, 0x653D }, + { 0xCCC2, 0x65A8 }, + { 0xCCC3, 0x65BB }, + { 0xCCC4, 0x6609 }, + { 0xCCC5, 0x65FC }, + { 0xCCC6, 0x6604 }, + { 0xCCC7, 0x6612 }, + { 0xCCC8, 0x6608 }, + { 0xCCC9, 0x65FB }, + { 0xCCCA, 0x6603 }, + { 0xCCCB, 0x660B }, + { 0xCCCC, 0x660D }, + { 0xCCCD, 0x6605 }, + { 0xCCCE, 0x65FD }, + { 0xCCCF, 0x6611 }, + { 0xCCD0, 0x6610 }, + { 0xCCD1, 0x66F6 }, + { 0xCCD2, 0x670A }, + { 0xCCD3, 0x6785 }, + { 0xCCD4, 0x676C }, + { 0xCCD5, 0x678E }, + { 0xCCD6, 0x6792 }, + { 0xCCD7, 0x6776 }, + { 0xCCD8, 0x677B }, + { 0xCCD9, 0x6798 }, + { 0xCCDA, 0x6786 }, + { 0xCCDB, 0x6784 }, + { 0xCCDC, 0x6774 }, + { 0xCCDD, 0x678D }, + { 0xCCDE, 0x678C }, + { 0xCCDF, 0x677A }, + { 0xCCE0, 0x679F }, + { 0xCCE1, 0x6791 }, + { 0xCCE2, 0x6799 }, + { 0xCCE3, 0x6783 }, + { 0xCCE4, 0x677D }, + { 0xCCE5, 0x6781 }, + { 0xCCE6, 0x6778 }, + { 0xCCE7, 0x6779 }, + { 0xCCE8, 0x6794 }, + { 0xCCE9, 0x6B25 }, + { 0xCCEA, 0x6B80 }, + { 0xCCEB, 0x6B7E }, + { 0xCCEC, 0x6BDE }, + { 0xCCED, 0x6C1D }, + { 0xCCEE, 0x6C93 }, + { 0xCCEF, 0x6CEC }, + { 0xCCF0, 0x6CEB }, + { 0xCCF1, 0x6CEE }, + { 0xCCF2, 0x6CD9 }, + { 0xCCF3, 0x6CB6 }, + { 0xCCF4, 0x6CD4 }, + { 0xCCF5, 0x6CAD }, + { 0xCCF6, 0x6CE7 }, + { 0xCCF7, 0x6CB7 }, + { 0xCCF8, 0x6CD0 }, + { 0xCCF9, 0x6CC2 }, + { 0xCCFA, 0x6CBA }, + { 0xCCFB, 0x6CC3 }, + { 0xCCFC, 0x6CC6 }, + { 0xCCFD, 0x6CED }, + { 0xCCFE, 0x6CF2 }, + { 0xCD40, 0x6CD2 }, + { 0xCD41, 0x6CDD }, + { 0xCD42, 0x6CB4 }, + { 0xCD43, 0x6C8A }, + { 0xCD44, 0x6C9D }, + { 0xCD45, 0x6C80 }, + { 0xCD46, 0x6CDE }, + { 0xCD47, 0x6CC0 }, + { 0xCD48, 0x6D30 }, + { 0xCD49, 0x6CCD }, + { 0xCD4A, 0x6CC7 }, + { 0xCD4B, 0x6CB0 }, + { 0xCD4C, 0x6CF9 }, + { 0xCD4D, 0x6CCF }, + { 0xCD4E, 0x6CE9 }, + { 0xCD4F, 0x6CD1 }, + { 0xCD50, 0x7094 }, + { 0xCD51, 0x7098 }, + { 0xCD52, 0x7085 }, + { 0xCD53, 0x7093 }, + { 0xCD54, 0x7086 }, + { 0xCD55, 0x7084 }, + { 0xCD56, 0x7091 }, + { 0xCD57, 0x7096 }, + { 0xCD58, 0x7082 }, + { 0xCD59, 0x709A }, + { 0xCD5A, 0x7083 }, + { 0xCD5B, 0x726A }, + { 0xCD5C, 0x72D6 }, + { 0xCD5D, 0x72CB }, + { 0xCD5E, 0x72D8 }, + { 0xCD5F, 0x72C9 }, + { 0xCD60, 0x72DC }, + { 0xCD61, 0x72D2 }, + { 0xCD62, 0x72D4 }, + { 0xCD63, 0x72DA }, + { 0xCD64, 0x72CC }, + { 0xCD65, 0x72D1 }, + { 0xCD66, 0x73A4 }, + { 0xCD67, 0x73A1 }, + { 0xCD68, 0x73AD }, + { 0xCD69, 0x73A6 }, + { 0xCD6A, 0x73A2 }, + { 0xCD6B, 0x73A0 }, + { 0xCD6C, 0x73AC }, + { 0xCD6D, 0x739D }, + { 0xCD6E, 0x74DD }, + { 0xCD6F, 0x74E8 }, + { 0xCD70, 0x753F }, + { 0xCD71, 0x7540 }, + { 0xCD72, 0x753E }, + { 0xCD73, 0x758C }, + { 0xCD74, 0x7598 }, + { 0xCD75, 0x76AF }, + { 0xCD76, 0x76F3 }, + { 0xCD77, 0x76F1 }, + { 0xCD78, 0x76F0 }, + { 0xCD79, 0x76F5 }, + { 0xCD7A, 0x77F8 }, + { 0xCD7B, 0x77FC }, + { 0xCD7C, 0x77F9 }, + { 0xCD7D, 0x77FB }, + { 0xCD7E, 0x77FA }, + { 0xCDA1, 0x77F7 }, + { 0xCDA2, 0x7942 }, + { 0xCDA3, 0x793F }, + { 0xCDA4, 0x79C5 }, + { 0xCDA5, 0x7A78 }, + { 0xCDA6, 0x7A7B }, + { 0xCDA7, 0x7AFB }, + { 0xCDA8, 0x7C75 }, + { 0xCDA9, 0x7CFD }, + { 0xCDAA, 0x8035 }, + { 0xCDAB, 0x808F }, + { 0xCDAC, 0x80AE }, + { 0xCDAD, 0x80A3 }, + { 0xCDAE, 0x80B8 }, + { 0xCDAF, 0x80B5 }, + { 0xCDB0, 0x80AD }, + { 0xCDB1, 0x8220 }, + { 0xCDB2, 0x82A0 }, + { 0xCDB3, 0x82C0 }, + { 0xCDB4, 0x82AB }, + { 0xCDB5, 0x829A }, + { 0xCDB6, 0x8298 }, + { 0xCDB7, 0x829B }, + { 0xCDB8, 0x82B5 }, + { 0xCDB9, 0x82A7 }, + { 0xCDBA, 0x82AE }, + { 0xCDBB, 0x82BC }, + { 0xCDBC, 0x829E }, + { 0xCDBD, 0x82BA }, + { 0xCDBE, 0x82B4 }, + { 0xCDBF, 0x82A8 }, + { 0xCDC0, 0x82A1 }, + { 0xCDC1, 0x82A9 }, + { 0xCDC2, 0x82C2 }, + { 0xCDC3, 0x82A4 }, + { 0xCDC4, 0x82C3 }, + { 0xCDC5, 0x82B6 }, + { 0xCDC6, 0x82A2 }, + { 0xCDC7, 0x8670 }, + { 0xCDC8, 0x866F }, + { 0xCDC9, 0x866D }, + { 0xCDCA, 0x866E }, + { 0xCDCB, 0x8C56 }, + { 0xCDCC, 0x8FD2 }, + { 0xCDCD, 0x8FCB }, + { 0xCDCE, 0x8FD3 }, + { 0xCDCF, 0x8FCD }, + { 0xCDD0, 0x8FD6 }, + { 0xCDD1, 0x8FD5 }, + { 0xCDD2, 0x8FD7 }, + { 0xCDD3, 0x90B2 }, + { 0xCDD4, 0x90B4 }, + { 0xCDD5, 0x90AF }, + { 0xCDD6, 0x90B3 }, + { 0xCDD7, 0x90B0 }, + { 0xCDD8, 0x9639 }, + { 0xCDD9, 0x963D }, + { 0xCDDA, 0x963C }, + { 0xCDDB, 0x963A }, + { 0xCDDC, 0x9643 }, + { 0xCDDD, 0x4FCD }, + { 0xCDDE, 0x4FC5 }, + { 0xCDDF, 0x4FD3 }, + { 0xCDE0, 0x4FB2 }, + { 0xCDE1, 0x4FC9 }, + { 0xCDE2, 0x4FCB }, + { 0xCDE3, 0x4FC1 }, + { 0xCDE4, 0x4FD4 }, + { 0xCDE5, 0x4FDC }, + { 0xCDE6, 0x4FD9 }, + { 0xCDE7, 0x4FBB }, + { 0xCDE8, 0x4FB3 }, + { 0xCDE9, 0x4FDB }, + { 0xCDEA, 0x4FC7 }, + { 0xCDEB, 0x4FD6 }, + { 0xCDEC, 0x4FBA }, + { 0xCDED, 0x4FC0 }, + { 0xCDEE, 0x4FB9 }, + { 0xCDEF, 0x4FEC }, + { 0xCDF0, 0x5244 }, + { 0xCDF1, 0x5249 }, + { 0xCDF2, 0x52C0 }, + { 0xCDF3, 0x52C2 }, + { 0xCDF4, 0x533D }, + { 0xCDF5, 0x537C }, + { 0xCDF6, 0x5397 }, + { 0xCDF7, 0x5396 }, + { 0xCDF8, 0x5399 }, + { 0xCDF9, 0x5398 }, + { 0xCDFA, 0x54BA }, + { 0xCDFB, 0x54A1 }, + { 0xCDFC, 0x54AD }, + { 0xCDFD, 0x54A5 }, + { 0xCDFE, 0x54CF }, + { 0xCE40, 0x54C3 }, + { 0xCE41, 0x830D }, + { 0xCE42, 0x54B7 }, + { 0xCE43, 0x54AE }, + { 0xCE44, 0x54D6 }, + { 0xCE45, 0x54B6 }, + { 0xCE46, 0x54C5 }, + { 0xCE47, 0x54C6 }, + { 0xCE48, 0x54A0 }, + { 0xCE49, 0x5470 }, + { 0xCE4A, 0x54BC }, + { 0xCE4B, 0x54A2 }, + { 0xCE4C, 0x54BE }, + { 0xCE4D, 0x5472 }, + { 0xCE4E, 0x54DE }, + { 0xCE4F, 0x54B0 }, + { 0xCE50, 0x57B5 }, + { 0xCE51, 0x579E }, + { 0xCE52, 0x579F }, + { 0xCE53, 0x57A4 }, + { 0xCE54, 0x578C }, + { 0xCE55, 0x5797 }, + { 0xCE56, 0x579D }, + { 0xCE57, 0x579B }, + { 0xCE58, 0x5794 }, + { 0xCE59, 0x5798 }, + { 0xCE5A, 0x578F }, + { 0xCE5B, 0x5799 }, + { 0xCE5C, 0x57A5 }, + { 0xCE5D, 0x579A }, + { 0xCE5E, 0x5795 }, + { 0xCE5F, 0x58F4 }, + { 0xCE60, 0x590D }, + { 0xCE61, 0x5953 }, + { 0xCE62, 0x59E1 }, + { 0xCE63, 0x59DE }, + { 0xCE64, 0x59EE }, + { 0xCE65, 0x5A00 }, + { 0xCE66, 0x59F1 }, + { 0xCE67, 0x59DD }, + { 0xCE68, 0x59FA }, + { 0xCE69, 0x59FD }, + { 0xCE6A, 0x59FC }, + { 0xCE6B, 0x59F6 }, + { 0xCE6C, 0x59E4 }, + { 0xCE6D, 0x59F2 }, + { 0xCE6E, 0x59F7 }, + { 0xCE6F, 0x59DB }, + { 0xCE70, 0x59E9 }, + { 0xCE71, 0x59F3 }, + { 0xCE72, 0x59F5 }, + { 0xCE73, 0x59E0 }, + { 0xCE74, 0x59FE }, + { 0xCE75, 0x59F4 }, + { 0xCE76, 0x59ED }, + { 0xCE77, 0x5BA8 }, + { 0xCE78, 0x5C4C }, + { 0xCE79, 0x5CD0 }, + { 0xCE7A, 0x5CD8 }, + { 0xCE7B, 0x5CCC }, + { 0xCE7C, 0x5CD7 }, + { 0xCE7D, 0x5CCB }, + { 0xCE7E, 0x5CDB }, + { 0xCEA1, 0x5CDE }, + { 0xCEA2, 0x5CDA }, + { 0xCEA3, 0x5CC9 }, + { 0xCEA4, 0x5CC7 }, + { 0xCEA5, 0x5CCA }, + { 0xCEA6, 0x5CD6 }, + { 0xCEA7, 0x5CD3 }, + { 0xCEA8, 0x5CD4 }, + { 0xCEA9, 0x5CCF }, + { 0xCEAA, 0x5CC8 }, + { 0xCEAB, 0x5CC6 }, + { 0xCEAC, 0x5CCE }, + { 0xCEAD, 0x5CDF }, + { 0xCEAE, 0x5CF8 }, + { 0xCEAF, 0x5DF9 }, + { 0xCEB0, 0x5E21 }, + { 0xCEB1, 0x5E22 }, + { 0xCEB2, 0x5E23 }, + { 0xCEB3, 0x5E20 }, + { 0xCEB4, 0x5E24 }, + { 0xCEB5, 0x5EB0 }, + { 0xCEB6, 0x5EA4 }, + { 0xCEB7, 0x5EA2 }, + { 0xCEB8, 0x5E9B }, + { 0xCEB9, 0x5EA3 }, + { 0xCEBA, 0x5EA5 }, + { 0xCEBB, 0x5F07 }, + { 0xCEBC, 0x5F2E }, + { 0xCEBD, 0x5F56 }, + { 0xCEBE, 0x5F86 }, + { 0xCEBF, 0x6037 }, + { 0xCEC0, 0x6039 }, + { 0xCEC1, 0x6054 }, + { 0xCEC2, 0x6072 }, + { 0xCEC3, 0x605E }, + { 0xCEC4, 0x6045 }, + { 0xCEC5, 0x6053 }, + { 0xCEC6, 0x6047 }, + { 0xCEC7, 0x6049 }, + { 0xCEC8, 0x605B }, + { 0xCEC9, 0x604C }, + { 0xCECA, 0x6040 }, + { 0xCECB, 0x6042 }, + { 0xCECC, 0x605F }, + { 0xCECD, 0x6024 }, + { 0xCECE, 0x6044 }, + { 0xCECF, 0x6058 }, + { 0xCED0, 0x6066 }, + { 0xCED1, 0x606E }, + { 0xCED2, 0x6242 }, + { 0xCED3, 0x6243 }, + { 0xCED4, 0x62CF }, + { 0xCED5, 0x630D }, + { 0xCED6, 0x630B }, + { 0xCED7, 0x62F5 }, + { 0xCED8, 0x630E }, + { 0xCED9, 0x6303 }, + { 0xCEDA, 0x62EB }, + { 0xCEDB, 0x62F9 }, + { 0xCEDC, 0x630F }, + { 0xCEDD, 0x630C }, + { 0xCEDE, 0x62F8 }, + { 0xCEDF, 0x62F6 }, + { 0xCEE0, 0x6300 }, + { 0xCEE1, 0x6313 }, + { 0xCEE2, 0x6314 }, + { 0xCEE3, 0x62FA }, + { 0xCEE4, 0x6315 }, + { 0xCEE5, 0x62FB }, + { 0xCEE6, 0x62F0 }, + { 0xCEE7, 0x6541 }, + { 0xCEE8, 0x6543 }, + { 0xCEE9, 0x65AA }, + { 0xCEEA, 0x65BF }, + { 0xCEEB, 0x6636 }, + { 0xCEEC, 0x6621 }, + { 0xCEED, 0x6632 }, + { 0xCEEE, 0x6635 }, + { 0xCEEF, 0x661C }, + { 0xCEF0, 0x6626 }, + { 0xCEF1, 0x6622 }, + { 0xCEF2, 0x6633 }, + { 0xCEF3, 0x662B }, + { 0xCEF4, 0x663A }, + { 0xCEF5, 0x661D }, + { 0xCEF6, 0x6634 }, + { 0xCEF7, 0x6639 }, + { 0xCEF8, 0x662E }, + { 0xCEF9, 0x670F }, + { 0xCEFA, 0x6710 }, + { 0xCEFB, 0x67C1 }, + { 0xCEFC, 0x67F2 }, + { 0xCEFD, 0x67C8 }, + { 0xCEFE, 0x67BA }, + { 0xCF40, 0x67DC }, + { 0xCF41, 0x67BB }, + { 0xCF42, 0x67F8 }, + { 0xCF43, 0x67D8 }, + { 0xCF44, 0x67C0 }, + { 0xCF45, 0x67B7 }, + { 0xCF46, 0x67C5 }, + { 0xCF47, 0x67EB }, + { 0xCF48, 0x67E4 }, + { 0xCF49, 0x67DF }, + { 0xCF4A, 0x67B5 }, + { 0xCF4B, 0x67CD }, + { 0xCF4C, 0x67B3 }, + { 0xCF4D, 0x67F7 }, + { 0xCF4E, 0x67F6 }, + { 0xCF4F, 0x67EE }, + { 0xCF50, 0x67E3 }, + { 0xCF51, 0x67C2 }, + { 0xCF52, 0x67B9 }, + { 0xCF53, 0x67CE }, + { 0xCF54, 0x67E7 }, + { 0xCF55, 0x67F0 }, + { 0xCF56, 0x67B2 }, + { 0xCF57, 0x67FC }, + { 0xCF58, 0x67C6 }, + { 0xCF59, 0x67ED }, + { 0xCF5A, 0x67CC }, + { 0xCF5B, 0x67AE }, + { 0xCF5C, 0x67E6 }, + { 0xCF5D, 0x67DB }, + { 0xCF5E, 0x67FA }, + { 0xCF5F, 0x67C9 }, + { 0xCF60, 0x67CA }, + { 0xCF61, 0x67C3 }, + { 0xCF62, 0x67EA }, + { 0xCF63, 0x67CB }, + { 0xCF64, 0x6B28 }, + { 0xCF65, 0x6B82 }, + { 0xCF66, 0x6B84 }, + { 0xCF67, 0x6BB6 }, + { 0xCF68, 0x6BD6 }, + { 0xCF69, 0x6BD8 }, + { 0xCF6A, 0x6BE0 }, + { 0xCF6B, 0x6C20 }, + { 0xCF6C, 0x6C21 }, + { 0xCF6D, 0x6D28 }, + { 0xCF6E, 0x6D34 }, + { 0xCF6F, 0x6D2D }, + { 0xCF70, 0x6D1F }, + { 0xCF71, 0x6D3C }, + { 0xCF72, 0x6D3F }, + { 0xCF73, 0x6D12 }, + { 0xCF74, 0x6D0A }, + { 0xCF75, 0x6CDA }, + { 0xCF76, 0x6D33 }, + { 0xCF77, 0x6D04 }, + { 0xCF78, 0x6D19 }, + { 0xCF79, 0x6D3A }, + { 0xCF7A, 0x6D1A }, + { 0xCF7B, 0x6D11 }, + { 0xCF7C, 0x6D00 }, + { 0xCF7D, 0x6D1D }, + { 0xCF7E, 0x6D42 }, + { 0xCFA1, 0x6D01 }, + { 0xCFA2, 0x6D18 }, + { 0xCFA3, 0x6D37 }, + { 0xCFA4, 0x6D03 }, + { 0xCFA5, 0x6D0F }, + { 0xCFA6, 0x6D40 }, + { 0xCFA7, 0x6D07 }, + { 0xCFA8, 0x6D20 }, + { 0xCFA9, 0x6D2C }, + { 0xCFAA, 0x6D08 }, + { 0xCFAB, 0x6D22 }, + { 0xCFAC, 0x6D09 }, + { 0xCFAD, 0x6D10 }, + { 0xCFAE, 0x70B7 }, + { 0xCFAF, 0x709F }, + { 0xCFB0, 0x70BE }, + { 0xCFB1, 0x70B1 }, + { 0xCFB2, 0x70B0 }, + { 0xCFB3, 0x70A1 }, + { 0xCFB4, 0x70B4 }, + { 0xCFB5, 0x70B5 }, + { 0xCFB6, 0x70A9 }, + { 0xCFB7, 0x7241 }, + { 0xCFB8, 0x7249 }, + { 0xCFB9, 0x724A }, + { 0xCFBA, 0x726C }, + { 0xCFBB, 0x7270 }, + { 0xCFBC, 0x7273 }, + { 0xCFBD, 0x726E }, + { 0xCFBE, 0x72CA }, + { 0xCFBF, 0x72E4 }, + { 0xCFC0, 0x72E8 }, + { 0xCFC1, 0x72EB }, + { 0xCFC2, 0x72DF }, + { 0xCFC3, 0x72EA }, + { 0xCFC4, 0x72E6 }, + { 0xCFC5, 0x72E3 }, + { 0xCFC6, 0x7385 }, + { 0xCFC7, 0x73CC }, + { 0xCFC8, 0x73C2 }, + { 0xCFC9, 0x73C8 }, + { 0xCFCA, 0x73C5 }, + { 0xCFCB, 0x73B9 }, + { 0xCFCC, 0x73B6 }, + { 0xCFCD, 0x73B5 }, + { 0xCFCE, 0x73B4 }, + { 0xCFCF, 0x73EB }, + { 0xCFD0, 0x73BF }, + { 0xCFD1, 0x73C7 }, + { 0xCFD2, 0x73BE }, + { 0xCFD3, 0x73C3 }, + { 0xCFD4, 0x73C6 }, + { 0xCFD5, 0x73B8 }, + { 0xCFD6, 0x73CB }, + { 0xCFD7, 0x74EC }, + { 0xCFD8, 0x74EE }, + { 0xCFD9, 0x752E }, + { 0xCFDA, 0x7547 }, + { 0xCFDB, 0x7548 }, + { 0xCFDC, 0x75A7 }, + { 0xCFDD, 0x75AA }, + { 0xCFDE, 0x7679 }, + { 0xCFDF, 0x76C4 }, + { 0xCFE0, 0x7708 }, + { 0xCFE1, 0x7703 }, + { 0xCFE2, 0x7704 }, + { 0xCFE3, 0x7705 }, + { 0xCFE4, 0x770A }, + { 0xCFE5, 0x76F7 }, + { 0xCFE6, 0x76FB }, + { 0xCFE7, 0x76FA }, + { 0xCFE8, 0x77E7 }, + { 0xCFE9, 0x77E8 }, + { 0xCFEA, 0x7806 }, + { 0xCFEB, 0x7811 }, + { 0xCFEC, 0x7812 }, + { 0xCFED, 0x7805 }, + { 0xCFEE, 0x7810 }, + { 0xCFEF, 0x780F }, + { 0xCFF0, 0x780E }, + { 0xCFF1, 0x7809 }, + { 0xCFF2, 0x7803 }, + { 0xCFF3, 0x7813 }, + { 0xCFF4, 0x794A }, + { 0xCFF5, 0x794C }, + { 0xCFF6, 0x794B }, + { 0xCFF7, 0x7945 }, + { 0xCFF8, 0x7944 }, + { 0xCFF9, 0x79D5 }, + { 0xCFFA, 0x79CD }, + { 0xCFFB, 0x79CF }, + { 0xCFFC, 0x79D6 }, + { 0xCFFD, 0x79CE }, + { 0xCFFE, 0x7A80 }, + { 0xD040, 0x7A7E }, + { 0xD041, 0x7AD1 }, + { 0xD042, 0x7B00 }, + { 0xD043, 0x7B01 }, + { 0xD044, 0x7C7A }, + { 0xD045, 0x7C78 }, + { 0xD046, 0x7C79 }, + { 0xD047, 0x7C7F }, + { 0xD048, 0x7C80 }, + { 0xD049, 0x7C81 }, + { 0xD04A, 0x7D03 }, + { 0xD04B, 0x7D08 }, + { 0xD04C, 0x7D01 }, + { 0xD04D, 0x7F58 }, + { 0xD04E, 0x7F91 }, + { 0xD04F, 0x7F8D }, + { 0xD050, 0x7FBE }, + { 0xD051, 0x8007 }, + { 0xD052, 0x800E }, + { 0xD053, 0x800F }, + { 0xD054, 0x8014 }, + { 0xD055, 0x8037 }, + { 0xD056, 0x80D8 }, + { 0xD057, 0x80C7 }, + { 0xD058, 0x80E0 }, + { 0xD059, 0x80D1 }, + { 0xD05A, 0x80C8 }, + { 0xD05B, 0x80C2 }, + { 0xD05C, 0x80D0 }, + { 0xD05D, 0x80C5 }, + { 0xD05E, 0x80E3 }, + { 0xD05F, 0x80D9 }, + { 0xD060, 0x80DC }, + { 0xD061, 0x80CA }, + { 0xD062, 0x80D5 }, + { 0xD063, 0x80C9 }, + { 0xD064, 0x80CF }, + { 0xD065, 0x80D7 }, + { 0xD066, 0x80E6 }, + { 0xD067, 0x80CD }, + { 0xD068, 0x81FF }, + { 0xD069, 0x8221 }, + { 0xD06A, 0x8294 }, + { 0xD06B, 0x82D9 }, + { 0xD06C, 0x82FE }, + { 0xD06D, 0x82F9 }, + { 0xD06E, 0x8307 }, + { 0xD06F, 0x82E8 }, + { 0xD070, 0x8300 }, + { 0xD071, 0x82D5 }, + { 0xD072, 0x833A }, + { 0xD073, 0x82EB }, + { 0xD074, 0x82D6 }, + { 0xD075, 0x82F4 }, + { 0xD076, 0x82EC }, + { 0xD077, 0x82E1 }, + { 0xD078, 0x82F2 }, + { 0xD079, 0x82F5 }, + { 0xD07A, 0x830C }, + { 0xD07B, 0x82FB }, + { 0xD07C, 0x82F6 }, + { 0xD07D, 0x82F0 }, + { 0xD07E, 0x82EA }, + { 0xD0A1, 0x82E4 }, + { 0xD0A2, 0x82E0 }, + { 0xD0A3, 0x82FA }, + { 0xD0A4, 0x82F3 }, + { 0xD0A5, 0x82ED }, + { 0xD0A6, 0x8677 }, + { 0xD0A7, 0x8674 }, + { 0xD0A8, 0x867C }, + { 0xD0A9, 0x8673 }, + { 0xD0AA, 0x8841 }, + { 0xD0AB, 0x884E }, + { 0xD0AC, 0x8867 }, + { 0xD0AD, 0x886A }, + { 0xD0AE, 0x8869 }, + { 0xD0AF, 0x89D3 }, + { 0xD0B0, 0x8A04 }, + { 0xD0B1, 0x8A07 }, + { 0xD0B2, 0x8D72 }, + { 0xD0B3, 0x8FE3 }, + { 0xD0B4, 0x8FE1 }, + { 0xD0B5, 0x8FEE }, + { 0xD0B6, 0x8FE0 }, + { 0xD0B7, 0x90F1 }, + { 0xD0B8, 0x90BD }, + { 0xD0B9, 0x90BF }, + { 0xD0BA, 0x90D5 }, + { 0xD0BB, 0x90C5 }, + { 0xD0BC, 0x90BE }, + { 0xD0BD, 0x90C7 }, + { 0xD0BE, 0x90CB }, + { 0xD0BF, 0x90C8 }, + { 0xD0C0, 0x91D4 }, + { 0xD0C1, 0x91D3 }, + { 0xD0C2, 0x9654 }, + { 0xD0C3, 0x964F }, + { 0xD0C4, 0x9651 }, + { 0xD0C5, 0x9653 }, + { 0xD0C6, 0x964A }, + { 0xD0C7, 0x964E }, + { 0xD0C8, 0x501E }, + { 0xD0C9, 0x5005 }, + { 0xD0CA, 0x5007 }, + { 0xD0CB, 0x5013 }, + { 0xD0CC, 0x5022 }, + { 0xD0CD, 0x5030 }, + { 0xD0CE, 0x501B }, + { 0xD0CF, 0x4FF5 }, + { 0xD0D0, 0x4FF4 }, + { 0xD0D1, 0x5033 }, + { 0xD0D2, 0x5037 }, + { 0xD0D3, 0x502C }, + { 0xD0D4, 0x4FF6 }, + { 0xD0D5, 0x4FF7 }, + { 0xD0D6, 0x5017 }, + { 0xD0D7, 0x501C }, + { 0xD0D8, 0x5020 }, + { 0xD0D9, 0x5027 }, + { 0xD0DA, 0x5035 }, + { 0xD0DB, 0x502F }, + { 0xD0DC, 0x5031 }, + { 0xD0DD, 0x500E }, + { 0xD0DE, 0x515A }, + { 0xD0DF, 0x5194 }, + { 0xD0E0, 0x5193 }, + { 0xD0E1, 0x51CA }, + { 0xD0E2, 0x51C4 }, + { 0xD0E3, 0x51C5 }, + { 0xD0E4, 0x51C8 }, + { 0xD0E5, 0x51CE }, + { 0xD0E6, 0x5261 }, + { 0xD0E7, 0x525A }, + { 0xD0E8, 0x5252 }, + { 0xD0E9, 0x525E }, + { 0xD0EA, 0x525F }, + { 0xD0EB, 0x5255 }, + { 0xD0EC, 0x5262 }, + { 0xD0ED, 0x52CD }, + { 0xD0EE, 0x530E }, + { 0xD0EF, 0x539E }, + { 0xD0F0, 0x5526 }, + { 0xD0F1, 0x54E2 }, + { 0xD0F2, 0x5517 }, + { 0xD0F3, 0x5512 }, + { 0xD0F4, 0x54E7 }, + { 0xD0F5, 0x54F3 }, + { 0xD0F6, 0x54E4 }, + { 0xD0F7, 0x551A }, + { 0xD0F8, 0x54FF }, + { 0xD0F9, 0x5504 }, + { 0xD0FA, 0x5508 }, + { 0xD0FB, 0x54EB }, + { 0xD0FC, 0x5511 }, + { 0xD0FD, 0x5505 }, + { 0xD0FE, 0x54F1 }, + { 0xD140, 0x550A }, + { 0xD141, 0x54FB }, + { 0xD142, 0x54F7 }, + { 0xD143, 0x54F8 }, + { 0xD144, 0x54E0 }, + { 0xD145, 0x550E }, + { 0xD146, 0x5503 }, + { 0xD147, 0x550B }, + { 0xD148, 0x5701 }, + { 0xD149, 0x5702 }, + { 0xD14A, 0x57CC }, + { 0xD14B, 0x5832 }, + { 0xD14C, 0x57D5 }, + { 0xD14D, 0x57D2 }, + { 0xD14E, 0x57BA }, + { 0xD14F, 0x57C6 }, + { 0xD150, 0x57BD }, + { 0xD151, 0x57BC }, + { 0xD152, 0x57B8 }, + { 0xD153, 0x57B6 }, + { 0xD154, 0x57BF }, + { 0xD155, 0x57C7 }, + { 0xD156, 0x57D0 }, + { 0xD157, 0x57B9 }, + { 0xD158, 0x57C1 }, + { 0xD159, 0x590E }, + { 0xD15A, 0x594A }, + { 0xD15B, 0x5A19 }, + { 0xD15C, 0x5A16 }, + { 0xD15D, 0x5A2D }, + { 0xD15E, 0x5A2E }, + { 0xD15F, 0x5A15 }, + { 0xD160, 0x5A0F }, + { 0xD161, 0x5A17 }, + { 0xD162, 0x5A0A }, + { 0xD163, 0x5A1E }, + { 0xD164, 0x5A33 }, + { 0xD165, 0x5B6C }, + { 0xD166, 0x5BA7 }, + { 0xD167, 0x5BAD }, + { 0xD168, 0x5BAC }, + { 0xD169, 0x5C03 }, + { 0xD16A, 0x5C56 }, + { 0xD16B, 0x5C54 }, + { 0xD16C, 0x5CEC }, + { 0xD16D, 0x5CFF }, + { 0xD16E, 0x5CEE }, + { 0xD16F, 0x5CF1 }, + { 0xD170, 0x5CF7 }, + { 0xD171, 0x5D00 }, + { 0xD172, 0x5CF9 }, + { 0xD173, 0x5E29 }, + { 0xD174, 0x5E28 }, + { 0xD175, 0x5EA8 }, + { 0xD176, 0x5EAE }, + { 0xD177, 0x5EAA }, + { 0xD178, 0x5EAC }, + { 0xD179, 0x5F33 }, + { 0xD17A, 0x5F30 }, + { 0xD17B, 0x5F67 }, + { 0xD17C, 0x605D }, + { 0xD17D, 0x605A }, + { 0xD17E, 0x6067 }, + { 0xD1A1, 0x6041 }, + { 0xD1A2, 0x60A2 }, + { 0xD1A3, 0x6088 }, + { 0xD1A4, 0x6080 }, + { 0xD1A5, 0x6092 }, + { 0xD1A6, 0x6081 }, + { 0xD1A7, 0x609D }, + { 0xD1A8, 0x6083 }, + { 0xD1A9, 0x6095 }, + { 0xD1AA, 0x609B }, + { 0xD1AB, 0x6097 }, + { 0xD1AC, 0x6087 }, + { 0xD1AD, 0x609C }, + { 0xD1AE, 0x608E }, + { 0xD1AF, 0x6219 }, + { 0xD1B0, 0x6246 }, + { 0xD1B1, 0x62F2 }, + { 0xD1B2, 0x6310 }, + { 0xD1B3, 0x6356 }, + { 0xD1B4, 0x632C }, + { 0xD1B5, 0x6344 }, + { 0xD1B6, 0x6345 }, + { 0xD1B7, 0x6336 }, + { 0xD1B8, 0x6343 }, + { 0xD1B9, 0x63E4 }, + { 0xD1BA, 0x6339 }, + { 0xD1BB, 0x634B }, + { 0xD1BC, 0x634A }, + { 0xD1BD, 0x633C }, + { 0xD1BE, 0x6329 }, + { 0xD1BF, 0x6341 }, + { 0xD1C0, 0x6334 }, + { 0xD1C1, 0x6358 }, + { 0xD1C2, 0x6354 }, + { 0xD1C3, 0x6359 }, + { 0xD1C4, 0x632D }, + { 0xD1C5, 0x6347 }, + { 0xD1C6, 0x6333 }, + { 0xD1C7, 0x635A }, + { 0xD1C8, 0x6351 }, + { 0xD1C9, 0x6338 }, + { 0xD1CA, 0x6357 }, + { 0xD1CB, 0x6340 }, + { 0xD1CC, 0x6348 }, + { 0xD1CD, 0x654A }, + { 0xD1CE, 0x6546 }, + { 0xD1CF, 0x65C6 }, + { 0xD1D0, 0x65C3 }, + { 0xD1D1, 0x65C4 }, + { 0xD1D2, 0x65C2 }, + { 0xD1D3, 0x664A }, + { 0xD1D4, 0x665F }, + { 0xD1D5, 0x6647 }, + { 0xD1D6, 0x6651 }, + { 0xD1D7, 0x6712 }, + { 0xD1D8, 0x6713 }, + { 0xD1D9, 0x681F }, + { 0xD1DA, 0x681A }, + { 0xD1DB, 0x6849 }, + { 0xD1DC, 0x6832 }, + { 0xD1DD, 0x6833 }, + { 0xD1DE, 0x683B }, + { 0xD1DF, 0x684B }, + { 0xD1E0, 0x684F }, + { 0xD1E1, 0x6816 }, + { 0xD1E2, 0x6831 }, + { 0xD1E3, 0x681C }, + { 0xD1E4, 0x6835 }, + { 0xD1E5, 0x682B }, + { 0xD1E6, 0x682D }, + { 0xD1E7, 0x682F }, + { 0xD1E8, 0x684E }, + { 0xD1E9, 0x6844 }, + { 0xD1EA, 0x6834 }, + { 0xD1EB, 0x681D }, + { 0xD1EC, 0x6812 }, + { 0xD1ED, 0x6814 }, + { 0xD1EE, 0x6826 }, + { 0xD1EF, 0x6828 }, + { 0xD1F0, 0x682E }, + { 0xD1F1, 0x684D }, + { 0xD1F2, 0x683A }, + { 0xD1F3, 0x6825 }, + { 0xD1F4, 0x6820 }, + { 0xD1F5, 0x6B2C }, + { 0xD1F6, 0x6B2F }, + { 0xD1F7, 0x6B2D }, + { 0xD1F8, 0x6B31 }, + { 0xD1F9, 0x6B34 }, + { 0xD1FA, 0x6B6D }, + { 0xD1FB, 0x8082 }, + { 0xD1FC, 0x6B88 }, + { 0xD1FD, 0x6BE6 }, + { 0xD1FE, 0x6BE4 }, + { 0xD240, 0x6BE8 }, + { 0xD241, 0x6BE3 }, + { 0xD242, 0x6BE2 }, + { 0xD243, 0x6BE7 }, + { 0xD244, 0x6C25 }, + { 0xD245, 0x6D7A }, + { 0xD246, 0x6D63 }, + { 0xD247, 0x6D64 }, + { 0xD248, 0x6D76 }, + { 0xD249, 0x6D0D }, + { 0xD24A, 0x6D61 }, + { 0xD24B, 0x6D92 }, + { 0xD24C, 0x6D58 }, + { 0xD24D, 0x6D62 }, + { 0xD24E, 0x6D6D }, + { 0xD24F, 0x6D6F }, + { 0xD250, 0x6D91 }, + { 0xD251, 0x6D8D }, + { 0xD252, 0x6DEF }, + { 0xD253, 0x6D7F }, + { 0xD254, 0x6D86 }, + { 0xD255, 0x6D5E }, + { 0xD256, 0x6D67 }, + { 0xD257, 0x6D60 }, + { 0xD258, 0x6D97 }, + { 0xD259, 0x6D70 }, + { 0xD25A, 0x6D7C }, + { 0xD25B, 0x6D5F }, + { 0xD25C, 0x6D82 }, + { 0xD25D, 0x6D98 }, + { 0xD25E, 0x6D2F }, + { 0xD25F, 0x6D68 }, + { 0xD260, 0x6D8B }, + { 0xD261, 0x6D7E }, + { 0xD262, 0x6D80 }, + { 0xD263, 0x6D84 }, + { 0xD264, 0x6D16 }, + { 0xD265, 0x6D83 }, + { 0xD266, 0x6D7B }, + { 0xD267, 0x6D7D }, + { 0xD268, 0x6D75 }, + { 0xD269, 0x6D90 }, + { 0xD26A, 0x70DC }, + { 0xD26B, 0x70D3 }, + { 0xD26C, 0x70D1 }, + { 0xD26D, 0x70DD }, + { 0xD26E, 0x70CB }, + { 0xD26F, 0x7F39 }, + { 0xD270, 0x70E2 }, + { 0xD271, 0x70D7 }, + { 0xD272, 0x70D2 }, + { 0xD273, 0x70DE }, + { 0xD274, 0x70E0 }, + { 0xD275, 0x70D4 }, + { 0xD276, 0x70CD }, + { 0xD277, 0x70C5 }, + { 0xD278, 0x70C6 }, + { 0xD279, 0x70C7 }, + { 0xD27A, 0x70DA }, + { 0xD27B, 0x70CE }, + { 0xD27C, 0x70E1 }, + { 0xD27D, 0x7242 }, + { 0xD27E, 0x7278 }, + { 0xD2A1, 0x7277 }, + { 0xD2A2, 0x7276 }, + { 0xD2A3, 0x7300 }, + { 0xD2A4, 0x72FA }, + { 0xD2A5, 0x72F4 }, + { 0xD2A6, 0x72FE }, + { 0xD2A7, 0x72F6 }, + { 0xD2A8, 0x72F3 }, + { 0xD2A9, 0x72FB }, + { 0xD2AA, 0x7301 }, + { 0xD2AB, 0x73D3 }, + { 0xD2AC, 0x73D9 }, + { 0xD2AD, 0x73E5 }, + { 0xD2AE, 0x73D6 }, + { 0xD2AF, 0x73BC }, + { 0xD2B0, 0x73E7 }, + { 0xD2B1, 0x73E3 }, + { 0xD2B2, 0x73E9 }, + { 0xD2B3, 0x73DC }, + { 0xD2B4, 0x73D2 }, + { 0xD2B5, 0x73DB }, + { 0xD2B6, 0x73D4 }, + { 0xD2B7, 0x73DD }, + { 0xD2B8, 0x73DA }, + { 0xD2B9, 0x73D7 }, + { 0xD2BA, 0x73D8 }, + { 0xD2BB, 0x73E8 }, + { 0xD2BC, 0x74DE }, + { 0xD2BD, 0x74DF }, + { 0xD2BE, 0x74F4 }, + { 0xD2BF, 0x74F5 }, + { 0xD2C0, 0x7521 }, + { 0xD2C1, 0x755B }, + { 0xD2C2, 0x755F }, + { 0xD2C3, 0x75B0 }, + { 0xD2C4, 0x75C1 }, + { 0xD2C5, 0x75BB }, + { 0xD2C6, 0x75C4 }, + { 0xD2C7, 0x75C0 }, + { 0xD2C8, 0x75BF }, + { 0xD2C9, 0x75B6 }, + { 0xD2CA, 0x75BA }, + { 0xD2CB, 0x768A }, + { 0xD2CC, 0x76C9 }, + { 0xD2CD, 0x771D }, + { 0xD2CE, 0x771B }, + { 0xD2CF, 0x7710 }, + { 0xD2D0, 0x7713 }, + { 0xD2D1, 0x7712 }, + { 0xD2D2, 0x7723 }, + { 0xD2D3, 0x7711 }, + { 0xD2D4, 0x7715 }, + { 0xD2D5, 0x7719 }, + { 0xD2D6, 0x771A }, + { 0xD2D7, 0x7722 }, + { 0xD2D8, 0x7727 }, + { 0xD2D9, 0x7823 }, + { 0xD2DA, 0x782C }, + { 0xD2DB, 0x7822 }, + { 0xD2DC, 0x7835 }, + { 0xD2DD, 0x782F }, + { 0xD2DE, 0x7828 }, + { 0xD2DF, 0x782E }, + { 0xD2E0, 0x782B }, + { 0xD2E1, 0x7821 }, + { 0xD2E2, 0x7829 }, + { 0xD2E3, 0x7833 }, + { 0xD2E4, 0x782A }, + { 0xD2E5, 0x7831 }, + { 0xD2E6, 0x7954 }, + { 0xD2E7, 0x795B }, + { 0xD2E8, 0x794F }, + { 0xD2E9, 0x795C }, + { 0xD2EA, 0x7953 }, + { 0xD2EB, 0x7952 }, + { 0xD2EC, 0x7951 }, + { 0xD2ED, 0x79EB }, + { 0xD2EE, 0x79EC }, + { 0xD2EF, 0x79E0 }, + { 0xD2F0, 0x79EE }, + { 0xD2F1, 0x79ED }, + { 0xD2F2, 0x79EA }, + { 0xD2F3, 0x79DC }, + { 0xD2F4, 0x79DE }, + { 0xD2F5, 0x79DD }, + { 0xD2F6, 0x7A86 }, + { 0xD2F7, 0x7A89 }, + { 0xD2F8, 0x7A85 }, + { 0xD2F9, 0x7A8B }, + { 0xD2FA, 0x7A8C }, + { 0xD2FB, 0x7A8A }, + { 0xD2FC, 0x7A87 }, + { 0xD2FD, 0x7AD8 }, + { 0xD2FE, 0x7B10 }, + { 0xD340, 0x7B04 }, + { 0xD341, 0x7B13 }, + { 0xD342, 0x7B05 }, + { 0xD343, 0x7B0F }, + { 0xD344, 0x7B08 }, + { 0xD345, 0x7B0A }, + { 0xD346, 0x7B0E }, + { 0xD347, 0x7B09 }, + { 0xD348, 0x7B12 }, + { 0xD349, 0x7C84 }, + { 0xD34A, 0x7C91 }, + { 0xD34B, 0x7C8A }, + { 0xD34C, 0x7C8C }, + { 0xD34D, 0x7C88 }, + { 0xD34E, 0x7C8D }, + { 0xD34F, 0x7C85 }, + { 0xD350, 0x7D1E }, + { 0xD351, 0x7D1D }, + { 0xD352, 0x7D11 }, + { 0xD353, 0x7D0E }, + { 0xD354, 0x7D18 }, + { 0xD355, 0x7D16 }, + { 0xD356, 0x7D13 }, + { 0xD357, 0x7D1F }, + { 0xD358, 0x7D12 }, + { 0xD359, 0x7D0F }, + { 0xD35A, 0x7D0C }, + { 0xD35B, 0x7F5C }, + { 0xD35C, 0x7F61 }, + { 0xD35D, 0x7F5E }, + { 0xD35E, 0x7F60 }, + { 0xD35F, 0x7F5D }, + { 0xD360, 0x7F5B }, + { 0xD361, 0x7F96 }, + { 0xD362, 0x7F92 }, + { 0xD363, 0x7FC3 }, + { 0xD364, 0x7FC2 }, + { 0xD365, 0x7FC0 }, + { 0xD366, 0x8016 }, + { 0xD367, 0x803E }, + { 0xD368, 0x8039 }, + { 0xD369, 0x80FA }, + { 0xD36A, 0x80F2 }, + { 0xD36B, 0x80F9 }, + { 0xD36C, 0x80F5 }, + { 0xD36D, 0x8101 }, + { 0xD36E, 0x80FB }, + { 0xD36F, 0x8100 }, + { 0xD370, 0x8201 }, + { 0xD371, 0x822F }, + { 0xD372, 0x8225 }, + { 0xD373, 0x8333 }, + { 0xD374, 0x832D }, + { 0xD375, 0x8344 }, + { 0xD376, 0x8319 }, + { 0xD377, 0x8351 }, + { 0xD378, 0x8325 }, + { 0xD379, 0x8356 }, + { 0xD37A, 0x833F }, + { 0xD37B, 0x8341 }, + { 0xD37C, 0x8326 }, + { 0xD37D, 0x831C }, + { 0xD37E, 0x8322 }, + { 0xD3A1, 0x8342 }, + { 0xD3A2, 0x834E }, + { 0xD3A3, 0x831B }, + { 0xD3A4, 0x832A }, + { 0xD3A5, 0x8308 }, + { 0xD3A6, 0x833C }, + { 0xD3A7, 0x834D }, + { 0xD3A8, 0x8316 }, + { 0xD3A9, 0x8324 }, + { 0xD3AA, 0x8320 }, + { 0xD3AB, 0x8337 }, + { 0xD3AC, 0x832F }, + { 0xD3AD, 0x8329 }, + { 0xD3AE, 0x8347 }, + { 0xD3AF, 0x8345 }, + { 0xD3B0, 0x834C }, + { 0xD3B1, 0x8353 }, + { 0xD3B2, 0x831E }, + { 0xD3B3, 0x832C }, + { 0xD3B4, 0x834B }, + { 0xD3B5, 0x8327 }, + { 0xD3B6, 0x8348 }, + { 0xD3B7, 0x8653 }, + { 0xD3B8, 0x8652 }, + { 0xD3B9, 0x86A2 }, + { 0xD3BA, 0x86A8 }, + { 0xD3BB, 0x8696 }, + { 0xD3BC, 0x868D }, + { 0xD3BD, 0x8691 }, + { 0xD3BE, 0x869E }, + { 0xD3BF, 0x8687 }, + { 0xD3C0, 0x8697 }, + { 0xD3C1, 0x8686 }, + { 0xD3C2, 0x868B }, + { 0xD3C3, 0x869A }, + { 0xD3C4, 0x8685 }, + { 0xD3C5, 0x86A5 }, + { 0xD3C6, 0x8699 }, + { 0xD3C7, 0x86A1 }, + { 0xD3C8, 0x86A7 }, + { 0xD3C9, 0x8695 }, + { 0xD3CA, 0x8698 }, + { 0xD3CB, 0x868E }, + { 0xD3CC, 0x869D }, + { 0xD3CD, 0x8690 }, + { 0xD3CE, 0x8694 }, + { 0xD3CF, 0x8843 }, + { 0xD3D0, 0x8844 }, + { 0xD3D1, 0x886D }, + { 0xD3D2, 0x8875 }, + { 0xD3D3, 0x8876 }, + { 0xD3D4, 0x8872 }, + { 0xD3D5, 0x8880 }, + { 0xD3D6, 0x8871 }, + { 0xD3D7, 0x887F }, + { 0xD3D8, 0x886F }, + { 0xD3D9, 0x8883 }, + { 0xD3DA, 0x887E }, + { 0xD3DB, 0x8874 }, + { 0xD3DC, 0x887C }, + { 0xD3DD, 0x8A12 }, + { 0xD3DE, 0x8C47 }, + { 0xD3DF, 0x8C57 }, + { 0xD3E0, 0x8C7B }, + { 0xD3E1, 0x8CA4 }, + { 0xD3E2, 0x8CA3 }, + { 0xD3E3, 0x8D76 }, + { 0xD3E4, 0x8D78 }, + { 0xD3E5, 0x8DB5 }, + { 0xD3E6, 0x8DB7 }, + { 0xD3E7, 0x8DB6 }, + { 0xD3E8, 0x8ED1 }, + { 0xD3E9, 0x8ED3 }, + { 0xD3EA, 0x8FFE }, + { 0xD3EB, 0x8FF5 }, + { 0xD3EC, 0x9002 }, + { 0xD3ED, 0x8FFF }, + { 0xD3EE, 0x8FFB }, + { 0xD3EF, 0x9004 }, + { 0xD3F0, 0x8FFC }, + { 0xD3F1, 0x8FF6 }, + { 0xD3F2, 0x90D6 }, + { 0xD3F3, 0x90E0 }, + { 0xD3F4, 0x90D9 }, + { 0xD3F5, 0x90DA }, + { 0xD3F6, 0x90E3 }, + { 0xD3F7, 0x90DF }, + { 0xD3F8, 0x90E5 }, + { 0xD3F9, 0x90D8 }, + { 0xD3FA, 0x90DB }, + { 0xD3FB, 0x90D7 }, + { 0xD3FC, 0x90DC }, + { 0xD3FD, 0x90E4 }, + { 0xD3FE, 0x9150 }, + { 0xD440, 0x914E }, + { 0xD441, 0x914F }, + { 0xD442, 0x91D5 }, + { 0xD443, 0x91E2 }, + { 0xD444, 0x91DA }, + { 0xD445, 0x965C }, + { 0xD446, 0x965F }, + { 0xD447, 0x96BC }, + { 0xD448, 0x98E3 }, + { 0xD449, 0x9ADF }, + { 0xD44A, 0x9B2F }, + { 0xD44B, 0x4E7F }, + { 0xD44C, 0x5070 }, + { 0xD44D, 0x506A }, + { 0xD44E, 0x5061 }, + { 0xD44F, 0x505E }, + { 0xD450, 0x5060 }, + { 0xD451, 0x5053 }, + { 0xD452, 0x504B }, + { 0xD453, 0x505D }, + { 0xD454, 0x5072 }, + { 0xD455, 0x5048 }, + { 0xD456, 0x504D }, + { 0xD457, 0x5041 }, + { 0xD458, 0x505B }, + { 0xD459, 0x504A }, + { 0xD45A, 0x5062 }, + { 0xD45B, 0x5015 }, + { 0xD45C, 0x5045 }, + { 0xD45D, 0x505F }, + { 0xD45E, 0x5069 }, + { 0xD45F, 0x506B }, + { 0xD460, 0x5063 }, + { 0xD461, 0x5064 }, + { 0xD462, 0x5046 }, + { 0xD463, 0x5040 }, + { 0xD464, 0x506E }, + { 0xD465, 0x5073 }, + { 0xD466, 0x5057 }, + { 0xD467, 0x5051 }, + { 0xD468, 0x51D0 }, + { 0xD469, 0x526B }, + { 0xD46A, 0x526D }, + { 0xD46B, 0x526C }, + { 0xD46C, 0x526E }, + { 0xD46D, 0x52D6 }, + { 0xD46E, 0x52D3 }, + { 0xD46F, 0x532D }, + { 0xD470, 0x539C }, + { 0xD471, 0x5575 }, + { 0xD472, 0x5576 }, + { 0xD473, 0x553C }, + { 0xD474, 0x554D }, + { 0xD475, 0x5550 }, + { 0xD476, 0x5534 }, + { 0xD477, 0x552A }, + { 0xD478, 0x5551 }, + { 0xD479, 0x5562 }, + { 0xD47A, 0x5536 }, + { 0xD47B, 0x5535 }, + { 0xD47C, 0x5530 }, + { 0xD47D, 0x5552 }, + { 0xD47E, 0x5545 }, + { 0xD4A1, 0x550C }, + { 0xD4A2, 0x5532 }, + { 0xD4A3, 0x5565 }, + { 0xD4A4, 0x554E }, + { 0xD4A5, 0x5539 }, + { 0xD4A6, 0x5548 }, + { 0xD4A7, 0x552D }, + { 0xD4A8, 0x553B }, + { 0xD4A9, 0x5540 }, + { 0xD4AA, 0x554B }, + { 0xD4AB, 0x570A }, + { 0xD4AC, 0x5707 }, + { 0xD4AD, 0x57FB }, + { 0xD4AE, 0x5814 }, + { 0xD4AF, 0x57E2 }, + { 0xD4B0, 0x57F6 }, + { 0xD4B1, 0x57DC }, + { 0xD4B2, 0x57F4 }, + { 0xD4B3, 0x5800 }, + { 0xD4B4, 0x57ED }, + { 0xD4B5, 0x57FD }, + { 0xD4B6, 0x5808 }, + { 0xD4B7, 0x57F8 }, + { 0xD4B8, 0x580B }, + { 0xD4B9, 0x57F3 }, + { 0xD4BA, 0x57CF }, + { 0xD4BB, 0x5807 }, + { 0xD4BC, 0x57EE }, + { 0xD4BD, 0x57E3 }, + { 0xD4BE, 0x57F2 }, + { 0xD4BF, 0x57E5 }, + { 0xD4C0, 0x57EC }, + { 0xD4C1, 0x57E1 }, + { 0xD4C2, 0x580E }, + { 0xD4C3, 0x57FC }, + { 0xD4C4, 0x5810 }, + { 0xD4C5, 0x57E7 }, + { 0xD4C6, 0x5801 }, + { 0xD4C7, 0x580C }, + { 0xD4C8, 0x57F1 }, + { 0xD4C9, 0x57E9 }, + { 0xD4CA, 0x57F0 }, + { 0xD4CB, 0x580D }, + { 0xD4CC, 0x5804 }, + { 0xD4CD, 0x595C }, + { 0xD4CE, 0x5A60 }, + { 0xD4CF, 0x5A58 }, + { 0xD4D0, 0x5A55 }, + { 0xD4D1, 0x5A67 }, + { 0xD4D2, 0x5A5E }, + { 0xD4D3, 0x5A38 }, + { 0xD4D4, 0x5A35 }, + { 0xD4D5, 0x5A6D }, + { 0xD4D6, 0x5A50 }, + { 0xD4D7, 0x5A5F }, + { 0xD4D8, 0x5A65 }, + { 0xD4D9, 0x5A6C }, + { 0xD4DA, 0x5A53 }, + { 0xD4DB, 0x5A64 }, + { 0xD4DC, 0x5A57 }, + { 0xD4DD, 0x5A43 }, + { 0xD4DE, 0x5A5D }, + { 0xD4DF, 0x5A52 }, + { 0xD4E0, 0x5A44 }, + { 0xD4E1, 0x5A5B }, + { 0xD4E2, 0x5A48 }, + { 0xD4E3, 0x5A8E }, + { 0xD4E4, 0x5A3E }, + { 0xD4E5, 0x5A4D }, + { 0xD4E6, 0x5A39 }, + { 0xD4E7, 0x5A4C }, + { 0xD4E8, 0x5A70 }, + { 0xD4E9, 0x5A69 }, + { 0xD4EA, 0x5A47 }, + { 0xD4EB, 0x5A51 }, + { 0xD4EC, 0x5A56 }, + { 0xD4ED, 0x5A42 }, + { 0xD4EE, 0x5A5C }, + { 0xD4EF, 0x5B72 }, + { 0xD4F0, 0x5B6E }, + { 0xD4F1, 0x5BC1 }, + { 0xD4F2, 0x5BC0 }, + { 0xD4F3, 0x5C59 }, + { 0xD4F4, 0x5D1E }, + { 0xD4F5, 0x5D0B }, + { 0xD4F6, 0x5D1D }, + { 0xD4F7, 0x5D1A }, + { 0xD4F8, 0x5D20 }, + { 0xD4F9, 0x5D0C }, + { 0xD4FA, 0x5D28 }, + { 0xD4FB, 0x5D0D }, + { 0xD4FC, 0x5D26 }, + { 0xD4FD, 0x5D25 }, + { 0xD4FE, 0x5D0F }, + { 0xD540, 0x5D30 }, + { 0xD541, 0x5D12 }, + { 0xD542, 0x5D23 }, + { 0xD543, 0x5D1F }, + { 0xD544, 0x5D2E }, + { 0xD545, 0x5E3E }, + { 0xD546, 0x5E34 }, + { 0xD547, 0x5EB1 }, + { 0xD548, 0x5EB4 }, + { 0xD549, 0x5EB9 }, + { 0xD54A, 0x5EB2 }, + { 0xD54B, 0x5EB3 }, + { 0xD54C, 0x5F36 }, + { 0xD54D, 0x5F38 }, + { 0xD54E, 0x5F9B }, + { 0xD54F, 0x5F96 }, + { 0xD550, 0x5F9F }, + { 0xD551, 0x608A }, + { 0xD552, 0x6090 }, + { 0xD553, 0x6086 }, + { 0xD554, 0x60BE }, + { 0xD555, 0x60B0 }, + { 0xD556, 0x60BA }, + { 0xD557, 0x60D3 }, + { 0xD558, 0x60D4 }, + { 0xD559, 0x60CF }, + { 0xD55A, 0x60E4 }, + { 0xD55B, 0x60D9 }, + { 0xD55C, 0x60DD }, + { 0xD55D, 0x60C8 }, + { 0xD55E, 0x60B1 }, + { 0xD55F, 0x60DB }, + { 0xD560, 0x60B7 }, + { 0xD561, 0x60CA }, + { 0xD562, 0x60BF }, + { 0xD563, 0x60C3 }, + { 0xD564, 0x60CD }, + { 0xD565, 0x60C0 }, + { 0xD566, 0x6332 }, + { 0xD567, 0x6365 }, + { 0xD568, 0x638A }, + { 0xD569, 0x6382 }, + { 0xD56A, 0x637D }, + { 0xD56B, 0x63BD }, + { 0xD56C, 0x639E }, + { 0xD56D, 0x63AD }, + { 0xD56E, 0x639D }, + { 0xD56F, 0x6397 }, + { 0xD570, 0x63AB }, + { 0xD571, 0x638E }, + { 0xD572, 0x636F }, + { 0xD573, 0x6387 }, + { 0xD574, 0x6390 }, + { 0xD575, 0x636E }, + { 0xD576, 0x63AF }, + { 0xD577, 0x6375 }, + { 0xD578, 0x639C }, + { 0xD579, 0x636D }, + { 0xD57A, 0x63AE }, + { 0xD57B, 0x637C }, + { 0xD57C, 0x63A4 }, + { 0xD57D, 0x633B }, + + + { 0xD57E, 0x639F }, + { 0xD5A1, 0x6378 }, + { 0xD5A2, 0x6385 }, + { 0xD5A3, 0x6381 }, + { 0xD5A4, 0x6391 }, + { 0xD5A5, 0x638D }, + { 0xD5A6, 0x6370 }, + { 0xD5A7, 0x6553 }, + { 0xD5A8, 0x65CD }, + { 0xD5A9, 0x6665 }, + { 0xD5AA, 0x6661 }, + { 0xD5AB, 0x665B }, + { 0xD5AC, 0x6659 }, + { 0xD5AD, 0x665C }, + { 0xD5AE, 0x6662 }, + { 0xD5AF, 0x6718 }, + { 0xD5B0, 0x6879 }, + { 0xD5B1, 0x6887 }, + { 0xD5B2, 0x6890 }, + { 0xD5B3, 0x689C }, + { 0xD5B4, 0x686D }, + { 0xD5B5, 0x686E }, + { 0xD5B6, 0x68AE }, + { 0xD5B7, 0x68AB }, + { 0xD5B8, 0x6956 }, + { 0xD5B9, 0x686F }, + { 0xD5BA, 0x68A3 }, + { 0xD5BB, 0x68AC }, + { 0xD5BC, 0x68A9 }, + { 0xD5BD, 0x6875 }, + { 0xD5BE, 0x6874 }, + { 0xD5BF, 0x68B2 }, + { 0xD5C0, 0x688F }, + { 0xD5C1, 0x6877 }, + { 0xD5C2, 0x6892 }, + { 0xD5C3, 0x687C }, + { 0xD5C4, 0x686B }, + { 0xD5C5, 0x6872 }, + { 0xD5C6, 0x68AA }, + { 0xD5C7, 0x6880 }, + { 0xD5C8, 0x6871 }, + { 0xD5C9, 0x687E }, + { 0xD5CA, 0x689B }, + { 0xD5CB, 0x6896 }, + { 0xD5CC, 0x688B }, + { 0xD5CD, 0x68A0 }, + { 0xD5CE, 0x6889 }, + { 0xD5CF, 0x68A4 }, + { 0xD5D0, 0x6878 }, + { 0xD5D1, 0x687B }, + { 0xD5D2, 0x6891 }, + { 0xD5D3, 0x688C }, + { 0xD5D4, 0x688A }, + { 0xD5D5, 0x687D }, + { 0xD5D6, 0x6B36 }, + { 0xD5D7, 0x6B33 }, + { 0xD5D8, 0x6B37 }, + { 0xD5D9, 0x6B38 }, + { 0xD5DA, 0x6B91 }, + { 0xD5DB, 0x6B8F }, + { 0xD5DC, 0x6B8D }, + { 0xD5DD, 0x6B8E }, + { 0xD5DE, 0x6B8C }, + { 0xD5DF, 0x6C2A }, + { 0xD5E0, 0x6DC0 }, + { 0xD5E1, 0x6DAB }, + { 0xD5E2, 0x6DB4 }, + { 0xD5E3, 0x6DB3 }, + { 0xD5E4, 0x6E74 }, + { 0xD5E5, 0x6DAC }, + { 0xD5E6, 0x6DE9 }, + { 0xD5E7, 0x6DE2 }, + { 0xD5E8, 0x6DB7 }, + { 0xD5E9, 0x6DF6 }, + { 0xD5EA, 0x6DD4 }, + { 0xD5EB, 0x6E00 }, + { 0xD5EC, 0x6DC8 }, + { 0xD5ED, 0x6DE0 }, + { 0xD5EE, 0x6DDF }, + { 0xD5EF, 0x6DD6 }, + { 0xD5F0, 0x6DBE }, + { 0xD5F1, 0x6DE5 }, + { 0xD5F2, 0x6DDC }, + { 0xD5F3, 0x6DDD }, + { 0xD5F4, 0x6DDB }, + { 0xD5F5, 0x6DF4 }, + { 0xD5F6, 0x6DCA }, + { 0xD5F7, 0x6DBD }, + { 0xD5F8, 0x6DED }, + { 0xD5F9, 0x6DF0 }, + { 0xD5FA, 0x6DBA }, + { 0xD5FB, 0x6DD5 }, + { 0xD5FC, 0x6DC2 }, + { 0xD5FD, 0x6DCF }, + { 0xD5FE, 0x6DC9 }, + { 0xD640, 0x6DD0 }, + { 0xD641, 0x6DF2 }, + { 0xD642, 0x6DD3 }, + { 0xD643, 0x6DFD }, + { 0xD644, 0x6DD7 }, + { 0xD645, 0x6DCD }, + { 0xD646, 0x6DE3 }, + { 0xD647, 0x6DBB }, + { 0xD648, 0x70FA }, + { 0xD649, 0x710D }, + { 0xD64A, 0x70F7 }, + { 0xD64B, 0x7117 }, + { 0xD64C, 0x70F4 }, + { 0xD64D, 0x710C }, + { 0xD64E, 0x70F0 }, + { 0xD64F, 0x7104 }, + { 0xD650, 0x70F3 }, + { 0xD651, 0x7110 }, + { 0xD652, 0x70FC }, + { 0xD653, 0x70FF }, + { 0xD654, 0x7106 }, + { 0xD655, 0x7113 }, + { 0xD656, 0x7100 }, + { 0xD657, 0x70F8 }, + { 0xD658, 0x70F6 }, + { 0xD659, 0x710B }, + { 0xD65A, 0x7102 }, + { 0xD65B, 0x710E }, + { 0xD65C, 0x727E }, + { 0xD65D, 0x727B }, + { 0xD65E, 0x727C }, + { 0xD65F, 0x727F }, + { 0xD660, 0x731D }, + { 0xD661, 0x7317 }, + { 0xD662, 0x7307 }, + { 0xD663, 0x7311 }, + { 0xD664, 0x7318 }, + { 0xD665, 0x730A }, + { 0xD666, 0x7308 }, + { 0xD667, 0x72FF }, + { 0xD668, 0x730F }, + { 0xD669, 0x731E }, + { 0xD66A, 0x7388 }, + { 0xD66B, 0x73F6 }, + { 0xD66C, 0x73F8 }, + { 0xD66D, 0x73F5 }, + { 0xD66E, 0x7404 }, + { 0xD66F, 0x7401 }, + { 0xD670, 0x73FD }, + { 0xD671, 0x7407 }, + { 0xD672, 0x7400 }, + { 0xD673, 0x73FA }, + { 0xD674, 0x73FC }, + { 0xD675, 0x73FF }, + { 0xD676, 0x740C }, + { 0xD677, 0x740B }, + { 0xD678, 0x73F4 }, + { 0xD679, 0x7408 }, + { 0xD67A, 0x7564 }, + { 0xD67B, 0x7563 }, + { 0xD67C, 0x75CE }, + { 0xD67D, 0x75D2 }, + { 0xD67E, 0x75CF }, + { 0xD6A1, 0x75CB }, + { 0xD6A2, 0x75CC }, + { 0xD6A3, 0x75D1 }, + { 0xD6A4, 0x75D0 }, + { 0xD6A5, 0x768F }, + { 0xD6A6, 0x7689 }, + { 0xD6A7, 0x76D3 }, + { 0xD6A8, 0x7739 }, + { 0xD6A9, 0x772F }, + { 0xD6AA, 0x772D }, + { 0xD6AB, 0x7731 }, + { 0xD6AC, 0x7732 }, + { 0xD6AD, 0x7734 }, + { 0xD6AE, 0x7733 }, + { 0xD6AF, 0x773D }, + { 0xD6B0, 0x7725 }, + { 0xD6B1, 0x773B }, + { 0xD6B2, 0x7735 }, + { 0xD6B3, 0x7848 }, + { 0xD6B4, 0x7852 }, + { 0xD6B5, 0x7849 }, + { 0xD6B6, 0x784D }, + { 0xD6B7, 0x784A }, + { 0xD6B8, 0x784C }, + { 0xD6B9, 0x7826 }, + { 0xD6BA, 0x7845 }, + { 0xD6BB, 0x7850 }, + { 0xD6BC, 0x7964 }, + { 0xD6BD, 0x7967 }, + { 0xD6BE, 0x7969 }, + { 0xD6BF, 0x796A }, + { 0xD6C0, 0x7963 }, + { 0xD6C1, 0x796B }, + { 0xD6C2, 0x7961 }, + { 0xD6C3, 0x79BB }, + { 0xD6C4, 0x79FA }, + { 0xD6C5, 0x79F8 }, + { 0xD6C6, 0x79F6 }, + { 0xD6C7, 0x79F7 }, + { 0xD6C8, 0x7A8F }, + { 0xD6C9, 0x7A94 }, + { 0xD6CA, 0x7A90 }, + { 0xD6CB, 0x7B35 }, + { 0xD6CC, 0x7B47 }, + { 0xD6CD, 0x7B34 }, + { 0xD6CE, 0x7B25 }, + { 0xD6CF, 0x7B30 }, + { 0xD6D0, 0x7B22 }, + { 0xD6D1, 0x7B24 }, + { 0xD6D2, 0x7B33 }, + { 0xD6D3, 0x7B18 }, + { 0xD6D4, 0x7B2A }, + { 0xD6D5, 0x7B1D }, + { 0xD6D6, 0x7B31 }, + { 0xD6D7, 0x7B2B }, + { 0xD6D8, 0x7B2D }, + { 0xD6D9, 0x7B2F }, + { 0xD6DA, 0x7B32 }, + { 0xD6DB, 0x7B38 }, + { 0xD6DC, 0x7B1A }, + { 0xD6DD, 0x7B23 }, + { 0xD6DE, 0x7C94 }, + { 0xD6DF, 0x7C98 }, + { 0xD6E0, 0x7C96 }, + { 0xD6E1, 0x7CA3 }, + { 0xD6E2, 0x7D35 }, + { 0xD6E3, 0x7D3D }, + { 0xD6E4, 0x7D38 }, + { 0xD6E5, 0x7D36 }, + { 0xD6E6, 0x7D3A }, + { 0xD6E7, 0x7D45 }, + { 0xD6E8, 0x7D2C }, + { 0xD6E9, 0x7D29 }, + { 0xD6EA, 0x7D41 }, + { 0xD6EB, 0x7D47 }, + { 0xD6EC, 0x7D3E }, + { 0xD6ED, 0x7D3F }, + { 0xD6EE, 0x7D4A }, + { 0xD6EF, 0x7D3B }, + { 0xD6F0, 0x7D28 }, + { 0xD6F1, 0x7F63 }, + { 0xD6F2, 0x7F95 }, + { 0xD6F3, 0x7F9C }, + { 0xD6F4, 0x7F9D }, + { 0xD6F5, 0x7F9B }, + { 0xD6F6, 0x7FCA }, + { 0xD6F7, 0x7FCB }, + { 0xD6F8, 0x7FCD }, + { 0xD6F9, 0x7FD0 }, + { 0xD6FA, 0x7FD1 }, + { 0xD6FB, 0x7FC7 }, + { 0xD6FC, 0x7FCF }, + { 0xD6FD, 0x7FC9 }, + { 0xD6FE, 0x801F }, + { 0xD740, 0x801E }, + { 0xD741, 0x801B }, + { 0xD742, 0x8047 }, + { 0xD743, 0x8043 }, + { 0xD744, 0x8048 }, + { 0xD745, 0x8118 }, + { 0xD746, 0x8125 }, + { 0xD747, 0x8119 }, + { 0xD748, 0x811B }, + { 0xD749, 0x812D }, + { 0xD74A, 0x811F }, + { 0xD74B, 0x812C }, + { 0xD74C, 0x811E }, + { 0xD74D, 0x8121 }, + { 0xD74E, 0x8115 }, + { 0xD74F, 0x8127 }, + { 0xD750, 0x811D }, + { 0xD751, 0x8122 }, + { 0xD752, 0x8211 }, + { 0xD753, 0x8238 }, + { 0xD754, 0x8233 }, + { 0xD755, 0x823A }, + { 0xD756, 0x8234 }, + { 0xD757, 0x8232 }, + { 0xD758, 0x8274 }, + { 0xD759, 0x8390 }, + { 0xD75A, 0x83A3 }, + { 0xD75B, 0x83A8 }, + { 0xD75C, 0x838D }, + { 0xD75D, 0x837A }, + { 0xD75E, 0x8373 }, + { 0xD75F, 0x83A4 }, + { 0xD760, 0x8374 }, + { 0xD761, 0x838F }, + { 0xD762, 0x8381 }, + { 0xD763, 0x8395 }, + { 0xD764, 0x8399 }, + { 0xD765, 0x8375 }, + { 0xD766, 0x8394 }, + { 0xD767, 0x83A9 }, + { 0xD768, 0x837D }, + { 0xD769, 0x8383 }, + { 0xD76A, 0x838C }, + { 0xD76B, 0x839D }, + { 0xD76C, 0x839B }, + { 0xD76D, 0x83AA }, + { 0xD76E, 0x838B }, + { 0xD76F, 0x837E }, + { 0xD770, 0x83A5 }, + { 0xD771, 0x83AF }, + { 0xD772, 0x8388 }, + { 0xD773, 0x8397 }, + { 0xD774, 0x83B0 }, + { 0xD775, 0x837F }, + { 0xD776, 0x83A6 }, + { 0xD777, 0x8387 }, + { 0xD778, 0x83AE }, + { 0xD779, 0x8376 }, + { 0xD77A, 0x839A }, + { 0xD77B, 0x8659 }, + { 0xD77C, 0x8656 }, + { 0xD77D, 0x86BF }, + { 0xD77E, 0x86B7 }, + { 0xD7A1, 0x86C2 }, + { 0xD7A2, 0x86C1 }, + { 0xD7A3, 0x86C5 }, + { 0xD7A4, 0x86BA }, + { 0xD7A5, 0x86B0 }, + { 0xD7A6, 0x86C8 }, + { 0xD7A7, 0x86B9 }, + { 0xD7A8, 0x86B3 }, + { 0xD7A9, 0x86B8 }, + { 0xD7AA, 0x86CC }, + { 0xD7AB, 0x86B4 }, + { 0xD7AC, 0x86BB }, + { 0xD7AD, 0x86BC }, + { 0xD7AE, 0x86C3 }, + { 0xD7AF, 0x86BD }, + { 0xD7B0, 0x86BE }, + { 0xD7B1, 0x8852 }, + { 0xD7B2, 0x8889 }, + { 0xD7B3, 0x8895 }, + { 0xD7B4, 0x88A8 }, + { 0xD7B5, 0x88A2 }, + { 0xD7B6, 0x88AA }, + { 0xD7B7, 0x889A }, + { 0xD7B8, 0x8891 }, + { 0xD7B9, 0x88A1 }, + { 0xD7BA, 0x889F }, + { 0xD7BB, 0x8898 }, + { 0xD7BC, 0x88A7 }, + { 0xD7BD, 0x8899 }, + { 0xD7BE, 0x889B }, + { 0xD7BF, 0x8897 }, + { 0xD7C0, 0x88A4 }, + { 0xD7C1, 0x88AC }, + { 0xD7C2, 0x888C }, + { 0xD7C3, 0x8893 }, + { 0xD7C4, 0x888E }, + { 0xD7C5, 0x8982 }, + { 0xD7C6, 0x89D6 }, + { 0xD7C7, 0x89D9 }, + { 0xD7C8, 0x89D5 }, + { 0xD7C9, 0x8A30 }, + { 0xD7CA, 0x8A27 }, + { 0xD7CB, 0x8A2C }, + { 0xD7CC, 0x8A1E }, + { 0xD7CD, 0x8C39 }, + { 0xD7CE, 0x8C3B }, + { 0xD7CF, 0x8C5C }, + { 0xD7D0, 0x8C5D }, + { 0xD7D1, 0x8C7D }, + { 0xD7D2, 0x8CA5 }, + { 0xD7D3, 0x8D7D }, + { 0xD7D4, 0x8D7B }, + { 0xD7D5, 0x8D79 }, + { 0xD7D6, 0x8DBC }, + { 0xD7D7, 0x8DC2 }, + { 0xD7D8, 0x8DB9 }, + { 0xD7D9, 0x8DBF }, + { 0xD7DA, 0x8DC1 }, + { 0xD7DB, 0x8ED8 }, + { 0xD7DC, 0x8EDE }, + { 0xD7DD, 0x8EDD }, + { 0xD7DE, 0x8EDC }, + { 0xD7DF, 0x8ED7 }, + { 0xD7E0, 0x8EE0 }, + { 0xD7E1, 0x8EE1 }, + { 0xD7E2, 0x9024 }, + { 0xD7E3, 0x900B }, + { 0xD7E4, 0x9011 }, + { 0xD7E5, 0x901C }, + { 0xD7E6, 0x900C }, + { 0xD7E7, 0x9021 }, + { 0xD7E8, 0x90EF }, + { 0xD7E9, 0x90EA }, + { 0xD7EA, 0x90F0 }, + { 0xD7EB, 0x90F4 }, + { 0xD7EC, 0x90F2 }, + { 0xD7ED, 0x90F3 }, + { 0xD7EE, 0x90D4 }, + { 0xD7EF, 0x90EB }, + { 0xD7F0, 0x90EC }, + { 0xD7F1, 0x90E9 }, + { 0xD7F2, 0x9156 }, + { 0xD7F3, 0x9158 }, + { 0xD7F4, 0x915A }, + { 0xD7F5, 0x9153 }, + { 0xD7F6, 0x9155 }, + { 0xD7F7, 0x91EC }, + { 0xD7F8, 0x91F4 }, + { 0xD7F9, 0x91F1 }, + { 0xD7FA, 0x91F3 }, + { 0xD7FB, 0x91F8 }, + { 0xD7FC, 0x91E4 }, + { 0xD7FD, 0x91F9 }, + { 0xD7FE, 0x91EA }, + { 0xD840, 0x91EB }, + { 0xD841, 0x91F7 }, + { 0xD842, 0x91E8 }, + { 0xD843, 0x91EE }, + { 0xD844, 0x957A }, + { 0xD845, 0x9586 }, + { 0xD846, 0x9588 }, + { 0xD847, 0x967C }, + { 0xD848, 0x966D }, + { 0xD849, 0x966B }, + { 0xD84A, 0x9671 }, + { 0xD84B, 0x966F }, + { 0xD84C, 0x96BF }, + { 0xD84D, 0x976A }, + { 0xD84E, 0x9804 }, + { 0xD84F, 0x98E5 }, + { 0xD850, 0x9997 }, + { 0xD851, 0x509B }, + { 0xD852, 0x5095 }, + { 0xD853, 0x5094 }, + { 0xD854, 0x509E }, + { 0xD855, 0x508B }, + { 0xD856, 0x50A3 }, + { 0xD857, 0x5083 }, + { 0xD858, 0x508C }, + { 0xD859, 0x508E }, + { 0xD85A, 0x509D }, + { 0xD85B, 0x5068 }, + { 0xD85C, 0x509C }, + { 0xD85D, 0x5092 }, + { 0xD85E, 0x5082 }, + { 0xD85F, 0x5087 }, + { 0xD860, 0x515F }, + { 0xD861, 0x51D4 }, + { 0xD862, 0x5312 }, + { 0xD863, 0x5311 }, + { 0xD864, 0x53A4 }, + { 0xD865, 0x53A7 }, + { 0xD866, 0x5591 }, + { 0xD867, 0x55A8 }, + { 0xD868, 0x55A5 }, + { 0xD869, 0x55AD }, + { 0xD86A, 0x5577 }, + { 0xD86B, 0x5645 }, + { 0xD86C, 0x55A2 }, + { 0xD86D, 0x5593 }, + { 0xD86E, 0x5588 }, + { 0xD86F, 0x558F }, + { 0xD870, 0x55B5 }, + { 0xD871, 0x5581 }, + { 0xD872, 0x55A3 }, + { 0xD873, 0x5592 }, + { 0xD874, 0x55A4 }, + { 0xD875, 0x557D }, + { 0xD876, 0x558C }, + { 0xD877, 0x55A6 }, + { 0xD878, 0x557F }, + { 0xD879, 0x5595 }, + { 0xD87A, 0x55A1 }, + { 0xD87B, 0x558E }, + { 0xD87C, 0x570C }, + { 0xD87D, 0x5829 }, + { 0xD87E, 0x5837 }, + { 0xD8A1, 0x5819 }, + { 0xD8A2, 0x581E }, + { 0xD8A3, 0x5827 }, + { 0xD8A4, 0x5823 }, + { 0xD8A5, 0x5828 }, + { 0xD8A6, 0x57F5 }, + { 0xD8A7, 0x5848 }, + { 0xD8A8, 0x5825 }, + { 0xD8A9, 0x581C }, + { 0xD8AA, 0x581B }, + { 0xD8AB, 0x5833 }, + { 0xD8AC, 0x583F }, + { 0xD8AD, 0x5836 }, + { 0xD8AE, 0x582E }, + { 0xD8AF, 0x5839 }, + { 0xD8B0, 0x5838 }, + { 0xD8B1, 0x582D }, + { 0xD8B2, 0x582C }, + { 0xD8B3, 0x583B }, + { 0xD8B4, 0x5961 }, + { 0xD8B5, 0x5AAF }, + { 0xD8B6, 0x5A94 }, + { 0xD8B7, 0x5A9F }, + { 0xD8B8, 0x5A7A }, + { 0xD8B9, 0x5AA2 }, + { 0xD8BA, 0x5A9E }, + { 0xD8BB, 0x5A78 }, + { 0xD8BC, 0x5AA6 }, + { 0xD8BD, 0x5A7C }, + { 0xD8BE, 0x5AA5 }, + { 0xD8BF, 0x5AAC }, + { 0xD8C0, 0x5A95 }, + { 0xD8C1, 0x5AAE }, + { 0xD8C2, 0x5A37 }, + { 0xD8C3, 0x5A84 }, + { 0xD8C4, 0x5A8A }, + { 0xD8C5, 0x5A97 }, + { 0xD8C6, 0x5A83 }, + { 0xD8C7, 0x5A8B }, + { 0xD8C8, 0x5AA9 }, + { 0xD8C9, 0x5A7B }, + { 0xD8CA, 0x5A7D }, + { 0xD8CB, 0x5A8C }, + { 0xD8CC, 0x5A9C }, + { 0xD8CD, 0x5A8F }, + { 0xD8CE, 0x5A93 }, + { 0xD8CF, 0x5A9D }, + { 0xD8D0, 0x5BEA }, + { 0xD8D1, 0x5BCD }, + { 0xD8D2, 0x5BCB }, + { 0xD8D3, 0x5BD4 }, + { 0xD8D4, 0x5BD1 }, + { 0xD8D5, 0x5BCA }, + { 0xD8D6, 0x5BCE }, + { 0xD8D7, 0x5C0C }, + { 0xD8D8, 0x5C30 }, + { 0xD8D9, 0x5D37 }, + { 0xD8DA, 0x5D43 }, + { 0xD8DB, 0x5D6B }, + { 0xD8DC, 0x5D41 }, + { 0xD8DD, 0x5D4B }, + { 0xD8DE, 0x5D3F }, + { 0xD8DF, 0x5D35 }, + { 0xD8E0, 0x5D51 }, + { 0xD8E1, 0x5D4E }, + { 0xD8E2, 0x5D55 }, + { 0xD8E3, 0x5D33 }, + { 0xD8E4, 0x5D3A }, + { 0xD8E5, 0x5D52 }, + { 0xD8E6, 0x5D3D }, + { 0xD8E7, 0x5D31 }, + { 0xD8E8, 0x5D59 }, + { 0xD8E9, 0x5D42 }, + { 0xD8EA, 0x5D39 }, + { 0xD8EB, 0x5D49 }, + { 0xD8EC, 0x5D38 }, + { 0xD8ED, 0x5D3C }, + { 0xD8EE, 0x5D32 }, + { 0xD8EF, 0x5D36 }, + { 0xD8F0, 0x5D40 }, + { 0xD8F1, 0x5D45 }, + { 0xD8F2, 0x5E44 }, + { 0xD8F3, 0x5E41 }, + { 0xD8F4, 0x5F58 }, + { 0xD8F5, 0x5FA6 }, + { 0xD8F6, 0x5FA5 }, + { 0xD8F7, 0x5FAB }, + { 0xD8F8, 0x60C9 }, + { 0xD8F9, 0x60B9 }, + { 0xD8FA, 0x60CC }, + { 0xD8FB, 0x60E2 }, + { 0xD8FC, 0x60CE }, + { 0xD8FD, 0x60C4 }, + { 0xD8FE, 0x6114 }, + { 0xD940, 0x60F2 }, + { 0xD941, 0x610A }, + { 0xD942, 0x6116 }, + { 0xD943, 0x6105 }, + { 0xD944, 0x60F5 }, + { 0xD945, 0x6113 }, + { 0xD946, 0x60F8 }, + { 0xD947, 0x60FC }, + { 0xD948, 0x60FE }, + { 0xD949, 0x60C1 }, + { 0xD94A, 0x6103 }, + { 0xD94B, 0x6118 }, + { 0xD94C, 0x611D }, + { 0xD94D, 0x6110 }, + { 0xD94E, 0x60FF }, + { 0xD94F, 0x6104 }, + { 0xD950, 0x610B }, + { 0xD951, 0x624A }, + { 0xD952, 0x6394 }, + { 0xD953, 0x63B1 }, + { 0xD954, 0x63B0 }, + { 0xD955, 0x63CE }, + { 0xD956, 0x63E5 }, + { 0xD957, 0x63E8 }, + { 0xD958, 0x63EF }, + { 0xD959, 0x63C3 }, + { 0xD95A, 0x649D }, + { 0xD95B, 0x63F3 }, + { 0xD95C, 0x63CA }, + { 0xD95D, 0x63E0 }, + { 0xD95E, 0x63F6 }, + { 0xD95F, 0x63D5 }, + { 0xD960, 0x63F2 }, + { 0xD961, 0x63F5 }, + { 0xD962, 0x6461 }, + { 0xD963, 0x63DF }, + { 0xD964, 0x63BE }, + { 0xD965, 0x63DD }, + { 0xD966, 0x63DC }, + { 0xD967, 0x63C4 }, + { 0xD968, 0x63D8 }, + { 0xD969, 0x63D3 }, + { 0xD96A, 0x63C2 }, + { 0xD96B, 0x63C7 }, + { 0xD96C, 0x63CC }, + { 0xD96D, 0x63CB }, + { 0xD96E, 0x63C8 }, + { 0xD96F, 0x63F0 }, + { 0xD970, 0x63D7 }, + { 0xD971, 0x63D9 }, + { 0xD972, 0x6532 }, + { 0xD973, 0x6567 }, + { 0xD974, 0x656A }, + { 0xD975, 0x6564 }, + { 0xD976, 0x655C }, + { 0xD977, 0x6568 }, + { 0xD978, 0x6565 }, + { 0xD979, 0x658C }, + { 0xD97A, 0x659D }, + { 0xD97B, 0x659E }, + { 0xD97C, 0x65AE }, + { 0xD97D, 0x65D0 }, + { 0xD97E, 0x65D2 }, + { 0xD9A1, 0x667C }, + { 0xD9A2, 0x666C }, + { 0xD9A3, 0x667B }, + { 0xD9A4, 0x6680 }, + { 0xD9A5, 0x6671 }, + { 0xD9A6, 0x6679 }, + { 0xD9A7, 0x666A }, + { 0xD9A8, 0x6672 }, + { 0xD9A9, 0x6701 }, + { 0xD9AA, 0x690C }, + { 0xD9AB, 0x68D3 }, + { 0xD9AC, 0x6904 }, + { 0xD9AD, 0x68DC }, + { 0xD9AE, 0x692A }, + { 0xD9AF, 0x68EC }, + { 0xD9B0, 0x68EA }, + { 0xD9B1, 0x68F1 }, + { 0xD9B2, 0x690F }, + { 0xD9B3, 0x68D6 }, + { 0xD9B4, 0x68F7 }, + { 0xD9B5, 0x68EB }, + { 0xD9B6, 0x68E4 }, + { 0xD9B7, 0x68F6 }, + { 0xD9B8, 0x6913 }, + { 0xD9B9, 0x6910 }, + { 0xD9BA, 0x68F3 }, + { 0xD9BB, 0x68E1 }, + { 0xD9BC, 0x6907 }, + { 0xD9BD, 0x68CC }, + { 0xD9BE, 0x6908 }, + { 0xD9BF, 0x6970 }, + { 0xD9C0, 0x68B4 }, + { 0xD9C1, 0x6911 }, + { 0xD9C2, 0x68EF }, + { 0xD9C3, 0x68C6 }, + { 0xD9C4, 0x6914 }, + { 0xD9C5, 0x68F8 }, + { 0xD9C6, 0x68D0 }, + { 0xD9C7, 0x68FD }, + { 0xD9C8, 0x68FC }, + { 0xD9C9, 0x68E8 }, + { 0xD9CA, 0x690B }, + { 0xD9CB, 0x690A }, + { 0xD9CC, 0x6917 }, + { 0xD9CD, 0x68CE }, + { 0xD9CE, 0x68C8 }, + { 0xD9CF, 0x68DD }, + { 0xD9D0, 0x68DE }, + { 0xD9D1, 0x68E6 }, + { 0xD9D2, 0x68F4 }, + { 0xD9D3, 0x68D1 }, + { 0xD9D4, 0x6906 }, + { 0xD9D5, 0x68D4 }, + { 0xD9D6, 0x68E9 }, + { 0xD9D7, 0x6915 }, + { 0xD9D8, 0x6925 }, + { 0xD9D9, 0x68C7 }, + { 0xD9DA, 0x6B39 }, + { 0xD9DB, 0x6B3B }, + { 0xD9DC, 0x6B3F }, + { 0xD9DD, 0x6B3C }, + { 0xD9DE, 0x6B94 }, + { 0xD9DF, 0x6B97 }, + { 0xD9E0, 0x6B99 }, + { 0xD9E1, 0x6B95 }, + { 0xD9E2, 0x6BBD }, + { 0xD9E3, 0x6BF0 }, + { 0xD9E4, 0x6BF2 }, + { 0xD9E5, 0x6BF3 }, + { 0xD9E6, 0x6C30 }, + { 0xD9E7, 0x6DFC }, + { 0xD9E8, 0x6E46 }, + { 0xD9E9, 0x6E47 }, + { 0xD9EA, 0x6E1F }, + { 0xD9EB, 0x6E49 }, + { 0xD9EC, 0x6E88 }, + { 0xD9ED, 0x6E3C }, + { 0xD9EE, 0x6E3D }, + { 0xD9EF, 0x6E45 }, + { 0xD9F0, 0x6E62 }, + { 0xD9F1, 0x6E2B }, + { 0xD9F2, 0x6E3F }, + { 0xD9F3, 0x6E41 }, + { 0xD9F4, 0x6E5D }, + { 0xD9F5, 0x6E73 }, + { 0xD9F6, 0x6E1C }, + { 0xD9F7, 0x6E33 }, + { 0xD9F8, 0x6E4B }, + { 0xD9F9, 0x6E40 }, + { 0xD9FA, 0x6E51 }, + { 0xD9FB, 0x6E3B }, + { 0xD9FC, 0x6E03 }, + { 0xD9FD, 0x6E2E }, + { 0xD9FE, 0x6E5E }, + { 0xDA40, 0x6E68 }, + { 0xDA41, 0x6E5C }, + { 0xDA42, 0x6E61 }, + { 0xDA43, 0x6E31 }, + { 0xDA44, 0x6E28 }, + { 0xDA45, 0x6E60 }, + { 0xDA46, 0x6E71 }, + { 0xDA47, 0x6E6B }, + { 0xDA48, 0x6E39 }, + { 0xDA49, 0x6E22 }, + { 0xDA4A, 0x6E30 }, + { 0xDA4B, 0x6E53 }, + { 0xDA4C, 0x6E65 }, + { 0xDA4D, 0x6E27 }, + { 0xDA4E, 0x6E78 }, + { 0xDA4F, 0x6E64 }, + { 0xDA50, 0x6E77 }, + { 0xDA51, 0x6E55 }, + { 0xDA52, 0x6E79 }, + { 0xDA53, 0x6E52 }, + { 0xDA54, 0x6E66 }, + { 0xDA55, 0x6E35 }, + { 0xDA56, 0x6E36 }, + { 0xDA57, 0x6E5A }, + { 0xDA58, 0x7120 }, + { 0xDA59, 0x711E }, + { 0xDA5A, 0x712F }, + { 0xDA5B, 0x70FB }, + { 0xDA5C, 0x712E }, + { 0xDA5D, 0x7131 }, + { 0xDA5E, 0x7123 }, + { 0xDA5F, 0x7125 }, + { 0xDA60, 0x7122 }, + { 0xDA61, 0x7132 }, + { 0xDA62, 0x711F }, + { 0xDA63, 0x7128 }, + { 0xDA64, 0x713A }, + { 0xDA65, 0x711B }, + { 0xDA66, 0x724B }, + { 0xDA67, 0x725A }, + { 0xDA68, 0x7288 }, + { 0xDA69, 0x7289 }, + { 0xDA6A, 0x7286 }, + { 0xDA6B, 0x7285 }, + { 0xDA6C, 0x728B }, + { 0xDA6D, 0x7312 }, + { 0xDA6E, 0x730B }, + { 0xDA6F, 0x7330 }, + { 0xDA70, 0x7322 }, + { 0xDA71, 0x7331 }, + { 0xDA72, 0x7333 }, + { 0xDA73, 0x7327 }, + { 0xDA74, 0x7332 }, + { 0xDA75, 0x732D }, + { 0xDA76, 0x7326 }, + { 0xDA77, 0x7323 }, + { 0xDA78, 0x7335 }, + { 0xDA79, 0x730C }, + { 0xDA7A, 0x742E }, + { 0xDA7B, 0x742C }, + { 0xDA7C, 0x7430 }, + { 0xDA7D, 0x742B }, + { 0xDA7E, 0x7416 }, + { 0xDAA1, 0x741A }, + { 0xDAA2, 0x7421 }, + { 0xDAA3, 0x742D }, + { 0xDAA4, 0x7431 }, + { 0xDAA5, 0x7424 }, + { 0xDAA6, 0x7423 }, + { 0xDAA7, 0x741D }, + { 0xDAA8, 0x7429 }, + { 0xDAA9, 0x7420 }, + { 0xDAAA, 0x7432 }, + { 0xDAAB, 0x74FB }, + { 0xDAAC, 0x752F }, + { 0xDAAD, 0x756F }, + { 0xDAAE, 0x756C }, + { 0xDAAF, 0x75E7 }, + { 0xDAB0, 0x75DA }, + { 0xDAB1, 0x75E1 }, + { 0xDAB2, 0x75E6 }, + { 0xDAB3, 0x75DD }, + { 0xDAB4, 0x75DF }, + { 0xDAB5, 0x75E4 }, + { 0xDAB6, 0x75D7 }, + { 0xDAB7, 0x7695 }, + { 0xDAB8, 0x7692 }, + { 0xDAB9, 0x76DA }, + { 0xDABA, 0x7746 }, + { 0xDABB, 0x7747 }, + { 0xDABC, 0x7744 }, + { 0xDABD, 0x774D }, + { 0xDABE, 0x7745 }, + { 0xDABF, 0x774A }, + { 0xDAC0, 0x774E }, + { 0xDAC1, 0x774B }, + { 0xDAC2, 0x774C }, + { 0xDAC3, 0x77DE }, + { 0xDAC4, 0x77EC }, + { 0xDAC5, 0x7860 }, + { 0xDAC6, 0x7864 }, + { 0xDAC7, 0x7865 }, + { 0xDAC8, 0x785C }, + { 0xDAC9, 0x786D }, + { 0xDACA, 0x7871 }, + { 0xDACB, 0x786A }, + { 0xDACC, 0x786E }, + { 0xDACD, 0x7870 }, + { 0xDACE, 0x7869 }, + { 0xDACF, 0x7868 }, + { 0xDAD0, 0x785E }, + { 0xDAD1, 0x7862 }, + { 0xDAD2, 0x7974 }, + { 0xDAD3, 0x7973 }, + { 0xDAD4, 0x7972 }, + { 0xDAD5, 0x7970 }, + { 0xDAD6, 0x7A02 }, + { 0xDAD7, 0x7A0A }, + { 0xDAD8, 0x7A03 }, + { 0xDAD9, 0x7A0C }, + { 0xDADA, 0x7A04 }, + { 0xDADB, 0x7A99 }, + { 0xDADC, 0x7AE6 }, + { 0xDADD, 0x7AE4 }, + { 0xDADE, 0x7B4A }, + { 0xDADF, 0x7B3B }, + { 0xDAE0, 0x7B44 }, + { 0xDAE1, 0x7B48 }, + { 0xDAE2, 0x7B4C }, + { 0xDAE3, 0x7B4E }, + { 0xDAE4, 0x7B40 }, + { 0xDAE5, 0x7B58 }, + { 0xDAE6, 0x7B45 }, + { 0xDAE7, 0x7CA2 }, + { 0xDAE8, 0x7C9E }, + { 0xDAE9, 0x7CA8 }, + { 0xDAEA, 0x7CA1 }, + { 0xDAEB, 0x7D58 }, + { 0xDAEC, 0x7D6F }, + { 0xDAED, 0x7D63 }, + { 0xDAEE, 0x7D53 }, + { 0xDAEF, 0x7D56 }, + { 0xDAF0, 0x7D67 }, + { 0xDAF1, 0x7D6A }, + { 0xDAF2, 0x7D4F }, + { 0xDAF3, 0x7D6D }, + { 0xDAF4, 0x7D5C }, + { 0xDAF5, 0x7D6B }, + { 0xDAF6, 0x7D52 }, + { 0xDAF7, 0x7D54 }, + { 0xDAF8, 0x7D69 }, + { 0xDAF9, 0x7D51 }, + { 0xDAFA, 0x7D5F }, + { 0xDAFB, 0x7D4E }, + { 0xDAFC, 0x7F3E }, + { 0xDAFD, 0x7F3F }, + { 0xDAFE, 0x7F65 }, + { 0xDB40, 0x7F66 }, + { 0xDB41, 0x7FA2 }, + { 0xDB42, 0x7FA0 }, + { 0xDB43, 0x7FA1 }, + { 0xDB44, 0x7FD7 }, + { 0xDB45, 0x8051 }, + { 0xDB46, 0x804F }, + { 0xDB47, 0x8050 }, + { 0xDB48, 0x80FE }, + { 0xDB49, 0x80D4 }, + { 0xDB4A, 0x8143 }, + { 0xDB4B, 0x814A }, + { 0xDB4C, 0x8152 }, + { 0xDB4D, 0x814F }, + { 0xDB4E, 0x8147 }, + { 0xDB4F, 0x813D }, + { 0xDB50, 0x814D }, + { 0xDB51, 0x813A }, + { 0xDB52, 0x81E6 }, + { 0xDB53, 0x81EE }, + { 0xDB54, 0x81F7 }, + { 0xDB55, 0x81F8 }, + { 0xDB56, 0x81F9 }, + { 0xDB57, 0x8204 }, + { 0xDB58, 0x823C }, + { 0xDB59, 0x823D }, + { 0xDB5A, 0x823F }, + { 0xDB5B, 0x8275 }, + { 0xDB5C, 0x833B }, + { 0xDB5D, 0x83CF }, + { 0xDB5E, 0x83F9 }, + { 0xDB5F, 0x8423 }, + { 0xDB60, 0x83C0 }, + { 0xDB61, 0x83E8 }, + { 0xDB62, 0x8412 }, + { 0xDB63, 0x83E7 }, + { 0xDB64, 0x83E4 }, + { 0xDB65, 0x83FC }, + { 0xDB66, 0x83F6 }, + { 0xDB67, 0x8410 }, + { 0xDB68, 0x83C6 }, + { 0xDB69, 0x83C8 }, + { 0xDB6A, 0x83EB }, + { 0xDB6B, 0x83E3 }, + { 0xDB6C, 0x83BF }, + { 0xDB6D, 0x8401 }, + { 0xDB6E, 0x83DD }, + { 0xDB6F, 0x83E5 }, + { 0xDB70, 0x83D8 }, + { 0xDB71, 0x83FF }, + { 0xDB72, 0x83E1 }, + { 0xDB73, 0x83CB }, + { 0xDB74, 0x83CE }, + { 0xDB75, 0x83D6 }, + { 0xDB76, 0x83F5 }, + { 0xDB77, 0x83C9 }, + { 0xDB78, 0x8409 }, + { 0xDB79, 0x840F }, + { 0xDB7A, 0x83DE }, + { 0xDB7B, 0x8411 }, + { 0xDB7C, 0x8406 }, + { 0xDB7D, 0x83C2 }, + { 0xDB7E, 0x83F3 }, + { 0xDBA1, 0x83D5 }, + { 0xDBA2, 0x83FA }, + { 0xDBA3, 0x83C7 }, + { 0xDBA4, 0x83D1 }, + { 0xDBA5, 0x83EA }, + { 0xDBA6, 0x8413 }, + { 0xDBA7, 0x83C3 }, + { 0xDBA8, 0x83EC }, + { 0xDBA9, 0x83EE }, + { 0xDBAA, 0x83C4 }, + { 0xDBAB, 0x83FB }, + { 0xDBAC, 0x83D7 }, + { 0xDBAD, 0x83E2 }, + { 0xDBAE, 0x841B }, + { 0xDBAF, 0x83DB }, + { 0xDBB0, 0x83FE }, + { 0xDBB1, 0x86D8 }, + { 0xDBB2, 0x86E2 }, + { 0xDBB3, 0x86E6 }, + { 0xDBB4, 0x86D3 }, + { 0xDBB5, 0x86E3 }, + { 0xDBB6, 0x86DA }, + { 0xDBB7, 0x86EA }, + { 0xDBB8, 0x86DD }, + { 0xDBB9, 0x86EB }, + { 0xDBBA, 0x86DC }, + { 0xDBBB, 0x86EC }, + { 0xDBBC, 0x86E9 }, + { 0xDBBD, 0x86D7 }, + { 0xDBBE, 0x86E8 }, + { 0xDBBF, 0x86D1 }, + { 0xDBC0, 0x8848 }, + { 0xDBC1, 0x8856 }, + { 0xDBC2, 0x8855 }, + { 0xDBC3, 0x88BA }, + { 0xDBC4, 0x88D7 }, + { 0xDBC5, 0x88B9 }, + { 0xDBC6, 0x88B8 }, + { 0xDBC7, 0x88C0 }, + { 0xDBC8, 0x88BE }, + { 0xDBC9, 0x88B6 }, + { 0xDBCA, 0x88BC }, + { 0xDBCB, 0x88B7 }, + { 0xDBCC, 0x88BD }, + { 0xDBCD, 0x88B2 }, + { 0xDBCE, 0x8901 }, + { 0xDBCF, 0x88C9 }, + { 0xDBD0, 0x8995 }, + { 0xDBD1, 0x8998 }, + { 0xDBD2, 0x8997 }, + { 0xDBD3, 0x89DD }, + { 0xDBD4, 0x89DA }, + { 0xDBD5, 0x89DB }, + { 0xDBD6, 0x8A4E }, + { 0xDBD7, 0x8A4D }, + { 0xDBD8, 0x8A39 }, + { 0xDBD9, 0x8A59 }, + { 0xDBDA, 0x8A40 }, + { 0xDBDB, 0x8A57 }, + { 0xDBDC, 0x8A58 }, + { 0xDBDD, 0x8A44 }, + { 0xDBDE, 0x8A45 }, + { 0xDBDF, 0x8A52 }, + { 0xDBE0, 0x8A48 }, + { 0xDBE1, 0x8A51 }, + { 0xDBE2, 0x8A4A }, + { 0xDBE3, 0x8A4C }, + { 0xDBE4, 0x8A4F }, + { 0xDBE5, 0x8C5F }, + { 0xDBE6, 0x8C81 }, + { 0xDBE7, 0x8C80 }, + { 0xDBE8, 0x8CBA }, + { 0xDBE9, 0x8CBE }, + { 0xDBEA, 0x8CB0 }, + { 0xDBEB, 0x8CB9 }, + { 0xDBEC, 0x8CB5 }, + { 0xDBED, 0x8D84 }, + { 0xDBEE, 0x8D80 }, + { 0xDBEF, 0x8D89 }, + { 0xDBF0, 0x8DD8 }, + { 0xDBF1, 0x8DD3 }, + { 0xDBF2, 0x8DCD }, + { 0xDBF3, 0x8DC7 }, + { 0xDBF4, 0x8DD6 }, + { 0xDBF5, 0x8DDC }, + { 0xDBF6, 0x8DCF }, + { 0xDBF7, 0x8DD5 }, + { 0xDBF8, 0x8DD9 }, + { 0xDBF9, 0x8DC8 }, + { 0xDBFA, 0x8DD7 }, + { 0xDBFB, 0x8DC5 }, + { 0xDBFC, 0x8EEF }, + { 0xDBFD, 0x8EF7 }, + { 0xDBFE, 0x8EFA }, + { 0xDC40, 0x8EF9 }, + { 0xDC41, 0x8EE6 }, + { 0xDC42, 0x8EEE }, + { 0xDC43, 0x8EE5 }, + { 0xDC44, 0x8EF5 }, + { 0xDC45, 0x8EE7 }, + { 0xDC46, 0x8EE8 }, + { 0xDC47, 0x8EF6 }, + { 0xDC48, 0x8EEB }, + { 0xDC49, 0x8EF1 }, + { 0xDC4A, 0x8EEC }, + { 0xDC4B, 0x8EF4 }, + { 0xDC4C, 0x8EE9 }, + { 0xDC4D, 0x902D }, + { 0xDC4E, 0x9034 }, + { 0xDC4F, 0x902F }, + { 0xDC50, 0x9106 }, + { 0xDC51, 0x912C }, + { 0xDC52, 0x9104 }, + { 0xDC53, 0x90FF }, + { 0xDC54, 0x90FC }, + { 0xDC55, 0x9108 }, + { 0xDC56, 0x90F9 }, + { 0xDC57, 0x90FB }, + { 0xDC58, 0x9101 }, + { 0xDC59, 0x9100 }, + { 0xDC5A, 0x9107 }, + { 0xDC5B, 0x9105 }, + { 0xDC5C, 0x9103 }, + { 0xDC5D, 0x9161 }, + { 0xDC5E, 0x9164 }, + { 0xDC5F, 0x915F }, + { 0xDC60, 0x9162 }, + { 0xDC61, 0x9160 }, + { 0xDC62, 0x9201 }, + { 0xDC63, 0x920A }, + { 0xDC64, 0x9225 }, + { 0xDC65, 0x9203 }, + { 0xDC66, 0x921A }, + { 0xDC67, 0x9226 }, + { 0xDC68, 0x920F }, + { 0xDC69, 0x920C }, + { 0xDC6A, 0x9200 }, + { 0xDC6B, 0x9212 }, + { 0xDC6C, 0x91FF }, + { 0xDC6D, 0x91FD }, + { 0xDC6E, 0x9206 }, + { 0xDC6F, 0x9204 }, + { 0xDC70, 0x9227 }, + { 0xDC71, 0x9202 }, + { 0xDC72, 0x921C }, + { 0xDC73, 0x9224 }, + { 0xDC74, 0x9219 }, + { 0xDC75, 0x9217 }, + { 0xDC76, 0x9205 }, + { 0xDC77, 0x9216 }, + { 0xDC78, 0x957B }, + { 0xDC79, 0x958D }, + { 0xDC7A, 0x958C }, + { 0xDC7B, 0x9590 }, + { 0xDC7C, 0x9687 }, + { 0xDC7D, 0x967E }, + { 0xDC7E, 0x9688 }, + { 0xDCA1, 0x9689 }, + { 0xDCA2, 0x9683 }, + { 0xDCA3, 0x9680 }, + { 0xDCA4, 0x96C2 }, + { 0xDCA5, 0x96C8 }, + { 0xDCA6, 0x96C3 }, + { 0xDCA7, 0x96F1 }, + { 0xDCA8, 0x96F0 }, + { 0xDCA9, 0x976C }, + { 0xDCAA, 0x9770 }, + { 0xDCAB, 0x976E }, + { 0xDCAC, 0x9807 }, + { 0xDCAD, 0x98A9 }, + { 0xDCAE, 0x98EB }, + { 0xDCAF, 0x9CE6 }, + { 0xDCB0, 0x9EF9 }, + { 0xDCB1, 0x4E83 }, + { 0xDCB2, 0x4E84 }, + { 0xDCB3, 0x4EB6 }, + { 0xDCB4, 0x50BD }, + { 0xDCB5, 0x50BF }, + { 0xDCB6, 0x50C6 }, + { 0xDCB7, 0x50AE }, + { 0xDCB8, 0x50C4 }, + { 0xDCB9, 0x50CA }, + { 0xDCBA, 0x50B4 }, + { 0xDCBB, 0x50C8 }, + { 0xDCBC, 0x50C2 }, + { 0xDCBD, 0x50B0 }, + { 0xDCBE, 0x50C1 }, + { 0xDCBF, 0x50BA }, + { 0xDCC0, 0x50B1 }, + { 0xDCC1, 0x50CB }, + { 0xDCC2, 0x50C9 }, + { 0xDCC3, 0x50B6 }, + { 0xDCC4, 0x50B8 }, + { 0xDCC5, 0x51D7 }, + { 0xDCC6, 0x527A }, + { 0xDCC7, 0x5278 }, + { 0xDCC8, 0x527B }, + { 0xDCC9, 0x527C }, + { 0xDCCA, 0x55C3 }, + { 0xDCCB, 0x55DB }, + { 0xDCCC, 0x55CC }, + { 0xDCCD, 0x55D0 }, + { 0xDCCE, 0x55CB }, + { 0xDCCF, 0x55CA }, + { 0xDCD0, 0x55DD }, + { 0xDCD1, 0x55C0 }, + { 0xDCD2, 0x55D4 }, + { 0xDCD3, 0x55C4 }, + { 0xDCD4, 0x55E9 }, + { 0xDCD5, 0x55BF }, + { 0xDCD6, 0x55D2 }, + { 0xDCD7, 0x558D }, + { 0xDCD8, 0x55CF }, + { 0xDCD9, 0x55D5 }, + { 0xDCDA, 0x55E2 }, + { 0xDCDB, 0x55D6 }, + { 0xDCDC, 0x55C8 }, + { 0xDCDD, 0x55F2 }, + { 0xDCDE, 0x55CD }, + { 0xDCDF, 0x55D9 }, + { 0xDCE0, 0x55C2 }, + { 0xDCE1, 0x5714 }, + { 0xDCE2, 0x5853 }, + { 0xDCE3, 0x5868 }, + { 0xDCE4, 0x5864 }, + { 0xDCE5, 0x584F }, + { 0xDCE6, 0x584D }, + { 0xDCE7, 0x5849 }, + { 0xDCE8, 0x586F }, + { 0xDCE9, 0x5855 }, + { 0xDCEA, 0x584E }, + { 0xDCEB, 0x585D }, + { 0xDCEC, 0x5859 }, + { 0xDCED, 0x5865 }, + { 0xDCEE, 0x585B }, + { 0xDCEF, 0x583D }, + { 0xDCF0, 0x5863 }, + { 0xDCF1, 0x5871 }, + { 0xDCF2, 0x58FC }, + { 0xDCF3, 0x5AC7 }, + { 0xDCF4, 0x5AC4 }, + { 0xDCF5, 0x5ACB }, + { 0xDCF6, 0x5ABA }, + { 0xDCF7, 0x5AB8 }, + { 0xDCF8, 0x5AB1 }, + { 0xDCF9, 0x5AB5 }, + { 0xDCFA, 0x5AB0 }, + { 0xDCFB, 0x5ABF }, + { 0xDCFC, 0x5AC8 }, + { 0xDCFD, 0x5ABB }, + { 0xDCFE, 0x5AC6 }, + { 0xDD40, 0x5AB7 }, + { 0xDD41, 0x5AC0 }, + { 0xDD42, 0x5ACA }, + { 0xDD43, 0x5AB4 }, + { 0xDD44, 0x5AB6 }, + { 0xDD45, 0x5ACD }, + { 0xDD46, 0x5AB9 }, + { 0xDD47, 0x5A90 }, + { 0xDD48, 0x5BD6 }, + { 0xDD49, 0x5BD8 }, + { 0xDD4A, 0x5BD9 }, + { 0xDD4B, 0x5C1F }, + { 0xDD4C, 0x5C33 }, + { 0xDD4D, 0x5D71 }, + { 0xDD4E, 0x5D63 }, + { 0xDD4F, 0x5D4A }, + { 0xDD50, 0x5D65 }, + { 0xDD51, 0x5D72 }, + { 0xDD52, 0x5D6C }, + { 0xDD53, 0x5D5E }, + { 0xDD54, 0x5D68 }, + { 0xDD55, 0x5D67 }, + { 0xDD56, 0x5D62 }, + { 0xDD57, 0x5DF0 }, + { 0xDD58, 0x5E4F }, + { 0xDD59, 0x5E4E }, + { 0xDD5A, 0x5E4A }, + { 0xDD5B, 0x5E4D }, + { 0xDD5C, 0x5E4B }, + { 0xDD5D, 0x5EC5 }, + { 0xDD5E, 0x5ECC }, + { 0xDD5F, 0x5EC6 }, + { 0xDD60, 0x5ECB }, + { 0xDD61, 0x5EC7 }, + { 0xDD62, 0x5F40 }, + { 0xDD63, 0x5FAF }, + { 0xDD64, 0x5FAD }, + { 0xDD65, 0x60F7 }, + { 0xDD66, 0x6149 }, + { 0xDD67, 0x614A }, + { 0xDD68, 0x612B }, + { 0xDD69, 0x6145 }, + { 0xDD6A, 0x6136 }, + { 0xDD6B, 0x6132 }, + { 0xDD6C, 0x612E }, + { 0xDD6D, 0x6146 }, + { 0xDD6E, 0x612F }, + { 0xDD6F, 0x614F }, + { 0xDD70, 0x6129 }, + { 0xDD71, 0x6140 }, + { 0xDD72, 0x6220 }, + { 0xDD73, 0x9168 }, + { 0xDD74, 0x6223 }, + { 0xDD75, 0x6225 }, + { 0xDD76, 0x6224 }, + { 0xDD77, 0x63C5 }, + { 0xDD78, 0x63F1 }, + { 0xDD79, 0x63EB }, + { 0xDD7A, 0x6410 }, + { 0xDD7B, 0x6412 }, + { 0xDD7C, 0x6409 }, + { 0xDD7D, 0x6420 }, + { 0xDD7E, 0x6424 }, + { 0xDDA1, 0x6433 }, + { 0xDDA2, 0x6443 }, + { 0xDDA3, 0x641F }, + { 0xDDA4, 0x6415 }, + { 0xDDA5, 0x6418 }, + { 0xDDA6, 0x6439 }, + { 0xDDA7, 0x6437 }, + { 0xDDA8, 0x6422 }, + { 0xDDA9, 0x6423 }, + { 0xDDAA, 0x640C }, + { 0xDDAB, 0x6426 }, + { 0xDDAC, 0x6430 }, + { 0xDDAD, 0x6428 }, + { 0xDDAE, 0x6441 }, + { 0xDDAF, 0x6435 }, + { 0xDDB0, 0x642F }, + { 0xDDB1, 0x640A }, + { 0xDDB2, 0x641A }, + { 0xDDB3, 0x6440 }, + { 0xDDB4, 0x6425 }, + { 0xDDB5, 0x6427 }, + { 0xDDB6, 0x640B }, + { 0xDDB7, 0x63E7 }, + { 0xDDB8, 0x641B }, + { 0xDDB9, 0x642E }, + { 0xDDBA, 0x6421 }, + { 0xDDBB, 0x640E }, + { 0xDDBC, 0x656F }, + { 0xDDBD, 0x6592 }, + { 0xDDBE, 0x65D3 }, + { 0xDDBF, 0x6686 }, + { 0xDDC0, 0x668C }, + { 0xDDC1, 0x6695 }, + { 0xDDC2, 0x6690 }, + { 0xDDC3, 0x668B }, + { 0xDDC4, 0x668A }, + { 0xDDC5, 0x6699 }, + { 0xDDC6, 0x6694 }, + { 0xDDC7, 0x6678 }, + { 0xDDC8, 0x6720 }, + { 0xDDC9, 0x6966 }, + { 0xDDCA, 0x695F }, + { 0xDDCB, 0x6938 }, + { 0xDDCC, 0x694E }, + { 0xDDCD, 0x6962 }, + { 0xDDCE, 0x6971 }, + { 0xDDCF, 0x693F }, + { 0xDDD0, 0x6945 }, + { 0xDDD1, 0x696A }, + { 0xDDD2, 0x6939 }, + { 0xDDD3, 0x6942 }, + { 0xDDD4, 0x6957 }, + { 0xDDD5, 0x6959 }, + { 0xDDD6, 0x697A }, + { 0xDDD7, 0x6948 }, + { 0xDDD8, 0x6949 }, + { 0xDDD9, 0x6935 }, + { 0xDDDA, 0x696C }, + { 0xDDDB, 0x6933 }, + { 0xDDDC, 0x693D }, + { 0xDDDD, 0x6965 }, + { 0xDDDE, 0x68F0 }, + { 0xDDDF, 0x6978 }, + { 0xDDE0, 0x6934 }, + { 0xDDE1, 0x6969 }, + { 0xDDE2, 0x6940 }, + { 0xDDE3, 0x696F }, + { 0xDDE4, 0x6944 }, + { 0xDDE5, 0x6976 }, + { 0xDDE6, 0x6958 }, + { 0xDDE7, 0x6941 }, + { 0xDDE8, 0x6974 }, + { 0xDDE9, 0x694C }, + { 0xDDEA, 0x693B }, + { 0xDDEB, 0x694B }, + { 0xDDEC, 0x6937 }, + { 0xDDED, 0x695C }, + { 0xDDEE, 0x694F }, + { 0xDDEF, 0x6951 }, + { 0xDDF0, 0x6932 }, + { 0xDDF1, 0x6952 }, + { 0xDDF2, 0x692F }, + { 0xDDF3, 0x697B }, + { 0xDDF4, 0x693C }, + { 0xDDF5, 0x6B46 }, + { 0xDDF6, 0x6B45 }, + { 0xDDF7, 0x6B43 }, + { 0xDDF8, 0x6B42 }, + { 0xDDF9, 0x6B48 }, + { 0xDDFA, 0x6B41 }, + { 0xDDFB, 0x6B9B }, + { 0xDDFC, 0xFA0D }, + { 0xDDFD, 0x6BFB }, + { 0xDDFE, 0x6BFC }, + { 0xDE40, 0x6BF9 }, + { 0xDE41, 0x6BF7 }, + { 0xDE42, 0x6BF8 }, + { 0xDE43, 0x6E9B }, + { 0xDE44, 0x6ED6 }, + { 0xDE45, 0x6EC8 }, + { 0xDE46, 0x6E8F }, + { 0xDE47, 0x6EC0 }, + { 0xDE48, 0x6E9F }, + { 0xDE49, 0x6E93 }, + { 0xDE4A, 0x6E94 }, + { 0xDE4B, 0x6EA0 }, + { 0xDE4C, 0x6EB1 }, + { 0xDE4D, 0x6EB9 }, + { 0xDE4E, 0x6EC6 }, + { 0xDE4F, 0x6ED2 }, + { 0xDE50, 0x6EBD }, + { 0xDE51, 0x6EC1 }, + { 0xDE52, 0x6E9E }, + { 0xDE53, 0x6EC9 }, + { 0xDE54, 0x6EB7 }, + { 0xDE55, 0x6EB0 }, + { 0xDE56, 0x6ECD }, + { 0xDE57, 0x6EA6 }, + { 0xDE58, 0x6ECF }, + { 0xDE59, 0x6EB2 }, + { 0xDE5A, 0x6EBE }, + { 0xDE5B, 0x6EC3 }, + { 0xDE5C, 0x6EDC }, + { 0xDE5D, 0x6ED8 }, + { 0xDE5E, 0x6E99 }, + { 0xDE5F, 0x6E92 }, + { 0xDE60, 0x6E8E }, + { 0xDE61, 0x6E8D }, + { 0xDE62, 0x6EA4 }, + { 0xDE63, 0x6EA1 }, + { 0xDE64, 0x6EBF }, + { 0xDE65, 0x6EB3 }, + { 0xDE66, 0x6ED0 }, + { 0xDE67, 0x6ECA }, + { 0xDE68, 0x6E97 }, + { 0xDE69, 0x6EAE }, + { 0xDE6A, 0x6EA3 }, + { 0xDE6B, 0x7147 }, + { 0xDE6C, 0x7154 }, + { 0xDE6D, 0x7152 }, + { 0xDE6E, 0x7163 }, + { 0xDE6F, 0x7160 }, + { 0xDE70, 0x7141 }, + { 0xDE71, 0x715D }, + { 0xDE72, 0x7162 }, + { 0xDE73, 0x7172 }, + { 0xDE74, 0x7178 }, + { 0xDE75, 0x716A }, + { 0xDE76, 0x7161 }, + { 0xDE77, 0x7142 }, + { 0xDE78, 0x7158 }, + { 0xDE79, 0x7143 }, + { 0xDE7A, 0x714B }, + { 0xDE7B, 0x7170 }, + { 0xDE7C, 0x715F }, + { 0xDE7D, 0x7150 }, + { 0xDE7E, 0x7153 }, + { 0xDEA1, 0x7144 }, + { 0xDEA2, 0x714D }, + { 0xDEA3, 0x715A }, + { 0xDEA4, 0x724F }, + { 0xDEA5, 0x728D }, + { 0xDEA6, 0x728C }, + { 0xDEA7, 0x7291 }, + { 0xDEA8, 0x7290 }, + { 0xDEA9, 0x728E }, + { 0xDEAA, 0x733C }, + { 0xDEAB, 0x7342 }, + { 0xDEAC, 0x733B }, + { 0xDEAD, 0x733A }, + { 0xDEAE, 0x7340 }, + { 0xDEAF, 0x734A }, + { 0xDEB0, 0x7349 }, + { 0xDEB1, 0x7444 }, + { 0xDEB2, 0x744A }, + { 0xDEB3, 0x744B }, + { 0xDEB4, 0x7452 }, + { 0xDEB5, 0x7451 }, + { 0xDEB6, 0x7457 }, + { 0xDEB7, 0x7440 }, + { 0xDEB8, 0x744F }, + { 0xDEB9, 0x7450 }, + { 0xDEBA, 0x744E }, + { 0xDEBB, 0x7442 }, + { 0xDEBC, 0x7446 }, + { 0xDEBD, 0x744D }, + { 0xDEBE, 0x7454 }, + { 0xDEBF, 0x74E1 }, + { 0xDEC0, 0x74FF }, + { 0xDEC1, 0x74FE }, + { 0xDEC2, 0x74FD }, + { 0xDEC3, 0x751D }, + { 0xDEC4, 0x7579 }, + { 0xDEC5, 0x7577 }, + { 0xDEC6, 0x6983 }, + { 0xDEC7, 0x75EF }, + { 0xDEC8, 0x760F }, + { 0xDEC9, 0x7603 }, + { 0xDECA, 0x75F7 }, + { 0xDECB, 0x75FE }, + { 0xDECC, 0x75FC }, + { 0xDECD, 0x75F9 }, + { 0xDECE, 0x75F8 }, + { 0xDECF, 0x7610 }, + { 0xDED0, 0x75FB }, + { 0xDED1, 0x75F6 }, + { 0xDED2, 0x75ED }, + { 0xDED3, 0x75F5 }, + { 0xDED4, 0x75FD }, + { 0xDED5, 0x7699 }, + { 0xDED6, 0x76B5 }, + { 0xDED7, 0x76DD }, + { 0xDED8, 0x7755 }, + { 0xDED9, 0x775F }, + { 0xDEDA, 0x7760 }, + { 0xDEDB, 0x7752 }, + { 0xDEDC, 0x7756 }, + { 0xDEDD, 0x775A }, + { 0xDEDE, 0x7769 }, + { 0xDEDF, 0x7767 }, + { 0xDEE0, 0x7754 }, + { 0xDEE1, 0x7759 }, + { 0xDEE2, 0x776D }, + { 0xDEE3, 0x77E0 }, + { 0xDEE4, 0x7887 }, + { 0xDEE5, 0x789A }, + { 0xDEE6, 0x7894 }, + { 0xDEE7, 0x788F }, + { 0xDEE8, 0x7884 }, + { 0xDEE9, 0x7895 }, + { 0xDEEA, 0x7885 }, + { 0xDEEB, 0x7886 }, + { 0xDEEC, 0x78A1 }, + { 0xDEED, 0x7883 }, + { 0xDEEE, 0x7879 }, + { 0xDEEF, 0x7899 }, + { 0xDEF0, 0x7880 }, + { 0xDEF1, 0x7896 }, + { 0xDEF2, 0x787B }, + { 0xDEF3, 0x797C }, + { 0xDEF4, 0x7982 }, + { 0xDEF5, 0x797D }, + { 0xDEF6, 0x7979 }, + { 0xDEF7, 0x7A11 }, + { 0xDEF8, 0x7A18 }, + { 0xDEF9, 0x7A19 }, + { 0xDEFA, 0x7A12 }, + { 0xDEFB, 0x7A17 }, + { 0xDEFC, 0x7A15 }, + { 0xDEFD, 0x7A22 }, + { 0xDEFE, 0x7A13 }, + { 0xDF40, 0x7A1B }, + { 0xDF41, 0x7A10 }, + { 0xDF42, 0x7AA3 }, + { 0xDF43, 0x7AA2 }, + { 0xDF44, 0x7A9E }, + { 0xDF45, 0x7AEB }, + { 0xDF46, 0x7B66 }, + { 0xDF47, 0x7B64 }, + { 0xDF48, 0x7B6D }, + { 0xDF49, 0x7B74 }, + { 0xDF4A, 0x7B69 }, + { 0xDF4B, 0x7B72 }, + { 0xDF4C, 0x7B65 }, + { 0xDF4D, 0x7B73 }, + { 0xDF4E, 0x7B71 }, + { 0xDF4F, 0x7B70 }, + { 0xDF50, 0x7B61 }, + { 0xDF51, 0x7B78 }, + { 0xDF52, 0x7B76 }, + { 0xDF53, 0x7B63 }, + { 0xDF54, 0x7CB2 }, + { 0xDF55, 0x7CB4 }, + { 0xDF56, 0x7CAF }, + { 0xDF57, 0x7D88 }, + { 0xDF58, 0x7D86 }, + { 0xDF59, 0x7D80 }, + { 0xDF5A, 0x7D8D }, + { 0xDF5B, 0x7D7F }, + { 0xDF5C, 0x7D85 }, + { 0xDF5D, 0x7D7A }, + { 0xDF5E, 0x7D8E }, + { 0xDF5F, 0x7D7B }, + { 0xDF60, 0x7D83 }, + { 0xDF61, 0x7D7C }, + { 0xDF62, 0x7D8C }, + { 0xDF63, 0x7D94 }, + { 0xDF64, 0x7D84 }, + { 0xDF65, 0x7D7D }, + { 0xDF66, 0x7D92 }, + { 0xDF67, 0x7F6D }, + { 0xDF68, 0x7F6B }, + { 0xDF69, 0x7F67 }, + { 0xDF6A, 0x7F68 }, + { 0xDF6B, 0x7F6C }, + { 0xDF6C, 0x7FA6 }, + { 0xDF6D, 0x7FA5 }, + { 0xDF6E, 0x7FA7 }, + { 0xDF6F, 0x7FDB }, + { 0xDF70, 0x7FDC }, + { 0xDF71, 0x8021 }, + { 0xDF72, 0x8164 }, + { 0xDF73, 0x8160 }, + { 0xDF74, 0x8177 }, + { 0xDF75, 0x815C }, + { 0xDF76, 0x8169 }, + { 0xDF77, 0x815B }, + { 0xDF78, 0x8162 }, + { 0xDF79, 0x8172 }, + { 0xDF7A, 0x6721 }, + { 0xDF7B, 0x815E }, + { 0xDF7C, 0x8176 }, + { 0xDF7D, 0x8167 }, + { 0xDF7E, 0x816F }, + { 0xDFA1, 0x8144 }, + { 0xDFA2, 0x8161 }, + { 0xDFA3, 0x821D }, + { 0xDFA4, 0x8249 }, + { 0xDFA5, 0x8244 }, + { 0xDFA6, 0x8240 }, + { 0xDFA7, 0x8242 }, + { 0xDFA8, 0x8245 }, + { 0xDFA9, 0x84F1 }, + { 0xDFAA, 0x843F }, + { 0xDFAB, 0x8456 }, + { 0xDFAC, 0x8476 }, + { 0xDFAD, 0x8479 }, + { 0xDFAE, 0x848F }, + { 0xDFAF, 0x848D }, + { 0xDFB0, 0x8465 }, + { 0xDFB1, 0x8451 }, + { 0xDFB2, 0x8440 }, + { 0xDFB3, 0x8486 }, + { 0xDFB4, 0x8467 }, + { 0xDFB5, 0x8430 }, + { 0xDFB6, 0x844D }, + { 0xDFB7, 0x847D }, + { 0xDFB8, 0x845A }, + { 0xDFB9, 0x8459 }, + { 0xDFBA, 0x8474 }, + { 0xDFBB, 0x8473 }, + { 0xDFBC, 0x845D }, + { 0xDFBD, 0x8507 }, + { 0xDFBE, 0x845E }, + { 0xDFBF, 0x8437 }, + { 0xDFC0, 0x843A }, + { 0xDFC1, 0x8434 }, + { 0xDFC2, 0x847A }, + { 0xDFC3, 0x8443 }, + { 0xDFC4, 0x8478 }, + { 0xDFC5, 0x8432 }, + { 0xDFC6, 0x8445 }, + { 0xDFC7, 0x8429 }, + { 0xDFC8, 0x83D9 }, + { 0xDFC9, 0x844B }, + { 0xDFCA, 0x842F }, + { 0xDFCB, 0x8442 }, + { 0xDFCC, 0x842D }, + { 0xDFCD, 0x845F }, + { 0xDFCE, 0x8470 }, + { 0xDFCF, 0x8439 }, + { 0xDFD0, 0x844E }, + { 0xDFD1, 0x844C }, + { 0xDFD2, 0x8452 }, + { 0xDFD3, 0x846F }, + { 0xDFD4, 0x84C5 }, + { 0xDFD5, 0x848E }, + { 0xDFD6, 0x843B }, + { 0xDFD7, 0x8447 }, + { 0xDFD8, 0x8436 }, + { 0xDFD9, 0x8433 }, + { 0xDFDA, 0x8468 }, + { 0xDFDB, 0x847E }, + { 0xDFDC, 0x8444 }, + { 0xDFDD, 0x842B }, + { 0xDFDE, 0x8460 }, + { 0xDFDF, 0x8454 }, + { 0xDFE0, 0x846E }, + { 0xDFE1, 0x8450 }, + { 0xDFE2, 0x870B }, + { 0xDFE3, 0x8704 }, + { 0xDFE4, 0x86F7 }, + { 0xDFE5, 0x870C }, + { 0xDFE6, 0x86FA }, + { 0xDFE7, 0x86D6 }, + { 0xDFE8, 0x86F5 }, + { 0xDFE9, 0x874D }, + { 0xDFEA, 0x86F8 }, + { 0xDFEB, 0x870E }, + { 0xDFEC, 0x8709 }, + { 0xDFED, 0x8701 }, + { 0xDFEE, 0x86F6 }, + { 0xDFEF, 0x870D }, + { 0xDFF0, 0x8705 }, + { 0xDFF1, 0x88D6 }, + { 0xDFF2, 0x88CB }, + { 0xDFF3, 0x88CD }, + { 0xDFF4, 0x88CE }, + { 0xDFF5, 0x88DE }, + { 0xDFF6, 0x88DB }, + { 0xDFF7, 0x88DA }, + { 0xDFF8, 0x88CC }, + { 0xDFF9, 0x88D0 }, + { 0xDFFA, 0x8985 }, + { 0xDFFB, 0x899B }, + { 0xDFFC, 0x89DF }, + { 0xDFFD, 0x89E5 }, + { 0xDFFE, 0x89E4 }, + { 0xE040, 0x89E1 }, + { 0xE041, 0x89E0 }, + { 0xE042, 0x89E2 }, + { 0xE043, 0x89DC }, + { 0xE044, 0x89E6 }, + { 0xE045, 0x8A76 }, + { 0xE046, 0x8A86 }, + { 0xE047, 0x8A7F }, + { 0xE048, 0x8A61 }, + { 0xE049, 0x8A3F }, + { 0xE04A, 0x8A77 }, + { 0xE04B, 0x8A82 }, + { 0xE04C, 0x8A84 }, + { 0xE04D, 0x8A75 }, + { 0xE04E, 0x8A83 }, + { 0xE04F, 0x8A81 }, + { 0xE050, 0x8A74 }, + { 0xE051, 0x8A7A }, + { 0xE052, 0x8C3C }, + { 0xE053, 0x8C4B }, + { 0xE054, 0x8C4A }, + { 0xE055, 0x8C65 }, + { 0xE056, 0x8C64 }, + { 0xE057, 0x8C66 }, + { 0xE058, 0x8C86 }, + { 0xE059, 0x8C84 }, + { 0xE05A, 0x8C85 }, + { 0xE05B, 0x8CCC }, + { 0xE05C, 0x8D68 }, + { 0xE05D, 0x8D69 }, + { 0xE05E, 0x8D91 }, + { 0xE05F, 0x8D8C }, + { 0xE060, 0x8D8E }, + { 0xE061, 0x8D8F }, + { 0xE062, 0x8D8D }, + { 0xE063, 0x8D93 }, + { 0xE064, 0x8D94 }, + { 0xE065, 0x8D90 }, + { 0xE066, 0x8D92 }, + { 0xE067, 0x8DF0 }, + { 0xE068, 0x8DE0 }, + { 0xE069, 0x8DEC }, + { 0xE06A, 0x8DF1 }, + { 0xE06B, 0x8DEE }, + { 0xE06C, 0x8DD0 }, + { 0xE06D, 0x8DE9 }, + { 0xE06E, 0x8DE3 }, + { 0xE06F, 0x8DE2 }, + { 0xE070, 0x8DE7 }, + { 0xE071, 0x8DF2 }, + { 0xE072, 0x8DEB }, + { 0xE073, 0x8DF4 }, + { 0xE074, 0x8F06 }, + { 0xE075, 0x8EFF }, + { 0xE076, 0x8F01 }, + { 0xE077, 0x8F00 }, + { 0xE078, 0x8F05 }, + { 0xE079, 0x8F07 }, + { 0xE07A, 0x8F08 }, + { 0xE07B, 0x8F02 }, + { 0xE07C, 0x8F0B }, + { 0xE07D, 0x9052 }, + { 0xE07E, 0x903F }, + { 0xE0A1, 0x9044 }, + { 0xE0A2, 0x9049 }, + { 0xE0A3, 0x903D }, + { 0xE0A4, 0x9110 }, + { 0xE0A5, 0x910D }, + { 0xE0A6, 0x910F }, + { 0xE0A7, 0x9111 }, + { 0xE0A8, 0x9116 }, + { 0xE0A9, 0x9114 }, + { 0xE0AA, 0x910B }, + { 0xE0AB, 0x910E }, + { 0xE0AC, 0x916E }, + { 0xE0AD, 0x916F }, + { 0xE0AE, 0x9248 }, + { 0xE0AF, 0x9252 }, + { 0xE0B0, 0x9230 }, + { 0xE0B1, 0x923A }, + { 0xE0B2, 0x9266 }, + { 0xE0B3, 0x9233 }, + { 0xE0B4, 0x9265 }, + { 0xE0B5, 0x925E }, + { 0xE0B6, 0x9283 }, + { 0xE0B7, 0x922E }, + { 0xE0B8, 0x924A }, + { 0xE0B9, 0x9246 }, + { 0xE0BA, 0x926D }, + { 0xE0BB, 0x926C }, + { 0xE0BC, 0x924F }, + { 0xE0BD, 0x9260 }, + { 0xE0BE, 0x9267 }, + { 0xE0BF, 0x926F }, + { 0xE0C0, 0x9236 }, + { 0xE0C1, 0x9261 }, + { 0xE0C2, 0x9270 }, + { 0xE0C3, 0x9231 }, + { 0xE0C4, 0x9254 }, + { 0xE0C5, 0x9263 }, + { 0xE0C6, 0x9250 }, + { 0xE0C7, 0x9272 }, + { 0xE0C8, 0x924E }, + { 0xE0C9, 0x9253 }, + { 0xE0CA, 0x924C }, + { 0xE0CB, 0x9256 }, + { 0xE0CC, 0x9232 }, + { 0xE0CD, 0x959F }, + { 0xE0CE, 0x959C }, + { 0xE0CF, 0x959E }, + { 0xE0D0, 0x959B }, + { 0xE0D1, 0x9692 }, + { 0xE0D2, 0x9693 }, + { 0xE0D3, 0x9691 }, + { 0xE0D4, 0x9697 }, + { 0xE0D5, 0x96CE }, + { 0xE0D6, 0x96FA }, + { 0xE0D7, 0x96FD }, + { 0xE0D8, 0x96F8 }, + { 0xE0D9, 0x96F5 }, + { 0xE0DA, 0x9773 }, + { 0xE0DB, 0x9777 }, + { 0xE0DC, 0x9778 }, + { 0xE0DD, 0x9772 }, + { 0xE0DE, 0x980F }, + { 0xE0DF, 0x980D }, + { 0xE0E0, 0x980E }, + { 0xE0E1, 0x98AC }, + { 0xE0E2, 0x98F6 }, + { 0xE0E3, 0x98F9 }, + { 0xE0E4, 0x99AF }, + { 0xE0E5, 0x99B2 }, + { 0xE0E6, 0x99B0 }, + { 0xE0E7, 0x99B5 }, + { 0xE0E8, 0x9AAD }, + { 0xE0E9, 0x9AAB }, + { 0xE0EA, 0x9B5B }, + { 0xE0EB, 0x9CEA }, + { 0xE0EC, 0x9CED }, + { 0xE0ED, 0x9CE7 }, + { 0xE0EE, 0x9E80 }, + { 0xE0EF, 0x9EFD }, + { 0xE0F0, 0x50E6 }, + { 0xE0F1, 0x50D4 }, + { 0xE0F2, 0x50D7 }, + { 0xE0F3, 0x50E8 }, + { 0xE0F4, 0x50F3 }, + { 0xE0F5, 0x50DB }, + { 0xE0F6, 0x50EA }, + { 0xE0F7, 0x50DD }, + { 0xE0F8, 0x50E4 }, + { 0xE0F9, 0x50D3 }, + { 0xE0FA, 0x50EC }, + { 0xE0FB, 0x50F0 }, + { 0xE0FC, 0x50EF }, + { 0xE0FD, 0x50E3 }, + { 0xE0FE, 0x50E0 }, + { 0xE140, 0x51D8 }, + { 0xE141, 0x5280 }, + { 0xE142, 0x5281 }, + { 0xE143, 0x52E9 }, + { 0xE144, 0x52EB }, + { 0xE145, 0x5330 }, + { 0xE146, 0x53AC }, + { 0xE147, 0x5627 }, + { 0xE148, 0x5615 }, + { 0xE149, 0x560C }, + { 0xE14A, 0x5612 }, + { 0xE14B, 0x55FC }, + { 0xE14C, 0x560F }, + { 0xE14D, 0x561C }, + { 0xE14E, 0x5601 }, + { 0xE14F, 0x5613 }, + { 0xE150, 0x5602 }, + { 0xE151, 0x55FA }, + { 0xE152, 0x561D }, + { 0xE153, 0x5604 }, + { 0xE154, 0x55FF }, + { 0xE155, 0x55F9 }, + { 0xE156, 0x5889 }, + { 0xE157, 0x587C }, + { 0xE158, 0x5890 }, + { 0xE159, 0x5898 }, + { 0xE15A, 0x5886 }, + { 0xE15B, 0x5881 }, + { 0xE15C, 0x587F }, + { 0xE15D, 0x5874 }, + { 0xE15E, 0x588B }, + { 0xE15F, 0x587A }, + { 0xE160, 0x5887 }, + { 0xE161, 0x5891 }, + { 0xE162, 0x588E }, + { 0xE163, 0x5876 }, + { 0xE164, 0x5882 }, + { 0xE165, 0x5888 }, + { 0xE166, 0x587B }, + { 0xE167, 0x5894 }, + { 0xE168, 0x588F }, + { 0xE169, 0x58FE }, + { 0xE16A, 0x596B }, + { 0xE16B, 0x5ADC }, + { 0xE16C, 0x5AEE }, + { 0xE16D, 0x5AE5 }, + { 0xE16E, 0x5AD5 }, + { 0xE16F, 0x5AEA }, + { 0xE170, 0x5ADA }, + { 0xE171, 0x5AED }, + { 0xE172, 0x5AEB }, + { 0xE173, 0x5AF3 }, + { 0xE174, 0x5AE2 }, + { 0xE175, 0x5AE0 }, + { 0xE176, 0x5ADB }, + { 0xE177, 0x5AEC }, + { 0xE178, 0x5ADE }, + { 0xE179, 0x5ADD }, + { 0xE17A, 0x5AD9 }, + { 0xE17B, 0x5AE8 }, + { 0xE17C, 0x5ADF }, + { 0xE17D, 0x5B77 }, + { 0xE17E, 0x5BE0 }, + { 0xE1A1, 0x5BE3 }, + { 0xE1A2, 0x5C63 }, + { 0xE1A3, 0x5D82 }, + { 0xE1A4, 0x5D80 }, + { 0xE1A5, 0x5D7D }, + { 0xE1A6, 0x5D86 }, + { 0xE1A7, 0x5D7A }, + { 0xE1A8, 0x5D81 }, + { 0xE1A9, 0x5D77 }, + { 0xE1AA, 0x5D8A }, + { 0xE1AB, 0x5D89 }, + { 0xE1AC, 0x5D88 }, + { 0xE1AD, 0x5D7E }, + { 0xE1AE, 0x5D7C }, + { 0xE1AF, 0x5D8D }, + { 0xE1B0, 0x5D79 }, + { 0xE1B1, 0x5D7F }, + { 0xE1B2, 0x5E58 }, + { 0xE1B3, 0x5E59 }, + { 0xE1B4, 0x5E53 }, + { 0xE1B5, 0x5ED8 }, + { 0xE1B6, 0x5ED1 }, + { 0xE1B7, 0x5ED7 }, + { 0xE1B8, 0x5ECE }, + { 0xE1B9, 0x5EDC }, + { 0xE1BA, 0x5ED5 }, + { 0xE1BB, 0x5ED9 }, + { 0xE1BC, 0x5ED2 }, + { 0xE1BD, 0x5ED4 }, + { 0xE1BE, 0x5F44 }, + { 0xE1BF, 0x5F43 }, + { 0xE1C0, 0x5F6F }, + { 0xE1C1, 0x5FB6 }, + { 0xE1C2, 0x612C }, + { 0xE1C3, 0x6128 }, + { 0xE1C4, 0x6141 }, + { 0xE1C5, 0x615E }, + { 0xE1C6, 0x6171 }, + { 0xE1C7, 0x6173 }, + { 0xE1C8, 0x6152 }, + { 0xE1C9, 0x6153 }, + { 0xE1CA, 0x6172 }, + { 0xE1CB, 0x616C }, + { 0xE1CC, 0x6180 }, + { 0xE1CD, 0x6174 }, + { 0xE1CE, 0x6154 }, + { 0xE1CF, 0x617A }, + { 0xE1D0, 0x615B }, + { 0xE1D1, 0x6165 }, + { 0xE1D2, 0x613B }, + { 0xE1D3, 0x616A }, + { 0xE1D4, 0x6161 }, + { 0xE1D5, 0x6156 }, + { 0xE1D6, 0x6229 }, + { 0xE1D7, 0x6227 }, + { 0xE1D8, 0x622B }, + { 0xE1D9, 0x642B }, + { 0xE1DA, 0x644D }, + { 0xE1DB, 0x645B }, + { 0xE1DC, 0x645D }, + { 0xE1DD, 0x6474 }, + { 0xE1DE, 0x6476 }, + { 0xE1DF, 0x6472 }, + { 0xE1E0, 0x6473 }, + { 0xE1E1, 0x647D }, + { 0xE1E2, 0x6475 }, + { 0xE1E3, 0x6466 }, + { 0xE1E4, 0x64A6 }, + { 0xE1E5, 0x644E }, + { 0xE1E6, 0x6482 }, + { 0xE1E7, 0x645E }, + { 0xE1E8, 0x645C }, + { 0xE1E9, 0x644B }, + { 0xE1EA, 0x6453 }, + { 0xE1EB, 0x6460 }, + { 0xE1EC, 0x6450 }, + { 0xE1ED, 0x647F }, + { 0xE1EE, 0x643F }, + { 0xE1EF, 0x646C }, + { 0xE1F0, 0x646B }, + { 0xE1F1, 0x6459 }, + { 0xE1F2, 0x6465 }, + { 0xE1F3, 0x6477 }, + { 0xE1F4, 0x6573 }, + { 0xE1F5, 0x65A0 }, + { 0xE1F6, 0x66A1 }, + { 0xE1F7, 0x66A0 }, + { 0xE1F8, 0x669F }, + { 0xE1F9, 0x6705 }, + { 0xE1FA, 0x6704 }, + { 0xE1FB, 0x6722 }, + { 0xE1FC, 0x69B1 }, + { 0xE1FD, 0x69B6 }, + { 0xE1FE, 0x69C9 }, + { 0xE240, 0x69A0 }, + { 0xE241, 0x69CE }, + { 0xE242, 0x6996 }, + { 0xE243, 0x69B0 }, + { 0xE244, 0x69AC }, + { 0xE245, 0x69BC }, + { 0xE246, 0x6991 }, + { 0xE247, 0x6999 }, + { 0xE248, 0x698E }, + { 0xE249, 0x69A7 }, + { 0xE24A, 0x698D }, + { 0xE24B, 0x69A9 }, + { 0xE24C, 0x69BE }, + { 0xE24D, 0x69AF }, + { 0xE24E, 0x69BF }, + { 0xE24F, 0x69C4 }, + { 0xE250, 0x69BD }, + { 0xE251, 0x69A4 }, + { 0xE252, 0x69D4 }, + { 0xE253, 0x69B9 }, + { 0xE254, 0x69CA }, + { 0xE255, 0x699A }, + { 0xE256, 0x69CF }, + { 0xE257, 0x69B3 }, + { 0xE258, 0x6993 }, + { 0xE259, 0x69AA }, + { 0xE25A, 0x69A1 }, + { 0xE25B, 0x699E }, + { 0xE25C, 0x69D9 }, + { 0xE25D, 0x6997 }, + { 0xE25E, 0x6990 }, + { 0xE25F, 0x69C2 }, + { 0xE260, 0x69B5 }, + { 0xE261, 0x69A5 }, + { 0xE262, 0x69C6 }, + { 0xE263, 0x6B4A }, + { 0xE264, 0x6B4D }, + { 0xE265, 0x6B4B }, + { 0xE266, 0x6B9E }, + { 0xE267, 0x6B9F }, + { 0xE268, 0x6BA0 }, + { 0xE269, 0x6BC3 }, + { 0xE26A, 0x6BC4 }, + { 0xE26B, 0x6BFE }, + { 0xE26C, 0x6ECE }, + { 0xE26D, 0x6EF5 }, + { 0xE26E, 0x6EF1 }, + { 0xE26F, 0x6F03 }, + { 0xE270, 0x6F25 }, + { 0xE271, 0x6EF8 }, + { 0xE272, 0x6F37 }, + { 0xE273, 0x6EFB }, + { 0xE274, 0x6F2E }, + { 0xE275, 0x6F09 }, + { 0xE276, 0x6F4E }, + { 0xE277, 0x6F19 }, + { 0xE278, 0x6F1A }, + { 0xE279, 0x6F27 }, + { 0xE27A, 0x6F18 }, + { 0xE27B, 0x6F3B }, + { 0xE27C, 0x6F12 }, + { 0xE27D, 0x6EED }, + { 0xE27E, 0x6F0A }, + { 0xE2A1, 0x6F36 }, + { 0xE2A2, 0x6F73 }, + { 0xE2A3, 0x6EF9 }, + { 0xE2A4, 0x6EEE }, + { 0xE2A5, 0x6F2D }, + { 0xE2A6, 0x6F40 }, + { 0xE2A7, 0x6F30 }, + { 0xE2A8, 0x6F3C }, + { 0xE2A9, 0x6F35 }, + { 0xE2AA, 0x6EEB }, + { 0xE2AB, 0x6F07 }, + { 0xE2AC, 0x6F0E }, + { 0xE2AD, 0x6F43 }, + { 0xE2AE, 0x6F05 }, + { 0xE2AF, 0x6EFD }, + { 0xE2B0, 0x6EF6 }, + { 0xE2B1, 0x6F39 }, + { 0xE2B2, 0x6F1C }, + { 0xE2B3, 0x6EFC }, + { 0xE2B4, 0x6F3A }, + { 0xE2B5, 0x6F1F }, + { 0xE2B6, 0x6F0D }, + { 0xE2B7, 0x6F1E }, + { 0xE2B8, 0x6F08 }, + { 0xE2B9, 0x6F21 }, + { 0xE2BA, 0x7187 }, + { 0xE2BB, 0x7190 }, + { 0xE2BC, 0x7189 }, + { 0xE2BD, 0x7180 }, + { 0xE2BE, 0x7185 }, + { 0xE2BF, 0x7182 }, + { 0xE2C0, 0x718F }, + { 0xE2C1, 0x717B }, + { 0xE2C2, 0x7186 }, + { 0xE2C3, 0x7181 }, + { 0xE2C4, 0x7197 }, + { 0xE2C5, 0x7244 }, + { 0xE2C6, 0x7253 }, + { 0xE2C7, 0x7297 }, + { 0xE2C8, 0x7295 }, + { 0xE2C9, 0x7293 }, + { 0xE2CA, 0x7343 }, + { 0xE2CB, 0x734D }, + { 0xE2CC, 0x7351 }, + { 0xE2CD, 0x734C }, + { 0xE2CE, 0x7462 }, + { 0xE2CF, 0x7473 }, + { 0xE2D0, 0x7471 }, + { 0xE2D1, 0x7475 }, + { 0xE2D2, 0x7472 }, + { 0xE2D3, 0x7467 }, + { 0xE2D4, 0x746E }, + { 0xE2D5, 0x7500 }, + { 0xE2D6, 0x7502 }, + { 0xE2D7, 0x7503 }, + { 0xE2D8, 0x757D }, + { 0xE2D9, 0x7590 }, + { 0xE2DA, 0x7616 }, + { 0xE2DB, 0x7608 }, + { 0xE2DC, 0x760C }, + { 0xE2DD, 0x7615 }, + { 0xE2DE, 0x7611 }, + { 0xE2DF, 0x760A }, + { 0xE2E0, 0x7614 }, + { 0xE2E1, 0x76B8 }, + { 0xE2E2, 0x7781 }, + { 0xE2E3, 0x777C }, + { 0xE2E4, 0x7785 }, + { 0xE2E5, 0x7782 }, + { 0xE2E6, 0x776E }, + { 0xE2E7, 0x7780 }, + { 0xE2E8, 0x776F }, + { 0xE2E9, 0x777E }, + { 0xE2EA, 0x7783 }, + { 0xE2EB, 0x78B2 }, + { 0xE2EC, 0x78AA }, + { 0xE2ED, 0x78B4 }, + { 0xE2EE, 0x78AD }, + { 0xE2EF, 0x78A8 }, + { 0xE2F0, 0x787E }, + { 0xE2F1, 0x78AB }, + { 0xE2F2, 0x789E }, + { 0xE2F3, 0x78A5 }, + { 0xE2F4, 0x78A0 }, + { 0xE2F5, 0x78AC }, + { 0xE2F6, 0x78A2 }, + { 0xE2F7, 0x78A4 }, + { 0xE2F8, 0x7998 }, + { 0xE2F9, 0x798A }, + { 0xE2FA, 0x798B }, + { 0xE2FB, 0x7996 }, + { 0xE2FC, 0x7995 }, + { 0xE2FD, 0x7994 }, + { 0xE2FE, 0x7993 }, + { 0xE340, 0x7997 }, + { 0xE341, 0x7988 }, + { 0xE342, 0x7992 }, + { 0xE343, 0x7990 }, + { 0xE344, 0x7A2B }, + { 0xE345, 0x7A4A }, + { 0xE346, 0x7A30 }, + { 0xE347, 0x7A2F }, + { 0xE348, 0x7A28 }, + { 0xE349, 0x7A26 }, + { 0xE34A, 0x7AA8 }, + { 0xE34B, 0x7AAB }, + { 0xE34C, 0x7AAC }, + { 0xE34D, 0x7AEE }, + { 0xE34E, 0x7B88 }, + { 0xE34F, 0x7B9C }, + { 0xE350, 0x7B8A }, + { 0xE351, 0x7B91 }, + { 0xE352, 0x7B90 }, + { 0xE353, 0x7B96 }, + { 0xE354, 0x7B8D }, + { 0xE355, 0x7B8C }, + { 0xE356, 0x7B9B }, + { 0xE357, 0x7B8E }, + { 0xE358, 0x7B85 }, + { 0xE359, 0x7B98 }, + { 0xE35A, 0x5284 }, + { 0xE35B, 0x7B99 }, + { 0xE35C, 0x7BA4 }, + { 0xE35D, 0x7B82 }, + { 0xE35E, 0x7CBB }, + { 0xE35F, 0x7CBF }, + { 0xE360, 0x7CBC }, + { 0xE361, 0x7CBA }, + { 0xE362, 0x7DA7 }, + { 0xE363, 0x7DB7 }, + { 0xE364, 0x7DC2 }, + { 0xE365, 0x7DA3 }, + { 0xE366, 0x7DAA }, + { 0xE367, 0x7DC1 }, + { 0xE368, 0x7DC0 }, + { 0xE369, 0x7DC5 }, + { 0xE36A, 0x7D9D }, + { 0xE36B, 0x7DCE }, + { 0xE36C, 0x7DC4 }, + { 0xE36D, 0x7DC6 }, + { 0xE36E, 0x7DCB }, + { 0xE36F, 0x7DCC }, + { 0xE370, 0x7DAF }, + { 0xE371, 0x7DB9 }, + { 0xE372, 0x7D96 }, + { 0xE373, 0x7DBC }, + { 0xE374, 0x7D9F }, + { 0xE375, 0x7DA6 }, + { 0xE376, 0x7DAE }, + { 0xE377, 0x7DA9 }, + { 0xE378, 0x7DA1 }, + { 0xE379, 0x7DC9 }, + { 0xE37A, 0x7F73 }, + { 0xE37B, 0x7FE2 }, + { 0xE37C, 0x7FE3 }, + { 0xE37D, 0x7FE5 }, + { 0xE37E, 0x7FDE }, + { 0xE3A1, 0x8024 }, + { 0xE3A2, 0x805D }, + { 0xE3A3, 0x805C }, + { 0xE3A4, 0x8189 }, + { 0xE3A5, 0x8186 }, + { 0xE3A6, 0x8183 }, + { 0xE3A7, 0x8187 }, + { 0xE3A8, 0x818D }, + { 0xE3A9, 0x818C }, + { 0xE3AA, 0x818B }, + { 0xE3AB, 0x8215 }, + { 0xE3AC, 0x8497 }, + { 0xE3AD, 0x84A4 }, + { 0xE3AE, 0x84A1 }, + { 0xE3AF, 0x849F }, + { 0xE3B0, 0x84BA }, + { 0xE3B1, 0x84CE }, + { 0xE3B2, 0x84C2 }, + { 0xE3B3, 0x84AC }, + { 0xE3B4, 0x84AE }, + { 0xE3B5, 0x84AB }, + { 0xE3B6, 0x84B9 }, + { 0xE3B7, 0x84B4 }, + { 0xE3B8, 0x84C1 }, + { 0xE3B9, 0x84CD }, + { 0xE3BA, 0x84AA }, + { 0xE3BB, 0x849A }, + { 0xE3BC, 0x84B1 }, + { 0xE3BD, 0x84D0 }, + { 0xE3BE, 0x849D }, + { 0xE3BF, 0x84A7 }, + { 0xE3C0, 0x84BB }, + { 0xE3C1, 0x84A2 }, + { 0xE3C2, 0x8494 }, + { 0xE3C3, 0x84C7 }, + { 0xE3C4, 0x84CC }, + { 0xE3C5, 0x849B }, + { 0xE3C6, 0x84A9 }, + { 0xE3C7, 0x84AF }, + { 0xE3C8, 0x84A8 }, + { 0xE3C9, 0x84D6 }, + { 0xE3CA, 0x8498 }, + { 0xE3CB, 0x84B6 }, + { 0xE3CC, 0x84CF }, + { 0xE3CD, 0x84A0 }, + { 0xE3CE, 0x84D7 }, + { 0xE3CF, 0x84D4 }, + { 0xE3D0, 0x84D2 }, + { 0xE3D1, 0x84DB }, + { 0xE3D2, 0x84B0 }, + { 0xE3D3, 0x8491 }, + { 0xE3D4, 0x8661 }, + { 0xE3D5, 0x8733 }, + { 0xE3D6, 0x8723 }, + { 0xE3D7, 0x8728 }, + { 0xE3D8, 0x876B }, + { 0xE3D9, 0x8740 }, + { 0xE3DA, 0x872E }, + { 0xE3DB, 0x871E }, + { 0xE3DC, 0x8721 }, + { 0xE3DD, 0x8719 }, + { 0xE3DE, 0x871B }, + { 0xE3DF, 0x8743 }, + { 0xE3E0, 0x872C }, + { 0xE3E1, 0x8741 }, + { 0xE3E2, 0x873E }, + { 0xE3E3, 0x8746 }, + { 0xE3E4, 0x8720 }, + { 0xE3E5, 0x8732 }, + { 0xE3E6, 0x872A }, + { 0xE3E7, 0x872D }, + { 0xE3E8, 0x873C }, + { 0xE3E9, 0x8712 }, + { 0xE3EA, 0x873A }, + { 0xE3EB, 0x8731 }, + { 0xE3EC, 0x8735 }, + { 0xE3ED, 0x8742 }, + { 0xE3EE, 0x8726 }, + { 0xE3EF, 0x8727 }, + { 0xE3F0, 0x8738 }, + { 0xE3F1, 0x8724 }, + { 0xE3F2, 0x871A }, + { 0xE3F3, 0x8730 }, + { 0xE3F4, 0x8711 }, + { 0xE3F5, 0x88F7 }, + { 0xE3F6, 0x88E7 }, + { 0xE3F7, 0x88F1 }, + { 0xE3F8, 0x88F2 }, + { 0xE3F9, 0x88FA }, + { 0xE3FA, 0x88FE }, + { 0xE3FB, 0x88EE }, + { 0xE3FC, 0x88FC }, + { 0xE3FD, 0x88F6 }, + { 0xE3FE, 0x88FB }, + { 0xE440, 0x88F0 }, + { 0xE441, 0x88EC }, + { 0xE442, 0x88EB }, + { 0xE443, 0x899D }, + { 0xE444, 0x89A1 }, + { 0xE445, 0x899F }, + { 0xE446, 0x899E }, + { 0xE447, 0x89E9 }, + { 0xE448, 0x89EB }, + { 0xE449, 0x89E8 }, + { 0xE44A, 0x8AAB }, + { 0xE44B, 0x8A99 }, + { 0xE44C, 0x8A8B }, + { 0xE44D, 0x8A92 }, + { 0xE44E, 0x8A8F }, + { 0xE44F, 0x8A96 }, + { 0xE450, 0x8C3D }, + { 0xE451, 0x8C68 }, + { 0xE452, 0x8C69 }, + { 0xE453, 0x8CD5 }, + { 0xE454, 0x8CCF }, + { 0xE455, 0x8CD7 }, + { 0xE456, 0x8D96 }, + { 0xE457, 0x8E09 }, + { 0xE458, 0x8E02 }, + { 0xE459, 0x8DFF }, + { 0xE45A, 0x8E0D }, + { 0xE45B, 0x8DFD }, + { 0xE45C, 0x8E0A }, + { 0xE45D, 0x8E03 }, + { 0xE45E, 0x8E07 }, + { 0xE45F, 0x8E06 }, + { 0xE460, 0x8E05 }, + { 0xE461, 0x8DFE }, + { 0xE462, 0x8E00 }, + { 0xE463, 0x8E04 }, + { 0xE464, 0x8F10 }, + { 0xE465, 0x8F11 }, + { 0xE466, 0x8F0E }, + { 0xE467, 0x8F0D }, + { 0xE468, 0x9123 }, + { 0xE469, 0x911C }, + { 0xE46A, 0x9120 }, + { 0xE46B, 0x9122 }, + { 0xE46C, 0x911F }, + { 0xE46D, 0x911D }, + { 0xE46E, 0x911A }, + { 0xE46F, 0x9124 }, + { 0xE470, 0x9121 }, + { 0xE471, 0x911B }, + { 0xE472, 0x917A }, + { 0xE473, 0x9172 }, + { 0xE474, 0x9179 }, + { 0xE475, 0x9173 }, + { 0xE476, 0x92A5 }, + { 0xE477, 0x92A4 }, + { 0xE478, 0x9276 }, + { 0xE479, 0x929B }, + { 0xE47A, 0x927A }, + { 0xE47B, 0x92A0 }, + { 0xE47C, 0x9294 }, + { 0xE47D, 0x92AA }, + { 0xE47E, 0x928D }, + { 0xE4A1, 0x92A6 }, + { 0xE4A2, 0x929A }, + { 0xE4A3, 0x92AB }, + { 0xE4A4, 0x9279 }, + { 0xE4A5, 0x9297 }, + { 0xE4A6, 0x927F }, + { 0xE4A7, 0x92A3 }, + { 0xE4A8, 0x92EE }, + { 0xE4A9, 0x928E }, + { 0xE4AA, 0x9282 }, + { 0xE4AB, 0x9295 }, + { 0xE4AC, 0x92A2 }, + { 0xE4AD, 0x927D }, + { 0xE4AE, 0x9288 }, + { 0xE4AF, 0x92A1 }, + { 0xE4B0, 0x928A }, + { 0xE4B1, 0x9286 }, + { 0xE4B2, 0x928C }, + { 0xE4B3, 0x9299 }, + { 0xE4B4, 0x92A7 }, + { 0xE4B5, 0x927E }, + { 0xE4B6, 0x9287 }, + { 0xE4B7, 0x92A9 }, + { 0xE4B8, 0x929D }, + { 0xE4B9, 0x928B }, + { 0xE4BA, 0x922D }, + { 0xE4BB, 0x969E }, + { 0xE4BC, 0x96A1 }, + { 0xE4BD, 0x96FF }, + { 0xE4BE, 0x9758 }, + { 0xE4BF, 0x977D }, + { 0xE4C0, 0x977A }, + { 0xE4C1, 0x977E }, + { 0xE4C2, 0x9783 }, + { 0xE4C3, 0x9780 }, + { 0xE4C4, 0x9782 }, + { 0xE4C5, 0x977B }, + { 0xE4C6, 0x9784 }, + { 0xE4C7, 0x9781 }, + { 0xE4C8, 0x977F }, + { 0xE4C9, 0x97CE }, + { 0xE4CA, 0x97CD }, + { 0xE4CB, 0x9816 }, + { 0xE4CC, 0x98AD }, + { 0xE4CD, 0x98AE }, + { 0xE4CE, 0x9902 }, + { 0xE4CF, 0x9900 }, + { 0xE4D0, 0x9907 }, + { 0xE4D1, 0x999D }, + { 0xE4D2, 0x999C }, + { 0xE4D3, 0x99C3 }, + { 0xE4D4, 0x99B9 }, + { 0xE4D5, 0x99BB }, + { 0xE4D6, 0x99BA }, + { 0xE4D7, 0x99C2 }, + { 0xE4D8, 0x99BD }, + { 0xE4D9, 0x99C7 }, + { 0xE4DA, 0x9AB1 }, + { 0xE4DB, 0x9AE3 }, + { 0xE4DC, 0x9AE7 }, + { 0xE4DD, 0x9B3E }, + { 0xE4DE, 0x9B3F }, + { 0xE4DF, 0x9B60 }, + { 0xE4E0, 0x9B61 }, + { 0xE4E1, 0x9B5F }, + { 0xE4E2, 0x9CF1 }, + { 0xE4E3, 0x9CF2 }, + { 0xE4E4, 0x9CF5 }, + { 0xE4E5, 0x9EA7 }, + { 0xE4E6, 0x50FF }, + { 0xE4E7, 0x5103 }, + { 0xE4E8, 0x5130 }, + { 0xE4E9, 0x50F8 }, + { 0xE4EA, 0x5106 }, + { 0xE4EB, 0x5107 }, + { 0xE4EC, 0x50F6 }, + { 0xE4ED, 0x50FE }, + { 0xE4EE, 0x510B }, + { 0xE4EF, 0x510C }, + { 0xE4F0, 0x50FD }, + { 0xE4F1, 0x510A }, + { 0xE4F2, 0x528B }, + { 0xE4F3, 0x528C }, + { 0xE4F4, 0x52F1 }, + { 0xE4F5, 0x52EF }, + { 0xE4F6, 0x5648 }, + { 0xE4F7, 0x5642 }, + { 0xE4F8, 0x564C }, + { 0xE4F9, 0x5635 }, + { 0xE4FA, 0x5641 }, + { 0xE4FB, 0x564A }, + { 0xE4FC, 0x5649 }, + { 0xE4FD, 0x5646 }, + { 0xE4FE, 0x5658 }, + { 0xE540, 0x565A }, + { 0xE541, 0x5640 }, + { 0xE542, 0x5633 }, + { 0xE543, 0x563D }, + { 0xE544, 0x562C }, + { 0xE545, 0x563E }, + { 0xE546, 0x5638 }, + { 0xE547, 0x562A }, + { 0xE548, 0x563A }, + { 0xE549, 0x571A }, + { 0xE54A, 0x58AB }, + { 0xE54B, 0x589D }, + { 0xE54C, 0x58B1 }, + { 0xE54D, 0x58A0 }, + { 0xE54E, 0x58A3 }, + { 0xE54F, 0x58AF }, + { 0xE550, 0x58AC }, + { 0xE551, 0x58A5 }, + { 0xE552, 0x58A1 }, + { 0xE553, 0x58FF }, + { 0xE554, 0x5AFF }, + { 0xE555, 0x5AF4 }, + { 0xE556, 0x5AFD }, + { 0xE557, 0x5AF7 }, + { 0xE558, 0x5AF6 }, + { 0xE559, 0x5B03 }, + { 0xE55A, 0x5AF8 }, + { 0xE55B, 0x5B02 }, + { 0xE55C, 0x5AF9 }, + { 0xE55D, 0x5B01 }, + { 0xE55E, 0x5B07 }, + { 0xE55F, 0x5B05 }, + { 0xE560, 0x5B0F }, + { 0xE561, 0x5C67 }, + { 0xE562, 0x5D99 }, + { 0xE563, 0x5D97 }, + { 0xE564, 0x5D9F }, + { 0xE565, 0x5D92 }, + { 0xE566, 0x5DA2 }, + { 0xE567, 0x5D93 }, + { 0xE568, 0x5D95 }, + { 0xE569, 0x5DA0 }, + { 0xE56A, 0x5D9C }, + { 0xE56B, 0x5DA1 }, + { 0xE56C, 0x5D9A }, + { 0xE56D, 0x5D9E }, + { 0xE56E, 0x5E69 }, + { 0xE56F, 0x5E5D }, + { 0xE570, 0x5E60 }, + { 0xE571, 0x5E5C }, + { 0xE572, 0x7DF3 }, + { 0xE573, 0x5EDB }, + { 0xE574, 0x5EDE }, + { 0xE575, 0x5EE1 }, + { 0xE576, 0x5F49 }, + { 0xE577, 0x5FB2 }, + { 0xE578, 0x618B }, + { 0xE579, 0x6183 }, + { 0xE57A, 0x6179 }, + { 0xE57B, 0x61B1 }, + { 0xE57C, 0x61B0 }, + { 0xE57D, 0x61A2 }, + { 0xE57E, 0x6189 }, + { 0xE5A1, 0x619B }, + { 0xE5A2, 0x6193 }, + { 0xE5A3, 0x61AF }, + { 0xE5A4, 0x61AD }, + { 0xE5A5, 0x619F }, + { 0xE5A6, 0x6192 }, + { 0xE5A7, 0x61AA }, + { 0xE5A8, 0x61A1 }, + { 0xE5A9, 0x618D }, + { 0xE5AA, 0x6166 }, + { 0xE5AB, 0x61B3 }, + { 0xE5AC, 0x622D }, + { 0xE5AD, 0x646E }, + { 0xE5AE, 0x6470 }, + { 0xE5AF, 0x6496 }, + { 0xE5B0, 0x64A0 }, + { 0xE5B1, 0x6485 }, + { 0xE5B2, 0x6497 }, + { 0xE5B3, 0x649C }, + { 0xE5B4, 0x648F }, + { 0xE5B5, 0x648B }, + { 0xE5B6, 0x648A }, + { 0xE5B7, 0x648C }, + { 0xE5B8, 0x64A3 }, + { 0xE5B9, 0x649F }, + { 0xE5BA, 0x6468 }, + { 0xE5BB, 0x64B1 }, + { 0xE5BC, 0x6498 }, + { 0xE5BD, 0x6576 }, + { 0xE5BE, 0x657A }, + { 0xE5BF, 0x6579 }, + { 0xE5C0, 0x657B }, + { 0xE5C1, 0x65B2 }, + { 0xE5C2, 0x65B3 }, + { 0xE5C3, 0x66B5 }, + { 0xE5C4, 0x66B0 }, + { 0xE5C5, 0x66A9 }, + { 0xE5C6, 0x66B2 }, + { 0xE5C7, 0x66B7 }, + { 0xE5C8, 0x66AA }, + { 0xE5C9, 0x66AF }, + { 0xE5CA, 0x6A00 }, + { 0xE5CB, 0x6A06 }, + { 0xE5CC, 0x6A17 }, + { 0xE5CD, 0x69E5 }, + { 0xE5CE, 0x69F8 }, + { 0xE5CF, 0x6A15 }, + { 0xE5D0, 0x69F1 }, + { 0xE5D1, 0x69E4 }, + { 0xE5D2, 0x6A20 }, + { 0xE5D3, 0x69FF }, + { 0xE5D4, 0x69EC }, + { 0xE5D5, 0x69E2 }, + { 0xE5D6, 0x6A1B }, + { 0xE5D7, 0x6A1D }, + { 0xE5D8, 0x69FE }, + { 0xE5D9, 0x6A27 }, + { 0xE5DA, 0x69F2 }, + { 0xE5DB, 0x69EE }, + { 0xE5DC, 0x6A14 }, + { 0xE5DD, 0x69F7 }, + { 0xE5DE, 0x69E7 }, + { 0xE5DF, 0x6A40 }, + { 0xE5E0, 0x6A08 }, + { 0xE5E1, 0x69E6 }, + { 0xE5E2, 0x69FB }, + { 0xE5E3, 0x6A0D }, + { 0xE5E4, 0x69FC }, + { 0xE5E5, 0x69EB }, + { 0xE5E6, 0x6A09 }, + { 0xE5E7, 0x6A04 }, + { 0xE5E8, 0x6A18 }, + { 0xE5E9, 0x6A25 }, + { 0xE5EA, 0x6A0F }, + { 0xE5EB, 0x69F6 }, + { 0xE5EC, 0x6A26 }, + { 0xE5ED, 0x6A07 }, + { 0xE5EE, 0x69F4 }, + { 0xE5EF, 0x6A16 }, + { 0xE5F0, 0x6B51 }, + { 0xE5F1, 0x6BA5 }, + { 0xE5F2, 0x6BA3 }, + { 0xE5F3, 0x6BA2 }, + { 0xE5F4, 0x6BA6 }, + { 0xE5F5, 0x6C01 }, + { 0xE5F6, 0x6C00 }, + { 0xE5F7, 0x6BFF }, + { 0xE5F8, 0x6C02 }, + { 0xE5F9, 0x6F41 }, + { 0xE5FA, 0x6F26 }, + { 0xE5FB, 0x6F7E }, + { 0xE5FC, 0x6F87 }, + { 0xE5FD, 0x6FC6 }, + { 0xE5FE, 0x6F92 }, + { 0xE640, 0x6F8D }, + { 0xE641, 0x6F89 }, + { 0xE642, 0x6F8C }, + { 0xE643, 0x6F62 }, + { 0xE644, 0x6F4F }, + { 0xE645, 0x6F85 }, + { 0xE646, 0x6F5A }, + { 0xE647, 0x6F96 }, + { 0xE648, 0x6F76 }, + { 0xE649, 0x6F6C }, + { 0xE64A, 0x6F82 }, + { 0xE64B, 0x6F55 }, + { 0xE64C, 0x6F72 }, + { 0xE64D, 0x6F52 }, + { 0xE64E, 0x6F50 }, + { 0xE64F, 0x6F57 }, + { 0xE650, 0x6F94 }, + { 0xE651, 0x6F93 }, + { 0xE652, 0x6F5D }, + { 0xE653, 0x6F00 }, + { 0xE654, 0x6F61 }, + { 0xE655, 0x6F6B }, + { 0xE656, 0x6F7D }, + { 0xE657, 0x6F67 }, + { 0xE658, 0x6F90 }, + { 0xE659, 0x6F53 }, + { 0xE65A, 0x6F8B }, + { 0xE65B, 0x6F69 }, + { 0xE65C, 0x6F7F }, + { 0xE65D, 0x6F95 }, + { 0xE65E, 0x6F63 }, + { 0xE65F, 0x6F77 }, + { 0xE660, 0x6F6A }, + { 0xE661, 0x6F7B }, + { 0xE662, 0x71B2 }, + { 0xE663, 0x71AF }, + { 0xE664, 0x719B }, + { 0xE665, 0x71B0 }, + { 0xE666, 0x71A0 }, + { 0xE667, 0x719A }, + { 0xE668, 0x71A9 }, + { 0xE669, 0x71B5 }, + { 0xE66A, 0x719D }, + { 0xE66B, 0x71A5 }, + { 0xE66C, 0x719E }, + { 0xE66D, 0x71A4 }, + { 0xE66E, 0x71A1 }, + { 0xE66F, 0x71AA }, + { 0xE670, 0x719C }, + { 0xE671, 0x71A7 }, + { 0xE672, 0x71B3 }, + { 0xE673, 0x7298 }, + { 0xE674, 0x729A }, + { 0xE675, 0x7358 }, + { 0xE676, 0x7352 }, + { 0xE677, 0x735E }, + { 0xE678, 0x735F }, + { 0xE679, 0x7360 }, + { 0xE67A, 0x735D }, + { 0xE67B, 0x735B }, + { 0xE67C, 0x7361 }, + { 0xE67D, 0x735A }, + { 0xE67E, 0x7359 }, + { 0xE6A1, 0x7362 }, + { 0xE6A2, 0x7487 }, + { 0xE6A3, 0x7489 }, + { 0xE6A4, 0x748A }, + { 0xE6A5, 0x7486 }, + { 0xE6A6, 0x7481 }, + { 0xE6A7, 0x747D }, + { 0xE6A8, 0x7485 }, + { 0xE6A9, 0x7488 }, + { 0xE6AA, 0x747C }, + { 0xE6AB, 0x7479 }, + { 0xE6AC, 0x7508 }, + { 0xE6AD, 0x7507 }, + { 0xE6AE, 0x757E }, + { 0xE6AF, 0x7625 }, + { 0xE6B0, 0x761E }, + { 0xE6B1, 0x7619 }, + { 0xE6B2, 0x761D }, + { 0xE6B3, 0x761C }, + { 0xE6B4, 0x7623 }, + { 0xE6B5, 0x761A }, + { 0xE6B6, 0x7628 }, + { 0xE6B7, 0x761B }, + { 0xE6B8, 0x769C }, + { 0xE6B9, 0x769D }, + { 0xE6BA, 0x769E }, + { 0xE6BB, 0x769B }, + { 0xE6BC, 0x778D }, + { 0xE6BD, 0x778F }, + { 0xE6BE, 0x7789 }, + { 0xE6BF, 0x7788 }, + { 0xE6C0, 0x78CD }, + { 0xE6C1, 0x78BB }, + { 0xE6C2, 0x78CF }, + { 0xE6C3, 0x78CC }, + { 0xE6C4, 0x78D1 }, + { 0xE6C5, 0x78CE }, + { 0xE6C6, 0x78D4 }, + { 0xE6C7, 0x78C8 }, + { 0xE6C8, 0x78C3 }, + { 0xE6C9, 0x78C4 }, + { 0xE6CA, 0x78C9 }, + { 0xE6CB, 0x799A }, + { 0xE6CC, 0x79A1 }, + { 0xE6CD, 0x79A0 }, + { 0xE6CE, 0x799C }, + { 0xE6CF, 0x79A2 }, + { 0xE6D0, 0x799B }, + { 0xE6D1, 0x6B76 }, + { 0xE6D2, 0x7A39 }, + { 0xE6D3, 0x7AB2 }, + { 0xE6D4, 0x7AB4 }, + { 0xE6D5, 0x7AB3 }, + { 0xE6D6, 0x7BB7 }, + { 0xE6D7, 0x7BCB }, + { 0xE6D8, 0x7BBE }, + { 0xE6D9, 0x7BAC }, + { 0xE6DA, 0x7BCE }, + { 0xE6DB, 0x7BAF }, + { 0xE6DC, 0x7BB9 }, + { 0xE6DD, 0x7BCA }, + { 0xE6DE, 0x7BB5 }, + { 0xE6DF, 0x7CC5 }, + { 0xE6E0, 0x7CC8 }, + { 0xE6E1, 0x7CCC }, + { 0xE6E2, 0x7CCB }, + { 0xE6E3, 0x7DF7 }, + { 0xE6E4, 0x7DDB }, + { 0xE6E5, 0x7DEA }, + { 0xE6E6, 0x7DE7 }, + { 0xE6E7, 0x7DD7 }, + { 0xE6E8, 0x7DE1 }, + { 0xE6E9, 0x7E03 }, + { 0xE6EA, 0x7DFA }, + { 0xE6EB, 0x7DE6 }, + { 0xE6EC, 0x7DF6 }, + { 0xE6ED, 0x7DF1 }, + { 0xE6EE, 0x7DF0 }, + { 0xE6EF, 0x7DEE }, + { 0xE6F0, 0x7DDF }, + { 0xE6F1, 0x7F76 }, + { 0xE6F2, 0x7FAC }, + { 0xE6F3, 0x7FB0 }, + { 0xE6F4, 0x7FAD }, + { 0xE6F5, 0x7FED }, + { 0xE6F6, 0x7FEB }, + { 0xE6F7, 0x7FEA }, + { 0xE6F8, 0x7FEC }, + { 0xE6F9, 0x7FE6 }, + { 0xE6FA, 0x7FE8 }, + { 0xE6FB, 0x8064 }, + { 0xE6FC, 0x8067 }, + { 0xE6FD, 0x81A3 }, + { 0xE6FE, 0x819F }, + { 0xE740, 0x819E }, + { 0xE741, 0x8195 }, + { 0xE742, 0x81A2 }, + { 0xE743, 0x8199 }, + { 0xE744, 0x8197 }, + { 0xE745, 0x8216 }, + { 0xE746, 0x824F }, + { 0xE747, 0x8253 }, + { 0xE748, 0x8252 }, + { 0xE749, 0x8250 }, + { 0xE74A, 0x824E }, + { 0xE74B, 0x8251 }, + { 0xE74C, 0x8524 }, + { 0xE74D, 0x853B }, + { 0xE74E, 0x850F }, + { 0xE74F, 0x8500 }, + { 0xE750, 0x8529 }, + { 0xE751, 0x850E }, + { 0xE752, 0x8509 }, + { 0xE753, 0x850D }, + { 0xE754, 0x851F }, + { 0xE755, 0x850A }, + { 0xE756, 0x8527 }, + { 0xE757, 0x851C }, + { 0xE758, 0x84FB }, + { 0xE759, 0x852B }, + { 0xE75A, 0x84FA }, + { 0xE75B, 0x8508 }, + { 0xE75C, 0x850C }, + { 0xE75D, 0x84F4 }, + { 0xE75E, 0x852A }, + { 0xE75F, 0x84F2 }, + { 0xE760, 0x8515 }, + { 0xE761, 0x84F7 }, + { 0xE762, 0x84EB }, + { 0xE763, 0x84F3 }, + { 0xE764, 0x84FC }, + { 0xE765, 0x8512 }, + { 0xE766, 0x84EA }, + { 0xE767, 0x84E9 }, + { 0xE768, 0x8516 }, + { 0xE769, 0x84FE }, + { 0xE76A, 0x8528 }, + { 0xE76B, 0x851D }, + { 0xE76C, 0x852E }, + { 0xE76D, 0x8502 }, + { 0xE76E, 0x84FD }, + { 0xE76F, 0x851E }, + { 0xE770, 0x84F6 }, + { 0xE771, 0x8531 }, + { 0xE772, 0x8526 }, + { 0xE773, 0x84E7 }, + { 0xE774, 0x84E8 }, + { 0xE775, 0x84F0 }, + { 0xE776, 0x84EF }, + { 0xE777, 0x84F9 }, + { 0xE778, 0x8518 }, + { 0xE779, 0x8520 }, + { 0xE77A, 0x8530 }, + { 0xE77B, 0x850B }, + { 0xE77C, 0x8519 }, + { 0xE77D, 0x852F }, + { 0xE77E, 0x8662 }, + { 0xE7A1, 0x8756 }, + { 0xE7A2, 0x8763 }, + { 0xE7A3, 0x8764 }, + { 0xE7A4, 0x8777 }, + { 0xE7A5, 0x87E1 }, + { 0xE7A6, 0x8773 }, + { 0xE7A7, 0x8758 }, + { 0xE7A8, 0x8754 }, + { 0xE7A9, 0x875B }, + { 0xE7AA, 0x8752 }, + { 0xE7AB, 0x8761 }, + { 0xE7AC, 0x875A }, + { 0xE7AD, 0x8751 }, + { 0xE7AE, 0x875E }, + { 0xE7AF, 0x876D }, + { 0xE7B0, 0x876A }, + { 0xE7B1, 0x8750 }, + { 0xE7B2, 0x874E }, + { 0xE7B3, 0x875F }, + { 0xE7B4, 0x875D }, + { 0xE7B5, 0x876F }, + { 0xE7B6, 0x876C }, + { 0xE7B7, 0x877A }, + { 0xE7B8, 0x876E }, + { 0xE7B9, 0x875C }, + { 0xE7BA, 0x8765 }, + { 0xE7BB, 0x874F }, + { 0xE7BC, 0x877B }, + { 0xE7BD, 0x8775 }, + { 0xE7BE, 0x8762 }, + { 0xE7BF, 0x8767 }, + { 0xE7C0, 0x8769 }, + { 0xE7C1, 0x885A }, + { 0xE7C2, 0x8905 }, + { 0xE7C3, 0x890C }, + { 0xE7C4, 0x8914 }, + { 0xE7C5, 0x890B }, + { 0xE7C6, 0x8917 }, + { 0xE7C7, 0x8918 }, + { 0xE7C8, 0x8919 }, + { 0xE7C9, 0x8906 }, + { 0xE7CA, 0x8916 }, + { 0xE7CB, 0x8911 }, + { 0xE7CC, 0x890E }, + { 0xE7CD, 0x8909 }, + { 0xE7CE, 0x89A2 }, + { 0xE7CF, 0x89A4 }, + { 0xE7D0, 0x89A3 }, + { 0xE7D1, 0x89ED }, + { 0xE7D2, 0x89F0 }, + { 0xE7D3, 0x89EC }, + { 0xE7D4, 0x8ACF }, + { 0xE7D5, 0x8AC6 }, + { 0xE7D6, 0x8AB8 }, + { 0xE7D7, 0x8AD3 }, + { 0xE7D8, 0x8AD1 }, + { 0xE7D9, 0x8AD4 }, + { 0xE7DA, 0x8AD5 }, + { 0xE7DB, 0x8ABB }, + { 0xE7DC, 0x8AD7 }, + { 0xE7DD, 0x8ABE }, + { 0xE7DE, 0x8AC0 }, + { 0xE7DF, 0x8AC5 }, + { 0xE7E0, 0x8AD8 }, + { 0xE7E1, 0x8AC3 }, + { 0xE7E2, 0x8ABA }, + { 0xE7E3, 0x8ABD }, + { 0xE7E4, 0x8AD9 }, + { 0xE7E5, 0x8C3E }, + { 0xE7E6, 0x8C4D }, + { 0xE7E7, 0x8C8F }, + { 0xE7E8, 0x8CE5 }, + { 0xE7E9, 0x8CDF }, + { 0xE7EA, 0x8CD9 }, + { 0xE7EB, 0x8CE8 }, + { 0xE7EC, 0x8CDA }, + { 0xE7ED, 0x8CDD }, + { 0xE7EE, 0x8CE7 }, + { 0xE7EF, 0x8DA0 }, + { 0xE7F0, 0x8D9C }, + { 0xE7F1, 0x8DA1 }, + { 0xE7F2, 0x8D9B }, + { 0xE7F3, 0x8E20 }, + { 0xE7F4, 0x8E23 }, + { 0xE7F5, 0x8E25 }, + { 0xE7F6, 0x8E24 }, + { 0xE7F7, 0x8E2E }, + { 0xE7F8, 0x8E15 }, + { 0xE7F9, 0x8E1B }, + { 0xE7FA, 0x8E16 }, + { 0xE7FB, 0x8E11 }, + { 0xE7FC, 0x8E19 }, + { 0xE7FD, 0x8E26 }, + { 0xE7FE, 0x8E27 }, + { 0xE840, 0x8E14 }, + { 0xE841, 0x8E12 }, + { 0xE842, 0x8E18 }, + { 0xE843, 0x8E13 }, + { 0xE844, 0x8E1C }, + { 0xE845, 0x8E17 }, + { 0xE846, 0x8E1A }, + { 0xE847, 0x8F2C }, + { 0xE848, 0x8F24 }, + { 0xE849, 0x8F18 }, + { 0xE84A, 0x8F1A }, + { 0xE84B, 0x8F20 }, + { 0xE84C, 0x8F23 }, + { 0xE84D, 0x8F16 }, + { 0xE84E, 0x8F17 }, + { 0xE84F, 0x9073 }, + { 0xE850, 0x9070 }, + { 0xE851, 0x906F }, + { 0xE852, 0x9067 }, + { 0xE853, 0x906B }, + { 0xE854, 0x912F }, + { 0xE855, 0x912B }, + { 0xE856, 0x9129 }, + { 0xE857, 0x912A }, + { 0xE858, 0x9132 }, + { 0xE859, 0x9126 }, + { 0xE85A, 0x912E }, + { 0xE85B, 0x9185 }, + { 0xE85C, 0x9186 }, + { 0xE85D, 0x918A }, + { 0xE85E, 0x9181 }, + { 0xE85F, 0x9182 }, + { 0xE860, 0x9184 }, + { 0xE861, 0x9180 }, + { 0xE862, 0x92D0 }, + { 0xE863, 0x92C3 }, + { 0xE864, 0x92C4 }, + { 0xE865, 0x92C0 }, + { 0xE866, 0x92D9 }, + { 0xE867, 0x92B6 }, + { 0xE868, 0x92CF }, + { 0xE869, 0x92F1 }, + { 0xE86A, 0x92DF }, + { 0xE86B, 0x92D8 }, + { 0xE86C, 0x92E9 }, + { 0xE86D, 0x92D7 }, + { 0xE86E, 0x92DD }, + { 0xE86F, 0x92CC }, + { 0xE870, 0x92EF }, + { 0xE871, 0x92C2 }, + { 0xE872, 0x92E8 }, + { 0xE873, 0x92CA }, + { 0xE874, 0x92C8 }, + { 0xE875, 0x92CE }, + { 0xE876, 0x92E6 }, + { 0xE877, 0x92CD }, + { 0xE878, 0x92D5 }, + { 0xE879, 0x92C9 }, + { 0xE87A, 0x92E0 }, + { 0xE87B, 0x92DE }, + { 0xE87C, 0x92E7 }, + { 0xE87D, 0x92D1 }, + { 0xE87E, 0x92D3 }, + { 0xE8A1, 0x92B5 }, + { 0xE8A2, 0x92E1 }, + { 0xE8A3, 0x92C6 }, + { 0xE8A4, 0x92B4 }, + { 0xE8A5, 0x957C }, + { 0xE8A6, 0x95AC }, + { 0xE8A7, 0x95AB }, + { 0xE8A8, 0x95AE }, + { 0xE8A9, 0x95B0 }, + { 0xE8AA, 0x96A4 }, + { 0xE8AB, 0x96A2 }, + { 0xE8AC, 0x96D3 }, + { 0xE8AD, 0x9705 }, + { 0xE8AE, 0x9708 }, + { 0xE8AF, 0x9702 }, + { 0xE8B0, 0x975A }, + { 0xE8B1, 0x978A }, + { 0xE8B2, 0x978E }, + { 0xE8B3, 0x9788 }, + { 0xE8B4, 0x97D0 }, + { 0xE8B5, 0x97CF }, + { 0xE8B6, 0x981E }, + { 0xE8B7, 0x981D }, + { 0xE8B8, 0x9826 }, + { 0xE8B9, 0x9829 }, + { 0xE8BA, 0x9828 }, + { 0xE8BB, 0x9820 }, + { 0xE8BC, 0x981B }, + { 0xE8BD, 0x9827 }, + { 0xE8BE, 0x98B2 }, + { 0xE8BF, 0x9908 }, + { 0xE8C0, 0x98FA }, + { 0xE8C1, 0x9911 }, + { 0xE8C2, 0x9914 }, + { 0xE8C3, 0x9916 }, + { 0xE8C4, 0x9917 }, + { 0xE8C5, 0x9915 }, + { 0xE8C6, 0x99DC }, + { 0xE8C7, 0x99CD }, + { 0xE8C8, 0x99CF }, + { 0xE8C9, 0x99D3 }, + { 0xE8CA, 0x99D4 }, + { 0xE8CB, 0x99CE }, + { 0xE8CC, 0x99C9 }, + { 0xE8CD, 0x99D6 }, + { 0xE8CE, 0x99D8 }, + { 0xE8CF, 0x99CB }, + { 0xE8D0, 0x99D7 }, + { 0xE8D1, 0x99CC }, + { 0xE8D2, 0x9AB3 }, + { 0xE8D3, 0x9AEC }, + { 0xE8D4, 0x9AEB }, + { 0xE8D5, 0x9AF3 }, + { 0xE8D6, 0x9AF2 }, + { 0xE8D7, 0x9AF1 }, + { 0xE8D8, 0x9B46 }, + { 0xE8D9, 0x9B43 }, + { 0xE8DA, 0x9B67 }, + { 0xE8DB, 0x9B74 }, + { 0xE8DC, 0x9B71 }, + { 0xE8DD, 0x9B66 }, + { 0xE8DE, 0x9B76 }, + { 0xE8DF, 0x9B75 }, + { 0xE8E0, 0x9B70 }, + { 0xE8E1, 0x9B68 }, + { 0xE8E2, 0x9B64 }, + { 0xE8E3, 0x9B6C }, + { 0xE8E4, 0x9CFC }, + { 0xE8E5, 0x9CFA }, + { 0xE8E6, 0x9CFD }, + { 0xE8E7, 0x9CFF }, + { 0xE8E8, 0x9CF7 }, + { 0xE8E9, 0x9D07 }, + { 0xE8EA, 0x9D00 }, + { 0xE8EB, 0x9CF9 }, + { 0xE8EC, 0x9CFB }, + { 0xE8ED, 0x9D08 }, + { 0xE8EE, 0x9D05 }, + { 0xE8EF, 0x9D04 }, + { 0xE8F0, 0x9E83 }, + { 0xE8F1, 0x9ED3 }, + { 0xE8F2, 0x9F0F }, + { 0xE8F3, 0x9F10 }, + { 0xE8F4, 0x511C }, + { 0xE8F5, 0x5113 }, + { 0xE8F6, 0x5117 }, + { 0xE8F7, 0x511A }, + { 0xE8F8, 0x5111 }, + { 0xE8F9, 0x51DE }, + { 0xE8FA, 0x5334 }, + { 0xE8FB, 0x53E1 }, + { 0xE8FC, 0x5670 }, + { 0xE8FD, 0x5660 }, + { 0xE8FE, 0x566E }, + { 0xE940, 0x5673 }, + { 0xE941, 0x5666 }, + { 0xE942, 0x5663 }, + { 0xE943, 0x566D }, + { 0xE944, 0x5672 }, + { 0xE945, 0x565E }, + { 0xE946, 0x5677 }, + { 0xE947, 0x571C }, + { 0xE948, 0x571B }, + { 0xE949, 0x58C8 }, + { 0xE94A, 0x58BD }, + { 0xE94B, 0x58C9 }, + { 0xE94C, 0x58BF }, + { 0xE94D, 0x58BA }, + { 0xE94E, 0x58C2 }, + { 0xE94F, 0x58BC }, + { 0xE950, 0x58C6 }, + { 0xE951, 0x5B17 }, + { 0xE952, 0x5B19 }, + { 0xE953, 0x5B1B }, + { 0xE954, 0x5B21 }, + { 0xE955, 0x5B14 }, + { 0xE956, 0x5B13 }, + { 0xE957, 0x5B10 }, + { 0xE958, 0x5B16 }, + { 0xE959, 0x5B28 }, + { 0xE95A, 0x5B1A }, + { 0xE95B, 0x5B20 }, + { 0xE95C, 0x5B1E }, + { 0xE95D, 0x5BEF }, + { 0xE95E, 0x5DAC }, + { 0xE95F, 0x5DB1 }, + { 0xE960, 0x5DA9 }, + { 0xE961, 0x5DA7 }, + { 0xE962, 0x5DB5 }, + { 0xE963, 0x5DB0 }, + { 0xE964, 0x5DAE }, + { 0xE965, 0x5DAA }, + { 0xE966, 0x5DA8 }, + { 0xE967, 0x5DB2 }, + { 0xE968, 0x5DAD }, + { 0xE969, 0x5DAF }, + { 0xE96A, 0x5DB4 }, + { 0xE96B, 0x5E67 }, + { 0xE96C, 0x5E68 }, + { 0xE96D, 0x5E66 }, + { 0xE96E, 0x5E6F }, + { 0xE96F, 0x5EE9 }, + { 0xE970, 0x5EE7 }, + { 0xE971, 0x5EE6 }, + { 0xE972, 0x5EE8 }, + { 0xE973, 0x5EE5 }, + { 0xE974, 0x5F4B }, + { 0xE975, 0x5FBC }, + { 0xE976, 0x619D }, + { 0xE977, 0x61A8 }, + { 0xE978, 0x6196 }, + { 0xE979, 0x61C5 }, + { 0xE97A, 0x61B4 }, + { 0xE97B, 0x61C6 }, + { 0xE97C, 0x61C1 }, + { 0xE97D, 0x61CC }, + { 0xE97E, 0x61BA }, + { 0xE9A1, 0x61BF }, + { 0xE9A2, 0x61B8 }, + { 0xE9A3, 0x618C }, + { 0xE9A4, 0x64D7 }, + { 0xE9A5, 0x64D6 }, + { 0xE9A6, 0x64D0 }, + { 0xE9A7, 0x64CF }, + { 0xE9A8, 0x64C9 }, + { 0xE9A9, 0x64BD }, + { 0xE9AA, 0x6489 }, + { 0xE9AB, 0x64C3 }, + { 0xE9AC, 0x64DB }, + { 0xE9AD, 0x64F3 }, + { 0xE9AE, 0x64D9 }, + { 0xE9AF, 0x6533 }, + { 0xE9B0, 0x657F }, + { 0xE9B1, 0x657C }, + { 0xE9B2, 0x65A2 }, + { 0xE9B3, 0x66C8 }, + { 0xE9B4, 0x66BE }, + { 0xE9B5, 0x66C0 }, + { 0xE9B6, 0x66CA }, + { 0xE9B7, 0x66CB }, + { 0xE9B8, 0x66CF }, + { 0xE9B9, 0x66BD }, + { 0xE9BA, 0x66BB }, + { 0xE9BB, 0x66BA }, + { 0xE9BC, 0x66CC }, + { 0xE9BD, 0x6723 }, + { 0xE9BE, 0x6A34 }, + { 0xE9BF, 0x6A66 }, + { 0xE9C0, 0x6A49 }, + { 0xE9C1, 0x6A67 }, + { 0xE9C2, 0x6A32 }, + { 0xE9C3, 0x6A68 }, + { 0xE9C4, 0x6A3E }, + { 0xE9C5, 0x6A5D }, + { 0xE9C6, 0x6A6D }, + { 0xE9C7, 0x6A76 }, + { 0xE9C8, 0x6A5B }, + { 0xE9C9, 0x6A51 }, + { 0xE9CA, 0x6A28 }, + { 0xE9CB, 0x6A5A }, + { 0xE9CC, 0x6A3B }, + { 0xE9CD, 0x6A3F }, + { 0xE9CE, 0x6A41 }, + { 0xE9CF, 0x6A6A }, + { 0xE9D0, 0x6A64 }, + { 0xE9D1, 0x6A50 }, + { 0xE9D2, 0x6A4F }, + { 0xE9D3, 0x6A54 }, + { 0xE9D4, 0x6A6F }, + { 0xE9D5, 0x6A69 }, + { 0xE9D6, 0x6A60 }, + { 0xE9D7, 0x6A3C }, + { 0xE9D8, 0x6A5E }, + { 0xE9D9, 0x6A56 }, + { 0xE9DA, 0x6A55 }, + { 0xE9DB, 0x6A4D }, + { 0xE9DC, 0x6A4E }, + { 0xE9DD, 0x6A46 }, + { 0xE9DE, 0x6B55 }, + { 0xE9DF, 0x6B54 }, + { 0xE9E0, 0x6B56 }, + { 0xE9E1, 0x6BA7 }, + { 0xE9E2, 0x6BAA }, + { 0xE9E3, 0x6BAB }, + { 0xE9E4, 0x6BC8 }, + { 0xE9E5, 0x6BC7 }, + { 0xE9E6, 0x6C04 }, + { 0xE9E7, 0x6C03 }, + { 0xE9E8, 0x6C06 }, + { 0xE9E9, 0x6FAD }, + { 0xE9EA, 0x6FCB }, + { 0xE9EB, 0x6FA3 }, + { 0xE9EC, 0x6FC7 }, + { 0xE9ED, 0x6FBC }, + { 0xE9EE, 0x6FCE }, + { 0xE9EF, 0x6FC8 }, + { 0xE9F0, 0x6F5E }, + { 0xE9F1, 0x6FC4 }, + { 0xE9F2, 0x6FBD }, + { 0xE9F3, 0x6F9E }, + { 0xE9F4, 0x6FCA }, + { 0xE9F5, 0x6FA8 }, + { 0xE9F6, 0x7004 }, + { 0xE9F7, 0x6FA5 }, + { 0xE9F8, 0x6FAE }, + { 0xE9F9, 0x6FBA }, + { 0xE9FA, 0x6FAC }, + { 0xE9FB, 0x6FAA }, + { 0xE9FC, 0x6FCF }, + { 0xE9FD, 0x6FBF }, + { 0xE9FE, 0x6FB8 }, + { 0xEA40, 0x6FA2 }, + { 0xEA41, 0x6FC9 }, + { 0xEA42, 0x6FAB }, + { 0xEA43, 0x6FCD }, + { 0xEA44, 0x6FAF }, + { 0xEA45, 0x6FB2 }, + { 0xEA46, 0x6FB0 }, + { 0xEA47, 0x71C5 }, + { 0xEA48, 0x71C2 }, + { 0xEA49, 0x71BF }, + { 0xEA4A, 0x71B8 }, + { 0xEA4B, 0x71D6 }, + { 0xEA4C, 0x71C0 }, + { 0xEA4D, 0x71C1 }, + { 0xEA4E, 0x71CB }, + { 0xEA4F, 0x71D4 }, + { 0xEA50, 0x71CA }, + { 0xEA51, 0x71C7 }, + { 0xEA52, 0x71CF }, + { 0xEA53, 0x71BD }, + { 0xEA54, 0x71D8 }, + { 0xEA55, 0x71BC }, + { 0xEA56, 0x71C6 }, + { 0xEA57, 0x71DA }, + { 0xEA58, 0x71DB }, + { 0xEA59, 0x729D }, + { 0xEA5A, 0x729E }, + { 0xEA5B, 0x7369 }, + { 0xEA5C, 0x7366 }, + { 0xEA5D, 0x7367 }, + { 0xEA5E, 0x736C }, + { 0xEA5F, 0x7365 }, + { 0xEA60, 0x736B }, + { 0xEA61, 0x736A }, + { 0xEA62, 0x747F }, + { 0xEA63, 0x749A }, + { 0xEA64, 0x74A0 }, + { 0xEA65, 0x7494 }, + { 0xEA66, 0x7492 }, + { 0xEA67, 0x7495 }, + { 0xEA68, 0x74A1 }, + { 0xEA69, 0x750B }, + { 0xEA6A, 0x7580 }, + { 0xEA6B, 0x762F }, + { 0xEA6C, 0x762D }, + { 0xEA6D, 0x7631 }, + { 0xEA6E, 0x763D }, + { 0xEA6F, 0x7633 }, + { 0xEA70, 0x763C }, + { 0xEA71, 0x7635 }, + { 0xEA72, 0x7632 }, + { 0xEA73, 0x7630 }, + { 0xEA74, 0x76BB }, + { 0xEA75, 0x76E6 }, + { 0xEA76, 0x779A }, + { 0xEA77, 0x779D }, + { 0xEA78, 0x77A1 }, + { 0xEA79, 0x779C }, + { 0xEA7A, 0x779B }, + { 0xEA7B, 0x77A2 }, + { 0xEA7C, 0x77A3 }, + { 0xEA7D, 0x7795 }, + { 0xEA7E, 0x7799 }, + { 0xEAA1, 0x7797 }, + { 0xEAA2, 0x78DD }, + { 0xEAA3, 0x78E9 }, + { 0xEAA4, 0x78E5 }, + { 0xEAA5, 0x78EA }, + { 0xEAA6, 0x78DE }, + { 0xEAA7, 0x78E3 }, + { 0xEAA8, 0x78DB }, + { 0xEAA9, 0x78E1 }, + { 0xEAAA, 0x78E2 }, + { 0xEAAB, 0x78ED }, + { 0xEAAC, 0x78DF }, + { 0xEAAD, 0x78E0 }, + { 0xEAAE, 0x79A4 }, + { 0xEAAF, 0x7A44 }, + { 0xEAB0, 0x7A48 }, + { 0xEAB1, 0x7A47 }, + { 0xEAB2, 0x7AB6 }, + { 0xEAB3, 0x7AB8 }, + { 0xEAB4, 0x7AB5 }, + { 0xEAB5, 0x7AB1 }, + { 0xEAB6, 0x7AB7 }, + { 0xEAB7, 0x7BDE }, + { 0xEAB8, 0x7BE3 }, + { 0xEAB9, 0x7BE7 }, + { 0xEABA, 0x7BDD }, + { 0xEABB, 0x7BD5 }, + { 0xEABC, 0x7BE5 }, + { 0xEABD, 0x7BDA }, + { 0xEABE, 0x7BE8 }, + { 0xEABF, 0x7BF9 }, + { 0xEAC0, 0x7BD4 }, + { 0xEAC1, 0x7BEA }, + { 0xEAC2, 0x7BE2 }, + { 0xEAC3, 0x7BDC }, + { 0xEAC4, 0x7BEB }, + { 0xEAC5, 0x7BD8 }, + { 0xEAC6, 0x7BDF }, + { 0xEAC7, 0x7CD2 }, + { 0xEAC8, 0x7CD4 }, + { 0xEAC9, 0x7CD7 }, + { 0xEACA, 0x7CD0 }, + { 0xEACB, 0x7CD1 }, + { 0xEACC, 0x7E12 }, + { 0xEACD, 0x7E21 }, + { 0xEACE, 0x7E17 }, + { 0xEACF, 0x7E0C }, + { 0xEAD0, 0x7E1F }, + { 0xEAD1, 0x7E20 }, + { 0xEAD2, 0x7E13 }, + { 0xEAD3, 0x7E0E }, + { 0xEAD4, 0x7E1C }, + { 0xEAD5, 0x7E15 }, + { 0xEAD6, 0x7E1A }, + { 0xEAD7, 0x7E22 }, + { 0xEAD8, 0x7E0B }, + { 0xEAD9, 0x7E0F }, + { 0xEADA, 0x7E16 }, + { 0xEADB, 0x7E0D }, + { 0xEADC, 0x7E14 }, + { 0xEADD, 0x7E25 }, + { 0xEADE, 0x7E24 }, + { 0xEADF, 0x7F43 }, + { 0xEAE0, 0x7F7B }, + { 0xEAE1, 0x7F7C }, + { 0xEAE2, 0x7F7A }, + { 0xEAE3, 0x7FB1 }, + { 0xEAE4, 0x7FEF }, + { 0xEAE5, 0x802A }, + { 0xEAE6, 0x8029 }, + { 0xEAE7, 0x806C }, + { 0xEAE8, 0x81B1 }, + { 0xEAE9, 0x81A6 }, + { 0xEAEA, 0x81AE }, + { 0xEAEB, 0x81B9 }, + { 0xEAEC, 0x81B5 }, + { 0xEAED, 0x81AB }, + { 0xEAEE, 0x81B0 }, + { 0xEAEF, 0x81AC }, + { 0xEAF0, 0x81B4 }, + { 0xEAF1, 0x81B2 }, + { 0xEAF2, 0x81B7 }, + { 0xEAF3, 0x81A7 }, + { 0xEAF4, 0x81F2 }, + { 0xEAF5, 0x8255 }, + { 0xEAF6, 0x8256 }, + { 0xEAF7, 0x8257 }, + { 0xEAF8, 0x8556 }, + { 0xEAF9, 0x8545 }, + { 0xEAFA, 0x856B }, + { 0xEAFB, 0x854D }, + { 0xEAFC, 0x8553 }, + { 0xEAFD, 0x8561 }, + { 0xEAFE, 0x8558 }, + { 0xEB40, 0x8540 }, + { 0xEB41, 0x8546 }, + { 0xEB42, 0x8564 }, + { 0xEB43, 0x8541 }, + { 0xEB44, 0x8562 }, + { 0xEB45, 0x8544 }, + { 0xEB46, 0x8551 }, + { 0xEB47, 0x8547 }, + { 0xEB48, 0x8563 }, + { 0xEB49, 0x853E }, + { 0xEB4A, 0x855B }, + { 0xEB4B, 0x8571 }, + { 0xEB4C, 0x854E }, + { 0xEB4D, 0x856E }, + { 0xEB4E, 0x8575 }, + { 0xEB4F, 0x8555 }, + { 0xEB50, 0x8567 }, + { 0xEB51, 0x8560 }, + { 0xEB52, 0x858C }, + { 0xEB53, 0x8566 }, + { 0xEB54, 0x855D }, + { 0xEB55, 0x8554 }, + { 0xEB56, 0x8565 }, + { 0xEB57, 0x856C }, + { 0xEB58, 0x8663 }, + { 0xEB59, 0x8665 }, + { 0xEB5A, 0x8664 }, + { 0xEB5B, 0x879B }, + { 0xEB5C, 0x878F }, + { 0xEB5D, 0x8797 }, + { 0xEB5E, 0x8793 }, + { 0xEB5F, 0x8792 }, + { 0xEB60, 0x8788 }, + { 0xEB61, 0x8781 }, + { 0xEB62, 0x8796 }, + { 0xEB63, 0x8798 }, + { 0xEB64, 0x8779 }, + { 0xEB65, 0x8787 }, + { 0xEB66, 0x87A3 }, + { 0xEB67, 0x8785 }, + { 0xEB68, 0x8790 }, + { 0xEB69, 0x8791 }, + { 0xEB6A, 0x879D }, + { 0xEB6B, 0x8784 }, + { 0xEB6C, 0x8794 }, + { 0xEB6D, 0x879C }, + { 0xEB6E, 0x879A }, + { 0xEB6F, 0x8789 }, + { 0xEB70, 0x891E }, + { 0xEB71, 0x8926 }, + { 0xEB72, 0x8930 }, + { 0xEB73, 0x892D }, + { 0xEB74, 0x892E }, + { 0xEB75, 0x8927 }, + { 0xEB76, 0x8931 }, + { 0xEB77, 0x8922 }, + { 0xEB78, 0x8929 }, + { 0xEB79, 0x8923 }, + { 0xEB7A, 0x892F }, + { 0xEB7B, 0x892C }, + { 0xEB7C, 0x891F }, + { 0xEB7D, 0x89F1 }, + { 0xEB7E, 0x8AE0 }, + { 0xEBA1, 0x8AE2 }, + { 0xEBA2, 0x8AF2 }, + { 0xEBA3, 0x8AF4 }, + { 0xEBA4, 0x8AF5 }, + { 0xEBA5, 0x8ADD }, + { 0xEBA6, 0x8B14 }, + { 0xEBA7, 0x8AE4 }, + { 0xEBA8, 0x8ADF }, + { 0xEBA9, 0x8AF0 }, + { 0xEBAA, 0x8AC8 }, + { 0xEBAB, 0x8ADE }, + { 0xEBAC, 0x8AE1 }, + { 0xEBAD, 0x8AE8 }, + { 0xEBAE, 0x8AFF }, + { 0xEBAF, 0x8AEF }, + { 0xEBB0, 0x8AFB }, + { 0xEBB1, 0x8C91 }, + { 0xEBB2, 0x8C92 }, + { 0xEBB3, 0x8C90 }, + { 0xEBB4, 0x8CF5 }, + { 0xEBB5, 0x8CEE }, + { 0xEBB6, 0x8CF1 }, + { 0xEBB7, 0x8CF0 }, + { 0xEBB8, 0x8CF3 }, + { 0xEBB9, 0x8D6C }, + { 0xEBBA, 0x8D6E }, + { 0xEBBB, 0x8DA5 }, + { 0xEBBC, 0x8DA7 }, + { 0xEBBD, 0x8E33 }, + { 0xEBBE, 0x8E3E }, + { 0xEBBF, 0x8E38 }, + { 0xEBC0, 0x8E40 }, + { 0xEBC1, 0x8E45 }, + { 0xEBC2, 0x8E36 }, + { 0xEBC3, 0x8E3C }, + { 0xEBC4, 0x8E3D }, + { 0xEBC5, 0x8E41 }, + { 0xEBC6, 0x8E30 }, + { 0xEBC7, 0x8E3F }, + { 0xEBC8, 0x8EBD }, + { 0xEBC9, 0x8F36 }, + { 0xEBCA, 0x8F2E }, + { 0xEBCB, 0x8F35 }, + { 0xEBCC, 0x8F32 }, + { 0xEBCD, 0x8F39 }, + { 0xEBCE, 0x8F37 }, + { 0xEBCF, 0x8F34 }, + { 0xEBD0, 0x9076 }, + { 0xEBD1, 0x9079 }, + { 0xEBD2, 0x907B }, + { 0xEBD3, 0x9086 }, + { 0xEBD4, 0x90FA }, + { 0xEBD5, 0x9133 }, + { 0xEBD6, 0x9135 }, + { 0xEBD7, 0x9136 }, + { 0xEBD8, 0x9193 }, + { 0xEBD9, 0x9190 }, + { 0xEBDA, 0x9191 }, + { 0xEBDB, 0x918D }, + { 0xEBDC, 0x918F }, + { 0xEBDD, 0x9327 }, + { 0xEBDE, 0x931E }, + { 0xEBDF, 0x9308 }, + { 0xEBE0, 0x931F }, + { 0xEBE1, 0x9306 }, + { 0xEBE2, 0x930F }, + { 0xEBE3, 0x937A }, + { 0xEBE4, 0x9338 }, + { 0xEBE5, 0x933C }, + { 0xEBE6, 0x931B }, + { 0xEBE7, 0x9323 }, + { 0xEBE8, 0x9312 }, + { 0xEBE9, 0x9301 }, + { 0xEBEA, 0x9346 }, + { 0xEBEB, 0x932D }, + { 0xEBEC, 0x930E }, + { 0xEBED, 0x930D }, + { 0xEBEE, 0x92CB }, + { 0xEBEF, 0x931D }, + { 0xEBF0, 0x92FA }, + { 0xEBF1, 0x9325 }, + { 0xEBF2, 0x9313 }, + { 0xEBF3, 0x92F9 }, + { 0xEBF4, 0x92F7 }, + { 0xEBF5, 0x9334 }, + { 0xEBF6, 0x9302 }, + { 0xEBF7, 0x9324 }, + { 0xEBF8, 0x92FF }, + { 0xEBF9, 0x9329 }, + { 0xEBFA, 0x9339 }, + { 0xEBFB, 0x9335 }, + { 0xEBFC, 0x932A }, + { 0xEBFD, 0x9314 }, + { 0xEBFE, 0x930C }, + { 0xEC40, 0x930B }, + { 0xEC41, 0x92FE }, + { 0xEC42, 0x9309 }, + { 0xEC43, 0x9300 }, + { 0xEC44, 0x92FB }, + { 0xEC45, 0x9316 }, + { 0xEC46, 0x95BC }, + { 0xEC47, 0x95CD }, + { 0xEC48, 0x95BE }, + { 0xEC49, 0x95B9 }, + { 0xEC4A, 0x95BA }, + { 0xEC4B, 0x95B6 }, + { 0xEC4C, 0x95BF }, + { 0xEC4D, 0x95B5 }, + { 0xEC4E, 0x95BD }, + { 0xEC4F, 0x96A9 }, + { 0xEC50, 0x96D4 }, + { 0xEC51, 0x970B }, + { 0xEC52, 0x9712 }, + { 0xEC53, 0x9710 }, + { 0xEC54, 0x9799 }, + { 0xEC55, 0x9797 }, + { 0xEC56, 0x9794 }, + { 0xEC57, 0x97F0 }, + { 0xEC58, 0x97F8 }, + { 0xEC59, 0x9835 }, + { 0xEC5A, 0x982F }, + { 0xEC5B, 0x9832 }, + { 0xEC5C, 0x9924 }, + { 0xEC5D, 0x991F }, + { 0xEC5E, 0x9927 }, + { 0xEC5F, 0x9929 }, + { 0xEC60, 0x999E }, + { 0xEC61, 0x99EE }, + { 0xEC62, 0x99EC }, + { 0xEC63, 0x99E5 }, + { 0xEC64, 0x99E4 }, + { 0xEC65, 0x99F0 }, + { 0xEC66, 0x99E3 }, + { 0xEC67, 0x99EA }, + { 0xEC68, 0x99E9 }, + { 0xEC69, 0x99E7 }, + { 0xEC6A, 0x9AB9 }, + { 0xEC6B, 0x9ABF }, + { 0xEC6C, 0x9AB4 }, + { 0xEC6D, 0x9ABB }, + { 0xEC6E, 0x9AF6 }, + { 0xEC6F, 0x9AFA }, + { 0xEC70, 0x9AF9 }, + { 0xEC71, 0x9AF7 }, + { 0xEC72, 0x9B33 }, + { 0xEC73, 0x9B80 }, + { 0xEC74, 0x9B85 }, + { 0xEC75, 0x9B87 }, + { 0xEC76, 0x9B7C }, + { 0xEC77, 0x9B7E }, + { 0xEC78, 0x9B7B }, + { 0xEC79, 0x9B82 }, + { 0xEC7A, 0x9B93 }, + { 0xEC7B, 0x9B92 }, + { 0xEC7C, 0x9B90 }, + { 0xEC7D, 0x9B7A }, + { 0xEC7E, 0x9B95 }, + { 0xECA1, 0x9B7D }, + { 0xECA2, 0x9B88 }, + { 0xECA3, 0x9D25 }, + { 0xECA4, 0x9D17 }, + { 0xECA5, 0x9D20 }, + { 0xECA6, 0x9D1E }, + { 0xECA7, 0x9D14 }, + { 0xECA8, 0x9D29 }, + { 0xECA9, 0x9D1D }, + { 0xECAA, 0x9D18 }, + { 0xECAB, 0x9D22 }, + { 0xECAC, 0x9D10 }, + { 0xECAD, 0x9D19 }, + { 0xECAE, 0x9D1F }, + { 0xECAF, 0x9E88 }, + { 0xECB0, 0x9E86 }, + { 0xECB1, 0x9E87 }, + { 0xECB2, 0x9EAE }, + { 0xECB3, 0x9EAD }, + { 0xECB4, 0x9ED5 }, + { 0xECB5, 0x9ED6 }, + { 0xECB6, 0x9EFA }, + { 0xECB7, 0x9F12 }, + { 0xECB8, 0x9F3D }, + { 0xECB9, 0x5126 }, + { 0xECBA, 0x5125 }, + { 0xECBB, 0x5122 }, + { 0xECBC, 0x5124 }, + { 0xECBD, 0x5120 }, + { 0xECBE, 0x5129 }, + { 0xECBF, 0x52F4 }, + { 0xECC0, 0x5693 }, + { 0xECC1, 0x568C }, + { 0xECC2, 0x568D }, + { 0xECC3, 0x5686 }, + { 0xECC4, 0x5684 }, + { 0xECC5, 0x5683 }, + { 0xECC6, 0x567E }, + { 0xECC7, 0x5682 }, + { 0xECC8, 0x567F }, + { 0xECC9, 0x5681 }, + { 0xECCA, 0x58D6 }, + { 0xECCB, 0x58D4 }, + { 0xECCC, 0x58CF }, + { 0xECCD, 0x58D2 }, + { 0xECCE, 0x5B2D }, + { 0xECCF, 0x5B25 }, + { 0xECD0, 0x5B32 }, + { 0xECD1, 0x5B23 }, + { 0xECD2, 0x5B2C }, + { 0xECD3, 0x5B27 }, + { 0xECD4, 0x5B26 }, + { 0xECD5, 0x5B2F }, + { 0xECD6, 0x5B2E }, + { 0xECD7, 0x5B7B }, + { 0xECD8, 0x5BF1 }, + { 0xECD9, 0x5BF2 }, + { 0xECDA, 0x5DB7 }, + { 0xECDB, 0x5E6C }, + { 0xECDC, 0x5E6A }, + { 0xECDD, 0x5FBE }, + { 0xECDE, 0x5FBB }, + { 0xECDF, 0x61C3 }, + { 0xECE0, 0x61B5 }, + { 0xECE1, 0x61BC }, + { 0xECE2, 0x61E7 }, + { 0xECE3, 0x61E0 }, + { 0xECE4, 0x61E5 }, + { 0xECE5, 0x61E4 }, + { 0xECE6, 0x61E8 }, + { 0xECE7, 0x61DE }, + { 0xECE8, 0x64EF }, + { 0xECE9, 0x64E9 }, + { 0xECEA, 0x64E3 }, + { 0xECEB, 0x64EB }, + { 0xECEC, 0x64E4 }, + { 0xECED, 0x64E8 }, + { 0xECEE, 0x6581 }, + { 0xECEF, 0x6580 }, + { 0xECF0, 0x65B6 }, + { 0xECF1, 0x65DA }, + { 0xECF2, 0x66D2 }, + { 0xECF3, 0x6A8D }, + { 0xECF4, 0x6A96 }, + { 0xECF5, 0x6A81 }, + { 0xECF6, 0x6AA5 }, + { 0xECF7, 0x6A89 }, + { 0xECF8, 0x6A9F }, + { 0xECF9, 0x6A9B }, + { 0xECFA, 0x6AA1 }, + { 0xECFB, 0x6A9E }, + { 0xECFC, 0x6A87 }, + { 0xECFD, 0x6A93 }, + { 0xECFE, 0x6A8E }, + { 0xED40, 0x6A95 }, + { 0xED41, 0x6A83 }, + { 0xED42, 0x6AA8 }, + { 0xED43, 0x6AA4 }, + { 0xED44, 0x6A91 }, + { 0xED45, 0x6A7F }, + { 0xED46, 0x6AA6 }, + { 0xED47, 0x6A9A }, + { 0xED48, 0x6A85 }, + { 0xED49, 0x6A8C }, + { 0xED4A, 0x6A92 }, + { 0xED4B, 0x6B5B }, + { 0xED4C, 0x6BAD }, + { 0xED4D, 0x6C09 }, + { 0xED4E, 0x6FCC }, + { 0xED4F, 0x6FA9 }, + { 0xED50, 0x6FF4 }, + { 0xED51, 0x6FD4 }, + { 0xED52, 0x6FE3 }, + { 0xED53, 0x6FDC }, + { 0xED54, 0x6FED }, + { 0xED55, 0x6FE7 }, + { 0xED56, 0x6FE6 }, + { 0xED57, 0x6FDE }, + { 0xED58, 0x6FF2 }, + { 0xED59, 0x6FDD }, + { 0xED5A, 0x6FE2 }, + { 0xED5B, 0x6FE8 }, + { 0xED5C, 0x71E1 }, + { 0xED5D, 0x71F1 }, + { 0xED5E, 0x71E8 }, + { 0xED5F, 0x71F2 }, + { 0xED60, 0x71E4 }, + { 0xED61, 0x71F0 }, + { 0xED62, 0x71E2 }, + { 0xED63, 0x7373 }, + { 0xED64, 0x736E }, + { 0xED65, 0x736F }, + { 0xED66, 0x7497 }, + { 0xED67, 0x74B2 }, + { 0xED68, 0x74AB }, + { 0xED69, 0x7490 }, + { 0xED6A, 0x74AA }, + { 0xED6B, 0x74AD }, + { 0xED6C, 0x74B1 }, + { 0xED6D, 0x74A5 }, + { 0xED6E, 0x74AF }, + { 0xED6F, 0x7510 }, + { 0xED70, 0x7511 }, + { 0xED71, 0x7512 }, + { 0xED72, 0x750F }, + { 0xED73, 0x7584 }, + { 0xED74, 0x7643 }, + { 0xED75, 0x7648 }, + { 0xED76, 0x7649 }, + { 0xED77, 0x7647 }, + { 0xED78, 0x76A4 }, + { 0xED79, 0x76E9 }, + { 0xED7A, 0x77B5 }, + { 0xED7B, 0x77AB }, + { 0xED7C, 0x77B2 }, + { 0xED7D, 0x77B7 }, + { 0xED7E, 0x77B6 }, + { 0xEDA1, 0x77B4 }, + { 0xEDA2, 0x77B1 }, + { 0xEDA3, 0x77A8 }, + { 0xEDA4, 0x77F0 }, + { 0xEDA5, 0x78F3 }, + { 0xEDA6, 0x78FD }, + { 0xEDA7, 0x7902 }, + { 0xEDA8, 0x78FB }, + { 0xEDA9, 0x78FC }, + { 0xEDAA, 0x78F2 }, + { 0xEDAB, 0x7905 }, + { 0xEDAC, 0x78F9 }, + { 0xEDAD, 0x78FE }, + { 0xEDAE, 0x7904 }, + { 0xEDAF, 0x79AB }, + { 0xEDB0, 0x79A8 }, + { 0xEDB1, 0x7A5C }, + { 0xEDB2, 0x7A5B }, + { 0xEDB3, 0x7A56 }, + { 0xEDB4, 0x7A58 }, + { 0xEDB5, 0x7A54 }, + { 0xEDB6, 0x7A5A }, + { 0xEDB7, 0x7ABE }, + { 0xEDB8, 0x7AC0 }, + { 0xEDB9, 0x7AC1 }, + { 0xEDBA, 0x7C05 }, + { 0xEDBB, 0x7C0F }, + { 0xEDBC, 0x7BF2 }, + { 0xEDBD, 0x7C00 }, + { 0xEDBE, 0x7BFF }, + { 0xEDBF, 0x7BFB }, + { 0xEDC0, 0x7C0E }, + { 0xEDC1, 0x7BF4 }, + { 0xEDC2, 0x7C0B }, + { 0xEDC3, 0x7BF3 }, + { 0xEDC4, 0x7C02 }, + { 0xEDC5, 0x7C09 }, + { 0xEDC6, 0x7C03 }, + { 0xEDC7, 0x7C01 }, + { 0xEDC8, 0x7BF8 }, + { 0xEDC9, 0x7BFD }, + { 0xEDCA, 0x7C06 }, + { 0xEDCB, 0x7BF0 }, + { 0xEDCC, 0x7BF1 }, + { 0xEDCD, 0x7C10 }, + { 0xEDCE, 0x7C0A }, + { 0xEDCF, 0x7CE8 }, + { 0xEDD0, 0x7E2D }, + { 0xEDD1, 0x7E3C }, + { 0xEDD2, 0x7E42 }, + { 0xEDD3, 0x7E33 }, + { 0xEDD4, 0x9848 }, + { 0xEDD5, 0x7E38 }, + { 0xEDD6, 0x7E2A }, + { 0xEDD7, 0x7E49 }, + { 0xEDD8, 0x7E40 }, + { 0xEDD9, 0x7E47 }, + { 0xEDDA, 0x7E29 }, + { 0xEDDB, 0x7E4C }, + { 0xEDDC, 0x7E30 }, + { 0xEDDD, 0x7E3B }, + { 0xEDDE, 0x7E36 }, + { 0xEDDF, 0x7E44 }, + { 0xEDE0, 0x7E3A }, + { 0xEDE1, 0x7F45 }, + { 0xEDE2, 0x7F7F }, + { 0xEDE3, 0x7F7E }, + { 0xEDE4, 0x7F7D }, + { 0xEDE5, 0x7FF4 }, + { 0xEDE6, 0x7FF2 }, + { 0xEDE7, 0x802C }, + { 0xEDE8, 0x81BB }, + { 0xEDE9, 0x81C4 }, + { 0xEDEA, 0x81CC }, + { 0xEDEB, 0x81CA }, + { 0xEDEC, 0x81C5 }, + { 0xEDED, 0x81C7 }, + { 0xEDEE, 0x81BC }, + { 0xEDEF, 0x81E9 }, + { 0xEDF0, 0x825B }, + { 0xEDF1, 0x825A }, + { 0xEDF2, 0x825C }, + { 0xEDF3, 0x8583 }, + { 0xEDF4, 0x8580 }, + { 0xEDF5, 0x858F }, + { 0xEDF6, 0x85A7 }, + { 0xEDF7, 0x8595 }, + { 0xEDF8, 0x85A0 }, + { 0xEDF9, 0x858B }, + { 0xEDFA, 0x85A3 }, + { 0xEDFB, 0x857B }, + { 0xEDFC, 0x85A4 }, + { 0xEDFD, 0x859A }, + { 0xEDFE, 0x859E }, + { 0xEE40, 0x8577 }, + { 0xEE41, 0x857C }, + { 0xEE42, 0x8589 }, + { 0xEE43, 0x85A1 }, + { 0xEE44, 0x857A }, + { 0xEE45, 0x8578 }, + { 0xEE46, 0x8557 }, + { 0xEE47, 0x858E }, + { 0xEE48, 0x8596 }, + { 0xEE49, 0x8586 }, + { 0xEE4A, 0x858D }, + { 0xEE4B, 0x8599 }, + { 0xEE4C, 0x859D }, + { 0xEE4D, 0x8581 }, + { 0xEE4E, 0x85A2 }, + { 0xEE4F, 0x8582 }, + { 0xEE50, 0x8588 }, + { 0xEE51, 0x8585 }, + { 0xEE52, 0x8579 }, + { 0xEE53, 0x8576 }, + { 0xEE54, 0x8598 }, + { 0xEE55, 0x8590 }, + { 0xEE56, 0x859F }, + { 0xEE57, 0x8668 }, + { 0xEE58, 0x87BE }, + { 0xEE59, 0x87AA }, + { 0xEE5A, 0x87AD }, + { 0xEE5B, 0x87C5 }, + { 0xEE5C, 0x87B0 }, + { 0xEE5D, 0x87AC }, + { 0xEE5E, 0x87B9 }, + { 0xEE5F, 0x87B5 }, + { 0xEE60, 0x87BC }, + { 0xEE61, 0x87AE }, + { 0xEE62, 0x87C9 }, + { 0xEE63, 0x87C3 }, + { 0xEE64, 0x87C2 }, + { 0xEE65, 0x87CC }, + { 0xEE66, 0x87B7 }, + { 0xEE67, 0x87AF }, + { 0xEE68, 0x87C4 }, + { 0xEE69, 0x87CA }, + { 0xEE6A, 0x87B4 }, + { 0xEE6B, 0x87B6 }, + { 0xEE6C, 0x87BF }, + { 0xEE6D, 0x87B8 }, + { 0xEE6E, 0x87BD }, + { 0xEE6F, 0x87DE }, + { 0xEE70, 0x87B2 }, + { 0xEE71, 0x8935 }, + { 0xEE72, 0x8933 }, + { 0xEE73, 0x893C }, + { 0xEE74, 0x893E }, + { 0xEE75, 0x8941 }, + { 0xEE76, 0x8952 }, + { 0xEE77, 0x8937 }, + { 0xEE78, 0x8942 }, + { 0xEE79, 0x89AD }, + { 0xEE7A, 0x89AF }, + { 0xEE7B, 0x89AE }, + { 0xEE7C, 0x89F2 }, + { 0xEE7D, 0x89F3 }, + { 0xEE7E, 0x8B1E }, + { 0xEEA1, 0x8B18 }, + { 0xEEA2, 0x8B16 }, + { 0xEEA3, 0x8B11 }, + { 0xEEA4, 0x8B05 }, + { 0xEEA5, 0x8B0B }, + { 0xEEA6, 0x8B22 }, + { 0xEEA7, 0x8B0F }, + { 0xEEA8, 0x8B12 }, + { 0xEEA9, 0x8B15 }, + { 0xEEAA, 0x8B07 }, + { 0xEEAB, 0x8B0D }, + { 0xEEAC, 0x8B08 }, + { 0xEEAD, 0x8B06 }, + { 0xEEAE, 0x8B1C }, + { 0xEEAF, 0x8B13 }, + { 0xEEB0, 0x8B1A }, + { 0xEEB1, 0x8C4F }, + { 0xEEB2, 0x8C70 }, + { 0xEEB3, 0x8C72 }, + { 0xEEB4, 0x8C71 }, + { 0xEEB5, 0x8C6F }, + { 0xEEB6, 0x8C95 }, + { 0xEEB7, 0x8C94 }, + { 0xEEB8, 0x8CF9 }, + { 0xEEB9, 0x8D6F }, + { 0xEEBA, 0x8E4E }, + { 0xEEBB, 0x8E4D }, + { 0xEEBC, 0x8E53 }, + { 0xEEBD, 0x8E50 }, + { 0xEEBE, 0x8E4C }, + { 0xEEBF, 0x8E47 }, + { 0xEEC0, 0x8F43 }, + { 0xEEC1, 0x8F40 }, + { 0xEEC2, 0x9085 }, + { 0xEEC3, 0x907E }, + { 0xEEC4, 0x9138 }, + { 0xEEC5, 0x919A }, + { 0xEEC6, 0x91A2 }, + { 0xEEC7, 0x919B }, + { 0xEEC8, 0x9199 }, + { 0xEEC9, 0x919F }, + { 0xEECA, 0x91A1 }, + { 0xEECB, 0x919D }, + { 0xEECC, 0x91A0 }, + { 0xEECD, 0x93A1 }, + { 0xEECE, 0x9383 }, + { 0xEECF, 0x93AF }, + { 0xEED0, 0x9364 }, + { 0xEED1, 0x9356 }, + { 0xEED2, 0x9347 }, + { 0xEED3, 0x937C }, + { 0xEED4, 0x9358 }, + { 0xEED5, 0x935C }, + { 0xEED6, 0x9376 }, + { 0xEED7, 0x9349 }, + { 0xEED8, 0x9350 }, + { 0xEED9, 0x9351 }, + { 0xEEDA, 0x9360 }, + { 0xEEDB, 0x936D }, + { 0xEEDC, 0x938F }, + { 0xEEDD, 0x934C }, + { 0xEEDE, 0x936A }, + { 0xEEDF, 0x9379 }, + { 0xEEE0, 0x9357 }, + { 0xEEE1, 0x9355 }, + { 0xEEE2, 0x9352 }, + { 0xEEE3, 0x934F }, + { 0xEEE4, 0x9371 }, + { 0xEEE5, 0x9377 }, + { 0xEEE6, 0x937B }, + { 0xEEE7, 0x9361 }, + { 0xEEE8, 0x935E }, + { 0xEEE9, 0x9363 }, + { 0xEEEA, 0x9367 }, + { 0xEEEB, 0x9380 }, + { 0xEEEC, 0x934E }, + + + { 0xEEED, 0x9359 }, + { 0xEEEE, 0x95C7 }, + { 0xEEEF, 0x95C0 }, + { 0xEEF0, 0x95C9 }, + { 0xEEF1, 0x95C3 }, + { 0xEEF2, 0x95C5 }, + { 0xEEF3, 0x95B7 }, + { 0xEEF4, 0x96AE }, + { 0xEEF5, 0x96B0 }, + { 0xEEF6, 0x96AC }, + { 0xEEF7, 0x9720 }, + { 0xEEF8, 0x971F }, + { 0xEEF9, 0x9718 }, + { 0xEEFA, 0x971D }, + { 0xEEFB, 0x9719 }, + { 0xEEFC, 0x979A }, + { 0xEEFD, 0x97A1 }, + { 0xEEFE, 0x979C }, + { 0xEF40, 0x979E }, + { 0xEF41, 0x979D }, + { 0xEF42, 0x97D5 }, + { 0xEF43, 0x97D4 }, + { 0xEF44, 0x97F1 }, + { 0xEF45, 0x9841 }, + { 0xEF46, 0x9844 }, + { 0xEF47, 0x984A }, + { 0xEF48, 0x9849 }, + { 0xEF49, 0x9845 }, + { 0xEF4A, 0x9843 }, + { 0xEF4B, 0x9925 }, + { 0xEF4C, 0x992B }, + { 0xEF4D, 0x992C }, + { 0xEF4E, 0x992A }, + { 0xEF4F, 0x9933 }, + { 0xEF50, 0x9932 }, + { 0xEF51, 0x992F }, + { 0xEF52, 0x992D }, + { 0xEF53, 0x9931 }, + { 0xEF54, 0x9930 }, + { 0xEF55, 0x9998 }, + { 0xEF56, 0x99A3 }, + { 0xEF57, 0x99A1 }, + { 0xEF58, 0x9A02 }, + { 0xEF59, 0x99FA }, + { 0xEF5A, 0x99F4 }, + { 0xEF5B, 0x99F7 }, + { 0xEF5C, 0x99F9 }, + { 0xEF5D, 0x99F8 }, + { 0xEF5E, 0x99F6 }, + { 0xEF5F, 0x99FB }, + { 0xEF60, 0x99FD }, + { 0xEF61, 0x99FE }, + { 0xEF62, 0x99FC }, + { 0xEF63, 0x9A03 }, + { 0xEF64, 0x9ABE }, + { 0xEF65, 0x9AFE }, + { 0xEF66, 0x9AFD }, + { 0xEF67, 0x9B01 }, + { 0xEF68, 0x9AFC }, + { 0xEF69, 0x9B48 }, + { 0xEF6A, 0x9B9A }, + { 0xEF6B, 0x9BA8 }, + { 0xEF6C, 0x9B9E }, + { 0xEF6D, 0x9B9B }, + { 0xEF6E, 0x9BA6 }, + { 0xEF6F, 0x9BA1 }, + { 0xEF70, 0x9BA5 }, + { 0xEF71, 0x9BA4 }, + { 0xEF72, 0x9B86 }, + { 0xEF73, 0x9BA2 }, + { 0xEF74, 0x9BA0 }, + { 0xEF75, 0x9BAF }, + { 0xEF76, 0x9D33 }, + { 0xEF77, 0x9D41 }, + { 0xEF78, 0x9D67 }, + { 0xEF79, 0x9D36 }, + { 0xEF7A, 0x9D2E }, + { 0xEF7B, 0x9D2F }, + { 0xEF7C, 0x9D31 }, + { 0xEF7D, 0x9D38 }, + { 0xEF7E, 0x9D30 }, + { 0xEFA1, 0x9D45 }, + { 0xEFA2, 0x9D42 }, + { 0xEFA3, 0x9D43 }, + { 0xEFA4, 0x9D3E }, + { 0xEFA5, 0x9D37 }, + { 0xEFA6, 0x9D40 }, + { 0xEFA7, 0x9D3D }, + { 0xEFA8, 0x7FF5 }, + { 0xEFA9, 0x9D2D }, + { 0xEFAA, 0x9E8A }, + { 0xEFAB, 0x9E89 }, + { 0xEFAC, 0x9E8D }, + { 0xEFAD, 0x9EB0 }, + { 0xEFAE, 0x9EC8 }, + { 0xEFAF, 0x9EDA }, + { 0xEFB0, 0x9EFB }, + { 0xEFB1, 0x9EFF }, + { 0xEFB2, 0x9F24 }, + { 0xEFB3, 0x9F23 }, + { 0xEFB4, 0x9F22 }, + { 0xEFB5, 0x9F54 }, + { 0xEFB6, 0x9FA0 }, + { 0xEFB7, 0x5131 }, + { 0xEFB8, 0x512D }, + { 0xEFB9, 0x512E }, + { 0xEFBA, 0x5698 }, + { 0xEFBB, 0x569C }, + { 0xEFBC, 0x5697 }, + { 0xEFBD, 0x569A }, + { 0xEFBE, 0x569D }, + { 0xEFBF, 0x5699 }, + { 0xEFC0, 0x5970 }, + { 0xEFC1, 0x5B3C }, + { 0xEFC2, 0x5C69 }, + { 0xEFC3, 0x5C6A }, + { 0xEFC4, 0x5DC0 }, + { 0xEFC5, 0x5E6D }, + { 0xEFC6, 0x5E6E }, + { 0xEFC7, 0x61D8 }, + { 0xEFC8, 0x61DF }, + { 0xEFC9, 0x61ED }, + { 0xEFCA, 0x61EE }, + { 0xEFCB, 0x61F1 }, + { 0xEFCC, 0x61EA }, + { 0xEFCD, 0x61F0 }, + { 0xEFCE, 0x61EB }, + { 0xEFCF, 0x61D6 }, + { 0xEFD0, 0x61E9 }, + { 0xEFD1, 0x64FF }, + { 0xEFD2, 0x6504 }, + { 0xEFD3, 0x64FD }, + { 0xEFD4, 0x64F8 }, + { 0xEFD5, 0x6501 }, + { 0xEFD6, 0x6503 }, + { 0xEFD7, 0x64FC }, + { 0xEFD8, 0x6594 }, + { 0xEFD9, 0x65DB }, + { 0xEFDA, 0x66DA }, + { 0xEFDB, 0x66DB }, + { 0xEFDC, 0x66D8 }, + { 0xEFDD, 0x6AC5 }, + { 0xEFDE, 0x6AB9 }, + { 0xEFDF, 0x6ABD }, + { 0xEFE0, 0x6AE1 }, + { 0xEFE1, 0x6AC6 }, + { 0xEFE2, 0x6ABA }, + { 0xEFE3, 0x6AB6 }, + { 0xEFE4, 0x6AB7 }, + { 0xEFE5, 0x6AC7 }, + { 0xEFE6, 0x6AB4 }, + { 0xEFE7, 0x6AAD }, + { 0xEFE8, 0x6B5E }, + { 0xEFE9, 0x6BC9 }, + { 0xEFEA, 0x6C0B }, + { 0xEFEB, 0x7007 }, + { 0xEFEC, 0x700C }, + { 0xEFED, 0x700D }, + { 0xEFEE, 0x7001 }, + { 0xEFEF, 0x7005 }, + { 0xEFF0, 0x7014 }, + { 0xEFF1, 0x700E }, + { 0xEFF2, 0x6FFF }, + { 0xEFF3, 0x7000 }, + { 0xEFF4, 0x6FFB }, + { 0xEFF5, 0x7026 }, + { 0xEFF6, 0x6FFC }, + { 0xEFF7, 0x6FF7 }, + { 0xEFF8, 0x700A }, + { 0xEFF9, 0x7201 }, + { 0xEFFA, 0x71FF }, + { 0xEFFB, 0x71F9 }, + { 0xEFFC, 0x7203 }, + { 0xEFFD, 0x71FD }, + { 0xEFFE, 0x7376 }, + { 0xF040, 0x74B8 }, + { 0xF041, 0x74C0 }, + { 0xF042, 0x74B5 }, + { 0xF043, 0x74C1 }, + { 0xF044, 0x74BE }, + { 0xF045, 0x74B6 }, + { 0xF046, 0x74BB }, + { 0xF047, 0x74C2 }, + { 0xF048, 0x7514 }, + { 0xF049, 0x7513 }, + { 0xF04A, 0x765C }, + { 0xF04B, 0x7664 }, + { 0xF04C, 0x7659 }, + { 0xF04D, 0x7650 }, + { 0xF04E, 0x7653 }, + { 0xF04F, 0x7657 }, + { 0xF050, 0x765A }, + { 0xF051, 0x76A6 }, + { 0xF052, 0x76BD }, + { 0xF053, 0x76EC }, + { 0xF054, 0x77C2 }, + { 0xF055, 0x77BA }, + { 0xF056, 0x78FF }, + { 0xF057, 0x790C }, + { 0xF058, 0x7913 }, + { 0xF059, 0x7914 }, + { 0xF05A, 0x7909 }, + { 0xF05B, 0x7910 }, + { 0xF05C, 0x7912 }, + { 0xF05D, 0x7911 }, + { 0xF05E, 0x79AD }, + { 0xF05F, 0x79AC }, + { 0xF060, 0x7A5F }, + { 0xF061, 0x7C1C }, + { 0xF062, 0x7C29 }, + { 0xF063, 0x7C19 }, + { 0xF064, 0x7C20 }, + { 0xF065, 0x7C1F }, + { 0xF066, 0x7C2D }, + { 0xF067, 0x7C1D }, + { 0xF068, 0x7C26 }, + { 0xF069, 0x7C28 }, + { 0xF06A, 0x7C22 }, + { 0xF06B, 0x7C25 }, + { 0xF06C, 0x7C30 }, + { 0xF06D, 0x7E5C }, + { 0xF06E, 0x7E50 }, + { 0xF06F, 0x7E56 }, + { 0xF070, 0x7E63 }, + { 0xF071, 0x7E58 }, + { 0xF072, 0x7E62 }, + { 0xF073, 0x7E5F }, + { 0xF074, 0x7E51 }, + { 0xF075, 0x7E60 }, + { 0xF076, 0x7E57 }, + { 0xF077, 0x7E53 }, + { 0xF078, 0x7FB5 }, + { 0xF079, 0x7FB3 }, + { 0xF07A, 0x7FF7 }, + { 0xF07B, 0x7FF8 }, + { 0xF07C, 0x8075 }, + { 0xF07D, 0x81D1 }, + { 0xF07E, 0x81D2 }, + { 0xF0A1, 0x81D0 }, + { 0xF0A2, 0x825F }, + { 0xF0A3, 0x825E }, + { 0xF0A4, 0x85B4 }, + { 0xF0A5, 0x85C6 }, + { 0xF0A6, 0x85C0 }, + { 0xF0A7, 0x85C3 }, + { 0xF0A8, 0x85C2 }, + { 0xF0A9, 0x85B3 }, + { 0xF0AA, 0x85B5 }, + { 0xF0AB, 0x85BD }, + { 0xF0AC, 0x85C7 }, + { 0xF0AD, 0x85C4 }, + { 0xF0AE, 0x85BF }, + { 0xF0AF, 0x85CB }, + { 0xF0B0, 0x85CE }, + { 0xF0B1, 0x85C8 }, + { 0xF0B2, 0x85C5 }, + { 0xF0B3, 0x85B1 }, + { 0xF0B4, 0x85B6 }, + { 0xF0B5, 0x85D2 }, + { 0xF0B6, 0x8624 }, + { 0xF0B7, 0x85B8 }, + { 0xF0B8, 0x85B7 }, + { 0xF0B9, 0x85BE }, + { 0xF0BA, 0x8669 }, + { 0xF0BB, 0x87E7 }, + { 0xF0BC, 0x87E6 }, + { 0xF0BD, 0x87E2 }, + { 0xF0BE, 0x87DB }, + { 0xF0BF, 0x87EB }, + { 0xF0C0, 0x87EA }, + { 0xF0C1, 0x87E5 }, + { 0xF0C2, 0x87DF }, + { 0xF0C3, 0x87F3 }, + { 0xF0C4, 0x87E4 }, + { 0xF0C5, 0x87D4 }, + { 0xF0C6, 0x87DC }, + { 0xF0C7, 0x87D3 }, + { 0xF0C8, 0x87ED }, + { 0xF0C9, 0x87D8 }, + { 0xF0CA, 0x87E3 }, + { 0xF0CB, 0x87A4 }, + { 0xF0CC, 0x87D7 }, + { 0xF0CD, 0x87D9 }, + { 0xF0CE, 0x8801 }, + { 0xF0CF, 0x87F4 }, + { 0xF0D0, 0x87E8 }, + { 0xF0D1, 0x87DD }, + { 0xF0D2, 0x8953 }, + { 0xF0D3, 0x894B }, + { 0xF0D4, 0x894F }, + { 0xF0D5, 0x894C }, + { 0xF0D6, 0x8946 }, + { 0xF0D7, 0x8950 }, + { 0xF0D8, 0x8951 }, + { 0xF0D9, 0x8949 }, + { 0xF0DA, 0x8B2A }, + { 0xF0DB, 0x8B27 }, + { 0xF0DC, 0x8B23 }, + { 0xF0DD, 0x8B33 }, + { 0xF0DE, 0x8B30 }, + { 0xF0DF, 0x8B35 }, + { 0xF0E0, 0x8B47 }, + { 0xF0E1, 0x8B2F }, + { 0xF0E2, 0x8B3C }, + { 0xF0E3, 0x8B3E }, + { 0xF0E4, 0x8B31 }, + { 0xF0E5, 0x8B25 }, + { 0xF0E6, 0x8B37 }, + { 0xF0E7, 0x8B26 }, + { 0xF0E8, 0x8B36 }, + { 0xF0E9, 0x8B2E }, + { 0xF0EA, 0x8B24 }, + { 0xF0EB, 0x8B3B }, + { 0xF0EC, 0x8B3D }, + { 0xF0ED, 0x8B3A }, + { 0xF0EE, 0x8C42 }, + { 0xF0EF, 0x8C75 }, + { 0xF0F0, 0x8C99 }, + { 0xF0F1, 0x8C98 }, + { 0xF0F2, 0x8C97 }, + { 0xF0F3, 0x8CFE }, + { 0xF0F4, 0x8D04 }, + { 0xF0F5, 0x8D02 }, + { 0xF0F6, 0x8D00 }, + { 0xF0F7, 0x8E5C }, + { 0xF0F8, 0x8E62 }, + { 0xF0F9, 0x8E60 }, + { 0xF0FA, 0x8E57 }, + { 0xF0FB, 0x8E56 }, + { 0xF0FC, 0x8E5E }, + { 0xF0FD, 0x8E65 }, + { 0xF0FE, 0x8E67 }, + { 0xF140, 0x8E5B }, + { 0xF141, 0x8E5A }, + { 0xF142, 0x8E61 }, + { 0xF143, 0x8E5D }, + { 0xF144, 0x8E69 }, + { 0xF145, 0x8E54 }, + { 0xF146, 0x8F46 }, + { 0xF147, 0x8F47 }, + { 0xF148, 0x8F48 }, + { 0xF149, 0x8F4B }, + { 0xF14A, 0x9128 }, + { 0xF14B, 0x913A }, + { 0xF14C, 0x913B }, + { 0xF14D, 0x913E }, + { 0xF14E, 0x91A8 }, + { 0xF14F, 0x91A5 }, + { 0xF150, 0x91A7 }, + { 0xF151, 0x91AF }, + { 0xF152, 0x91AA }, + { 0xF153, 0x93B5 }, + { 0xF154, 0x938C }, + { 0xF155, 0x9392 }, + { 0xF156, 0x93B7 }, + { 0xF157, 0x939B }, + { 0xF158, 0x939D }, + { 0xF159, 0x9389 }, + { 0xF15A, 0x93A7 }, + { 0xF15B, 0x938E }, + { 0xF15C, 0x93AA }, + { 0xF15D, 0x939E }, + { 0xF15E, 0x93A6 }, + { 0xF15F, 0x9395 }, + { 0xF160, 0x9388 }, + { 0xF161, 0x9399 }, + { 0xF162, 0x939F }, + { 0xF163, 0x938D }, + { 0xF164, 0x93B1 }, + { 0xF165, 0x9391 }, + { 0xF166, 0x93B2 }, + { 0xF167, 0x93A4 }, + { 0xF168, 0x93A8 }, + { 0xF169, 0x93B4 }, + { 0xF16A, 0x93A3 }, + { 0xF16B, 0x93A5 }, + { 0xF16C, 0x95D2 }, + { 0xF16D, 0x95D3 }, + { 0xF16E, 0x95D1 }, + { 0xF16F, 0x96B3 }, + { 0xF170, 0x96D7 }, + { 0xF171, 0x96DA }, + { 0xF172, 0x5DC2 }, + { 0xF173, 0x96DF }, + { 0xF174, 0x96D8 }, + { 0xF175, 0x96DD }, + { 0xF176, 0x9723 }, + { 0xF177, 0x9722 }, + { 0xF178, 0x9725 }, + { 0xF179, 0x97AC }, + { 0xF17A, 0x97AE }, + { 0xF17B, 0x97A8 }, + { 0xF17C, 0x97AB }, + { 0xF17D, 0x97A4 }, + { 0xF17E, 0x97AA }, + { 0xF1A1, 0x97A2 }, + { 0xF1A2, 0x97A5 }, + { 0xF1A3, 0x97D7 }, + { 0xF1A4, 0x97D9 }, + { 0xF1A5, 0x97D6 }, + { 0xF1A6, 0x97D8 }, + { 0xF1A7, 0x97FA }, + { 0xF1A8, 0x9850 }, + { 0xF1A9, 0x9851 }, + { 0xF1AA, 0x9852 }, + { 0xF1AB, 0x98B8 }, + { 0xF1AC, 0x9941 }, + { 0xF1AD, 0x993C }, + { 0xF1AE, 0x993A }, + { 0xF1AF, 0x9A0F }, + { 0xF1B0, 0x9A0B }, + { 0xF1B1, 0x9A09 }, + { 0xF1B2, 0x9A0D }, + { 0xF1B3, 0x9A04 }, + { 0xF1B4, 0x9A11 }, + { 0xF1B5, 0x9A0A }, + { 0xF1B6, 0x9A05 }, + { 0xF1B7, 0x9A07 }, + { 0xF1B8, 0x9A06 }, + { 0xF1B9, 0x9AC0 }, + { 0xF1BA, 0x9ADC }, + { 0xF1BB, 0x9B08 }, + { 0xF1BC, 0x9B04 }, + { 0xF1BD, 0x9B05 }, + { 0xF1BE, 0x9B29 }, + { 0xF1BF, 0x9B35 }, + { 0xF1C0, 0x9B4A }, + { 0xF1C1, 0x9B4C }, + { 0xF1C2, 0x9B4B }, + { 0xF1C3, 0x9BC7 }, + { 0xF1C4, 0x9BC6 }, + { 0xF1C5, 0x9BC3 }, + { 0xF1C6, 0x9BBF }, + { 0xF1C7, 0x9BC1 }, + { 0xF1C8, 0x9BB5 }, + { 0xF1C9, 0x9BB8 }, + { 0xF1CA, 0x9BD3 }, + { 0xF1CB, 0x9BB6 }, + { 0xF1CC, 0x9BC4 }, + { 0xF1CD, 0x9BB9 }, + { 0xF1CE, 0x9BBD }, + { 0xF1CF, 0x9D5C }, + { 0xF1D0, 0x9D53 }, + { 0xF1D1, 0x9D4F }, + { 0xF1D2, 0x9D4A }, + { 0xF1D3, 0x9D5B }, + { 0xF1D4, 0x9D4B }, + { 0xF1D5, 0x9D59 }, + { 0xF1D6, 0x9D56 }, + { 0xF1D7, 0x9D4C }, + { 0xF1D8, 0x9D57 }, + { 0xF1D9, 0x9D52 }, + { 0xF1DA, 0x9D54 }, + { 0xF1DB, 0x9D5F }, + { 0xF1DC, 0x9D58 }, + { 0xF1DD, 0x9D5A }, + { 0xF1DE, 0x9E8E }, + { 0xF1DF, 0x9E8C }, + { 0xF1E0, 0x9EDF }, + { 0xF1E1, 0x9F01 }, + { 0xF1E2, 0x9F00 }, + { 0xF1E3, 0x9F16 }, + { 0xF1E4, 0x9F25 }, + { 0xF1E5, 0x9F2B }, + { 0xF1E6, 0x9F2A }, + { 0xF1E7, 0x9F29 }, + { 0xF1E8, 0x9F28 }, + { 0xF1E9, 0x9F4C }, + { 0xF1EA, 0x9F55 }, + { 0xF1EB, 0x5134 }, + { 0xF1EC, 0x5135 }, + { 0xF1ED, 0x5296 }, + { 0xF1EE, 0x52F7 }, + { 0xF1EF, 0x53B4 }, + { 0xF1F0, 0x56AB }, + { 0xF1F1, 0x56AD }, + { 0xF1F2, 0x56A6 }, + { 0xF1F3, 0x56A7 }, + { 0xF1F4, 0x56AA }, + { 0xF1F5, 0x56AC }, + { 0xF1F6, 0x58DA }, + { 0xF1F7, 0x58DD }, + { 0xF1F8, 0x58DB }, + { 0xF1F9, 0x5912 }, + { 0xF1FA, 0x5B3D }, + { 0xF1FB, 0x5B3E }, + { 0xF1FC, 0x5B3F }, + { 0xF1FD, 0x5DC3 }, + { 0xF1FE, 0x5E70 }, + { 0xF240, 0x5FBF }, + { 0xF241, 0x61FB }, + { 0xF242, 0x6507 }, + { 0xF243, 0x6510 }, + { 0xF244, 0x650D }, + { 0xF245, 0x6509 }, + { 0xF246, 0x650C }, + { 0xF247, 0x650E }, + { 0xF248, 0x6584 }, + { 0xF249, 0x65DE }, + { 0xF24A, 0x65DD }, + { 0xF24B, 0x66DE }, + { 0xF24C, 0x6AE7 }, + { 0xF24D, 0x6AE0 }, + { 0xF24E, 0x6ACC }, + { 0xF24F, 0x6AD1 }, + { 0xF250, 0x6AD9 }, + { 0xF251, 0x6ACB }, + { 0xF252, 0x6ADF }, + { 0xF253, 0x6ADC }, + { 0xF254, 0x6AD0 }, + { 0xF255, 0x6AEB }, + { 0xF256, 0x6ACF }, + { 0xF257, 0x6ACD }, + { 0xF258, 0x6ADE }, + { 0xF259, 0x6B60 }, + { 0xF25A, 0x6BB0 }, + { 0xF25B, 0x6C0C }, + { 0xF25C, 0x7019 }, + { 0xF25D, 0x7027 }, + { 0xF25E, 0x7020 }, + { 0xF25F, 0x7016 }, + { 0xF260, 0x702B }, + { 0xF261, 0x7021 }, + { 0xF262, 0x7022 }, + { 0xF263, 0x7023 }, + { 0xF264, 0x7029 }, + { 0xF265, 0x7017 }, + { 0xF266, 0x7024 }, + { 0xF267, 0x701C }, + { 0xF268, 0x702A }, + { 0xF269, 0x720C }, + { 0xF26A, 0x720A }, + { 0xF26B, 0x7207 }, + { 0xF26C, 0x7202 }, + { 0xF26D, 0x7205 }, + { 0xF26E, 0x72A5 }, + { 0xF26F, 0x72A6 }, + { 0xF270, 0x72A4 }, + { 0xF271, 0x72A3 }, + { 0xF272, 0x72A1 }, + { 0xF273, 0x74CB }, + { 0xF274, 0x74C5 }, + { 0xF275, 0x74B7 }, + { 0xF276, 0x74C3 }, + { 0xF277, 0x7516 }, + { 0xF278, 0x7660 }, + { 0xF279, 0x77C9 }, + { 0xF27A, 0x77CA }, + { 0xF27B, 0x77C4 }, + { 0xF27C, 0x77F1 }, + { 0xF27D, 0x791D }, + { 0xF27E, 0x791B }, + { 0xF2A1, 0x7921 }, + { 0xF2A2, 0x791C }, + { 0xF2A3, 0x7917 }, + { 0xF2A4, 0x791E }, + { 0xF2A5, 0x79B0 }, + { 0xF2A6, 0x7A67 }, + { 0xF2A7, 0x7A68 }, + { 0xF2A8, 0x7C33 }, + { 0xF2A9, 0x7C3C }, + { 0xF2AA, 0x7C39 }, + { 0xF2AB, 0x7C2C }, + { 0xF2AC, 0x7C3B }, + { 0xF2AD, 0x7CEC }, + { 0xF2AE, 0x7CEA }, + { 0xF2AF, 0x7E76 }, + { 0xF2B0, 0x7E75 }, + { 0xF2B1, 0x7E78 }, + { 0xF2B2, 0x7E70 }, + { 0xF2B3, 0x7E77 }, + { 0xF2B4, 0x7E6F }, + { 0xF2B5, 0x7E7A }, + { 0xF2B6, 0x7E72 }, + { 0xF2B7, 0x7E74 }, + { 0xF2B8, 0x7E68 }, + { 0xF2B9, 0x7F4B }, + { 0xF2BA, 0x7F4A }, + { 0xF2BB, 0x7F83 }, + { 0xF2BC, 0x7F86 }, + { 0xF2BD, 0x7FB7 }, + { 0xF2BE, 0x7FFD }, + { 0xF2BF, 0x7FFE }, + { 0xF2C0, 0x8078 }, + { 0xF2C1, 0x81D7 }, + { 0xF2C2, 0x81D5 }, + { 0xF2C3, 0x8264 }, + { 0xF2C4, 0x8261 }, + { 0xF2C5, 0x8263 }, + { 0xF2C6, 0x85EB }, + { 0xF2C7, 0x85F1 }, + { 0xF2C8, 0x85ED }, + { 0xF2C9, 0x85D9 }, + { 0xF2CA, 0x85E1 }, + { 0xF2CB, 0x85E8 }, + { 0xF2CC, 0x85DA }, + { 0xF2CD, 0x85D7 }, + { 0xF2CE, 0x85EC }, + { 0xF2CF, 0x85F2 }, + { 0xF2D0, 0x85F8 }, + { 0xF2D1, 0x85D8 }, + { 0xF2D2, 0x85DF }, + { 0xF2D3, 0x85E3 }, + { 0xF2D4, 0x85DC }, + { 0xF2D5, 0x85D1 }, + { 0xF2D6, 0x85F0 }, + { 0xF2D7, 0x85E6 }, + { 0xF2D8, 0x85EF }, + { 0xF2D9, 0x85DE }, + { 0xF2DA, 0x85E2 }, + { 0xF2DB, 0x8800 }, + { 0xF2DC, 0x87FA }, + { 0xF2DD, 0x8803 }, + { 0xF2DE, 0x87F6 }, + { 0xF2DF, 0x87F7 }, + { 0xF2E0, 0x8809 }, + { 0xF2E1, 0x880C }, + { 0xF2E2, 0x880B }, + { 0xF2E3, 0x8806 }, + { 0xF2E4, 0x87FC }, + { 0xF2E5, 0x8808 }, + { 0xF2E6, 0x87FF }, + { 0xF2E7, 0x880A }, + { 0xF2E8, 0x8802 }, + { 0xF2E9, 0x8962 }, + { 0xF2EA, 0x895A }, + { 0xF2EB, 0x895B }, + { 0xF2EC, 0x8957 }, + { 0xF2ED, 0x8961 }, + { 0xF2EE, 0x895C }, + { 0xF2EF, 0x8958 }, + { 0xF2F0, 0x895D }, + { 0xF2F1, 0x8959 }, + { 0xF2F2, 0x8988 }, + { 0xF2F3, 0x89B7 }, + { 0xF2F4, 0x89B6 }, + { 0xF2F5, 0x89F6 }, + { 0xF2F6, 0x8B50 }, + { 0xF2F7, 0x8B48 }, + { 0xF2F8, 0x8B4A }, + { 0xF2F9, 0x8B40 }, + { 0xF2FA, 0x8B53 }, + { 0xF2FB, 0x8B56 }, + { 0xF2FC, 0x8B54 }, + { 0xF2FD, 0x8B4B }, + { 0xF2FE, 0x8B55 }, + { 0xF340, 0x8B51 }, + { 0xF341, 0x8B42 }, + { 0xF342, 0x8B52 }, + { 0xF343, 0x8B57 }, + { 0xF344, 0x8C43 }, + { 0xF345, 0x8C77 }, + { 0xF346, 0x8C76 }, + { 0xF347, 0x8C9A }, + { 0xF348, 0x8D06 }, + { 0xF349, 0x8D07 }, + { 0xF34A, 0x8D09 }, + { 0xF34B, 0x8DAC }, + { 0xF34C, 0x8DAA }, + { 0xF34D, 0x8DAD }, + { 0xF34E, 0x8DAB }, + { 0xF34F, 0x8E6D }, + { 0xF350, 0x8E78 }, + { 0xF351, 0x8E73 }, + { 0xF352, 0x8E6A }, + { 0xF353, 0x8E6F }, + { 0xF354, 0x8E7B }, + { 0xF355, 0x8EC2 }, + { 0xF356, 0x8F52 }, + { 0xF357, 0x8F51 }, + { 0xF358, 0x8F4F }, + { 0xF359, 0x8F50 }, + { 0xF35A, 0x8F53 }, + { 0xF35B, 0x8FB4 }, + { 0xF35C, 0x9140 }, + { 0xF35D, 0x913F }, + { 0xF35E, 0x91B0 }, + { 0xF35F, 0x91AD }, + { 0xF360, 0x93DE }, + { 0xF361, 0x93C7 }, + { 0xF362, 0x93CF }, + { 0xF363, 0x93C2 }, + { 0xF364, 0x93DA }, + { 0xF365, 0x93D0 }, + { 0xF366, 0x93F9 }, + { 0xF367, 0x93EC }, + { 0xF368, 0x93CC }, + { 0xF369, 0x93D9 }, + { 0xF36A, 0x93A9 }, + { 0xF36B, 0x93E6 }, + { 0xF36C, 0x93CA }, + { 0xF36D, 0x93D4 }, + { 0xF36E, 0x93EE }, + { 0xF36F, 0x93E3 }, + { 0xF370, 0x93D5 }, + { 0xF371, 0x93C4 }, + { 0xF372, 0x93CE }, + { 0xF373, 0x93C0 }, + { 0xF374, 0x93D2 }, + { 0xF375, 0x93E7 }, + { 0xF376, 0x957D }, + { 0xF377, 0x95DA }, + { 0xF378, 0x95DB }, + { 0xF379, 0x96E1 }, + { 0xF37A, 0x9729 }, + { 0xF37B, 0x972B }, + { 0xF37C, 0x972C }, + { 0xF37D, 0x9728 }, + { 0xF37E, 0x9726 }, + { 0xF3A1, 0x97B3 }, + { 0xF3A2, 0x97B7 }, + { 0xF3A3, 0x97B6 }, + { 0xF3A4, 0x97DD }, + { 0xF3A5, 0x97DE }, + { 0xF3A6, 0x97DF }, + { 0xF3A7, 0x985C }, + { 0xF3A8, 0x9859 }, + { 0xF3A9, 0x985D }, + { 0xF3AA, 0x9857 }, + { 0xF3AB, 0x98BF }, + { 0xF3AC, 0x98BD }, + { 0xF3AD, 0x98BB }, + { 0xF3AE, 0x98BE }, + { 0xF3AF, 0x9948 }, + { 0xF3B0, 0x9947 }, + { 0xF3B1, 0x9943 }, + { 0xF3B2, 0x99A6 }, + { 0xF3B3, 0x99A7 }, + { 0xF3B4, 0x9A1A }, + { 0xF3B5, 0x9A15 }, + { 0xF3B6, 0x9A25 }, + { 0xF3B7, 0x9A1D }, + { 0xF3B8, 0x9A24 }, + { 0xF3B9, 0x9A1B }, + { 0xF3BA, 0x9A22 }, + { 0xF3BB, 0x9A20 }, + { 0xF3BC, 0x9A27 }, + { 0xF3BD, 0x9A23 }, + { 0xF3BE, 0x9A1E }, + { 0xF3BF, 0x9A1C }, + { 0xF3C0, 0x9A14 }, + { 0xF3C1, 0x9AC2 }, + { 0xF3C2, 0x9B0B }, + { 0xF3C3, 0x9B0A }, + { 0xF3C4, 0x9B0E }, + { 0xF3C5, 0x9B0C }, + { 0xF3C6, 0x9B37 }, + { 0xF3C7, 0x9BEA }, + { 0xF3C8, 0x9BEB }, + { 0xF3C9, 0x9BE0 }, + { 0xF3CA, 0x9BDE }, + { 0xF3CB, 0x9BE4 }, + { 0xF3CC, 0x9BE6 }, + { 0xF3CD, 0x9BE2 }, + { 0xF3CE, 0x9BF0 }, + { 0xF3CF, 0x9BD4 }, + { 0xF3D0, 0x9BD7 }, + { 0xF3D1, 0x9BEC }, + { 0xF3D2, 0x9BDC }, + { 0xF3D3, 0x9BD9 }, + { 0xF3D4, 0x9BE5 }, + { 0xF3D5, 0x9BD5 }, + { 0xF3D6, 0x9BE1 }, + { 0xF3D7, 0x9BDA }, + { 0xF3D8, 0x9D77 }, + { 0xF3D9, 0x9D81 }, + { 0xF3DA, 0x9D8A }, + { 0xF3DB, 0x9D84 }, + { 0xF3DC, 0x9D88 }, + { 0xF3DD, 0x9D71 }, + { 0xF3DE, 0x9D80 }, + { 0xF3DF, 0x9D78 }, + { 0xF3E0, 0x9D86 }, + { 0xF3E1, 0x9D8B }, + { 0xF3E2, 0x9D8C }, + { 0xF3E3, 0x9D7D }, + { 0xF3E4, 0x9D6B }, + { 0xF3E5, 0x9D74 }, + { 0xF3E6, 0x9D75 }, + { 0xF3E7, 0x9D70 }, + { 0xF3E8, 0x9D69 }, + { 0xF3E9, 0x9D85 }, + { 0xF3EA, 0x9D73 }, + { 0xF3EB, 0x9D7B }, + { 0xF3EC, 0x9D82 }, + { 0xF3ED, 0x9D6F }, + { 0xF3EE, 0x9D79 }, + { 0xF3EF, 0x9D7F }, + { 0xF3F0, 0x9D87 }, + { 0xF3F1, 0x9D68 }, + { 0xF3F2, 0x9E94 }, + { 0xF3F3, 0x9E91 }, + { 0xF3F4, 0x9EC0 }, + { 0xF3F5, 0x9EFC }, + { 0xF3F6, 0x9F2D }, + { 0xF3F7, 0x9F40 }, + { 0xF3F8, 0x9F41 }, + { 0xF3F9, 0x9F4D }, + { 0xF3FA, 0x9F56 }, + { 0xF3FB, 0x9F57 }, + { 0xF3FC, 0x9F58 }, + { 0xF3FD, 0x5337 }, + { 0xF3FE, 0x56B2 }, + { 0xF440, 0x56B5 }, + { 0xF441, 0x56B3 }, + { 0xF442, 0x58E3 }, + { 0xF443, 0x5B45 }, + { 0xF444, 0x5DC6 }, + { 0xF445, 0x5DC7 }, + { 0xF446, 0x5EEE }, + { 0xF447, 0x5EEF }, + { 0xF448, 0x5FC0 }, + { 0xF449, 0x5FC1 }, + { 0xF44A, 0x61F9 }, + { 0xF44B, 0x6517 }, + { 0xF44C, 0x6516 }, + { 0xF44D, 0x6515 }, + { 0xF44E, 0x6513 }, + { 0xF44F, 0x65DF }, + { 0xF450, 0x66E8 }, + { 0xF451, 0x66E3 }, + { 0xF452, 0x66E4 }, + { 0xF453, 0x6AF3 }, + { 0xF454, 0x6AF0 }, + { 0xF455, 0x6AEA }, + { 0xF456, 0x6AE8 }, + { 0xF457, 0x6AF9 }, + { 0xF458, 0x6AF1 }, + { 0xF459, 0x6AEE }, + { 0xF45A, 0x6AEF }, + { 0xF45B, 0x703C }, + { 0xF45C, 0x7035 }, + { 0xF45D, 0x702F }, + { 0xF45E, 0x7037 }, + { 0xF45F, 0x7034 }, + { 0xF460, 0x7031 }, + { 0xF461, 0x7042 }, + { 0xF462, 0x7038 }, + { 0xF463, 0x703F }, + { 0xF464, 0x703A }, + { 0xF465, 0x7039 }, + { 0xF466, 0x7040 }, + { 0xF467, 0x703B }, + { 0xF468, 0x7033 }, + { 0xF469, 0x7041 }, + { 0xF46A, 0x7213 }, + { 0xF46B, 0x7214 }, + { 0xF46C, 0x72A8 }, + { 0xF46D, 0x737D }, + { 0xF46E, 0x737C }, + { 0xF46F, 0x74BA }, + { 0xF470, 0x76AB }, + { 0xF471, 0x76AA }, + { 0xF472, 0x76BE }, + { 0xF473, 0x76ED }, + { 0xF474, 0x77CC }, + { 0xF475, 0x77CE }, + { 0xF476, 0x77CF }, + { 0xF477, 0x77CD }, + { 0xF478, 0x77F2 }, + { 0xF479, 0x7925 }, + { 0xF47A, 0x7923 }, + { 0xF47B, 0x7927 }, + { 0xF47C, 0x7928 }, + { 0xF47D, 0x7924 }, + { 0xF47E, 0x7929 }, + { 0xF4A1, 0x79B2 }, + { 0xF4A2, 0x7A6E }, + { 0xF4A3, 0x7A6C }, + { 0xF4A4, 0x7A6D }, + { 0xF4A5, 0x7AF7 }, + { 0xF4A6, 0x7C49 }, + { 0xF4A7, 0x7C48 }, + { 0xF4A8, 0x7C4A }, + { 0xF4A9, 0x7C47 }, + { 0xF4AA, 0x7C45 }, + { 0xF4AB, 0x7CEE }, + { 0xF4AC, 0x7E7B }, + { 0xF4AD, 0x7E7E }, + { 0xF4AE, 0x7E81 }, + { 0xF4AF, 0x7E80 }, + { 0xF4B0, 0x7FBA }, + { 0xF4B1, 0x7FFF }, + { 0xF4B2, 0x8079 }, + { 0xF4B3, 0x81DB }, + { 0xF4B4, 0x81D9 }, + { 0xF4B5, 0x820B }, + { 0xF4B6, 0x8268 }, + { 0xF4B7, 0x8269 }, + { 0xF4B8, 0x8622 }, + { 0xF4B9, 0x85FF }, + { 0xF4BA, 0x8601 }, + { 0xF4BB, 0x85FE }, + { 0xF4BC, 0x861B }, + { 0xF4BD, 0x8600 }, + { 0xF4BE, 0x85F6 }, + { 0xF4BF, 0x8604 }, + { 0xF4C0, 0x8609 }, + { 0xF4C1, 0x8605 }, + { 0xF4C2, 0x860C }, + { 0xF4C3, 0x85FD }, + { 0xF4C4, 0x8819 }, + { 0xF4C5, 0x8810 }, + { 0xF4C6, 0x8811 }, + { 0xF4C7, 0x8817 }, + { 0xF4C8, 0x8813 }, + { 0xF4C9, 0x8816 }, + { 0xF4CA, 0x8963 }, + { 0xF4CB, 0x8966 }, + { 0xF4CC, 0x89B9 }, + { 0xF4CD, 0x89F7 }, + { 0xF4CE, 0x8B60 }, + { 0xF4CF, 0x8B6A }, + { 0xF4D0, 0x8B5D }, + { 0xF4D1, 0x8B68 }, + { 0xF4D2, 0x8B63 }, + { 0xF4D3, 0x8B65 }, + { 0xF4D4, 0x8B67 }, + { 0xF4D5, 0x8B6D }, + { 0xF4D6, 0x8DAE }, + { 0xF4D7, 0x8E86 }, + { 0xF4D8, 0x8E88 }, + { 0xF4D9, 0x8E84 }, + { 0xF4DA, 0x8F59 }, + { 0xF4DB, 0x8F56 }, + { 0xF4DC, 0x8F57 }, + { 0xF4DD, 0x8F55 }, + { 0xF4DE, 0x8F58 }, + { 0xF4DF, 0x8F5A }, + { 0xF4E0, 0x908D }, + { 0xF4E1, 0x9143 }, + { 0xF4E2, 0x9141 }, + { 0xF4E3, 0x91B7 }, + { 0xF4E4, 0x91B5 }, + { 0xF4E5, 0x91B2 }, + { 0xF4E6, 0x91B3 }, + { 0xF4E7, 0x940B }, + { 0xF4E8, 0x9413 }, + { 0xF4E9, 0x93FB }, + { 0xF4EA, 0x9420 }, + { 0xF4EB, 0x940F }, + { 0xF4EC, 0x9414 }, + { 0xF4ED, 0x93FE }, + { 0xF4EE, 0x9415 }, + { 0xF4EF, 0x9410 }, + { 0xF4F0, 0x9428 }, + { 0xF4F1, 0x9419 }, + { 0xF4F2, 0x940D }, + { 0xF4F3, 0x93F5 }, + { 0xF4F4, 0x9400 }, + { 0xF4F5, 0x93F7 }, + { 0xF4F6, 0x9407 }, + { 0xF4F7, 0x940E }, + { 0xF4F8, 0x9416 }, + { 0xF4F9, 0x9412 }, + { 0xF4FA, 0x93FA }, + { 0xF4FB, 0x9409 }, + { 0xF4FC, 0x93F8 }, + { 0xF4FD, 0x940A }, + { 0xF4FE, 0x93FF }, + { 0xF540, 0x93FC }, + { 0xF541, 0x940C }, + { 0xF542, 0x93F6 }, + { 0xF543, 0x9411 }, + { 0xF544, 0x9406 }, + { 0xF545, 0x95DE }, + { 0xF546, 0x95E0 }, + { 0xF547, 0x95DF }, + { 0xF548, 0x972E }, + { 0xF549, 0x972F }, + { 0xF54A, 0x97B9 }, + { 0xF54B, 0x97BB }, + { 0xF54C, 0x97FD }, + { 0xF54D, 0x97FE }, + { 0xF54E, 0x9860 }, + { 0xF54F, 0x9862 }, + { 0xF550, 0x9863 }, + { 0xF551, 0x985F }, + { 0xF552, 0x98C1 }, + { 0xF553, 0x98C2 }, + { 0xF554, 0x9950 }, + { 0xF555, 0x994E }, + { 0xF556, 0x9959 }, + { 0xF557, 0x994C }, + { 0xF558, 0x994B }, + { 0xF559, 0x9953 }, + { 0xF55A, 0x9A32 }, + { 0xF55B, 0x9A34 }, + { 0xF55C, 0x9A31 }, + { 0xF55D, 0x9A2C }, + { 0xF55E, 0x9A2A }, + { 0xF55F, 0x9A36 }, + { 0xF560, 0x9A29 }, + { 0xF561, 0x9A2E }, + { 0xF562, 0x9A38 }, + { 0xF563, 0x9A2D }, + { 0xF564, 0x9AC7 }, + { 0xF565, 0x9ACA }, + { 0xF566, 0x9AC6 }, + { 0xF567, 0x9B10 }, + { 0xF568, 0x9B12 }, + { 0xF569, 0x9B11 }, + { 0xF56A, 0x9C0B }, + { 0xF56B, 0x9C08 }, + { 0xF56C, 0x9BF7 }, + { 0xF56D, 0x9C05 }, + { 0xF56E, 0x9C12 }, + { 0xF56F, 0x9BF8 }, + { 0xF570, 0x9C40 }, + { 0xF571, 0x9C07 }, + { 0xF572, 0x9C0E }, + { 0xF573, 0x9C06 }, + { 0xF574, 0x9C17 }, + { 0xF575, 0x9C14 }, + { 0xF576, 0x9C09 }, + { 0xF577, 0x9D9F }, + { 0xF578, 0x9D99 }, + { 0xF579, 0x9DA4 }, + { 0xF57A, 0x9D9D }, + { 0xF57B, 0x9D92 }, + { 0xF57C, 0x9D98 }, + { 0xF57D, 0x9D90 }, + { 0xF57E, 0x9D9B }, + { 0xF5A1, 0x9DA0 }, + { 0xF5A2, 0x9D94 }, + { 0xF5A3, 0x9D9C }, + { 0xF5A4, 0x9DAA }, + { 0xF5A5, 0x9D97 }, + { 0xF5A6, 0x9DA1 }, + { 0xF5A7, 0x9D9A }, + { 0xF5A8, 0x9DA2 }, + { 0xF5A9, 0x9DA8 }, + { 0xF5AA, 0x9D9E }, + { 0xF5AB, 0x9DA3 }, + { 0xF5AC, 0x9DBF }, + { 0xF5AD, 0x9DA9 }, + { 0xF5AE, 0x9D96 }, + { 0xF5AF, 0x9DA6 }, + { 0xF5B0, 0x9DA7 }, + { 0xF5B1, 0x9E99 }, + { 0xF5B2, 0x9E9B }, + { 0xF5B3, 0x9E9A }, + { 0xF5B4, 0x9EE5 }, + { 0xF5B5, 0x9EE4 }, + { 0xF5B6, 0x9EE7 }, + { 0xF5B7, 0x9EE6 }, + { 0xF5B8, 0x9F30 }, + { 0xF5B9, 0x9F2E }, + { 0xF5BA, 0x9F5B }, + { 0xF5BB, 0x9F60 }, + { 0xF5BC, 0x9F5E }, + { 0xF5BD, 0x9F5D }, + { 0xF5BE, 0x9F59 }, + { 0xF5BF, 0x9F91 }, + { 0xF5C0, 0x513A }, + { 0xF5C1, 0x5139 }, + { 0xF5C2, 0x5298 }, + { 0xF5C3, 0x5297 }, + { 0xF5C4, 0x56C3 }, + { 0xF5C5, 0x56BD }, + { 0xF5C6, 0x56BE }, + { 0xF5C7, 0x5B48 }, + { 0xF5C8, 0x5B47 }, + { 0xF5C9, 0x5DCB }, + { 0xF5CA, 0x5DCF }, + { 0xF5CB, 0x5EF1 }, + { 0xF5CC, 0x61FD }, + { 0xF5CD, 0x651B }, + { 0xF5CE, 0x6B02 }, + { 0xF5CF, 0x6AFC }, + { 0xF5D0, 0x6B03 }, + { 0xF5D1, 0x6AF8 }, + { 0xF5D2, 0x6B00 }, + { 0xF5D3, 0x7043 }, + { 0xF5D4, 0x7044 }, + { 0xF5D5, 0x704A }, + { 0xF5D6, 0x7048 }, + { 0xF5D7, 0x7049 }, + { 0xF5D8, 0x7045 }, + { 0xF5D9, 0x7046 }, + { 0xF5DA, 0x721D }, + { 0xF5DB, 0x721A }, + { 0xF5DC, 0x7219 }, + { 0xF5DD, 0x737E }, + { 0xF5DE, 0x7517 }, + { 0xF5DF, 0x766A }, + { 0xF5E0, 0x77D0 }, + { 0xF5E1, 0x792D }, + { 0xF5E2, 0x7931 }, + { 0xF5E3, 0x792F }, + { 0xF5E4, 0x7C54 }, + { 0xF5E5, 0x7C53 }, + { 0xF5E6, 0x7CF2 }, + { 0xF5E7, 0x7E8A }, + { 0xF5E8, 0x7E87 }, + { 0xF5E9, 0x7E88 }, + { 0xF5EA, 0x7E8B }, + { 0xF5EB, 0x7E86 }, + { 0xF5EC, 0x7E8D }, + { 0xF5ED, 0x7F4D }, + { 0xF5EE, 0x7FBB }, + { 0xF5EF, 0x8030 }, + { 0xF5F0, 0x81DD }, + { 0xF5F1, 0x8618 }, + { 0xF5F2, 0x862A }, + { 0xF5F3, 0x8626 }, + { 0xF5F4, 0x861F }, + { 0xF5F5, 0x8623 }, + { 0xF5F6, 0x861C }, + { 0xF5F7, 0x8619 }, + { 0xF5F8, 0x8627 }, + { 0xF5F9, 0x862E }, + { 0xF5FA, 0x8621 }, + { 0xF5FB, 0x8620 }, + { 0xF5FC, 0x8629 }, + { 0xF5FD, 0x861E }, + { 0xF5FE, 0x8625 }, + { 0xF640, 0x8829 }, + { 0xF641, 0x881D }, + { 0xF642, 0x881B }, + { 0xF643, 0x8820 }, + { 0xF644, 0x8824 }, + { 0xF645, 0x881C }, + { 0xF646, 0x882B }, + { 0xF647, 0x884A }, + { 0xF648, 0x896D }, + { 0xF649, 0x8969 }, + { 0xF64A, 0x896E }, + { 0xF64B, 0x896B }, + { 0xF64C, 0x89FA }, + { 0xF64D, 0x8B79 }, + { 0xF64E, 0x8B78 }, + { 0xF64F, 0x8B45 }, + { 0xF650, 0x8B7A }, + { 0xF651, 0x8B7B }, + { 0xF652, 0x8D10 }, + { 0xF653, 0x8D14 }, + { 0xF654, 0x8DAF }, + { 0xF655, 0x8E8E }, + { 0xF656, 0x8E8C }, + { 0xF657, 0x8F5E }, + { 0xF658, 0x8F5B }, + { 0xF659, 0x8F5D }, + { 0xF65A, 0x9146 }, + { 0xF65B, 0x9144 }, + { 0xF65C, 0x9145 }, + { 0xF65D, 0x91B9 }, + { 0xF65E, 0x943F }, + { 0xF65F, 0x943B }, + { 0xF660, 0x9436 }, + { 0xF661, 0x9429 }, + { 0xF662, 0x943D }, + { 0xF663, 0x943C }, + { 0xF664, 0x9430 }, + { 0xF665, 0x9439 }, + { 0xF666, 0x942A }, + { 0xF667, 0x9437 }, + { 0xF668, 0x942C }, + { 0xF669, 0x9440 }, + { 0xF66A, 0x9431 }, + { 0xF66B, 0x95E5 }, + { 0xF66C, 0x95E4 }, + { 0xF66D, 0x95E3 }, + { 0xF66E, 0x9735 }, + { 0xF66F, 0x973A }, + { 0xF670, 0x97BF }, + { 0xF671, 0x97E1 }, + { 0xF672, 0x9864 }, + { 0xF673, 0x98C9 }, + { 0xF674, 0x98C6 }, + { 0xF675, 0x98C0 }, + { 0xF676, 0x9958 }, + { 0xF677, 0x9956 }, + { 0xF678, 0x9A39 }, + { 0xF679, 0x9A3D }, + { 0xF67A, 0x9A46 }, + { 0xF67B, 0x9A44 }, + { 0xF67C, 0x9A42 }, + { 0xF67D, 0x9A41 }, + { 0xF67E, 0x9A3A }, + { 0xF6A1, 0x9A3F }, + { 0xF6A2, 0x9ACD }, + { 0xF6A3, 0x9B15 }, + { 0xF6A4, 0x9B17 }, + { 0xF6A5, 0x9B18 }, + { 0xF6A6, 0x9B16 }, + { 0xF6A7, 0x9B3A }, + { 0xF6A8, 0x9B52 }, + { 0xF6A9, 0x9C2B }, + { 0xF6AA, 0x9C1D }, + { 0xF6AB, 0x9C1C }, + { 0xF6AC, 0x9C2C }, + { 0xF6AD, 0x9C23 }, + { 0xF6AE, 0x9C28 }, + { 0xF6AF, 0x9C29 }, + { 0xF6B0, 0x9C24 }, + { 0xF6B1, 0x9C21 }, + { 0xF6B2, 0x9DB7 }, + { 0xF6B3, 0x9DB6 }, + { 0xF6B4, 0x9DBC }, + { 0xF6B5, 0x9DC1 }, + { 0xF6B6, 0x9DC7 }, + { 0xF6B7, 0x9DCA }, + { 0xF6B8, 0x9DCF }, + { 0xF6B9, 0x9DBE }, + { 0xF6BA, 0x9DC5 }, + { 0xF6BB, 0x9DC3 }, + { 0xF6BC, 0x9DBB }, + { 0xF6BD, 0x9DB5 }, + { 0xF6BE, 0x9DCE }, + { 0xF6BF, 0x9DB9 }, + { 0xF6C0, 0x9DBA }, + { 0xF6C1, 0x9DAC }, + { 0xF6C2, 0x9DC8 }, + { 0xF6C3, 0x9DB1 }, + { 0xF6C4, 0x9DAD }, + { 0xF6C5, 0x9DCC }, + { 0xF6C6, 0x9DB3 }, + { 0xF6C7, 0x9DCD }, + { 0xF6C8, 0x9DB2 }, + { 0xF6C9, 0x9E7A }, + { 0xF6CA, 0x9E9C }, + { 0xF6CB, 0x9EEB }, + { 0xF6CC, 0x9EEE }, + { 0xF6CD, 0x9EED }, + { 0xF6CE, 0x9F1B }, + { 0xF6CF, 0x9F18 }, + { 0xF6D0, 0x9F1A }, + { 0xF6D1, 0x9F31 }, + { 0xF6D2, 0x9F4E }, + { 0xF6D3, 0x9F65 }, + { 0xF6D4, 0x9F64 }, + { 0xF6D5, 0x9F92 }, + { 0xF6D6, 0x4EB9 }, + { 0xF6D7, 0x56C6 }, + { 0xF6D8, 0x56C5 }, + { 0xF6D9, 0x56CB }, + { 0xF6DA, 0x5971 }, + { 0xF6DB, 0x5B4B }, + { 0xF6DC, 0x5B4C }, + { 0xF6DD, 0x5DD5 }, + { 0xF6DE, 0x5DD1 }, + { 0xF6DF, 0x5EF2 }, + { 0xF6E0, 0x6521 }, + { 0xF6E1, 0x6520 }, + { 0xF6E2, 0x6526 }, + { 0xF6E3, 0x6522 }, + { 0xF6E4, 0x6B0B }, + { 0xF6E5, 0x6B08 }, + { 0xF6E6, 0x6B09 }, + { 0xF6E7, 0x6C0D }, + { 0xF6E8, 0x7055 }, + { 0xF6E9, 0x7056 }, + { 0xF6EA, 0x7057 }, + { 0xF6EB, 0x7052 }, + { 0xF6EC, 0x721E }, + { 0xF6ED, 0x721F }, + { 0xF6EE, 0x72A9 }, + { 0xF6EF, 0x737F }, + { 0xF6F0, 0x74D8 }, + { 0xF6F1, 0x74D5 }, + { 0xF6F2, 0x74D9 }, + { 0xF6F3, 0x74D7 }, + { 0xF6F4, 0x766D }, + { 0xF6F5, 0x76AD }, + { 0xF6F6, 0x7935 }, + { 0xF6F7, 0x79B4 }, + { 0xF6F8, 0x7A70 }, + { 0xF6F9, 0x7A71 }, + { 0xF6FA, 0x7C57 }, + { 0xF6FB, 0x7C5C }, + { 0xF6FC, 0x7C59 }, + { 0xF6FD, 0x7C5B }, + { 0xF6FE, 0x7C5A }, + { 0xF740, 0x7CF4 }, + { 0xF741, 0x7CF1 }, + { 0xF742, 0x7E91 }, + { 0xF743, 0x7F4F }, + { 0xF744, 0x7F87 }, + { 0xF745, 0x81DE }, + { 0xF746, 0x826B }, + { 0xF747, 0x8634 }, + { 0xF748, 0x8635 }, + { 0xF749, 0x8633 }, + { 0xF74A, 0x862C }, + { 0xF74B, 0x8632 }, + { 0xF74C, 0x8636 }, + { 0xF74D, 0x882C }, + { 0xF74E, 0x8828 }, + { 0xF74F, 0x8826 }, + { 0xF750, 0x882A }, + { 0xF751, 0x8825 }, + { 0xF752, 0x8971 }, + { 0xF753, 0x89BF }, + { 0xF754, 0x89BE }, + { 0xF755, 0x89FB }, + { 0xF756, 0x8B7E }, + { 0xF757, 0x8B84 }, + { 0xF758, 0x8B82 }, + { 0xF759, 0x8B86 }, + { 0xF75A, 0x8B85 }, + { 0xF75B, 0x8B7F }, + { 0xF75C, 0x8D15 }, + { 0xF75D, 0x8E95 }, + { 0xF75E, 0x8E94 }, + { 0xF75F, 0x8E9A }, + { 0xF760, 0x8E92 }, + { 0xF761, 0x8E90 }, + { 0xF762, 0x8E96 }, + { 0xF763, 0x8E97 }, + { 0xF764, 0x8F60 }, + { 0xF765, 0x8F62 }, + { 0xF766, 0x9147 }, + { 0xF767, 0x944C }, + { 0xF768, 0x9450 }, + { 0xF769, 0x944A }, + { 0xF76A, 0x944B }, + { 0xF76B, 0x944F }, + { 0xF76C, 0x9447 }, + { 0xF76D, 0x9445 }, + { 0xF76E, 0x9448 }, + { 0xF76F, 0x9449 }, + { 0xF770, 0x9446 }, + { 0xF771, 0x973F }, + { 0xF772, 0x97E3 }, + { 0xF773, 0x986A }, + { 0xF774, 0x9869 }, + { 0xF775, 0x98CB }, + { 0xF776, 0x9954 }, + { 0xF777, 0x995B }, + { 0xF778, 0x9A4E }, + { 0xF779, 0x9A53 }, + { 0xF77A, 0x9A54 }, + { 0xF77B, 0x9A4C }, + { 0xF77C, 0x9A4F }, + { 0xF77D, 0x9A48 }, + { 0xF77E, 0x9A4A }, + { 0xF7A1, 0x9A49 }, + { 0xF7A2, 0x9A52 }, + { 0xF7A3, 0x9A50 }, + { 0xF7A4, 0x9AD0 }, + { 0xF7A5, 0x9B19 }, + { 0xF7A6, 0x9B2B }, + { 0xF7A7, 0x9B3B }, + { 0xF7A8, 0x9B56 }, + { 0xF7A9, 0x9B55 }, + { 0xF7AA, 0x9C46 }, + { 0xF7AB, 0x9C48 }, + { 0xF7AC, 0x9C3F }, + { 0xF7AD, 0x9C44 }, + { 0xF7AE, 0x9C39 }, + { 0xF7AF, 0x9C33 }, + { 0xF7B0, 0x9C41 }, + { 0xF7B1, 0x9C3C }, + { 0xF7B2, 0x9C37 }, + { 0xF7B3, 0x9C34 }, + { 0xF7B4, 0x9C32 }, + { 0xF7B5, 0x9C3D }, + { 0xF7B6, 0x9C36 }, + { 0xF7B7, 0x9DDB }, + { 0xF7B8, 0x9DD2 }, + { 0xF7B9, 0x9DDE }, + { 0xF7BA, 0x9DDA }, + { 0xF7BB, 0x9DCB }, + { 0xF7BC, 0x9DD0 }, + { 0xF7BD, 0x9DDC }, + { 0xF7BE, 0x9DD1 }, + { 0xF7BF, 0x9DDF }, + { 0xF7C0, 0x9DE9 }, + { 0xF7C1, 0x9DD9 }, + { 0xF7C2, 0x9DD8 }, + { 0xF7C3, 0x9DD6 }, + { 0xF7C4, 0x9DF5 }, + { 0xF7C5, 0x9DD5 }, + { 0xF7C6, 0x9DDD }, + { 0xF7C7, 0x9EB6 }, + { 0xF7C8, 0x9EF0 }, + { 0xF7C9, 0x9F35 }, + { 0xF7CA, 0x9F33 }, + { 0xF7CB, 0x9F32 }, + { 0xF7CC, 0x9F42 }, + { 0xF7CD, 0x9F6B }, + { 0xF7CE, 0x9F95 }, + { 0xF7CF, 0x9FA2 }, + { 0xF7D0, 0x513D }, + { 0xF7D1, 0x5299 }, + { 0xF7D2, 0x58E8 }, + { 0xF7D3, 0x58E7 }, + { 0xF7D4, 0x5972 }, + { 0xF7D5, 0x5B4D }, + { 0xF7D6, 0x5DD8 }, + { 0xF7D7, 0x882F }, + { 0xF7D8, 0x5F4F }, + { 0xF7D9, 0x6201 }, + { 0xF7DA, 0x6203 }, + { 0xF7DB, 0x6204 }, + { 0xF7DC, 0x6529 }, + { 0xF7DD, 0x6525 }, + { 0xF7DE, 0x6596 }, + { 0xF7DF, 0x66EB }, + { 0xF7E0, 0x6B11 }, + { 0xF7E1, 0x6B12 }, + { 0xF7E2, 0x6B0F }, + { 0xF7E3, 0x6BCA }, + { 0xF7E4, 0x705B }, + { 0xF7E5, 0x705A }, + { 0xF7E6, 0x7222 }, + { 0xF7E7, 0x7382 }, + { 0xF7E8, 0x7381 }, + { 0xF7E9, 0x7383 }, + { 0xF7EA, 0x7670 }, + { 0xF7EB, 0x77D4 }, + { 0xF7EC, 0x7C67 }, + { 0xF7ED, 0x7C66 }, + { 0xF7EE, 0x7E95 }, + { 0xF7EF, 0x826C }, + { 0xF7F0, 0x863A }, + { 0xF7F1, 0x8640 }, + { 0xF7F2, 0x8639 }, + { 0xF7F3, 0x863C }, + { 0xF7F4, 0x8631 }, + { 0xF7F5, 0x863B }, + { 0xF7F6, 0x863E }, + { 0xF7F7, 0x8830 }, + { 0xF7F8, 0x8832 }, + { 0xF7F9, 0x882E }, + { 0xF7FA, 0x8833 }, + { 0xF7FB, 0x8976 }, + { 0xF7FC, 0x8974 }, + { 0xF7FD, 0x8973 }, + { 0xF7FE, 0x89FE }, + { 0xF840, 0x8B8C }, + { 0xF841, 0x8B8E }, + { 0xF842, 0x8B8B }, + { 0xF843, 0x8B88 }, + { 0xF844, 0x8C45 }, + { 0xF845, 0x8D19 }, + { 0xF846, 0x8E98 }, + { 0xF847, 0x8F64 }, + { 0xF848, 0x8F63 }, + { 0xF849, 0x91BC }, + { 0xF84A, 0x9462 }, + { 0xF84B, 0x9455 }, + { 0xF84C, 0x945D }, + { 0xF84D, 0x9457 }, + { 0xF84E, 0x945E }, + { 0xF84F, 0x97C4 }, + { 0xF850, 0x97C5 }, + { 0xF851, 0x9800 }, + { 0xF852, 0x9A56 }, + { 0xF853, 0x9A59 }, + { 0xF854, 0x9B1E }, + { 0xF855, 0x9B1F }, + { 0xF856, 0x9B20 }, + { 0xF857, 0x9C52 }, + { 0xF858, 0x9C58 }, + { 0xF859, 0x9C50 }, + { 0xF85A, 0x9C4A }, + { 0xF85B, 0x9C4D }, + { 0xF85C, 0x9C4B }, + { 0xF85D, 0x9C55 }, + { 0xF85E, 0x9C59 }, + { 0xF85F, 0x9C4C }, + { 0xF860, 0x9C4E }, + { 0xF861, 0x9DFB }, + { 0xF862, 0x9DF7 }, + { 0xF863, 0x9DEF }, + { 0xF864, 0x9DE3 }, + { 0xF865, 0x9DEB }, + { 0xF866, 0x9DF8 }, + { 0xF867, 0x9DE4 }, + { 0xF868, 0x9DF6 }, + { 0xF869, 0x9DE1 }, + { 0xF86A, 0x9DEE }, + { 0xF86B, 0x9DE6 }, + { 0xF86C, 0x9DF2 }, + { 0xF86D, 0x9DF0 }, + { 0xF86E, 0x9DE2 }, + { 0xF86F, 0x9DEC }, + { 0xF870, 0x9DF4 }, + { 0xF871, 0x9DF3 }, + { 0xF872, 0x9DE8 }, + { 0xF873, 0x9DED }, + { 0xF874, 0x9EC2 }, + { 0xF875, 0x9ED0 }, + { 0xF876, 0x9EF2 }, + { 0xF877, 0x9EF3 }, + { 0xF878, 0x9F06 }, + { 0xF879, 0x9F1C }, + { 0xF87A, 0x9F38 }, + { 0xF87B, 0x9F37 }, + { 0xF87C, 0x9F36 }, + { 0xF87D, 0x9F43 }, + { 0xF87E, 0x9F4F }, + { 0xF8A1, 0x9F71 }, + { 0xF8A2, 0x9F70 }, + { 0xF8A3, 0x9F6E }, + { 0xF8A4, 0x9F6F }, + { 0xF8A5, 0x56D3 }, + { 0xF8A6, 0x56CD }, + { 0xF8A7, 0x5B4E }, + { 0xF8A8, 0x5C6D }, + { 0xF8A9, 0x652D }, + { 0xF8AA, 0x66ED }, + { 0xF8AB, 0x66EE }, + { 0xF8AC, 0x6B13 }, + { 0xF8AD, 0x705F }, + { 0xF8AE, 0x7061 }, + { 0xF8AF, 0x705D }, + { 0xF8B0, 0x7060 }, + { 0xF8B1, 0x7223 }, + { 0xF8B2, 0x74DB }, + { 0xF8B3, 0x74E5 }, + { 0xF8B4, 0x77D5 }, + { 0xF8B5, 0x7938 }, + { 0xF8B6, 0x79B7 }, + { 0xF8B7, 0x79B6 }, + { 0xF8B8, 0x7C6A }, + { 0xF8B9, 0x7E97 }, + { 0xF8BA, 0x7F89 }, + { 0xF8BB, 0x826D }, + { 0xF8BC, 0x8643 }, + { 0xF8BD, 0x8838 }, + { 0xF8BE, 0x8837 }, + { 0xF8BF, 0x8835 }, + { 0xF8C0, 0x884B }, + { 0xF8C1, 0x8B94 }, + { 0xF8C2, 0x8B95 }, + { 0xF8C3, 0x8E9E }, + { 0xF8C4, 0x8E9F }, + { 0xF8C5, 0x8EA0 }, + { 0xF8C6, 0x8E9D }, + { 0xF8C7, 0x91BE }, + { 0xF8C8, 0x91BD }, + { 0xF8C9, 0x91C2 }, + { 0xF8CA, 0x946B }, + { 0xF8CB, 0x9468 }, + { 0xF8CC, 0x9469 }, + { 0xF8CD, 0x96E5 }, + { 0xF8CE, 0x9746 }, + { 0xF8CF, 0x9743 }, + { 0xF8D0, 0x9747 }, + { 0xF8D1, 0x97C7 }, + { 0xF8D2, 0x97E5 }, + { 0xF8D3, 0x9A5E }, + { 0xF8D4, 0x9AD5 }, + { 0xF8D5, 0x9B59 }, + { 0xF8D6, 0x9C63 }, + { 0xF8D7, 0x9C67 }, + { 0xF8D8, 0x9C66 }, + { 0xF8D9, 0x9C62 }, + { 0xF8DA, 0x9C5E }, + { 0xF8DB, 0x9C60 }, + { 0xF8DC, 0x9E02 }, + { 0xF8DD, 0x9DFE }, + { 0xF8DE, 0x9E07 }, + { 0xF8DF, 0x9E03 }, + { 0xF8E0, 0x9E06 }, + { 0xF8E1, 0x9E05 }, + { 0xF8E2, 0x9E00 }, + { 0xF8E3, 0x9E01 }, + { 0xF8E4, 0x9E09 }, + { 0xF8E5, 0x9DFF }, + { 0xF8E6, 0x9DFD }, + { 0xF8E7, 0x9E04 }, + { 0xF8E8, 0x9EA0 }, + { 0xF8E9, 0x9F1E }, + { 0xF8EA, 0x9F46 }, + { 0xF8EB, 0x9F74 }, + { 0xF8EC, 0x9F75 }, + { 0xF8ED, 0x9F76 }, + { 0xF8EE, 0x56D4 }, + { 0xF8EF, 0x652E }, + { 0xF8F0, 0x65B8 }, + { 0xF8F1, 0x6B18 }, + { 0xF8F2, 0x6B19 }, + { 0xF8F3, 0x6B17 }, + { 0xF8F4, 0x6B1A }, + { 0xF8F5, 0x7062 }, + { 0xF8F6, 0x7226 }, + { 0xF8F7, 0x72AA }, + { 0xF8F8, 0x77D8 }, + { 0xF8F9, 0x77D9 }, + { 0xF8FA, 0x7939 }, + { 0xF8FB, 0x7C69 }, + { 0xF8FC, 0x7C6B }, + { 0xF8FD, 0x7CF6 }, + { 0xF8FE, 0x7E9A }, + { 0xF940, 0x7E98 }, + { 0xF941, 0x7E9B }, + { 0xF942, 0x7E99 }, + { 0xF943, 0x81E0 }, + { 0xF944, 0x81E1 }, + { 0xF945, 0x8646 }, + { 0xF946, 0x8647 }, + { 0xF947, 0x8648 }, + { 0xF948, 0x8979 }, + { 0xF949, 0x897A }, + { 0xF94A, 0x897C }, + { 0xF94B, 0x897B }, + { 0xF94C, 0x89FF }, + { 0xF94D, 0x8B98 }, + { 0xF94E, 0x8B99 }, + { 0xF94F, 0x8EA5 }, + { 0xF950, 0x8EA4 }, + { 0xF951, 0x8EA3 }, + { 0xF952, 0x946E }, + { 0xF953, 0x946D }, + { 0xF954, 0x946F }, + { 0xF955, 0x9471 }, + { 0xF956, 0x9473 }, + { 0xF957, 0x9749 }, + { 0xF958, 0x9872 }, + { 0xF959, 0x995F }, + { 0xF95A, 0x9C68 }, + { 0xF95B, 0x9C6E }, + { 0xF95C, 0x9C6D }, + { 0xF95D, 0x9E0B }, + { 0xF95E, 0x9E0D }, + { 0xF95F, 0x9E10 }, + { 0xF960, 0x9E0F }, + { 0xF961, 0x9E12 }, + { 0xF962, 0x9E11 }, + { 0xF963, 0x9EA1 }, + { 0xF964, 0x9EF5 }, + { 0xF965, 0x9F09 }, + { 0xF966, 0x9F47 }, + { 0xF967, 0x9F78 }, + { 0xF968, 0x9F7B }, + { 0xF969, 0x9F7A }, + { 0xF96A, 0x9F79 }, + { 0xF96B, 0x571E }, + { 0xF96C, 0x7066 }, + { 0xF96D, 0x7C6F }, + { 0xF96E, 0x883C }, + { 0xF96F, 0x8DB2 }, + { 0xF970, 0x8EA6 }, + { 0xF971, 0x91C3 }, + { 0xF972, 0x9474 }, + { 0xF973, 0x9478 }, + { 0xF974, 0x9476 }, + { 0xF975, 0x9475 }, + { 0xF976, 0x9A60 }, + { 0xF977, 0x9C74 }, + { 0xF978, 0x9C73 }, + { 0xF979, 0x9C71 }, + { 0xF97A, 0x9C75 }, + { 0xF97B, 0x9E14 }, + { 0xF97C, 0x9E13 }, + { 0xF97D, 0x9EF6 }, + { 0xF97E, 0x9F0A }, + { 0xF9A1, 0x9FA4 }, + { 0xF9A2, 0x7068 }, + { 0xF9A3, 0x7065 }, + { 0xF9A4, 0x7CF7 }, + { 0xF9A5, 0x866A }, + { 0xF9A6, 0x883E }, + { 0xF9A7, 0x883D }, + { 0xF9A8, 0x883F }, + { 0xF9A9, 0x8B9E }, + { 0xF9AA, 0x8C9C }, + { 0xF9AB, 0x8EA9 }, + { 0xF9AC, 0x8EC9 }, + { 0xF9AD, 0x974B }, + { 0xF9AE, 0x9873 }, + { 0xF9AF, 0x9874 }, + { 0xF9B0, 0x98CC }, + { 0xF9B1, 0x9961 }, + { 0xF9B2, 0x99AB }, + { 0xF9B3, 0x9A64 }, + { 0xF9B4, 0x9A66 }, + { 0xF9B5, 0x9A67 }, + { 0xF9B6, 0x9B24 }, + { 0xF9B7, 0x9E15 }, + { 0xF9B8, 0x9E17 }, + { 0xF9B9, 0x9F48 }, + { 0xF9BA, 0x6207 }, + { 0xF9BB, 0x6B1E }, + { 0xF9BC, 0x7227 }, + { 0xF9BD, 0x864C }, + { 0xF9BE, 0x8EA8 }, + { 0xF9BF, 0x9482 }, + { 0xF9C0, 0x9480 }, + { 0xF9C1, 0x9481 }, + { 0xF9C2, 0x9A69 }, + { 0xF9C3, 0x9A68 }, + { 0xF9C4, 0x9B2E }, + { 0xF9C5, 0x9E19 }, + { 0xF9C6, 0x7229 }, + { 0xF9C7, 0x864B }, + { 0xF9C8, 0x8B9F }, + { 0xF9C9, 0x9483 }, + { 0xF9CA, 0x9C79 }, + { 0xF9CB, 0x9EB7 }, + { 0xF9CC, 0x7675 }, + { 0xF9CD, 0x9A6B }, + { 0xF9CE, 0x9C7A }, + { 0xF9CF, 0x9E1D }, + { 0xF9D0, 0x7069 }, + { 0xF9D1, 0x706A }, + { 0xF9D2, 0x9EA4 }, + { 0xF9D3, 0x9F7E }, + { 0xF9D4, 0x9F49 }, + { 0xF9D5, 0x9F98 }, +}; diff --git a/src/localisation/currency.c b/src/localisation/currency.c index 7ef56e22f1..1dbd267e8b 100644 --- a/src/localisation/currency.c +++ b/src/localisation/currency.c @@ -19,16 +19,20 @@ *****************************************************************************/ #include "currency.h" +#include "string_ids.h" -const rct_currency_spec g_currency_specs[CURRENCY_END] = { - { 10 , "\xA3" , CURRENCY_PREFIX }, // British Pound - { 10 , "\x24" , CURRENCY_PREFIX }, // US Dollar - { 10 , "F" , CURRENCY_SUFFIX }, // French Franc - { 10 , "DM" , CURRENCY_PREFIX }, // Deutsche Mark - { 1000 , "\xA5" , CURRENCY_PREFIX }, // Japanese Yen - { 10 , "Pts" , CURRENCY_SUFFIX }, // Spanish Peseta - { 1000 , "L" , CURRENCY_PREFIX }, // Italian Lira - { 10 , "fl." , CURRENCY_PREFIX }, // Dutch Guilder - { 10 , "kr." , CURRENCY_SUFFIX }, // Swedish Krona - { 10 , "\xb5" , CURRENCY_PREFIX }, // Euro +const currency_descriptor CurrencyDescriptors[CURRENCY_END] = { + { 10 , CURRENCY_PREFIX, "\xC2\xA3" , CURRENCY_SUFFIX, "GBP" , STR_POUNDS }, // British Pound + { 10 , CURRENCY_PREFIX, "$" , CURRENCY_PREFIX, "$" , STR_DOLLARS }, // US Dollar + { 10 , CURRENCY_SUFFIX, "F" , CURRENCY_SUFFIX, "F" , STR_FRANC }, // French Franc + { 10 , CURRENCY_PREFIX, "DM" , CURRENCY_PREFIX, "DM" , STR_DEUTSCHMARK }, // Deutschmark + { 1000 , CURRENCY_PREFIX, "\xC2\xA5" , CURRENCY_SUFFIX, "YEN" , STR_YEN }, // Japanese Yen + { 10 , CURRENCY_SUFFIX, "Pts" , CURRENCY_SUFFIX, "Pts" , STR_PESETA }, // Spanish Peseta + { 1000 , CURRENCY_PREFIX, "L" , CURRENCY_PREFIX, "L" , STR_LIRA }, // Italian Lira + { 10 , CURRENCY_PREFIX, "\xC6\x92" , CURRENCY_PREFIX, "fl." , STR_GUILDERS }, // Dutch Guilder + { 10 , CURRENCY_SUFFIX, "kr." , CURRENCY_SUFFIX, "kr." , STR_KRONA }, // Swedish Krona + { 10 , CURRENCY_PREFIX, "\xE2\x82\xAC" , CURRENCY_SUFFIX, "EUR" , STR_EUROS }, // Euro + { 10000 , CURRENCY_PREFIX, "\xE2\x82\xA9" , CURRENCY_PREFIX, "W" , STR_WON }, // South Korean Won + { 1000 , CURRENCY_PREFIX, "R " , CURRENCY_PREFIX, "R " , STR_ROUBLE }, // Russian Rouble + { 100 , CURRENCY_SUFFIX, " K\xC4\x8D" , CURRENCY_SUFFIX, " Kc" , STR_CZECH_KORUNA }, // Czech koruna }; diff --git a/src/localisation/currency.h b/src/localisation/currency.h index 69b40556aa..ffa400828b 100644 --- a/src/localisation/currency.h +++ b/src/localisation/currency.h @@ -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,6 +21,8 @@ #ifndef CURRENCY_H #define CURRENCY_H +#include "../common.h" + // List of currencies typedef enum { CURRENCY_POUNDS, // British Pound @@ -33,7 +35,10 @@ typedef enum { CURRENCY_GUILDERS, // Dutch Gilder CURRENCY_KRONA, // Swedish Krona CURRENCY_EUROS, // Euro - + CURRENCY_WON, // South Korean Won + CURRENCY_ROUBLE, // Russian Rouble + CURRENCY_CZECH_KORUNA, // Czech koruna + CURRENCY_END // Last item } CURRENCY_TYPE; @@ -42,15 +47,20 @@ typedef enum { CURRENCY_SUFFIX } CURRENCY_AFFIX; +#define CURRENCY_SYMBOL_MAX_SIZE 8 + // Currency format specification - inspired by OpenTTD typedef struct { - // Rate is relative to 0.1 GBP + // Rate is relative to 0.10 GBP int rate; - char symbol[8]; - int affix; -} rct_currency_spec; + uint8 affix_unicode; + utf8 symbol_unicode[CURRENCY_SYMBOL_MAX_SIZE]; + uint8 affix_ascii; + char symbol_ascii[CURRENCY_SYMBOL_MAX_SIZE]; + rct_string_id stringId; +} currency_descriptor; // List of currency formats -extern const rct_currency_spec g_currency_specs[CURRENCY_END]; +extern const currency_descriptor CurrencyDescriptors[CURRENCY_END]; #endif diff --git a/src/localisation/date.c b/src/localisation/date.c index 8312f5d798..50a754bce2 100644 --- a/src/localisation/date.c +++ b/src/localisation/date.c @@ -8,22 +8,36 @@ * 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 "date.h" +#include "string_ids.h" // rct2: 0x00993988 const sint16 days_in_month[MONTH_COUNT] = { 31, 30, 31, 30, 31, 31, 30, 31 }; +const rct_string_id DateFormatStringIds[] = { + STR_DATE_FORMAT_DAY_MONTH_YEAR, + STR_DATE_FORMAT_MONTH_DAY_YEAR, + STR_DATE_FORMAT_YEAR_MONTH_DAY, + STR_DATE_FORMAT_YEAR_DAY_MONTH +}; + +const rct_string_id DateFormatStringFormatIds[] = { + STR_DATE_FORMAT_DMY, + STR_DATE_FORMAT_MDY, + STR_DATE_FORMAT_YMD, + STR_DATE_FORMAT_YDM +}; int date_get_month(int months) { @@ -48,5 +62,5 @@ void date_reset() { RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16) = MONTH_MARCH; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, sint16) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, sint32) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) = 0; } diff --git a/src/localisation/date.h b/src/localisation/date.h index 94d0f3af4c..6ae0b112e8 100644 --- a/src/localisation/date.h +++ b/src/localisation/date.h @@ -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 . *****************************************************************************/ @@ -36,7 +36,16 @@ enum { MONTH_COUNT }; +enum { + DATE_FORMAT_DAY_MONTH_YEAR, + DATE_FORMAT_MONTH_DAY_YEAR, + DATE_FORMAT_YEAR_MONTH_DAY, + DATE_FORMAT_YEAR_DAY_MONTH +}; + extern const sint16 days_in_month[MONTH_COUNT]; +extern const rct_string_id DateFormatStringIds[]; +extern const rct_string_id DateFormatStringFormatIds[]; int date_get_month(int months); int date_get_year(int months); diff --git a/src/localisation/format_codes.h b/src/localisation/format_codes.h index c0931c0b4b..4f312be760 100644 --- a/src/localisation/format_codes.h +++ b/src/localisation/format_codes.h @@ -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,8 +21,8 @@ #ifndef _FORMAT_CODES_H_ #define _FORMAT_CODES_H_ -char format_get_code(const char *token); -const char *format_get_token(char code); +uint32 format_get_code(const char *token); +const char *format_get_token(uint32 code); enum { // Font format codes @@ -56,9 +56,6 @@ enum { // The next 4 bytes specify the sprite FORMAT_INLINE_SPRITE = 23, - // Non ascii-characters - FORMAT_ENDQUOTES = 34, - // Argument format codes FORMAT_ARGUMENT_CODE_START = 123, FORMAT_COMMA32 = 123, @@ -80,6 +77,7 @@ enum { FORMAT_REALTIME, FORMAT_LENGTH, FORMAT_SPRITE, + FORMAT_ARGUMENT_CODE_END = FORMAT_SPRITE, // Colour format codes FORMAT_COLOUR_CODE_START = 142, @@ -101,27 +99,41 @@ enum { // Extra non-ascii characters FORMAT_AMINUSCULE = 159, - FORMAT_UP, + FORMAT_CENT = 162, FORMAT_POUND = 163, FORMAT_YEN = 165, FORMAT_COPYRIGHT = 169, - FORMAT_DOWN, - FORMAT_LEFTGUILLEMET, - FORMAT_TICK, - FORMAT_CROSS, - FORMAT_RIGHT = 175, - FORMAT_DEGREE, + FORMAT_LEFTGUILLEMET = 171, + FORMAT_DEGREE = 176, FORMAT_SQUARED = 178, - FORMAT_OPENQUOTES = 180, - FORMAT_EURO = 181, - FORMAT_APPROX = 184, - FORMAT_POWERNEGATIVEONE, - FORMAT_BULLET, - FORMAT_RIGHTGUILLEMET, - FORMAT_SMALLUP, - FORMAT_SMALLDOWN, - FORMAT_LEFT, - FORMAT_INVERTEDQUESTION + FORMAT_RIGHTGUILLEMET = 187, + FORMAT_INVERTEDQUESTION = 191, + + FORMAT_OPENQUOTES = 8220, + FORMAT_ENDQUOTES = 8221, + + FORMAT_BULLET = 8226, + FORMAT_POWERNEGATIVEONE = 8315, + FORMAT_EURO = 8364, + + FORMAT_APPROX = 8776, + + FORMAT_UP = 9650, + FORMAT_RIGHT = 9654, + FORMAT_DOWN = 9660, + FORMAT_LEFT = 9664, + + FORMAT_SMALLUP = 9652, + FORMAT_SMALLDOWN = 9662, + + FORMAT_TICK = 10003, + FORMAT_CROSS = 10005, + + // Format codes that need suitable unicode allocations + FORMAT_SYMBOL_i = 20000, + FORMAT_SYMBOL_RAILWAY = 20001, + FORMAT_SYMBOL_ROAD = 20002, + FORMAT_SYMBOL_FLAG = 20003, }; -#endif \ No newline at end of file +#endif diff --git a/src/localisation/language.c b/src/localisation/language.c deleted file mode 100644 index 5d4e1b17d1..0000000000 --- a/src/localisation/language.c +++ /dev/null @@ -1,349 +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 "../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 - "English (UK)", // LANGUAGE_ENGLISH_UK - "English (US)", // LANGUAGE_ENGLISH_US - "Deutsch", // LANGUAGE_GERMAN - "Nederlands", // LANGUAGE_DUTCH - "Fran\u00E7ais", // LANGUAGE_FRENCH - "Magyar", // LANGUAGE_HUNGARIAN - "Polski", // LANGUAGE_POLISH - "Espa\u00F1ol", // LANGUAGE_SPANISH - "Svenska", // LANGUAGE_SWEDISH - "Italiano" // LANGUAGE_ITALIAN -}; - -const char *language_filenames[LANGUAGE_COUNT] = { - "", // LANGUAGE_UNDEFINED - "english_uk", // LANGUAGE_ENGLISH_UK - "english_us", // LANGUAGE_ENGLISH_US - "german", // LANGUAGE_GERMAN - "dutch", // LANGUAGE_DUTCH - "french", // LANGUAGE_FRENCH - "hungarian", // LANGUAGE_HUNGARIAN - "polish", // LANGUAGE_POLISH - "spanish_sp", // LANGUAGE_SPANISH - "swedish", // LANGUAGE_SWEDISH - "italian" // LANGUAGE_ITALIAN -}; - -int gCurrentLanguage = LANGUAGE_UNDEFINED; - -language_data _languageFallback = { 0 }; -language_data _languageCurrent = { 0 }; - -const char **_languageOriginal = (char**)0x009BF2D4; - -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) -{ - int result; - int numBytes; - - if (!(char_ptr[0] & 0x80)) { - result = char_ptr[0]; - numBytes = 1; - } 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) - *nextchar_ptr = char_ptr + numBytes; - return result; -} - -const char *language_get_string(rct_string_id id) -{ - 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) -{ - static const char *languagePath = "%s/data/language/%s.txt"; - char filename[MAX_PATH]; - - language_close_all(); - if (id == LANGUAGE_UNDEFINED) - return 1; - - 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; - } - - 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, - * get_string will use those if the same entry in the loaded language is empty. - * - * Unsure at how the original game decides which entries to write resource strings to, but this could affect adding new - * strings for the time being. Further investigation is required. - * - * Also note that all strings are currently still ASCII. It probably can't be converted to UTF-8 until all game functions that - * read / write strings in some way is decompiled. The original game used a DIY extended 8-bit extended ASCII set for special - * characters, format codes and accents. - * - * In terms of reading the language files, the 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. 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, 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->string_data_size = ftell(f) + 1; - language->string_data = calloc(1, language->string_data_size); - fseek(f, 0, SEEK_SET); - fread(language->string_data, language->string_data_size, 1, f); - fclose(f); - - language->strings = calloc(STR_COUNT, sizeof(char*)); - - char *dst = NULL; - char *token = NULL; - char tokenBuffer[64]; - 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; - int utf8Char = utf8_get_next(src, &srcNext); - i += srcNext - src - 1; - if (utf8Char > 0xFF) - utf8Char = '?'; - else if (utf8Char > 0x7F) - utf8Char &= 0xFF; - - switch (mode) { - case 0: - // Search for a comment - if (utf8Char == '#') { - mode = 3; - } else if (utf8Char == ':' && stringId != -1) { - // Search for colon - dst = src + 1; - 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", &stringId) != 1) { - stringId = -1; - } else { - maxStringId = max(maxStringId, stringId); - } - } - break; - case 1: - // Copy string over, stop at line break - if (utf8Char == '{') { - token = src + 1; - mode = 2; - } else if (utf8Char == '\n' || *src == '\r') { - *dst = 0; - mode = 0; - } else { - *dst++ = utf8Char; - } - break; - case 2: - // Read token, convert to code - if (utf8Char == '}') { - int tokenLength = min(src - token, sizeof(tokenBuffer) - 1); - memcpy(tokenBuffer, token, tokenLength); - tokenBuffer[tokenLength] = 0; - char code = format_get_code(tokenBuffer); - if (code == 0) - code = atoi(tokenBuffer); - *dst++ = code; - mode = 1; - } - break; - case 3: - if (utf8Char == '\n' || utf8Char == '\r') { - mode = 0; - } - } - } - language->num_strings = maxStringId + 1; - language->strings = realloc(language->strings, language->num_strings * sizeof(char*)); - - return 1; -} - -static void language_close(language_data *language) -{ - 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.cpp b/src/localisation/language.cpp new file mode 100644 index 0000000000..7e22900aa5 --- /dev/null +++ b/src/localisation/language.cpp @@ -0,0 +1,413 @@ +/***************************************************************************** + * 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 "LanguagePack.h" + +extern "C" { + +#include "../addresses.h" +#include "../drawing/drawing.h" +#include "../object.h" +#include "../openrct2.h" +#include "../util/util.h" +#include "localisation.h" + +enum { + RCT2_LANGUAGE_ID_ENGLISH_UK, + RCT2_LANGUAGE_ID_ENGLISH_US, + RCT2_LANGUAGE_ID_FRENCH, + RCT2_LANGUAGE_ID_GERMAN, + RCT2_LANGUAGE_ID_SPANISH, + RCT2_LANGUAGE_ID_ITALIAN, + RCT2_LANGUAGE_ID_DUTCH, + RCT2_LANGUAGE_ID_SWEDISH, + RCT2_LANGUAGE_ID_8, + RCT2_LANGUAGE_ID_KOREAN, + RCT2_LANGUAGE_ID_CHINESE_SIMPLIFIED, + RCT2_LANGUAGE_ID_CHINESE_TRADITIONAL, + RCT2_LANGUAGE_ID_12, + RCT2_LANGUAGE_ID_PORTUGUESE, + RCT2_LANGUAGE_ID_END = 255 +}; + +static TTFFontSetDescriptor TTFFontMingLiu = {{ + { "msjh.ttc", 9, -1, -3, 6, nullptr }, + { "mingliu.ttc", 11, 1, 1, 12, nullptr }, + { "mingliu.ttc", 12, 1, 0, 12, nullptr }, + { "mingliu.ttc", 13, 1, 0, 20, nullptr }, +}}; + +static TTFFontSetDescriptor TTFFontSimSun = {{ + { "msyh.ttc", 9, -1, -3, 6, nullptr }, + { "simsun.ttc", 11, 1, -1, 14, nullptr }, + { "simsun.ttc", 12, 1, -2, 14, nullptr }, + { "simsun.ttc", 13, 1, 0, 20, nullptr }, +}}; + +static TTFFontSetDescriptor TTFFontGulim = {{ + { "gulim.ttc", 11, 1, 0, 15, nullptr }, + { "gulim.ttc", 12, 1, 0, 17, nullptr }, + { "gulim.ttc", 12, 1, 0, 17, nullptr }, + { "gulim.ttc", 13, 1, 0, 20, nullptr }, +}}; + +static TTFFontSetDescriptor TTFFontArial = {{ + { "arial.ttf", 8, 0, -1, 6, nullptr }, + { "arial.ttf", 10, 0, -1, 12, nullptr }, + { "arial.ttf", 11, 0, -1, 12, nullptr }, + { "arial.ttf", 12, 0, -1, 20, nullptr }, +}}; + +const language_descriptor LanguagesDescriptors[LANGUAGE_COUNT] = { + { "", "", "", "", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_UNDEFINED + { "en-GB", "English (UK)", "English (UK)", "english_uk", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_ENGLISH_UK + { "en-US", "English (US)", "English (US)", "english_us", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_US }, // LANGUAGE_ENGLISH_US + { "de-DE", "German", "Deutsch", "german", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_GERMAN }, // LANGUAGE_GERMAN + { "nl-NL", "Dutch", "Nederlands", "dutch", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_DUTCH }, // LANGUAGE_DUTCH + { "fr-FR", "French", "Fran\xC3\xA7" "ais", "french", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_FRENCH }, // LANGUAGE_FRENCH + { "hu-HU", "Hungarian", "Magyar", "hungarian", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_HUNGARIAN + { "pl-PL", "Polish", "Polski", "polish", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_POLISH + { "es-ES", "Spanish", "Espa\xC3\xB1ol", "spanish_sp", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_SPANISH }, // LANGUAGE_SPANISH + { "sv-SE", "Swedish", "Svenska", "swedish", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_SWEDISH }, // LANGUAGE_SWEDISH + { "it-IT", "Italian", "Italiano", "italian", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ITALIAN }, // LANGUAGE_ITALIAN + { "pt-BR", "Portuguese (BR)", "Portugu\xC3\xAAs (BR)", "portuguese_br", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_PORTUGUESE }, // LANGUAGE_PORTUGUESE_BR + { "zh-Hant", "Chinese (Traditional)", "Chinese (Traditional)", "chinese_traditional", &TTFFontMingLiu, RCT2_LANGUAGE_ID_CHINESE_TRADITIONAL }, // LANGUAGE_CHINESE_TRADITIONAL + { "zh-Hans", "Chinese (Simplified)", "Chinese (Simplified)", "chinese_simplified", &TTFFontSimSun, RCT2_LANGUAGE_ID_CHINESE_SIMPLIFIED }, // LANGUAGE_CHINESE_SIMPLIFIED + { "fi-FI", "Finnish", "Suomi", "finnish", FONT_OPENRCT2_SPRITE, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_FINNISH + { "ko", "Korean", "Korean", "korean", &TTFFontGulim, RCT2_LANGUAGE_ID_KOREAN }, // LANGUAGE_KOREAN + { "ru-RU", "Russian", "Russian", "russian", &TTFFontArial, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_RUSSIAN + { "cz-CZ", "Czech", "Czech", "czech", &TTFFontArial, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_CZECH +}; + +int gCurrentLanguage = LANGUAGE_UNDEFINED; +bool gUseTrueTypeFont = false; + +LanguagePack *_languageFallback = nullptr; +LanguagePack *_languageCurrent = nullptr; + +const char **_languageOriginal = (const char**)0x009BF2D4; + +const utf8 BlackUpArrowString[] = { (utf8)0xC2, (utf8)0x8E, (utf8)0xE2, (utf8)0x96, (utf8)0xB2, (utf8)0x00 }; +const utf8 BlackDownArrowString[] = { (utf8)0xC2, (utf8)0x8E, (utf8)0xE2, (utf8)0x96, (utf8)0xBC, (utf8)0x00 }; +const utf8 BlackLeftArrowString[] = { (utf8)0xC2, (utf8)0x8E, (utf8)0xE2, (utf8)0x97, (utf8)0x80, (utf8)0x00 }; +const utf8 BlackRightArrowString[] = { (utf8)0xC2, (utf8)0x8E, (utf8)0xE2, (utf8)0x96, (utf8)0xB6, (utf8)0x00 }; +const utf8 CheckBoxMarkString[] = { (utf8)0xE2, (utf8)0x9C, (utf8)0x93, (utf8)0x00 }; + +void utf8_remove_format_codes(utf8 *text) +{ + utf8 *dstCh = text; + utf8 *ch = text; + int codepoint; + while ((codepoint = utf8_get_next(ch, (const utf8**)&ch)) != 0) { + if (!utf8_is_format_code(codepoint)) { + dstCh = utf8_write_codepoint(dstCh, codepoint); + } + } + *dstCh = 0; +} + +const char *language_get_string(rct_string_id id) +{ + const char *openrctString = nullptr; + + if (id == (rct_string_id)STR_NONE) + return nullptr; + + if (_languageCurrent != nullptr) + openrctString = _languageCurrent->GetString(id); + if (openrctString == nullptr && _languageFallback != nullptr) + openrctString = _languageFallback->GetString(id); + + if (id >= STR_OPENRCT2_BEGIN_STRING_ID) { + return openrctString != nullptr ? openrctString : "(undefined string)"; + } else { + const char *rct = _languageOriginal[id]; + const char *str = (openrctString == nullptr || strlen(openrctString) == 0 ? rct : openrctString); + return str == nullptr ? "" : str; + } +} + +int language_open(int id) +{ + static const char *languagePath = "%s/data/language/%s.txt"; + char filename[MAX_PATH]; + + language_close_all(); + if (id == LANGUAGE_UNDEFINED) + return 1; + + if (id != LANGUAGE_ENGLISH_UK) { + sprintf(filename, languagePath, gExePath, LanguagesDescriptors[LANGUAGE_ENGLISH_UK].path); + _languageFallback = LanguagePack::FromFile(LANGUAGE_ENGLISH_UK, filename); + } + + sprintf(filename, languagePath, gExePath, LanguagesDescriptors[id].path); + _languageCurrent = LanguagePack::FromFile(id, filename); + if (_languageCurrent != nullptr) { + gCurrentLanguage = id; + + if (LanguagesDescriptors[id].font == FONT_OPENRCT2_SPRITE) { + ttf_dispose(); + gUseTrueTypeFont = false; + gCurrentTTFFontSet = nullptr; + } else { + ttf_dispose(); + gUseTrueTypeFont = true; + gCurrentTTFFontSet = LanguagesDescriptors[id].font; + if (!ttf_initialise()) { + log_warning("Unable to initialise TrueType fonts."); + + // Fall back to sprite font + gUseTrueTypeFont = false; + gCurrentTTFFontSet = nullptr; + return 0; + } + } + + return 1; + } + + return 0; +} + +void language_close_all() +{ + SafeDelete(_languageFallback); + SafeDelete(_languageCurrent); + gCurrentLanguage = LANGUAGE_UNDEFINED; +} + +#define STEX_BASE_STRING_ID 3447 +#define NONSTEX_BASE_STRING_ID 3463 +#define MAX_OBJECT_CACHED_STRINGS 2048 + +/* rct2: 0x0098DA16 */ +uint16 ObjectTypeStringTableCount[] = { 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 }; + +utf8 *_cachedObjectStrings[MAX_OBJECT_CACHED_STRINGS] = { nullptr }; + +void utf8_trim_string(utf8 *text) +{ + utf8 *src = text; + utf8 *dst = text; + utf8 *last = text; + int codepoint; + + // Trim left + while ((codepoint = utf8_get_next(src, (const utf8**)&src)) != 0) { + if (codepoint != ' ') { + dst = utf8_write_codepoint(dst, codepoint); + last = dst; + break; + } + } + if (codepoint != 0) { + // Trim right + while ((codepoint = utf8_get_next(src, (const utf8**)&src)) != 0) { + dst = utf8_write_codepoint(dst, codepoint); + if (codepoint != ' ') { + last = dst; + } + } + } + *last = 0; +} + +static wchar_t convert_specific_language_character_to_unicode(int languageId, wchar_t codepoint) +{ + switch (languageId) { + case RCT2_LANGUAGE_ID_KOREAN: + return codepoint; + case RCT2_LANGUAGE_ID_CHINESE_TRADITIONAL: + return encoding_convert_big5_to_unicode(codepoint); + case RCT2_LANGUAGE_ID_CHINESE_SIMPLIFIED: + return encoding_convert_gb2312_to_unicode(codepoint); + default: + return codepoint; + } +} + +static utf8 *convert_multibyte_charset(const char *src, int languageId) +{ + int reservedLength = (strlen(src) * 4) + 1; + utf8 *buffer = (utf8*)malloc(reservedLength); + utf8 *dst = buffer; + for (const uint8 *ch = (const uint8*)src; *ch != 0;) { + if (*ch == 0xFF) { + ch++; + uint8 a = *ch++; + uint8 b = *ch++; + uint16 codepoint = (a << 8) | b; + + codepoint = convert_specific_language_character_to_unicode(languageId, codepoint); + dst = utf8_write_codepoint(dst, codepoint); + } else { + dst = utf8_write_codepoint(dst, *ch++); + } + } + *dst++ = 0; + int actualLength = dst - buffer; + buffer = (utf8*)realloc(buffer, actualLength); + + return buffer; +} + +static bool rct2_language_is_multibyte_charset(int languageId) +{ + switch (languageId) { + case RCT2_LANGUAGE_ID_KOREAN: + case RCT2_LANGUAGE_ID_CHINESE_TRADITIONAL: + case RCT2_LANGUAGE_ID_CHINESE_SIMPLIFIED: + return true; + default: + return false; + } +} + +/* rct2: 0x006A9E24*/ +rct_string_id object_get_localised_text(uint8_t** pStringTable/*ebp*/, int type/*ecx*/, int index/*ebx*/, int tableindex/*edx*/) +{ + uint8 languageId, chosenLanguageId; + char *pString = nullptr; + int result = 0; + bool isBlank; + + while ((languageId = *(*pStringTable)++) != RCT2_LANGUAGE_ID_END) { + isBlank = true; + + // Strings that are just ' ' are set as invalid langauges. + // But if there is no real string then it will set the string as + // the blank string + for (char *ch = (char*)(*pStringTable); *ch != 0; ch++) { + if (!isblank(*ch)) { + isBlank = false; + break; + } + } + + if (isBlank) languageId = 0xFE; + + // This is the ideal situation. Language found + if (languageId == LanguagesDescriptors[gCurrentLanguage].rct2_original_id) { + chosenLanguageId = languageId; + pString = (char*)(*pStringTable); + result |= 1; + } + + // Just in case always load english into pString + if (languageId == RCT2_LANGUAGE_ID_ENGLISH_UK && !(result & 1)) { + chosenLanguageId = languageId; + pString = (char*)(*pStringTable); + result |= 2; + } + + // Failing that fall back to whatever is first string + if (!(result & 7)) { + chosenLanguageId = languageId; + pString = (char*)(*pStringTable); + if (!isBlank) result |= 4; + } + + // Skip over the actual string entry to get to the next entry + while (*(*pStringTable)++ != 0); + } + + char name[9]; + if (RCT2_GLOBAL(0x009ADAFC, uint8) == 0) { + memcpy(name, object_entry_groups[type].entries[index].name, 8); + } else { + memcpy(name, gTempObjectLoadName, 8); + } + name[8] = 0; + + rct_string_id stringId = _languageCurrent->GetObjectOverrideStringId(name, tableindex); + if (stringId != (rct_string_id)STR_NONE) { + return stringId; + } + + // If not scenario text + if (RCT2_GLOBAL(0x009ADAFC, uint8) == 0) { + int stringid = NONSTEX_BASE_STRING_ID; + 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; + + // cache UTF-8 string + int cacheStringOffset = stringid - STEX_BASE_STRING_ID; + utf8 **cacheString = &_cachedObjectStrings[cacheStringOffset]; + if (*cacheString != nullptr) { + free(*cacheString); + } + if (rct2_language_is_multibyte_charset(chosenLanguageId)) { + *cacheString = convert_multibyte_charset(pString, chosenLanguageId); + } else { + *cacheString = win1252_to_utf8_alloc(pString); + } + utf8_trim_string(*cacheString); + + //put pointer in stringtable + _languageCurrent->SetString(stringid, *cacheString); + // Until all string related functions are finished copy + // to old array as well. + _languageOriginal[stringid] = *cacheString; + return stringid; + } else { + int stringid = STEX_BASE_STRING_ID + tableindex; + + // cache UTF-8 string + int cacheStringOffset = stringid - STEX_BASE_STRING_ID; + utf8 **cacheString = &_cachedObjectStrings[cacheStringOffset]; + if (*cacheString != nullptr) { + free(*cacheString); + } + if (rct2_language_is_multibyte_charset(chosenLanguageId)) { + *cacheString = convert_multibyte_charset(pString, chosenLanguageId); + } else { + *cacheString = win1252_to_utf8_alloc(pString); + } + utf8_trim_string(*cacheString); + + //put pointer in stringtable + _languageCurrent->SetString(stringid, *cacheString); + // Until all string related functions are finished copy + // to old array as well. + _languageOriginal[stringid] = *cacheString; + return stringid; + } +} + +bool language_get_localised_scenario_strings(const utf8 *scenarioFilename, rct_string_id *outStringIds) +{ + outStringIds[0] = _languageCurrent->GetScenarioOverrideStringId(scenarioFilename, 0); + outStringIds[1] = _languageCurrent->GetScenarioOverrideStringId(scenarioFilename, 1); + outStringIds[2] = _languageCurrent->GetScenarioOverrideStringId(scenarioFilename, 2); + return + outStringIds[0] != (rct_string_id)STR_NONE || + outStringIds[1] != (rct_string_id)STR_NONE || + outStringIds[2] != (rct_string_id)STR_NONE; +} + +} diff --git a/src/localisation/language.h b/src/localisation/language.h index c86906f773..3adf76de0f 100644 --- a/src/localisation/language.h +++ b/src/localisation/language.h @@ -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,7 @@ #define _LANGUAGE_H_ #include "../common.h" +#include "../drawing/font.h" enum { LANGUAGE_UNDEFINED, @@ -35,11 +36,37 @@ enum { LANGUAGE_SPANISH, LANGUAGE_SWEDISH, LANGUAGE_ITALIAN, + LANGUAGE_PORTUGUESE_BR, + LANGUAGE_CHINESE_TRADITIONAL, + LANGUAGE_CHINESE_SIMPLIFIED, + LANGUAGE_FINNISH, + LANGUAGE_KOREAN, + LANGUAGE_RUSSIAN, + LANGUAGE_CZECH, LANGUAGE_COUNT }; -extern const char *language_names[LANGUAGE_COUNT]; +#define FONT_OPENRCT2_SPRITE NULL + +typedef struct { + const char *locale; + const utf8 *english_name; + const utf8 *native_name; + const utf8 *path; + TTFFontSetDescriptor *font; + uint8 rct2_original_id; +} language_descriptor; + +extern const language_descriptor LanguagesDescriptors[LANGUAGE_COUNT]; + extern int gCurrentLanguage; +extern bool gUseTrueTypeFont; + +extern const utf8 BlackUpArrowString[]; +extern const utf8 BlackDownArrowString[]; +extern const utf8 BlackLeftArrowString[]; +extern const utf8 BlackRightArrowString[]; +extern const utf8 CheckBoxMarkString[]; const char *language_get_string(rct_string_id id); int language_open(int id); @@ -47,4 +74,16 @@ void language_close_all(); rct_string_id object_get_localised_text(uint8_t** pStringTable/*ebp*/, int type/*ecx*/, int index/*ebx*/, int tableindex/*edx*/); +uint32 utf8_get_next(const utf8 *char_ptr, const utf8 **nextchar_ptr); +utf8 *utf8_write_codepoint(utf8 *dst, uint32 codepoint); +int utf8_insert_codepoint(utf8 *dst, uint32 codepoint); +bool utf8_is_codepoint_start(utf8 *text); +void utf8_remove_format_codes(utf8 *text); +int utf8_get_codepoint_length(int codepoint); +int utf8_length(const utf8 *text); +wchar_t *utf8_to_widechar(const utf8 *src); +utf8 *widechar_to_utf8(const wchar_t *src); + +bool language_get_localised_scenario_strings(const utf8 *scenarioFilename, rct_string_id *outStringIds); + #endif diff --git a/src/localisation/localisation.c b/src/localisation/localisation.c index 01cb13e66c..237f22f36c 100644 --- a/src/localisation/localisation.c +++ b/src/localisation/localisation.c @@ -8,17 +8,22 @@ * 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 . *****************************************************************************/ +#ifdef _WIN32 #include +#else +#include +#include +#endif // _WIN32 #include "../addresses.h" #include "../config.h" #include "../game.h" @@ -29,8 +34,8 @@ #pragma region Format codes typedef struct { - char code; - char *token; + uint32 code; + const char *token; } format_code_token; format_code_token format_code_tokens[] = { @@ -107,7 +112,7 @@ format_code_token format_code_tokens[] = { { FORMAT_INVERTEDQUESTION, "INVERTEDQUESTION" } }; -char format_get_code(const char *token) +uint32 format_get_code(const char *token) { int i; for (i = 0; i < countof(format_code_tokens); i++) @@ -116,7 +121,7 @@ char format_get_code(const char *token) return 0; } -const char *format_get_token(char code) +const char *format_get_token(uint32 code) { int i; for (i = 0; i < countof(format_code_tokens); i++) @@ -125,6 +130,52 @@ const char *format_get_token(char code) return 0; } +bool utf8_is_format_code(int codepoint) +{ + if (codepoint < 32) return true; + if (codepoint >= FORMAT_ARGUMENT_CODE_START && codepoint <= FORMAT_ARGUMENT_CODE_END) return true; + if (codepoint >= FORMAT_COLOUR_CODE_START && codepoint <= FORMAT_COLOUR_CODE_END) return true; + return false; +} + +bool utf8_should_use_sprite_for_codepoint(int codepoint) +{ + switch (codepoint) { + case FORMAT_UP: + case FORMAT_DOWN: + case FORMAT_LEFTGUILLEMET: + case FORMAT_TICK: + case FORMAT_CROSS: + case FORMAT_RIGHT: + case FORMAT_RIGHTGUILLEMET: + case FORMAT_SMALLUP: + case FORMAT_SMALLDOWN: + case FORMAT_LEFT: + case FORMAT_OPENQUOTES: + case FORMAT_ENDQUOTES: + return true; + default: + return false; + } +} + +int utf8_get_format_code_arg_length(int codepoint) +{ + switch (codepoint) { + case FORMAT_MOVE_X: + case FORMAT_ADJUST_PALETTE: + case 3: + case 4: + return 1; + case FORMAT_NEWLINE_X_Y: + return 2; + case FORMAT_INLINE_SPRITE: + return 4; + default: + return 0; + } +} + #pragma endregion void format_string_part_from_raw(char **dest, const char *src, char **args); @@ -193,10 +244,10 @@ void format_comma_separated_integer(char **dest, long long value) // Groups of three digits, right to left groupIndex = 0; while (value > 0) { - // Append group seperator + // Append group separator if (groupIndex == 3) { groupIndex = 0; - + ch = commaMark; while (*ch != 0) { *dst++ = *ch++; @@ -261,10 +312,10 @@ void format_comma_separated_fixed_2dp(char **dest, long long value) // Groups of three digits, right to left groupIndex = 0; while (value > 0) { - // Append group seperator + // Append group separator if (groupIndex == 3) { groupIndex = 0; - + ch = commaMark; while (*ch != 0) { *dst++ = *ch++; @@ -294,9 +345,9 @@ 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[gConfigGeneral.currency_format]; + const currency_descriptor *currencyDesc = &CurrencyDescriptors[gConfigGeneral.currency_format]; - int rate = currencySpec->rate; + int rate = currencyDesc->rate; value *= rate; // Negative sign @@ -312,28 +363,33 @@ void format_currency(char **dest, long long value) } // Currency symbol - const char *symbol = currencySpec->symbol; + const utf8 *symbol = currencyDesc->symbol_unicode; + uint8 affix = currencyDesc->affix_unicode; + if (!font_supports_string(symbol, FONT_SIZE_MEDIUM)) { + symbol = currencyDesc->symbol_ascii; + affix = currencyDesc->affix_ascii; + } // Prefix - if (currencySpec->affix == CURRENCY_PREFIX) { - strcpy(*dest, symbol); + if (affix == CURRENCY_PREFIX) { + safe_strncpy(*dest, symbol, CURRENCY_SYMBOL_MAX_SIZE); *dest += strlen(*dest); } format_comma_separated_integer(dest, value); // Currency symbol suffix - if (currencySpec->affix == CURRENCY_SUFFIX) { - strcpy(*dest, symbol); + if (affix == CURRENCY_SUFFIX) { + safe_strncpy(*dest, symbol, CURRENCY_SYMBOL_MAX_SIZE); *dest += strlen(*dest); } } void format_currency_2dp(char **dest, long long value) { - const rct_currency_spec *currencySpec = &g_currency_specs[gConfigGeneral.currency_format]; + const currency_descriptor *currencyDesc = &CurrencyDescriptors[gConfigGeneral.currency_format]; - int rate = currencySpec->rate; + int rate = currencyDesc->rate; value *= rate; // Negative sign @@ -343,11 +399,16 @@ void format_currency_2dp(char **dest, long long value) } // Currency symbol - const char *symbol = currencySpec->symbol; + const utf8 *symbol = currencyDesc->symbol_unicode; + uint8 affix = currencyDesc->affix_unicode; + if (!font_supports_string(symbol, FONT_SIZE_MEDIUM)) { + symbol = currencyDesc->symbol_ascii; + affix = currencyDesc->affix_ascii; + } // Prefix - if (currencySpec->affix == CURRENCY_PREFIX) { - strcpy(*dest, symbol); + if (affix == CURRENCY_PREFIX) { + safe_strncpy(*dest, symbol, CURRENCY_SYMBOL_MAX_SIZE); *dest += strlen(*dest); } @@ -359,8 +420,8 @@ void format_currency_2dp(char **dest, long long value) } // Currency symbol suffix - if (currencySpec->affix == CURRENCY_SUFFIX) { - strcpy(*dest, symbol); + if (affix == CURRENCY_SUFFIX) { + safe_strncpy(*dest, symbol, CURRENCY_SYMBOL_MAX_SIZE); *dest += strlen(*dest); } } @@ -382,7 +443,7 @@ void format_length(char **dest, sint16 value) stringId--; } - uint16 *argRef = &value; + sint16 *argRef = &value; format_string_part(dest, stringId, (char**)&argRef); (*dest)--; } @@ -579,11 +640,11 @@ void format_string_code(unsigned char format_code, char **dest, char **args) } } -void format_string_part_from_raw(char **dest, const char *src, char **args) +void format_string_part_from_raw(utf8 **dest, const utf8 *src, char **args) { - unsigned char code; + unsigned int code; while (1) { - code = *src++; + code = utf8_get_next(src, &src); if (code < ' ') { if (code == 0) { *(*dest)++ = code; @@ -609,12 +670,12 @@ void format_string_part_from_raw(char **dest, const char *src, char **args) } else if (code < 142) { format_string_code(code, dest, args); } else { - *(*dest)++ = code; + *dest = utf8_write_codepoint(*dest, code); } } } -void format_string_part(char **dest, rct_string_id format, char **args) +void format_string_part(utf8 **dest, rct_string_id format, char **args) { if (format == (rct_string_id)STR_NONE) { **dest = 0; @@ -654,16 +715,34 @@ void format_string_part(char **dest, rct_string_id format, char **args) * format (ax) * args (ecx) */ -void format_string(char *dest, rct_string_id format, void *args) +void format_string(utf8 *dest, rct_string_id format, void *args) { format_string_part(&dest, format, (char**)&args); } -void format_string_raw(char *dest, char *src, void *args) +void format_string_raw(utf8 *dest, utf8 *src, void *args) { format_string_part_from_raw(&dest, src, (char**)&args); } +/** + * Writes a formatted string to a buffer and converts it to upper case. + * rct2: 0x006C2538 + * dest (edi) + * format (ax) + * args (ecx) + */ +void format_string_to_upper(utf8 *dest, rct_string_id format, void *args) +{ + format_string(dest, format, args); + + char *ch = dest; + while (*ch != 0) { + *ch = toupper(*ch); + ch++; + } +} + /** * rct2: 0x006E37F7 * error (eax) @@ -720,65 +799,129 @@ void generate_string_file() } /** -* Return the length of the string in buffer. -* note you can't use strlen as there can be inline sprites! -* -* buffer (esi) -*/ -int get_string_length(char* buffer) + * Returns a pointer to the null terminator of the given UTF-8 string. + */ +utf8 *get_string_end(const utf8 *text) { - // Length of string - int length = 0; + int codepoint; + const utf8 *ch = text; - for (uint8* curr_char = (uint8*)buffer; *curr_char != (uint8)0; curr_char++) { - length++; - if (*curr_char >= 0x20) { - continue; - } - switch (*curr_char) { - case FORMAT_MOVE_X: - case FORMAT_ADJUST_PALETTE: - case 3: - case 4: - curr_char++; - length++; - break; - case FORMAT_NEWLINE: - case FORMAT_NEWLINE_SMALLER: - case FORMAT_TINYFONT: - case FORMAT_BIGFONT: - case FORMAT_MEDIUMFONT: - case FORMAT_SMALLFONT: - case FORMAT_OUTLINE: - case FORMAT_OUTLINE_OFF: - case FORMAT_WINDOW_COLOUR_1: - case FORMAT_WINDOW_COLOUR_2: - case FORMAT_WINDOW_COLOUR_3: - case 0x10: - continue; - case FORMAT_INLINE_SPRITE: - length += 4; - curr_char += 4; - break; - default: - if (*curr_char <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y - length += 2; - curr_char += 2; - continue; - } - length += 4; - curr_char += 4;//never happens? - break; - } + while ((codepoint = utf8_get_next(ch, &ch)) != 0) { + int argLength = utf8_get_format_code_arg_length(codepoint); + ch += argLength; } - return length; + return (utf8*)(ch - 1); } -int win1252_to_utf8(utf8string dst, const char *src, int maxBufferLength) +/** + * Return the number of bytes (including the null terminator) in the given UTF-8 string. + */ +size_t get_string_size(const utf8 *text) { - utf16 intermediateBuffer[512]; + return get_string_end(text) - text + 1; +} - // 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 +/** + * Return the number of visible characters (excludes format codes) in the given UTF-8 string. + */ +int get_string_length(const utf8 *text) +{ + int codepoint; + const utf8 *ch = text; + + int count = 0; + while ((codepoint = utf8_get_next(ch, &ch)) != 0) { + if (utf8_is_format_code(codepoint)) { + ch += utf8_get_format_code_arg_length(codepoint); + } else { + count++; + } + } + return count; +} + +utf8 *win1252_to_utf8_alloc(const char *src) +{ + int reservedSpace = (strlen(src) * 4) + 1; + utf8 *result = malloc(reservedSpace); + int actualSpace = win1252_to_utf8(result, src, reservedSpace); + return (utf8*)realloc(result, actualSpace); +} + +int win1252_to_utf8(utf8string dst, const char *src, size_t maxBufferLength) +{ + size_t srcLength = strlen(src); + +#ifdef _WIN32 + utf16 stackBuffer[256]; + utf16 *heapBuffer = NULL; + utf16 *intermediateBuffer = stackBuffer; + size_t bufferCount = countof(stackBuffer); + if (maxBufferLength > bufferCount) { + if (srcLength > bufferCount) { + bufferCount = srcLength + 4; + heapBuffer = malloc(bufferCount * sizeof(utf16)); + intermediateBuffer = heapBuffer; + } + } + MultiByteToWideChar(CP_ACP, 0, src, -1, intermediateBuffer, bufferCount); + int result = WideCharToMultiByte(CP_UTF8, 0, intermediateBuffer, -1, dst, maxBufferLength, NULL, NULL); + + if (heapBuffer != NULL) { + free(heapBuffer); + } +#else + //log_warning("converting %s of size %d", src, srcLength); + char *buffer_conv = strndup(src, srcLength); + char *buffer_orig = buffer_conv; + const char *to_charset = "UTF8"; + const char *from_charset = "CP1252"; + iconv_t cd = iconv_open(to_charset, from_charset); + if ((iconv_t)-1 == cd) + { + int error = errno; + switch (error) + { + case EINVAL: + log_error("Unsupported conversion from %s to %s, errno = %d", from_charset, to_charset, error); + break; + default: + log_error("Unknown error while initializing iconv, errno = %d", error); + } + return 0; + } + size_t obl = maxBufferLength; + char *outBuf = dst; + size_t conversion_result = iconv(cd, &buffer_conv, &srcLength, &outBuf, &obl); + if (conversion_result == (size_t)-1) + { + int error = errno; + switch (error) + { + case EILSEQ: + log_error("Encountered invalid sequence"); + break; + case EINVAL: + log_error("Encountered incomplete sequence"); + break; + case E2BIG: + log_error("Ran out of space"); + break; + default: + log_error("Unknown error encountered, errno = %d", error); + } + } + int close_result = iconv_close(cd); + if (close_result == -1) + { + log_error("Failed to close iconv, errno = %d", errno); + } + size_t byte_diff = maxBufferLength - obl + 1; + dst[byte_diff - 1] = '\0'; + //log_warning("converted %s of size %d, %d", dst, byte_diff, strlen(dst)); + int result = byte_diff; + free(buffer_orig); +#endif // _WIN32 + + return result; +} diff --git a/src/localisation/localisation.h b/src/localisation/localisation.h index c7bee7a75c..ac255f5b91 100644 --- a/src/localisation/localisation.h +++ b/src/localisation/localisation.h @@ -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 . *****************************************************************************/ @@ -26,18 +26,34 @@ #include "language.h" #include "string_ids.h" +bool utf8_is_format_code(int codepoint); +bool utf8_should_use_sprite_for_codepoint(int codepoint); +int font_sprite_get_codepoint_offset(int codepoint); +int utf8_get_format_code_arg_length(int codepoint); + void format_string(char *dest, rct_string_id format, void *args); void format_string_raw(char *dest, char *src, void *args); +void format_string_to_upper(char *dest, rct_string_id format, void *args); void generate_string_file(); void error_string_quit(int error, rct_string_id format); -int get_string_length(char* buffer); +utf8 *get_string_end(const utf8 *text); +size_t get_string_size(const utf8 *text); +int get_string_length(const utf8 *text); void user_string_clear_all(); -rct_string_id user_string_allocate(int base, const char *text); +rct_string_id user_string_allocate(int base, const utf8 *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); +utf8 *win1252_to_utf8_alloc(const char *src); +int win1252_to_utf8(utf8string dst, const char *src, size_t maxBufferLength); + +int rct2_to_utf8(utf8 *dst, const char *src); +int utf8_to_rct2(char *dst, const utf8 *src); +wchar_t encoding_convert_rct2_to_unicode(wchar_t rct2str); +wchar_t encoding_convert_unicode_to_rct2(wchar_t unicode); +wchar_t encoding_convert_gb2312_to_unicode(wchar_t gb2312); +wchar_t encoding_convert_big5_to_unicode(wchar_t big5); #define MAX_USER_STRINGS 1024 #define USER_STRING_MAX_LENGTH 32 @@ -46,4 +62,6 @@ int win1252_to_utf8(utf8string dst, const char *src, int maxBufferLength); extern const char real_name_initials[16]; extern const char *real_names[1024]; +extern utf8 *gUserStrings; + #endif diff --git a/src/localisation/real_names.c b/src/localisation/real_names.c index 0c1c8c1eef..2539f061c9 100644 --- a/src/localisation/real_names.c +++ b/src/localisation/real_names.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 . *****************************************************************************/ @@ -1049,4 +1049,4 @@ const char *real_names[] = { "Zachary", "Zachery", "Zola" -}; \ No newline at end of file +}; diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h index b1170543fe..bc2bb1b397 100644 --- a/src/localisation/string_ids.h +++ b/src/localisation/string_ids.h @@ -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 . *****************************************************************************/ @@ -73,7 +73,7 @@ enum { STR_CLOSE_X = 824, STR_CHOSEN_NAME_IN_USE_ALREADY = 825, STR_TOO_MANY_NAMES_DEFINED = 826, - + STR_NOT_ENOUGH_CASH_REQUIRES = 827, STR_CLOSE_WINDOW_TIP = 828, STR_WINDOW_TITLE_TIP = 829, @@ -83,6 +83,8 @@ enum { STR_PAUSE_GAME_TIP = 833, STR_DISC_AND_GAME_OPTIONS_TIP = 834, + STR_RESOLUTION_X_BY_Y = 840, + STR_ABOUT = 847, STR_ROLLERCOASTER_TYCOON_2 = 848, STR_VERSION_X = 849, @@ -107,6 +109,7 @@ enum { STR_TOO_HIGH = 878, STR_CANT_LOWER_LAND_HERE = 879, STR_CANT_RAISE_LAND_HERE = 880, + STR_OBJECT_IN_THE_WAY = 881, STR_LOAD_GAME = 882, STR_SAVE_GAME = 883, @@ -124,13 +127,55 @@ enum { STR_SCREENSHOT_FAILED = 893, STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND = 895, + STR_RIDE_CONSTRUCTION_DIRECTION = 897, + STR_RIDE_CONSTRUCTION_LEFT_CURVE_TIP = 898, + STR_RIDE_CONSTRUCTION_RIGHT_CURVE_TIP = 899, + STR_RIDE_CONSTRUCTION_LEFT_CURVE_SMALL_TIP = 900, + STR_RIDE_CONSTRUCTION_RIGHT_CURVE_SMALL_TIP = 901, + STR_RIDE_CONSTRUCTION_LEFT_CURVE_VERY_SMALL_TIP = 902, + STR_RIDE_CONSTRUCTION_RIGHT_CURVE_VERY_SMALL_TIP = 903, + STR_RIDE_CONSTRUCTION_LEFT_CURVE_LARGE_TIP = 904, + STR_RIDE_CONSTRUCTION_RIGHT_CURVE_LARGE_TIP = 905, + STR_RIDE_CONSTRUCTION_STRAIGHT_TIP = 906, + STR_RIDE_CONSTRUCTION_SLOPE = 907, + STR_RIDE_CONSTRUCTION_ROLL_BANKING = 908, + STR_RIDE_CONSTRUCTION_SEAT_ROT = 909, + + STR_RIDE_CONSTRUCTION_ROLL_FOR_LEFT_CURVE_TIP = 910, + STR_RIDE_CONSTRUCTION_ROLL_FOR_RIGHT_CURVE_TIP = 911, + STR_RIDE_CONSTRUCTION_NO_ROLL_TIP = 912, + STR_RIDE_CONSTRUCTION_MOVE_TO_PREVIOUS_SECTION_TIP = 913, + STR_RIDE_CONSTRUCTION_MOVE_TO_NEXT_SECTION_TIP = 914, + STR_RIDE_CONSTRUCTION_CONSTRUCT_SELECTED_SECTION_TIP = 915, + STR_RIDE_CONSTRUCTION_REMOVE_HIGHLIGHTED_SECTION_TIP = 916, + STR_RIDE_CONSTRUCTION_VERTICAL_DROP_TIP = 917, + STR_RIDE_CONSTRUCTION_STEEP_SLOPE_DOWN_TIP = 918, + STR_RIDE_CONSTRUCTION_SLOPE_DOWN_TIP = 919, + STR_RIDE_CONSTRUCTION_LEVEL_TIP = 920, + STR_RIDE_CONSTRUCTION_SLOPE_UP_TIP = 921, + STR_RIDE_CONSTRUCTION_STEEP_SLOPE_UP_TIP = 922, + STR_RIDE_CONSTRUCTION_VERTICAL_RISE_TIP = 923, + STR_RIDE_CONSTRUCTION_HELIX_DOWN_TIP = 924, + STR_RIDE_CONSTRUCTION_HELIX_UP_TIP = 925, + STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS = 926, + STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE = 927, + STR_RIDE_CONSTRUCTION_CHAIN_LIFT_TIP = 928, + + STR_S_BEND_LEFT = 929, + STR_S_BEND_RIGHT = 930, + STR_VERTICAL_LOOP_LEFT = 931, + STR_VERTICAL_LOOP_RIGHT = 932, + STR_RAISE_OR_LOWER_LAND_FIRST = 933, + STR_RIDE_ENTRANCE_IN_THE_WAY = 934, + STR_RIDE_EXIT_IN_THE_WAY = 935, + STR_PARK_ENTRANCE_IN_THE_WAY = 936, STR_VIEW_OPTIONS_TIP = 937, STR_ADJUST_LAND_TIP = 938, STR_UNDERGROUND_VIEW = 939, STR_REMOVE_BASE_LAND = 940, STR_REMOVE_VERTICAL_FACES = 941, STR_SEE_THROUGH_RIDES = 942, - STR_SEE_THROUGH_SCENERY = 943, + STR_SEE_THROUGH_SCENERY = 943, STR_SAVE_PROMPT_SAVE = 944, STR_SAVE_PROMPT_DONT_SAVE = 945, @@ -145,6 +190,24 @@ enum { STR_QUIT_GAME_2_PROMPT_TITLE = 952, STR_LOAD_LANDSCAPE_PROMPT_TITLE = 953, + STR_RIDE_CONSTRUCTION_SELECT_SEAT_ROTATION_ANGLE_TIP = 955, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_NEG_180 = 956, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_NEG_135 = 957, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_NEG_90 = 958, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_NEG_45 = 959, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_0 = 960, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_45 = 961, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_90 = 962, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_135 = 963, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_180 = 964, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_225 = 965, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_270 = 966, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_315 = 967, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_360 = 968, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_405 = 969, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_450 = 970, + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_495 = 971, + STR_CANCEL = 972, STR_OK = 973, @@ -164,8 +227,12 @@ enum { STR_LOWER_COST_AMOUNT = 985, STR_COST_AMOUNT = 986, + STR_TOO_MANY_RIDES = 987, + STR_CONSTRUCTION = 990, + STR_STATION_PLATFORM = 991, + STR_DEMOLISH_RIDE_TIP = 992, STR_DEMOLISH_RIDE = 993, STR_DEMOLISH = 994, @@ -192,13 +259,23 @@ enum { STR_CLOSE_PARK = 1013, STR_OPEN_PARK = 1014, + STR_UNABLE_TO_OPERATE_WITH_MORE_THAN_ONE_STATION_IN_THIS_MODE = 1015, + STR_UNABLE_TO_OPERATE_WITH_LESS_THAN_TWO_STATIONS_IN_THIS_MODE = 1016, STR_CANT_CHANGE_OPERATING_MODE = 1017, + STR_RIDE_SET_VEHICLE_TYPE_FAIL = 1018, + STR_RIDE_SET_VEHICLE_SET_NUM_CARS_PER_TRAIN_FAIL = 1019, + STR_RIDE_SET_VEHICLE_SET_NUM_TRAINS_FAIL = 1020, STR_LOCATE_SUBJECT_TIP = 1027, STR_OFF_EDGE_OF_MAP = 1028, + STR_CANNOT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_WATER = 1029, + STR_CAN_ONLY_BUILD_THIS_UNDERWATER = 1030, + STR_RIDE_CANT_BUILD_THIS_UNDERWATER = 1031, + STR_CAN_ONLY_BUILD_THIS_ON_WATER = 1032, + STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND = 1033, STR_CAN_ONLY_BUILD_THIS_ON_LAND = 1034, - + STR_LOCAL_AUTHORITY_WONT_ALLOW_CONSTRUCTION_ABOVE_TREE_HEIGHT = 1035, STR_LOAD_GAME_DIALOG_TITLE = 1036, STR_LOAD_LANDSCAPE_DIALOG_TITLE = 1037, STR_CONVERT_SAVED_GAME_TO_SCENARIO_1038 = 1038, @@ -209,6 +286,7 @@ enum { STR_RCT2_SAVED_GAME = 1043, STR_RCT2_SCENARIO_FILE = 1044, STR_RCT2_LANDSCAPE_FILE = 1045, + STR_SCENARIO_SAVE_FAILED = 1048, STR_INVISIBLE_SUPPORTS = 1051, @@ -304,6 +382,11 @@ enum { STR_SELECT_VEHICLE_COLOUR_SCHEME_TIP = 1140, STR_SELECT_VEHICLE_TO_MODIFY_TIP = 1141, + STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION = 1144, + STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION = 1145, + STR_ENTRANCE_NOT_YET_BUILT = 1146, + STR_EXIT_NOT_YET_BUILT = 1147, + STR_QUARTER_LOAD = 1148, STR_HALF_LOAD = 1149, STR_THREE_QUARTER_LOAD = 1150, @@ -318,12 +401,16 @@ enum { STR_PLACE_SCENERY_TIP = 1159, STR_ADJUST_WATER_TIP = 1160, + STR_CANT_POSITION_THIS_HERE = 1161, STR_CANT_LOWER_WATER_LEVEL_HERE = 1166, STR_CANT_RAISE_WATER_LEVEL_HERE = 1167, STR_OPTIONS_TITLE = 1168, STR_SOUND_NONE = 1169, + STR_RIDE_ENTRANCE_CLOSED = 1171, + STR_RIDE_ENTRANCE_NAME = 1172, + STR_BUILD_FOOTPATH_TIP = 1173, STR_BANNER_SIGN_IN_THE_WAY = 1174, @@ -331,6 +418,7 @@ enum { STR_CANT_BUILD_FOOTPATH_HERE = 1176, STR_CANT_REMOVE_FOOTPATH_FROM_HERE = 1177, STR_LAND_SLOPE_UNSUITABLE = 1178, + STR_FOOTPATH_IN_THE_WAY = 1179, STR_CANT_BUILD_THIS_UNDERWATER = 1180, STR_FOOTPATHS = 1181, @@ -408,6 +496,33 @@ enum { STR_QUEUE_TIME_MINUTE = 1359, STR_QUEUE_TIME_MINUTES = 1360, + STR_TOO_HIGH_FOR_SUPPORTS = 1363, + + STR_IN_LINE_TWIST_LEFT = 1365, + STR_IN_LINE_TWIST_RIGHT = 1366, + STR_HALF_LOOP = 1367, + STR_HALF_CORKSCREW_LEFT = 1368, + STR_HALF_CORKSCREW_RIGHT = 1369, + STR_BARREL_ROLL_LEFT = 1370, + STR_BARREL_ROLL_RIGHT = 1371, + STR_LAUNCHED_LIFT_HILL = 1372, + STR_LARGE_HALF_LOOP_LEFT = 1373, + STR_LARGE_HALF_LOOP_RIGHT = 1374, + STR_UPPER_TRANSFER = 1375, + STR_LOWER_TRANSFER = 1376, + STR_HEARTLINE_ROLL_LEFT = 1377, + STR_HEARTLINE_ROLL_RIGHT = 1378, + STR_REVERSER_LEFT = 1379, + STR_REVERSER_RIGHT = 1380, + STR_CURVED_LIFT_HILL_LEFT = 1381, + STR_CURVED_LIFT_HILL_RIGHT = 1382, + STR_QUARTER_LOOP = 1383, + + STR_RIDE_CONSTRUCTION_OTHER_TRACK_CONFIGURATIONS_TIP = 1385, + STR_RIDE_CONSTRUCTION_SPECIAL = 1386, + + STR_CANT_CHANGE_LAND_TYPE = 1387, + STR_VIEW_OF_RIDE_ATTRACTION_TIP = 1392, STR_VEHICLE_DETAILS_AND_OPTIONS_TIP = 1393, STR_OPERATING_OPTIONS_TIP = 1394, @@ -417,6 +532,10 @@ enum { STR_MEASUREMENTS_AND_TEST_DATA_TIP = 1398, STR_GRAPHS_TIP = 1399, + STR_RIDE_CONSTRUCTION_ENTRANCE = 1400, + STR_RIDE_CONSTRUCTION_EXIT = 1401, + STR_RIDE_CONSTRUCTION_ENTRANCE_TIP = 1402, + STR_RIDE_CONSTRUCTION_EXIT_TIP = 1403, STR_ROTATE_90_TIP = 1404, STR_MIRROR_IMAGE_TIP = 1405, STR_TOGGLE_SCENERY_TIP = 1406, @@ -424,6 +543,10 @@ enum { STR_BUILD_THIS = 1407, STR_COST_LABEL = 1408, + STR_ENTRY_EXIT_PLATFORM = 1409, + STR_VERTICAL_TOWER = 1410, + STR_X_IN_THE_WAY = 1411, + STR_DATA_LOGGING_NOT_AVAILABLE_FOR_THIS_TYPE_OF_RIDE = 1412, STR_DATA_LOGGING_WILL_START_WHEN_NEXT_LEAVES = 1413, STR_LOGGING_DATA_FROM_TIP = 1422, @@ -452,17 +575,30 @@ enum { STR_LOOKING_AT_SCENERY = 1446, STR_LEAVING_PARK = 1447, STR_WATCHING_NEW_RIDE_BEING_CONSTRUCTED = 1448, - + + STR_CANT_NAME_GUEST = 1454, + + STR_RIDE_CONSTRUCTION_TRACK_STYLE = 1459, + STR_RIDE_CONSTRUCTION_U_SHAPED_OPEN_TRACK_TIP = 1460, + STR_RIDE_CONSTRUCTION_O_SHAPED_ENCLOSED_TRACK_TIP = 1461, + + STR_TOO_STEEP_FOR_LIFT_HILL = 1462, + STR_GUESTS = 1463, + STR_HELIX_UP_SMALL = 1464, + STR_HELIX_UP_LARGE = 1465, + STR_HELIX_DOWN_SMALL = 1466, + STR_HELIX_DOWN_LARGE = 1467, + 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, - + STR_EXCITEMENT_RATING = 1473, STR_EXCITEMENT_RATING_NOT_YET_AVAILABLE = 1474, STR_INTENSITY_RATING = 1475, @@ -472,7 +608,7 @@ enum { STR_NAUSEA_RATING_NOT_YET_AVAILABLE = 1479, STR_THOUGHT_START = 1480, - + STR_CONSTRUCT_FOOTPATH_ON_LAND_TIP = 1655, STR_CONSTRUCT_BRIDGE_OR_TUNNEL_FOOTPATH_TIP = 1656, @@ -481,9 +617,27 @@ enum { STR_TOTAL_CUSTOMERS = 1670, STR_TOTAL_PROFIT = 1671, + STR_BRAKES = 1672, + STR_SPINNING_CONTROL_TOGGLE_TRACK = 1673, + + STR_RIDE_CONSTRUCTION_BRAKE_SPEED = 1674, + STR_RIDE_CONSTRUCTION_BRAKE_SPEED_LIMIT_TIP = 1676, + STR_POPULARITY_UNKNOWN = 1677, STR_POPULARITY_PERCENT = 1678, + STR_HELIX_UP_LEFT = 1679, + STR_HELIX_UP_RIGHT = 1680, + STR_HELIX_DOWN_LEFT = 1681, + STR_HELIX_DOWN_RIGHT = 1682, + STR_BASE_SIZE_2_X_2 = 1683, + STR_BASE_SIZE_4_X_4 = 1684, + STR_BASE_SIZE_2_X_4 = 1685, + STR_BASE_SIZE_5_X_1 = 1686, + STR_WATER_SPLASH = 1687, + STR_BASE_SIZE_4_X_1 = 1688, + STR_BLOCK_BRAKES = 1689, + STR_GUESTS_TIP = 1693, STR_STAFF_TIP = 1694, @@ -518,6 +672,13 @@ enum { STR_CANT_OPEN_PARK = 1723, STR_CANT_CLOSE_PARK = 1724, + STR_LAND_NOT_OWNED_BY_PARK = 1729, + + STR_BANNER_TEXT = 1731, + + STR_RIDE_CONSTRUCTION_BUILD = 1732, + STR_RIDE_CONSTRUCTION_MODE = 1733, + STR_NUMBER_OF_LAPS = 1734, STR_NUMBER_OF_LAPS_TIP = 1735, @@ -537,13 +698,28 @@ enum { STR_ADMISSION_PRICE = 1756, STR_RELIABILITY_LABEL_1757 = 1757, + STR_RIDE_CONSTRUCTION_BUILD_MODE = 1758, + STR_RIDE_CONSTRUCTION_MOVE_MODE = 1759, + STR_RIDE_CONSTRUCTION_FILL_IN_MODE = 1760, + STR_RIDE_CONSTRUCTION_BUILD_MAZE_IN_THIS_DIRECTION_TIP = 1761, + + STR_WATERFALLS = 1762, + STR_RAPIDS = 1763, + STR_LOG_BUMPS = 1764, + STR_ON_RIDE_PHOTO_SECTION = 1765, + STR_REVERSER_TURNTABLE = 1766, + STR_SPINNING_TUNNEL = 1767, + STR_NUMBER_OF_SWINGS = 1769, STR_NUMBER_OF_SWINGS_TIP = 1770, + STR_ONLY_ONE_ON_RIDE_PHOTO_PER_RIDE = 1773, + STR_ONLY_ONE_CABLE_LIFT_HILL_PER_RIDE = 1774, + STR_OFF = 1775, STR_ON = 1776, STR_MUSIC = 1777, - + STR_UNIFORM_COLOUR_TIP = 1790, STR_UNIFORM_COLOUR = 1791, STR_RESPONDING_TO_RIDE_BREAKDOWN_CALL = 1792, @@ -552,6 +728,8 @@ enum { STR_ANSWERING_RADIO_CALL = 1795, STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING = 1796, + STR_WHIRLPOOL = 1798, + STR_SAFETY_CUT_OUT = 1800, STR_RESTRAINTS_STUCK_CLOSED = 1801, STR_RESTRAINTS_STUCK_OPEN = 1802, @@ -564,6 +742,13 @@ enum { STR_LAST_BREAKDOWN = 1808, STR_CURRENT_BREAKDOWN = 1809, + STR_CARRYING = 1810, + STR_CANT_BUILD_PARK_ENTRANCE_HERE = 1811, + + STR_STRING_DEFINED_TOOLTIP = 1812, + + STR_MISCELLANEOUS = 1813, + STR_ACTIONS = 1814, STR_THOUGHTS = STR_ACTIONS + 1, STR_INFORMATION_TYPE_TIP = 1816, @@ -598,7 +783,7 @@ enum { STR_GUESTS_FAVOURITE_PLURAL_LABEL = 1843, STR_RIDE_LIST_INFORMATION_TYPE_TIP = 1844, STR_NUM_GUESTS = 1846, - + STR_PLAY_MUSIC = 1849, STR_SELECT_MUSIC_TIP = 1850, STR_RUNNING_COST_PER_HOUR = 1851, @@ -626,7 +811,7 @@ enum { STR_INCOME_PER_HOUR = 1873, STR_PROFIT_PER_HOUR = 1874, - + STR_GUEST_ITEM_FORMAT = 1875, STR_INSPECT_RIDES = 1876, STR_FIX_RIDES = 1877, STR_INSPECTION = 1878, @@ -640,12 +825,14 @@ enum { STR_NEVER = 1885, STR_INSPECTING_RIDE = 1886, - + STR_TIME_SINCE_LAST_INSPECTION_MINUTES = 1887, STR_TIME_SINCE_LAST_INSPECTION_MORE_THAN_4_HOURS = 1888, STR_DOWN_TIME_LABEL_1889 = 1889, STR_SELECT_HOW_OFTEN_A_MECHANIC_SHOULD_CHECK_THIS_RIDE = 1890, + STR_NO_THING_IN_PARK_YET = 1891, + STR_ITEMS_SOLD = 1894, STR_BUILD_RIDE_TIP = 1895, STR_FINANCES_SUMMARY_EXPENDITURE_INCOME = 1896, @@ -679,6 +866,9 @@ enum { STR_CONTINUE_SAVED_GAME_TIP = 1922, STR_SHOW_TUTORIAL_TIP = 1923, STR_EXIT = 1924, + STR_RIDE_HAS_CRASHED = 1928, + + STR_PEEP_TRACKING_NOTIFICATION_BOUGHT_X = 1936, STR_SHOW_SUBJECT_TIP = 1937, @@ -700,15 +890,204 @@ enum { STR_ON_RIDE_PHOTO_PRICE = 1963, - STR_MAIN_COLOUR_SCHEME = 2971, - STR_ALTERNATIVE_COLOUR_SCHEME_1 = 2972, - STR_ALTERNATIVE_COLOUR_SCHEME_2 = 2973, - STR_ALTERNATIVE_COLOUR_SCHEME_3 = 2974, + STR_SHOP_ITEM_SINGULAR_BALLOON = 1988, + STR_SHOP_ITEM_SINGULAR_CUDDLY_TOY = 1989, + STR_SHOP_ITEM_SINGULAR_PARK_MAP = 1990, + STR_SHOP_ITEM_SINGULAR_ON_RIDE_PHOTO = 1991, + STR_SHOP_ITEM_SINGULAR_UMBRELLA = 1992, + STR_SHOP_ITEM_SINGULAR_DRINK = 1993, + STR_SHOP_ITEM_SINGULAR_BURGER = 1994, + STR_SHOP_ITEM_SINGULAR_CHIPS = 1995, + STR_SHOP_ITEM_SINGULAR_ICE_CREAM = 1996, + STR_SHOP_ITEM_SINGULAR_CANDYFLOSS = 1997, + STR_SHOP_ITEM_SINGULAR_EMPTY_CAN = 1998, + STR_SHOP_ITEM_SINGULAR_RUBBISH = 1999, + STR_SHOP_ITEM_SINGULAR_EMPTY_BURGER_BOX = 2000, + STR_SHOP_ITEM_SINGULAR_PIZZA = 2001, + STR_SHOP_ITEM_SINGULAR_VOUCHER = 2002, + STR_SHOP_ITEM_SINGULAR_POPCORN = 2003, + STR_SHOP_ITEM_SINGULAR_HOT_DOG = 2004, + STR_SHOP_ITEM_SINGULAR_TENTACLE = 2005, + STR_SHOP_ITEM_SINGULAR_HAT = 2006, + STR_SHOP_ITEM_SINGULAR_TOFFEE_APPLE = 2007, + STR_SHOP_ITEM_SINGULAR_T_SHIRT = 2008, + STR_SHOP_ITEM_SINGULAR_DOUGHNUT = 2009, + STR_SHOP_ITEM_SINGULAR_COFFEE = 2010, + STR_SHOP_ITEM_SINGULAR_EMPTY_CUP = 2011, + STR_SHOP_ITEM_SINGULAR_FRIED_CHICKEN = 2012, + STR_SHOP_ITEM_SINGULAR_LEMONADE = 2013, + STR_SHOP_ITEM_SINGULAR_EMPTY_BOX = 2014, + STR_SHOP_ITEM_SINGULAR_EMPTY_BOTTLE = 2015, - STR_ITEM_START = 1988, - STR_ITEM_SINGULAR_START = 2044, - STR_ITEM2_START = 2090, - STR_ITEM2_SINGULAR_START = 2134, + STR_SHOP_ITEM_PLURAL_BALLOON = 2016, + STR_SHOP_ITEM_PLURAL_CUDDLY_TOY = 2017, + STR_SHOP_ITEM_PLURAL_PARK_MAP = 2018, + STR_SHOP_ITEM_PLURAL_ON_RIDE_PHOTO = 2019, + STR_SHOP_ITEM_PLURAL_UMBRELLA = 2020, + STR_SHOP_ITEM_PLURAL_DRINK = 2021, + STR_SHOP_ITEM_PLURAL_BURGER = 2022, + STR_SHOP_ITEM_PLURAL_CHIPS = 2023, + STR_SHOP_ITEM_PLURAL_ICE_CREAM = 2024, + STR_SHOP_ITEM_PLURAL_CANDYFLOSS = 2025, + STR_SHOP_ITEM_PLURAL_EMPTY_CAN = 2026, + STR_SHOP_ITEM_PLURAL_RUBBISH = 2027, + STR_SHOP_ITEM_PLURAL_EMPTY_BURGER_BOX = 2028, + STR_SHOP_ITEM_PLURAL_PIZZA = 2029, + STR_SHOP_ITEM_PLURAL_VOUCHER = 2030, + STR_SHOP_ITEM_PLURAL_POPCORN = 2031, + STR_SHOP_ITEM_PLURAL_HOT_DOG = 2032, + STR_SHOP_ITEM_PLURAL_TENTACLE = 2033, + STR_SHOP_ITEM_PLURAL_HAT = 2034, + STR_SHOP_ITEM_PLURAL_TOFFEE_APPLE = 2035, + STR_SHOP_ITEM_PLURAL_T_SHIRT = 2036, + STR_SHOP_ITEM_PLURAL_DOUGHNUT = 2037, + STR_SHOP_ITEM_PLURAL_COFFEE = 2038, + STR_SHOP_ITEM_PLURAL_EMPTY_CUP = 2039, + STR_SHOP_ITEM_PLURAL_FRIED_CHICKEN = 2040, + STR_SHOP_ITEM_PLURAL_LEMONADE = 2041, + STR_SHOP_ITEM_PLURAL_EMPTY_BOX = 2042, + STR_SHOP_ITEM_PLURAL_EMPTY_BOTTLE = 2043, + + STR_SHOP_ITEM_INDEFINITE_BALLOON = 2044, + STR_SHOP_ITEM_INDEFINITE_CUDDLY_TOY = 2045, + STR_SHOP_ITEM_INDEFINITE_PARK_MAP = 2046, + STR_SHOP_ITEM_INDEFINITE_ON_RIDE_PHOTO = 2047, + STR_SHOP_ITEM_INDEFINITE_UMBRELLA = 2048, + STR_SHOP_ITEM_INDEFINITE_DRINK = 2049, + STR_SHOP_ITEM_INDEFINITE_BURGER = 2050, + STR_SHOP_ITEM_INDEFINITE_CHIPS = 2051, + STR_SHOP_ITEM_INDEFINITE_ICE_CREAM = 2052, + STR_SHOP_ITEM_INDEFINITE_CANDYFLOSS = 2053, + STR_SHOP_ITEM_INDEFINITE_EMPTY_CAN = 2054, + STR_SHOP_ITEM_INDEFINITE_RUBBISH = 2055, + STR_SHOP_ITEM_INDEFINITE_EMPTY_BURGER_BOX = 2056, + STR_SHOP_ITEM_INDEFINITE_PIZZA = 2057, + STR_SHOP_ITEM_INDEFINITE_VOUCHER = 2058, + STR_SHOP_ITEM_INDEFINITE_POPCORN = 2059, + STR_SHOP_ITEM_INDEFINITE_HOT_DOG = 2060, + STR_SHOP_ITEM_INDEFINITE_TENTACLE = 2061, + STR_SHOP_ITEM_INDEFINITE_HAT = 2062, + STR_SHOP_ITEM_INDEFINITE_TOFFEE_APPLE = 2063, + STR_SHOP_ITEM_INDEFINITE_T_SHIRT = 2064, + STR_SHOP_ITEM_INDEFINITE_DOUGHNUT = 2065, + STR_SHOP_ITEM_INDEFINITE_COFFEE = 2066, + STR_SHOP_ITEM_INDEFINITE_EMPTY_CUP = 2067, + STR_SHOP_ITEM_INDEFINITE_FRIED_CHICKEN = 2068, + STR_SHOP_ITEM_INDEFINITE_LEMONADE = 2069, + STR_SHOP_ITEM_INDEFINITE_EMPTY_BOX = 2070, + STR_SHOP_ITEM_INDEFINITE_EMPTY_BOTTLE = 2071, + + STR_SHOP_ITEM_DISPLAY_BALLOON = 2072, + STR_SHOP_ITEM_DISPLAY_CUDDLY_TOY = 2073, + STR_SHOP_ITEM_DISPLAY_PARK_MAP = 2074, + STR_SHOP_ITEM_DISPLAY_ON_RIDE_PHOTO = 2075, + STR_SHOP_ITEM_DISPLAY_UMBRELLA = 2076, + STR_SHOP_ITEM_DISPLAY_DRINK = 2077, + STR_SHOP_ITEM_DISPLAY_BURGER = 2078, + STR_SHOP_ITEM_DISPLAY_CHIPS = 2079, + STR_SHOP_ITEM_DISPLAY_ICE_CREAM = 2080, + STR_SHOP_ITEM_DISPLAY_CANDYFLOSS = 2081, + STR_SHOP_ITEM_DISPLAY_EMPTY_CAN = 2082, + STR_SHOP_ITEM_DISPLAY_RUBBISH = 2083, + STR_SHOP_ITEM_DISPLAY_EMPTY_BURGER_BOX = 2084, + STR_SHOP_ITEM_DISPLAY_PIZZA = 2085, + STR_SHOP_ITEM_DISPLAY_VOUCHER = 2086, + STR_SHOP_ITEM_DISPLAY_POPCORN = 2087, + STR_SHOP_ITEM_DISPLAY_HOT_DOG = 2088, + STR_SHOP_ITEM_DISPLAY_TENTACLE = 2089, + STR_SHOP_ITEM_DISPLAY_HAT = 2090, + STR_SHOP_ITEM_DISPLAY_TOFFEE_APPLE = 2091, + STR_SHOP_ITEM_DISPLAY_T_SHIRT = 2092, + STR_SHOP_ITEM_DISPLAY_DOUGHNUT = 2093, + STR_SHOP_ITEM_DISPLAY_COFFEE = 2094, + STR_SHOP_ITEM_DISPLAY_EMPTY_CUP = 2095, + STR_SHOP_ITEM_DISPLAY_FRIED_CHICKEN = 2096, + STR_SHOP_ITEM_DISPLAY_LEMONADE = 2097, + STR_SHOP_ITEM_DISPLAY_EMPTY_BOX = 2098, + STR_SHOP_ITEM_DISPLAY_EMPTY_BOTTLE = 2099, + + STR_SHOP_ITEM_SINGULAR_PRETZEL = 2125, + STR_SHOP_ITEM_SINGULAR_HOT_CHOCOLATE = 2126, + STR_SHOP_ITEM_SINGULAR_ICED_TEA = 2127, + STR_SHOP_ITEM_SINGULAR_FUNNEL_CAKE = 2128, + STR_SHOP_ITEM_SINGULAR_SUNGLASSES = 2129, + STR_SHOP_ITEM_SINGULAR_BEEF_NOODLES = 2130, + STR_SHOP_ITEM_SINGULAR_FRIED_RICE_NOODLES = 2131, + STR_SHOP_ITEM_SINGULAR_WONTON_SOUP = 2132, + STR_SHOP_ITEM_SINGULAR_MEATBALL_SOUP = 2133, + STR_SHOP_ITEM_SINGULAR_FRUIT_JUICE = 2134, + STR_SHOP_ITEM_SINGULAR_SOYBEAN_MILK = 2135, + STR_SHOP_ITEM_SINGULAR_SUJONGKWA = 2136, + STR_SHOP_ITEM_SINGULAR_SUB_SANDWICH = 2137, + STR_SHOP_ITEM_SINGULAR_COOKIE = 2138, + STR_SHOP_ITEM_SINGULAR_EMPTY_BOWL_RED = 2139, + STR_SHOP_ITEM_SINGULAR_EMPTY_DRINK_CARTON = 2140, + STR_SHOP_ITEM_SINGULAR_EMPTY_JUICE_CUP = 2141, + STR_SHOP_ITEM_SINGULAR_ROAST_SAUSAGE = 2142, + STR_SHOP_ITEM_SINGULAR_EMPTY_BOWL_BLUE = 2143, + + STR_SHOP_ITEM_PLURAL_PRETZEL = 2147, + STR_SHOP_ITEM_PLURAL_HOT_CHOCOLATE = 2148, + STR_SHOP_ITEM_PLURAL_ICED_TEA = 2149, + STR_SHOP_ITEM_PLURAL_FUNNEL_CAKE = 2150, + STR_SHOP_ITEM_PLURAL_SUNGLASSES = 2151, + STR_SHOP_ITEM_PLURAL_BEEF_NOODLES = 2152, + STR_SHOP_ITEM_PLURAL_FRIED_RICE_NOODLES = 2153, + STR_SHOP_ITEM_PLURAL_WONTON_SOUP = 2154, + STR_SHOP_ITEM_PLURAL_MEATBALL_SOUP = 2155, + STR_SHOP_ITEM_PLURAL_FRUIT_JUICE = 2156, + STR_SHOP_ITEM_PLURAL_SOYBEAN_MILK = 2157, + STR_SHOP_ITEM_PLURAL_SUJONGKWA = 2158, + STR_SHOP_ITEM_PLURAL_SUB_SANDWICH = 2159, + STR_SHOP_ITEM_PLURAL_COOKIE = 2160, + STR_SHOP_ITEM_PLURAL_EMPTY_BOWL_RED = 2161, + STR_SHOP_ITEM_PLURAL_EMPTY_DRINK_CARTON = 2162, + STR_SHOP_ITEM_PLURAL_EMPTY_JUICE_CUP = 2163, + STR_SHOP_ITEM_PLURAL_ROAST_SAUSAGE = 2164, + STR_SHOP_ITEM_PLURAL_EMPTY_BOWL_BLUE = 2165, + + STR_SHOP_ITEM_INDEFINITE_PHOTO2 = 2166, + STR_SHOP_ITEM_INDEFINITE_PHOTO3 = 2167, + STR_SHOP_ITEM_INDEFINITE_PHOTO4 = 2168, + STR_SHOP_ITEM_INDEFINITE_PRETZEL = 2169, + STR_SHOP_ITEM_INDEFINITE_HOT_CHOCOLATE = 2170, + STR_SHOP_ITEM_INDEFINITE_ICED_TEA = 2171, + STR_SHOP_ITEM_INDEFINITE_FUNNEL_CAKE = 2172, + STR_SHOP_ITEM_INDEFINITE_SUNGLASSES = 2173, + STR_SHOP_ITEM_INDEFINITE_BEEF_NOODLES = 2174, + STR_SHOP_ITEM_INDEFINITE_FRIED_RICE_NOODLES = 2175, + STR_SHOP_ITEM_INDEFINITE_WONTON_SOUP = 2176, + STR_SHOP_ITEM_INDEFINITE_MEATBALL_SOUP = 2177, + STR_SHOP_ITEM_INDEFINITE_FRUIT_JUICE = 2178, + STR_SHOP_ITEM_INDEFINITE_SOYBEAN_MILK = 2179, + STR_SHOP_ITEM_INDEFINITE_SUJONGKWA = 2180, + STR_SHOP_ITEM_INDEFINITE_SUB_SANDWICH = 2181, + STR_SHOP_ITEM_INDEFINITE_COOKIE = 2182, + STR_SHOP_ITEM_INDEFINITE_EMPTY_BOWL_RED = 2183, + STR_SHOP_ITEM_INDEFINITE_EMPTY_DRINK_CARTON = 2184, + STR_SHOP_ITEM_INDEFINITE_EMPTY_JUICE_CUP = 2185, + STR_SHOP_ITEM_INDEFINITE_ROAST_SAUSAGE = 2186, + STR_SHOP_ITEM_INDEFINITE_EMPTY_BOWL_BLUE = 2187, + + STR_SHOP_ITEM_DISPLAY_PRETZEL = 2191, + STR_SHOP_ITEM_DISPLAY_HOT_CHOCOLATE = 2192, + STR_SHOP_ITEM_DISPLAY_ICED_TEA = 2193, + STR_SHOP_ITEM_DISPLAY_FUNNEL_CAKE = 2194, + STR_SHOP_ITEM_DISPLAY_SUNGLASSES = 2195, + STR_SHOP_ITEM_DISPLAY_BEEF_NOODLES = 2196, + STR_SHOP_ITEM_DISPLAY_FRIED_RICE_NOODLES = 2197, + STR_SHOP_ITEM_DISPLAY_WONTON_SOUP = 2198, + STR_SHOP_ITEM_DISPLAY_MEATBALL_SOUP = 2199, + STR_SHOP_ITEM_DISPLAY_FRUIT_JUICE = 2200, + STR_SHOP_ITEM_DISPLAY_SOYBEAN_MILK = 2201, + STR_SHOP_ITEM_DISPLAY_SUJONGKWA = 2202, + STR_SHOP_ITEM_DISPLAY_SUB_SANDWICH = 2203, + STR_SHOP_ITEM_DISPLAY_COOKIE = 2204, + STR_SHOP_ITEM_DISPLAY_EMPTY_BOWL_RED = 2205, + STR_SHOP_ITEM_DISPLAY_EMPTY_DRINK_CARTON = 2206, + STR_SHOP_ITEM_DISPLAY_EMPTY_JUICE_CUP = 2207, + STR_SHOP_ITEM_DISPLAY_ROAST_SAUSAGE = 2208, + STR_SHOP_ITEM_DISPLAY_EMPTY_BOWL_BLUE = 2209, STR_STAFF_HANDYMEN_TAB_TIP = 2210, STR_STAFF_MECHANICS_TAB_TIP = 2211, @@ -730,6 +1109,11 @@ enum { STR_COMPANY_VALUE_LABEL = 2227, STR_LAST_MONTH_PROFIT_FROM_FOOD_DRINK_MERCHANDISE_SALES_LABEL = 2228, + STR_SLOPE_UP_TO_VERTICAL = 2229, + STR_VERTICAL_TRACK = 2230, + STR_HOLDING_BRAKE_FOR_DROP = 2231, + STR_CABLE_LIFT_HILL = 2232, + STR_PARK_INFORMATION_TIP = 2233, STR_RECENT_MESSAGES = 2234, @@ -775,7 +1159,7 @@ enum { STR_RESEARCH_SCENERY_LABEL = 2273, STR_RESEARCH_SHOW_DETAILS_TIP = 2274, - STR_FINANCES_RESEARCH = 2275, + STR_FINANCES_RESEARCH_TIP = 2275, STR_RESEARCH_AND_DEVELOPMENT_TIP = 2276, STR_RESEARCH_UNKNOWN = 2277, @@ -794,6 +1178,7 @@ enum { STR_SELECT_SCENARIO = 2291, + STR_NOTHING = 2293, STR_CHANGE_BASE_LAND_TIP = 2294, STR_CHANGE_VERTICAL_LAND_TIP = 2295, @@ -808,10 +1193,6 @@ enum { STR_TRACK_LIST_COST_AROUND = 2315, STR_TRACK_LIST_SPACE_REQUIRED = 2316, - STR_SOUND_QUALITY = 2317, - STR_SOUND_LOW = 2318, - STR_SOUND_MEDIUM = 2319, - STR_SOUND_HIGH = 2320, STR_NUMBER_OF_RIDES_LABEL = 2321, STR_STAFF_LABEL = 2322, STR_PARK_SIZE_METRIC_LABEL = 2323, @@ -921,12 +1302,6 @@ enum { STR_ADVERTISING_CAMPAIGN_FOR_2 = 2435, STR_MARKETING_1_WEEK = 2436, - STR_MARKETING_2_WEEKS = 2437, - STR_MARKETING_3_WEEKS = 2438, - STR_MARKETING_4_WEEKS = 2439, - STR_MARKETING_5_WEEKS = 2440, - STR_MARKETING_6_WEEKS = 2441, - STR_MARKETING_WEEKS_REMAINING = 2442, STR_MARKETING_COST_PER_WEEK = 2443, STR_MARKETING_TOTAL_COST = 2444, STR_MARKETING_START_THIS_MARKETING_CAMPAIGN = 2445, @@ -985,70 +1360,71 @@ enum { STR_REAL_NAME_TIP = 2488, STR_HOTKEY = 2489, - STR_SHORTCUT_DESCRIPTION_0 = 2493, - - STR_SHORTCUT_DESCRIPTION_31 = 2524, + STR_SHORTCUT_CLOSE_TOP_MOST_WINDOW = 2493, + STR_SHORTCUT_CLOSE_ALL_FLOATING_WINDOWS = 2494, + STR_SHORTCUT_CANCEL_CONSTRUCTION_MODE = 2495, + STR_SHORTCUT_PAUSE_GAME = 2496, + STR_SHORTCUT_ZOOM_VIEW_OUT = 2497, + STR_SHORTCUT_ZOOM_VIEW_IN = 2498, + STR_SHORTCUT_ROTATE_VIEW_CLOCKWISE = 2499, + STR_SHORTCUT_ROTATE_CONSTRUCTION_OBJECT = 2500, + STR_SHORTCUT_UNDERGROUND_VIEW_TOGGLE = 2501, + STR_SHORTCUT_REMOVE_BASE_LAND_TOGGLE = 2502, + STR_SHORTCUT_REMOVE_VERTICAL_LAND_TOGGLE = 2503, + STR_SHORTCUT_SEE_THROUGH_RIDES_TOGGLE = 2504, + STR_SHORTCUT_SEE_THROUGH_SCENERY_TOGGLE = 2505, + STR_SHORTCUT_INVISIBLE_SUPPORTS_TOGGLE = 2506, + STR_SHORTCUT_INVISIBLE_PEOPLE_TOGGLE = 2507, + STR_SHORTCUT_HEIGHT_MARKS_ON_LAND_TOGGLE = 2508, + STR_SHORTCUT_HEIGHT_MARKS_ON_RIDE_TRACKS_TOGGLE = 2509, + STR_SHORTCUT_HEIGHT_MARKS_ON_PATHS_TOGGLE = 2510, + STR_SHORTCUT_ADJUST_LAND = 2511, + STR_SHORTCUT_ADJUST_WATER = 2512, + STR_SHORTCUT_BUILD_SCENERY = 2513, + STR_SHORTCUT_BUILD_PATHS = 2514, + STR_SHORTCUT_BUILD_NEW_RIDE = 2515, + STR_SHORTCUT_SHOW_FINANCIAL_INFORMATION = 2516, + STR_SHORTCUT_SHOW_RESEARCH_INFORMATION = 2517, + STR_SHORTCUT_SHOW_RIDES_LIST = 2518, + STR_SHORTCUT_SHOW_PARK_INFORMATION = 2519, + STR_SHORTCUT_SHOW_GUEST_LIST = 2520, + STR_SHORTCUT_SHOW_STAFF_LIST = 2521, + STR_SHORTCUT_SHOW_RECENT_MESSAGES = 2522, + STR_SHORTCUT_SHOW_MAP = 2523, + STR_SHORTCUT_SCREENSHOT = 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, + STR_CHEAT_TIP_5K_MONEY = 2681, - // Money - STR_CHEAT_5K_MONEY = 2760, - STR_CHEAT_PAY_ENTRANCE = 2761, - STR_CHEAT_CLEAR_LOAN = 5302, - STR_CHEAT_PAY_RIDES = 2762, + STR_CHEAT_TIP_LARGE_TRAM_GUESTS = 2684, - // Guests - STR_CHEAT_HAPPY_GUESTS = 2764, - STR_CHEAT_LARGE_TRAM_GUESTS = 2765, - STR_CHEAT_NAUSEA = 5254, - STR_CHEAT_EXPLODE = 5285, + STR_SAVE_EVERY_MINUTE = 2701, + STR_SAVE_EVERY_5MINUTES = 2702, + STR_SAVE_EVERY_15MINUTES = 2703, + STR_SAVE_EVERY_30MINUTES = 2704, + STR_SAVE_EVERY_HOUR = 2705, + STR_SAVE_NEVER = 2706, + + STR_DATE_FORMAT_DMY = 2737, + + STR_ROLLERCOASTER_TYCOON_1_DROPDOWN = 2740, + STR_ROLLERCOASTER_TYCOON_2_DROPDOWN = 2741, - // 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_FORCE_SUN = 2757, + STR_CHEAT_FORCE_THUNDER = 2758, + STR_CHEAT_ZERO_CLEARANCE = 2759, + STR_CHEAT_5K_MONEY = 2760, + STR_CHEAT_LARGE_TRAM_GUESTS = 2765, 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_CHEAT_FREEZE_CLIMATE = 2767, + STR_CHEAT_UNFREEZE_CLIMATE = 2768, + STR_CHEAT_OPEN_PARK = 2769, + STR_CHEAT_CLOSE_PARK = 2770, STR_SHORTCUT_ENTRY_FORMAT = 2781, STR_SHIFT_PLUS = 2782, @@ -1137,7 +1513,15 @@ enum { STR_MUSIC_ACKNOWLEDGEMENTS_ELLIPSIS = 2862, STR_MUSIC_ACKNOWLEDGEMENTS = 2863, + STR_MAIN_COLOUR_SCHEME = 2971, + STR_ALTERNATIVE_COLOUR_SCHEME_1 = 2972, + STR_ALTERNATIVE_COLOUR_SCHEME_2 = 2973, + STR_ALTERNATIVE_COLOUR_SCHEME_3 = 2974, + + STR_CANT_NAME_STAFF_MEMBER = 2979, + STR_TOO_MANY_BANNERS_IN_GAME = 2980, + STR_NO_ENTRY = 2981, STR_CHANGE_BANNER_TEXT_TIP = 2986, STR_SET_AS_NO_ENTRY_BANNER_TIP = 2987, @@ -1149,9 +1533,6 @@ enum { STR_CHANGE_SIGN_TEXT_TIP = 2994, STR_DEMOLISH_SIGN_TIP = 2995, - STR_LICENCE_AGREEMENT_NOTICE_1 = 2969, - STR_LICENCE_AGREEMENT_NOTICE_2 = 2970, - STR_COLOUR_SCHEME_TO_CHANGE_TIP = 2975, STR_PAINT_INDIVIDUAL_AREA_TIP = 2976, @@ -1167,7 +1548,7 @@ enum { STR_JUNGLE_DRUMS_STYLE = STR_MUSIC_STYLE_START + 5, STR_EGYPTIAN_STYLE = STR_MUSIC_STYLE_START + 6, STR_TOYLAND_STYLE = STR_MUSIC_STYLE_START + 7, - // STR_??? = STR_MUSIC_STYLE_START + 8, + // STR_??? = STR_MUSIC_STYLE_START + 8, // Circus show; never displayed as a string STR_SPACE_STYLE = STR_MUSIC_STYLE_START + 9, STR_HORROR_STYLE = STR_MUSIC_STYLE_START + 10, STR_TECHNO_STYLE = STR_MUSIC_STYLE_START + 11, @@ -1198,6 +1579,12 @@ enum { STR_THIS_RIDE_CANNOT_BE_MODIFIED = 3046, STR_LOCAL_AUTHORITY_FORBIDS_DEMOLITION_OR_MODIFICATIONS_TO_THIS_RIDE = 3047, + STR_GOLF_HOLE_A = 3049, + STR_GOLF_HOLE_B = 3050, + STR_GOLF_HOLE_C = 3051, + STR_GOLF_HOLE_D = 3052, + STR_GOLF_HOLE_E = 3053, + STR_WHITE = 3055, STR_TRANSLUCENT = 3056, STR_CONSTRUCTION_MARKER = 3057, @@ -1207,12 +1594,18 @@ enum { STR_ICE_BLOCKS = 3060, STR_WOODEN_FENCES = 3061, + STR_RIDE_CONSTRUCTION_STANDARD_RC_TRACK_TIP = 3062, + STR_RIDE_CONSTRUCTION_WATER_CHANNEL_TIP = 3063, + STR_BEGINNER_PARKS = 3064, STR_CHALLENGING_PARKS = STR_BEGINNER_PARKS + 1, STR_EXPERT_PARKS = STR_BEGINNER_PARKS + 2, STR_REAL_PARKS = STR_BEGINNER_PARKS + 3, STR_OTHER_PARKS = STR_BEGINNER_PARKS + 4, + STR_TOP_SECTION = 3069, + STR_SLOPE_TO_LEVEL = 3070, + STR_SAME_PRICE_THROUGHOUT_PARK = 3071, STR_SAME_PRICE_THROUGHOUT_PARK_TIP = 3072, @@ -1236,12 +1629,18 @@ enum { STR_SPACE_ENTRANCE = 3089, STR_SELECT_STYLE_OF_ENTRANCE_EXIT_STATION_TIP = 3090, + + STR_YOU_ARE_NOT_ALLOWED_TO_REMOVE_THIS_SECTION = 3091, + STR_NOT_ALLOWED_TO_MODIFY_STATION = 3092, + STR_SELECT_LIFT_HILL_CHAIN_SPEED_TIP = 3097, STR_SELECT_COLOUR = 3099, STR_SELECT_SECONDARY_COLOUR = 3100, STR_SELECT_TERNARY_COLOUR = 3101, + STR_CANT_REPAINT_THIS = 3103, + STR_LIST_RIDES_TIP = 3104, STR_LIST_SHOPS_AND_STALLS_TIP = 3105, STR_LIST_KIOSKS_AND_FACILITIES_TIP = 3106, @@ -1277,6 +1676,9 @@ enum { STR_THIS_DESIGN_WILL_BE_BUILT_WITH_AN_ALTERNATIVE_VEHICLE_TYPE = 3136, STR_SELECT_NEARBY_SCENERY = 3137, STR_RESET_SELECTION = 3138, + STR_CABLE_LIFT_UNABLE_TO_WORK_IN_THIS_OPERATING_MODE = 3139, + STR_CABLE_LIFT_HILL_MUST_START_IMMEDIATELY_AFTER_STATION = 3140, + STR_MULTICIRCUIT_NOT_POSSIBLE_WITH_CABLE_LIFT_HILL = 3141, STR_SHOW_PEOPLE_ON_MAP_TIP = 3143, STR_SHOW_RIDES_STALLS_ON_MAP_TIP = 3144, @@ -1297,6 +1699,7 @@ enum { 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_AT_LEAST_ONE_RIDE_OBJECT_MUST_BE_SELECTED = 3179, STR_INVALID_SELECTION_OF_OBJECTS = 3180, STR_OBJECT_SELECTION = 3181, @@ -1333,6 +1736,9 @@ enum { STR_MAP_SIZE = 3211, + STR_CANT_DECREASE_MAP_SIZE_ANY_FURTHER = 3213, + STR_CANT_INCREASE_MAP_SIZE_ANY_FURTHER = 3214, + STR_SELECT_PARK_OWNED_LAND_TIP = 3216, STR_LAND_OWNED = 3217, @@ -1390,12 +1796,14 @@ enum { 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_SCENARIO_NAME = 3313, + STR_ENTER_SCENARIO_NAME = 3314, STR_NO_DETAILS_YET = 3317, STR_SELECT_WHICH_GROUP_THIS_SCENARIO_APPEARS_IN = 3318, @@ -1404,6 +1812,7 @@ enum { STR_OBJECTIVE = 3322, + STR_PEEP_SPAWNS_NOT_SET = 3327, STR_CANT_ADVANCE_TO_NEXT_EDITOR_STAGE = 3328, STR_NO_PARK_ENTRANCES = 3329, STR_PARK_MUST_OWN_SOME_LAND = 3330, @@ -1413,7 +1822,6 @@ enum { 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, @@ -1421,10 +1829,15 @@ enum { STR_ROLLER_COASTER_DESIGNER = 3344, STR_TRACK_DESIGNS_MANAGER = 3345, + STR_CANT_SAVE_TRACK_DESIGN = 3346, + STR_TRACK_TOO_LARGE_OR_TOO_MUCH_SCENERY = 3347, STR_TRACK_MANAGE_RENAME = 3348, STR_TRACK_MANAGE_DELETE = 3349, STR_CANT_RENAME_TRACK_DESIGN = 3352, + STR_NEW_NAME_CONTAINS_INVALID_CHARACTERS = 3353, + STR_ANOTHER_FILE_EXISTS_WITH_NAME_OR_FILE_IS_WRITE_PROTECTED = 3354, + STR_FILE_IS_WRITE_PROTECTED_OR_LOCKED = 3355, STR_ARE_YOU_SURE_YOU_WANT_TO_PERMANENTLY_DELETE_TRACK = 3357, STR_CANT_DELETE_TRACK_DESIGN = 3358, @@ -1432,8 +1845,6 @@ enum { 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, @@ -1448,18 +1859,8 @@ enum { 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_SAVE_TRACK_SCENERY_UNABLE_TO_SELECT_ADDITIONAL_ITEM_OF_SCENERY = 3389, + STR_SAVE_TRACK_SCENERY_TOO_MANY_ITEMS_SELECTED = 3390, STR_CLEAR_SCENERY_TIP = 3437, STR_CLEAR_SCENERY = 3439, @@ -1473,8 +1874,37 @@ enum { STR_SET_PATROL_AREA = 3445, STR_CLEAR_PATROL_AREA = 3446, + STR_UNABLE_TO_REMOVE_ALL_SCENERY_FROM_HERE = 3438, + STR_OPENRCT2_BEGIN_STRING_ID = 5120, + STR_FINANCES_BUTTON_ON_TOOLBAR = 5120, + STR_RESEARCH_BUTTON_ON_TOOLBAR = 5121, + STR_SELECT_BY_TRACK_TYPE = 5122, + + STR_CHEAT_RENEW_RIDES = 5123, + 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, + STR_CHEATS_BUTTON_ON_TOOLBAR = 5147, + STR_GAME_SPEED_TIP = 5148, + STR_CHEATS_TIP = 5149, + + STR_ENABLE_DEBUGGING_TOOLS = 5150, + STR_EDIT_THEMES_BUTTON = 5153, + STR_HARDWARE_DISPLAY = 5154, + STR_TEST_UNFINISHED_TRACKS = 5155, + STR_TEST_UNFINISHED_TRACKS_TIP = 5156, + + STR_CHEAT_UNLOCK_PRICES = 5157, + + STR_DATE_FORMAT_MDY = 5160, + STR_DATE_FORMAT = 5161, + STR_DATE_FORMAT_DAY_MONTH_YEAR = 5162, + STR_DATE_FORMAT_MONTH_DAY_YEAR = 5163, + STR_TWITCH_NAME = 5164, STR_TWITCH_PEEP_FOLLOWERS = 5165, STR_TWITCH_PEEP_FOLLOWERS_TIP = 5166, @@ -1491,26 +1921,46 @@ enum { STR_FULLSCREEN_MODE = 5177, + // Cheat tab tips + STR_FINANCIAL_CHEATS_TIP = 5178, + STR_GUEST_CHEATS_TIP = 5179, + STR_PARK_CHEATS_TIP = 5180, + STR_RIDE_CHEATS_TIP = 5181, + + STR_CHEAT_TITLE = 5217, + STR_GIANT_SCREENSHOT = 5260, + STR_OBJECT_FILTER = 5261, + STR_OBJECT_FILTER_WW = 5262, + STR_OBJECT_FILTER_TT = 5263, + STR_OBJECT_FILTER_CUSTOM = 5264, + STR_OBJECT_FILTER_TIP = 5265, + + STR_OPTIONS_DISPLAY_TIP = 5266, + STR_OPTIONS_CULTURE_TIP = 5267, + STR_OPTIONS_AUDIO_TIP = 5268, + STR_OPTIONS_CONTROLS_AND_INTERFACE_TIP = 5269, + STR_OPTIONS_MISCELLANEOUS_TIP = 5270, + STR_OPTIONS_TWITCH_TIP = 5271, + + STR_OBJECT_SEARCH = 5275, + STR_OBJECT_SEARCH_DESC = 5276, + STR_OBJECT_SEARCH_CLEAR = 5277, + 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_CHEAT_EXPLODE = 5285, + STR_CHEAT_TIP_EXPLODE = 5286, - STR_CHANGELOG_TITLE = 5344, + STR_DEBUG_NO_BREAKDOWNS_AVAILABLE = 5289, + STR_DEBUG_FIX_RIDE = 5290, + + STR_CHEAT_TIP_CLEAR_LOAN = 5301, + STR_CHEAT_CLEAR_LOAN = 5302, + STR_CHEAT_BUILD_IN_PAUSE_MODE = 5303, STR_TITLE_SEQUENCE = 5304, STR_TITLE_SEQUENCE_RCT1 = 5305, @@ -1520,6 +1970,212 @@ enum { STR_TITLE_SEQUENCE_OPENRCT2 = 5309, STR_TITLE_SEQUENCE_RANDOM = 5310, + 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_AUTO_STAFF_PLACEMENT = 5343, + + STR_CHANGELOG_TITLE = 5344, + + STR_CHEAT_TITLE_FINANCIAL = 5345, + STR_CHEAT_TITLE_GUEST = 5346, + STR_CHEAT_TITLE_RIDE = 5347, + STR_CHEAT_TITLE_PARK = 5348, + + STR_OBJECT_FILTER_ALL_RIDES_TIP = 5349, + + STR_MAX = 5350, + STR_MIN = 5351, + + STR_CHEAT_GUEST_HAPPINESS = 5352, + STR_CHEAT_GUEST_ENERGY = 5353, + STR_CHEAT_GUEST_HUNGER = 5354, + STR_CHEAT_GUEST_THIRST = 5355, + STR_CHEAT_GUEST_NAUSEA = 5356, + STR_CHEAT_GUEST_NAUSEA_TOLERANCE = 5357, + STR_CHEAT_GUEST_BATHROOM = 5358, + STR_CHEAT_REMOVE_ALL_GUESTS = 5359, + STR_CHEAT_TIP_REMOVE_ALL_GUESTS = 5360, + STR_CHEAT_GIVE_ALL_GUESTS = 5361, + STR_CHEAT_GUEST_PREFERRED_INTENSITY = 5362, + STR_CHEAT_MORE_THAN_1 = 5363, + STR_CHEAT_LESS_THAN_15 = 5364, + STR_CHEAT_STAFF_SPEED = 5365, + STR_NORMAL = 5366, + STR_FAST = 5367, + STR_CHEAT_RESET_CRASH_STATUS = 5368, + STR_CHEAT_10_MINUTE_INSPECTIONS = 5559, + STR_CHEAT_10_MINUTE_INSPECTIONS_TIP = 5560, + STR_CHEAT_PARK_PARAMETERS = 5369, + STR_CHEAT_TIP_PARK_PARAMETERS = 5370, + + STR_DEBUG_DROPDOWN_OBJECT_SELECTION = 5371, + + STR_INVERT_RIGHT_MOUSE_DRAG = 5372, + + STR_NAME = 5373, + STR_DATE = 5374, + STR_UP = 5375, + STR_DOWN = 5376, + + + STR_EDIT_TITLE_SEQUENCES_BUTTON = 5436, + + STR_MININISE_FULL_SCREEN_ON_FOCUS_LOSS = 5440, + + STR_SELECT_BY_TRACK_TYPE_TIP = 5441, + + STR_FORCE_PARK_RATING = 5442, + + STR_OBJECTS_SORT_TYPE = 5447, + STR_OBJECTS_SORT_RIDE = 5448, + + STR_SHORTCUT_REDUCE_GAME_SPEED = 5449, + STR_SHORTCUT_INCREASE_GAME_SPEED = 5450, + STR_SHORTCUT_OPEN_CHEATS_WINDOW = 5451, + STR_SHORTCUT_TOGGLE_VISIBILITY_OF_TOOLBARS = 5452, + + STR_SELECT_OTHER_RIDE = 5453, + + STR_UNCAP_FPS = 5454, + + STR_ENABLE_SANDBOX_MODE = 5455, + STR_DISABLE_CLEARANCE_CHECKS = 5456, + STR_DISABLE_SUPPORT_LIMITS = 5457, + + STR_ROTATE_CLOCKWISE = 5458, + STR_ROTATE_ANTI_CLOCKWISE = 5459, + STR_SHORTCUT_ROTATE_VIEW_ANTICLOCKWISE = 5460, + + STR_CHEAT_SET_GUESTS_PARAMETERS = 5461, + STR_CHEAT_CURRENCY_FORMAT = 5462, + STR_CHEAT_HAVE_FUN = 5463, + STR_CHEAT_GENERAL_GROUP = 5464, + STR_CHEAT_CLIMATE_GROUP = 5465, + STR_CHEAT_STAFF_GROUP = 5466, + + STR_ALT_PLUS = 5467, + STR_SHOW_RECENT_MESSAGES_ON_TOOLBAR = 5468, + + STR_SHORTCUT_SCROLL_MAP_UP = 5469, + STR_SHORTCUT_SCROLL_MAP_LEFT = 5470, + STR_SHORTCUT_SCROLL_MAP_DOWN = 5471, + STR_SHORTCUT_SCROLL_MAP_RIGHT = 5472, + + STR_CYCLE_DAY_NIGHT = 5473, + STR_UPPER_CASE_BANNERS = 5474, + + STR_X_WEEKS = 5475, + + STR_HARDWARE_GROUP = 5476, + STR_RENDERING_GROUP = 5477, + STR_CONTROLS_GROUP = 5478, + STR_TOOLBAR_BUTTONS_GROUP = 5479, + STR_SHOW_TOOLBAR_BUTTONS_FOR = 5480, + STR_THEMES_GROUP = 5481, + + STR_TIME_SINCE_LAST_INSPECTION_MINUTE = 5482, + + STR_X_WEEKS_REMAINING = 5483, + STR_1_WEEK_REMAINING = 5484, + + STR_LAND_TOOL_SIZE_VALUE = 5486, + + STR_SHOW_RECENT_MESSAGES_TIP = 5487, + + STR_ENTRANCE_NONE = 5488, + + STR_TRACKED_GUESTS_ONLY_TIP = 5489, + + STR_AUDIO_FOCUS = 5490, + + STR_DEBUG_DROPDOWN_INVENTIONS_LIST = 5491, + STR_DEBUG_DROPDOWN_SCENARIO_OPTIONS = 5492, + + STR_SEND_MESSAGE = 5493, + STR_PLAYER_LIST = 5495, + STR_PLAYER = 5496, + STR_PING = 5497, + STR_SERVER_LIST = 5498, + STR_PLAYER_NAME = 5499, + STR_ADD_SERVER = 5500, + STR_START_SERVER = 5501, + STR_MULTIPLAYER = 5502, + STR_ENTER_HOSTNAME_OR_IP_ADDRESS = 5503, + STR_SHOW_MULTIPLAYER_STATUS_TIP = 5504, + STR_UNABLE_TO_CONNECT_TO_SERVER = 5505, + + STR_CHEAT_IGNORE_INTENSITY = 5506, + + STR_HANDYMEN_MOW_BY_DEFAULT = 5507, + + STR_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM = 5508, + STR_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM_TIP = 5509, + + STR_SAVE_GAME_AS = 5512, + STR_SHORTCUT_QUICK_SAVE_GAME = 5513, + + STR_CHEAT_DISABLE_VANDALISM = 5514, + STR_CHEAT_DISABLE_VANDALISM_TIP = 5515, + + STR_COLOUR_NAMES_START = 5516, + + STR_CHEAT_SHOW_ALL_OPERATING_MODES = 5548, + + STR_DATE_FORMAT_YEAR_MONTH_DAY = 5549, + STR_DATE_FORMAT_YMD = 5550, + STR_DATE_FORMAT_YEAR_DAY_MONTH = 5551, + STR_DATE_FORMAT_YDM = 5552, + + STR_STEAM_OVERLAY_PAUSE = 5553, + + STR_ENABLE_MOUNTAIN_TOOL_TIP = 5554, + + STR_CHEAT_SHOW_VEHICLES_FROM_OTHER_TRACK_TYPES = 5555, + + STR_KICK_PLAYER = 5556, + STR_STAY_CONNECTED_AFTER_DESYNC = 5557, + + STR_RESTART_REQUIRED = 5558, + STR_LANGUAGE_LOAD_FAILED = 5561, + + STR_WARNING_IN_CAPS = 5562, + STR_THIS_FEATURE_IS_CURRENTLY_UNSTABLE = 5563, + + STR_INSERT_CORRUPT = 5564, + STR_INSERT_CORRUPT_TIP = 5565, + + STR_PASSWORD = 5566, + STR_ADVERTISE = 5567, + STR_PASSWORD_REQUIRED = 5568, + STR_PASSWORD_REQUIRED_DESC = 5569, + STR_FETCH_SERVERS = 5570, + STR_JOIN_GAME = 5571, + STR_ADD_TO_FAVORITES = 5572, + STR_REMOVE_FROM_FAVORITES = 5573, + STR_SERVER_NAME = 5574, + STR_MAX_PLAYERS = 5575, + STR_PORT = 5576, + + STR_WON = 5577, + STR_ROUBLE = 5578, + + STR_UI_SCALING_DESC = 5579, + + STR_CZECH_KORUNA = 5580, + // 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 57358e4c65..e664715dd1 100644 --- a/src/localisation/user.c +++ b/src/localisation/user.c @@ -8,20 +8,22 @@ * 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.h" +#include "../ride/ride.h" +#include "../util/util.h" -char *gUserStrings = (char*)0x0135A8F4; +utf8 *gUserStrings = (char*)0x0135A8F4; static bool user_string_exists(const char *text); @@ -35,10 +37,10 @@ void user_string_clear_all() } /** - * + * * rct2: 0x006C421D */ -rct_string_id user_string_allocate(int base, const char *text) +rct_string_id user_string_allocate(int base, const utf8 *text) { int highBits = (base & 0x7F) << 9; bool allowDuplicates = base & 0x80; @@ -53,7 +55,7 @@ rct_string_id user_string_allocate(int base, const char *text) if (userString[0] != 0) continue; - strncpy(userString, text, USER_STRING_MAX_LENGTH - 1); + safe_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; @@ -61,7 +63,7 @@ rct_string_id user_string_allocate(int base, const char *text) } /** - * + * * rct2: 0x006C42AC */ void user_string_free(rct_string_id id) @@ -73,7 +75,7 @@ void user_string_free(rct_string_id id) gUserStrings[id * USER_STRING_MAX_LENGTH] = 0; } -static bool user_string_exists(const char *text) +static bool user_string_exists(const utf8 *text) { char *userString = gUserStrings; for (int i = 0; i < MAX_USER_STRINGS; i++, userString += USER_STRING_MAX_LENGTH) { @@ -89,4 +91,15 @@ static bool user_string_exists(const char *text) bool is_user_string_id(rct_string_id stringId) { return stringId >= 0x8000 && stringId < 0x9000; -} \ No newline at end of file +} + +void reset_user_strings() +{ + char *userString = gUserStrings; + + for (int i = 0; i < MAX_USER_STRINGS; i++, userString += USER_STRING_MAX_LENGTH) { + userString[0] = 0; + } + + ride_reset_all_names(); +} diff --git a/src/platform/unix.c b/src/localisation/user.h similarity index 69% rename from src/platform/unix.c rename to src/localisation/user.h index e5151df42d..54939ea9a8 100644 --- a/src/platform/unix.c +++ b/src/localisation/user.h @@ -1,9 +1,9 @@ /***************************************************************************** - * Copyright (c) 2014 Ted John + * 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 @@ -18,27 +18,4 @@ * along with this program. If not, see . *****************************************************************************/ -#ifndef _WIN32 -#ifndef __APPLE__ - -#include "../cmdline.h" -#include "../openrct2.h" - -/** - * Unix, linux and fallback entry point to OpenRCT2. - */ -// int main(char *argv[], int argc) -// { -// if (cmdline_run(argv, argc)) -// openrct2_launch(); -// -// return gExitCode; -// } - -char platform_get_path_separator() -{ - return '/'; -} - -#endif -#endif \ No newline at end of file +void reset_user_strings(); diff --git a/src/localisation/utf8.c b/src/localisation/utf8.c new file mode 100644 index 0000000000..e6403e1399 --- /dev/null +++ b/src/localisation/utf8.c @@ -0,0 +1,135 @@ +#include "localisation.h" +#include + +uint32 utf8_get_next(const utf8 *char_ptr, const utf8 **nextchar_ptr) +{ + int result; + int numBytes; + + if (!(char_ptr[0] & 0x80)) { + result = char_ptr[0]; + numBytes = 1; + } else if ((char_ptr[0] & 0xE0) == 0xC0) { + result = ((char_ptr[0] & 0x1F) << 6) | (char_ptr[1] & 0x3F); + numBytes = 2; + } else if ((char_ptr[0] & 0xF0) == 0xE0) { + result = ((char_ptr[0] & 0x0F) << 12) | ((char_ptr[1] & 0x3F) << 6) | (char_ptr[2] & 0x3F); + numBytes = 3; + } else if ((char_ptr[0] & 0xF8) == 0xF0) { + result = ((char_ptr[0] & 0x07) << 18) | ((char_ptr[1] & 0x3F) << 12) | ((char_ptr[1] & 0x3F) << 6) | (char_ptr[2] & 0x3F); + numBytes = 4; + } else { + // TODO 4 bytes + result = ' '; + numBytes = 1; + } + + if (nextchar_ptr != NULL) + *nextchar_ptr = char_ptr + numBytes; + return result; +} + +utf8 *utf8_write_codepoint(utf8 *dst, uint32 codepoint) +{ + if (codepoint <= 0x7F) { + dst[0] = (utf8)codepoint; + return dst + 1; + } else if (codepoint <= 0x7FF) { + dst[0] = 0xC0 | ((codepoint >> 6) & 0x1F); + dst[1] = 0x80 | (codepoint & 0x3F); + return dst + 2; + } else if (codepoint <= 0xFFFF) { + dst[0] = 0xE0 | ((codepoint >> 12) & 0x0F); + dst[1] = 0x80 | ((codepoint >> 6) & 0x3F); + dst[2] = 0x80 | (codepoint & 0x3F); + return dst + 3; + } else { + dst[0] = 0xF0 | ((codepoint >> 18) & 0x07); + dst[1] = 0x80 | ((codepoint >> 12) & 0x3F); + dst[2] = 0x80 | ((codepoint >> 6) & 0x3F); + dst[3] = 0x80 | (codepoint & 0x3F); + return dst + 4; + } +} + +/** + * Inserts the given codepoint at the given address, shifting all characters after along. + * @returns the size of the inserted codepoint. + */ +int utf8_insert_codepoint(utf8 *dst, uint32 codepoint) +{ + int shift = utf8_get_codepoint_length(codepoint); + utf8 *endPoint = get_string_end(dst); + memmove(dst + shift, dst, endPoint - dst + 1); + utf8_write_codepoint(dst, codepoint); + return shift; +} + +bool utf8_is_codepoint_start(utf8 *text) +{ + if ((text[0] & 0x80) == 0) return true; + if ((text[0] & 0xC0) == 0xC0) return true; + return false; +} + +int utf8_get_codepoint_length(int codepoint) +{ + if (codepoint <= 0x7F) { + return 1; + } else if (codepoint <= 0x7FF) { + return 2; + } else if (codepoint <= 0xFFFF) { + return 3; + } else { + return 4; + } +} + +/** + * Gets the number of characters / codepoints in a UTF-8 string (not necessarily 1:1 with bytes and not including null + * terminator). + */ +int utf8_length(const utf8 *text) +{ + int codepoint; + const utf8 *ch = text; + + int count = 0; + while ((codepoint = utf8_get_next(ch, &ch)) != 0) { + count++; + } + return count; +} + +wchar_t *utf8_to_widechar(const utf8 *src) +{ + wchar_t *result = malloc((utf8_length(src) + 1) * sizeof(wchar_t)); + wchar_t *dst = result; + + const utf8 *ch = src; + int codepoint; + while ((codepoint = utf8_get_next(ch, &ch)) != 0) { + if ((uint32)codepoint > 0xFFFF) { + *dst++ = '?'; + } else { + *dst++ = codepoint; + } + } + *dst = 0; + + return result; +} + +utf8 *widechar_to_utf8(const wchar_t *src) +{ + utf8 *result = malloc((wcslen(src) * 4) + 1); + utf8 *dst = result; + + for (; *src != 0; src++) { + dst = utf8_write_codepoint(dst, *src); + } + *dst++ = 0; + + int size = dst - result; + return realloc(result, size); +} diff --git a/src/management/award.c b/src/management/award.c index befba64a15..6eac789f6b 100644 --- a/src/management/award.c +++ b/src/management/award.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 . *****************************************************************************/ @@ -31,7 +31,7 @@ #define NEGATIVE 0 #define POSITIVE 1 -int _awardPositiveMap[] = { +static const uint8 AwardPositiveMap[] = { NEGATIVE, // PARK_AWARD_MOST_UNTIDY POSITIVE, // PARK_AWARD_MOST_TIDY POSITIVE, // PARK_AWARD_BEST_ROLLERCOASTERS @@ -53,9 +53,9 @@ int _awardPositiveMap[] = { rct_award *gCurrentAwards = (rct_award*)RCT2_ADDRESS_AWARD_LIST; -int award_is_positive(int type) +bool award_is_positive(int type) { - return _awardPositiveMap[type]; + return AwardPositiveMap[type]; } #pragma region Award checks @@ -76,7 +76,7 @@ static int award_is_deserved_most_untidy(int awardType, int activeAwardTypes) negativeCount = 0; FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->var_2A != 0) + if (peep->outside_of_park != 0) continue; if (peep->thoughts[0].var_2 > 5) @@ -109,7 +109,7 @@ static int award_is_deserved_most_tidy(int awardType, int activeAwardTypes) positiveCount = 0; negativeCount = 0; FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->var_2A != 0) + if (peep->outside_of_park != 0) continue; if (peep->thoughts[0].var_2 > 5) @@ -183,7 +183,7 @@ static int award_is_deserved_most_beautiful(int awardType, int activeAwardTypes) positiveCount = 0; negativeCount = 0; FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->var_2A != 0) + if (peep->outside_of_park != 0) continue; if (peep->thoughts[0].var_2 > 5) @@ -227,7 +227,7 @@ static int award_is_deserved_safest(int awardType, int activeAwardTypes) peepsWhoDislikeVandalism = 0; FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->var_2A != 0) + if (peep->outside_of_park != 0) continue; if (peep->thoughts[0].var_2 <= 5 && peep->thoughts[0].type == PEEP_THOUGHT_TYPE_VANDALISM) peepsWhoDislikeVandalism++; @@ -238,7 +238,7 @@ static int award_is_deserved_safest(int awardType, int activeAwardTypes) // Check for rides that have crashed maybe? FOR_ALL_RIDES(i, ride) - if (ride->var_1AE != 0) + if (ride->last_crash_type != RIDE_CRASH_TYPE_NONE) return 0; return 1; @@ -290,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 (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_23)) + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_SELLS_FOOD)) continue; shops++; @@ -307,7 +307,7 @@ static int award_is_deserved_best_food(int awardType, int activeAwardTypes) // Count hungry peeps hungryPeeps = 0; FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->var_2A != 0) + if (peep->outside_of_park != 0) continue; if (peep->thoughts[0].var_2 <= 5 && peep->thoughts[0].type == PEEP_THOUGHT_TYPE_HUNGRY) @@ -336,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 (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_23)) + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_SELLS_FOOD)) continue; shops++; @@ -353,7 +353,7 @@ static int award_is_deserved_worst_food(int awardType, int activeAwardTypes) // Count hungry peeps hungryPeeps = 0; FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->var_2A != 0) + if (peep->outside_of_park != 0) continue; if (peep->thoughts[0].var_2 <= 5 && peep->thoughts[0].type == PEEP_THOUGHT_TYPE_HUNGRY) @@ -388,7 +388,7 @@ static int award_is_deserved_best_restrooms(int awardType, int activeAwardTypes) // Count number of guests who are thinking they need the restroom guestsWhoNeedRestroom = 0; FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->var_2A != 0) + if (peep->outside_of_park != 0) continue; if (peep->thoughts[0].var_2 <= 5 && peep->thoughts[0].type == PEEP_THOUGHT_TYPE_BATHROOM) @@ -414,9 +414,9 @@ static int award_is_deserved_most_disappointing(int awardType, int activeAwardTy disappointingRides = 0; FOR_ALL_RIDES(i, ride) { - if (ride->excitement == 0xFFFF || ride->popularity == 0xFF) + if (ride->excitement == (ride_rating)0xFFFF || ride->popularity == 0xFF) continue; - + countedRides++; // Unpopular @@ -463,7 +463,7 @@ static int award_is_deserved_best_custom_designed_rides(int awardType, int activ FOR_ALL_RIDES(i, ride) { if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK)) continue; - if (ride->lifecycle_flags & RIDE_LIFECYCLE_18) + if (ride->lifecycle_flags & RIDE_LIFECYCLE_NOT_CUSTOM_DESIGN) continue; if (ride->excitement < RIDE_RATING(5, 50)) continue; @@ -517,7 +517,7 @@ static int award_is_deserved_most_confusing_layout(int awardType, int activeAwar peepsCounted = 0; peepsLost = 0; FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->var_2A != 0) + if (peep->outside_of_park != 0) continue; peepsCounted++; diff --git a/src/management/award.h b/src/management/award.h index faab09d43c..87e21fd6c3 100644 --- a/src/management/award.h +++ b/src/management/award.h @@ -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 . *****************************************************************************/ @@ -53,7 +53,7 @@ enum { extern rct_award *gCurrentAwards; -int award_is_positive(int type); +bool 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 00db151578..d8231779d9 100644 --- a/src/management/finance.c +++ b/src/management/finance.c @@ -46,6 +46,10 @@ const money32 research_cost_table[4] = { int dword_988E60[] = { 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0 }; +money32 *gCashHistory = RCT2_ADDRESS(RCT2_ADDRESS_BALANCE_HISTORY, money32); +money32 *gWeeklyProfitHistory = RCT2_ADDRESS(RCT2_ADDRESS_WEEKLY_PROFIT_HISTORY, money32); +money32 *gParkValueHistory = RCT2_ADDRESS(RCT2_ADDRESS_PARK_VALUE_HISTORY, money32); + /** * Pay an amount of money. * rct2: 0x069C674 @@ -62,7 +66,7 @@ void finance_payment(money32 amount, rct_expenditure_type type) RCT2_ADDRESS(RCT2_ADDRESS_EXPENDITURE_TABLE, money32)[type] -= amount; if (dword_988E60[type] & 1) RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_EXPENDITURE, money32) -= amount; // Cumulative amount of money spent this day - + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint32) |= BTM_TB_DIRTY_FLAG_MONEY; window_invalidate_by_class(WC_FINANCES); @@ -143,11 +147,10 @@ void finance_pay_ride_upkeep() void finance_reset_history() { - int i; - for (i = 0; i < 128; i++) { - RCT2_ADDRESS(RCT2_ADDRESS_BALANCE_HISTORY, money32)[i] = MONEY32_UNDEFINED; - RCT2_ADDRESS(RCT2_ADDRESS_WEEKLY_PROFIT_HISTORY, money32)[i] = MONEY32_UNDEFINED; - RCT2_ADDRESS(RCT2_ADDRESS_PARK_VALUE_HISTORY, money32)[i] = MONEY32_UNDEFINED; + for (int i = 0; i < 128; i++) { + gCashHistory[i] = MONEY32_UNDEFINED; + gWeeklyProfitHistory[i] = MONEY32_UNDEFINED; + gParkValueHistory[i] = MONEY32_UNDEFINED; } } @@ -168,7 +171,7 @@ void finance_init() { RCT2_GLOBAL(0x01358334, money32) = 0; RCT2_GLOBAL(0x01358338, uint16) = 0; - RCT2_GLOBAL(0x013573DC, money32) = MONEY(10000,00); // Cheat detection + RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32) = MONEY(10000,00); // Cheat detection RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32) = ENCRYPT_MONEY(MONEY(10000,00)); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) = MONEY(10000,00); @@ -185,7 +188,7 @@ void finance_init() { RCT2_GLOBAL(0x013587D8, uint16) = 0x3F; - sub_69E869(); + finance_update_loan_hash(); } /** @@ -240,9 +243,9 @@ void finance_update_daily_profit() window_invalidate_by_class(WC_FINANCES); } -void sub_69E869() +// This subroutine is used to mark loan changes as 'legitimate', to prevent cheat detection from incorrectly interfering +void finance_update_loan_hash() { - // This subroutine is loan related and is used for cheat detection sint32 value = 0x70093A; value -= RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32); value = ror32(value, 5); @@ -311,10 +314,10 @@ void game_command_set_current_loan(int* eax, int* ebx, int* ecx, int* edx, int* 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(); + finance_update_loan_hash(); window_invalidate_by_class(WC_FINANCES); - RCT2_GLOBAL(0x009A9804, uint16) |= 1; + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) |= 1; } *ebx = 0; @@ -347,4 +350,13 @@ void finance_shift_expenditure_table() { } // Invalidate the expenditure table window window_invalidate_by_number(0x1C, 0); -} \ No newline at end of file +} + +/** + * + * rct2: 0x0069E89B + */ +void finance_reset_cash_to_initial() +{ + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, money32) = ENCRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32)); +} diff --git a/src/management/finance.h b/src/management/finance.h index e16d04d787..f0bb67fe90 100644 --- a/src/management/finance.h +++ b/src/management/finance.h @@ -48,6 +48,10 @@ enum { extern const money32 research_cost_table[4]; +extern money32 *gCashHistory; +extern money32 *gWeeklyProfitHistory; +extern money32 *gParkValueHistory; + void finance_payment(money32 amount, rct_expenditure_type type); void finance_pay_wages(); void finance_pay_research(); @@ -57,7 +61,8 @@ void finance_reset_history(); void finance_init(); void finance_update_daily_profit(); void finance_shift_expenditure_table(); -void sub_69E869(); +void finance_update_loan_hash(); +void finance_reset_cash_to_initial(); void finance_set_loan(money32 loan); money32 finance_get_initial_cash(); @@ -66,4 +71,4 @@ 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 +#endif diff --git a/src/management/marketing.c b/src/management/marketing.c index d60a351c73..5eee2c627e 100644 --- a/src/management/marketing.c +++ b/src/management/marketing.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 . *****************************************************************************/ @@ -24,26 +24,27 @@ #include "../localisation/localisation.h" #include "../management/finance.h" #include "../ride/ride.h" +#include "../ride/ride_data.h" #include "marketing.h" #include "news_item.h" const money16 AdvertisingCampaignPricePerWeek[] = { - MONEY(50,00), // PARK_ENTRY_FREE, - MONEY(50,00), // RIDE_FREE, - MONEY(50,00), // PARK_ENTRY_HALF_PRICE, - MONEY(50,00), // FOOD_OR_DRINK_FREE, - MONEY(350,00), // PARK, - MONEY(200,00) // RIDE, + MONEY(50,00), // PARK_ENTRY_FREE + MONEY(50,00), // RIDE_FREE + MONEY(50,00), // PARK_ENTRY_HALF_PRICE + MONEY(50,00), // FOOD_OR_DRINK_FREE + MONEY(350,00), // PARK + MONEY(200,00) // RIDE }; -const int advertisingCampaignGuestGenerationProbabilities[] = { 400, 300, 200, 200, 250, 200 }; +static 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]; + int probability = AdvertisingCampaignGuestGenerationProbabilities[campaign]; rct_ride *ride; // Lower probability of guest generation if price was already low @@ -84,7 +85,7 @@ void marketing_update() gMarketingCampaignDaysLeft[campaign] &= ~CAMPAIGN_ACTIVE_FLAG; if (active) continue; - + if (--gMarketingCampaignDaysLeft[campaign] != 0) continue; @@ -93,13 +94,10 @@ void marketing_update() // This sets the string parameters for the marketing types that have an argument. if (campaign == ADVERTISING_CAMPAIGN_RIDE_FREE || campaign == ADVERTISING_CAMPAIGN_RIDE) { rct_ride* ride = GET_RIDE(campaignItem); - RCT2_GLOBAL(0x013CE952, uint16) = ride->name; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = ride->name; RCT2_GLOBAL(0x013CE954, uint32) = ride->name_arguments; } else if (campaign == ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE) { - campaignItem += 2016; - if (campaignItem >= 2048) - campaignItem += 96; - RCT2_GLOBAL(0x013CE952, uint16) = campaignItem; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = ShopItemStringIds[campaignItem].plural; } news_item_add_to_queue(NEWS_ITEM_MONEY, STR_MARKETING_FINISHED_BASE + campaign, 0); @@ -118,7 +116,7 @@ void marketing_set_guest_campaign(rct_peep *peep, int campaign) peep->voucher_type = VOUCHER_TYPE_RIDE_FREE; peep->voucher_arguments = gMarketingCampaignRideIndex[campaign]; peep->guest_heading_to_ride_id = gMarketingCampaignRideIndex[campaign]; - peep->var_C6 = 240; + peep->peep_is_lost_countdown = 240; break; case ADVERTISING_CAMPAIGN_PARK_ENTRY_HALF_PRICE: peep->item_standard_flags |= PEEP_ITEM_VOUCHER; @@ -133,7 +131,7 @@ void marketing_set_guest_campaign(rct_peep *peep, int campaign) break; case ADVERTISING_CAMPAIGN_RIDE: peep->guest_heading_to_ride_id = gMarketingCampaignRideIndex[campaign]; - peep->var_C6 = 240; + peep->peep_is_lost_countdown = 240; break; } } @@ -145,7 +143,7 @@ void marketing_start_campaign(int type, int rideOrItem, int numWeeks) } /** - * + * * rct2: 0x0069E73C */ void game_command_start_campaign(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) @@ -169,4 +167,49 @@ void game_command_start_campaign(int* eax, int* ebx, int* ecx, int* edx, int* es } *ebx = numWeeks * AdvertisingCampaignPricePerWeek[type]; -} \ No newline at end of file +} + +bool marketing_is_campaign_type_applicable(int campaignType) +{ + int i; + rct_ride *ride; + rct_ride_type *rideEntry; + + switch (campaignType) { + case ADVERTISING_CAMPAIGN_PARK_ENTRY_FREE: + case ADVERTISING_CAMPAIGN_PARK_ENTRY_HALF_PRICE: + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) + return false; + return true; + + case ADVERTISING_CAMPAIGN_RIDE_FREE: + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY)) + return false; + + // fall-through + case ADVERTISING_CAMPAIGN_RIDE: + // Check if any rides exist + FOR_ALL_RIDES(i, ride) { + if (gRideClassifications[ride->type] == RIDE_CLASS_RIDE) { + return true; + } + } + return false; + + case ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE: + // Check if any food or drink stalls exist + FOR_ALL_RIDES(i, ride) { + rideEntry = GET_RIDE_ENTRY(ride->subtype); + if ( + shop_item_is_food_or_drink(rideEntry->shop_item) || + shop_item_is_food_or_drink(rideEntry->shop_item_secondary) + ) { + return true; + } + } + return false; + + default: + return true; + } +} diff --git a/src/management/marketing.h b/src/management/marketing.h index 33abb47560..080289ad9d 100644 --- a/src/management/marketing.h +++ b/src/management/marketing.h @@ -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 . *****************************************************************************/ @@ -52,5 +52,6 @@ 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); +bool marketing_is_campaign_type_applicable(int campaignType); #endif \ No newline at end of file diff --git a/src/management/news_item.c b/src/management/news_item.c index 188f17ba6e..563703eeb7 100644 --- a/src/management/news_item.c +++ b/src/management/news_item.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 . *****************************************************************************/ @@ -26,13 +26,41 @@ #include "../localisation/localisation.h" #include "../ride/ride.h" #include "../world/sprite.h" +#include "../util/util.h" #include "news_item.h" -rct_news_item *newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); - +rct_news_item *gNewsItems = 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(); +bool news_item_is_valid_idx(int index) +{ + if (index > MAX_NEWS_ITEMS) { + log_error("Tried to get news item past MAX_NEWS."); + return false; + } + return true; +} + +rct_news_item *news_item_get(int index) +{ + if (news_item_is_valid_idx(index)) { + return &gNewsItems[index]; + } else { + return NULL; + } +} + +bool news_item_is_empty(int index) +{ + return news_item_get(index)->type == NEWS_ITEM_NULL; +} + +bool news_item_is_queue_empty() +{ + return news_item_is_empty(0); +} + /** * * rct2: 0x0066DF32 @@ -40,24 +68,49 @@ static int news_item_get_new_history_slot(); void news_item_init_queue() { int i; - rct_news_item *newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); - newsItems[0].type = NEWS_ITEM_NULL; - newsItems[11].type = NEWS_ITEM_NULL; + news_item_get(0)->type = NEWS_ITEM_NULL; + news_item_get(11)->type = NEWS_ITEM_NULL; + // Throttles for warning types (PEEP_*_WARNING) for (i = 0; i < 16; i++) RCT2_ADDRESS(0x01358750, uint8)[i] = 0; window_game_bottom_toolbar_invalidate_news_item(); } +static void news_item_tick_current() +{ + int ticks; + ticks = ++news_item_get(0)->ticks; + // Only play news item sound when in normal playing mode + if (ticks == 1 && (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) == SCREEN_FLAGS_PLAYING)) { + // Play sound + audio_play_sound_panned(SOUND_NEWS_ITEM, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2, 0, 0, 0); + } +} + +static bool news_item_is_current_old() +{ + int remove_time = 320; + if (!news_item_is_empty(5) && + !news_item_is_empty(4) && + !news_item_is_empty(3) && + !news_item_is_empty(2)) + remove_time = 256; + + if (news_item_get(0)->ticks >= remove_time) + return true; + + return false; +} + /** - * + * * rct2: 0x0066E252 */ void news_item_update_current() { - short ax, bx, remove_time; - rct_news_item *newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); + short ax, bx; get_system_time(); @@ -71,18 +124,18 @@ void news_item_update_current() bx = 12; if (bx != RCT2_GLOBAL(0x009DEA6B, sint16) || ax != 1) { // loc_66E2AE - RCT2_GLOBAL(0x013573DC, sint32) -= 10000; - if (RCT2_GLOBAL(0x013573DC, sint32) >= 0) - RCT2_GLOBAL(0x013573DC, sint32) = -RCT2_GLOBAL(0x013573DC, sint32); + RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, sint32) -= 10000; + if (RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, sint32) >= 0) + RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, sint32) = -RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, sint32); } } else { if (ax != RCT2_GLOBAL(0x009DEA69, sint16)) { ax--; if (ax != RCT2_GLOBAL(0x009DEA69, sint16)) { // loc_66E2AE - RCT2_GLOBAL(0x013573DC, sint32) -= 10000; - if (RCT2_GLOBAL(0x013573DC, sint32) >= 0) - RCT2_GLOBAL(0x013573DC, sint32) = -RCT2_GLOBAL(0x013573DC, sint32); + RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, sint32) -= 10000; + if (RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, sint32) >= 0) + RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, sint32) = -RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, sint32); } } } @@ -91,32 +144,21 @@ void news_item_update_current() RCT2_GLOBAL(0x009DEA6B, sint16) = RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_MONTH, sint16); // Check if there is a current news item - if (newsItems[0].type == 0) + if (news_item_is_queue_empty()) return; window_game_bottom_toolbar_invalidate_news_item(); // Update the current news item - newsItems[0].ticks++; - if (newsItems[0].ticks == 1 && !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 1)) { - // Play sound - sound_play_panned(SOUND_NEWS_ITEM, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) / 2, 0, 0, 0); - } + news_item_tick_current(); // Removal of current news item - remove_time = 320; - if (newsItems[2].type != 0 && - newsItems[3].type != 0 && - newsItems[4].type != 0 && - newsItems[5].type != 0) - remove_time = 256; - - if (newsItems[0].ticks >= remove_time) + if (news_item_is_current_old()) news_item_close_current(); } /** - * + * * rct2: 0x0066E377 */ void news_item_close_current() @@ -125,7 +167,7 @@ void news_item_close_current() rct_news_item *newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); // Check if there is a current message - if (newsItems[0].type == NEWS_ITEM_NULL) + if (news_item_is_queue_empty()) return; // Find an available history news item slot for current message @@ -135,7 +177,7 @@ void news_item_close_current() newsItems[i] = newsItems[0]; // Set the end of the end of the history list - if (i < 60) + if (i < MAX_NEWS_ITEMS) newsItems[i + 1].type = NEWS_ITEM_NULL; // Invalidate the news window @@ -150,6 +192,15 @@ void news_item_close_current() window_game_bottom_toolbar_invalidate_news_item(); } +static void news_item_shift_history_up() +{ + const int history_idx = 11; + rct_news_item *history_start = news_item_get(history_idx); + const size_t count = sizeof(rct_news_item) * (MAX_NEWS_ITEMS - 1 - history_idx); + memmove(history_start, history_start + 1, count); +} + + /** * Finds a spare history slot or replaces an existing one if there are no spare * slots available. @@ -157,17 +208,15 @@ void news_item_close_current() static int news_item_get_new_history_slot() { int i; - rct_news_item *newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); // Find an available history news item slot - for (i = 11; i < 61; i++) - if (newsItems[i].type == NEWS_ITEM_NULL) + for (i = 11; i < MAX_NEWS_ITEMS; i++) + if (news_item_is_empty(i)) return i; // Dequeue the first history news item, shift history up - for (i = 11; i < 60; i++) - newsItems[i] = newsItems[i + 1]; - return 60; + news_item_shift_history_up(); + return MAX_NEWS_ITEMS - 1; } /** @@ -199,7 +248,7 @@ void news_item_get_subject_location(int type, int subject, int *x, int *y, int * *x = peep->x; *y = peep->y; *z = peep->z; - if (*((uint16*)x) != SPRITE_LOCATION_NULL) + if (*x != SPRITE_LOCATION_NULL) break; if (peep->state != 3 && peep->state != 7) { @@ -250,21 +299,21 @@ void news_item_get_subject_location(int type, int subject, int *x, int *y, int * **/ void news_item_add_to_queue(uint8 type, rct_string_id string_id, uint32 assoc) { - char *buffer = (char*)0x0141EF68; + utf8 *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) +void news_item_add_to_queue_raw(uint8 type, const utf8 *text, uint32 assoc) { int i = 0; rct_news_item *newsItem = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); // find first open slot while (newsItem->type != NEWS_ITEM_NULL) { - if (newsItem + 1 >= (rct_news_item*)0x13CB1CC) + if (newsItem + 1 >= (rct_news_item*)0x13CB1CC) // &news_list[10] news_item_close_current(); else newsItem++; @@ -277,8 +326,7 @@ void news_item_add_to_queue_raw(uint8 type, const char *text, 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; - newsItem->colour = text[0]; - strncpy(newsItem->text, text + 1, 254); + safe_strncpy(newsItem->text, text, 255); newsItem->text[254] = 0; // blatant disregard for what happens on the last element. @@ -335,7 +383,7 @@ void news_item_open_subject(int type, int subject) } } } - + // Switch to new scenery tab window = window_find_by_class(WC_SCENERY); if (window != NULL) @@ -355,27 +403,53 @@ void news_item_open_subject(int type, int subject) } /** - * rct2: 0x0066E407 + * + * 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++; - } +void news_item_disable_news(uint8 type, uint32 assoc) +{ + // TODO: write test invalidating windows + for (int i = 0; i < 11; i++) { + if (!news_item_is_empty(i)) { + rct_news_item * const newsItem = news_item_get(i); + if (type == newsItem->type && assoc == newsItem->assoc) { + newsItem->flags |= 0x1; + if (i == 0) { + window_game_bottom_toolbar_invalidate_news_item(); + } + } + } else { + break; + } + } - 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++; - } + for (int i = 11; i <= MAX_NEWS_ITEMS; i++) { + if (!news_item_is_empty(i)) { + rct_news_item * const newsItem = news_item_get(i); + if (type == newsItem->type && assoc == newsItem->assoc) { + newsItem->flags |= 0x1; + window_invalidate_by_class(WC_RECENT_NEWS); + } + } else { + break; + } + } } +void news_item_add_to_queue_custom(rct_news_item *newNewsItem) +{ + int i = 0; + rct_news_item *newsItem = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); + + // Find first open slot + while (newsItem->type != NEWS_ITEM_NULL) { + if (newsItem + 1 >= (rct_news_item*)0x013CB1CC) + news_item_close_current(); + else + newsItem++; + } + + *newsItem = *newNewsItem; + newsItem++; + newsItem->type = 0; +} diff --git a/src/management/news_item.h b/src/management/news_item.h index 34d4459147..8e1cea3c41 100644 --- a/src/management/news_item.h +++ b/src/management/news_item.h @@ -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 . *****************************************************************************/ @@ -48,17 +48,24 @@ typedef struct { uint16 month_year; // 0x08 uint8 day; // 0x0A uint8 pad_0B; // 0x0B - uint8 colour; // 0x0C - char text[255]; // 0x0D + utf8 text[256]; // 0x0C } rct_news_item; +#define MAX_NEWS_ITEMS 60 + void news_item_init_queue(); 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_add_to_queue_raw(uint8 type, const utf8 *text, uint32 assoc); void news_item_open_subject(int type, int subject); void news_item_disable_news(uint8 type, uint32 assoc); +rct_news_item *news_item_get(int index); +bool news_item_is_empty(int index); +bool news_item_is_queue_empty(); +bool news_item_is_valid_idx(int index); + +void news_item_add_to_queue_custom(rct_news_item *newNewsItem); #endif diff --git a/src/management/research.c b/src/management/research.c index f44ed4c5b2..83df0fd6a1 100644 --- a/src/management/research.c +++ b/src/management/research.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 . *****************************************************************************/ @@ -24,6 +24,9 @@ #include "../localisation/date.h" #include "../management/finance.h" #include "../scenario.h" +#include "../rct1.h" +#include "../ride/ride.h" +#include "../ride/ride_data.h" #include "../world/scenery.h" #include "news_item.h" #include "research.h" @@ -44,7 +47,7 @@ bool gSilentResearch = false; */ void research_reset_items() { - gResearchItems[0].entryIndex = RESEARCHED_ITEMS_SEPERATOR; + gResearchItems[0].entryIndex = RESEARCHED_ITEMS_SEPARATOR; gResearchItems[1].entryIndex = RESEARCHED_ITEMS_END; gResearchItems[2].entryIndex = RESEARCHED_ITEMS_END_2; } @@ -57,7 +60,7 @@ void research_update_uncompleted_types() { int uncompletedResearchTypes = 0; rct_research_item *researchItem = gResearchItems; - while (researchItem++->entryIndex != RESEARCHED_ITEMS_SEPERATOR); + while (researchItem++->entryIndex != RESEARCHED_ITEMS_SEPARATOR); for (; researchItem->entryIndex != RESEARCHED_ITEMS_END; researchItem++) uncompletedResearchTypes |= (1 << researchItem->category); @@ -88,7 +91,7 @@ static void research_calculate_expected_date() expectedDay = currentDay + (daysRemaining & 0xFFFF); dayQuotient = expectedDay / 0x10000; dayRemainder = expectedDay % 0x10000; - + expectedMonth = date_get_month(currentMonth + dayQuotient + (daysRemaining >> 16)); expectedDay = (dayRemainder * days_in_month[expectedMonth]) >> 16; @@ -115,7 +118,7 @@ static void research_next_design() // Skip already researched items firstUnresearchedItem = gResearchItems; - while (firstUnresearchedItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR) + while (firstUnresearchedItem->entryIndex != RESEARCHED_ITEMS_SEPARATOR) firstUnresearchedItem++; ignoreActiveResearchTypes = 0; @@ -145,13 +148,13 @@ static void research_next_design() RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS, uint16) = 0; RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) = RESEARCH_STAGE_DESIGNING; - // Bubble research item up until it is above the researched items seperator + // Bubble research item up until it is above the researched items separator do { tmp = *researchItem; *researchItem = *(researchItem - 1); *(researchItem - 1) = tmp; researchItem--; - } while ((researchItem + 1)->entryIndex != RESEARCHED_ITEMS_SEPERATOR); + } while ((researchItem + 1)->entryIndex != RESEARCHED_ITEMS_SEPARATOR); research_invalidate_related_windows(); } @@ -176,18 +179,18 @@ void research_finish_item(sint32 entryIndex) 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) { + if (RideData4[base_ride_type].flags & RIDE_TYPE_FLAG4_3) { 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->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE)) { + if (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE)) { for (i = 0; i < 128; i++) { rideEntry2 = GET_RIDE_ENTRY(i); if (rideEntry2 == (rct_ride_type*)-1) continue; - if (rideEntry2->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE) + if ((rideEntry2->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE)) continue; if (rideEntry2->ride_type[0] == base_ride_type || rideEntry2->ride_type[1] == base_ride_type || rideEntry2->ride_type[2] == base_ride_type) @@ -197,7 +200,7 @@ 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) = rideEntry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME ? + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, rct_string_id) = ((rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME)) ? rideEntry->name : base_ride_type + 2; if (!gSilentResearch) news_item_add_to_queue(NEWS_ITEM_RESEARCH, 2249, entryIndex); @@ -214,7 +217,7 @@ 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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, rct_string_id) = scenerySetEntry->name; if (!gSilentResearch) news_item_add_to_queue(NEWS_ITEM_RESEARCH, 2250, entryIndex); } @@ -281,10 +284,10 @@ void sub_684AC3(){ for (; research->entryIndex != RESEARCHED_ITEMS_END_2; research += 2){ if (scenario_rand() & 1) continue; - rct_research_item* edx; - rct_research_item* ebp; + rct_research_item* edx = NULL; + rct_research_item* ebp = NULL; rct_research_item* inner_research = gResearchItems; - do{ + do { if (research->entryIndex == inner_research->entryIndex){ edx = inner_research; } @@ -292,11 +295,13 @@ void sub_684AC3(){ ebp = inner_research; } } while ((inner_research++)->entryIndex != RESEARCHED_ITEMS_END); + assert(edx != NULL); edx->entryIndex = research->entryIndex; + assert(ebp != NULL); ebp->entryIndex = (research + 1)->entryIndex; uint8 cat = edx->category; - edx->category = ebp->category; + edx->category = ebp->category; ebp->category = cat; } @@ -319,8 +324,8 @@ void sub_684AC3(){ } } - - for (research = gResearchItems; research->entryIndex != RESEARCHED_ITEMS_SEPERATOR; research++){ + + for (research = gResearchItems; research->entryIndex != RESEARCHED_ITEMS_SEPARATOR; research++){ research_finish_item(research->entryIndex); } @@ -346,25 +351,21 @@ void research_remove_non_separate_vehicle_types() loopBeginning: if ( researchItem != gResearchItems && - researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR && + researchItem->entryIndex != RESEARCHED_ITEMS_SEPARATOR && researchItem->entryIndex != RESEARCHED_ITEMS_END && - researchItem->entryIndex >= 0x10000 + 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))) { + if (!(rideEntry->flags & (RIDE_ENTRY_FLAG_SEPARATE_RIDE | RIDE_ENTRY_FLAG_SEPARATE_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 != RESEARCHED_ITEMS_SEPARATOR && 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 (!(rideEntry->flags & (RIDE_ENTRY_FLAG_SEPARATE_RIDE | RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME))) { if (((researchItem->entryIndex >> 8) & 0xFF) == ((researchItem2->entryIndex >> 8) & 0xFF)) { // Remove item @@ -416,9 +417,15 @@ static void research_insert_researched(int entryIndex, int category) { rct_research_item *researchItem, *researchItem2; + researchItem = gResearchItems; + // First check to make sure that entry is not already accounted for + for (; researchItem->entryIndex != RESEARCHED_ITEMS_END; researchItem++) { + if (researchItem->entryIndex == entryIndex) + return; + } researchItem = gResearchItems; do { - if (researchItem->entryIndex == RESEARCHED_ITEMS_SEPERATOR) { + if (researchItem->entryIndex == RESEARCHED_ITEMS_SEPARATOR) { // Insert slot researchItem2 = researchItem; while (researchItem2->entryIndex != RESEARCHED_ITEMS_END_2) { @@ -434,6 +441,18 @@ static void research_insert_researched(int entryIndex, int category) } while (entryIndex != (researchItem++)->entryIndex); } +/* rct2: 0x006857CF */ +void research_remove(sint32 entryIndex){ + for (rct_research_item *researchItem = gResearchItems; researchItem->entryIndex != RESEARCHED_ITEMS_END; researchItem++){ + if (researchItem->entryIndex == entryIndex){ + do{ + *researchItem = *(researchItem + 1); + } while (researchItem++->entryIndex != RESEARCHED_ITEMS_END_2); + return; + } + } +} + void research_insert(int researched, int entryIndex, int category) { if (researched) @@ -539,4 +558,4 @@ void game_command_set_research_funding(int* eax, int* ebx, int* ecx, int* edx, i } *ebx = 0; -} \ No newline at end of file +} diff --git a/src/management/research.h b/src/management/research.h index e26725b6db..f8cf061082 100644 --- a/src/management/research.h +++ b/src/management/research.h @@ -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 . *****************************************************************************/ @@ -29,14 +29,14 @@ typedef struct { uint8 category; } rct_research_item; -enum{ +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_SEPARATOR -1 +// Everything before this point and after separator still requires research #define RESEARCHED_ITEMS_END -2 // Extra end of list entry. Unsure why? #define RESEARCHED_ITEMS_END_2 -3 @@ -83,5 +83,6 @@ 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); +void research_remove(sint32 entryIndex); -#endif \ No newline at end of file +#endif diff --git a/src/network/http.cpp b/src/network/http.cpp index a2ad158bec..29392b73d6 100644 --- a/src/network/http.cpp +++ b/src/network/http.cpp @@ -1,5 +1,6 @@ extern "C" { #include "http.h" + #include "../platform/platform.h" } #ifdef DISABLE_HTTP @@ -10,8 +11,18 @@ void http_dispose() { } #else #include + +// cURL includes windows.h, but we don't need all of it. +#define WIN32_LEAN_AND_MEAN #include -#include + +#define MIME_TYPE_APPLICATION_JSON "application/json" + +typedef struct { + char *ptr; + int length; + int position; +} read_buffer; typedef struct { char *ptr; @@ -29,6 +40,22 @@ void http_dispose() curl_global_cleanup(); } +static size_t http_request_read_func(void *ptr, size_t size, size_t nmemb, void *userdata) +{ + read_buffer *readBuffer = (read_buffer*)userdata; + + size_t remainingBytes = readBuffer->length - readBuffer->position; + size_t readBytes = size * nmemb; + if (readBytes > remainingBytes) { + readBytes = remainingBytes; + } + + memcpy(ptr, readBuffer->ptr + readBuffer->position, readBytes); + + readBuffer->position += readBytes; + return readBytes; +} + static size_t http_request_write_func(void *ptr, size_t size, size_t nmemb, void *userdata) { write_buffer *writeBuffer = (write_buffer*)userdata; @@ -51,29 +78,58 @@ static size_t http_request_write_func(void *ptr, size_t size, size_t nmemb, void return newBytesLength; } -http_json_response *http_request_json(const char *url) +http_json_response *http_request_json(const http_json_request *request) { CURL *curl; CURLcode curlResult; http_json_response *response; + read_buffer readBuffer; write_buffer writeBuffer; curl = curl_easy_init(); if (curl == NULL) return NULL; + if (request->body != NULL) { + readBuffer.ptr = json_dumps(request->body, JSON_COMPACT); + readBuffer.length = strlen(readBuffer.ptr); + readBuffer.position = 0; + } + 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_slist *headers = NULL; + headers = curl_slist_append(headers, "Accept: " MIME_TYPE_APPLICATION_JSON); + if (request->body != NULL) { + headers = curl_slist_append(headers, "Content-Type: " MIME_TYPE_APPLICATION_JSON); + + char contentLengthHeaderValue[64]; + snprintf(contentLengthHeaderValue, sizeof(contentLengthHeaderValue), "Content-Length: %d", readBuffer.length); + headers = curl_slist_append(headers, contentLengthHeaderValue); + + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, readBuffer.ptr); + } + + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, request->method); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true); +#ifndef __linux__ + // On GNU/Linux, curl will use the system certs by default curl_easy_setopt(curl, CURLOPT_CAINFO, "curl-ca-bundle.crt"); - curl_easy_setopt(curl, CURLOPT_URL, url); +#endif + curl_easy_setopt(curl, CURLOPT_URL, request->url); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &writeBuffer); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_request_write_func); curlResult = curl_easy_perform(curl); + + if (request->body != NULL) { + free(readBuffer.ptr); + } + if (curlResult != CURLE_OK) { log_error("HTTP request failed: %s.", curl_easy_strerror(curlResult)); if (writeBuffer.ptr != NULL) @@ -108,24 +164,27 @@ http_json_response *http_request_json(const char *url) return response; } -void http_request_json_async(const char *url, void (*callback)(http_json_response*)) +void http_request_json_async(const http_json_request *request, void (*callback)(http_json_response*)) { struct TempThreadArgs { - char *url; + http_json_request request; void (*callback)(http_json_response*); }; TempThreadArgs *args = (TempThreadArgs*)malloc(sizeof(TempThreadArgs)); - args->url = _strdup(url); + args->request.url = _strdup(request->url); + args->request.method = request->method; + args->request.body = json_deep_copy(request->body); args->callback = callback; SDL_Thread *thread = SDL_CreateThread([](void *ptr) -> int { TempThreadArgs *args = (TempThreadArgs*)ptr; - http_json_response *response = http_request_json(args->url); + http_json_response *response = http_request_json(&args->request); args->callback(response); - free(args->url); + free((char*)args->request.url); + json_decref((json_t*)args->request.body); free(args); return 0; }, NULL, args); @@ -146,4 +205,4 @@ void http_request_json_dispose(http_json_response *response) free(response); } -#endif \ No newline at end of file +#endif diff --git a/src/network/http.h b/src/network/http.h index ffc051a235..3df1903fc6 100644 --- a/src/network/http.h +++ b/src/network/http.h @@ -1,18 +1,33 @@ #ifndef _HTTP_H_ #define _HTTP_H_ -#include +#ifndef DISABLE_HTTP +#include #include "../common.h" +typedef struct { + const char *method; + const char *url; + const json_t *body; +} http_json_request; + typedef struct { int status_code; json_t *root; } http_json_response; +#define HTTP_METHOD_GET "GET" +#define HTTP_METHOD_POST "POST" +#define HTTP_METHOD_PUT "PUT" +#define HTTP_METHOD_DELETE "DELETE" + +http_json_response *http_request_json(const http_json_request *request); +void http_request_json_async(const http_json_request *request, void (*callback)(http_json_response*)); +void http_request_json_dispose(http_json_response *response); +#endif // DISABLE_HTTP + +// These callbacks are defined anyway, but are dummy if HTTP is disabled 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/network.cpp b/src/network/network.cpp new file mode 100644 index 0000000000..265da30a25 --- /dev/null +++ b/src/network/network.cpp @@ -0,0 +1,1651 @@ +/***************************************************************************** + * 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 . + *****************************************************************************/ + +extern "C" { +#include "../openrct2.h" +#include "../platform/platform.h" +} + +#include "network.h" + +extern "C" { +#include "../addresses.h" +} + +#ifndef DISABLE_NETWORK + +#include +#include +#include +#include +#include +extern "C" { +#include "../config.h" +#include "../game.h" +#include "../interface/chat.h" +#include "../interface/window.h" +#include "../localisation/date.h" +#include "../localisation/localisation.h" +#include "../network/http.h" +#include "../scenario.h" +#include "../windows/error.h" +#include "../util/util.h" +} + +#pragma comment(lib, "Ws2_32.lib") + +Network gNetwork; + +enum { + NETWORK_READPACKET_SUCCESS, + NETWORK_READPACKET_NO_DATA, + NETWORK_READPACKET_MORE_DATA, + NETWORK_READPACKET_DISCONNECTED +}; + +enum { + NETWORK_COMMAND_AUTH, + NETWORK_COMMAND_MAP, + NETWORK_COMMAND_CHAT, + NETWORK_COMMAND_GAMECMD, + NETWORK_COMMAND_TICK, + NETWORK_COMMAND_PLAYERLIST, + NETWORK_COMMAND_PING, + NETWORK_COMMAND_PINGLIST, + NETWORK_COMMAND_SETDISCONNECTMSG, + NETWORK_COMMAND_GAMEINFO, + NETWORK_COMMAND_MAX, + NETWORK_COMMAND_INVALID = -1 +}; + +const char *NetworkCommandNames[] = { + "NETWORK_COMMAND_AUTH", + "NETWORK_COMMAND_MAP", + "NETWORK_COMMAND_CHAT", + "NETWORK_COMMAND_GAMECMD", + "NETWORK_COMMAND_TICK", + "NETWORK_COMMAND_PLAYERLIST", + "NETWORK_COMMAND_PING", + "NETWORK_COMMAND_PINGLIST", +}; + +enum { + ADVERTISE_STATUS_DISABLED, + ADVERTISE_STATUS_UNREGISTERED, + ADVERTISE_STATUS_REGISTERED +}; + +enum { + MASTER_SERVER_STATUS_OK = 200, + MASTER_SERVER_STATUS_INVALID_TOKEN = 401, + MASTER_SERVER_STATUS_SERVER_NOT_FOUND = 404, + MASTER_SERVER_STATUS_INTERNAL_ERROR = 500 +}; + +constexpr int MASTER_SERVER_REGISTER_TIME = 120 * 1000; // 2 minutes +constexpr int MASTER_SERVER_HEARTBEAT_TIME = 60 * 1000; // 1 minute + +NetworkPacket::NetworkPacket() +{ + transferred = 0; + read = 0; + size = 0; + data = std::make_shared>(); +} + +std::unique_ptr NetworkPacket::Allocate() +{ + return std::unique_ptr(new NetworkPacket); // change to make_unique in c++14 +} + +std::unique_ptr NetworkPacket::Duplicate(NetworkPacket& packet) +{ + return std::unique_ptr(new NetworkPacket(packet)); // change to make_unique in c++14 +} + +uint8* NetworkPacket::GetData() +{ + return &(*data)[0]; +} + +uint32 NetworkPacket::GetCommand() +{ + if (data->size() >= sizeof(uint32)) { + return ByteSwapBE(*(uint32*)(&(*data)[0])); + } else { + return NETWORK_COMMAND_INVALID; + } +} + +void NetworkPacket::Write(uint8* bytes, unsigned int size) +{ + data->insert(data->end(), bytes, bytes + size); +} + +void NetworkPacket::WriteString(const char* string) +{ + Write((uint8*)string, strlen(string) + 1); +} + +const uint8* NetworkPacket::Read(unsigned int size) +{ + if (read + size > NetworkPacket::size) { + return 0; + } else { + uint8* data = &GetData()[read]; + read += size; + return data; + } +} + +const char* NetworkPacket::ReadString() +{ + char* str = (char*)&GetData()[read]; + char* strend = str; + while (read < size && *strend != 0) { + read++; + strend++; + } + if (*strend != 0) { + return 0; + } + read++; + return str; +} + +void NetworkPacket::Clear() +{ + transferred = 0; + read = 0; + data->clear(); +} + +bool NetworkPacket::CommandRequiresAuth() +{ + switch (GetCommand()) { + case NETWORK_COMMAND_PING: + case NETWORK_COMMAND_AUTH: + case NETWORK_COMMAND_GAMEINFO: + return false; + default: + return true; + } +} + +NetworkPlayer::NetworkPlayer(const char* name) +{ + safe_strncpy((char*)NetworkPlayer::name, name, sizeof(NetworkPlayer::name)); + NetworkPlayer::name[sizeof(NetworkPlayer::name) - 1] = 0; + ping = 0; + flags = 0; +} + +NetworkConnection::NetworkConnection() +{ + authstatus = NETWORK_AUTH_NONE; + player = 0; + socket = INVALID_SOCKET; + ResetLastPacketTime(); + last_disconnect_reason = NULL; +} + +NetworkConnection::~NetworkConnection() +{ + if (socket != INVALID_SOCKET) { + closesocket(socket); + } +} + +int NetworkConnection::ReadPacket() +{ + if (inboundpacket.transferred < sizeof(inboundpacket.size)) { + // read packet size + int readBytes = recv(socket, &((char*)&inboundpacket.size)[inboundpacket.transferred], sizeof(inboundpacket.size) - inboundpacket.transferred, 0); + if (readBytes == SOCKET_ERROR || readBytes == 0) { + if (LAST_SOCKET_ERROR() != EWOULDBLOCK && LAST_SOCKET_ERROR() != EAGAIN) { + return NETWORK_READPACKET_DISCONNECTED; + } else { + return NETWORK_READPACKET_NO_DATA; + } + } + inboundpacket.transferred += readBytes; + if (inboundpacket.transferred == sizeof(inboundpacket.size)) { + inboundpacket.size = ntohs(inboundpacket.size); + if(inboundpacket.size == 0){ // Can't have a size 0 packet + return NETWORK_READPACKET_DISCONNECTED; + } + inboundpacket.data->resize(inboundpacket.size); + } + } else { + // read packet data + if (inboundpacket.data->capacity() > 0) { + int readBytes = recv(socket, (char*)&inboundpacket.GetData()[inboundpacket.transferred - sizeof(inboundpacket.size)], sizeof(inboundpacket.size) + inboundpacket.size - inboundpacket.transferred, 0); + if (readBytes == SOCKET_ERROR || readBytes == 0) { + if (LAST_SOCKET_ERROR() != EWOULDBLOCK && LAST_SOCKET_ERROR() != EAGAIN) { + return NETWORK_READPACKET_DISCONNECTED; + } else { + return NETWORK_READPACKET_NO_DATA; + } + } + inboundpacket.transferred += readBytes; + } + if (inboundpacket.transferred == sizeof(inboundpacket.size) + inboundpacket.size) { + last_packet_time = SDL_GetTicks(); + return NETWORK_READPACKET_SUCCESS; + } + } + return NETWORK_READPACKET_MORE_DATA; +} + +bool NetworkConnection::SendPacket(NetworkPacket& packet) +{ + uint16 sizen = htons(packet.size); + std::vector tosend; + tosend.reserve(sizeof(sizen) + packet.size); + tosend.insert(tosend.end(), (uint8*)&sizen, (uint8*)&sizen + sizeof(sizen)); + tosend.insert(tosend.end(), packet.data->begin(), packet.data->end()); + while (1) { + int sentBytes = send(socket, (const char*)&tosend[packet.transferred], tosend.size() - packet.transferred, 0); + if (sentBytes == SOCKET_ERROR) { + return false; + } + packet.transferred += sentBytes; + if (packet.transferred == tosend.size()) { + return true; + } + } + return false; +} + +void NetworkConnection::QueuePacket(std::unique_ptr packet, bool front) +{ + if (authstatus == NETWORK_AUTH_OK || !packet->CommandRequiresAuth()) { + packet->size = (uint16)packet->data->size(); + if (front) { + outboundpackets.push_front(std::move(packet)); + } else { + outboundpackets.push_back(std::move(packet)); + } + } +} + +void NetworkConnection::SendQueuedPackets() +{ + while (outboundpackets.size() > 0 && SendPacket(*(outboundpackets.front()).get())) { + outboundpackets.remove(outboundpackets.front()); + } +} + +bool NetworkConnection::SetTCPNoDelay(bool on) +{ + return setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(on)) == 0; +} + +bool NetworkConnection::SetNonBlocking(bool on) +{ + return SetNonBlocking(socket, on); +} + +bool NetworkConnection::SetNonBlocking(SOCKET socket, bool on) +{ +#ifdef _WIN32 + u_long nonblocking = on; + return ioctlsocket(socket, FIONBIO, &nonblocking) == 0; +#else + int flags = fcntl(socket, F_GETFL, 0); + return fcntl(socket, F_SETFL, on ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK)) == 0; +#endif +} + +void NetworkConnection::ResetLastPacketTime() +{ + last_packet_time = SDL_GetTicks(); +} + +bool NetworkConnection::ReceivedPacketRecently() +{ + if (SDL_TICKS_PASSED(SDL_GetTicks(), last_packet_time + 7000)) { + return false; + } + return true; +} + +NetworkAddress::NetworkAddress() +{ + ss = std::make_shared(); + ss_len = std::make_shared(); + status = std::make_shared(); + *status = RESOLVE_NONE; +} + +void NetworkAddress::Resolve(const char* host, unsigned short port, bool nonblocking) +{ + // A non-blocking hostname resolver + *status = RESOLVE_INPROGRESS; + mutex = SDL_CreateMutex(); + cond = SDL_CreateCond(); + NetworkAddress::host = host; + NetworkAddress::port = port; + SDL_LockMutex(mutex); + SDL_Thread* thread = SDL_CreateThread(ResolveFunc, 0, this); + // The mutex/cond is to make sure ResolveFunc doesn't ever get a dangling pointer + SDL_CondWait(cond, mutex); + SDL_UnlockMutex(mutex); + SDL_DestroyCond(cond); + SDL_DestroyMutex(mutex); + if (!nonblocking) { + int status; + SDL_WaitThread(thread, &status); + } +} + +int NetworkAddress::GetResolveStatus(void) +{ + return *status; +} + +int NetworkAddress::ResolveFunc(void* pointer) +{ + // Copy data for thread safety + NetworkAddress * networkaddress = (NetworkAddress*)pointer; + SDL_LockMutex(networkaddress->mutex); + std::string host; + if (networkaddress->host) host = networkaddress->host; + std::string port = std::to_string(networkaddress->port); + std::shared_ptr ss = networkaddress->ss; + std::shared_ptr ss_len = networkaddress->ss_len; + std::shared_ptr status = networkaddress->status; + SDL_CondSignal(networkaddress->cond); + SDL_UnlockMutex(networkaddress->mutex); + + // Perform the resolve + addrinfo hints; + addrinfo* res; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + if (host.length() == 0) { + hints.ai_flags = AI_PASSIVE; + } + getaddrinfo(host.length() == 0 ? NULL : host.c_str(), port.c_str(), &hints, &res); + if (res) { + memcpy(&(*ss), res->ai_addr, res->ai_addrlen); + *ss_len = res->ai_addrlen; + *status = RESOLVE_OK; + freeaddrinfo(res); + } else { + *status = RESOLVE_FAILED; + } + return 0; +} + +Network::Network() +{ + wsa_initialized = false; + mode = NETWORK_MODE_NONE; + status = NETWORK_STATUS_NONE; + last_tick_sent_time = 0; + last_ping_sent_time = 0; + last_advertise_time = 0; + client_command_handlers.resize(NETWORK_COMMAND_MAX, 0); + client_command_handlers[NETWORK_COMMAND_AUTH] = &Network::Client_Handle_AUTH; + client_command_handlers[NETWORK_COMMAND_MAP] = &Network::Client_Handle_MAP; + client_command_handlers[NETWORK_COMMAND_CHAT] = &Network::Client_Handle_CHAT; + client_command_handlers[NETWORK_COMMAND_GAMECMD] = &Network::Client_Handle_GAMECMD; + client_command_handlers[NETWORK_COMMAND_TICK] = &Network::Client_Handle_TICK; + client_command_handlers[NETWORK_COMMAND_PLAYERLIST] = &Network::Client_Handle_PLAYERLIST; + client_command_handlers[NETWORK_COMMAND_PING] = &Network::Client_Handle_PING; + client_command_handlers[NETWORK_COMMAND_PINGLIST] = &Network::Client_Handle_PINGLIST; + client_command_handlers[NETWORK_COMMAND_SETDISCONNECTMSG] = &Network::Client_Handle_SETDISCONNECTMSG; + server_command_handlers.resize(NETWORK_COMMAND_MAX, 0); + server_command_handlers[NETWORK_COMMAND_AUTH] = &Network::Server_Handle_AUTH; + server_command_handlers[NETWORK_COMMAND_CHAT] = &Network::Server_Handle_CHAT; + server_command_handlers[NETWORK_COMMAND_GAMECMD] = &Network::Server_Handle_GAMECMD; + server_command_handlers[NETWORK_COMMAND_PING] = &Network::Server_Handle_PING; + server_command_handlers[NETWORK_COMMAND_GAMEINFO] = &Network::Server_Handle_GAMEINFO; +} + +Network::~Network() +{ + Close(); +} + +bool Network::Init() +{ +#ifdef _WIN32 + if (!wsa_initialized) { + log_verbose("Initialising WSA"); + WSADATA wsa_data; + if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) { + log_error("Unable to initialise winsock."); + return false; + } + wsa_initialized = true; + } +#endif + status = NETWORK_STATUS_READY; + return true; +} + +void Network::Close() +{ + if (status == NETWORK_STATUS_NONE) + { + // Already closed. This prevents a call in ~Network() to gfx_invalidate_screen() + // which may no longer be valid on Linux and would cause a segfault. + return; + } + if (mode == NETWORK_MODE_CLIENT) { + closesocket(server_connection.socket); + } else + if (mode == NETWORK_MODE_SERVER) { + closesocket(listening_socket); + } + + mode = NETWORK_MODE_NONE; + status = NETWORK_STATUS_NONE; + server_connection.authstatus = NETWORK_AUTH_NONE; + server_connection.last_disconnect_reason = NULL; + + client_connection_list.clear(); + game_command_queue.clear(); + player_list.clear(); + +#ifdef _WIN32 + if (wsa_initialized) { + WSACleanup(); + wsa_initialized = false; + } +#endif + + gfx_invalidate_screen(); +} + +bool Network::BeginClient(const char* host, unsigned short port) +{ + if (GetMode() != NETWORK_MODE_NONE) { + return false; + } + + Close(); + if (!Init()) + return false; + + server_address.Resolve(host, port); + status = NETWORK_STATUS_RESOLVING; + + window_network_status_open("Resolving..."); + + mode = NETWORK_MODE_CLIENT; + + return true; +} + +bool Network::BeginServer(unsigned short port, const char* address) +{ + Close(); + if (!Init()) + return false; + + NetworkAddress networkaddress; + networkaddress.Resolve(address, port, false); + + log_verbose("Begin listening for clients"); + listening_socket = socket(networkaddress.ss->ss_family, SOCK_STREAM, IPPROTO_TCP); + if (listening_socket == INVALID_SOCKET) { + log_error("Unable to create socket."); + return false; + } + + // Turn off IPV6_V6ONLY so we can accept both v4 and v6 connections + int value = 0; + if (setsockopt(listening_socket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&value, sizeof(value)) != 0) { + log_error("IPV6_V6ONLY failed. %d", LAST_SOCKET_ERROR()); + } + + if (bind(listening_socket, (sockaddr*)&(*networkaddress.ss), (*networkaddress.ss_len)) != 0) { + closesocket(listening_socket); + log_error("Unable to bind to socket."); + return false; + } + + if (listen(listening_socket, SOMAXCONN) != 0) { + closesocket(listening_socket); + log_error("Unable to listen on socket."); + return false; + } + + if (!NetworkConnection::SetNonBlocking(listening_socket, true)) { + closesocket(listening_socket); + log_error("Failed to set non-blocking mode."); + return false; + } + + NetworkPlayer* player = AddPlayer(gConfigNetwork.player_name); + player->flags |= NETWORK_PLAYER_FLAG_ISSERVER; + player_id = player->id; + + printf("Ready for clients...\n"); + + mode = NETWORK_MODE_SERVER; + status = NETWORK_STATUS_CONNECTED; + listening_port = port; + advertise_status = ADVERTISE_STATUS_DISABLED; + last_advertise_time = 0; + last_heartbeat_time = 0; + advertise_token = ""; + advertise_key = GenerateAdvertiseKey(); + +#ifndef DISABLE_HTTP + if (gConfigNetwork.advertise) { + advertise_status = ADVERTISE_STATUS_UNREGISTERED; + } +#endif + return true; +} + +int Network::GetMode() +{ + return mode; +} + +int Network::GetStatus() +{ + return status; +} + +int Network::GetAuthStatus() +{ + if (GetMode() == NETWORK_MODE_CLIENT) { + return server_connection.authstatus; + } else + if (GetMode() == NETWORK_MODE_SERVER) { + return NETWORK_AUTH_OK; + } + return NETWORK_AUTH_NONE; +} + +uint32 Network::GetServerTick() +{ + return server_tick; +} + +uint8 Network::GetPlayerID() +{ + return player_id; +} + +void Network::Update() +{ + switch (GetMode()) { + case NETWORK_MODE_SERVER: + UpdateServer(); + break; + case NETWORK_MODE_CLIENT: + UpdateClient(); + break; + } +} + +void Network::UpdateServer() +{ + auto it = client_connection_list.begin(); + while (it != client_connection_list.end()) { + if (!ProcessConnection(*(*it))) { + RemoveClient((*it)); + it = client_connection_list.begin(); + } else { + it++; + } + } + if (SDL_TICKS_PASSED(SDL_GetTicks(), last_tick_sent_time + 25)) { + Server_Send_TICK(); + } + if (SDL_TICKS_PASSED(SDL_GetTicks(), last_ping_sent_time + 3000)) { + Server_Send_PING(); + Server_Send_PINGLIST(); + } + + switch (advertise_status) { + case ADVERTISE_STATUS_UNREGISTERED: + if (last_advertise_time == 0 || SDL_TICKS_PASSED(SDL_GetTicks(), last_advertise_time + MASTER_SERVER_REGISTER_TIME)) { + AdvertiseRegister(); + } + break; + case ADVERTISE_STATUS_REGISTERED: + if (SDL_TICKS_PASSED(SDL_GetTicks(), last_heartbeat_time + MASTER_SERVER_HEARTBEAT_TIME)) { + AdvertiseHeartbeat(); + } + break; + } + + SOCKET socket = accept(listening_socket, NULL, NULL); + if (socket == INVALID_SOCKET) { + if (LAST_SOCKET_ERROR() != EWOULDBLOCK) { + PrintError(); + log_error("Failed to accept client."); + } + } else { + if (!NetworkConnection::SetNonBlocking(socket, true)) { + closesocket(socket); + log_error("Failed to set non-blocking mode."); + } else { + AddClient(socket); + } + } +} + +void Network::UpdateClient() +{ + bool connectfailed = false; + switch(status){ + case NETWORK_STATUS_RESOLVING:{ + if (server_address.GetResolveStatus() == NetworkAddress::RESOLVE_OK) { + server_connection.socket = socket(server_address.ss->ss_family, SOCK_STREAM, IPPROTO_TCP); + if (server_connection.socket == INVALID_SOCKET) { + log_error("Unable to create socket."); + connectfailed = true; + break; + } + + server_connection.SetTCPNoDelay(true); + if (!server_connection.SetNonBlocking(true)) { + log_error("Failed to set non-blocking mode."); + connectfailed = true; + break; + } + + if (connect(server_connection.socket, (sockaddr *)&(*server_address.ss), (*server_address.ss_len)) == SOCKET_ERROR && (LAST_SOCKET_ERROR() == EINPROGRESS || LAST_SOCKET_ERROR() == EWOULDBLOCK)){ + window_network_status_open("Connecting..."); + server_connect_time = SDL_GetTicks(); + status = NETWORK_STATUS_CONNECTING; + } else { + log_error("connect() failed %d", LAST_SOCKET_ERROR()); + connectfailed = true; + break; + } + } else { + log_error("Could not resolve address."); + connectfailed = true; + } + }break; + case NETWORK_STATUS_CONNECTING:{ + int error = 0; + socklen_t len = sizeof(error); + int result = getsockopt(server_connection.socket, SOL_SOCKET, SO_ERROR, (char*)&error, &len); + if (result != 0) { + log_error("getsockopt failed with error %d", LAST_SOCKET_ERROR()); + break; + } + if (error != 0) { + log_error("Connection failed %d", error); + connectfailed = true; + break; + } + if (SDL_TICKS_PASSED(SDL_GetTicks(), server_connect_time + 3000)) { + log_error("Connection timed out."); + connectfailed = true; + break; + } + fd_set writeFD; + FD_ZERO(&writeFD); + FD_SET(server_connection.socket, &writeFD); + timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + if (select(server_connection.socket + 1, NULL, &writeFD, NULL, &timeout) > 0) { + error = 0; + socklen_t len = sizeof(error); + result = getsockopt(server_connection.socket, SOL_SOCKET, SO_ERROR, (char*)&error, &len); + if (result != 0) { + log_error("getsockopt failed with error %d", LAST_SOCKET_ERROR()); + break; + } + if (error == 0) { + status = NETWORK_STATUS_CONNECTED; + server_connection.ResetLastPacketTime(); + Client_Send_AUTH(gConfigNetwork.player_name, ""); + window_network_status_open("Authenticating..."); + } + } + }break; + case NETWORK_STATUS_CONNECTED: + if (!ProcessConnection(server_connection)) { + std::string errormsg = "Disconnected"; + if (server_connection.last_disconnect_reason) { + errormsg += ": "; + errormsg += server_connection.last_disconnect_reason; + } + if (server_connection.authstatus == NETWORK_AUTH_REQUIREPASSWORD) { // Do not show disconnect message window when password window closed/canceled + window_network_status_close(); + } else { + window_network_status_open(errormsg.c_str()); + } + Close(); + } + ProcessGameCommandQueue(); + + // Check synchronisation + if (!_desynchronised && !CheckSRAND(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32), RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, uint32))) { + _desynchronised = true; + window_network_status_open("Network desync detected"); + if (!gConfigNetwork.stay_connected) { + Close(); + } + } + break; + } + + if (connectfailed) { + Close(); + window_network_status_close(); + window_error_open(STR_UNABLE_TO_CONNECT_TO_SERVER, STR_NONE); + } +} + +NetworkPlayer* Network::GetPlayerByID(int id) { + auto it = std::find_if(player_list.begin(), player_list.end(), [&id](std::unique_ptr const& player) { return player->id == id; }); + if (it != player_list.end()) { + return (*it).get(); + } + return 0; +} + +const char* Network::FormatChat(NetworkPlayer* fromplayer, const char* text) +{ + static char formatted[1024]; + char* lineCh = formatted; + formatted[0] = 0; + if (fromplayer) { + lineCh = utf8_write_codepoint(lineCh, FORMAT_OUTLINE); + lineCh = utf8_write_codepoint(lineCh, FORMAT_BABYBLUE); + safe_strncpy(lineCh, (const char*)fromplayer->name, sizeof(fromplayer->name)); + strcat(lineCh, ": "); + lineCh = strchr(lineCh, '\0'); + } + lineCh = utf8_write_codepoint(lineCh, FORMAT_OUTLINE); + lineCh = utf8_write_codepoint(lineCh, FORMAT_WHITE); + safe_strncpy(lineCh, text, 800); + return formatted; +} + +void Network::SendPacketToClients(NetworkPacket& packet, bool front) +{ + for (auto it = client_connection_list.begin(); it != client_connection_list.end(); it++) { + (*it)->QueuePacket(std::move(NetworkPacket::Duplicate(packet)), front); + } +} + +bool Network::CheckSRAND(uint32 tick, uint32 srand0) +{ + if (server_srand0_tick == 0) + return true; + + if (tick > server_srand0_tick) { + server_srand0_tick = 0; + return true; + } + + if (tick == server_srand0_tick) { + server_srand0_tick = 0; + if (srand0 != server_srand0) { + return false; + } + } + return true; +} + +void Network::KickPlayer(int playerId) +{ + NetworkPlayer *player = GetPlayerByID(playerId); + for(auto it = client_connection_list.begin(); it != client_connection_list.end(); it++) { + if ((*it)->player->id == playerId) { + // Disconnect the client gracefully + (*it)->last_disconnect_reason = "Kicked"; + Server_Send_SETDISCONNECTMSG(*(*it), "Get out of the server!"); + shutdown((*it)->socket, SHUT_RD); + (*it)->SendQueuedPackets(); + break; + } + } +} + +void Network::SetPassword(const char* password) +{ + Network::password = password; +} + +void Network::ShutdownClient() +{ + if (GetMode() == NETWORK_MODE_CLIENT) { + shutdown(server_connection.socket, SHUT_RDWR); + } +} + +std::string Network::GenerateAdvertiseKey() +{ + // Generate a string of 16 random hex characters (64-integer key as a hex formatted string) + static char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + char key[17]; + for (int i = 0; i < 16; i++) { + int hexCharIndex = util_rand() % countof(hexChars); + key[i] = hexChars[hexCharIndex]; + } + key[countof(key) - 1] = 0; + + return key; +} + +const char *Network::GetMasterServerUrl() +{ + if (str_is_null_or_empty(gConfigNetwork.master_server_url)) { + return OPENRCT2_MASTER_SERVER_URL; + } else { + return gConfigNetwork.master_server_url; + } +} + +void Network::AdvertiseRegister() +{ +#ifndef DISABLE_HTTP + last_advertise_time = SDL_GetTicks(); + + // Send the registration request + http_json_request request; + request.url = GetMasterServerUrl(); + request.method = HTTP_METHOD_POST; + + json_t *body = json_object(); + json_object_set_new(body, "key", json_string(advertise_key.c_str())); + json_object_set_new(body, "port", json_integer(listening_port)); + request.body = body; + + http_request_json_async(&request, [](http_json_response *response) -> void { + if (response == NULL) { + log_warning("Unable to connect to master server"); + return; + } + + json_t *jsonStatus = json_object_get(response->root, "status"); + if (json_is_integer(jsonStatus)) { + int status = (int)json_integer_value(jsonStatus); + if (status == MASTER_SERVER_STATUS_OK) { + json_t *jsonToken = json_object_get(response->root, "token"); + if (json_is_string(jsonToken)) { + gNetwork.advertise_token = json_string_value(jsonToken); + gNetwork.advertise_status = ADVERTISE_STATUS_REGISTERED; + } + } else { + const char *message = "Invalid response from server"; + json_t *jsonMessage = json_object_get(response->root, "message"); + if (json_is_string(jsonMessage)) { + message = json_string_value(jsonMessage); + } + log_warning("Unable to advertise: %s", message); + } + } + http_request_json_dispose(response); + }); + + json_decref(body); +#endif +} + +void Network::AdvertiseHeartbeat() +{ +#ifndef DISABLE_HTTP + // Send the heartbeat request + http_json_request request; + request.url = GetMasterServerUrl(); + request.method = HTTP_METHOD_PUT; + + json_t *body = json_object(); + json_object_set_new(body, "token", json_string(advertise_token.c_str())); + json_object_set_new(body, "players", json_integer(network_get_num_players())); + + json_t *gameInfo = json_object(); + json_object_set_new(gameInfo, "mapSize", json_integer(RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint8) - 2)); + json_object_set_new(gameInfo, "day", json_integer(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16))); + json_object_set_new(gameInfo, "month", json_integer(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16))); + json_object_set_new(gameInfo, "guests", json_integer(RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16))); + json_object_set_new(gameInfo, "parkValue", json_integer(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_VALUE, money32))); + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) { + money32 cash = DECRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, money32)); + json_object_set_new(gameInfo, "cash", json_integer(cash)); + } + + json_object_set_new(body, "gameInfo", gameInfo); + request.body = body; + + gNetwork.last_heartbeat_time = SDL_GetTicks(); + http_request_json_async(&request, [](http_json_response *response) -> void { + if (response == NULL) { + log_warning("Unable to connect to master server"); + return; + } + + json_t *jsonStatus = json_object_get(response->root, "status"); + if (json_is_integer(jsonStatus)) { + int status = (int)json_integer_value(jsonStatus); + if (status == MASTER_SERVER_STATUS_OK) { + // Master server has successfully updated our server status + } else if (status == MASTER_SERVER_STATUS_INVALID_TOKEN) { + gNetwork.advertise_status = ADVERTISE_STATUS_UNREGISTERED; + log_warning("Master server heartbeat failed: Invalid Token"); + } + } + http_request_json_dispose(response); + }); + + json_decref(body); +#endif +} + +void Network::Client_Send_AUTH(const char* name, const char* password) +{ + std::unique_ptr packet = std::move(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_AUTH; + packet->WriteString(OPENRCT2_VERSION); + packet->WriteString(name); + packet->WriteString(password); + server_connection.authstatus = NETWORK_AUTH_REQUESTED; + server_connection.QueuePacket(std::move(packet)); +} + +void Network::Server_Send_AUTH(NetworkConnection& connection) +{ + uint8 new_playerid = 0; + if (connection.player) { + new_playerid = connection.player->id; + } + std::unique_ptr packet = std::move(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_AUTH << (uint32)connection.authstatus << (uint8)new_playerid; + connection.QueuePacket(std::move(packet)); + if (connection.authstatus != NETWORK_AUTH_OK && connection.authstatus != NETWORK_AUTH_REQUIREPASSWORD) { + shutdown(connection.socket, SHUT_RD); + connection.SendQueuedPackets(); + } +} + +void Network::Server_Send_MAP(NetworkConnection* connection) +{ + int buffersize = 0x600000; + std::vector buffer(buffersize); + SDL_RWops* rw = SDL_RWFromMem(&buffer[0], buffersize); + scenario_save_network(rw); + int size = (int)SDL_RWtell(rw); + int chunksize = 1000; + for (int i = 0; i < size; i += chunksize) { + int datasize = (std::min)(chunksize, size - i); + std::unique_ptr packet = std::move(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_MAP << (uint32)size << (uint32)i; + packet->Write(&buffer[i], datasize); + if (connection) { + connection->QueuePacket(std::move(packet)); + } else { + SendPacketToClients(*packet); + } + } + SDL_RWclose(rw); +} + +void Network::Client_Send_CHAT(const char* text) +{ + std::unique_ptr packet = std::move(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_CHAT; + packet->WriteString(text); + server_connection.QueuePacket(std::move(packet)); +} + +void Network::Server_Send_CHAT(const char* text) +{ + std::unique_ptr packet = std::move(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_CHAT; + packet->WriteString(text); + SendPacketToClients(*packet); +} + +void Network::Client_Send_GAMECMD(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp, uint8 callback) +{ + std::unique_ptr packet = std::move(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_GAMECMD << (uint32)RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) << eax << (ebx | GAME_COMMAND_FLAG_NETWORKED) << ecx << edx << esi << edi << ebp << callback; + server_connection.QueuePacket(std::move(packet)); +} + +void Network::Server_Send_GAMECMD(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp, uint8 playerid, uint8 callback) +{ + std::unique_ptr packet = std::move(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_GAMECMD << (uint32)RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) << eax << (ebx | GAME_COMMAND_FLAG_NETWORKED) << ecx << edx << esi << edi << ebp << playerid << callback; + SendPacketToClients(*packet); +} + +void Network::Server_Send_TICK() +{ + last_tick_sent_time = SDL_GetTicks(); + std::unique_ptr packet = std::move(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_TICK << (uint32)RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) << (uint32)RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, uint32); + SendPacketToClients(*packet); +} + +void Network::Server_Send_PLAYERLIST() +{ + std::unique_ptr packet = std::move(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_PLAYERLIST << (uint32)player_list.size(); + for (unsigned int i = 0; i < player_list.size(); i++) { + packet->WriteString((const char*)player_list[i]->name); + *packet << player_list[i]->id << player_list[i]->flags; + } + SendPacketToClients(*packet); +} + +void Network::Client_Send_PING() +{ + std::unique_ptr packet = std::move(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_PING; + server_connection.QueuePacket(std::move(packet)); +} + +void Network::Server_Send_PING() +{ + last_ping_sent_time = SDL_GetTicks(); + std::unique_ptr packet = std::move(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_PING; + for (auto it = client_connection_list.begin(); it != client_connection_list.end(); it++) { + (*it)->ping_time = SDL_GetTicks(); + } + SendPacketToClients(*packet, true); +} + +void Network::Server_Send_PINGLIST() +{ + std::unique_ptr packet = std::move(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_PINGLIST << (uint32)player_list.size(); + for (unsigned int i = 0; i < player_list.size(); i++) { + *packet << player_list[i]->id << player_list[i]->ping; + } + SendPacketToClients(*packet); +} + +void Network::Server_Send_SETDISCONNECTMSG(NetworkConnection& connection, const char* msg) +{ + std::unique_ptr packet = std::move(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_SETDISCONNECTMSG; + packet->WriteString(msg); + connection.QueuePacket(std::move(packet)); +} + +void Network::Server_Send_GAMEINFO(NetworkConnection& connection) +{ + std::unique_ptr packet = std::move(NetworkPacket::Allocate()); + *packet << (uint32)NETWORK_COMMAND_GAMEINFO; +#ifndef DISABLE_HTTP + json_t* obj = json_object(); + json_object_set_new(obj, "name", json_string(gConfigNetwork.server_name)); + json_object_set_new(obj, "requiresPassword", json_boolean(password.size() > 0)); + json_object_set_new(obj, "version", json_string(OPENRCT2_VERSION)); + json_object_set_new(obj, "players", json_integer(player_list.size())); + json_object_set_new(obj, "maxPlayers", json_integer(gConfigNetwork.maxplayers)); + json_object_set_new(obj, "description", json_string(gConfigNetwork.server_description)); + json_object_set_new(obj, "dedicated", json_boolean(gOpenRCT2Headless)); + + // Provider details + json_t* jsonProvider = json_object(); + json_object_set_new(jsonProvider, "name", json_string(gConfigNetwork.provider_name)); + json_object_set_new(jsonProvider, "email", json_string(gConfigNetwork.provider_email)); + json_object_set_new(jsonProvider, "website", json_string(gConfigNetwork.provider_website)); + json_object_set_new(obj, "provider", jsonProvider); + + packet->WriteString(json_dumps(obj, 0)); + json_decref(obj); +#endif + connection.QueuePacket(std::move(packet)); +} + +bool Network::ProcessConnection(NetworkConnection& connection) +{ + int packetStatus; + do { + packetStatus = connection.ReadPacket(); + switch(packetStatus) { + case NETWORK_READPACKET_DISCONNECTED: + // closed connection or network error + if (!connection.last_disconnect_reason) { + connection.last_disconnect_reason = "Connection Closed"; + } + return false; + break; + case NETWORK_READPACKET_SUCCESS: + // done reading in packet + ProcessPacket(connection, connection.inboundpacket); + break; + case NETWORK_READPACKET_MORE_DATA: + // more data required to be read + break; + case NETWORK_READPACKET_NO_DATA: + // could not read anything from socket + break; + } + } while (packetStatus == NETWORK_READPACKET_MORE_DATA || packetStatus == NETWORK_READPACKET_SUCCESS); + connection.SendQueuedPackets(); + if (!connection.ReceivedPacketRecently()) { + if (!connection.last_disconnect_reason) { + connection.last_disconnect_reason = "No Data"; + } + return false; + } + return true; +} + +void Network::ProcessPacket(NetworkConnection& connection, NetworkPacket& packet) +{ + uint32 command; + packet >> command; + if (command < NETWORK_COMMAND_MAX) { + // printf("RECV %s\n", NetworkCommandNames[command]); + switch (gNetwork.GetMode()) { + case NETWORK_MODE_SERVER: + if (server_command_handlers[command]) { + if (connection.authstatus == NETWORK_AUTH_OK || !packet.CommandRequiresAuth()) { + (this->*server_command_handlers[command])(connection, packet); + } + } + break; + case NETWORK_MODE_CLIENT: + if (client_command_handlers[command]) { + (this->*client_command_handlers[command])(connection, packet); + } + break; + } + } + packet.Clear(); +} + +void Network::ProcessGameCommandQueue() +{ + while (game_command_queue.begin() != game_command_queue.end() && game_command_queue.begin()->tick == RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32)) { + // run all the game commands at the current tick + const GameCommand& gc = (*game_command_queue.begin()); + if (GetPlayerID() == gc.playerid) { + game_command_callback = game_command_callback_get_callback(gc.callback); + } + game_do_command_p(gc.esi, (int*)&gc.eax, (int*)&gc.ebx, (int*)&gc.ecx, (int*)&gc.edx, (int*)&gc.esi, (int*)&gc.edi, (int*)&gc.ebp); + game_command_queue.erase(game_command_queue.begin()); + } +} + +void Network::AddClient(SOCKET socket) +{ + auto connection = std::unique_ptr(new NetworkConnection); // change to make_unique in c++14 + connection->socket = socket; + connection->SetTCPNoDelay(true); + client_connection_list.push_back(std::move(connection)); +} + +void Network::RemoveClient(std::unique_ptr& connection) +{ + NetworkPlayer* connection_player = connection->player; + if (connection_player) { + char text[256]; + char* lineCh = text; + lineCh = utf8_write_codepoint(lineCh, FORMAT_OUTLINE); + lineCh = utf8_write_codepoint(lineCh, FORMAT_RED); + char reasonstr[100]; + reasonstr[0] = 0; + if (connection->last_disconnect_reason && strlen(connection->last_disconnect_reason) < sizeof(reasonstr)) { + sprintf(reasonstr, " (%s)", connection->last_disconnect_reason); + } + sprintf(lineCh, "%s has disconnected%s", connection_player->name, reasonstr); + chat_history_add(text); + gNetwork.Server_Send_CHAT(text); + } + player_list.erase(std::remove_if(player_list.begin(), player_list.end(), [connection_player](std::unique_ptr& player){ return player.get() == connection_player; }), player_list.end()); + client_connection_list.remove(connection); + Server_Send_PLAYERLIST(); +} + +NetworkPlayer* Network::AddPlayer(const char* name) +{ + NetworkPlayer* addedplayer = 0; + int newid = -1; + if (GetMode() == NETWORK_MODE_SERVER) { + // Find first unused player id + for (int id = 0; id < 255; id++) { + if (std::find_if(player_list.begin(), player_list.end(), [&id](std::unique_ptr const& player) { return player->id == id; }) == player_list.end()) { + newid = id; + break; + } + } + } else { + newid = 0; + } + if (newid != -1) { + std::unique_ptr player(new NetworkPlayer(name)); // change to make_unique in c++14 + player->id = newid; + addedplayer = player.get(); + player_list.push_back(std::move(player)); + if (GetMode() == NETWORK_MODE_SERVER) { + Server_Send_PLAYERLIST(); + } + } + return addedplayer; +} + +void Network::PrintError() +{ +#ifdef _WIN32 + wchar_t *s = NULL; + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, LAST_SOCKET_ERROR(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&s, 0, NULL); + fprintf(stderr, "%S\n", s); + LocalFree(s); +#else + char *s = strerror(LAST_SOCKET_ERROR()); + fprintf(stderr, "%s\n", s); +#endif + +} + +int Network::Client_Handle_AUTH(NetworkConnection& connection, NetworkPacket& packet) +{ + packet >> (uint32&)connection.authstatus >> (uint8&)player_id; + switch(connection.authstatus) { + case NETWORK_AUTH_BADNAME: + connection.last_disconnect_reason = "Bad Player Name"; + shutdown(connection.socket, SHUT_RDWR); + break; + case NETWORK_AUTH_BADVERSION: + connection.last_disconnect_reason = "Incorrect Software Version"; + shutdown(connection.socket, SHUT_RDWR); + break; + case NETWORK_AUTH_BADPASSWORD: + connection.last_disconnect_reason = "Bad Password"; + shutdown(connection.socket, SHUT_RDWR); + break; + case NETWORK_AUTH_FULL: + connection.last_disconnect_reason = "Server Full"; + shutdown(connection.socket, SHUT_RDWR); + break; + case NETWORK_AUTH_REQUIREPASSWORD: + window_network_status_open_password(); + break; + } + return 1; +} + +int Network::Server_Handle_AUTH(NetworkConnection& connection, NetworkPacket& packet) +{ + if (connection.authstatus != NETWORK_AUTH_OK) { + const char* gameversion = packet.ReadString(); + const char* name = packet.ReadString(); + const char* password = packet.ReadString(); + if (!gameversion || strcmp(gameversion, OPENRCT2_VERSION) != 0) { + connection.authstatus = NETWORK_AUTH_BADVERSION; + } else + if (!name) { + connection.authstatus = NETWORK_AUTH_BADNAME; + } else + if ((!password || strlen(password) == 0) && Network::password.size() > 0) { + connection.authstatus = NETWORK_AUTH_REQUIREPASSWORD; + } else + if (password && Network::password != password) { + connection.authstatus = NETWORK_AUTH_BADPASSWORD; + } else + if (gConfigNetwork.maxplayers <= player_list.size()) { + connection.authstatus = NETWORK_AUTH_FULL; + } else { + connection.authstatus = NETWORK_AUTH_OK; + NetworkPlayer* player = AddPlayer(name); + connection.player = player; + if (player) { + char text[256]; + char* lineCh = text; + lineCh = utf8_write_codepoint(lineCh, FORMAT_OUTLINE); + lineCh = utf8_write_codepoint(lineCh, FORMAT_GREEN); + sprintf(lineCh, "%s has joined the game", player->name); + chat_history_add(text); + gNetwork.Server_Send_CHAT(text); + Server_Send_MAP(&connection); + } + } + Server_Send_AUTH(connection); + } + return 1; +} + +int Network::Client_Handle_MAP(NetworkConnection& connection, NetworkPacket& packet) +{ + uint32 size, offset; + packet >> size >> offset; + if (offset > 0x600000) { + // too big + return 0; + } else { + int chunksize = packet.size - packet.read; + if (chunksize <= 0) { + return 0; + } + if (offset + chunksize > chunk_buffer.size()) { + chunk_buffer.resize(offset + chunksize); + } + char status[256]; + sprintf(status, "Downloading map ... (%lu / %lu)", (offset + chunksize) / 1000, size / 1000); + window_network_status_open(status); + memcpy(&chunk_buffer[offset], (void*)packet.Read(chunksize), chunksize); + if (offset + chunksize == size) { + window_network_status_close(); + + SDL_RWops* rw = SDL_RWFromMem(&chunk_buffer[0], size); + if (game_load_network(rw)) { + game_load_init(); + game_command_queue.clear(); + server_tick = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32); + server_srand0_tick = 0; + // window_network_status_open("Loaded new map from network"); + _desynchronised = false; + } + SDL_RWclose(rw); + } + } + return 1; +} + +int Network::Client_Handle_CHAT(NetworkConnection& connection, NetworkPacket& packet) +{ + const char* text = packet.ReadString(); + if (text) { + chat_history_add(text); + } + return 1; +} + +int Network::Server_Handle_CHAT(NetworkConnection& connection, NetworkPacket& packet) +{ + const char* text = packet.ReadString(); + if (text) { + const char* formatted = FormatChat(connection.player, text); + chat_history_add(formatted); + Server_Send_CHAT(formatted); + } + return 1; +} + +int Network::Client_Handle_GAMECMD(NetworkConnection& connection, NetworkPacket& packet) +{ + uint32 tick; + uint32 args[7]; + uint8 playerid; + uint8 callback; + packet >> tick >> args[0] >> args[1] >> args[2] >> args[3] >> args[4] >> args[5] >> args[6] >> playerid >> callback; + + GameCommand gc = GameCommand(tick, args, playerid, callback); + game_command_queue.insert(gc); + return 1; +} + +int Network::Server_Handle_GAMECMD(NetworkConnection& connection, NetworkPacket& packet) +{ + uint32 tick; + uint32 args[7]; + uint8 playerid; + uint8 callback; + if (connection.player) { + playerid = connection.player->id; + } + packet >> tick >> args[0] >> args[1] >> args[2] >> args[3] >> args[4] >> args[5] >> args[6] >> callback; + + int commandCommand = args[4]; + + // Don't let clients send pause or quit + if (commandCommand != GAME_COMMAND_TOGGLE_PAUSE && + commandCommand != GAME_COMMAND_LOAD_OR_QUIT + ) { + Server_Send_GAMECMD(args[0], args[1], args[2], args[3], args[4], args[5], args[6], playerid, callback); + game_do_command(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + } + + return 1; +} + +int Network::Client_Handle_TICK(NetworkConnection& connection, NetworkPacket& packet) +{ + uint32 srand0; + packet >> server_tick >> srand0; + if (server_srand0_tick == 0) { + server_srand0 = srand0; + server_srand0_tick = server_tick; + } + return 1; +} + +int Network::Client_Handle_PLAYERLIST(NetworkConnection& connection, NetworkPacket& packet) +{ + player_list.clear(); + uint32 size; + packet >> size; + for (unsigned int i = 0; i < size; i++) { + const char* name = packet.ReadString(); + NetworkPlayer* player = AddPlayer(name); + if (player) { + packet >> player->id >> player->flags; + if (player->flags & NETWORK_PLAYER_FLAG_ISSERVER) { + server_connection.player = player; + } + } + } + return 1; +} + +int Network::Client_Handle_PING(NetworkConnection& connection, NetworkPacket& packet) +{ + Client_Send_PING(); + return 1; +} + +int Network::Server_Handle_PING(NetworkConnection& connection, NetworkPacket& packet) +{ + int ping = SDL_GetTicks() - connection.ping_time; + if (ping < 0) { + ping = 0; + } + if (connection.player) { + connection.player->ping = ping; + } + return 1; +} + +int Network::Client_Handle_PINGLIST(NetworkConnection& connection, NetworkPacket& packet) +{ + uint32 size; + packet >> size; + for (unsigned int i = 0; i < size; i++) { + uint8 id; + uint16 ping; + packet >> id >> ping; + NetworkPlayer* player = GetPlayerByID(id); + if (player) { + player->ping = ping; + } + } + return 1; +} + +int Network::Client_Handle_SETDISCONNECTMSG(NetworkConnection& connection, NetworkPacket& packet) +{ + static std::string msg; + const char* disconnectmsg = packet.ReadString(); + if (disconnectmsg) { + msg = disconnectmsg; + connection.last_disconnect_reason = msg.c_str(); + } + return 1; +} + +int Network::Server_Handle_GAMEINFO(NetworkConnection& connection, NetworkPacket& packet) +{ + Server_Send_GAMEINFO(connection); + return 1; +} + +int network_init() +{ + return gNetwork.Init(); +} + +void network_close() +{ + gNetwork.Close(); +} + +void network_shutdown_client() +{ + gNetwork.ShutdownClient(); +} + +int network_begin_client(const char *host, int port) +{ + return gNetwork.BeginClient(host, port); +} + +int network_begin_server(int port) +{ + return gNetwork.BeginServer(port); +} + +void network_update() +{ + gNetwork.Update(); +} + +int network_get_mode() +{ + return gNetwork.GetMode(); +} + +int network_get_status() +{ + return gNetwork.GetStatus(); +} + +int network_get_authstatus() +{ + return gNetwork.GetAuthStatus(); +} + +uint32 network_get_server_tick() +{ + return gNetwork.GetServerTick(); +} + +uint8 network_get_current_player_id() +{ + return gNetwork.GetPlayerID(); +} + +int network_get_num_players() +{ + return gNetwork.player_list.size(); +} + +const char* network_get_player_name(unsigned int index) +{ + return (const char*)gNetwork.player_list[index]->name; +} + +uint32 network_get_player_flags(unsigned int index) +{ + return gNetwork.player_list[index]->flags; +} + +int network_get_player_ping(unsigned int index) +{ + return gNetwork.player_list[index]->ping; +} + +int network_get_player_id(unsigned int index) +{ + return gNetwork.player_list[index]->id; +} + +void network_send_map() +{ + gNetwork.Server_Send_MAP(); +} + +void network_send_chat(const char* text) +{ + if (gNetwork.GetMode() == NETWORK_MODE_CLIENT) { + gNetwork.Client_Send_CHAT(text); + } else + if (gNetwork.GetMode() == NETWORK_MODE_SERVER) { + NetworkPlayer* player = gNetwork.GetPlayerByID(gNetwork.GetPlayerID()); + const char* formatted = gNetwork.FormatChat(player, text); + chat_history_add(formatted); + gNetwork.Server_Send_CHAT(formatted); + } +} + +void network_send_gamecmd(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp, uint8 callback) +{ + switch (gNetwork.GetMode()) { + case NETWORK_MODE_SERVER: + gNetwork.Server_Send_GAMECMD(eax, ebx, ecx, edx, esi, edi, ebp, gNetwork.GetPlayerID(), callback); + break; + case NETWORK_MODE_CLIENT: + gNetwork.Client_Send_GAMECMD(eax, ebx, ecx, edx, esi, edi, ebp, callback); + break; + } +} + +void network_send_password(const char* password) +{ + gNetwork.Client_Send_AUTH(gConfigNetwork.player_name, password); +} + +void network_kick_player(int playerId) +{ + gNetwork.KickPlayer(playerId); +} + +void network_set_password(const char* password) +{ + gNetwork.SetPassword(password); +} + +#else +int network_get_mode() { return NETWORK_MODE_NONE; } +int network_get_status() { return NETWORK_STATUS_NONE; } +int network_get_authstatus() { return NETWORK_AUTH_NONE; } +uint32 network_get_server_tick() { return RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32); } +void network_send_gamecmd(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp, uint8 callback) {} +void network_send_map() {} +void network_update() {} +int network_begin_client(const char *host, int port) { return 1; } +int network_begin_server(int port) { return 1; } +int network_get_num_players() { return 1; } +const char* network_get_player_name(unsigned int index) { return "local (OpenRCT2 compiled without MP)"; } +uint32 network_get_player_flags(unsigned int index) { return 0; } +int network_get_player_ping(unsigned int index) { return 0; } +int network_get_player_id(unsigned int index) { return 0; } +void network_send_chat(const char* text) {} +void network_send_password(const char* password) {} +void network_close() {} +void network_shutdown_client() {} +void network_kick_player(int playerId) {} +void network_set_password(const char* password) {} +uint8 network_get_current_player_id() { return 0; } +#endif /* DISABLE_NETWORK */ diff --git a/src/network/network.h b/src/network/network.h new file mode 100644 index 0000000000..56260ce5f2 --- /dev/null +++ b/src/network/network.h @@ -0,0 +1,352 @@ +/***************************************************************************** + * 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 _NETWORK_H_ +#define _NETWORK_H_ + +enum { + NETWORK_MODE_NONE, + NETWORK_MODE_CLIENT, + NETWORK_MODE_SERVER +}; + +enum { + NETWORK_PLAYER_FLAG_ISSERVER = 1 << 0, +}; + +enum { + NETWORK_AUTH_NONE, + NETWORK_AUTH_REQUESTED, + NETWORK_AUTH_OK, + NETWORK_AUTH_BADVERSION, + NETWORK_AUTH_BADNAME, + NETWORK_AUTH_BADPASSWORD, + NETWORK_AUTH_FULL, + NETWORK_AUTH_REQUIREPASSWORD +}; + +enum { + NETWORK_STATUS_NONE, + NETWORK_STATUS_READY, + NETWORK_STATUS_RESOLVING, + NETWORK_STATUS_CONNECTING, + NETWORK_STATUS_CONNECTED +}; + +#define NETWORK_DEFAULT_PORT 11753 + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus +#include "../common.h" +#include "../platform/platform.h" +#ifdef __cplusplus +} +#endif // __cplusplus + +#ifndef DISABLE_NETWORK + +#ifdef _WIN32 + #include + #include + #define LAST_SOCKET_ERROR() WSAGetLastError() + #undef EWOULDBLOCK + #define EWOULDBLOCK WSAEWOULDBLOCK + #ifndef SHUT_RD + #define SHUT_RD SD_RECEIVE + #endif + #ifndef SHUT_RDWR + #define SHUT_RDWR SD_BOTH + #endif +#else + #include + #include + #include + #include + #include + #include + typedef int SOCKET; + #define SOCKET_ERROR -1 + #define INVALID_SOCKET -1 + #define LAST_SOCKET_ERROR() errno + #define closesocket close + #define ioctlsocket ioctl +#endif // _WIN32 + +#ifdef __cplusplus + +#include +#include +#include +#include +#include +#include + +template +struct ByteSwapT { }; +template <> +struct ByteSwapT<1> { static uint8 SwapBE(uint8 value) { return value; } }; +template <> +struct ByteSwapT<2> { static uint16 SwapBE(uint16 value) { return SDL_SwapBE16(value); } }; +template <> +struct ByteSwapT<4> { static uint32 SwapBE(uint32 value) { return SDL_SwapBE32(value); } }; +template +T ByteSwapBE(const T& value) { return ByteSwapT::SwapBE(value); } + +class NetworkPacket +{ +public: + NetworkPacket(); + static std::unique_ptr Allocate(); + static std::unique_ptr Duplicate(NetworkPacket& packet); + uint8* GetData(); + uint32 GetCommand(); + template + NetworkPacket& operator<<(T value) { T swapped = ByteSwapBE(value); uint8* bytes = (uint8*)&swapped; data->insert(data->end(), bytes, bytes + sizeof(value)); return *this; } + void Write(uint8* bytes, unsigned int size); + void WriteString(const char* string); + template + NetworkPacket& operator>>(T& value) { if (read + sizeof(value) > size) { value = 0; } else { value = ByteSwapBE(*((T*)&GetData()[read])); read += sizeof(value); } return *this; } + const uint8* Read(unsigned int size); + const char* ReadString(); + void Clear(); + bool CommandRequiresAuth(); + + uint16 size; + std::shared_ptr> data; + int transferred; + int read; +}; + +class NetworkPlayer +{ +public: + NetworkPlayer(const char* name); + uint8 id; + uint8 name[32 + 1]; + uint16 ping; + uint32 flags; +}; + +class NetworkConnection +{ +public: + NetworkConnection(); + ~NetworkConnection(); + int ReadPacket(); + void QueuePacket(std::unique_ptr packet, bool front = false); + void SendQueuedPackets(); + bool SetTCPNoDelay(bool on); + bool SetNonBlocking(bool on); + static bool SetNonBlocking(SOCKET socket, bool on); + void ResetLastPacketTime(); + bool ReceivedPacketRecently(); + + SOCKET socket; + NetworkPacket inboundpacket; + int authstatus; + NetworkPlayer* player; + uint32 ping_time; + const char* last_disconnect_reason; + +private: + bool SendPacket(NetworkPacket& packet); + std::list> outboundpackets; + uint32 last_packet_time; +}; + +class NetworkAddress +{ +public: + NetworkAddress(); + void Resolve(const char* host, unsigned short port, bool nonblocking = true); + int GetResolveStatus(void); + + std::shared_ptr ss; + std::shared_ptr ss_len; + + enum { + RESOLVE_NONE, + RESOLVE_INPROGRESS, + RESOLVE_OK, + RESOLVE_FAILED + }; + +private: + static int ResolveFunc(void* pointer); + + const char* host; + unsigned short port; + SDL_mutex* mutex; + SDL_cond* cond; + std::shared_ptr status; +}; + +class Network +{ +public: + Network(); + ~Network(); + bool Init(); + void Close(); + bool BeginClient(const char* host, unsigned short port); + bool BeginServer(unsigned short port, const char* address = NULL); + int GetMode(); + int GetStatus(); + int GetAuthStatus(); + uint32 GetServerTick(); + uint8 GetPlayerID(); + void Update(); + NetworkPlayer* GetPlayerByID(int id); + const char* FormatChat(NetworkPlayer* fromplayer, const char* text); + void SendPacketToClients(NetworkPacket& packet, bool front = false); + bool CheckSRAND(uint32 tick, uint32 srand0); + void KickPlayer(int playerId); + void SetPassword(const char* password); + void ShutdownClient(); + void AdvertiseRegister(); + void AdvertiseHeartbeat(); + + void Client_Send_AUTH(const char* name, const char* password); + void Server_Send_AUTH(NetworkConnection& connection); + void Server_Send_MAP(NetworkConnection* connection = nullptr); + void Client_Send_CHAT(const char* text); + void Server_Send_CHAT(const char* text); + void Client_Send_GAMECMD(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp, uint8 callback); + void Server_Send_GAMECMD(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp, uint8 playerid, uint8 callback); + void Server_Send_TICK(); + void Server_Send_PLAYERLIST(); + void Client_Send_PING(); + void Server_Send_PING(); + void Server_Send_PINGLIST(); + void Server_Send_SETDISCONNECTMSG(NetworkConnection& connection, const char* msg); + void Server_Send_GAMEINFO(NetworkConnection& connection); + + std::vector> player_list; + +private: + bool ProcessConnection(NetworkConnection& connection); + void ProcessPacket(NetworkConnection& connection, NetworkPacket& packet); + void ProcessGameCommandQueue(); + void AddClient(SOCKET socket); + void RemoveClient(std::unique_ptr& connection); + NetworkPlayer* AddPlayer(const char* name); + void PrintError(); + const char *GetMasterServerUrl(); + std::string GenerateAdvertiseKey(); + + struct GameCommand + { + GameCommand(uint32 t, uint32* args, uint8 p, uint8 cb) { tick = t, eax = args[0], ebx = args[1], ecx = args[2], edx = args[3], esi = args[4], edi = args[5], ebp = args[6]; playerid = p; callback = cb; }; + uint32 tick; + uint32 eax, ebx, ecx, edx, esi, edi, ebp; + uint8 playerid; + uint8 callback; + bool operator<(const GameCommand& comp) const { + return tick < comp.tick; + } + }; + + int mode; + int status; + NetworkAddress server_address; + bool wsa_initialized; + SOCKET listening_socket; + unsigned short listening_port; + NetworkConnection server_connection; + uint32 last_tick_sent_time; + uint32 last_ping_sent_time; + uint32 server_tick; + uint32 server_srand0; + uint32 server_srand0_tick; + uint8 player_id; + std::list> client_connection_list; + std::multiset game_command_queue; + std::vector chunk_buffer; + std::string password; + bool _desynchronised; + uint32 server_connect_time; + uint32 last_advertise_time; + std::string advertise_token; + std::string advertise_key; + int advertise_status; + uint32 last_heartbeat_time; + + void UpdateServer(); + void UpdateClient(); + +private: + std::vector client_command_handlers; + std::vector server_command_handlers; + int Client_Handle_AUTH(NetworkConnection& connection, NetworkPacket& packet); + int Server_Handle_AUTH(NetworkConnection& connection, NetworkPacket& packet); + int Client_Handle_MAP(NetworkConnection& connection, NetworkPacket& packet); + int Client_Handle_CHAT(NetworkConnection& connection, NetworkPacket& packet); + int Server_Handle_CHAT(NetworkConnection& connection, NetworkPacket& packet); + int Client_Handle_GAMECMD(NetworkConnection& connection, NetworkPacket& packet); + int Server_Handle_GAMECMD(NetworkConnection& connection, NetworkPacket& packet); + int Client_Handle_TICK(NetworkConnection& connection, NetworkPacket& packet); + int Client_Handle_PLAYERLIST(NetworkConnection& connection, NetworkPacket& packet); + int Client_Handle_PING(NetworkConnection& connection, NetworkPacket& packet); + int Server_Handle_PING(NetworkConnection& connection, NetworkPacket& packet); + int Client_Handle_PINGLIST(NetworkConnection& connection, NetworkPacket& packet); + int Client_Handle_SETDISCONNECTMSG(NetworkConnection& connection, NetworkPacket& packet); + int Server_Handle_GAMEINFO(NetworkConnection& connection, NetworkPacket& packet); +}; + +#endif // __cplusplus +#endif /* DISABLE_NETWORK */ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus +int network_init(); +void network_close(); +void network_shutdown_client(); +int network_begin_client(const char *host, int port); +int network_begin_server(int port); + +int network_get_mode(); +int network_get_status(); +void network_update(); +int network_get_authstatus(); +uint32 network_get_server_tick(); +uint8 network_get_current_player_id(); +int network_get_num_players(); +const char* network_get_player_name(unsigned int index); +uint32 network_get_player_flags(unsigned int index); +int network_get_player_ping(unsigned int index); +int network_get_player_id(unsigned int index); + +void network_send_map(); +void network_send_chat(const char* text); +void network_send_gamecmd(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp, uint8 callback); +void network_send_password(const char* password); + +void network_kick_player(int playerId); +void network_set_password(const char* password); + +void network_print_error(); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif diff --git a/src/network/twitch.cpp b/src/network/twitch.cpp index 1e36c0526b..fbc47434e9 100644 --- a/src/network/twitch.cpp +++ b/src/network/twitch.cpp @@ -22,6 +22,7 @@ extern "C" { #include "../management/news_item.h" #include "../peep/peep.h" #include "../world/sprite.h" + #include "../util/util.h" #include "http.h" #include "twitch.h" @@ -129,7 +130,12 @@ static void twitch_join() _twitchState = TWITCH_STATE_JOINING; _twitchIdle = false; - http_request_json_async(url, [](http_json_response *jsonResponse) -> void { + + http_json_request request; + request.url = url; + request.method = HTTP_METHOD_GET; + request.body = NULL; + http_request_json_async(&request, [](http_json_response *jsonResponse) -> void { if (jsonResponse == NULL) { _twitchState = TWITCH_STATE_LEFT; console_writeline("Unable to connect to twitch channel."); @@ -175,7 +181,7 @@ static void twitch_leave() // http_request_json_dispose(jsonResponse); // _twitchState = TWITCH_STATE_LEFT; // _twitchIdle = true; - // + // // console_writeline("Left twitch channel."); // }); } @@ -190,7 +196,12 @@ static void twitch_get_followers() _twitchState = TWITCH_STATE_WAITING; _twitchIdle = false; - http_request_json_async(url, [](http_json_response *jsonResponse) -> void { + + http_json_request request; + request.url = url; + request.method = HTTP_METHOD_GET; + request.body = NULL; + http_request_json_async(&request, [](http_json_response *jsonResponse) -> void { if (jsonResponse == NULL) { _twitchState = TWITCH_STATE_JOINED; } else { @@ -211,7 +222,12 @@ static void twitch_get_messages() _twitchState = TWITCH_STATE_WAITING; _twitchIdle = false; - http_request_json_async(url, [](http_json_response *jsonResponse) -> void { + + http_json_request request; + request.url = url; + request.method = HTTP_METHOD_GET; + request.body = NULL; + http_request_json_async(&request, [](http_json_response *jsonResponse) -> void { if (jsonResponse == NULL) { _twitchState = TWITCH_STATE_JOINED; } else { @@ -406,14 +422,14 @@ static void twitch_parse_chat_message(const char *message) message++; ch = strchrm(message, " \t"); - strncpy(buffer, message, ch - message); + safe_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); + safe_strncpy(buffer + 1, ch, sizeof(buffer) - 2); buffer[sizeof(buffer) - 2] = 0; // Remove unsupport characters @@ -432,4 +448,4 @@ static void twitch_parse_chat_message(const char *message) } } -#endif \ No newline at end of file +#endif diff --git a/src/object.c b/src/object.c index 0f83bab287..96badbb090 100644 --- a/src/object.c +++ b/src/object.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include "addresses.h" +#include "config.h" #include "localisation/localisation.h" #include "object.h" #include "platform/platform.h" @@ -30,21 +31,24 @@ #include "world/entrance.h" #include "world/scenery.h" #include "scenario.h" +#include "rct1.h" -int object_load_entry(const char *path, rct_object_entry *outEntry) +char gTempObjectLoadName[9] = { 0 }; + +int object_load_entry(const utf8 *path, rct_object_entry *outEntry) { - FILE *file; + SDL_RWops *file; - file = fopen(path, "rb"); + file = SDL_RWFromFile(path, "rb"); if (file == NULL) return 0; - if (fread(outEntry, sizeof(rct_object_entry), 1, file) != 1) { - fclose(file); + if (SDL_RWread(file, outEntry, sizeof(rct_object_entry), 1) != 1) { + SDL_RWclose(file); return 0; } - fclose(file); + SDL_RWclose(file); return 1; } @@ -52,20 +56,20 @@ int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSi { uint8 objectType; rct_object_entry openedEntry; - char path[260]; - FILE *file; + char path[MAX_PATH]; + SDL_RWops* rw; subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), (char*)installedObject + 16); log_verbose("loading object, %s", path); - file = fopen(path, "rb"); - if (file == NULL) + rw = SDL_RWFromFile(path, "rb"); + if (rw == NULL) return 0; - fread(&openedEntry, sizeof(rct_object_entry), 1, file); + SDL_RWread(rw, &openedEntry, sizeof(rct_object_entry), 1); if (!object_entry_compare(&openedEntry, entry)) { - fclose(file); + SDL_RWclose(rw); return 0; } @@ -76,18 +80,18 @@ int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSi // Read chunk size *chunkSize = *((uint32*)installedObject_pointer); - char *chunk; + uint8 *chunk; if (*chunkSize == 0xFFFFFFFF) { chunk = rct2_malloc(0x600000); - *chunkSize = sawyercoding_read_chunk(file, chunk); + *chunkSize = sawyercoding_read_chunk(rw, chunk); chunk = rct2_realloc(chunk, *chunkSize); } else { chunk = rct2_malloc(*chunkSize); - *chunkSize = sawyercoding_read_chunk(file, chunk); + *chunkSize = sawyercoding_read_chunk(rw, chunk); } - fclose(file); + SDL_RWclose(rw); @@ -133,7 +137,7 @@ int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSi memcpy(extended_entry, &openedEntry, sizeof(rct_object_entry)); extended_entry->chunk_size = *chunkSize; - RCT2_GLOBAL(RCT2_ADDRESS_CURR_OBJECT_CHUNK_POINTER, char*) = chunk; + RCT2_GLOBAL(RCT2_ADDRESS_CURR_OBJECT_CHUNK_POINTER, uint8*) = chunk; if (RCT2_GLOBAL(0x9ADAFD, uint8) != 0) object_paint(objectType, 0, groupIndex, objectType, 0, (int)chunk, 0, 0); @@ -175,7 +179,7 @@ int object_load(int groupIndex, rct_object_entry *entry, int* chunkSize) * ebx : file * ebp : entry */ -int write_object_file(FILE *file, rct_object_entry* entry){ +int write_object_file(SDL_RWops *rw, rct_object_entry* entry){ uint8 entryGroupIndex = 0, type = 0; uint8* chunk = 0; @@ -199,7 +203,7 @@ int write_object_file(FILE *file, rct_object_entry* entry){ chunkHeader.length = installed_entry->chunk_size; size_dst += sawyercoding_write_chunk_buffer(dst_buffer + sizeof(rct_object_entry), chunk, chunkHeader); - fwrite(dst_buffer, 1, size_dst, file); + SDL_RWwrite(rw, dst_buffer, 1, size_dst); free(dst_buffer); return 1; @@ -209,16 +213,16 @@ int write_object_file(FILE *file, rct_object_entry* entry){ * * rct2: 0x006AA2B7 */ -int object_load_packed(FILE *file) +int object_load_packed(SDL_RWops* rw) { object_unload_all(); rct_object_entry entry; - fread(&entry, 16, 1, file); + SDL_RWread(rw, &entry, 16, 1); uint8* chunk = rct2_malloc(0x600000); - uint32 chunkSize = sawyercoding_read_chunk(file, chunk); + uint32 chunkSize = sawyercoding_read_chunk(rw, chunk); chunk = rct2_realloc(chunk, chunkSize); if (chunk == NULL){ @@ -255,7 +259,7 @@ int object_load_packed(FILE *file) } if (entryGroupIndex == object_entry_group_counts[type]){ - // This should never occur. Objects are not loaded before installing a + // 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); @@ -281,7 +285,7 @@ int object_load_packed(FILE *file) } // Convert the entry name to a upper case path name - char path[260]; + char path[MAX_PATH]; char objectPath[9] = { 0 }; for (int i = 0; i < 8; ++i){ if (entry.name[i] != ' ') @@ -313,11 +317,11 @@ int object_load_packed(FILE *file) } // Actually write the object to the file - FILE* obj_file = fopen(path, "wb"); - if (obj_file){ - uint8 result = write_object_file(obj_file, &entry); + SDL_RWops* rw_out = SDL_RWFromFile(path, "wb"); + if (rw_out != NULL){ + uint8 result = write_object_file(rw_out, &entry); - fclose(obj_file); + SDL_RWclose(rw_out); object_unload_all(); return result; @@ -331,9 +335,19 @@ int object_load_packed(FILE *file) * * rct2: 0x006A9CAF */ -void object_unload(int groupIndex, rct_object_entry_extended *entry) +void object_unload(rct_object_entry *entry) { - RCT2_CALLPROC_X(0x006A9CAF, 0, groupIndex, 0, 0, 0, 0, (int)entry); + uint8 object_type, object_index; + if (!find_object_in_entry_group(entry, &object_type, &object_index)){ + return; + } + + uint8* chunk = object_entry_groups[object_type].chunks[object_index]; + + object_paint(object_type, 1, 0, 0, 0, (int)chunk, 0, 0); + + rct2_free(chunk); + object_entry_groups[object_type].chunks[object_index] = (uint8*)-1; } int object_entry_compare(const rct_object_entry *a, const rct_object_entry *b) @@ -361,7 +375,7 @@ int object_entry_compare(const rct_object_entry *a, const rct_object_entry *b) return 1; } -int object_calculate_checksum(const rct_object_entry *entry, const char *data, int dataLength) +int object_calculate_checksum(const rct_object_entry *entry, const uint8 *data, int dataLength) { int i; const char *eee = (char*)entry; @@ -386,7 +400,7 @@ int object_calculate_checksum(const rct_object_entry *entry, const char *data, i 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; @@ -425,9 +439,14 @@ int paint_ride_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dp 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); + + //TODO: Move to its own function when ride construction window is merged. + if(gConfigInterface.select_by_track_type) { + ride_type->enabledTrackPieces = 0xFFFFFFFFFFFFFFFF; + } + object_get_localised_text(&chunk, ecx, ebx, 2); - // Offset to Unknown struct - ride_type->var_1AE = (uint32_t)chunk; + ride_type->vehicle_preset_list = (vehicle_colour_preset_list*)chunk; // If Unknown struct size is 0xFF then there are 32 3 byte structures uint8 unknown_size = *chunk++; @@ -439,7 +458,7 @@ int paint_ride_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dp chunk += 0x60; } - sint8* peep_loading_positions = chunk; + sint8* peep_loading_positions = (sint8 *)chunk; // Peep loading positions variable size // 4 different vehicle subtypes are available for (int i = 0; i < 4; ++i){ @@ -461,20 +480,18 @@ int paint_ride_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dp for (int i = 0; i < 4; ++i){ rct_ride_type_vehicle* rideVehicleEntry = &ride_type->vehicles[i]; - if (rideVehicleEntry->var_0C & 1){ + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT) { int al = 1; - if (rideVehicleEntry->var_14 & 2) - { + if (rideVehicleEntry->var_14 & 2) { al = 13; - if ((rideVehicleEntry->var_14 & 0x820) != 0x820) - { + if ((rideVehicleEntry->var_14 & 0x820) != 0x820) { al = 7; - if (!(rideVehicleEntry->var_14 & 0x20)) - { - if (!(rideVehicleEntry->var_14 & 0x800)) - { + if (!(rideVehicleEntry->var_14 & 0x20)) { + if (!(rideVehicleEntry->var_14 & 0x800)) { al = 5; - if (rideVehicleEntry->var_14 & 0x200) al = 3; + if (rideVehicleEntry->var_14 & 0x200) { + al = 3; + } } } } @@ -495,7 +512,7 @@ int paint_ride_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dp } } } - if (rideVehicleEntry->var_12 & 0x1000) al = rideVehicleEntry->var_60; + if (rideVehicleEntry->var_12 & 0x1000) al = rideVehicleEntry->special_frames; rideVehicleEntry->var_02 = al; // 0x6DE946 @@ -503,16 +520,16 @@ int paint_ride_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dp rideVehicleEntry->base_image_id = cur_vehicle_images_offset; int image_index = rideVehicleEntry->base_image_id; - if (rideVehicleEntry->var_5D != 4){ + if (rideVehicleEntry->car_visual != VEHICLE_VISUAL_RIVER_RAPIDS) { int b = rideVehicleEntry->var_16 * 32; if (rideVehicleEntry->var_12 & 0x800) b /= 2; - if (rideVehicleEntry->var_0C & 0x8000) b /= 8; + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_15) b /= 8; image_index += b; // Incline 25 - if (rideVehicleEntry->var_0C & 0x2){ + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_GENTLE_SLOPES) { rideVehicleEntry->var_20 = image_index; b = rideVehicleEntry->var_16 * 72; if (rideVehicleEntry->var_12 & 0x4000) @@ -522,81 +539,81 @@ int paint_ride_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dp } // Incline 60 - if (rideVehicleEntry->var_0C & 0x4){ + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_STEEP_SLOPES) { rideVehicleEntry->var_24 = image_index; b = rideVehicleEntry->var_16 * 80; image_index += b; } // Verticle - if (rideVehicleEntry->var_0C & 0x8){ + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_VERTICAL_SLOPES) { rideVehicleEntry->var_28 = image_index; b = rideVehicleEntry->var_16 * 116; image_index += b; } // Unknown - if (rideVehicleEntry->var_0C & 0x10){ + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_DIAGONAL_SLOPES) { rideVehicleEntry->var_2C = image_index; b = rideVehicleEntry->var_16 * 24; image_index += b; } // Bank - if (rideVehicleEntry->var_0C & 0x20){ + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT_BANKED) { rideVehicleEntry->var_30 = image_index; b = rideVehicleEntry->var_16 * 80; image_index += b; } - if (rideVehicleEntry->var_0C & 0x40){ + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_INLINE_TWISTS) { rideVehicleEntry->var_34 = image_index; b = rideVehicleEntry->var_16 * 40; image_index += b; } // Track half? Up/Down - if (rideVehicleEntry->var_0C & 0x80){ + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_BANKED_TRANSITIONS) { rideVehicleEntry->var_38 = image_index; b = rideVehicleEntry->var_16 * 128; image_index += b; } // Unknown - if (rideVehicleEntry->var_0C & 0x100){ + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_DIAGONAL_GENTLE_SLOPE_BANKED_TRANSITIONS) { rideVehicleEntry->var_3C = image_index; b = rideVehicleEntry->var_16 * 16; image_index += b; } // Unknown - if (rideVehicleEntry->var_0C & 0x200){ + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TRANSITIONS) { rideVehicleEntry->var_40 = image_index; b = rideVehicleEntry->var_16 * 16; image_index += b; } - if (rideVehicleEntry->var_0C & 0x400){ + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TURNS) { rideVehicleEntry->var_44 = image_index; b = rideVehicleEntry->var_16 * 128; image_index += b; } - if (rideVehicleEntry->var_0C & 0x800){ + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_WHILE_BANKED_TRANSITIONS) { rideVehicleEntry->var_48 = image_index; b = rideVehicleEntry->var_16 * 16; image_index += b; } - if (rideVehicleEntry->var_0C & 0x1000){ + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_CORKSCREWS) { rideVehicleEntry->var_4C = image_index; b = rideVehicleEntry->var_16 * 80; image_index += b; } // Unknown - if (rideVehicleEntry->var_0C & 0x2000){ + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_RESTRAINT_ANIMATION) { rideVehicleEntry->var_1C = image_index; b = rideVehicleEntry->var_16 * 12; image_index += b; } - if (rideVehicleEntry->var_0C & 0x4000){ + if (rideVehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_14) { // Same offset as above??? rideVehicleEntry->var_4C = image_index; b = rideVehicleEntry->var_16 * 32; @@ -615,31 +632,16 @@ int paint_ride_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dp // 0x6DEB0D if (!(rideVehicleEntry->var_12 & 0x400)){ - int ecx = cur_vehicle_images_offset - rideVehicleEntry->base_image_id; + int num_images = cur_vehicle_images_offset - rideVehicleEntry->base_image_id; if (rideVehicleEntry->var_12 & 0x2000){ - ecx *= 2; + num_images *= 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; + set_vehicle_type_image_max_sizes(rideVehicleEntry, num_images); } - uint8 no_positions = *peep_loading_positions++; - if (no_positions == 0xFF) + sint8 no_positions = *peep_loading_positions++; + if (no_positions == -1) { // The no_positions is 16 bit skip over peep_loading_positions += 2; @@ -677,7 +679,7 @@ int paint_ride_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dp 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; + if ((ride_type->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) && !rideTypeShouldLoseSeparateFlag(ride_type)) di |= 0x1000000; RCT2_GLOBAL(0xF433DD, uint32) = di; return 0;// flags; @@ -711,16 +713,16 @@ int paint_ride_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dp rideVehicleEntry->var_16 = 0; if (!(rideVehicleEntry->var_12 & 0x400)){ - rideVehicleEntry->var_0E = 0; - rideVehicleEntry->var_0F = 0; - rideVehicleEntry->var_10 = 0; + rideVehicleEntry->sprite_width = 0; + rideVehicleEntry->sprite_height_negative = 0; + rideVehicleEntry->sprite_height_positive = 0; } rideVehicleEntry->var_02 = 0; rideVehicleEntry->var_03 = 0; rideVehicleEntry->peep_loading_positions = 0; } - ride_type->var_1AE = 0; + ride_type->vehicle_preset_list = NULL; return flags; } else if ((flags & 0xFF) == 2){ @@ -750,12 +752,12 @@ int paint_ride_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dp 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)) + if (!(ride_type->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) || rideTypeShouldLoseSeparateFlag(ride_type)) { format_args = ride_type->ride_type[0]; if ((format_args & 0xFF) == 0xFF) @@ -1411,7 +1413,7 @@ int paint_water_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* d return 0; } else if ((flags & 0xFF) == 3){ - if (!((flags >> 8) & 0xFF)) + if (!((flags >> 8) & 0xFF)) gfx_draw_string_centred(dpi, 3326, ecx, edx, 0, (void*)esi); } return flags; @@ -1463,7 +1465,7 @@ int object_paint(int type, int eax, int ebx, int ecx, int edx, int esi, int edi, switch (type) { case OBJECT_TYPE_RIDE: - return paint_ride_entry(eax, ebx, ecx, edx, (rct_drawpixelinfo*)edi, esi, ebp); + 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: @@ -1473,7 +1475,7 @@ int object_paint(int type, int eax, int ebx, int ecx, int edx, int esi, int edi, 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); + 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: @@ -1499,21 +1501,21 @@ int object_get_scenario_text(rct_object_entry *entry) rct_object_entry *installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); 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 path[MAX_PATH]; 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); + SDL_RWops* rw = SDL_RWFromFile(path, "rb"); + if (rw != NULL) { + SDL_RWread(rw, &openedEntry, sizeof(rct_object_entry), 1); if (object_entry_compare(&openedEntry, entry)) { // Skip over the object entry @@ -1524,17 +1526,17 @@ int object_get_scenario_text(rct_object_entry *entry) // Read chunk int chunkSize = *((uint32*)pos); - char *chunk; + uint8 *chunk; if (chunkSize == 0xFFFFFFFF) { chunk = malloc(0x600000); - chunkSize = sawyercoding_read_chunk(file, chunk); + chunkSize = sawyercoding_read_chunk(rw, chunk); chunk = realloc(chunk, chunkSize); } else { chunk = malloc(chunkSize); - sawyercoding_read_chunk(file, chunk); + sawyercoding_read_chunk(rw, chunk); } - fclose(file); + SDL_RWclose(rw); // Calculate and check checksum if (object_calculate_checksum(&openedEntry, chunk, chunkSize) != openedEntry.checksum) { @@ -1564,9 +1566,10 @@ int object_get_scenario_text(rct_object_entry *entry) // Tell text to be loaded into a different address RCT2_GLOBAL(0x009ADAFC, uint8) = 255; + memcpy(gTempObjectLoadName, openedEntry.name, 8); // Not used?? RCT2_GLOBAL(0x009ADAFD, uint8) = 1; - object_paint(openedEntry.flags & 0x0F, 0, 0, 0, 0, (int)chunk, 0, 0); + 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?? @@ -1575,7 +1578,7 @@ int object_get_scenario_text(rct_object_entry *entry) return 1; } log_error("Opened object didn't match."); - fclose(file); + SDL_RWclose(rw); return 0; } log_error("File failed to open."); @@ -1590,7 +1593,7 @@ int object_get_scenario_text(rct_object_entry *entry) void object_free_scenario_text() { if (RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, void*) != NULL) { - rct2_free(RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, void*)); + free(RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, void*)); RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, void*) = NULL; } } @@ -1619,13 +1622,13 @@ rct_object_entry *object_get_next(rct_object_entry *entry) // Skip size of chunk pos += 4; - // Skip + // Skip required objects pos += *pos * 16 + 1; // Skip theme objects pos += *pos * 16 + 1; - // Skip + // Skip pos += 4; return (rct_object_entry*)pos; @@ -1644,5 +1647,5 @@ char *object_get_name(rct_object_entry *entry) // Skip no of images pos += 4; - return pos; -} \ No newline at end of file + return (char *)pos; +} diff --git a/src/object.h b/src/object.h index cfe41692d6..dfbfc30901 100644 --- a/src/object.h +++ b/src/object.h @@ -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,7 @@ #define _OBJECT_H_ #include "common.h" +#include "platform/platform.h" // First 0xF of rct_object_entry->flags typedef enum{ @@ -38,6 +39,17 @@ typedef enum{ OBJECT_TYPE_SCENARIO_TEXT }OBJECT_TYPE; +typedef enum{ + OBJECT_SELECTION_FLAG_SELECTED = (1 << 0), + OBJECT_SELECTION_FLAG_2 = (1 << 1), + OBJECT_SELECTION_FLAG_IN_USE = (1 << 2), + OBJECT_SELECTION_FLAG_REQUIRED = (1 << 3), + OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED = (1 << 4), + OBJECT_SELECTION_FLAG_6 = (1 << 5), + OBJECT_SELECTION_FLAG_7 = (1 << 6), + OBJECT_SELECTION_FLAG_8 = (1 << 7), +}OBJECT_SELECTION_FLAGS; + /** * Object entry structure. * size: 0x10 @@ -63,13 +75,13 @@ extern int object_entry_group_counts[]; extern int object_entry_group_encoding[]; typedef struct { - uint8 **chunks; + uint8 **chunks; rct_object_entry_extended *entries; } rct_object_entry_group; typedef struct { uint8 category[2]; - + uint8 ride_type; } rct_ride_filters; typedef struct { @@ -79,28 +91,30 @@ typedef struct { } rct_object_filters; extern rct_object_entry_group object_entry_groups[]; +extern char gTempObjectLoadName[9]; -int object_load_entry(const char *path, rct_object_entry *outEntry); +int object_load_entry(const utf8 *path, rct_object_entry *outEntry); void object_list_load(); void set_load_objects_fail_reason(); -int object_read_and_load_entries(FILE *file); -int object_load_packed(FILE *file); +int object_read_and_load_entries(SDL_RWops* rw); +int object_load_packed(SDL_RWops* rw); 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); +void object_unload(rct_object_entry *entry); int object_get_scenario_text(rct_object_entry *entry); void object_free_scenario_text(); int object_get_length(rct_object_entry *entry); 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_calculate_checksum(const rct_object_entry *entry, const uint8 *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 write_object_file(FILE *file, rct_object_entry* entry); +int write_object_file(SDL_RWops* rw, rct_object_entry* entry); void reset_loaded_objects(); int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8* entry_index); +void object_create_identifier_name(char* string_buffer, const rct_object_entry* object); rct_object_entry *object_list_find(rct_object_entry *entry); @@ -108,4 +122,4 @@ char *object_get_name(rct_object_entry *entry); rct_object_filters *get_object_filter(int index); -#endif \ No newline at end of file +#endif diff --git a/src/object_list.c b/src/object_list.c index 7c11b55a7b..12410c6580 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -8,23 +8,29 @@ * 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 "localisation/localisation.h" #include "object.h" #include "platform/platform.h" #include "ride/track.h" #include "util/sawyercoding.h" #include "game.h" +#include "rct1.h" +#include "world/entrance.h" +#include "world/footpath.h" +#include "world/scenery.h" +#include "world/water.h" #define OBJECT_ENTRY_GROUP_COUNT 11 #define OBJECT_ENTRY_COUNT 721 @@ -92,7 +98,7 @@ static void load_object_filter(rct_object_entry* entry, uint8* chunk, rct_object static rct_object_filters *_installedObjectFilters = NULL; -static void get_plugin_path(char *outPath) +static void get_plugin_path(utf8 *outPath) { platform_get_user_directory(outPath, NULL); strcat(outPath, "plugin.dat"); @@ -100,8 +106,8 @@ static void get_plugin_path(char *outPath) static void object_list_sort() { - rct_object_entry **objectBuffer, *newBuffer, *entry, *destEntry, *lowestEntry; - rct_object_filters *newFilters, *destFilter; + rct_object_entry **objectBuffer, *newBuffer, *entry, *destEntry, *lowestEntry = NULL; + rct_object_filters *newFilters = NULL, *destFilter = NULL; int numObjects, i, j, bufferSize, entrySize, lowestIndex; char *objectName, *lowestString; uint8 *copied; @@ -109,7 +115,7 @@ static void object_list_sort() 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++) @@ -160,7 +166,7 @@ static void object_list_sort() } /** - * + * * rct2: 0x006A93CD */ static void object_list_examine() @@ -231,7 +237,7 @@ static int object_list_query_directory(int *outTotalFiles, uint64 *outTotalFileS } /** - * + * * rct2: 0x006A8B40 */ void object_list_load() @@ -276,6 +282,7 @@ void object_list_load() uint32 fileCount = 0; uint32 objectCount = 0; uint32 current_item_offset = 0; + uint32 next_offset = 0; RCT2_GLOBAL(RCT2_ADDRESS_ORIGINAL_RCT2_OBJECT_COUNT, uint32) = 0; log_verbose("building cache of available objects..."); @@ -284,17 +291,17 @@ void object_list_load() 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; - + while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { fileCount++; if ((installed_buffer_size - current_item_offset) <= 2842){ 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); + 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){ log_error("Failed to allocate memory for object list"); rct2_exit_reason(835, 3162); @@ -317,10 +324,13 @@ void object_list_load() 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; + next_offset = install_object_entry(&entry, installed_entry, enumFileInfo.path, &filter); + if (next_offset) { + current_item_offset += next_offset; - objectCount++; + _installedObjectFilters[objectCount] = filter; + objectCount++; + } } platform_enumerate_files_end(enumFileHandle); } @@ -341,20 +351,20 @@ void object_list_load() static int object_list_cache_load(int totalFiles, uint64 totalFileSize, int fileDateModifiedChecksum) { char path[MAX_PATH]; - FILE *file; + SDL_RWops *file; rct_plugin_header pluginHeader; uint32 filterVersion = 0; log_verbose("loading object list cache (plugin.dat)"); get_plugin_path(path); - file = fopen(path, "rb"); + file = SDL_RWFromFile(path, "rb"); if (file == NULL) { log_verbose("Unable to load %s", path); return 0; } - if (fread(&pluginHeader, sizeof(rct_plugin_header), 1, file) == 1) { + if (SDL_RWread(file, &pluginHeader, sizeof(rct_plugin_header), 1) == 1) { // Check if object repository has changed in anyway if ( pluginHeader.total_files == totalFiles && @@ -369,20 +379,20 @@ static int object_list_cache_load(int totalFiles, uint64 totalFileSize, int file // Read installed object list RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*) = rct2_malloc(pluginHeader.object_list_size); - if (fread(RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*), pluginHeader.object_list_size, 1, file) == 1) { + if (SDL_RWread(file, RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, void*), pluginHeader.object_list_size, 1) == 1) { RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32) = pluginHeader.object_list_no_items; 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 (SDL_RWread(file, &filterVersion, sizeof(filterVersion), 1) == 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); + if (SDL_RWread(file, _installedObjectFilters, sizeof(rct_object_filters) * pluginHeader.object_list_no_items, 1) == 1) { + + SDL_RWclose(file); reset_loaded_objects(); object_list_examine(); return 1; @@ -405,11 +415,11 @@ static int object_list_cache_load(int totalFiles, uint64 totalFileSize, int file log_info("Objects files have been updated... updating object list cache"); } - fclose(file); + SDL_RWclose(file); return 0; } - fclose(file); + SDL_RWclose(file); log_error("loading object list cache failed"); return 0; @@ -417,11 +427,11 @@ static int object_list_cache_load(int totalFiles, uint64 totalFileSize, int file static int object_list_cache_save(int fileCount, uint64 totalFileSize, int fileDateModifiedChecksum, int currentItemOffset) { - char path[MAX_PATH]; - FILE *file; + utf8 path[MAX_PATH]; + SDL_RWops *file; rct_plugin_header pluginHeader; uint32 filterVersion = FILTER_VERSION; - + log_verbose("saving object list cache (plugin.dat)"); pluginHeader.total_files = fileCount | 0x01000000; @@ -431,17 +441,17 @@ static int object_list_cache_save(int fileCount, uint64 totalFileSize, int fileD pluginHeader.object_list_no_items = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); get_plugin_path(path); - file = fopen(path,"wb"); + file = SDL_RWFromFile(path,"wb"); if (file == NULL) { log_error("Failed to save %s", path); return 0; } - 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); + SDL_RWwrite(file, &pluginHeader, sizeof(rct_plugin_header), 1); + SDL_RWwrite(file, RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, uint8*), pluginHeader.object_list_size, 1); + SDL_RWwrite(file, &filterVersion, sizeof(filterVersion), 1); + SDL_RWwrite(file, _installedObjectFilters, sizeof(rct_object_filters) * RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32), 1); + SDL_RWclose(file); return 1; } @@ -451,6 +461,30 @@ int check_object_entry(rct_object_entry *entry) return (0xFFFFFFFF & dwords[0] & dwords[1] & dwords[2] & dwords[3]) + 1 != 0; } +/* rct2: 0x006AB344 */ +void object_create_identifier_name(char* string_buffer, const rct_object_entry* object){ + for (uint8 i = 0; i < 8; ++i){ + if (object->name[i] != ' '){ + *string_buffer++ = object->name[i]; + } + } + + *string_buffer++ = '/'; + + for (uint8 i = 0; i < 4; ++i){ + uint8 flag_part = (object->flags >> (i * 8)) & 0xFF; + *string_buffer++ = RCT2_ADDRESS(0x0098DA64, char)[flag_part >> 4]; + *string_buffer++ = RCT2_ADDRESS(0x0098DA64, char)[flag_part & 0xF]; + } + + for (uint8 i = 0; i < 4; ++i){ + uint8 checksum_part = (object->checksum >> (i * 8)) & 0xFF; + *string_buffer++ = RCT2_ADDRESS(0x0098DA64, char)[checksum_part >> 4]; + *string_buffer++ = RCT2_ADDRESS(0x0098DA64, char)[checksum_part & 0xF]; + } + *string_buffer++ = '\0'; +} + /* rct2: 0x675827 */ void set_load_objects_fail_reason(){ rct_object_entry* object = RCT2_ADDRESS(0x13CE952, rct_object_entry); @@ -463,7 +497,7 @@ 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); + object_create_identifier_name(string_buffer, object); RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 0xFF; RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = 3165; return; @@ -485,10 +519,10 @@ void set_load_objects_fail_reason(){ } /** - * + * * rct2: 0x006AA0C6 */ -int object_read_and_load_entries(FILE *file) +int object_read_and_load_entries(SDL_RWops* rw) { object_unload_all(); @@ -499,7 +533,7 @@ int object_read_and_load_entries(FILE *file) // Read all the object entries entries = malloc(OBJECT_ENTRY_COUNT * sizeof(rct_object_entry)); - sawyercoding_read_chunk(file, (uint8*)entries); + sawyercoding_read_chunk(rw, (uint8*)entries); uint8 load_fail = 0; // Load each object @@ -523,7 +557,7 @@ int object_read_and_load_entries(FILE *file) } } - free(entries); + free(entries); if (load_fail){ object_unload_all(); RCT2_GLOBAL(0x14241BC, uint32) = 0; @@ -537,7 +571,7 @@ int object_read_and_load_entries(FILE *file) /** - * + * * rct2: 0x006A9CE8 */ void object_unload_all() @@ -547,7 +581,7 @@ void object_unload_all() for (i = 0; i < OBJECT_ENTRY_GROUP_COUNT; i++) for (j = 0; j < object_entry_group_counts[i]; j++) if (object_entry_groups[i].chunks[j] != (uint8*)0xFFFFFFFF) - object_unload(j, &object_entry_groups[i].entries[j]); + object_unload((rct_object_entry*)&object_entry_groups[i].entries[j]); reset_loaded_objects(); } @@ -597,7 +631,7 @@ void object_list_create_hash_table() // Set hash table slot _installedObjectHashTable[index] = installedObject; - + // Next installed object installedObject = object_get_next(installedObject); } @@ -611,8 +645,8 @@ int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8 *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]; + for (*entry_index = 0; + *entry_index < object_entry_group_counts[*entry_type]; ++(*entry_index), entry_group.chunks++, entry_group.entries++){ @@ -643,6 +677,33 @@ rct_object_entry *object_list_find(rct_object_entry *entry) return NULL; } +rct_string_id object_get_name_string_id(rct_object_entry *entry, const void *chunk) +{ + int objectType = entry->flags & 0x0F; + switch (objectType) { + case OBJECT_TYPE_RIDE: + return ((rct_ride_type*)chunk)->name; + case OBJECT_TYPE_SMALL_SCENERY: + case OBJECT_TYPE_LARGE_SCENERY: + case OBJECT_TYPE_WALLS: + case OBJECT_TYPE_BANNERS: + case OBJECT_TYPE_PATH_BITS: + return ((rct_scenery_entry*)chunk)->name; + case OBJECT_TYPE_PATHS: + return ((rct_path_type*)chunk)->string_idx; + case OBJECT_TYPE_SCENERY_SETS: + return ((rct_scenery_set_entry*)chunk)->name; + case OBJECT_TYPE_PARK_ENTRANCE: + return ((rct_entrance_type*)chunk)->string_idx; + case OBJECT_TYPE_WATER: + return ((rct_water_type*)chunk)->string_idx; + case OBJECT_TYPE_SCENARIO_TEXT: + return ((rct_stex_entry*)chunk)->scenario_name; + default: + return STR_NONE; + } +} + /* Installs an object_entry at the desired installed_entry address * Returns the size of the new entry. Will return 0 on failure. */ @@ -653,7 +714,7 @@ static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* in memcpy(installed_entry_pointer, entry, sizeof(rct_object_entry)); installed_entry_pointer += sizeof(rct_object_entry); - strcpy(installed_entry_pointer, path); + strcpy((char *)installed_entry_pointer, path); while (*installed_entry_pointer++); // Chunk size is set to unknown @@ -698,7 +759,7 @@ static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* in 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); + object_unload(entry); return 0; } } @@ -709,29 +770,15 @@ static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* in 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 = ride_type->ride_type[1]; - if (obj_string == 0xFF) { - obj_string = ride_type->ride_type[2]; - } - } - - format_string(installed_entry_pointer, obj_string + 2, 0); - strcat(installed_entry_pointer, "\t ("); - 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((rct_string_id)RCT2_GLOBAL(RCT2_ADDRESS_CURR_OBJECT_BASE_STRING_ID, uint32))); - while (*installed_entry_pointer++); + // Always extract only the vehicle type, since the track type is always displayed in the left column, to prevent duplicate track names. + rct_string_id nameStringId = object_get_name_string_id(entry, chunk); + if (nameStringId == (rct_string_id)STR_NONE) { + nameStringId = (rct_string_id)RCT2_GLOBAL(RCT2_ADDRESS_CURR_OBJECT_BASE_STRING_ID, uint32); } + strcpy((char *)installed_entry_pointer, language_get_string(nameStringId)); + while (*installed_entry_pointer++); + // 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; @@ -758,17 +805,29 @@ static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* in uint32 size_of_object = installed_entry_pointer - (uint8*)installed_entry; - object_unload(objectType, (rct_object_entry_extended*)entry); + object_unload(entry); return size_of_object; } static void load_object_filter(rct_object_entry* entry, uint8* chunk, rct_object_filters* filter) { + rct_ride_type *rideType; + rct_ride_filters *rideFilter; + 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]; + rideType = ((rct_ride_type*)chunk); + rideFilter = &(filter->ride); + + rideFilter->category[0] = rideType->category[0]; + rideFilter->category[1] = rideType->category[1]; + + for (int i = 0; i < 3; i++) { + rideFilter->ride_type = rideType->ride_type[i]; + if (rideFilter->ride_type != 255) + break; + } break; case OBJECT_TYPE_SMALL_SCENERY: case OBJECT_TYPE_LARGE_SCENERY: diff --git a/src/openrct2.c b/src/openrct2.c index 83875fa3d6..6a6692d8d9 100644 --- a/src/openrct2.c +++ b/src/openrct2.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 . *****************************************************************************/ @@ -24,40 +24,95 @@ #include "cmdline.h" #include "config.h" #include "editor.h" +#include "game.h" +#include "hook.h" +#include "interface/chat.h" +#include "interface/window.h" +#include "interface/viewport.h" #include "localisation/localisation.h" #include "network/http.h" +#include "network/network.h" #include "openrct2.h" #include "platform/platform.h" +#include "ride/ride.h" +#include "title.h" #include "util/sawyercoding.h" +#include "util/util.h" #include "world/mapgen.h" +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#include +#include +#include +#include +#include +#include +#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) + int gOpenRCT2StartupAction = STARTUP_ACTION_TITLE; -char gOpenRCT2StartupActionPath[512] = { 0 }; -char gExePath[MAX_PATH]; +utf8 gOpenRCT2StartupActionPath[512] = { 0 }; +utf8 gExePath[MAX_PATH]; +utf8 gCustomUserDataPath[MAX_PATH] = { 0 }; // This should probably be changed later and allow a custom selection of things to initialise like SDL_INIT bool gOpenRCT2Headless = false; bool gOpenRCT2ShowChangelog; +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +void *gDataSegment; +void *gTextSegment; +int gExeFd; +#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) + /** 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(); +// Used for object movement tweening +static struct { sint16 x, y, z; } _spritelocations1[MAX_SPRITES], _spritelocations2[MAX_SPRITES]; -static void openrct2_copy_files_over(const char *originalDirectory, const char *newDirectory, const char *extension) +static void openrct2_loop(); +static bool openrct2_setup_rct2_segment(); +static bool openrct2_release_rct2_segment(); +static void openrct2_setup_rct2_hooks(); + +void openrct2_write_full_version_info(utf8 *buffer, size_t bufferSize) { - char *ch, filter[MAX_PATH], oldPath[MAX_PATH], newPath[MAX_PATH]; + utf8 *ch = buffer; + + // Name and version + strcpy(ch, OPENRCT2_NAME); + strcat(buffer, ", v"); + strcat(buffer, OPENRCT2_VERSION); + + // Build information + if (!str_is_null_or_empty(OPENRCT2_BRANCH)) { + sprintf(strchr(buffer, 0), "-%s", OPENRCT2_BRANCH); + } + if (!str_is_null_or_empty(OPENRCT2_BUILD_NUMBER)) { + sprintf(strchr(buffer, 0), " build %s", OPENRCT2_BUILD_NUMBER); + } + 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); + } +} + +static void openrct2_copy_files_over(const utf8 *originalDirectory, const utf8 *newDirectory, const utf8 *extension) +{ + utf8 *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); + safe_strncpy(filter, originalDirectory, MAX_PATH); ch = strchr(filter, '*'); if (ch != NULL) *ch = 0; @@ -66,26 +121,26 @@ static void openrct2_copy_files_over(const char *originalDirectory, const char * fileEnumHandle = platform_enumerate_files_begin(filter); while (platform_enumerate_files_next(fileEnumHandle, &fileInfo)) { - strcpy(newPath, newDirectory); + safe_strncpy(newPath, newDirectory, MAX_PATH); strcat(newPath, fileInfo.path); - - strcpy(oldPath, originalDirectory); + + safe_strncpy(oldPath, originalDirectory, MAX_PATH); ch = strchr(oldPath, '*'); if (ch != NULL) *ch = 0; strcat(oldPath, fileInfo.path); if (!platform_file_exists(newPath)) - platform_file_copy(oldPath, newPath); + platform_file_copy(oldPath, newPath, false); } platform_enumerate_files_end(fileEnumHandle); fileEnumHandle = platform_enumerate_directories_begin(originalDirectory); while (platform_enumerate_directories_next(fileEnumHandle, filter)) { - strcpy(newPath, newDirectory); + safe_strncpy(newPath, newDirectory, MAX_PATH); strcat(newPath, filter); - strcpy(oldPath, originalDirectory); + safe_strncpy(oldPath, originalDirectory, MAX_PATH); ch = strchr(oldPath, '*'); if (ch != NULL) *ch = 0; @@ -100,21 +155,43 @@ static void openrct2_copy_files_over(const char *originalDirectory, const char * platform_enumerate_directories_end(fileEnumHandle); } +// TODO move to platform static void openrct2_set_exe_path() { - char exePath[MAX_PATH]; - char tempPath[MAX_PATH]; - char *exeDelimiter; - int pathEnd; +#ifdef _WIN32 + wchar_t exePath[MAX_PATH]; + wchar_t tempPath[MAX_PATH]; + wchar_t *exeDelimiter; int exeDelimiterIndex; - GetModuleFileName(NULL, exePath, MAX_PATH); - exeDelimiter = strrchr(exePath, platform_get_path_separator()); + GetModuleFileNameW(NULL, exePath, MAX_PATH); + exeDelimiter = wcsrchr(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); + lstrcpynW(tempPath, exePath, exeDelimiterIndex + 1); + tempPath[exeDelimiterIndex] = L'\0'; + _wfullpath(exePath, tempPath, MAX_PATH); + WideCharToMultiByte(CP_UTF8, 0, exePath, countof(exePath), gExePath, countof(gExePath), NULL, NULL); +#else + char exePath[MAX_PATH]; + ssize_t bytesRead; + bytesRead = readlink("/proc/self/exe", exePath, MAX_PATH); + if (bytesRead == -1) { + log_fatal("failed to read /proc/self/exe"); + } + exePath[bytesRead - 1] = '\0'; + log_verbose("######################################## Setting exe path to %s", exePath); + char *exeDelimiter = strrchr(exePath, platform_get_path_separator()); + if (exeDelimiter == NULL) + { + log_error("should never happen here"); + gExePath[0] = '\0'; + return; + } + int exeDelimiterIndex = (int)(exeDelimiter - exePath); + + safe_strncpy(gExePath, exePath, exeDelimiterIndex + 1); + gExePath[exeDelimiterIndex] = '\0'; +#endif // _WIN32 } /** @@ -122,25 +199,31 @@ static void openrct2_set_exe_path() */ static void openrct2_copy_original_user_files_over() { - char path[MAX_PATH]; + utf8 path[MAX_PATH]; platform_get_user_directory(path, "save"); - openrct2_copy_files_over((char*)RCT2_ADDRESS_SAVED_GAMES_PATH, path, ".sv6"); + openrct2_copy_files_over((utf8*)RCT2_ADDRESS_SAVED_GAMES_PATH, path, ".sv6"); platform_get_user_directory(path, "landscape"); - openrct2_copy_files_over((char*)RCT2_ADDRESS_LANDSCAPES_PATH, path, ".sc6"); + openrct2_copy_files_over((utf8*)RCT2_ADDRESS_LANDSCAPES_PATH, path, ".sc6"); } bool openrct2_initialise() { - char userPath[MAX_PATH]; + utf8 userPath[MAX_PATH]; + platform_resolve_user_data_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; } + if (!openrct2_setup_rct2_segment()) { + log_fatal("Unable to load RCT2 data sector"); + return false; + } + openrct2_set_exe_path(); config_set_defaults(); @@ -158,29 +241,53 @@ bool openrct2_initialise() 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; - } + // 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(); + audio_populate_devices(); + } + if (!language_open(gConfigGeneral.language)) { + log_error("Failed to open configured language..."); + + if (!language_open(LANGUAGE_ENGLISH_UK)) { + log_fatal("Failed to open fallback language..."); + return false; + } } - language_open(gConfigGeneral.language); http_init(); themes_set_default(); themes_load_presets(); + title_sequences_set_default(); + title_sequences_load_presets(); + + openrct2_setup_rct2_hooks(); if (!rct2_init()) return false; + chat_init(); + openrct2_copy_original_user_files_over(); - Mixer_Init(NULL); + // TODO move to audio initialise function + if (str_is_null_or_empty(gConfigSound.device)) { + Mixer_Init(NULL); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) = 0; + } else { + Mixer_Init(gConfigSound.device); + for (int i = 0; i < gAudioDeviceCount; i++) { + if (strcmp(gAudioDevices[i].name, gConfigSound.device) == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) = i; + } + } + } + return true; } @@ -191,18 +298,28 @@ void openrct2_launch() { if (openrct2_initialise()) { RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) = 0; + if((gOpenRCT2StartupAction == STARTUP_ACTION_TITLE) && gConfigGeneral.play_intro) + gOpenRCT2StartupAction = STARTUP_ACTION_INTRO; + switch (gOpenRCT2StartupAction) { case STARTUP_ACTION_INTRO: - RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) = 8; + RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) = 1; 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); + if (rct2_open_file(gOpenRCT2StartupActionPath) == 0) + break; RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_PLAYING; + +#ifndef DISABLE_NETWORK + if (gNetworkStart == NETWORK_MODE_SERVER) { + network_begin_server(gNetworkStartPort); + } +#endif // DISABLE_NETWORK break; case STARTUP_ACTION_EDIT: if (strlen(gOpenRCT2StartupActionPath) == 0) { @@ -211,7 +328,14 @@ void openrct2_launch() editor_load_landscape(gOpenRCT2StartupActionPath); } break; - } + } + +#ifndef DISABLE_NETWORK + if (gNetworkStart == NETWORK_MODE_CLIENT) { + network_begin_client(gNetworkStartHost, gNetworkStartPort); + } +#endif // DISABLE_NETWORK + openrct2_loop(); } openrct2_dispose(); @@ -222,35 +346,135 @@ void openrct2_launch() void openrct2_dispose() { + network_close(); http_dispose(); language_close_all(); + openrct2_release_rct2_segment(); platform_free(); } +/** + * Determines whether its worth tweening a sprite or not when frame smoothing is on. + */ +static bool sprite_should_tween(rct_sprite *sprite) +{ + if (sprite->unknown.linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_VEHICLE) + return true; + if (sprite->unknown.linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_PEEP) + return true; + if (sprite->unknown.linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_UNKNOWN) + return true; + + return false; +} + /** * Run the main game loop until the finished flag is set at 40fps (25ms interval). */ static void openrct2_loop() { uint32 currentTick, ticksElapsed, lastTick = 0; + static uint32 uncapTick = 0; + static int fps = 0; + static uint32 secondTick = 0; log_verbose("begin openrct2 loop"); _finished = 0; do { - currentTick = SDL_GetTicks(); - ticksElapsed = currentTick - lastTick; - if (ticksElapsed < 25) { - if (ticksElapsed < 15) - SDL_Delay(15 - ticksElapsed); - continue; + if (gConfigGeneral.uncap_fps && gGameSpeed <= 4) { + currentTick = SDL_GetTicks(); + if (uncapTick == 0) { + // Reset sprite locations + uncapTick = SDL_GetTicks(); + openrct2_reset_object_tween_locations(); + } + + // Limit number of updates per loop (any long pauses or debugging can make this update for a very long time) + if (currentTick - uncapTick > 25 * 60) { + uncapTick = currentTick - 25 - 1; + } + + platform_process_messages(); + + while (uncapTick <= currentTick && currentTick - uncapTick > 25) { + // Get the original position of each sprite + for (uint16 i = 0; i < MAX_SPRITES; i++) { + _spritelocations1[i].x = g_sprite_list[i].unknown.x; + _spritelocations1[i].y = g_sprite_list[i].unknown.y; + _spritelocations1[i].z = g_sprite_list[i].unknown.z; + } + + // Update the game so the sprite positions update + rct2_update(); + + // Get the next position of each sprite + for (uint16 i = 0; i < MAX_SPRITES; i++) { + _spritelocations2[i].x = g_sprite_list[i].unknown.x; + _spritelocations2[i].y = g_sprite_list[i].unknown.y; + _spritelocations2[i].z = g_sprite_list[i].unknown.z; + } + + uncapTick += 25; + } + + // Tween the position of each sprite from the last position to the new position based on the time between the last + // tick and the next tick. + float nudge = 1 - ((float)(currentTick - uncapTick) / 25); + for (uint16 i = 0; i < MAX_SPRITES; i++) { + if (!sprite_should_tween(&g_sprite_list[i])) + continue; + + sprite_move( + _spritelocations2[i].x + (sint16)((_spritelocations1[i].x - _spritelocations2[i].x) * nudge), + _spritelocations2[i].y + (sint16)((_spritelocations1[i].y - _spritelocations2[i].y) * nudge), + _spritelocations2[i].z + (sint16)((_spritelocations1[i].z - _spritelocations2[i].z) * nudge), + &g_sprite_list[i] + ); + invalidate_sprite_2(&g_sprite_list[i]); + } + + if ((SDL_GetWindowFlags(gWindow) & (SDL_WINDOW_MINIMIZED | SDL_WINDOW_HIDDEN)) == 0) { + rct2_draw(); + platform_draw(); + } + + fps++; + if (SDL_GetTicks() - secondTick >= 1000) { + fps = 0; + secondTick = SDL_GetTicks(); + } + + // Restore the real positions of the sprites so they aren't left at the mid-tween positions + for (uint16 i = 0; i < MAX_SPRITES; i++) { + if (!sprite_should_tween(&g_sprite_list[i])) + continue; + + invalidate_sprite_2(&g_sprite_list[i]); + sprite_move(_spritelocations2[i].x, _spritelocations2[i].y, _spritelocations2[i].z, &g_sprite_list[i]); + } + network_update(); + } else { + uncapTick = 0; + currentTick = SDL_GetTicks(); + ticksElapsed = currentTick - lastTick; + if (ticksElapsed < 25) { + if (ticksElapsed < 15) + SDL_Delay(15 - ticksElapsed); + continue; + } + + lastTick = currentTick; + + platform_process_messages(); + + rct2_update(); + + if ((SDL_GetWindowFlags(gWindow) & (SDL_WINDOW_MINIMIZED | SDL_WINDOW_HIDDEN)) == 0) { + rct2_draw(); + platform_draw(); + } } - - lastTick = currentTick; - - platform_process_messages(); - rct2_update(); - platform_draw(); } while (!_finished); } @@ -260,4 +484,180 @@ static void openrct2_loop() void openrct2_finish() { _finished = 1; -} \ No newline at end of file +} + +void openrct2_reset_object_tween_locations() +{ + for (uint16 i = 0; i < MAX_SPRITES; i++) { + _spritelocations1[i].x = _spritelocations2[i].x = g_sprite_list[i].unknown.x; + _spritelocations1[i].y = _spritelocations2[i].y = g_sprite_list[i].unknown.y; + _spritelocations1[i].z = _spritelocations2[i].z = g_sprite_list[i].unknown.z; + } +} + +/** + * Loads RCT2's data model and remaps the addresses. + * @returns true if the data integrity check succeeded, otherwise false. + */ +static bool openrct2_setup_rct2_segment() +{ + // POSIX OSes will run OpenRCT2 as a native application and then load in the Windows PE, mapping the appropriate addresses as + // necessary. Windows does not need to do this as OpenRCT2 runs as a DLL loaded from the Windows PE. +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) + #define RDATA_OFFSET 0x004A4000 + #define DATASEG_OFFSET 0x005E2000 + + const char *exepath = "openrct2.exe"; + gExeFd = open(exepath, O_RDONLY); + if (gExeFd < 0) { + log_fatal("failed to open %s, errno = %d", exepath, errno); + exit(1); + } + + // Using PE-bear I was able to figure out all the needed addresses to be filled. + // There are three sections to be loaded: .rdata, .data and .text, plus another + // one to be mapped: DATASEG. + // Out of the three, two can simply be mmapped into memory, while the third one, + // .data has a virtual size which is much completely different to its file size + // (even when taking page-alignment into consideration) + // + // The sections are as follows (dump from gdb) + // [0] 0x401000->0x6f7000 at 0x00001000: .text ALLOC LOAD READONLY CODE HAS_CONTENTS + // [1] 0x6f7000->0x8a325d at 0x002f7000: CODESEG ALLOC LOAD READONLY CODE HAS_CONTENTS + // [2] 0x8a4000->0x9a5894 at 0x004a4000: .rdata ALLOC LOAD DATA HAS_CONTENTS + // [3] 0x9a6000->0x9e2000 at 0x005a6000: .data ALLOC LOAD DATA HAS_CONTENTS + // [4] 0x1428000->0x14282bc at 0x005e2000: DATASEG ALLOC LOAD DATA HAS_CONTENTS + // [5] 0x1429000->0x1452000 at 0x005e3000: .cms_t ALLOC LOAD READONLY CODE HAS_CONTENTS + // [6] 0x1452000->0x14aaf3e at 0x0060c000: .cms_d ALLOC LOAD DATA HAS_CONTENTS + // [7] 0x14ab000->0x14ac58a at 0x00665000: .idata ALLOC LOAD READONLY DATA HAS_CONTENTS + // [8] 0x14ad000->0x14b512f at 0x00667000: .rsrc ALLOC LOAD DATA HAS_CONTENTS + // + // .data section, however, has virtual size of 0xA81C3C, and so + // 0x9a6000 + 0xA81C3C = 0x1427C3C, which after alignment to page size becomes + // 0x1428000, which can be seen as next section, DATASEG + // + // Since mmap does not provide a way to create a mapping with virtual size, + // I resorted to creating a one large map for data and memcpy'ing data where + // required. + // Another section is needed for .text, as it requires PROT_EXEC flag. + + // TODO: UGLY, UGLY HACK! + off_t file_size = 6750208; + + int len = 0x01429000 - 0x8a4000; // 0xB85000, 12079104 bytes or around 11.5MB + // section: rw data + gDataSegment = mmap((void *)0x8a4000, len, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_SHARED, 0, 0); + if (gDataSegment != (void *)0x8a4000) { + log_fatal("mmap failed to get required offset for data segment! got %p, expected %p, errno = %d", gDataSegment, (void *)(0x8a4000), errno); + exit(1); + } + + len = 0x004A3000; + // section: text + gTextSegment = mmap((void *)(0x401000), len, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_FIXED | MAP_PRIVATE, gExeFd, 0x1000); + if (gTextSegment != (void *)(0x401000)) + { + log_fatal("mmap failed to get required offset for text segment! got %p, expected %p, errno = %d", gTextSegment, (void *)(0x401000), errno); + exit(1); + } + + void *fbase = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, gExeFd, 0); + int err = errno; + log_warning("mmapped file to %p", fbase); + if (fbase == MAP_FAILED) + { + log_fatal("mmap failed to get required offset! got %p, errno = %d", fbase, err); + exit(1); + } + // .rdata and real part of .data + // 0x9e2000 - 0x8a4000 = 0x13e000 + memcpy(gDataSegment, fbase + RDATA_OFFSET, 0x13e000); + // 0x8a4000 + 0xb84000 = 0x1428000 aka DATASEG + memcpy(gDataSegment + 0xB84000, fbase + DATASEG_OFFSET, 0x1000); + err = munmap(fbase, file_size); + if (err != 0) + { + err = errno; + log_error("Failed to unmap file! errno = %d", err); + } +#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) + + // Check that the expected data is at various addresses. + // Start at 0x9a6000, which is start of .data, to skip the region containing addresses to DLL + // calls, which can be changed by windows/wine loader. + const uint32 c1 = sawyercoding_calculate_checksum((void *)0x009A6000, 0x009E0000 - 0x009A6000); + const uint32 c2 = sawyercoding_calculate_checksum((void *)0x01428000, 0x014282BC - 0x01428000); + const uint32 exp_c1 = 10114815; + const uint32 exp_c2 = 23564; + if (c1 != exp_c1 || c2 != exp_c2) { + log_warning("c1 = %u, expected %u, match %d", c1, exp_c1, c1 == exp_c1); + log_warning("c2 = %u, expected %u, match %d", c2, exp_c2, c2 == exp_c2); + return false; + } + + return true; +} + +/** + * Releases segments created with @ref openrct2_setup_rct2_segment, if any. + */ +static bool openrct2_release_rct2_segment() +{ + bool result = true; +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) + int len = 0x01429000 - 0x8a4000; // 0xB85000, 12079104 bytes or around 11.5MB + int err; + err = munmap(gDataSegment, len); + if (err != 0) + { + err = errno; + log_error("Failed to unmap data segment! errno = %d", err); + result = false; + } + len = 0x004A3000; + err = munmap(gTextSegment, len); + if (err != 0) + { + err = errno; + log_error("Failed to unmap text segment! errno = %d", err); + result = false; + } + err = close(gExeFd); + if (err != 0) + { + err = errno; + log_error("Failed to close file! errno = %d", err); + result = false; + } +#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) + return result; +} + +/** + * Setup hooks to allow RCT2 to call OpenRCT2 functions instead. + */ +static void openrct2_setup_rct2_hooks() +{ + addhook(0x006E732D, (int)gfx_set_dirty_blocks, 0, (int[]){ EAX, EBX, EDX, EBP, END }, 0, 0); // remove when all callers are decompiled + addhook(0x006E7499, (int)gfx_redraw_screen_rect, 0, (int[]){ EAX, EBX, EDX, EBP, END }, 0, 0); // remove when 0x6E7FF3 is decompiled + addhook(0x006B752C, (int)ride_crash, 0, (int[]){ EDX, EBX, END }, 0, 0); // remove when all callers are decompiled + addhook(0x0069A42F, (int)peep_window_state_update, 0, (int[]){ ESI, END }, 0, 0); // remove when all callers are decompiled + addhook(0x006BB76E, (int)audio_play_sound_panned, 0, (int[]){EAX, EBX, ECX, EDX, EBP, END}, EAX, 0); // remove when all callers are decompiled + addhook(0x006C42D9, (int)scrolling_text_setup, 0, (int[]){EAX, ECX, EBP, END}, 0, EBX); // remove when all callers are decompiled + addhook(0x006C2321, (int)gfx_get_string_width, 0, (int[]){ESI, END}, 0, ECX); // remove when all callers are decompiled + addhook(0x006C2555, (int)format_string, 0, (int[]){EDI, EAX, ECX, END}, 0, 0); // remove when all callers are decompiled +} + +#if _MSC_VER >= 1900 +/** + * Temporary fix for libraries not compiled with VS2015 + */ +FILE **__iob_func() +{ + static FILE* streams[3]; + streams[0] = stdin; + streams[1] = stdout; + streams[2] = stderr; + return streams; +} +#endif diff --git a/src/openrct2.h b/src/openrct2.h index 120b09051f..4642985872 100644 --- a/src/openrct2.h +++ b/src/openrct2.h @@ -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 . *****************************************************************************/ @@ -31,14 +31,17 @@ enum { }; extern int gOpenRCT2StartupAction; -extern char gOpenRCT2StartupActionPath[512]; -extern char gExePath[MAX_PATH]; +extern utf8 gOpenRCT2StartupActionPath[512]; +extern utf8 gExePath[MAX_PATH]; +extern utf8 gCustomUserDataPath[MAX_PATH]; extern bool gOpenRCT2Headless; extern bool gOpenRCT2ShowChangelog; +void openrct2_write_full_version_info(utf8 *buffer, size_t bufferSize); bool openrct2_initialise(); void openrct2_launch(); void openrct2_dispose(); void openrct2_finish(); +void openrct2_reset_object_tween_locations(); #endif \ No newline at end of file diff --git a/src/peep/peep.c b/src/peep/peep.c index eac001cd5d..a147e5415c 100644 --- a/src/peep/peep.c +++ b/src/peep/peep.c @@ -19,22 +19,41 @@ *****************************************************************************/ #include "../addresses.h" +#include "../util/util.h" #include "../audio/audio.h" #include "../audio/mixer.h" #include "../interface/window.h" #include "../localisation/localisation.h" +#include "../management/finance.h" #include "../management/news_item.h" +#include "../config.h" +#include "../openrct2.h" #include "../ride/ride.h" +#include "../ride/ride_data.h" #include "../scenario.h" #include "../sprites.h" #include "../world/sprite.h" #include "../world/scenery.h" +#include "../world/footpath.h" #include "../management/marketing.h" +#include "../game.h" #include "peep.h" #include "staff.h" +enum { + PATH_SEARCH_DEAD_END, + PATH_SEARCH_RIDE_EXIT, + PATH_SEARCH_RIDE_ENTRANCE, + PATH_SEARCH_3, + PATH_SEARCH_PARK_EXIT, + PATH_SEARCH_LIMIT_REACHED, + PATH_SEARCH_WIDE, +}; + +static void sub_68F41A(rct_peep *peep, int index); static void peep_update(rct_peep *peep); static int peep_has_empty_container(rct_peep* peep); +static int peep_has_drink(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); @@ -42,6 +61,34 @@ 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); +static int sub_693C9E(rct_peep *peep); +static void peep_spend_money(rct_peep *peep, money16 *peep_expend_type, money32 amount); +static void peep_set_has_ridden(rct_peep *peep, int rideIndex); +static bool peep_has_ridden(rct_peep *peep, int rideIndex); +static void peep_set_has_ridden_ride_type(rct_peep *peep, int rideType); +static bool peep_has_ridden_ride_type(rct_peep *peep, int rideType); +static void peep_on_enter_or_exit_ride(rct_peep *peep, int rideIndex, int flags); +static void peep_update_favourite_ride(rct_peep *peep, rct_ride *ride); +static sint8 peep_calculate_ride_satisfaction(rct_peep *peep, rct_ride *ride); +static void peep_update_ride_nausea_growth(rct_peep *peep, rct_ride *ride); +static bool sub_69AF1E(rct_peep *peep, int rideIndex, int shopItem, money32 price); +static bool peep_should_use_cash_machine(rct_peep *peep, int rideIndex); +static bool peep_should_go_on_ride(rct_peep *peep, int rideIndex, int entranceNum, int flags); +static void peep_ride_is_too_intense(rct_peep *peep, int rideIndex, bool peepAtRide); +static void peep_chose_not_to_go_on_ride(rct_peep *peep, int rideIndex, bool peepAtRide, bool updateLastRide); +static void peep_tried_to_enter_full_queue(rct_peep *peep, int rideIndex); +static bool peep_should_go_to_shop(rct_peep *peep, int rideIndex, bool peepAtShop); +static void sub_69A98C(rct_peep *peep); +static void sub_68FD3A(rct_peep *peep); +static bool sub_690B99(rct_peep *peep, int edge, uint8 *rideToView, uint8 *rideSeatToView); +static int peep_get_height_on_slope(rct_peep *peep, int x, int y); +static void peep_pick_ride_to_go_on(rct_peep *peep); +static void peep_head_for_nearest_ride_type(rct_peep *peep, int rideType); +static void peep_head_for_nearest_ride_with_flags(rct_peep *peep, int rideTypeFlags); +static void peep_give_real_name(rct_peep *peep); +static int guest_surface_path_finding(rct_peep* peep); +static void peep_read_map(rct_peep *peep); +static bool peep_heading_for_ride_or_park_exit(rct_peep *peep); const char *gPeepEasterEggNames[] = { "MICHAEL SCHUMACHER", @@ -72,6 +119,15 @@ const char *gPeepEasterEggNames[] = { "DAVID ELLIS" }; +// These arrays contain the base minimum and maximum nausea ratings for peeps, based on their nausea tolerance level. +static const ride_rating NauseaMinimumThresholds[] = { + 0, 0, 200, 400 +}; + +static const ride_rating NauseaMaximumThresholds[] = { + 300, 600, 800, 1000 +}; + int peep_get_staff_count() { uint16 spriteIndex; @@ -92,7 +148,7 @@ void peep_update_all() { int i; uint16 spriteIndex; - rct_peep* peep; + rct_peep* peep; if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 0x0E) return; @@ -106,7 +162,7 @@ void peep_update_all() if ((i & 0x7F) != (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 0x7F)) { peep_update(peep); } else { - RCT2_CALLPROC_X(0x0068F41A, 0, 0, 0, i, (int)peep, 0, 0); + sub_68F41A(peep, i); if (peep->linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_PEEP) peep_update(peep); } @@ -115,6 +171,628 @@ void peep_update_all() } } +/* rct2: 0x0069BC9A */ +static uint8 peep_assess_surroundings(sint16 center_x, sint16 center_y, sint16 center_z){ + if ((map_element_height(center_x, center_y) & 0xFFFF) > center_z) + return 0; + + uint16 num_scenery = 0; + uint16 num_fountains = 0; + uint16 nearby_music = 0; + uint16 num_rubbish = 0; + + sint16 initial_x = max(center_x - 160, 0); + sint16 initial_y = max(center_y - 160, 0); + sint16 final_x = min(center_x + 160, 8192); + sint16 final_y = min(center_y + 160, 8192); + + for (sint16 x = initial_x; x < final_x; x += 32){ + for (sint16 y = initial_y; y < final_y; y += 32){ + rct_map_element* mapElement = map_get_first_element_at(x / 32, y / 32); + + do{ + rct_ride* ride; + rct_scenery_entry* scenery; + + switch (map_element_get_type(mapElement)){ + case MAP_ELEMENT_TYPE_PATH: + if ((mapElement->properties.path.additions & 0xF) == 0) + break; + + scenery = g_pathBitSceneryEntries[(mapElement->properties.path.additions & 0x0F) - 1]; + if (mapElement->properties.path.additions & (1 << 7)) + break; + + if (scenery->path_bit.var_06 & + (PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER | + PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW)){ + num_fountains++; + break; + } + if (mapElement->flags & MAP_ELEMENT_FLAG_BROKEN){ + num_rubbish++; + } + break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + case MAP_ELEMENT_TYPE_SCENERY: + num_scenery++; + break; + case MAP_ELEMENT_TYPE_TRACK: + ride = GET_RIDE(mapElement->properties.track.ride_index); + if (ride->type == RIDE_TYPE_MERRY_GO_ROUND && + ride->music_tune_id != 0xFF){ + nearby_music |= 1; + break; + } + + if (ride->music_tune_id == MUSIC_STYLE_ORGAN){ + nearby_music |= 1; + break; + } + + if (ride->type == RIDE_TYPE_DODGEMS && + ride->music_tune_id != 0xFF){ + // Dodgems drown out music? + nearby_music |= 2; + } + break; + } + } while (!map_element_is_last_for_tile(mapElement++)); + } + } + + + short num_litter; + + num_litter = 0; + rct_litter* litter; + for (uint16 sprite_idx = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_LITTER, uint16); sprite_idx != SPRITE_INDEX_NULL; sprite_idx = litter->next) { + litter = &(g_sprite_list[sprite_idx].litter); + + sint16 dist_x = abs(litter->x - center_x); + sint16 dist_y = abs(litter->y - center_y); + if (max(dist_x, dist_y) <= 160){ + num_rubbish++; + } + } + + if (num_fountains >= 5){ + if (num_rubbish < 20) + return 3; + } + + if (num_scenery >= 40){ + if (num_rubbish < 8) + return 1; + } + + if (nearby_music == 1){ + if (num_rubbish < 20) + return 4; + } + + if (num_rubbish < 2) + return 2; + + return 0; +} + +/* rct2: 0x0068F9A9*/ +static void peep_update_hunger(rct_peep *peep){ + if (peep->hunger >= 3){ + peep->hunger -= 2; + peep->energy_growth_rate = min(peep->energy_growth_rate + 2, 255); + peep->bathroom = min(peep->bathroom + 1, 255); + } +} + +/* rct2: 0x0068F93E */ +static void peep_leave_park(rct_peep* peep){ + peep->guest_heading_to_ride_id = 0xFF; + if (peep->flags & PEEP_FLAGS_LEAVING_PARK){ + if (peep->peep_is_lost_countdown < 60){ + return; + } + } + else{ + peep->peep_is_lost_countdown = 254; + peep->flags |= PEEP_FLAGS_LEAVING_PARK; + peep->flags &= ~PEEP_FLAGS_PARK_ENTRANCE_CHOSEN; + } + + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_GO_HOME, 0xFF); + + rct_window* w = window_find_by_number(WC_PEEP, peep->sprite_index); + if (w != NULL) window_event_invalidate_call(w); + window_invalidate_by_number(WC_PEEP, peep->sprite_index); +} + +/** + * + * rct2: 0x0068F8CD + */ +static void sub_68F8CD(rct_peep *peep) +{ + if (peep->energy_growth_rate >= 33) { + peep->energy_growth_rate -= 2; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TEMPERATURE, uint8) >= 21 && peep->thirst >= 5) { + peep->thirst--; + } + + if (peep->outside_of_park != 0) { + return; + } + + if (!(peep->flags & PEEP_FLAGS_LEAVING_PARK)){ + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) { + if (peep->energy >= 70 && peep->happiness >= 60) { + return; + } + } else { + if ( + peep->energy >= 55 && + peep->happiness >= 45 && + peep->cash_in_pocket >= MONEY(5, 00) + ) { + return; + } + } + } + + if ((scenario_rand() & 0xFFFF) > 3276) { + return; + } + + peep_leave_park(peep); +} + +/** + * + * rct2: 0x0068F41A + */ +static void sub_68F41A(rct_peep *peep, int index) +{ + if (peep->type == PEEP_TYPE_STAFF){ + if (peep->staff_type != STAFF_TYPE_SECURITY) + return; + + uint8 sprite_type = PEEP_SPRITE_TYPE_23; + if (peep->state != PEEP_STATE_PATROLLING) + sprite_type = PEEP_SPRITE_TYPE_3; + + if (peep->sprite_type == sprite_type) + return; + + peep->sprite_type = sprite_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)[sprite_type] & 1){ + peep->flags |= PEEP_FLAGS_SLOW_WALK; + } + + peep->action_sprite_type = 0xFF; + sub_693B58(peep); + return; + } + + if ((index & 0x1FF) == (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 0x1FF)){ + //RCT2_GLOBAL(0x00F1EDFE, uint32) = index; not needed all cases accounted for + + if (peep->flags & PEEP_FLAGS_CROWDED){ + uint8 thought_type = RCT2_ADDRESS(0x009823AC, uint8)[scenario_rand() & 0xF]; + if (thought_type != PEEP_THOUGHT_TYPE_NONE){ + peep_insert_new_thought(peep, thought_type, 0xFF); + } + } + + if (peep->flags & PEEP_FLAGS_EXPLODE && peep->x != (sint16)0x8000){ + audio_play_sound_at_location(SOUND_CRASH, peep->x, peep->y, peep->z); + + sprite_misc_3_create(peep->x, peep->y, peep->z + 16); + sprite_misc_5_create(peep->x, peep->y, peep->z + 16); + + peep_remove(peep); + return; + } + + if (peep->flags & PEEP_FLAGS_HUNGER){ + if (peep->hunger >= 15)peep->hunger -= 15; + } + + if (peep->flags & PEEP_FLAGS_BATHROOM){ + if (peep->bathroom <= 180)peep->bathroom += 50; + } + + if (peep->flags & PEEP_FLAGS_HAPPINESS){ + peep->happiness_growth_rate = 5; + } + + if (peep->flags & PEEP_FLAGS_NAUSEA){ + peep->nausea_growth_rate = 200; + if (peep->nausea <= 130)peep->nausea = 130; + } + + if (peep->var_F3 != 0) + peep->var_F3--; + + if (peep->state == PEEP_STATE_WALKING || peep->state == PEEP_STATE_SITTING){ + peep->var_F2++; + if (peep->var_F2 >= 18){ + peep->var_F2 = 0; + if (peep->x != (sint16)0x8000){ + + uint8 bl = peep_assess_surroundings(peep->x & 0xFFE0, peep->y & 0xFFE0, peep->z); + + if (bl != 0){ + peep->happiness_growth_rate = min(255, peep->happiness_growth_rate + 45); + + switch (bl){ + case 1: + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_SCENERY, 0xFF); + break; + case 2: + peep_insert_new_thought(peep, PEEP_THOUGHT_VERY_CLEAN, 0xFF); + break; + case 3: + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_FOUNTAINS, 0xFF); + break; + default: + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_MUSIC, 0xFF); + break; + } + } + } + } + } + + peep_update_sprite_type(peep); + + if (peep->state == PEEP_STATE_ON_RIDE || peep->state == PEEP_STATE_ENTERING_RIDE){ + peep->time_on_ride = min(255, peep->time_on_ride + 1); + + if (peep->flags & PEEP_FLAGS_WOW){ + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_WOW2, 0xFF); + } + + if (peep->time_on_ride > 15){ + peep->happiness_growth_rate = min(0, peep->happiness_growth_rate - 5); + + if (peep->time_on_ride > 22){ + rct_ride* ride = GET_RIDE(peep->current_ride); + + uint8 thought_type = ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IN_RIDE) ? + PEEP_THOUGHT_TYPE_GET_OUT : + PEEP_THOUGHT_TYPE_GET_OFF; + + peep_insert_new_thought(peep, thought_type, peep->current_ride); + } + } + } + + if (peep->state == PEEP_STATE_WALKING && + peep->outside_of_park == 0 && + !(peep->flags & PEEP_FLAGS_LEAVING_PARK) && + peep->no_of_rides == 0 && + peep->guest_heading_to_ride_id == 0xFF){ + + uint32 time_duration = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) - peep->time_in_park; + time_duration /= 2048; + + if (time_duration >= 5){ + peep_pick_ride_to_go_on(peep); + + if (peep->guest_heading_to_ride_id == 0xFF){ + peep->happiness_growth_rate = max(peep->happiness_growth_rate - 128, 0); + peep_leave_park(peep); + peep_update_hunger(peep); + goto loc_68F9F3; + } + } + } + + if ((scenario_rand() & 0xFFFF) <= (peep->item_standard_flags & PEEP_ITEM_MAP ? 8192U : 2184U)){ + peep_pick_ride_to_go_on(peep); + } + + if ((index & 0x3FF) == (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 0x3FF)){ + + if (peep->outside_of_park == 0 && + (peep->state == PEEP_STATE_WALKING || peep->state == PEEP_STATE_SITTING)){ + + uint8 num_thoughts = 0; + uint8 possible_thoughts[5] = { 0 }; + + if (peep->flags & PEEP_FLAGS_LEAVING_PARK){ + possible_thoughts[num_thoughts++] = PEEP_THOUGHT_TYPE_GO_HOME; + } + else{ + if (peep->energy <= 70 && + peep->happiness < 128){ + possible_thoughts[num_thoughts++] = PEEP_THOUGHT_TYPE_TIRED; + } + + if (peep->hunger <= 10 && + !peep_has_food(peep)){ + possible_thoughts[num_thoughts++] = PEEP_THOUGHT_TYPE_HUNGRY; + } + + if (peep->thirst <= 25 && + !peep_has_food(peep)){ + possible_thoughts[num_thoughts++] = PEEP_THOUGHT_TYPE_THIRSTY; + } + + if (peep->bathroom >= 160){ + possible_thoughts[num_thoughts++] = PEEP_THOUGHT_TYPE_BATHROOM; + } + + // Not sure why the happiness check is like that seems wrong to me + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) && + peep->cash_in_pocket <= MONEY(9, 00) && + peep->happiness >= 105 && + peep->happiness >= 70){ + possible_thoughts[num_thoughts++] = PEEP_THOUGHT_RUNNING_OUT; + } + } + + if (num_thoughts != 0){ + uint8 chosen_thought = possible_thoughts[scenario_rand() % num_thoughts]; + + peep_insert_new_thought(peep, chosen_thought, 0xFF); + + switch (chosen_thought){ + case PEEP_THOUGHT_TYPE_HUNGRY: + peep_head_for_nearest_ride_with_flags(peep, 0x00800000); + break; + case PEEP_THOUGHT_TYPE_THIRSTY: + peep_head_for_nearest_ride_with_flags(peep, 0x01000000); + break; + case PEEP_THOUGHT_TYPE_BATHROOM: + peep_head_for_nearest_ride_with_flags(peep, 0x00200000); + break; + case PEEP_THOUGHT_RUNNING_OUT: + peep_head_for_nearest_ride_type(peep, RIDE_TYPE_CASH_MACHINE); + break; + } + } + } + } + else{ + if (peep->nausea >= 140){ + uint8 thought = PEEP_THOUGHT_TYPE_SICK; + if (peep->nausea >= 200){ + thought = PEEP_THOUGHT_TYPE_VERY_SICK; + peep_head_for_nearest_ride_type(peep, RIDE_TYPE_FIRST_AID); + } + peep_insert_new_thought(peep, thought, 0xFF); + } + } + + + switch (peep->state){ + case PEEP_STATE_WALKING: + case PEEP_STATE_LEAVING_PARK: + case PEEP_STATE_ENTERING_PARK: + sub_68F8CD(peep); + peep_update_hunger(peep); + break; + + case PEEP_STATE_SITTING: + if (peep->energy_growth_rate <= 135) + peep->energy_growth_rate += 5; + + if (peep->thirst >= 5){ + peep->thirst -= 4; + peep->bathroom = min(255, peep->bathroom + 3); + } + + if (peep->nausea_growth_rate >= 50) + peep->nausea_growth_rate -= 6; + + // In the original this branched differently + // but it would mean setting the peep happiness from + // a thought type entry which i think is incorrect. + peep_update_hunger(peep); + break; + + case PEEP_STATE_QUEUING: + if (peep->time_in_queue >= 2000){ + rct_map_element* mapElement = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32); + uint8 found = 0; + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH) + continue; + if (mapElement->base_height != peep->next_z) + continue; + + uint8 additions = mapElement->properties.path.additions & 0xF; + if (additions != 0 && mapElement->properties.path.additions & (1 << 7)){ + rct_scenery_entry *sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + if (sceneryEntry->path_bit.var_06 & (1 << 8)){ + found = 1; + } + } + break; + } while (!map_element_is_last_for_tile(mapElement++)); + + if (found){ + if (peep->happiness_growth_rate < 90) + peep->happiness_growth_rate = 90; + + if (peep->happiness_growth_rate < 165) + peep->happiness_growth_rate += 2; + } + else{ + peep->happiness_growth_rate = max(peep->happiness_growth_rate - 4, 0); + } + } + peep_update_hunger(peep); + break; + case PEEP_STATE_ENTERING_RIDE: + if (peep->sub_state == 17 || + peep->sub_state == 15){ + sub_68F8CD(peep); + } + peep_update_hunger(peep); + break; + } + + loc_68F9F3: + if (peep->happiness_growth_rate >= 128) + peep->happiness_growth_rate--; + else + peep->happiness_growth_rate++; + + peep->nausea_growth_rate = max(peep->nausea_growth_rate - 2, 0); + + if (peep->energy <= 50){ + peep->energy = max(peep->energy - 2, 0); + } + + if (peep->hunger < 10){ + peep->hunger = max(peep->hunger - 1, 0); + } + + if (peep->thirst < 10){ + peep->thirst = max(peep->thirst - 1, 0); + } + + if (peep->bathroom >= 195){ + peep->bathroom--; + } + + if (peep->state == PEEP_STATE_WALKING && + peep->nausea_growth_rate >= 128){ + + if ((scenario_rand() & 0xFF) <= (uint8)((peep->nausea - 128) / 2)){ + if (peep->action >= PEEP_ACTION_NONE_1){ + peep->action = PEEP_ACTION_THROW_UP; + peep->action_frame = 0; + peep->action_sprite_image_offset = 0; + sub_693B58(peep); + invalidate_sprite_2((rct_sprite*)peep); + } + } + } + } + // 68FA89 + if (peep->var_42 == 0 && + peep_has_food(peep)){ + peep->var_42 += 3; + } + + if (peep->var_42 != 0 && + peep->state != PEEP_STATE_ON_RIDE){ + + peep->var_42 = max(peep->var_42 - 3, 0); + + if (peep_has_drink(peep)){ + peep->thirst = min(peep->thirst + 7, 255); + } + else{ + peep->hunger = min(peep->hunger + 7, 255); + peep->thirst = max(peep->thirst - 3, 0); + peep->bathroom = min(peep->bathroom + 2, 255); + } + + if (peep->var_42 == 0){ + int chosen_food = bitscanforward(peep_has_food_standard_flag(peep)); + if (chosen_food != -1){ + peep->item_standard_flags &= ~(1 << chosen_food); + + uint8 discard_container = RCT2_ADDRESS(0x00982326, uint8)[chosen_food]; + if (discard_container != 0xFF){ + peep->item_standard_flags |= (1 << discard_container); + } + + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_INVENTORY; + peep_update_sprite_type(peep); + } + else{ + chosen_food = bitscanforward(peep_has_food_extra_flag(peep)); + if (chosen_food != -1){ + peep->item_extra_flags &= ~(1 << chosen_food); + uint8 discard_container = RCT2_ADDRESS(0x00982342, uint8)[chosen_food]; + if (discard_container != 0xFF){ + if (discard_container >= 32) + peep->item_extra_flags |= (1 << (discard_container - 32)); + else + peep->item_standard_flags |= (1 << discard_container); + } + + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_INVENTORY; + peep_update_sprite_type(peep); + } + } + } + } + + uint8 energy = peep->energy; + uint8 energy_growth = peep->energy_growth_rate; + if (energy >= energy_growth){ + energy -= 2; + if (energy < energy_growth) + energy = energy_growth; + } + else{ + energy = min(255, energy + 4); + if (energy > energy_growth) + energy = energy_growth; + } + + if (energy < 32) + energy = 32; + + if (energy > 128) + energy = 128; + + if (energy != peep->energy){ + peep->energy = energy; + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_2; + } + + uint8 happiness = peep->happiness; + uint8 happiness_growth = peep->happiness_growth_rate; + if (happiness >= happiness_growth){ + happiness = max(happiness - 4, 0); + if (happiness < happiness_growth) + happiness = happiness_growth; + } + else{ + happiness = min(255, happiness + 4); + if (happiness > happiness_growth) + happiness = happiness_growth; + } + + if (happiness != peep->happiness){ + peep->happiness = happiness; + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_2; + } + + uint8 nausea = peep->nausea; + uint8 nausea_growth = peep->nausea_growth_rate; + if (nausea >= nausea_growth){ + nausea = max(nausea - 4, 0); + if (nausea < nausea_growth) + nausea = nausea_growth; + } + else{ + nausea = min(255, nausea + 4); + if (nausea > nausea_growth) + nausea = nausea_growth; + } + + if (nausea != peep->nausea){ + peep->nausea = nausea; + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_2; + } +} + /* some sort of check to see if peep is connected to the ground?? */ int sub_68F3AE(rct_peep* peep){ peep->var_C4++; @@ -134,7 +812,7 @@ int sub_68F3AE(rct_peep* peep){ if (z == map_element->base_height)return 1; } } while (!map_element_is_last_for_tile(map_element++)); - + peep_decrement_num_riders(peep); peep->state = PEEP_STATE_FALLING; peep_window_state_update(peep); @@ -151,7 +829,7 @@ void sub_693B58(rct_peep* peep){ } if (ebx == peep->action_sprite_type)return; - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); peep->action_sprite_type = ebx; uint8* edx = RCT2_ADDRESS(0x98270C, uint8*)[peep->sprite_type * 2]; @@ -159,11 +837,11 @@ void sub_693B58(rct_peep* peep){ 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); + invalidate_sprite_2((rct_sprite*)peep); } /* 0x00693BE5 */ -static void sub_693BE5(rct_peep* peep, uint8 al){ +void sub_693BE5(rct_peep* peep, uint8 al){ if (al == peep->var_6D)return; peep->var_6D = al; @@ -198,7 +876,7 @@ static void peep_state_reset(rct_peep* peep){ sub_693BE5(peep, 0); } -/* rct2: 0x69C308 +/* rct2: 0x69C308 * Check if lost. */ void peep_check_if_lost(rct_peep* peep){ @@ -221,16 +899,18 @@ void peep_check_if_lost(rct_peep* peep){ * 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->guest_heading_to_ride_id == 0xFF) + return; - if (peep->var_C6 == 30 || peep->var_C6 == 60){ + // Peeps will think "I can't find ride X" twice before giving up completely. + if (peep->peep_is_lost_countdown == 30 || peep->peep_is_lost_countdown == 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->peep_is_lost_countdown--; + if (peep->peep_is_lost_countdown != 0) + return; peep->guest_heading_to_ride_id = 0xFF; rct_window* w = window_find_by_number(WC_PEEP, peep->sprite_index); @@ -246,20 +926,22 @@ void peep_check_cant_find_ride(rct_peep* peep){ * Check if cant find exit. */ void peep_check_cant_find_exit(rct_peep* peep){ - if (!(peep->flags & PEEP_FLAGS_LEAVING_PARK))return; + if (!(peep->flags & PEEP_FLAGS_LEAVING_PARK)) + return; - if (peep->var_C6 == 1){ + // Peeps who can't find the park exit will continue to get less happy until they find it. + if (peep->peep_is_lost_countdown == 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; + if (--peep->peep_is_lost_countdown == 0) + peep->peep_is_lost_countdown = 90; } -/* rct2: 0x6939EB +/* rct2: 0x6939EB * Also used to move peeps to the correct position to - * start an action. Returns 1 if the correct destination + * 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. */ @@ -274,9 +956,9 @@ int peep_update_action(sint16* x, sint16* y, sint16* xy_distance, rct_peep* peep int x_delta = abs(*x); int y_delta = abs(*y); - + *xy_distance = x_delta + y_delta; - + if (peep->action >= 0xFE){ if (*xy_distance <= peep->destination_tolerence){ return 0; @@ -306,7 +988,7 @@ int peep_update_action(sint16* x, sint16* y, sint16* xy_distance, rct_peep* peep peep->action_sprite_image_offset = _edi[peep->no_action_frame_no + 1]; return 1; } - + uint32* edi = RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2]; uint8* _edi = (uint8*)(edi[peep->action_sprite_type * 2 + 1]); peep->action_frame++; @@ -317,7 +999,7 @@ int peep_update_action(sint16* x, sint16* y, sint16* xy_distance, rct_peep* peep peep->action_sprite_image_offset = 0; peep->action = 0xFF; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); *x = peep->x; *y = peep->y; return 1; @@ -326,7 +1008,7 @@ int peep_update_action(sint16* x, sint16* y, sint16* xy_distance, rct_peep* peep // If not throwing up and not at the frame where sick appears. if (peep->action != PEEP_ACTION_THROW_UP || peep->action_frame != 15){ - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); *x = peep->x; *y = peep->y; return 1; @@ -341,16 +1023,15 @@ int peep_update_action(sint16* x, sint16* y, sint16* xy_distance, rct_peep* peep else peep->nausea -= 30; - peep->var_45 |= (1 << 2); + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_2; // Create sick at location - RCT2_CALLPROC_X(0x67375D, peep->x, peep->sprite_direction, peep->y, peep->z, 0, 0, peep->sprite_index & 1); + litter_create(peep->x, peep->y, peep->z, peep->sprite_direction, peep->sprite_index & 1); - int sound_id = (scenario_rand() & 3) + 24; + int sound_id = SOUND_COUGH_1 + (scenario_rand() & 3); + audio_play_sound_at_location(sound_id, peep->x, peep->y, peep->z); - sound_play_panned(sound_id, 0x8001, peep->x, peep->y, peep->z); - - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); *x = peep->x; *y = peep->y; return 1; @@ -361,7 +1042,7 @@ int peep_update_action(sint16* x, sint16* y, sint16* xy_distance, rct_peep* peep * Decreases rider count if on/entering a ride. */ void peep_decrement_num_riders(rct_peep* peep){ - if (peep->state == PEEP_STATE_ON_RIDE + if (peep->state == PEEP_STATE_ON_RIDE || peep->state == PEEP_STATE_ENTERING_RIDE){ rct_ride* ride = GET_RIDE(peep->current_ride); @@ -377,7 +1058,7 @@ void set_sprite_type(rct_peep* peep, uint8 type){ 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; @@ -442,97 +1123,103 @@ item_pref item_order_preference[] = { { 0xFF, 0xFFFFFFFF, 0xFF} }; -/* rct2: 0x0069B8CC */ -void peep_update_sprite_type(rct_peep* peep){ - if (peep->sprite_type == 19 && - (scenario_rand() & 0xFFFF) <= 327){ +/** + * + * rct2: 0x0069B8CC + */ +void peep_update_sprite_type(rct_peep* peep) +{ + if ( + peep->sprite_type == PEEP_SPRITE_TYPE_19 && + (scenario_rand() & 0xFFFF) <= 327 + ) { uint8 bl = 0; - if ((scenario_rand() & 0xFFFF) <= 13107 && - peep->x != SPRITE_LOCATION_NULL){ - + 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); + audio_play_sound_at_location(SOUND_BALLOON_POP, peep->x, peep->y, peep->z); } - if (peep->x != SPRITE_LOCATION_NULL){ + 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); + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_INVENTORY; } - if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RAIN_LEVEL, uint8) != 0 && - peep->item_standard_flags & PEEP_ITEM_UMBRELLA && - peep->x != SPRITE_LOCATION_NULL){ + 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){ + 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 ((peep->z / 8) < map_element->base_height) break; - if (map_element_is_last_for_tile(map_element)){ - set_sprite_type(peep, 21); + if (map_element_is_last_for_tile(map_element)) { + set_sprite_type(peep, PEEP_SPRITE_TYPE_UMBRELLA); return; } map_element++; } - } + } } - for (item_pref* item_pref = item_order_preference; item_pref->type != 0xFF; item_pref++){ + 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){ + 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){ + } 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); + if (peep->state == PEEP_STATE_WATCHING && peep->standing_flags & (1 << 1)) { + set_sprite_type(peep, PEEP_SPRITE_TYPE_WATCHING); return; } - - if (peep->nausea > 170){ - set_sprite_type(peep, 28); + + if (peep->nausea > 170) { + set_sprite_type(peep, PEEP_SPRITE_TYPE_VERY_NAUSEOUS); return; } - - if (peep->nausea > 140){ - set_sprite_type(peep, 27); + + if (peep->nausea > 140) { + set_sprite_type(peep, PEEP_SPRITE_TYPE_NAUSEOUS); return; } - - if (peep->energy <= 64 && - peep->happiness < 128){ - set_sprite_type(peep, 26); + + if (peep->energy <= 64 && peep->happiness < 128) { + set_sprite_type(peep, PEEP_SPRITE_TYPE_26); return; } - - if (peep->energy <= 80 && - peep->happiness < 128){ - set_sprite_type(peep, 25); + + if (peep->energy <= 80 && peep->happiness < 128) { + set_sprite_type(peep, PEEP_SPRITE_TYPE_25); return; } - - if (peep->bathroom > 220){ - set_sprite_type(peep, 29); + + if (peep->bathroom > 220) { + set_sprite_type(peep, PEEP_SPRITE_TYPE_REQUIRE_BATHROOM); return; } - - set_sprite_type(peep, 0); + + set_sprite_type(peep, PEEP_SPRITE_TYPE_NORMAL); } /** @@ -542,7 +1229,7 @@ void peep_update_sprite_type(rct_peep* peep){ * count if on/entering a ride. */ void peep_window_state_update(rct_peep* peep){ - + rct_window* w = window_find_by_number(WC_PEEP, peep->sprite_index); if (w != NULL) window_event_invalidate_call(w); @@ -569,7 +1256,7 @@ 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); + invalidate_sprite_2((rct_sprite*)peep); window_close_by_number(WC_PEEP, peep->sprite_index); @@ -593,12 +1280,12 @@ void peep_sprite_remove(rct_peep* peep){ sprite_remove((rct_sprite*)peep); } -/** New function removes peep from +/** New function removes peep from * park existance. Works with staff. */ void peep_remove(rct_peep* peep){ if (peep->type == PEEP_TYPE_GUEST){ - if (peep->var_2A == 0){ + if (peep->outside_of_park == 0){ RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16)--; RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) |= BTM_TB_DIRTY_FLAG_PEEP_COUNT; } @@ -657,7 +1344,7 @@ void peep_update_falling(rct_peep* peep){ if (height - 4 >= peep->z && height < peep->z + 20){ // Looks like we are drowning! - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(peep->x, peep->y, height, (rct_sprite*)peep); // Drop balloon if held if (peep->item_standard_flags & PEEP_ITEM_BALLOON){ @@ -665,7 +1352,7 @@ void peep_update_falling(rct_peep* peep){ 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); + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_INVENTORY; peep_update_sprite_type(peep); } } @@ -677,7 +1364,7 @@ void peep_update_falling(rct_peep* peep){ peep->action_sprite_image_offset = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); peep_window_state_update(peep); return; } @@ -692,20 +1379,20 @@ void peep_update_falling(rct_peep* peep){ // This will be null if peep is falling if (saved_map == NULL){ - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); if (peep->z <= 1){ // Remove peep if it has gone to the void peep_remove(peep); return; } sprite_move(peep->x, peep->y, peep->z - 2, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } - - invalidate_sprite((rct_sprite*)peep); + + invalidate_sprite_2((rct_sprite*)peep); sprite_move(peep->x, peep->y, saved_height, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); peep->next_x = peep->x & 0xFFE0; peep->next_y = peep->y & 0xFFE0; @@ -743,26 +1430,26 @@ void peep_try_get_up_from_sitting(rct_peep* peep){ } /** - * rct2: 0x0069152B + * rct2: 0x0069152B */ void peep_update_sitting(rct_peep* peep){ if (peep->sub_state == 0){ if (!sub_68F3AE(peep))return; //691541 - RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); + sub_693C9E(peep); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return; 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]; - int z = peep->z; - - invalidate_sprite((rct_sprite*)peep); + int z = peep->z; + + invalidate_sprite_2((rct_sprite*)peep); sprite_move(x, y, z, (rct_sprite*)peep); peep->sprite_direction = ((peep->var_37 + 2) & 3) * 8; - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); peep->action = 254; peep->var_6F = 7; sub_693BAB(peep); @@ -782,7 +1469,7 @@ void peep_update_sitting(rct_peep* peep){ peep_try_get_up_from_sitting(peep); return; } - + if ((peep->flags & PEEP_FLAGS_LEAVING_PARK)){ peep_decrement_num_riders(peep); peep->state = PEEP_STATE_WALKING; @@ -795,7 +1482,7 @@ void peep_update_sitting(rct_peep* peep){ sub_693B58(peep); return; } - + if (peep->sprite_type == 0x15){ peep_try_get_up_from_sitting(peep); return; @@ -810,7 +1497,7 @@ void peep_update_sitting(rct_peep* peep){ peep->action_frame = 0; peep->action_sprite_image_offset = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } @@ -835,14 +1522,14 @@ void peep_update_sitting(rct_peep* peep){ peep->action_frame = 0; peep->action_sprite_image_offset = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } } /** * - * rct2: 0x006966A9 + * rct2: 0x006966A9 */ void remove_peep_from_queue(rct_peep* peep) { @@ -850,13 +1537,13 @@ void remove_peep_from_queue(rct_peep* peep) uint8 cur_station = peep->current_ride_station; ride->queue_length[cur_station]--; - if (peep->sprite_index == ride->first_peep_in_queue[cur_station]) + if (peep->sprite_index == ride->last_peep_in_queue[cur_station]) { - ride->first_peep_in_queue[cur_station] = peep->next_in_queue; + ride->last_peep_in_queue[cur_station] = peep->next_in_queue; return; } - for (rct_peep* other_peep = GET_PEEP(ride->first_peep_in_queue[cur_station]);; + for (rct_peep* other_peep = GET_PEEP(ride->last_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; @@ -911,7 +1598,7 @@ 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; @@ -947,7 +1634,7 @@ static void peep_go_to_ride_entrance(rct_peep* peep, rct_ride* ride){ peep_window_state_update(peep); peep->var_AC = 0; - peep->var_E2 = 0; + peep->time_on_ride = 0; remove_peep_from_queue(peep); } @@ -957,7 +1644,7 @@ 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); + invalidate_sprite_2((rct_sprite*)peep); sint16 x, y, xy_distance; @@ -967,7 +1654,7 @@ static void peep_update_ride_sub_state_0(rct_peep* peep){ z = ride->station_heights[peep->current_ride_station] * 8 + 2; } sprite_move(x, y, z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); } else{ peep->destination_tolerence = 0; @@ -1003,7 +1690,7 @@ static void peep_update_ride_sub_state_0(rct_peep* peep){ } else{ chosen_train = ride->var_066[peep->current_ride_station]; - } + } if (chosen_train == 0xFF){ return; } @@ -1050,7 +1737,7 @@ static void peep_update_ride_sub_state_0(rct_peep* peep){ if (car_array_size == 0)return; } - if (ride->status != RIDE_STATUS_OPEN || + if (ride->status != RIDE_STATUS_OPEN || ride->var_1CA != 0){ if (peep->destination_tolerence == 0){ remove_peep_from_queue(peep); @@ -1081,7 +1768,7 @@ static void peep_update_ride_sub_state_0(rct_peep* peep){ } if (ride->price > peep->cash_in_pocket){ - peep_insert_new_thought(peep, 0, peep->current_ride); + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_CANT_AFFORD_0, peep->current_ride); if (peep->destination_tolerence == 0){ remove_peep_from_queue(peep); peep_decrement_num_riders(peep); @@ -1125,7 +1812,7 @@ void peep_update_ride_sub_state_1(rct_peep* peep){ { uint8 vehicle = ride_entry->default_vehicle; - if (ride_entry->vehicles[vehicle].var_12 & (1 << 3) || + 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 @@ -1134,8 +1821,8 @@ void peep_update_ride_sub_state_1(rct_peep* peep){ if (peep->sub_state == 1 && xy_distance < RCT2_GLOBAL(0xF1AECA, uint16)) peep->sub_state = 2; - - invalidate_sprite((rct_sprite*)peep); + + invalidate_sprite_2((rct_sprite*)peep); sint16 z = ride->station_heights[peep->current_ride_station] * 8; @@ -1146,7 +1833,7 @@ void peep_update_ride_sub_state_1(rct_peep* peep){ } sprite_move(x, y, z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } @@ -1161,13 +1848,13 @@ void peep_update_ride_sub_state_1(rct_peep* peep){ uint8 direction_entrance = (map_element->type & MAP_ELEMENT_DIRECTION_MASK); - if (ride->type == RIDE_TYPE_MAZE){ + 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]; + x += TileDirectionDelta[direction_entrance].x; + y += TileDirectionDelta[direction_entrance].y; uint8 direction = direction_entrance * 4 + 11; if (scenario_rand() & 0x40){ @@ -1187,7 +1874,7 @@ void peep_update_ride_sub_state_1(rct_peep* peep){ peep->destination_tolerence = 3; ride->var_120++; - RCT2_CALLPROC_X(0x00695444, 0, 0, 0, peep->current_ride, (int)peep, 0, 0); + peep_on_enter_or_exit_ride(peep, peep->current_ride, 0); peep->sub_state = 17; return; } @@ -1214,7 +1901,7 @@ void peep_update_ride_sub_state_1(rct_peep* peep){ peep->current_car = 0; ride->var_120++; - RCT2_CALLPROC_X(0x00695444, 0, 0, 0, peep->current_ride, (int)peep, 0, 0); + peep_on_enter_or_exit_ride(peep, peep->current_ride, 0); peep->sub_state = 14; return; } @@ -1293,7 +1980,7 @@ void peep_update_ride_sub_state_1(rct_peep* peep){ } 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; @@ -1318,7 +2005,7 @@ static void peep_go_to_ride_exit(rct_peep* peep, rct_ride* ride, sint16 x, sint1 z += RCT2_ADDRESS(0x0097D21C, uint8)[ride->type * 8]; sprite_move(x, y, z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); x = ride->exits[peep->current_ride_station] & 0xFF; y = ride->exits[peep->current_ride_station] >> 8; @@ -1362,15 +2049,13 @@ static void peep_update_ride_sub_state_2_enter_ride(rct_peep* peep, rct_ride* ri (peep->voucher_arguments == peep->current_ride)){ peep->item_standard_flags &= ~PEEP_ITEM_VOUCHER; - peep->var_45 |= (1 << 3); + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_INVENTORY; } 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); + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_PARK_RIDE_TICKETS * 4; + peep_spend_money(peep, &peep->paid_on_rides, ride->price); } } @@ -1435,32 +2120,32 @@ static void peep_update_ride_sub_state_2_rejoin_queue(rct_peep* peep, rct_ride* 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; + uint16 current_last = ride->last_peep_in_queue[peep->current_ride_station]; + if (current_last == 0xFFFF){ + ride->last_peep_in_queue[peep->current_ride_station] = peep->sprite_index; return; } rct_peep* queue_peep; - for (queue_peep = GET_PEEP(current_first); + for (queue_peep = GET_PEEP(current_last); 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 +/* 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. + * 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 || + ride->var_1CA != 0 || (++peep->var_AC) == 0){ peep_update_ride_sub_state_2_rejoin_queue(peep, ride); @@ -1506,7 +2191,7 @@ static void peep_update_ride_sub_state_2(rct_peep* peep){ if (ride->mode == RIDE_MODE_FORWARD_ROTATION || ride->mode == RIDE_MODE_BACKWARD_ROTATION){ - if (peep->current_seat & 1 || + if (peep->current_seat & 1 || !(vehicle->next_free_seat & 1)){ peep_update_ride_sub_state_2_enter_ride(peep, ride); return; @@ -1521,11 +2206,14 @@ static void peep_update_ride_sub_state_2(rct_peep* peep){ } } + rct_vehicle *currentTrain = GET_VEHICLE(ride->vehicles[peep->current_train]); if (ride->status == RIDE_STATUS_OPEN && ++peep->var_AC != 0 && - !((GET_VEHICLE(ride->vehicles[peep->current_train]))->var_48 & (1 << 4))) + !(vehicle->update_flags & VEHICLE_UPDATE_FLAG_TRAIN_READY_DEPART) + ) { return; - + } + if (ride->mode != RIDE_MODE_FORWARD_ROTATION && ride->mode != RIDE_MODE_BACKWARD_ROTATION){ if (vehicle->next_free_seat - 1 != peep->current_seat) @@ -1560,39 +2248,39 @@ static void peep_update_ride_sub_state_5(rct_peep* peep){ vehicle->num_peeps++; ride->var_120++; - vehicle->var_46 += seated_peep->var_41; - invalidate_sprite((rct_sprite*)seated_peep); + vehicle->friction += seated_peep->var_41; + invalidate_sprite_2((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->time_on_ride = 0; seated_peep->sub_state = 6; - RCT2_CALLPROC_X(0x00695444, 0, 0, 0, seated_peep->current_ride, (int)seated_peep, 0, 0); + peep_on_enter_or_exit_ride(seated_peep, peep->current_ride, 0); } vehicle->num_peeps++; ride->var_120++; - vehicle->var_46 += peep->var_41; - invalidate_sprite((rct_sprite*)vehicle); + vehicle->friction += peep->var_41; + invalidate_sprite_2((rct_sprite*)vehicle); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((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->time_on_ride = 0; peep->sub_state = 6; - RCT2_CALLPROC_X(0x00695444, 0, 0, 0, peep->current_ride, (int)peep, 0, 0); + peep_on_enter_or_exit_ride(peep, peep->current_ride, 0); } /* rct2: 0x00693028*/ -static void peep_update_ride_sub_state_7(rct_peep* peep){ +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]); @@ -1615,8 +2303,8 @@ static void peep_update_ride_sub_state_7(rct_peep* peep){ peep->action_sprite_image_offset = 0; vehicle->num_peeps--; - vehicle->var_46 -= peep->var_41; - invalidate_sprite((rct_sprite*)vehicle); + vehicle->friction -= peep->var_41; + invalidate_sprite_2((rct_sprite*)vehicle); peep->current_ride_station = ride_station; @@ -1635,17 +2323,17 @@ static void peep_update_ride_sub_state_7(rct_peep* peep){ 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) + + for (; vehicle->is_child; vehicle = GET_VEHICLE(vehicle->prev_vehicle_on_ride)){ + uint16 trackType = vehicle->track_type >> 2; + if (trackType == 0 || trackType > 3) continue; - rct_map_element* inner_map = map_get_first_element_at(vehicle->var_38 / 32, vehicle->var_3A / 32); + rct_map_element* inner_map = map_get_first_element_at(vehicle->track_x / 32, vehicle->track_y / 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) + if (inner_map->base_height == vehicle->track_z / 8) break; } @@ -1725,7 +2413,7 @@ static void peep_update_ride_sub_state_7(rct_peep* peep){ 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]; @@ -1766,7 +2454,7 @@ static void peep_update_ride_sub_state_7(rct_peep* peep){ z += 15; sprite_move(exit_x, exit_y, z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((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]; @@ -1780,7 +2468,7 @@ static void peep_update_ride_sub_state_7(rct_peep* peep){ /* 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]; @@ -1821,9 +2509,9 @@ static void peep_update_ride_prepare_for_state_9(rct_peep* peep){ 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); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(x, y, peep->z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } @@ -1836,25 +2524,25 @@ static void peep_update_ride_sub_state_9(rct_peep* peep){ rct_ride* ride = GET_RIDE(peep->current_ride); if (peep_update_action(&x, &y, &xy_distance, peep)){ - invalidate_sprite((rct_sprite*)peep); - + invalidate_sprite_2((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); + invalidate_sprite_2((rct_sprite*)peep); return; } - + sub_693BE5(peep, 0); sprite_move(x, y, peep->z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((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)){ + if (sub_69AF1E(peep, peep->current_ride, secondaryItem, ride->price_secondary)) { ride->no_secondary_items_sold++; } } @@ -1884,9 +2572,9 @@ static void peep_update_ride_sub_state_12(rct_peep* peep){ else{ z = peep->z; } - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(x, y, z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } @@ -1923,7 +2611,7 @@ static void peep_update_ride_sub_state_12(rct_peep* peep){ } /* rct2: 0x0069357D */ -static void peep_udpate_ride_sub_state_13(rct_peep* peep){ +static void peep_update_ride_sub_state_13(rct_peep* peep){ sint16 x, y, xy_distance; rct_ride* ride = GET_RIDE(peep->current_ride); @@ -1933,7 +2621,7 @@ static void peep_udpate_ride_sub_state_13(rct_peep* peep){ z = ride->station_heights[peep->current_ride_station] * 8 + 2; if ((peep->var_37 & 3) == 1){ - + if (xy_distance > 15) xy_distance = 15; @@ -1943,9 +2631,9 @@ static void peep_udpate_ride_sub_state_13(rct_peep* peep){ else{ z = peep->z; } - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(x, y, z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } @@ -1979,6 +2667,7 @@ static void peep_udpate_ride_sub_state_13(rct_peep* peep){ peep->destination_x = x; peep->destination_y = y; + return; } peep->var_37 |= 3; @@ -2024,9 +2713,9 @@ static void peep_update_ride_sub_state_14(rct_peep* peep){ rct_ride* ride = GET_RIDE(peep->current_ride); if (peep_update_action(&x, &y, &xy_distance, peep)){ - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(x, y, peep->z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } @@ -2057,7 +2746,7 @@ static void peep_update_ride_sub_state_14(rct_peep* peep){ 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; @@ -2074,7 +2763,7 @@ static void peep_update_ride_sub_state_14(rct_peep* peep){ peep->sub_state = 16; return; } - } + } peep->var_37++; x = ride->station_starts[peep->current_ride_station] & 0xFF; @@ -2118,13 +2807,13 @@ static void peep_update_ride_sub_state_15(rct_peep* peep){ 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]; @@ -2139,10 +2828,10 @@ static void peep_update_ride_sub_state_15(rct_peep* peep){ peep->sprite_direction = (peep->var_37 & 0xC) * 2; - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); peep->var_37++; - return; + return; } default: return; @@ -2152,9 +2841,9 @@ static void peep_update_ride_sub_state_15(rct_peep* peep){ sint16 x, y, xy_distance; if (peep_update_action(&x, &y, &xy_distance, peep)){ - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(x, y, peep->z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } @@ -2180,9 +2869,9 @@ 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); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(x, y, peep->z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } @@ -2246,9 +2935,9 @@ 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); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(x, y, peep->z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } @@ -2266,7 +2955,7 @@ static void peep_update_ride_sub_state_17(rct_peep* peep){ peep->action_frame = 0; peep->action_sprite_image_offset = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); } } @@ -2316,8 +3005,8 @@ static void peep_update_ride_sub_state_17(rct_peep* peep){ 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 = TileDirectionDelta[chosen_edge].x / 2; + y = TileDirectionDelta[chosen_edge].y / 2; x += peep->destination_x; y += peep->destination_y; @@ -2328,7 +3017,7 @@ static void peep_update_ride_sub_state_17(rct_peep* peep){ do { if (z != mapElement->base_height) continue; - + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_TRACK){ type = 1; break; @@ -2372,9 +3061,9 @@ static void peep_update_ride_sub_state_17(rct_peep* peep){ } if (peep_update_action(&x, &y, &xy_distance, peep)){ - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(x, y, peep->z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } } @@ -2385,13 +3074,13 @@ static void peep_update_ride_sub_state_18(rct_peep* peep){ rct_ride* ride = GET_RIDE(peep->current_ride); if (peep_update_action(&x, &y, &xy_distance, peep)){ - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(x, y, ride->station_heights[peep->current_ride_station] * 8, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } - RCT2_CALLPROC_X(0x00695444, 0, 0, 0, peep->current_ride | (1 << 8), (int)peep, 0, 0); + peep_on_enter_or_exit_ride(peep, peep->current_ride, 1); if (peep->flags & PEEP_FLAGS_TRACKING){ RCT2_GLOBAL(0x13CE952, uint16) = peep->name_string_idx; @@ -2424,7 +3113,7 @@ static void peep_update_ride_sub_state_18(rct_peep* peep){ continue; sprite_move(peep->x, peep->y, z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } while (!map_element_is_last_for_tile(mapElement++)); } @@ -2434,9 +3123,9 @@ 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); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(x, y, peep->z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } @@ -2472,7 +3161,10 @@ static void peep_update_ride_sub_state_20(rct_peep* peep){ return; } - sound_play_panned(SOUND_TOILET_FLUSH, 0x8001, peep->x, peep->y, peep->z); + // Do not play toilet flush sound on title screen as its considered loud and annoying + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO)) { + audio_play_sound_at_location(SOUND_TOILET_FLUSH, peep->x, peep->y, peep->z); + } peep->sub_state++; @@ -2493,9 +3185,9 @@ 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); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(x, y, peep->z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); x = peep->x & 0xFFE0; y = peep->y & 0xFFE0; @@ -2516,7 +3208,7 @@ static void peep_update_ride_sub_state_21(rct_peep* peep){ ride_update_satisfaction(ride, peep->happiness / 64); } -/* rct2: 0x691A30 +/* rct2: 0x691A30 * Used by entering_ride and queueing_front */ static void peep_update_ride(rct_peep* peep){ switch (peep->sub_state){ @@ -2541,9 +3233,9 @@ static void peep_update_ride(rct_peep* peep){ break; } - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(x, y, peep->z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); break; } case 5: @@ -2569,7 +3261,7 @@ static void peep_update_ride(rct_peep* peep){ peep_update_ride_sub_state_12(peep); break; case 13: - peep_udpate_ride_sub_state_13(peep); + peep_update_ride_sub_state_13(peep); break; case 14: peep_update_ride_sub_state_14(peep); @@ -2600,7 +3292,7 @@ static void peep_update_ride(rct_peep* peep){ } } -/* rct2: 0x006C0E8B +/* rct2: 0x006C0E8B * Also used by inspecting. */ static void peep_update_fixing(int steps, rct_peep* peep){ @@ -2646,7 +3338,7 @@ static void peep_update_queuing(rct_peep* peep){ } //Give up queueing for the ride peep->sprite_direction ^= (1 << 4); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); remove_peep_from_queue(peep); peep_decrement_num_riders(peep); peep->state = PEEP_STATE_1; @@ -2654,7 +3346,7 @@ static void peep_update_queuing(rct_peep* peep){ return; } - RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); + sub_693C9E(peep); if (peep->action < 0xFE)return; if (peep->sprite_type == 0){ if (peep->time_in_queue >= 2000 && (0xFFFF & scenario_rand()) <= 119){ @@ -2663,7 +3355,7 @@ static void peep_update_queuing(rct_peep* peep){ peep->action_frame = 0; peep->action_sprite_image_offset = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); } if (peep->time_in_queue >= 3500 && (0xFFFF & scenario_rand()) <= 93) { @@ -2701,7 +3393,7 @@ static void peep_update_queuing(rct_peep* peep){ peep->action_frame = 0; peep->action_sprite_image_offset = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); break; } } @@ -2711,7 +3403,7 @@ static void peep_update_queuing(rct_peep* peep){ if (peep->happiness <= 65 && (0xFFFF & scenario_rand()) < 2184){ //Give up queueing for the ride peep->sprite_direction ^= (1 << 4); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); remove_peep_from_queue(peep); peep_decrement_num_riders(peep); peep->state = PEEP_STATE_1; @@ -2724,17 +3416,13 @@ static void peep_update_mowing(rct_peep* peep){ peep->var_E2 = 0; if (!sub_68F3AE(peep))return; - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); while (1){ - sint16 x = 0, y = 0, xy_distance; + sint16 x = 0, y = 0, z, 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); - x = eax; - y = ecx; + z = map_element_height(x, y) & 0xFFFF; sprite_move(x, y, z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } @@ -2760,10 +3448,10 @@ static void peep_update_mowing(rct_peep* peep){ if ((map_element->properties.surface.terrain & MAP_ELEMENT_SURFACE_TERRAIN_MASK) == (TERRAIN_GRASS << 5)){ map_element->properties.surface.grass_length = 0; - gfx_invalidate_tile_if_zoomed(peep->next_x, peep->next_y, map_element->base_height * 8, map_element->base_height * 8 + 16); + map_invalidate_tile_zoom0(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); + peep->window_invalidate_flags |= PEEP_INVALIDATE_STAFF_STATS; } } @@ -2773,7 +3461,7 @@ static void peep_update_watering(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); + sub_693C9E(peep); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return; peep->sprite_direction = (peep->var_37 & 3) << 3; @@ -2781,8 +3469,8 @@ static void peep_update_watering(rct_peep* peep){ peep->action_frame = 0; peep->action_sprite_image_offset = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); - + invalidate_sprite_2((rct_sprite*)peep); + peep->sub_state = 1; } else if (peep->sub_state == 1){ @@ -2792,27 +3480,27 @@ static void peep_update_watering(rct_peep* 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]; + int x = peep->next_x + TileDirectionDelta[peep->var_37].x; + int y = peep->next_y + TileDirectionDelta[peep->var_37].y; 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; - + 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_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); + map_invalidate_tile_zoom0(x, y, map_element->base_height * 8, map_element->clearance_height * 8); peep->staff_gardens_watered++; - peep->var_45 |= (1 << 4); + peep->window_invalidate_flags |= PEEP_INVALIDATE_STAFF_STATS; } while (!map_element_is_last_for_tile(map_element++)); peep_state_reset(peep); @@ -2826,7 +3514,7 @@ static void peep_update_emptying_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); + sub_693C9E(peep); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return; peep->sprite_direction = (peep->var_37 & 3) << 3; @@ -2834,7 +3522,7 @@ static void peep_update_emptying_bin(rct_peep* peep){ peep->action_frame = 0; peep->action_sprite_image_offset = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); peep->sub_state = 1; } @@ -2880,10 +3568,10 @@ static void peep_update_emptying_bin(rct_peep* peep){ map_element->properties.path.addition_status |= ((3 << peep->var_37) << peep->var_37); - gfx_invalidate_tile_if_zoomed(peep->next_x, peep->next_y, map_element->base_height * 8, map_element->clearance_height * 8); + map_invalidate_tile_zoom0(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); + peep->window_invalidate_flags |= PEEP_INVALIDATE_STAFF_STATS; } } @@ -2891,24 +3579,20 @@ static void peep_update_emptying_bin(rct_peep* peep){ static void peep_update_sweeping(rct_peep* peep){ peep->var_E2 = 0; if (!sub_68F3AE(peep))return; - - invalidate_sprite((rct_sprite*)peep); + + invalidate_sprite_2((rct_sprite*)peep); if (peep->action == PEEP_ACTION_STAFF_SWEEP && peep->action_frame == 8){ - //Remove sick at this location - RCT2_CALLPROC_X(0x6738E1, peep->x, 0, peep->y, peep->z, 0, 0, 0); + // Remove sick at this location + litter_remove_at(peep->x, peep->y, peep->z); peep->staff_litter_swept++; - peep->var_45 |= (1 << 4); + peep->window_invalidate_flags |= PEEP_INVALIDATE_STAFF_STATS; } - sint16 x = 0, y = 0, xy_distance; + sint16 x = 0, y = 0, z, 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); - x = eax; - y = ecx; + z = peep_get_height_on_slope(peep, x, y); sprite_move(x, y, z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } @@ -2918,7 +3602,7 @@ static void peep_update_sweeping(rct_peep* peep){ peep->action_frame = 0; peep->action_sprite_image_offset = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } peep_state_reset(peep); @@ -2958,7 +3642,7 @@ static void peep_update_picked(rct_peep* peep){ /* rct2: 0x6914CD */ 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); + sub_693C9E(peep); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 2))return; peep_sprite_remove(peep); return; @@ -2966,13 +3650,13 @@ static void peep_update_leaving_park(rct_peep* peep){ sint16 x = 0, y = 0, xy_distance; if (peep_update_action(&x, &y, &xy_distance, peep)){ - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(x, y, peep->z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } - peep->var_2A = 1; + peep->outside_of_park = 1; peep->destination_tolerence = 5; RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16)--; RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) |= BTM_TB_DIRTY_FLAG_PEEP_COUNT; @@ -2980,7 +3664,7 @@ static void peep_update_leaving_park(rct_peep* peep){ window_invalidate_by_class(WC_GUEST_LIST); - RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); + sub_693C9E(peep); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 2))return; peep_sprite_remove(peep); } @@ -2990,14 +3674,14 @@ static void peep_update_watching(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); + sub_693C9E(peep); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return; peep->destination_x = peep->x; peep->destination_y = peep->y; peep->sprite_direction = (peep->var_37 & 3) * 8; - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); peep->action = 0xFE; peep->var_6F = 2; @@ -3025,27 +3709,27 @@ static void peep_update_watching(rct_peep* peep){ peep->action_frame = 0; peep->action_sprite_image_offset = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } } - + if ((scenario_rand() & 0xFFFF) <= 655){ peep->action = PEEP_ACTION_TAKE_PHOTO; peep->action_frame = 0; peep->action_sprite_image_offset = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } - + if ((peep->standing_flags & 1)){ if ((scenario_rand() & 0xFFFF) <= 655){ peep->action = PEEP_ACTION_WAVE; peep->action_frame = 0; peep->action_sprite_image_offset = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } } @@ -3074,7 +3758,7 @@ static void peep_update_watching(rct_peep* peep){ */ static void peep_update_entering_park(rct_peep* peep){ if (peep->var_37 != 1){ - RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); + sub_693C9E(peep); if ((RCT2_GLOBAL(0xF1EE18, uint16) & 2)){ RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16)--; peep_sprite_remove(peep); @@ -3083,17 +3767,17 @@ static void peep_update_entering_park(rct_peep* peep){ } sint16 x = 0, y = 0, xy_distance; if (peep_update_action(&x, &y, &xy_distance, peep)){ - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(x, y, peep->z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); return; } peep_decrement_num_riders(peep); peep->state = PEEP_STATE_FALLING; peep_window_state_update(peep); - peep->var_2A = 0; - peep->time_in_park = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, sint32); + peep->outside_of_park = 0; + peep->time_in_park = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32); RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16)++; RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16)--; RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) |= BTM_TB_DIRTY_FLAG_PEEP_COUNT; @@ -3149,7 +3833,7 @@ static int peep_update_walking_find_bench(rct_peep* peep){ free_edge &= ~(1 << ((sprite->peep.var_37 & 0x4) >> 2)); } - + if (!free_edge) return 0; free_edge ^= 0x3; @@ -3168,7 +3852,7 @@ static int peep_update_walking_find_bench(rct_peep* peep){ 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; @@ -3245,13 +3929,16 @@ static int peep_update_walking_find_bin(rct_peep* peep){ /* rct2: 0x00690848*/ static void peep_update_walking_break_scenery(rct_peep* peep){ + if(gConfigCheat.disable_vandalism) + return; + 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 ((peep->litter_count & 0xC0) != 0xC0 && + (peep->disgusting_count & 0xC0) != 0xC0) return; if ((scenario_rand() & 0xFFFF) > 3276) return; } @@ -3287,9 +3974,9 @@ static void peep_update_walking_break_scenery(rct_peep* peep){ uint16 sprite_index; FOR_ALL_STAFF(sprite_index, inner_peep){ - if (inner_peep->staff_type != STAFF_TYPE_SECURITY)continue; + if (inner_peep->staff_type != STAFF_TYPE_SECURITY) continue; - if (inner_peep->x == (sint16)SPRITE_LOCATION_NULL)continue; + if (inner_peep->x == SPRITE_LOCATION_NULL) continue; int x_diff = abs(inner_peep->x - peep->x); int y_diff = abs(inner_peep->y - peep->y); @@ -3299,10 +3986,10 @@ static void peep_update_walking_break_scenery(rct_peep* peep){ map_element->flags |= MAP_ELEMENT_FLAG_BROKEN; - map_invalidate_tile( - peep->next_x, - peep->next_y, - (map_element->base_height << 3) + 32, + map_invalidate_tile_zoom1( + peep->next_x, + peep->next_y, + (map_element->base_height << 3) + 32, map_element->base_height << 3); peep->var_F3 = 0x10; @@ -3314,7 +4001,7 @@ static void peep_update_walking_break_scenery(rct_peep* peep){ 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); @@ -3351,19 +4038,17 @@ static void peep_update_buying(rct_peep* peep) 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){ + item_bought = peep_should_use_cash_machine(peep, peep->current_ride); + if (!item_bought) { peep->previous_ride = peep->current_ride; peep->previous_ride_time_out = 0; - } - else{ + } 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); + invalidate_sprite_2((rct_sprite*)peep); ride->no_primary_items_sold++; } @@ -3373,9 +4058,8 @@ static void peep_update_buying(rct_peep* peep) 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){ + item_bought = sub_69AF1E(peep, peep->current_ride, ride_type->shop_item_secondary, price); + if (item_bought) { ride->no_secondary_items_sold++; } } @@ -3383,9 +4067,8 @@ static void peep_update_buying(rct_peep* peep) 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){ + item_bought = sub_69AF1E(peep, peep->current_ride, ride_type->shop_item, price); + if (item_bought) { ride->no_primary_items_sold++; } } @@ -3399,7 +4082,7 @@ static void peep_update_buying(rct_peep* peep) } else{ ride_update_popularity(ride, 0); - } + } peep->sub_state = 1; return; } @@ -3409,7 +4092,7 @@ 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); + sub_693C9E(peep); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return; peep->sub_state = 1; @@ -3467,7 +4150,7 @@ static void peep_update_using_bin(rct_peep* peep){ 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 (!(empty_containers & (1u << cur_container))) continue; if (rubbish_in_bin != 0){ // OpenRCT2 modification: This previously used @@ -3475,7 +4158,7 @@ static void peep_update_using_bin(rct_peep* peep){ // 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->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_INVENTORY; peep_update_sprite_type(peep); continue; } @@ -3485,9 +4168,9 @@ static void peep_update_using_bin(rct_peep* peep){ 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); + litter_create(x, y, peep->z, scenario_rand() & 3, bp); peep->item_standard_flags &= ~(1 << cur_container); - peep->var_45 |= 8; + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_INVENTORY; peep_update_sprite_type(peep); } @@ -3497,7 +4180,7 @@ static void peep_update_using_bin(rct_peep* peep){ 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 (!(empty_containers & (1u << cur_container))) continue; if (rubbish_in_bin != 0){ // OpenRCT2 modification: This previously used @@ -3505,7 +4188,7 @@ static void peep_update_using_bin(rct_peep* peep){ // 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->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_INVENTORY; peep_update_sprite_type(peep); continue; @@ -3516,9 +4199,9 @@ static void peep_update_using_bin(rct_peep* peep){ 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); + litter_create(x, y, peep->z, scenario_rand() & 3, bp); peep->item_extra_flags &= ~(1 << cur_container); - peep->var_45 |= 8; + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_INVENTORY; peep_update_sprite_type(peep); } @@ -3528,7 +4211,7 @@ static void peep_update_using_bin(rct_peep* peep){ // 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); + map_invalidate_tile_zoom0(peep->next_x, peep->next_y, map_element->base_height << 3, map_element->clearance_height << 3); peep_state_reset(peep); } } @@ -3552,7 +4235,7 @@ static void peep_update_heading_to_inspect(rct_peep* peep){ return; } - if (ride->mechanic_status != RIDE_MECHANIC_STATUS_HEADING || + 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; @@ -3562,10 +4245,10 @@ static void peep_update_heading_to_inspect(rct_peep* peep){ if (peep->sub_state == 0){ peep->var_74 = 0; - RCT2_CALLPROC_X(0x0069A98C, 0, 0, 0, 0, (int)peep, 0, 0); + sub_69A98C(peep); peep->sub_state = 2; } - + if (peep->sub_state <= 3){ peep->var_74++; if (peep->var_74 > 2500){ @@ -3581,7 +4264,7 @@ static void peep_update_heading_to_inspect(rct_peep* peep){ if (!sub_68F3AE(peep))return; - RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); + sub_693C9E(peep); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 0xC))return; @@ -3616,7 +4299,7 @@ static void peep_update_heading_to_inspect(rct_peep* peep){ // Falls through into sub_state 4 } - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); sint16 delta_y = abs(peep->y - peep->destination_y); @@ -3636,14 +4319,14 @@ static void peep_update_heading_to_inspect(rct_peep* peep){ } sprite_move(x, y, z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((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 || + if (ride->type == RIDE_TYPE_NULL || ride->mechanic_status != RIDE_MECHANIC_STATUS_HEADING){ peep_decrement_num_riders(peep); @@ -3658,7 +4341,7 @@ static void peep_update_answering(rct_peep* peep){ peep->action_sprite_image_offset = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); peep->sub_state = 1; peep_window_state_update(peep); @@ -3669,7 +4352,7 @@ static void peep_update_answering(rct_peep* peep){ 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); + sub_69A98C(peep); return; } sint16 x, y, xy_distance; @@ -3691,13 +4374,13 @@ static void peep_update_answering(rct_peep* peep){ if (!sub_68F3AE(peep))return; - RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); + sub_693C9E(peep); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 0xC))return; rct_map_element* map_element = RCT2_GLOBAL(0x00F1EE1A, rct_map_element*); - if (peep->current_ride != + if (peep->current_ride != map_element->properties.entrance.ride_index) return; @@ -3726,7 +4409,7 @@ static void peep_update_answering(rct_peep* peep){ // Falls through into sub_state 4 } - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); sint16 delta_y = abs(peep->y - peep->destination_y); @@ -3746,7 +4429,7 @@ static void peep_update_answering(rct_peep* peep){ } sprite_move(x, y, z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); } /* rct2: 0x006BF483 */ @@ -3758,8 +4441,8 @@ static int peep_update_patrolling_find_watering(rct_peep* peep){ 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]; + int x = peep->next_x + TileDirectionDelta[chosen_position].x; + int y = peep->next_y + TileDirectionDelta[chosen_position].y; rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); @@ -3931,7 +4614,7 @@ 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); + sub_693C9E(peep); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return; if ((peep->next_var_29 & 0x18) == 8){ @@ -3940,10 +4623,10 @@ static void peep_update_patrolling(rct_peep* peep){ 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); + invalidate_sprite_2((rct_sprite*)peep); water_height *= 16; sprite_move(peep->x, peep->y, water_height, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); peep_decrement_num_riders(peep); peep->state = PEEP_STATE_FALLING; @@ -3971,14 +4654,14 @@ static void peep_update_walking(rct_peep* peep){ if (peep->flags & PEEP_FLAGS_WAVING){ if (peep->action >= PEEP_ACTION_NONE_1){ if ((0xFFFF & scenario_rand()) < 936){ - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((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); + invalidate_sprite_2((rct_sprite*)peep); } } } @@ -3986,14 +4669,14 @@ static void peep_update_walking(rct_peep* peep){ if (peep->flags & PEEP_FLAGS_PHOTO){ if (peep->action >= PEEP_ACTION_NONE_1){ if ((0xFFFF & scenario_rand()) < 936){ - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((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); + invalidate_sprite_2((rct_sprite*)peep); } } } @@ -4001,14 +4684,14 @@ static void peep_update_walking(rct_peep* peep){ if (peep->flags & PEEP_FLAGS_PAINTING){ if (peep->action >= PEEP_ACTION_NONE_1){ if ((0xFFFF & scenario_rand()) < 936){ - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((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); + invalidate_sprite_2((rct_sprite*)peep); } } } @@ -4021,15 +4704,15 @@ static void peep_update_walking(rct_peep* peep){ 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); + litter_create(x, y, peep->z, direction, ebp); } } } else if (peep_has_empty_container(peep)){ - if ((!(peep->next_var_29 & 0x18)) && + 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<var_45 |= 8; + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_INVENTORY; 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); + litter_create(x, y, peep->z, direction, bp); } } - RCT2_CALLPROC_X(0x693C9E, 0, 0, 0, 0, (int)peep, 0, 0); + sub_693C9E(peep); 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); + invalidate_sprite_2((rct_sprite*)peep); water_height *= 16; sprite_move(peep->x, peep->y, water_height, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); peep_decrement_num_riders(peep); peep->state = PEEP_STATE_FALLING; @@ -4133,16 +4816,9 @@ static void peep_update_walking(rct_peep* peep){ 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; - } + uint8 ride_to_view, ride_seat_to_view; + if (!sub_690B99(peep, chosen_edge, &ride_to_view, &ride_seat_to_view)) + return; 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){ @@ -4194,7 +4870,7 @@ static void peep_update_walking(rct_peep* peep){ /* From peep_update */ static void peep_update_thoughts(rct_peep* peep){ // Thoughts must always have a gap of at least - // 220 ticks in age between them. In order to + // 220 ticks in age between them. In order to // allow this when a thought is new it enters // a holding zone. Before it becomes fresh. int add_fresh = 1; @@ -4205,7 +4881,7 @@ static void peep_update_thoughts(rct_peep* peep){ if (peep->thoughts[i].var_2 == 1) { - add_fresh = 0; + add_fresh = 0; // If thought is fresh we wait 220 ticks // before allowing a new thought to become fresh. if (++peep->thoughts[i].var_3 >= 220) { @@ -4216,13 +4892,15 @@ static void peep_update_thoughts(rct_peep* peep){ } } else if (peep->thoughts[i].var_2 > 1) { - if (++peep->thoughts[i].var_3 == 0) { + if (++peep->thoughts[i].var_3 == 0) { // When thought is older than ~6900 ticks remove it if (++peep->thoughts[i].var_2 >= 28) { - peep->var_45 |= 1; + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_THOUGHTS; // Clear top thought, push others up - memmove(&peep->thoughts[i], &peep->thoughts[i + 1], sizeof(rct_peep_thought)*(PEEP_MAX_THOUGHTS - i - 1)); + if (i < PEEP_MAX_THOUGHTS - 1) { + 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; } } @@ -4231,12 +4909,12 @@ static void peep_update_thoughts(rct_peep* peep){ fresh_thought = i; } } - // If there are no fresh thoughts - // a previously new thought can become + // If there are no fresh thoughts + // a previously new thought can become // fresh. if (add_fresh && fresh_thought != -1) { peep->thoughts[fresh_thought].var_2 = 1; - peep->var_45 |= 1; + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_THOUGHTS; } } @@ -4270,7 +4948,7 @@ static void peep_update(rct_peep *peep) peep->var_73 = carryCheck; if (carryCheck <= 255) { // loc_68FD3A - RCT2_CALLPROC_X(0x0068FD3A, 0, 0, 0, 0, (int)peep, 0, 0); + sub_68FD3A(peep); } else { // loc_68FD2F switch (peep->state) { @@ -4347,7 +5025,7 @@ static void peep_update(rct_peep *peep) peep_update_fixing(stepsToTake, peep); break; //There shouldnt be any more - default: + default: assert(0); break; } @@ -4367,12 +5045,12 @@ void peep_problem_warnings_update() uint16 guests_in_park = RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16); int hunger_counter = 0, lost_counter = 0, noexit_counter = 0, thirst_counter = 0, litter_counter = 0, disgust_counter = 0, bathroom_counter = 0 ,vandalism_counter = 0; - static int warning_throttle[7] = { 0, 0, 0, 0, 0, 0, 0 }; + uint8* warning_throttle = RCT2_ADDRESS(0x01358750, uint8); RCT2_GLOBAL(RCT2_ADDRESS_RIDE_COUNT, sint16) = ride_get_count(); // refactor this to somewhere else FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->var_2A != 0 || peep->thoughts[0].var_2 > 5) + if (peep->outside_of_park != 0 || peep->thoughts[0].var_2 > 5) continue; switch (peep->thoughts[0].type) { @@ -4386,7 +5064,7 @@ void peep_problem_warnings_update() break; } ride = &g_ride_list[peep->guest_heading_to_ride_id]; - if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_SELLS_FOOD)) + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) hunger_counter++; break; @@ -4491,13 +5169,10 @@ void peep_update_crowd_noise() rct_peep *peep; int visiblePeeps; - if (!(RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0))) + if (gGameSoundsOff) return; - if (RCT2_GLOBAL(0x009AF59C, uint8) != 0) - return; - - if (!(RCT2_GLOBAL(0x009AF59D, uint8) & (1 << 0))) + if (!gConfigSound.sound) return; if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) @@ -4533,14 +5208,9 @@ void peep_update_crowd_noise() visiblePeeps = (visiblePeeps / 2) - 6; if (visiblePeeps < 0) { // Mute crowd noise - if (RCT2_GLOBAL(0x009AF5FC, uint32) != 1) { -#ifdef USE_MIXER + if (gCrowdSoundChannel) { Mixer_Stop_Channel(gCrowdSoundChannel); gCrowdSoundChannel = 0; -#else - sound_channel_stop(2); //RCT2_CALLPROC_1(0x00401A05, int, 2); -#endif - RCT2_GLOBAL(0x009AF5FC, uint32) = 1; } } else { sint32 volume; @@ -4551,37 +5221,16 @@ void peep_update_crowd_noise() volume = volume * volume * volume * volume; volume = (((207360000 - volume) >> viewport->zoom) - 207360000) / 65536 - 150; - // Check if crowd noise is already playing - if (RCT2_GLOBAL(0x009AF5FC, uint32) == 1) { - // Load and play crowd noise -#ifdef USE_MIXER - if (!gCrowdSoundChannel) { - gCrowdSoundChannel = Mixer_Play_Music(PATH_ID_CSS2, MIXER_LOOP_INFINITE, false); - if (gCrowdSoundChannel) { - Mixer_Channel_SetGroup(gCrowdSoundChannel, MIXER_GROUP_NONE); - } - } + // Load and play crowd noise if needed and set volume + if (!gCrowdSoundChannel) { + gCrowdSoundChannel = Mixer_Play_Music(PATH_ID_CSS2, MIXER_LOOP_INFINITE, false); if (gCrowdSoundChannel) { - Mixer_Channel_Volume(gCrowdSoundChannel, DStoMixerVolume(volume)); - RCT2_GLOBAL(0x009AF5FC, uint32) = volume; - } -#else - if (sound_channel_load_file2(2, (char*)get_file_path(PATH_ID_CSS2), 0)) { - sound_channel_play(2, 1, volume, 0, 0); - RCT2_GLOBAL(0x009AF5FC, uint32) = volume; - } -#endif - } else { - // Alter crowd noise volume - if (RCT2_GLOBAL(0x009AF5FC, uint32) != volume) { -#ifdef USE_MIXER - Mixer_Channel_Volume(gCrowdSoundChannel, DStoMixerVolume(volume)); -#else - sound_channel_set_volume(2, volume);//RCT2_CALLPROC_2(0x00401AD3, int, int, 2, volume); -#endif - RCT2_GLOBAL(0x009AF5FC, uint32) = volume; + Mixer_Channel_SetGroup(gCrowdSoundChannel, MIXER_GROUP_NONE); } } + if (gCrowdSoundChannel) { + Mixer_Channel_Volume(gCrowdSoundChannel, DStoMixerVolume(volume)); + } } } @@ -4592,10 +5241,10 @@ void peep_update_crowd_noise() void peep_applause() { uint16 spriteIndex; - rct_peep* peep; + rct_peep* peep; FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->var_2A != 0) + if (peep->outside_of_park != 0) continue; // Release balloon @@ -4603,7 +5252,7 @@ void peep_applause() peep->item_standard_flags &= ~PEEP_ITEM_BALLOON; if (peep->x != (sint16)0x8000) { create_balloon(peep->x, peep->y, peep->z + 9, peep->balloon_colour, 0); - peep->var_45 |= 8; + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_INVENTORY; peep_update_sprite_type(peep); } } @@ -4614,12 +5263,12 @@ void peep_applause() peep->action_frame = 0; peep->action_sprite_image_offset = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); } } // Play applause noise - sound_play_panned(SOUND_APPLAUSE, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2, 0, 0, 0); + audio_play_sound_panned(SOUND_APPLAUSE, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2, 0, 0, 0); } /** @@ -4632,7 +5281,7 @@ void peep_update_days_in_queue() rct_peep *peep; FOR_ALL_GUESTS(sprite_index, peep) { - if (peep->var_2A == 0 && peep->state == PEEP_STATE_QUEUING) { + if (peep->outside_of_park == 0 && peep->state == PEEP_STATE_QUEUING) { if (peep->days_in_queue < 255) { peep->days_in_queue += 1; } @@ -4654,8 +5303,8 @@ rct_peep *peep_generate(int x, int y, int z) move_sprite_to_list((rct_sprite*)peep, SPRITE_LINKEDLIST_OFFSET_PEEP); peep->sprite_identifier = 1; - peep->sprite_type = 0; - peep->var_2A = 1; + peep->sprite_type = PEEP_SPRITE_TYPE_NORMAL; + peep->outside_of_park = 1; peep->state = PEEP_STATE_FALLING; peep->action = PEEP_ACTION_NONE_2; peep->var_6D = 0; @@ -4664,7 +5313,7 @@ rct_peep *peep_generate(int x, int y, int z) peep->action_sprite_type = 0; peep->flags = 0; peep->favourite_ride = 0xFF; - peep->var_FA = 0; + peep->favourite_ride_rating = 0; uint8* edx = RCT2_ADDRESS(0x98270C, uint8*)[peep->sprite_type * 2]; peep->sprite_width = edx[peep->action_sprite_type * 4]; @@ -4674,7 +5323,7 @@ rct_peep *peep_generate(int x, int y, int z) peep->sprite_direction = 0; sprite_move(x, y, z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); peep->var_41 = (scenario_rand() & 0x1F) + 45; peep->var_C4 = 0; @@ -4682,7 +5331,7 @@ rct_peep *peep_generate(int x, int y, int z) peep->type = PEEP_TYPE_GUEST; peep->previous_ride = 0xFF; peep->thoughts->type = PEEP_THOUGHT_TYPE_NONE; - peep->var_45 = 0; + peep->window_invalidate_flags = 0; uint8 al = (scenario_rand() & 0x7) + 3; uint8 ah = min(al, 7) - 3; @@ -4731,7 +5380,7 @@ rct_peep *peep_generate(int x, int y, int z) memset(&peep->rides_been_on, 0, 32); peep->no_of_rides = 0; - memset(&peep->var_48, 0, 16); + memset(&peep->ride_types_been_on, 0, 16); peep->id = RCT2_GLOBAL(0x013B0E6C, uint32)++; peep->name_string_idx = 767; @@ -4746,19 +5395,22 @@ rct_peep *peep_generate(int x, int y, int z) cash = 0; } - if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) == 0xFFFF){ + if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) == (money16)0xFFFF){ cash = 0; } peep->cash_in_pocket = cash; peep->cash_spent = 0; peep->time_in_park = -1; - peep->var_CC = 0xFFFF; + peep->var_CC.x = 0xFF; + peep->var_CC.y = 0xFF; + peep->var_CC.z = 0xFF; + peep->var_CC.direction = 0xFF; 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->litter_count = 0; + peep->disgusting_count = 0; peep->var_EF = 0; peep->paid_to_enter = 0; peep->paid_on_rides = 0; @@ -4783,9 +5435,9 @@ rct_peep *peep_generate(int x, int y, int z) 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); + peep_give_real_name(peep); } - RCT2_CALLPROC_X(0x00699115, 0, 0, 0, 0, (int)peep, 0, 0); + peep_update_name_sort(peep); RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16)++; @@ -4930,39 +5582,26 @@ void get_arguments_from_action(rct_peep* peep, uint32 *argument_1, uint32* argum * argument_1 (esi & ebx) * argument_2 (esi+2) */ -void get_arguments_from_thought(rct_peep_thought thought, uint32* argument_1, uint32* argument_2){ - int esi = 0x9AC86C; +void get_arguments_from_thought(rct_peep_thought thought, uint32* argument_1, uint32* argument_2) +{ + int esi = 0x009AC86C; - if ((RCT2_ADDRESS(0x981DB1, uint16)[thought.type] & 0xFF) & 1){ + if ((RCT2_ADDRESS(0x00981DB1, uint16)[thought.type] & 0xFF) & 1) { rct_ride* ride = &g_ride_list[thought.item]; esi = (int)(&(ride->name)); - } - else if ((RCT2_ADDRESS(0x981DB1, uint16)[thought.type] & 0xFF) & 2){ - if (thought.item < 0x20){ - RCT2_GLOBAL(0x9AC86C, uint16) = thought.item + STR_ITEM_START; - } - else{ - RCT2_GLOBAL(0x9AC86C, uint16) = thought.item + STR_ITEM2_START; - } - } - else if ((RCT2_ADDRESS(0x981DB1, uint16)[thought.type] & 0xFF) & 4){ - if (thought.item < 0x20){ - RCT2_GLOBAL(0x9AC86C, uint16) = thought.item + STR_ITEM_SINGULAR_START; - } - else - { - RCT2_GLOBAL(0x9AC86C, uint16) = thought.item + STR_ITEM2_SINGULAR_START; - } - } - else{ - esi = 0x9AC864; //No thought? + } else if ((RCT2_ADDRESS(0x00981DB1, uint16)[thought.type] & 0xFF) & 2) { + RCT2_GLOBAL(0x009AC86C, uint16) = ShopItemStringIds[thought.item].singular; + } else if ((RCT2_ADDRESS(0x00981DB1, uint16)[thought.type] & 0xFF) & 4) { + RCT2_GLOBAL(0x009AC86C, uint16) = ShopItemStringIds[thought.item].indefinite; + } else { + esi = 0x009AC864; //No thought? } *argument_1 = ((thought.type + STR_THOUGHT_START) & 0xFFFF) | (*((uint16*)esi) << 16); *argument_2 = *((uint32*)(esi + 2)); //Always 0 apart from on rides? } /** - * rct2: 0x00698827 + * rct2: 0x00698827 * returns 1 on pickup (CF not set) */ int peep_can_be_picked_up(rct_peep* peep){ @@ -5082,7 +5721,7 @@ int peep_get_easteregg_name_id(rct_peep *peep) { char buffer[256]; int i; - + format_string(buffer, peep->name_string_idx, &peep->id); for (i = 0; i < countof(gPeepEasterEggNames); i++) @@ -5102,6 +5741,15 @@ int peep_is_mechanic(rct_peep *peep) ); } +bool peep_has_item(rct_peep *peep, int peepItem) +{ + if (peepItem < 32) { + return peep->item_standard_flags & (1u << peepItem); + } else { + return peep->item_extra_flags & (1u << (peepItem - 32)); + } +} + static int peep_has_food_standard_flag(rct_peep* peep){ return peep->item_standard_flags &( PEEP_ITEM_DRINK | @@ -5139,7 +5787,7 @@ static int peep_has_food_extra_flag(rct_peep* peep){ ); } -/* To simplify check of 0x36BA3E0 and 0x11FF78 +/* To simplify check of 0x36BA3E0 and 0x11FF78 * returns 0 on no food. */ int peep_has_food(rct_peep* peep){ @@ -5147,6 +5795,31 @@ int peep_has_food(rct_peep* peep){ peep_has_food_extra_flag(peep); } +static int peep_has_drink_standard_flag(rct_peep* peep){ + return peep->item_standard_flags &( + PEEP_ITEM_DRINK | + PEEP_ITEM_COFFEE | + PEEP_ITEM_LEMONADE); +} + +static int peep_has_drink_extra_flag(rct_peep* peep){ + return peep->item_extra_flags &( + PEEP_ITEM_CHOCOLATE | + PEEP_ITEM_ICED_TEA | + PEEP_ITEM_FRUIT_JUICE | + PEEP_ITEM_SOYBEAN_MILK | + PEEP_ITEM_SU_JONGKWA + ); +} + +/* To simplify check of NOT(0x12BA3C0 and 0x118F48) + * returns 0 on no food. + */ +static int peep_has_drink(rct_peep* peep){ + return peep_has_drink_standard_flag(peep) || + peep_has_drink_extra_flag(peep); +} + static int peep_empty_container_standard_flag(rct_peep* peep){ return peep->item_standard_flags &( PEEP_ITEM_EMPTY_CAN | @@ -5185,7 +5858,7 @@ static int peep_should_find_bench(rct_peep* peep){ if (peep->nausea <= 170 && peep->energy > 50){ return 0; } - + if (!(peep->next_var_29 & 0x1C)){ return 1; } @@ -5207,9 +5880,9 @@ void peep_insert_new_thought(rct_peep *peep, uint8 thought_type, uint8 thought_a peep->action_frame = 0; peep->action_sprite_image_offset = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); } - + for (int i = 0; i < PEEP_MAX_THOUGHTS; ++i){ rct_peep_thought* thought = &peep->thoughts[i]; // Remove the oldest thought by setting it to NONE. @@ -5219,7 +5892,9 @@ void peep_insert_new_thought(rct_peep *peep, uint8 thought_type, uint8 thought_a // If the thought type has not changed then we need to move // it to the top of the thought list. This is done by first removing the // existing thought and placing it at the top. - memmove(thought, thought + 1, sizeof(rct_peep_thought)*(PEEP_MAX_THOUGHTS - i - 1)); + if (i < PEEP_MAX_THOUGHTS - 1) { + memmove(thought, thought + 1, sizeof(rct_peep_thought)*(PEEP_MAX_THOUGHTS - i - 1)); + } break; } } @@ -5231,10 +5906,10 @@ void peep_insert_new_thought(rct_peep *peep, uint8 thought_type, uint8 thought_a peep->thoughts[0].var_2 = 0; peep->thoughts[0].var_3 = 0; - peep->var_45 |= (1 << 0); + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_THOUGHTS; } -/* rct2: 0x00699FE3 +/* 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 @@ -5264,11 +5939,14 @@ static void peep_stop_purchase_thought(rct_peep* peep, uint8 ride_type){ if (thought->type != thought_type)continue; - memmove(thought, thought + 1, sizeof(rct_peep_thought)*(PEEP_MAX_THOUGHTS - i - 1)); + + if (i < PEEP_MAX_THOUGHTS - 1) { + 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); + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_THOUGHTS; i--; } } @@ -5301,13 +5979,3217 @@ void peep_set_map_tooltip(rct_peep *peep) void sub_693BAB(rct_peep* peep) { uint8 bl = peep->var_6F; if (bl != peep->action_sprite_type) { - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((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); + invalidate_sprite_2((rct_sprite*)peep); } } +/** + * + * rct2: 0x00693CBB + */ +static int peep_update_queue_position(rct_peep* peep){ + peep->time_in_queue++; + if (peep->next_in_queue == 0xFFFF) + return 0; + + rct_peep* peep_next = GET_PEEP(peep->next_in_queue); + + sint16 x_diff = abs(peep_next->x - peep->x); + sint16 y_diff = abs(peep_next->y - peep->y); + sint16 z_diff = abs(peep_next->z - peep->z); + + if (z_diff > 10) + return 0; + + if (x_diff < y_diff){ + sint16 temp_x = x_diff; + x_diff = y_diff; + y_diff = temp_x; + } + + x_diff += y_diff / 2; + if (x_diff > 7){ + if (x_diff > 13){ + if ((peep->x & 0xFFE0) != (peep_next->x & 0xFFE0) || + (peep->y & 0xFFE0) != (peep_next->y & 0xFFE0)) + return 0; + } + + if (peep->sprite_direction != peep_next->sprite_direction) + return 0; + + switch (peep->sprite_direction / 8){ + case 0: + if (peep->x >= peep_next->x) + return 0; + break; + case 1: + if (peep->y <= peep_next->y) + return 0; + break; + case 2: + if (peep->x <= peep_next->x) + return 0; + break; + case 3: + if (peep->y >= peep_next->y) + return 0; + break; + } + } + + sint16 xy_dist, x, y; + if (peep->action < PEEP_ACTION_NONE_1) + peep_update_action(&x, &y, &xy_dist, peep); + + if (peep->action != PEEP_ACTION_NONE_2) + return 1; + + peep->action = PEEP_ACTION_NONE_1; + peep->var_6F = 2; + if (RCT2_GLOBAL(0x00F1AEF1, uint8) != 0xFE) + invalidate_sprite_2((rct_sprite*)peep); + return 1; +} + +/* rct2: 0x00693EF2 */ +static int peep_return_to_center_of_tile(rct_peep* peep){ + peep->var_78 ^= (1 << 1); + peep->destination_x = (peep->x & 0xFFE0) + 16; + peep->destination_y = (peep->y & 0xFFE0) + 16; + peep->destination_tolerence = 5; + return 1; +} + +/* rct2: 0x00693f2C*/ +static int peep_interact_with_entrance(rct_peep* peep, sint16 x, sint16 y, rct_map_element* map_element){ + uint8 entranceType = map_element->properties.entrance.type; + uint8 rideIndex = map_element->properties.entrance.ride_index; + + if (entranceType == ENTRANCE_TYPE_RIDE_EXIT){ + RCT2_GLOBAL(0x00F1EE18, uint8) |= (1 << 2); + RCT2_GLOBAL(0x00F1EE1A, rct_map_element*) = map_element; + } + else if (entranceType == ENTRANCE_TYPE_RIDE_ENTRANCE){ + RCT2_GLOBAL(0x00F1EE18, uint8) |= (1 << 3); + RCT2_GLOBAL(0x00F1EE1A, rct_map_element*) = map_element; + } + + if (entranceType == ENTRANCE_TYPE_RIDE_EXIT){ + peep->var_79 = 0xFF; + return peep_return_to_center_of_tile(peep); + } + + if (entranceType == ENTRANCE_TYPE_RIDE_ENTRANCE){ + if (peep->type == PEEP_TYPE_STAFF){ + peep->var_79 = 0xFF; + return peep_return_to_center_of_tile(peep); + } + + if (peep->state == PEEP_STATE_QUEUING){ + peep->sub_state = 11; + peep->action_sprite_image_offset = RCT2_GLOBAL(0x00F1AEF0, uint8); + return 1; + } + + if (peep->var_79 == rideIndex) + return peep_return_to_center_of_tile(peep); + + peep->var_F4 = 0; + uint8 stationNum = (map_element->properties.entrance.index >> 4) & 0x7; + if (!peep_should_go_on_ride(peep, rideIndex, stationNum, 0)){ + peep->var_79 = rideIndex; + return peep_return_to_center_of_tile(peep); + } + + peep->action_sprite_image_offset = RCT2_GLOBAL(0x00F1AEF0, uint8); + peep->var_79 = rideIndex; + + rct_ride* ride = GET_RIDE(rideIndex); + uint16 previous_last = ride->last_peep_in_queue[stationNum]; + ride->last_peep_in_queue[stationNum] = peep->sprite_index; + peep->next_in_queue = previous_last; + ride->queue_length[stationNum]++; + + peep_decrement_num_riders(peep); + peep->current_ride = rideIndex; + peep->current_ride_station = stationNum; + peep->state = PEEP_STATE_QUEUING; + peep->days_in_queue = 0; + peep_window_state_update(peep); + peep->sub_state = 11; + peep->time_in_queue = 0; + if (peep->flags & PEEP_FLAGS_TRACKING){ + RCT2_GLOBAL(0x0013CE952, rct_string_id) = peep->name_string_idx; + RCT2_GLOBAL(0x0013CE954, uint32) = peep->id; + RCT2_GLOBAL(0x0013CE958, rct_string_id) = ride->name; + RCT2_GLOBAL(0x0013CE95A, uint32) = ride->name_arguments; + news_item_add_to_queue(NEWS_ITEM_PEEP_ON_RIDE, 1931, peep->sprite_index); + } + return 1; + } + else{ + // PARK_ENTRANCE + if (peep->type == PEEP_TYPE_STAFF) + return peep_return_to_center_of_tile(peep); + + // If not the center of the entrance arch + if (map_element->properties.entrance.index & 0xF) + return peep_return_to_center_of_tile(peep); + + uint8 entranceDirection = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + if (entranceDirection != peep->var_78){ + if ((entranceDirection ^ (1 << 1)) != peep->var_78) + return peep_return_to_center_of_tile(peep); + // Peep is leaving the park. + if (peep->state != PEEP_STATE_WALKING) + return peep_return_to_center_of_tile(peep); + + if (!(peep->flags & PEEP_FLAGS_LEAVING_PARK)){ + // If the park is open and leaving flag isnt set return to center + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_OPEN) + return peep_return_to_center_of_tile(peep); + } + + peep->destination_x += TileDirectionDelta[peep->var_78].x; + peep->destination_y += TileDirectionDelta[peep->var_78].y; + peep->destination_tolerence = 9; + invalidate_sprite_2((rct_sprite*)peep); + sprite_move(x, y, peep->z, (rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); + + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_LEAVING_PARK; + peep_window_state_update(peep); + + peep->var_37 = 0; + if (peep->flags & PEEP_FLAGS_TRACKING){ + RCT2_GLOBAL(0x0013CE952, rct_string_id) = peep->name_string_idx; + RCT2_GLOBAL(0x0013CE954, uint32) = peep->id; + news_item_add_to_queue(NEWS_ITEM_PEEP_ON_RIDE, 1935, peep->sprite_index); + } + return 1; + } + + // Peep is entering the park. + + if (peep->state != PEEP_STATE_ENTERING_PARK) + return peep_return_to_center_of_tile(peep); + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_OPEN)){ + peep->state = PEEP_STATE_LEAVING_PARK; + peep->var_37 = 1; + RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16)--; + peep_window_state_update(peep); + return peep_return_to_center_of_tile(peep); + } + + uint8 entranceIndex = 0; + while (1){ + if (RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[entranceIndex] == (x & 0xFFE0) && + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, sint16)[entranceIndex] == (y & 0xFFE0)) + break; + entranceIndex++; + } + + sint16 z = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Z, sint16)[entranceIndex] / 8; + entranceDirection = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_DIRECTION, uint8)[entranceIndex]; + + sint16 next_x = (x & 0xFFE0) + TileDirectionDelta[entranceDirection].x; + sint16 next_y = (y & 0xFFE0) + TileDirectionDelta[entranceDirection].y; + + uint8 found = 0; + rct_map_element* nextMapElement = map_get_first_element_at(next_x / 32, next_y / 32); + do{ + if (map_element_get_type(nextMapElement) != MAP_ELEMENT_TYPE_PATH) + continue; + + if (nextMapElement->type & 1) + continue; + + if (footpath_element_is_sloped(nextMapElement)){ + uint8 slopeDirection = footpath_element_get_slope_direction(nextMapElement); + if (slopeDirection == entranceDirection){ + if (z != nextMapElement->base_height){ + continue; + } + found = 1; + break; + } + + if ((slopeDirection ^ (1 << 1)) != entranceDirection) + continue; + + if (z - 2 != nextMapElement->base_height) + continue; + found = 1; + break; + } + else{ + if (z != nextMapElement->base_height){ + continue; + } + found = 1; + break; + } + } while (!map_element_is_last_for_tile(nextMapElement++)); + + if (!found){ + peep->state = PEEP_STATE_LEAVING_PARK; + peep->var_37 = 1; + RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16)--; + peep_window_state_update(peep); + return peep_return_to_center_of_tile(peep); + } + + money16 entranceFee = RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, money16); + if (entranceFee != 0 && !(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)){ + if (peep->item_standard_flags & PEEP_ITEM_VOUCHER){ + if (peep->voucher_type == VOUCHER_TYPE_PARK_ENTRY_HALF_PRICE){ + entranceFee /= 2; + peep->item_standard_flags &= ~PEEP_ITEM_VOUCHER; + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_INVENTORY; + } + else if (peep->voucher_type == VOUCHER_TYPE_PARK_ENTRY_FREE){ + entranceFee = 0; + peep->item_standard_flags &= ~PEEP_ITEM_VOUCHER; + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_INVENTORY; + } + } + if (entranceFee > peep->cash_in_pocket){ + peep->state = PEEP_STATE_LEAVING_PARK; + peep->var_37 = 1; + RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16)--; + peep_window_state_update(peep); + return peep_return_to_center_of_tile(peep); + } + + RCT2_GLOBAL(RCT2_ADDRESS_INCOME_FROM_ADMISSIONS, money32) += entranceFee; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_PARK_ENTRANCE_TICKETS * 4; + peep_spend_money(peep, &peep->paid_to_enter, entranceFee); + peep->flags |= PEEP_FLAGS_HAS_PAID_FOR_PARK_ENTRY; + } + + RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_ADMISSIONS, uint32)++; + window_invalidate_by_number(WC_PARK_INFORMATION, 0); + + peep->var_37 = 1; + peep->destination_x += TileDirectionDelta[peep->var_78].x; + peep->destination_y += TileDirectionDelta[peep->var_78].y; + peep->destination_tolerence = 7; + + invalidate_sprite_2((rct_sprite*)peep); + sprite_move(x, y, peep->z, (rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); + + return 1; + } +} + +/* rct2: 0x006946D8 */ +static int peep_footpath_move_forward(rct_peep* peep, sint16 x, sint16 y, rct_map_element* map_element, bool vandalism){ + peep->next_x = (x & 0xFFE0); + peep->next_y = (y & 0xFFE0); + peep->next_z = map_element->base_height; + peep->next_var_29 = map_element->properties.path.type & 7; + + sint16 z = peep_get_height_on_slope(peep, x, y); + + if (peep->type == PEEP_TYPE_STAFF){ + invalidate_sprite_2((rct_sprite*)peep); + sprite_move(x, y, z, (rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); + return 1; + } + + uint8 var_EF = (peep->var_EF * 2) & 0x3F; + peep->var_EF &= 0xC0; + peep->var_EF |= var_EF; + + if (vandalism == true){ + peep->var_EF |= 1; + if (peep->var_EF & 0x3E && + !(peep->var_EF & 0xC0)){ + + if ((scenario_rand() & 0xFFFF) <= 10922){ + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_VANDALISM, 0xFF); + peep->happiness_growth_rate = max(0, peep->happiness_growth_rate - 17); + } + peep->var_EF |= 0xC0; + } + } + + if (peep->var_EF & 0xC0 && + (scenario_rand()&0xFFFF) <= 4369){ + peep->var_EF -= 0x40; + } + + uint16 crowded = 0; + uint8 litter_count = 0; + uint8 sick_count = 0; + uint16 sprite_id = RCT2_ADDRESS(0xF1EF60, uint16)[((x & 0x1FE0) << 3) | (y >> 5)]; + for (rct_sprite* sprite; sprite_id != 0xFFFF; sprite_id = sprite->unknown.next_in_quadrant){ + sprite = &g_sprite_list[sprite_id]; + if (sprite->unknown.sprite_identifier == SPRITE_IDENTIFIER_PEEP){ + rct_peep* other_peep = (rct_peep*)sprite; + if (other_peep->state != PEEP_STATE_WALKING) + continue; + + if (abs(other_peep->z - peep->next_z * 8) > 16) + continue; + crowded++; + continue; + } + else if (sprite->unknown.sprite_identifier == SPRITE_IDENTIFIER_LITTER){ + rct_litter* litter = (rct_litter*)sprite; + if (abs(litter->z - peep->next_z * 8) > 16) + continue; + + litter_count++; + if (litter->type > 1) + continue; + + litter_count--; + sick_count++; + } + } + + if (crowded >= 10 && + peep->state == PEEP_STATE_WALKING && + (scenario_rand() & 0xFFFF) <= 21845){ + + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_CROWDED, 0xFF); + peep->happiness_growth_rate = max(0, peep->happiness_growth_rate - 14); + } + + litter_count = min(3, litter_count); + sick_count = min(3, sick_count); + + uint8 disgusting_time = peep->disgusting_count & 0xC0; + uint8 disgusting_count = ((peep->disgusting_count & 0xF) << 2) | sick_count; + peep->disgusting_count = disgusting_count | disgusting_time; + + if (disgusting_time & 0xC0 && + (scenario_rand() & 0xFFFF) <= 4369){ + // Reduce the disgusting time + peep->disgusting_count -= 0x40; + } + else{ + uint8 total_sick = 0; + for (uint8 time = 0; time < 3; time++){ + total_sick += (disgusting_count >> (2 * time)) & 0x3; + } + + if (total_sick >= 3 && + (scenario_rand() & 0xFFFF) <= 10922){ + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_PATH_DISGUSTING, 0xFF); + peep->happiness_growth_rate = max(0, peep->happiness_growth_rate - 17); + // Reset disgusting time + peep->disgusting_count |= 0xC0; + } + } + + uint8 litter_time = peep->litter_count & 0xC0; + litter_count = ((peep->litter_count & 0xF) << 2) | litter_count; + peep->litter_count = litter_count | litter_time; + + if (litter_time & 0xC0 && + (scenario_rand() & 0xFFFF) <= 4369){ + // Reduce the litter time + peep->litter_count -= 0x40; + } + else{ + uint8 total_litter = 0; + for (uint8 time = 0; time < 3; time++){ + total_litter += (litter_count >> (2 * time)) & 0x3; + } + + if (total_litter >= 3 && + (scenario_rand() & 0xFFFF) <= 10922){ + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_BAD_LITTER, 0xFF); + peep->happiness_growth_rate = max(0, peep->happiness_growth_rate - 17); + // Reset litter time + peep->litter_count |= 0xC0; + } + } + + invalidate_sprite_2((rct_sprite*)peep); + sprite_move(x, y, z, (rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); + return 1; +} + +/* rct2: 0x0069455E */ +static int peep_interact_with_path(rct_peep* peep, sint16 x, sint16 y, rct_map_element* map_element){ + + // 0x00F1AEE2 + bool vandalism_present = false; + if ((map_element->properties.path.additions & 0xF) != 0 && + (map_element->flags & MAP_ELEMENT_FLAG_BROKEN) && + (map_element->properties.path.edges & 0xF) != 0xF){ + vandalism_present = 1; + } + + sint16 z = map_element->base_height * 8; + if (!map_is_location_owned(x, y, z)){ + if (peep->outside_of_park == 0) + return peep_return_to_center_of_tile(peep); + } + else{ + if (peep->outside_of_park == 1) + return peep_return_to_center_of_tile(peep); + } + + if (peep->type == PEEP_TYPE_GUEST && + footpath_element_is_queue(map_element)){ + + uint8 rideIndex = map_element->properties.path.ride_index; + + if (rideIndex == 0xFF){ + peep->var_79 = 0xFF; + return peep_footpath_move_forward(peep, x, y, map_element, vandalism_present); + } + + if (peep->state == PEEP_STATE_QUEUING){ + if (peep->current_ride == rideIndex){ + return peep_footpath_move_forward(peep, x, y, map_element, vandalism_present); + } + remove_peep_from_queue(peep); + peep_decrement_num_riders(peep); + peep->state = PEEP_STATE_1; + peep_window_state_update(peep); + return peep_footpath_move_forward(peep, x, y, map_element, vandalism_present); + } + + if (peep->var_79 == rideIndex){ + return peep_footpath_move_forward(peep, x, y, map_element, vandalism_present); + } + + peep->var_F4 = 0; + uint8 stationNum = (map_element->properties.path.additions & 0x70) >> 4; + if (!peep_should_go_on_ride(peep, rideIndex, stationNum, PEEP_RIDE_DECISION_AT_QUEUE)){ + peep->var_79 = rideIndex; + return peep_return_to_center_of_tile(peep); + } + + peep->var_79 = rideIndex; + rct_ride* ride = GET_RIDE(rideIndex); + + uint16 old_last_peep = ride->last_peep_in_queue[stationNum]; + ride->last_peep_in_queue[stationNum] = peep->sprite_index; + peep->next_in_queue = old_last_peep; + ride->queue_length[stationNum]++; + + peep_decrement_num_riders(peep); + peep->current_ride = rideIndex; + peep->current_ride_station = stationNum; + peep->state = PEEP_STATE_QUEUING; + peep->days_in_queue = 0; + peep_window_state_update(peep); + + peep->sub_state = 10; + peep->destination_tolerence = 2; + peep->time_in_queue = 0; + if (peep->flags & PEEP_FLAGS_TRACKING){ + RCT2_GLOBAL(0x0013CE952, rct_string_id) = peep->name_string_idx; + RCT2_GLOBAL(0x0013CE954, uint32) = peep->id; + RCT2_GLOBAL(0x0013CE958, rct_string_id) = ride->name; + RCT2_GLOBAL(0x0013CE95A, uint32) = ride->name_arguments; + news_item_add_to_queue(NEWS_ITEM_PEEP_ON_RIDE, 1931, peep->sprite_index); + } + + return peep_footpath_move_forward(peep, x, y, map_element, vandalism_present); + } + else{ + peep->var_79 = 0xFF; + 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); + } + return peep_footpath_move_forward(peep, x, y, map_element, vandalism_present); + } +} + +/* rct2: 0x00693F70 */ +static int peep_interact_with_shop(rct_peep* peep, sint16 x, sint16 y, rct_map_element* map_element){ + uint8 rideIndex = map_element->properties.track.ride_index; + rct_ride* ride = GET_RIDE(rideIndex); + + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP)) + return 0; + + if (peep->type == PEEP_TYPE_STAFF) + return peep_return_to_center_of_tile(peep); + + peep->var_F4 = 0; + + if (ride->status != RIDE_STATUS_OPEN) + return peep_return_to_center_of_tile(peep); + + if (peep->var_79 == rideIndex) + return peep_return_to_center_of_tile(peep); + + if (peep->flags & PEEP_FLAGS_LEAVING_PARK) + return peep_return_to_center_of_tile(peep); + + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_PEEP_SHOULD_GO_INSIDE_FACILITY)){ + peep->var_F4 = 0; + if (!peep_should_go_on_ride(peep, rideIndex, 0, 0)) + return peep_return_to_center_of_tile(peep); + + money16 cost = ride->price; + if (cost != 0){ + ride->total_profit += cost; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_PARK_RIDE_TICKETS * 4; + peep_spend_money(peep, NULL, cost); + } + peep->destination_x = (x & 0xFFE0) + 16; + peep->destination_y = (y & 0xFFE0) + 16; + peep->destination_tolerence = 3; + + peep_decrement_num_riders(peep); + peep->current_ride = rideIndex; + peep->state = PEEP_STATE_ENTERING_RIDE; + peep->sub_state = 19; + peep_window_state_update(peep); + + peep->time_on_ride = 0; + ride->var_120++; + if (peep->flags & PEEP_FLAGS_TRACKING){ + RCT2_GLOBAL(0x0013CE952, rct_string_id) = peep->name_string_idx; + RCT2_GLOBAL(0x0013CE954, uint32) = peep->id; + RCT2_GLOBAL(0x0013CE958, rct_string_id) = ride->name; + RCT2_GLOBAL(0x0013CE95A, uint32) = ride->name_arguments; + rct_string_id string_id = ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IN_RIDE) ? 1933 : 1932; + news_item_add_to_queue(NEWS_ITEM_PEEP_ON_RIDE, string_id, peep->sprite_index); + } + return 1; + } + else{ + if (peep->guest_heading_to_ride_id == rideIndex) + peep->guest_heading_to_ride_id = 0xFF; + peep->action_sprite_image_offset = RCT2_GLOBAL(0x00F1AEF0, uint8); + peep_decrement_num_riders(peep); + peep->current_ride = rideIndex; + peep->state = PEEP_STATE_BUYING; + peep->sub_state = 0; + peep_window_state_update(peep); + return 1; + } +} + +/* rct2: 0x0069524E */ +static int peep_move_one_tile(uint8 direction, rct_peep* peep){ + assert(direction <= 7); + sint16 x = peep->next_x; + sint16 y = peep->next_y; + x += TileDirectionDelta[direction].x; + y += TileDirectionDelta[direction].y; + + if (x >= 8192 || y >= 8192){ + // This could loop! + return guest_surface_path_finding(peep); + } + + peep->var_78 = direction; + peep->destination_x = x + 16; + peep->destination_y = y + 16; + peep->destination_tolerence = 2; + if (peep->state == PEEP_STATE_QUEUING){ + peep->destination_tolerence = (scenario_rand() & 7) + 2; + } + return 0; +} + +/* rct2: 0x00694C41 */ +static int guest_surface_path_finding(rct_peep* peep){ + sint16 x = peep->next_x; + sint16 y = peep->next_y; + sint16 z = peep->next_z; + uint8 randDirection = scenario_rand() & 3; + + if (!fence_in_the_way(x, y, z, z + 4, randDirection)){ + x += TileDirectionDelta[randDirection].x; + y += TileDirectionDelta[randDirection].y; + randDirection ^= (1 << 1); + + if (!fence_in_the_way(x, y, z, z + 4, randDirection)){ + randDirection ^= (1 << 1); + if (!map_surface_is_blocked(x, y)){ + return peep_move_one_tile(randDirection, peep); + } + } + } + + randDirection++; + uint8 rand_backwards = scenario_rand() & 1; + if (rand_backwards){ + randDirection -= 2; + } + randDirection &= 3; + + if (!fence_in_the_way(x, y, z, z + 4, randDirection)){ + x += TileDirectionDelta[randDirection].x; + y += TileDirectionDelta[randDirection].y; + randDirection ^= (1 << 1); + + if (!fence_in_the_way(x, y, z, z + 4, randDirection)){ + randDirection ^= (1 << 1); + if (!map_surface_is_blocked(x, y)){ + return peep_move_one_tile(randDirection, peep); + } + } + } + + randDirection -= 2; + randDirection &= 3; + + if (!fence_in_the_way(x, y, z, z + 4, randDirection)){ + x += TileDirectionDelta[randDirection].x; + y += TileDirectionDelta[randDirection].y; + randDirection ^= (1 << 1); + + if (!fence_in_the_way(x, y, z, z + 4, randDirection)){ + randDirection ^= (1 << 1); + if (!map_surface_is_blocked(x, y)){ + return peep_move_one_tile(randDirection, peep); + } + } + } + + randDirection--; + if (rand_backwards){ + randDirection += 2; + } + return peep_move_one_tile(randDirection, peep); +} + +rct_map_element* get_banner_on_path(rct_map_element *path_element) +{ + // This is an improved version of original. + // That only checked for one fence in the way. + if (map_element_is_last_for_tile(path_element)) + return NULL; + + rct_map_element *bannerElement = path_element + 1; + do { + // Path on top, so no banners + if (map_element_get_type(bannerElement) == MAP_ELEMENT_TYPE_PATH) + return NULL; + // Found a banner + if (map_element_get_type(bannerElement) == MAP_ELEMENT_TYPE_BANNER) + return bannerElement; + // Last element so there cant be any other banners + if (map_element_is_last_for_tile(bannerElement)) + return NULL; + + } while (bannerElement++); + + return NULL; +} + +static int banner_clear_path_edges(rct_map_element *mapElement, int edges) +{ + rct_map_element *bannerElement = get_banner_on_path(mapElement); + if (bannerElement != NULL) { + do { + edges &= bannerElement->properties.banner.flags; + } while ((bannerElement = get_banner_on_path(bannerElement)) != NULL); + } + return edges; +} + +/** + * Gets the connected edges of a path that are permitted (i.e. no 'no entry' signs) + */ +static int path_get_permitted_edges(rct_map_element *mapElement) +{ + return banner_clear_path_edges(mapElement, mapElement->properties.path.edges) & 0x0F; +} + +static bool is_valid_path_z_and_direction(rct_map_element *mapElement, int currentZ, int currentDirection) +{ + if (footpath_element_is_sloped(mapElement)) { + int slopeDirection = footpath_element_get_slope_direction(mapElement); + if (slopeDirection == currentDirection) { + if (currentZ != mapElement->base_height) return false; + } else { + slopeDirection ^= 2; + if (slopeDirection != currentDirection) return false; + if (currentZ != mapElement->base_height + 2) return false; + } + } else { + if (currentZ != mapElement->base_height) return false; + } + return true; +} + +/** + * + * rct2: 0x00694BAE + */ +static uint8 sub_694BAE(sint16 x, sint16 y, sint16 z, rct_map_element *mapElement, uint8 chosenDirection) +{ + rct_map_element *nextMapElement; + + if (footpath_element_is_sloped(mapElement)) { + if (footpath_element_get_slope_direction(mapElement) == chosenDirection) { + z += 2; + } + } + + x += TileDirectionDelta[chosenDirection].x; + y += TileDirectionDelta[chosenDirection].y; + nextMapElement = map_get_first_element_at(x / 32, y / 32); + do { + if (map_element_get_type(nextMapElement) != MAP_ELEMENT_TYPE_PATH) continue; + if (!is_valid_path_z_and_direction(nextMapElement, z, chosenDirection)) continue; + + if (nextMapElement->type & 2) return 6; + + return 0; + } while (!map_element_is_last_for_tile(nextMapElement++)); + + return 0; +} + +/** + * + * rct2: 0x006949B9 + */ +static uint8 loc_6949B9( + sint16 x, sint16 y, sint16 z, rct_map_element *inputMapElement, uint8 chosenDirection, uint8 *outRideIndex, + int level +) { + rct_map_element *mapElement; + int direction; + + if (level > 25) return PATH_SEARCH_LIMIT_REACHED; + + x += TileDirectionDelta[chosenDirection].x; + y += TileDirectionDelta[chosenDirection].y; + mapElement = map_get_first_element_at(x / 32, y / 32); + do { + if (mapElement->flags & MAP_ELEMENT_FLAG_GHOST) continue; + + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_TRACK: + if (z != mapElement->base_height) continue; + int rideIndex = inputMapElement->properties.path.ride_index; + rct_ride *ride = GET_RIDE(rideIndex); + if (RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x20000) { + *outRideIndex = rideIndex; + return PATH_SEARCH_RIDE_ENTRANCE; + } + break; + case MAP_ELEMENT_TYPE_ENTRANCE: + if (z != mapElement->base_height) continue; + switch (mapElement->properties.entrance.type) { + case ENTRANCE_TYPE_RIDE_ENTRANCE: + direction = mapElement->type & MAP_ELEMENT_DIRECTION_MASK; + if (direction == chosenDirection) { + *outRideIndex = mapElement->properties.entrance.ride_index; + return PATH_SEARCH_RIDE_ENTRANCE; + } + break; + case ENTRANCE_TYPE_RIDE_EXIT: + direction = mapElement->type & MAP_ELEMENT_DIRECTION_MASK; + if (direction == chosenDirection) { + *outRideIndex = mapElement->properties.entrance.ride_index; + return PATH_SEARCH_RIDE_EXIT; + } + break; + case ENTRANCE_TYPE_PARK_ENTRANCE: + return PATH_SEARCH_PARK_EXIT; + } + break; + case MAP_ELEMENT_TYPE_PATH: + if (!is_valid_path_z_and_direction(mapElement, z, chosenDirection)) continue; + if (footpath_element_is_wide(mapElement)) return PATH_SEARCH_WIDE; + + uint8 edges = path_get_permitted_edges(mapElement); + edges &= ~(1 << (chosenDirection ^ 2)); + z = mapElement->base_height; + + for (direction = 0; direction < 4; direction++) { + if (!(edges & (1 << direction))) continue; + + edges &= ~(1 << direction); + if (edges != 0) return PATH_SEARCH_3; + + if (footpath_element_is_sloped(mapElement)) { + if (footpath_element_get_slope_direction(mapElement) == direction) { + z += 2; + } + } + return loc_6949B9(x, y, z, mapElement, direction, outRideIndex, level + 1); + } + } + } while (!map_element_is_last_for_tile(mapElement++)); + + return PATH_SEARCH_DEAD_END; +} + +/** + * Returns: + * 0 - dead end? + * 1 - ride exit + * 2 - ride entrance + * 4 - park entrance / exit + * 5 - search limit reached + * 6 - wide path + * rct2: 0x006949A4 + */ +static uint8 sub_6949A4(sint16 x, sint16 y, sint16 z, rct_map_element *inputMapElement, uint8 chosenDirection, uint8 *outRideIndex) +{ + if (footpath_element_is_sloped(inputMapElement)) { + if (footpath_element_get_slope_direction(inputMapElement) == chosenDirection) { + z += 2; + } + } + + return loc_6949B9(x, y, z, inputMapElement, chosenDirection, outRideIndex, 0); +} + +/* rct2: 0x00695225 */ +static int guest_path_find_aimless(rct_peep* peep, uint8 edges){ + if (scenario_rand() & 1){ + // If possible go straight + if (edges & (1 << peep->var_78)){ + return peep_move_one_tile(peep->var_78, peep); + } + } + + while (1){ + uint8 direction = scenario_rand() & 3; + if (edges & (1 << direction)){ + return peep_move_one_tile(direction, peep); + } + } +} + +/* rct2: 0x0069A60A */ +uint8 sub_69A60A(rct_peep* peep){ + RCT2_GLOBAL(0x00F1AED8, uint32) = 0xC350; + RCT2_GLOBAL(0x00F1AEDD, uint8) = 0x80; + + if (peep->type == PEEP_TYPE_STAFF) + return 16; + + RCT2_GLOBAL(0x00F1AED8, uint32) = 0x3A98; + RCT2_GLOBAL(0x00F1AEDD, uint8) = 0; + if ((peep->flags & PEEP_FLAGS_2)){ + if ((scenario_rand() & 0xFFFF) <= 7281) + peep->flags &= ~PEEP_FLAGS_2; + + return 16; + } + + if (peep->flags & PEEP_FLAGS_LEAVING_PARK && + peep->peep_is_lost_countdown < 90){ + return 16; + } + + if (peep->item_standard_flags & PEEP_ITEM_MAP) + return 14; + + if (peep->flags & PEEP_FLAGS_LEAVING_PARK) + return 14; + + return 10; +} + +/* rct2: 0x0069A5F0 */ +static int sub_69A5F0(sint16 x, sint16 y, sint16 z, rct_peep *peep, rct_map_element *map_element){ + //RCT2_GLOBAL(0x00F1AEDC, uint8) = sub_69A60A(peep); + + //// Redundant check to make sure peep is not null?? + //sint16 start_x = RCT2_GLOBAL(0x00F1AECE, sint16); + //sint16 start_y = RCT2_GLOBAL(0x00F1AED0, sint16); + //uint8 start_z = RCT2_GLOBAL(0x00F1AED2, uint8); + // + //uint8 edges = 0xF; + //if (peep->var_CC.x == (start_x / 32) && + // peep->var_CC.y == (start_y / 32) && + // peep->var_CC.z == start_z){ + + // uint8 index = 0; + // for (; index < 4; ++index){ + // if (peep->var_D0[index].x == x && + // peep->var_D0[index].y == y && + // peep->var_D0[index].z == z){ + // edges = peep->var_D0[index].direction & 0xF; + // break; + // } + // } + //} + + //bool found = false; + //rct_map_element *destMapElement = map_get_first_element_at(x / 32, y / 32); + //do{ + // if (destMapElement->base_height != z) + // continue; + + // if (map_element_get_type(destMapElement) != MAP_ELEMENT_TYPE_PATH) + // continue; + + // found = true; + // break; + //} while (!map_element_is_last_for_tile(destMapElement++)); + + //sint8 chosenDirection = 0xF; + //if (!found){ + // chosenDirection = 0xF; + // //goto 69A89C + //} + + //edges &= path_get_permitted_edges(destMapElement); + //if (edges == 0){ + // chosenDirection = 0xF; + // // goto 69A89C + //} + + //chosenDirection = bitscanforward(edges); + //if (edges & ~(1 << chosenDirection) == 0){ + // // goto 69A8A1 chosenDirection + //} + + //for (; chosenDirection != -1; chosenDirection = bitscanforward(edges)){ + // edges &= ~(1 << chosenDirection); + // //69a814 + //} + ////69a895 + int eax = x, ebx, ecx = y, edx = z, esi = (int)peep, ebp, edi = (int)map_element; + RCT2_CALLFUNC_X(0x0069A5F0, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return ebp; +} + +/* rct2: 0x006952C0 */ +static int guest_path_find_entering_park(rct_peep *peep, rct_map_element *map_element, uint8 edges){ + uint8 chosenEntrance = 0xFF; + uint16 nearestDist = 0xFFFF; + for (uint8 entranceNum = 0; entranceNum < 4; ++entranceNum){ + if (RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[entranceNum] == (sint16)0x8000) + continue; + + uint16 dist = abs(RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[entranceNum] - peep->next_x) + + abs(RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, sint16)[entranceNum] - peep->next_y); + + if (dist >= nearestDist) + continue; + + nearestDist = dist; + chosenEntrance = entranceNum; + } + + if (chosenEntrance == 0xFF) + return guest_path_find_aimless(peep, edges); + + sint16 x = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[chosenEntrance]; + sint16 y = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, sint16)[chosenEntrance]; + sint16 z = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Z, sint16)[chosenEntrance]; + RCT2_GLOBAL(0x00F1AECE, sint16) = x; + RCT2_GLOBAL(0x00F1AED0, sint16) = y; + RCT2_GLOBAL(0x00F1AED2, uint8) = z / 8; + + RCT2_GLOBAL(0x00F1AEE0, uint8) = 1; + RCT2_GLOBAL(0x00F1AEE1, uint8) = 0xFF; + + int chosenDirection = sub_69A5F0(peep->next_x, peep->next_y, peep->next_z, peep, map_element); + + if (chosenDirection == -1) + return guest_path_find_aimless(peep, edges); + else + return peep_move_one_tile(chosenDirection, peep); +} + +/* rct2: 0x0069536C */ +static int guest_path_find_leaving_park(rct_peep *peep, rct_map_element *map_element, uint8 edges){ + rct2_peep_spawn* peepSpawn = &gPeepSpawns[0]; + // Peeps for whatever reason return to their original spawn point + // this in future should look for the nearest. + if (peep->sprite_index & 1 && gPeepSpawns[1].x != 0xFFFF){ + peepSpawn++; + } + + sint16 x = peepSpawn->x & 0xFFE0; + sint16 y = peepSpawn->y & 0xFFE0; + uint8 z = peepSpawn->z * 2; + uint8 direction = peepSpawn->direction; + + RCT2_GLOBAL(0x00F1AECE, sint16) = x; + RCT2_GLOBAL(0x00F1AED0, sint16) = y; + RCT2_GLOBAL(0x00F1AED2, uint8) = z; + + if (x == peep->next_x && y == peep->next_y){ + return peep_move_one_tile(direction, peep); + } + + RCT2_GLOBAL(0x00F1AEE0, uint8) = 1; + RCT2_GLOBAL(0x00F1AEE1, uint8) = 0xFF; + direction = sub_69A5F0(peep->next_x, peep->next_y, peep->next_z, peep, map_element); + if (direction == 0xFF) + return guest_path_find_aimless(peep, edges); + else + return peep_move_one_tile(direction, peep); +} + +/* rct2: 0x00695161 */ +static int guest_path_find_park_entrance(rct_peep* peep, rct_map_element *map_element, uint8 edges){ + uint8 entranceNum; + + if (!(peep->flags & PEEP_FLAGS_PARK_ENTRANCE_CHOSEN)){ + uint8 chosenEntrance = 0xFF; + uint16 nearestDist = 0xFFFF; + for (entranceNum = 0; entranceNum < 4; ++entranceNum){ + if (RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[entranceNum] == (sint16)0x8000) + continue; + + uint16 dist = abs(RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[entranceNum] - peep->next_x) + + abs(RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, sint16)[entranceNum] - peep->next_y); + + if (dist >= nearestDist) + continue; + + nearestDist = dist; + chosenEntrance = entranceNum; + } + + if (chosenEntrance == 0xFF) + return guest_path_find_aimless(peep, edges); + + peep->current_ride = chosenEntrance; + peep->flags |= PEEP_FLAGS_PARK_ENTRANCE_CHOSEN; + } + + entranceNum = peep->current_ride; + sint16 x = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[entranceNum]; + sint16 y = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, sint16)[entranceNum]; + sint16 z = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Z, sint16)[entranceNum]; + RCT2_GLOBAL(0x00F1AECE, sint16) = x; + RCT2_GLOBAL(0x00F1AED0, sint16) = y; + RCT2_GLOBAL(0x00F1AED2, uint8) = z / 8; + + RCT2_GLOBAL(0x00F1AEE0, uint8) = 1; + RCT2_GLOBAL(0x00F1AEE1, uint8) = 0xFF; + + int chosenDirection = sub_69A5F0(peep->next_x, peep->next_y, peep->next_z, peep, map_element); + + if (chosenDirection == -1) + return guest_path_find_aimless(peep, edges); + else + return peep_move_one_tile(chosenDirection, peep); +} + +/* rct2: 0x006A72C5 */ +static void get_ride_queue_end(sint16 *x, sint16 *y, sint16 *z, sint16 dist){ + rct_map_element *mapElement = map_get_first_element_at(*x / 32, *y / 32); + + bool found = false; + do{ + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_ENTRANCE) + continue; + + if (*z != mapElement->base_height) + continue; + + found = true; + break; + } while (!map_element_is_last_for_tile(mapElement++)); + + if (!found) + return; + + uint8 direction = (mapElement->type & 3) ^ (1 << 1); + RCT2_GLOBAL(0x00F3EFE0, rct_map_element*) = NULL; + RCT2_GLOBAL(0x00F3EFE8, rct_map_element*) = NULL; + + sint16 baseZ = mapElement->base_height; + sint16 nextX = *x; + sint16 nextY = *y; + while (1){ + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH){ + RCT2_GLOBAL(0x00F3EFE0, rct_map_element*) = mapElement; + RCT2_GLOBAL(0x00F3EFE4, sint16) = nextX; + RCT2_GLOBAL(0x00F3EFE6, sint16) = nextY; + RCT2_GLOBAL(0x00F3EFEC, uint32) = direction; + if (footpath_element_is_sloped(mapElement)){ + if (footpath_element_get_slope_direction(mapElement) == direction){ + baseZ += 2; + } + } + } + nextX += TileDirectionDelta[direction].x; + nextY += TileDirectionDelta[direction].y; + + mapElement = map_get_first_element_at(nextX / 32, nextY / 32); + found = false; + do{ + if (mapElement == RCT2_GLOBAL(0x00F3EFE8, rct_map_element*)) + continue; + + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH) + continue; + + if (baseZ == mapElement->base_height){ + if (footpath_element_is_sloped(mapElement)){ + if (footpath_element_get_slope_direction(mapElement) != direction){ + break; + } + } + found = true; + break; + } + + if (baseZ - 2 == mapElement->base_height){ + if (!footpath_element_is_sloped(mapElement)) + break; + + if (footpath_element_get_slope_direction(mapElement) != direction) + break; + + baseZ -= 2; + found = true; + break; + } + } while (!map_element_is_last_for_tile(mapElement++)); + + if (found == false) + break; + + if (!footpath_element_is_queue(mapElement)) + break; + + if (!(mapElement->properties.path.edges & (1 << (direction ^ (1 << 1))))) + break; + + if (RCT2_GLOBAL(0x00F3EFE8, rct_map_element*) == NULL) + RCT2_GLOBAL(0x00F3EFE8, rct_map_element*) = mapElement; + + // More queue to go. + if (mapElement->properties.path.edges & (1 << (direction))) + continue; + + direction++; + direction &= 3; + // More queue to go. + if (mapElement->properties.path.edges & (1 << (direction))) + continue; + + direction ^= (1 << 1); + // More queue to go. + if (mapElement->properties.path.edges & (1 << (direction))) + continue; + + break; + } + + if ((uint8)*z == 0xFF) + return; + + mapElement = RCT2_GLOBAL(0x00F3EFE0, rct_map_element*); + if (mapElement == NULL) + return; + + if (!footpath_element_is_queue(mapElement)) + return; + + *x = RCT2_GLOBAL(0x00F3EFE4, sint16); + *y = RCT2_GLOBAL(0x00F3EFE6, sint16); + *z = mapElement->base_height; +} + +/* rct2: 0x00694C35 */ +static int guest_path_finding(rct_peep* peep) +{ + sint16 x, y, z; + + if (peep->next_var_29 & 0x18) { + return guest_surface_path_finding(peep); + } + + x = peep->next_x; + y = peep->next_y; + z = peep->next_z; + + rct_map_element *mapElement = map_get_path_element_at(x / 32, y / 32, z); + if (mapElement == NULL) { + return 1; + } + + uint8 edges = path_get_permitted_edges(mapElement); + if (peep->outside_of_park == 0 && peep_heading_for_ride_or_park_exit(peep)) { + uint8 adjustedEdges = edges; + for (int chosenDirection = 0; chosenDirection < 4; chosenDirection++) { + // If there is no path in that direction try another + if (!(adjustedEdges & (1 << chosenDirection))) + continue; + + if (sub_694BAE(peep->next_x, peep->next_y, peep->next_z, mapElement, chosenDirection) == 6) { + adjustedEdges &= ~(1 << chosenDirection); + } + } + if (adjustedEdges != 0) + edges = adjustedEdges; + } + + if (edges == 0) { + return guest_surface_path_finding(peep); + } + + sint8 direction = peep->var_78 ^ (1 << 1); + if (!(edges & ~(1 << direction))) { + peep_check_if_lost(peep); + peep_check_cant_find_ride(peep); + peep_check_cant_find_exit(peep); + } else { + edges &= ~(1 << direction); + } + + direction = bitscanforward(edges); + // IF only one edge to choose from + if ((edges & ~(1 << direction)) == 0) { + return peep_move_one_tile(direction, peep); + } + + // loc_694F19: + if (peep->outside_of_park != 0){ + switch (peep->state) { + case PEEP_STATE_ENTERING_PARK: + return guest_path_find_entering_park(peep, mapElement, edges); + case PEEP_STATE_LEAVING_PARK: + return guest_path_find_leaving_park(peep, mapElement, edges); + default: + return guest_path_find_aimless(peep, edges); + } + } + + + if (!peep_has_food(peep) && (scenario_rand() & 0xFFFF) >= 2184) { + uint8 adjustedEdges = edges; + for (int chosenDirection = 0; chosenDirection < 4; chosenDirection++) { + // If there is no path in that direction try another + if (!(adjustedEdges & (1 << chosenDirection))) + continue; + + uint8 rideIndex, pathSearchResult; + pathSearchResult = sub_6949A4(peep->next_x, peep->next_y, peep->next_z, mapElement, chosenDirection, &rideIndex); + switch (pathSearchResult) { + case PATH_SEARCH_DEAD_END: + case PATH_SEARCH_RIDE_EXIT: + case PATH_SEARCH_WIDE: + adjustedEdges &= ~(1 << chosenDirection); + break; + } + } + if (adjustedEdges != 0) + edges = adjustedEdges; + } + + if (peep->item_standard_flags & PEEP_ITEM_MAP) { + // If at least 2 directions consult map + if (bitcount(edges) >= 2) { + uint16 probability = 1638; + if (peep_heading_for_ride_or_park_exit(peep)) { + probability = 9362; + } + if ((scenario_rand() & 0xFFFF) < probability) { + peep_read_map(peep); + } + } + } + + if (peep->flags & PEEP_FLAGS_LEAVING_PARK) + return guest_path_find_park_entrance(peep, mapElement, edges); + + if (peep->guest_heading_to_ride_id == 0xFF) + return guest_path_find_aimless(peep, edges); + + uint8 rideIndex = peep->guest_heading_to_ride_id; + rct_ride* ride = GET_RIDE(rideIndex); + + if (ride->status != RIDE_STATUS_OPEN) + return guest_path_find_aimless(peep, edges); + + RCT2_GLOBAL(0x00F1AEE1, uint8) = rideIndex; + + RCT2_GLOBAL(0x00F1AEBC, uint32) = 4; + + uint16 closestDist = 0xFFFF; + uint8 closestStationNum = 4; + + for (uint8 stationNum = 0; stationNum < 4; ++stationNum){ + if (ride->entrances[stationNum] == 0xFFFF) + continue; + + sint16 stationX = (ride->entrances[stationNum] & 0xFF) * 32; + sint16 stationY = (ride->entrances[stationNum] & 0xFF00) / 8; + uint16 dist = abs(stationX - peep->next_x) + abs(stationY - peep->next_y); + + if (dist < closestDist){ + closestDist = dist; + RCT2_GLOBAL(0x00F1AEBC, uint32) = closestStationNum; + closestStationNum = stationNum; + continue; + } + + if (RCT2_GLOBAL(0x00F1AEBC, uint32) == 4){ + RCT2_GLOBAL(0x00F1AEBC, uint32) = stationNum; + } + } + + if (closestStationNum == 4) + closestStationNum = 0; + + if (RCT2_GLOBAL(0x00F1AEBC, uint32) != 4) { + if ( + (ride->depart_flags & RIDE_DEPART_SYNCHRONISE_WITH_ADJACENT_STATIONS) && + ride->num_stations == 2 && + ride->entrances[0] != 0xFFFF && + ride->entrances[1] != 0xFFFF + ) { + closestStationNum = 0; + if (peep->no_of_rides & 1) + closestStationNum++; + } + } + + uint16 entranceXY = ride->entrances[closestStationNum]; + if (entranceXY == 0xFFFF){ + entranceXY = ride->entrances[closestStationNum + 1]; + if (entranceXY == 0xFFFF){ + entranceXY = ride->entrances[closestStationNum + 2]; + } + } + + if (closestDist == 0xFFFF){ + entranceXY = ride->station_starts[closestStationNum]; + } + + x = (entranceXY & 0xFF) * 32; + y = (entranceXY & 0xFF00) / 8; + z = ride->station_heights[closestStationNum]; + + get_ride_queue_end(&x, &y, &z, closestDist); + RCT2_GLOBAL(0x00F1AECE, sint16) = x; + RCT2_GLOBAL(0x00F1AED0, sint16) = y; + RCT2_GLOBAL(0x00F1AED2, uint8) = (uint8)z; + RCT2_GLOBAL(0x00F1AEE0, uint8) = 1; + + direction = sub_69A5F0(peep->next_x, peep->next_y, peep->next_z, peep, mapElement); + if (direction == -1){ + return guest_path_find_aimless(peep, edges); + } + return peep_move_one_tile(direction, peep); +} + +/** + * + * rct2: 0x00693C9E + */ +static int sub_693C9E(rct_peep *peep) +{ + RCT2_GLOBAL(0x00F1EE18, uint16) = 0; + RCT2_GLOBAL(0x00F1AEF1, uint8) = peep->action; + + if (peep->action == PEEP_ACTION_NONE_1) + peep->action = PEEP_ACTION_NONE_2; + + if (peep->state == PEEP_STATE_QUEUING){ + if (peep_update_queue_position(peep)) + return 1; + } + + sint16 x, y, xy_dist; + if (!peep_update_action(&x, &y, &xy_dist, peep)){ + RCT2_GLOBAL(0x00F1EE18, uint16) |= 1; + uint8 result = 0; + if (peep->type == PEEP_TYPE_GUEST){ + result = guest_path_finding(peep); + } + else{ + result = RCT2_CALLPROC_X(0x006BF926, x, 0, y, 0, (int)peep, 0, 0) & 0x100; + } + + if (result != 0) + return 1; + + if (!peep_update_action(&x, &y, &xy_dist, peep)) + return 1; + } + + if ((x & 0xFFE0) == peep->next_x && (y & 0xFFE0) == peep->next_y){ + sint16 z = peep_get_height_on_slope(peep, x, y); + invalidate_sprite_2((rct_sprite*)peep); + sprite_move(x, y, z, (rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); + return 1; + } + + if (x < 32 || y < 32 || x >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) || y >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16)){ + if (peep->outside_of_park == 1){ + RCT2_GLOBAL(0x00F1EE18, uint16) |= (1 << 1); + } + return peep_return_to_center_of_tile(peep); + } + + rct_map_element* mapElement = map_get_first_element_at(x / 32, y / 32); + sint16 base_z = max(0, (peep->z / 8) - 2); + sint16 top_z = (peep->z / 8) + 1; + + do{ + if (base_z > mapElement->base_height) + continue; + if (top_z < mapElement->base_height) + continue; + + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH){ + if ((mapElement->flags & MAP_ELEMENT_FLAG_GHOST)) + continue; + if (peep_interact_with_path(peep, x, y, mapElement)) + return 1; + } + else if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_TRACK){ + if (peep_interact_with_shop(peep, x, y, mapElement)) + return 1; + } + else if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_ENTRANCE){ + if (peep_interact_with_entrance(peep, x, y, mapElement)) + return 1; + } + } while (!map_element_is_last_for_tile(mapElement++)); + + if (peep->type == PEEP_TYPE_STAFF || (peep->next_var_29 & 0x18)){ + sint16 z = abs(map_element_height(x, y) - peep->z); + + if (z <= 3 || (peep->type == PEEP_TYPE_STAFF && z <= 32)){ + peep->var_79 = 0xFF; + 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); + } + + if (!map_is_location_in_park(x & 0xFFE0, y & 0xFFE0)){ + return peep_return_to_center_of_tile(peep); + } + + mapElement = map_get_surface_element_at(x / 32, y / 32); + if (mapElement == NULL) + return peep_return_to_center_of_tile(peep); + + sint16 water_height = mapElement->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK; + if (water_height) + return peep_return_to_center_of_tile(peep); + + peep->next_x = x & 0xFFE0; + peep->next_y = y & 0xFFE0; + peep->next_z = mapElement->base_height; + peep->next_var_29 = 8; + + sint16 z = peep_get_height_on_slope(peep, x, y); + invalidate_sprite_2((rct_sprite*)peep); + sprite_move(x, y, z, (rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); + return 1; + } + } + return peep_return_to_center_of_tile(peep); +} + +/** + * + * rct2: 0x0069926C + * Expend type was previously an offset saved in 0x00F1AEC0 + */ +static void peep_spend_money(rct_peep *peep, money16 *peep_expend_type, money32 amount) +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) + return; + + peep->cash_in_pocket = max(0, peep->cash_in_pocket - amount); + peep->cash_spent += amount; + if (peep_expend_type != NULL) { + *peep_expend_type += (money16)amount; + } + window_invalidate_by_number(WC_PEEP, peep->sprite_index); + + RCT2_GLOBAL(0x00141F568, uint8) = RCT2_GLOBAL(0x0013CA740, uint8); + finance_payment(-amount, RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) / 4); + + audio_play_sound_at_location(SOUND_PURCHASE, peep->x, peep->y, peep->z); +} + +static void peep_set_has_ridden(rct_peep *peep, int rideIndex) +{ + peep->rides_been_on[rideIndex / 8] |= 1 << (rideIndex % 8); + rct_ride *ride = GET_RIDE(rideIndex); + peep_set_has_ridden_ride_type(peep, ride->type); +} + +static bool peep_has_ridden(rct_peep *peep, int rideIndex) +{ + return peep->rides_been_on[rideIndex / 8] & (1 << (rideIndex % 8)); +} + +static void peep_set_has_ridden_ride_type(rct_peep *peep, int rideType) +{ + peep->ride_types_been_on[rideType / 8] |= 1 << (rideType % 8); +} + +static bool peep_has_ridden_ride_type(rct_peep *peep, int rideType) +{ + return peep->ride_types_been_on[rideType / 8] & (1 << (rideType % 8)); +} + +/** + * + * rct2: 0x0069545B + * Updates various peep stats upon entering a ride, as well as updating the + * ride's satisfaction value. + */ +static void peep_on_enter_ride(rct_peep *peep, int rideIndex) +{ + rct_ride *ride = GET_RIDE(rideIndex); + + // Calculate how satisfying the ride is for the peep. Can range from -140 to +140. + sint8 satisfaction = peep_calculate_ride_satisfaction(peep, ride); + + // Update the satisfaction stat of the ride. + uint8 rideSatisfaction = 0; + if (satisfaction >= 40) + rideSatisfaction = 3; + else if (satisfaction >= 20) + rideSatisfaction = 2; + else if (satisfaction >= 0) + rideSatisfaction = 1; + + ride_update_satisfaction(ride, rideSatisfaction); + + // Update various peep stats. + if (peep->no_of_rides < 255) + peep->no_of_rides++; + + peep_set_has_ridden(peep, peep->current_ride); + peep_update_favourite_ride(peep, ride); + peep->happiness_growth_rate = clamp(0, peep->happiness_growth_rate + satisfaction, 255); + peep_update_ride_nausea_growth(peep, ride); +} + +/* + * Check to see if the specified ride should become the peep's favourite. + * For this, a "ride rating" is calculated based on the excitement of the ride and the peep's current happiness. + * As this value cannot exceed 255, the happier the peep is, the more irrelevant the ride's excitement becomes. + * Due to the minimum happiness requirement, an excitement rating of more than 3.8 has no further effect. + * + * If the ride rating is higher than any ride the peep has already been on and the happiness criteria is met, + * the ride becomes the peep's favourite. (This doesn't happen right away, but will be updated once the peep + * exits the ride.) + */ +static void peep_update_favourite_ride(rct_peep *peep, rct_ride *ride) +{ + peep->flags &= ~PEEP_FLAGS_RIDE_SHOULD_BE_MARKED_AS_FAVOURITE; + uint8 peepRideRating = clamp(0, (ride->excitement / 4) + peep->happiness, 255); + if (peepRideRating >= peep->favourite_ride_rating) { + if (peep->happiness >= 160 && peep->happiness_growth_rate >= 160) { + peep->favourite_ride_rating = peepRideRating; + peep->flags |= PEEP_FLAGS_RIDE_SHOULD_BE_MARKED_AS_FAVOURITE; + } + } +} + +/** + * The satisfaction values calculated here are used to determine how happy the peep is with the ride, + * and also affects the satisfaction stat of the ride itself. The factors that affect satisfaction include: + * - The price of the ride compared to the ride's value + * - How closely the intensity and nausea of the ride matches the peep's preferences + * - How long the peep was waiting in the queue + * - If the peep has been on the ride before, or on another ride of the same type + */ +static sint8 peep_calculate_ride_satisfaction(rct_peep *peep, rct_ride *ride) +{ + sint8 satisfaction = 0; + + // Calculate satisfaction based on the price and value of the ride. + uint8 valueSatisfaction = 1; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) { + if (ride->value != 0xFFFF) { + if (ride->price <= (money16)ride->value) { + valueSatisfaction = 2; + } + // Even if the price is more than the value, the peep will still be partially satisfied if their + // happiness is high enough to offset the difference. (Scales from +0% at empty happiness to +99% at full) + else if (ride->price <= (money16)(ride->value + ride->value * (peep->happiness / 256.0))) { + valueSatisfaction = 1; + } + else { + valueSatisfaction = 0; + } + } + } + + switch (valueSatisfaction) { + case 2: + satisfaction += 40; + break; + case 1: + satisfaction += 15; + break; + case 0: + satisfaction -= 45; + break; + } + + // Calculate satisfaction based on the intensity and nausea of the ride. + // The best possible score from this section is achieved by having the intensity and nausea + // of the ride fall exactly within the peep's preferences, but lower scores can still be achieved + // if the peep's happiness is enough to offset it. + ride_rating minIntensity, maxIntensity; + ride_rating minNausea, maxNausea; + uint8 intensitySatisfaction = 3; + uint8 nauseaSatisfaction = 3; + + if (ride->excitement != (ride_rating)0xFFFF) { + maxIntensity = (peep->intensity >> 4) * 100; + minIntensity = (peep->intensity & 0xF) * 100; + if (ride->intensity > maxIntensity || ride->intensity < minIntensity) { + intensitySatisfaction--; + } + + minIntensity -= peep->happiness * 2; + maxIntensity += peep->happiness; + if (ride->intensity > maxIntensity || ride->intensity < minIntensity) { + intensitySatisfaction--; + } + + minIntensity -= peep->happiness * 2; + maxIntensity += peep->happiness; + if (ride->intensity > maxIntensity || ride->intensity < minIntensity) { + intensitySatisfaction--; + } + + // Although it's not shown in the interface, a peep with Average or High nausea tolerance + // has a minimum preferred nausea value. (For peeps with None or Low, this is set to zero.) + minNausea = NauseaMinimumThresholds[peep->nausea_tolerance & 3]; + maxNausea = NauseaMaximumThresholds[peep->nausea_tolerance & 3]; + if (ride->nausea > maxNausea || ride->nausea < minNausea) { + nauseaSatisfaction--; + } + + minNausea -= peep->happiness * 2; + maxNausea += peep->happiness; + if (ride->nausea > maxNausea || ride->nausea < minNausea) { + nauseaSatisfaction--; + } + + minNausea -= peep->happiness * 2; + maxNausea += peep->happiness; + if (ride->nausea > maxNausea || ride->nausea < minNausea) { + nauseaSatisfaction--; + } + } + + // The combination of the intensity and nausea satisfaction is then used to determine the raw satisfaction value. + uint8 highestSatisfaction = max(intensitySatisfaction, nauseaSatisfaction); + uint8 lowestSatisfaction = min(intensitySatisfaction, nauseaSatisfaction); + + if (highestSatisfaction == 3) { + switch (lowestSatisfaction) { + case 3: + satisfaction += 20; + case 2: + satisfaction += 15; + case 1: + satisfaction += 35; + break; + case 0: + satisfaction -= 35; + } + } + else if (highestSatisfaction == 2) { + switch (lowestSatisfaction) { + case 2: + satisfaction += 15; + case 1: + satisfaction += 20; + break; + case 0: + satisfaction -= 50; + } + } + else if (highestSatisfaction == 1 && lowestSatisfaction == 1) { + satisfaction += 10; + } + else { + satisfaction -= 60; + } + + // Calculate satisfaction based on how long the peep has been in the queue for. + // (For comparison: peeps start thinking "I've been queueing for a long time" at 3500 and + // start leaving the queue at 4300.) + if (peep->time_in_queue >= 4500) + satisfaction -= 35; + else if (peep->time_in_queue >= 2250) + satisfaction -= 10; + else if (peep->time_in_queue <= 750) + satisfaction += 10; + + // Peeps get a small boost in satisfaction if they've been on a ride of the same type before, + // and this boost is doubled if they've already been on this particular ride. + if (peep_has_ridden_ride_type(peep, ride->type)) + satisfaction += 10; + + if (peep_has_ridden(peep, peep->current_ride)) + satisfaction += 10; + + return satisfaction; +} + +/* + * Update the nausea growth of the peep based on a ride. This is calculated based on: + * - The nausea rating of the ride + * - Their new happiness growth rate (the higher, the less nauseous) + * - How hungry the peep is (+0% nausea at 50% hunger up to +100% nausea at 100% hunger) + * - The peep's nausea tolerance (Final modifier: none: 100%, low: 50%, average: 25%, high: 12.5%) + */ +static void peep_update_ride_nausea_growth(rct_peep *peep, rct_ride *ride) +{ + uint32 nauseaMultiplier = clamp(64, 256 - peep->happiness_growth_rate, 200); + uint32 nauseaGrowthRateChange = (ride->nausea * nauseaMultiplier) / 512; + nauseaGrowthRateChange *= max(128, peep->hunger) / 64; + nauseaGrowthRateChange >>= (peep->nausea_tolerance & 3); + peep->nausea_growth_rate = (uint8)clamp(0, peep->nausea_growth_rate + nauseaGrowthRateChange, 255); +} + +static bool peep_should_go_on_ride_again(rct_peep *peep, rct_ride *ride) +{ + if (!(RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32) & 0x100000)) return false; + if (ride->excitement == (ride_rating)0xFFFF) return false; + if (ride->intensity > RIDE_RATING(10,00) && !gConfigCheat.ignore_ride_intensity) return false; + if (peep->happiness < 180) return false; + if (peep->energy < 100) return false; + if (peep->nausea > 160) return false; + if (peep->hunger < 30) return false; + if (peep->thirst < 20) return false; + if (peep->balloon_colour > 170) return false; + + uint8 r = (scenario_rand() & 0xFF); + if (r <= 128) { + if (peep->no_of_rides > 7) return false; + if (r > 64) return false; + } + + return true; +} + +static bool peep_should_preferred_intensity_increase(rct_peep *peep) +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PREF_LESS_INTENSE_RIDES) return false; + if (peep->happiness < 200) return false; + + return (scenario_rand() & 0xFF) >= peep->intensity; +} + +static bool peep_really_liked_ride(rct_peep *peep, rct_ride *ride) +{ + return + peep->happiness >= 215 && + ((peep->nausea <= 120 && + ride->excitement != (ride_rating)0xFFFF && + ride->intensity <= RIDE_RATING(10,00))||gConfigCheat.ignore_ride_intensity); +} + +/** + * + * rct2: 0x0069576E + */ +static void peep_on_exit_ride(rct_peep *peep, int rideIndex) +{ + rct_ride *ride = GET_RIDE(rideIndex); + + if (peep->flags & PEEP_FLAGS_RIDE_SHOULD_BE_MARKED_AS_FAVOURITE) { + peep->flags &= ~PEEP_FLAGS_RIDE_SHOULD_BE_MARKED_AS_FAVOURITE; + peep->favourite_ride = rideIndex; + // TODO fix this flag name or add another one + peep->window_invalidate_flags |= PEEP_INVALIDATE_STAFF_STATS; + } + peep->happiness = peep->happiness_growth_rate; + peep->nausea = peep->nausea_growth_rate; + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_STATS; + + if (peep_should_go_on_ride_again(peep, ride)) { + peep->guest_heading_to_ride_id = rideIndex; + peep->peep_is_lost_countdown = 200; + sub_69A98C(peep); + + rct_window *w = window_find_by_number(WC_PEEP, peep->sprite_index); + if (w != NULL) { + window_event_invalidate_call(w); + widget_invalidate(w, 12); + } + } + + if (peep_should_preferred_intensity_increase(peep)) { + if (peep->intensity <= 255 - 16) { + peep->intensity += 16; + } + } + + if (peep->flags & PEEP_FLAGS_NICE_RIDE) { + peep_insert_new_thought(peep, PEEP_THOUGHT_NICE_RIDE, 255); + } + + if (peep_really_liked_ride(peep, ride)) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_WAS_GREAT, rideIndex); + + int laugh = scenario_rand() & 7; + if (laugh < 3) { + audio_play_sound_at_location(SOUND_LAUGH_1 + laugh, peep->x, peep->y, peep->z); + } + } + + ride->total_customers++; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_CUSTOMER; +} + +/** + * + * rct2: 0x00695444 + */ +static void peep_on_enter_or_exit_ride(rct_peep *peep, int rideIndex, int flags) +{ + if (flags & 1) { + peep_on_exit_ride(peep, rideIndex); + } else { + peep_on_enter_ride(peep, rideIndex); + } +} + +/** Main logic to decide whether a peep should buy an item in question + * + * Also handles the purchase as well, so once it returns, the peep will have the + * item and the money will have been deducted. + * + * eax: shopItem | (rideIndex << 8) + * ecx: price + * esi: *peep + * + * Returns 0 or 1 depending on if the peep decided to buy the item + * + * rct2: 0x0069AF1E + */ +static bool sub_69AF1E(rct_peep *peep, int rideIndex, int shopItem, money32 price) +{ + rct_ride* ride = GET_RIDE(rideIndex); + money32 value; + + bool has_voucher = false; + + if ((peep->item_standard_flags & PEEP_ITEM_VOUCHER) && + (peep->voucher_type == VOUCHER_TYPE_FOOD_OR_DRINK_FREE) && + (peep->voucher_arguments == shopItem)) { + has_voucher = true; + } + + if (peep_has_item(peep, shopItem)) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_ALREADY_GOT, shopItem); + return 0; + } + + if (shop_item_is_food_or_drink(shopItem)) { + int food = -1; + if ((food = peep_has_food_standard_flag(peep))) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_HAVENT_FINISHED, bitscanforward(food)); + return 0; + } else if ((food = peep_has_food_extra_flag(peep))) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_HAVENT_FINISHED, bitscanforward(food) + 32); + return 0; + } else if (peep->nausea >= 145) + return 0; + } + + if ((shopItem == SHOP_ITEM_BALLOON) || (shopItem == SHOP_ITEM_ICE_CREAM) + || (shopItem == SHOP_ITEM_COTTON_CANDY) || (shopItem == SHOP_ITEM_SUNGLASSES)) { + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RAIN_LEVEL, sint8) != 0) + return 0; + } + + if ((shopItem == SHOP_ITEM_SUNGLASSES) || (shopItem == SHOP_ITEM_ICE_CREAM)) { + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TEMPERATURE, sint8) < 12) + return 0; + } + + if (shop_item_is_food(shopItem) && (peep->hunger > 75)) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_NOT_HUNGRY, 0xFF); + return 0; + } + + if (shop_item_is_drink(shopItem) && (peep->thirst > 75)) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_NOT_THIRSTY, 0xFF); + return 0; + } + + if ((shopItem == SHOP_ITEM_UMBRELLA) && (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RAIN_LEVEL, sint8) != 0)) + goto loc_69B119; + + if ((shopItem != SHOP_ITEM_MAP) && shop_item_is_souvenir(shopItem) && !has_voucher) { + if (((scenario_rand() & 0x7F) + 0x73) > peep->happiness) + return 0; + else if (peep->no_of_rides < 3) + return 0; + } + +loc_69B119: + if (!has_voucher) { + if (price != 0) { + if (peep->cash_in_pocket == 0) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_SPENT_MONEY, 0xFF); + return 0; + } + if (price > peep->cash_in_pocket) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_CANT_AFFORD, shopItem); + return 0; + } + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TEMPERATURE, uint16) >= 21) + value = get_shop_hot_value(shopItem); + else if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TEMPERATURE, uint16) <= 11) + value = get_shop_cold_value(shopItem); + else + value = get_shop_base_value(shopItem); + + if (value < price) { + value -= price; + if (shopItem == SHOP_ITEM_UMBRELLA) { + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RAIN_LEVEL, sint8) != 0) + goto loc_69B221; + } + + value = -value; + if (peep->happiness >= 128) + value /= 2; + + if (peep->happiness >= 180) + value /= 2; + + if (value > ((money16)(scenario_rand() & 0x07))) { + // "I'm not paying that much for x" + uint8 thought_type = (shopItem >= 32 ? (PEEP_THOUGHT_TYPE_PHOTO2_MUCH + (shopItem - 32)) : (PEEP_THOUGHT_TYPE_BALLOON_MUCH + shopItem)); + peep_insert_new_thought(peep, thought_type, rideIndex); + return 0; + } + } + else { + value -= price; + value = max(8, value); + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) { + if (value >= (money32)(scenario_rand() & 0x07)) { + // "This x is a really good value" + uint8 thought_item = (shopItem >= 32 ? (PEEP_THOUGHT_TYPE_PHOTO2 + (shopItem - 32)) : (PEEP_THOUGHT_TYPE_BALLOON + shopItem)); + peep_insert_new_thought(peep, thought_item, rideIndex); + } + } + + int happinessGrowth = value * 4; + peep->happiness_growth_rate = min((peep->happiness_growth_rate + happinessGrowth), 255); + peep->happiness = min((peep->happiness + happinessGrowth), 255); + } + } + +loc_69B221: + if (!has_voucher) { + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TEMPERATURE, uint16) >= 21) + value = get_shop_hot_value(shopItem); + else if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TEMPERATURE, uint16) <= 11) + value = get_shop_cold_value(shopItem); + else + value = get_shop_base_value(shopItem); + + value -= price; + uint8 satisfaction = 0; + if (value > -8) { + satisfaction++; + if (value > -3) { + satisfaction++; + if (value > 3) + satisfaction++; + } + } + + ride_update_satisfaction(ride, satisfaction); + } + + // The peep has now decided to buy the item (or, specifically, has not been + // dissuaded so far). + if (shopItem >= 32) + peep->item_extra_flags |= (1 << (shopItem - 32)); + else + peep->item_standard_flags |= (1 << shopItem); + + if (shopItem == SHOP_ITEM_TSHIRT) + peep->tshirt_colour = ride->track_colour_main[0]; + + if (shopItem == SHOP_ITEM_HAT) + peep->hat_colour = ride->track_colour_main[0]; + + if (shopItem == SHOP_ITEM_BALLOON) + peep->balloon_colour = ride->track_colour_main[0]; + + if (shopItem == SHOP_ITEM_UMBRELLA) + peep->umbrella_colour = ride->track_colour_main[0]; + + if (shopItem == SHOP_ITEM_MAP) + sub_69A98C(peep); + + uint16 dl; + if (shopItem >= 32) + dl = RCT2_ADDRESS(0x982310, uint8)[shopItem - 32]; + else + dl = RCT2_ADDRESS(0x9822F4, uint8)[shopItem]; + + peep->var_42 = min((peep->var_42 + dl), 255); + + if (shopItem == SHOP_ITEM_PHOTO) + peep->photo1_ride_ref = rideIndex; + + if (shopItem == SHOP_ITEM_PHOTO2) + peep->photo2_ride_ref = rideIndex; + + if (shopItem == SHOP_ITEM_PHOTO3) + peep->photo3_ride_ref = rideIndex; + + if (shopItem == SHOP_ITEM_PHOTO4) + peep->photo4_ride_ref = rideIndex; + + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_INVENTORY; + peep_update_sprite_type(peep); + if (peep->flags & PEEP_FLAGS_TRACKING) { + RCT2_GLOBAL(0x13CE952,uint16) = peep->name_string_idx; + RCT2_GLOBAL((0x13CE952 + 2), uint32) = peep->id; + RCT2_GLOBAL((0x13CE956 + 2), uint16) = (shopItem >= 32 ? STR_SHOP_ITEM_INDEFINITE_PHOTO2 + (shopItem - 32) : STR_SHOP_ITEM_INDEFINITE_BALLOON + shopItem); + news_item_add_to_queue(2, STR_PEEP_TRACKING_NOTIFICATION_BOUGHT_X, peep->sprite_index); + } + + if (shop_item_is_food(shopItem)) + peep->no_of_food++; + + if (shop_item_is_drink(shopItem)) + peep->no_of_drinks++; + + if (shop_item_is_souvenir(shopItem)) + peep->no_of_souvenirs++; + + money16* expend_type = &peep->paid_on_souvenirs; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_SHOP_STOCK * 4; + + if (shop_item_is_food(shopItem)) { + expend_type = &peep->paid_on_food; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_FOODDRINK_STOCK * 4; + } + + if (shop_item_is_drink(shopItem)) { + expend_type = &peep->paid_on_drink; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_FOODDRINK_STOCK * 4; + } + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) + finance_payment(get_shop_item_cost(shopItem), (RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) / 4)); + + // Sets the expenditure type to *_FOODDRINK_SALES or *_SHOP_SALES appropriately. + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) -= 4; + if (!has_voucher) + peep_spend_money(peep, expend_type, price); + else { + peep->item_standard_flags &= ~PEEP_ITEM_VOUCHER; + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_INVENTORY; + } + + ride->total_profit += (price - get_shop_item_cost(shopItem)); + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME; + ride->var_120++; + ride->total_customers++; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_CUSTOMER; + + return 1; +} + +/** + * + * rct2: 0x0069AEB7 + */ +static bool peep_should_use_cash_machine(rct_peep *peep, int rideIndex) +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) return false; + if (peep->flags & PEEP_FLAGS_LEAVING_PARK) return false; + if (peep->cash_in_pocket > MONEY(20,00)) return false; + if (115 + (scenario_rand() % 128) > peep->happiness) return false; + if (peep->energy < 80) return false; + + rct_ride *ride = GET_RIDE(rideIndex); + ride_update_satisfaction(ride, peep->happiness >> 6); + ride->var_120++; + ride->total_customers++; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_CUSTOMER; + return true; +} + +/** + * + * rct2: 0x0069A98C + */ +static void sub_69A98C(rct_peep *peep) +{ + peep->var_CC.x = 0xFF; + peep->var_CC.y = 0xFF; + peep->var_CC.z = 0xFF; + peep->var_CC.direction = 0xFF; +} + +/** + * + * rct2: 0x0068FD3A + */ +static void sub_68FD3A(rct_peep *peep) +{ + RCT2_CALLPROC_X(0x0068FD3A, 0, 0, 0, 0, (int)peep, 0, 0); +} + +/** + * + * rct2: 0x00690B99 + */ +static bool sub_690B99(rct_peep *peep, int edge, uint8 *rideToView, uint8 *rideSeatToView) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = edge; + esi = (int)peep; + if (RCT2_CALLFUNC_X(0x00690B99, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp) & 0x100) + return false; + + *rideToView = ecx & 0xFF; + *rideSeatToView = (ecx >> 8) & 0xFF; + return true; +} + +/** + * + * rct2: 0x00694921 + * Gets the height including the bit depending + * on how far up the slope the peep is. + */ +static int peep_get_height_on_slope(rct_peep *peep, int x, int y) +{ + if (x == (sint16)0x8000) + return 0; + + if (peep->next_var_29 & 0x18){ + return map_element_height(x, y) & 0xFFFF; + } + + int z = peep->next_z * 8; + + return z + map_height_from_slope(x, y, peep->next_var_29); +} + +static bool peep_has_voucher_for_free_ride(rct_peep *peep, int rideIndex) +{ + return + peep->item_standard_flags & PEEP_ITEM_VOUCHER && + peep->voucher_type == VOUCHER_TYPE_RIDE_FREE && + peep->voucher_arguments == rideIndex; +} + +static void peep_reset_ride_heading(rct_peep *peep) +{ + rct_window *w; + + peep->guest_heading_to_ride_id = 255; + w = window_find_by_number(WC_PEEP, peep->sprite_index); + if (w != NULL) { + window_event_invalidate_call(w); + widget_invalidate(w, 12); + } +} + +/** + * + * rct2: 0x006960AB + * + * This function is called whenever a peep is deciding whether or not they want to go on a ride or visit a shop. + * They may be physically present at the ride/shop, or they may just be thinking about it. + */ +static bool peep_should_go_on_ride(rct_peep *peep, int rideIndex, int entranceNum, int flags) +{ + rct_ride *ride = GET_RIDE(rideIndex); + + // Indicates if the peep is about to enter a queue (as opposed to entering an entrance directly from a path) + bool peepAtQueue = flags & PEEP_RIDE_DECISION_AT_QUEUE; + + // Indicates whether a peep is physically at the ride, or is just thinking about going on the ride. + bool peepAtRide = !(flags & PEEP_RIDE_DECISION_THINKING); + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_8)) { + if (ride->status == RIDE_STATUS_OPEN && !(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) { + + // Peeps that are leaving the park will refuse to go on any rides, with the exception of free transport rides. + if (!(RideData4[ride->type].flags & RIDE_TYPE_FLAG4_TRANSPORT_RIDE) || ride->value == 0xFFFF || ride->price != 0) { + if (peep->flags & PEEP_FLAGS_LEAVING_PARK) { + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtRide, false); + return false; + } + } + + if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & RIDE_TYPE_FLAG_IS_SHOP) { + return peep_should_go_to_shop(peep, rideIndex, peepAtRide); + } + + // This used to check !(flags & 2), but the function is only ever called with flags = 0, 1 or 6. + // This means we can use the existing !(flags & 4) check. + if (peepAtRide) { + // Peeps won't join a queue that has 1000 peeps already in it. + if (ride->queue_length[entranceNum] >= 1000) { + peep_tried_to_enter_full_queue(peep, rideIndex); + return false; + } + + // Rides without queues can only have one peep waiting at a time. + if (!peepAtQueue) { + if (ride->last_peep_in_queue[entranceNum] != 0xFFFF) { + peep_tried_to_enter_full_queue(peep, rideIndex); + return false; + } + } + else { + // Check if there's room in the queue for the peep to enter. + if (ride->last_peep_in_queue[entranceNum] != 0xFFFF) { + rct_peep *lastPeepInQueue = GET_PEEP(ride->last_peep_in_queue[entranceNum]); + if (abs(lastPeepInQueue->z - peep->z) <= 6) { + int dx = abs(lastPeepInQueue->x - peep->x); + int dy = abs(lastPeepInQueue->y - peep->y); + int maxD = max(dx, dy); + + // Unlike normal paths, peeps cannot overlap when queueing for a ride. + // This check enforces a minimum distance between peeps entering the queue. + if (maxD < 8) { + peep_tried_to_enter_full_queue(peep, rideIndex); + return false; + } + + // This checks if there's a peep standing still at the very end of the queue. + if (maxD <= 13 + && lastPeepInQueue->time_in_queue > 10) { + peep_tried_to_enter_full_queue(peep, rideIndex); + return false; + } + } + } + } + } + + // Assuming the queue conditions are met, peeps will always go on free transport rides. + // Ride ratings, recent crashes and weather will all be ignored. + if (!(RideData4[ride->type].flags & RIDE_TYPE_FLAG4_TRANSPORT_RIDE) || ride->value == 0xFFFF || ride->price != 0) { + if (peep->previous_ride == rideIndex) { + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtRide, false); + return false; + } + + // Basic price checks + if (ride->price != 0 && !peep_has_voucher_for_free_ride(peep, rideIndex)) { + + if (ride->price > peep->cash_in_pocket) { + if (peepAtRide) { + if (peep->cash_in_pocket <= 0) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_SPENT_MONEY, 255); + } + else { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_CANT_AFFORD_0, rideIndex); + } + } + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtRide, true); + return false; + } + } + + // If happy enough, peeps will ignore the fact that a ride has recently crashed. + if (ride->last_crash_type != RIDE_CRASH_TYPE_NONE && peep->happiness < 225) { + if (peepAtRide) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_NOT_SAFE, rideIndex); + if (peep->happiness_growth_rate >= 64) { + peep->happiness_growth_rate -= 8; + } + ride_update_popularity(ride, 0); + } + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtRide, true); + return false; + } + + + if (ride->excitement != (ride_rating)0xFFFF) { + // If a peep has already decided that they're going to go on a ride, they'll skip the weather and + // excitment check and will only do a basic intensity check when they arrive at the ride itself. + if (rideIndex == peep->guest_heading_to_ride_id) { + if (ride->intensity > RIDE_RATING(10, 00) && !gConfigCheat.ignore_ride_intensity) { + peep_ride_is_too_intense(peep, rideIndex, peepAtRide); + return false; + } + } + + // Peeps won't go on rides that aren't sufficiently undercover while it's raining. + // The threshold is fairly low and only requires about 10-15% of the ride to be undercover. + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RAIN_LEVEL, uint8) != 0 && (ride->undercover_portion >> 5) < 3) { + if (peepAtRide) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_NOT_WHILE_RAINING, rideIndex); + if (peep->happiness_growth_rate >= 64) { + peep->happiness_growth_rate -= 8; + } + ride_update_popularity(ride, 0); + } + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtRide, true); + return false; + } + + if (!gConfigCheat.ignore_ride_intensity) { + // Intensity calculations. Even though the max intensity can go up to 15, it's capped + // at 10.0 (before happiness calculations). A full happiness bar will increase the max + // intensity and decrease the min intensity by about 2.5. + ride_rating maxIntensity = min((peep->intensity >> 4) * 100, 1000) + peep->happiness; + ride_rating minIntensity = ((peep->intensity & 0x0F) * 100) - peep->happiness; + if (ride->intensity < minIntensity) { + if (peepAtRide) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_MORE_THRILLING, rideIndex); + if (peep->happiness_growth_rate >= 64) { + peep->happiness_growth_rate -= 8; + } + ride_update_popularity(ride, 0); + } + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtRide, true); + return false; + } + if (ride->intensity > maxIntensity) { + peep_ride_is_too_intense(peep, rideIndex, peepAtRide); + return false; + } + + // Nausea calculations. + ride_rating maxNausea = NauseaMaximumThresholds[(peep->nausea_tolerance & 3)] + peep->happiness; + + if (ride->nausea > maxNausea) { + if (peepAtRide) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_SICKENING, rideIndex); + if (peep->happiness_growth_rate >= 64) { + peep->happiness_growth_rate -= 8; + } + ride_update_popularity(ride, 0); + } + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtRide, true); + return false; + } + + // Very nauseous peeps will only go on very gentle rides. + if (ride->nausea >= FIXED_2DP(1, 40) && peep->nausea > 160) { + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtRide, false); + return false; + } + } + } + + // If the ride has not yet been rated and is capable of having g-forces, + // there's a 90% chance that the peep will ignore it. + if ((ride->excitement == (ride_rating)0xFFFF) + && (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES)) { + if ((scenario_rand() & 0xFFFF) > 0x1999U) { + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtRide, false); + return false; + } + + if (!gConfigCheat.ignore_ride_intensity) { + if (ride->max_positive_vertical_g > FIXED_2DP(5, 00) + || ride->max_negative_vertical_g < FIXED_2DP(-4, 00) + || ride->max_lateral_g > FIXED_2DP(4, 00)) { + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtRide, false); + return false; + } + } + } + + uint32 value = ride->value; + + // If the value of the ride hasn't yet been calculated, peeps will be willing to pay any amount for the ride. + if (value != 0xFFFF && !peep_has_voucher_for_free_ride(peep, rideIndex)) { + + // The amount peeps are willing to pay is decreased by 75% if they had to pay to enter the park. + if (peep->flags & PEEP_FLAGS_HAS_PAID_FOR_PARK_ENTRY) + value /= 4; + + // Peeps won't pay more than twice the value of the ride. + if (ride->price > (money16)(value * 2)) { + if (peepAtRide) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_BAD_VALUE, rideIndex); + if (peep->happiness_growth_rate < 60) { + peep->happiness_growth_rate -= 16; + } + ride_update_popularity(ride, 0); + } + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtRide, true); + return false; + } + + // A ride is good value if the price is 50% or less of the ride value and the peep didn't pay to enter the park. + if (ride->price <= (money16)(value / 2) && peepAtRide) { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) { + if (!(peep->flags & PEEP_FLAGS_HAS_PAID_FOR_PARK_ENTRY)) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_GOOD_VALUE, rideIndex); + } + } + } + } + } + + // At this point, the peep has decided to go on the ride. + if (peepAtRide) { + ride_update_popularity(ride, 1); + if ((peep->flags & PEEP_FLAGS_INTAMIN) && ride_type_is_intamin(ride->type)) { + peep_insert_new_thought(peep, PEEP_THOUGHT_EXCITED, 255); + } + } + + if (rideIndex == peep->guest_heading_to_ride_id) { + peep_reset_ride_heading(peep); + } + + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_QUEUE_FULL; + return true; + } + } + + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtRide, false); + return false; +} + +static void peep_ride_is_too_intense(rct_peep *peep, int rideIndex, bool peepAtRide) +{ + rct_ride *ride = GET_RIDE(rideIndex); + + if (peepAtRide) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_INTENSE, rideIndex); + if (peep->happiness_growth_rate >= 64) { + peep->happiness_growth_rate -= 8; + } + ride_update_popularity(ride, 0); + } + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtRide, true); +} + +static void peep_chose_not_to_go_on_ride(rct_peep *peep, int rideIndex, bool peepAtRide, bool updateLastRide) +{ + if (peepAtRide && updateLastRide) { + peep->previous_ride = rideIndex; + peep->previous_ride_time_out = 0; + } + + if (rideIndex == peep->guest_heading_to_ride_id) { + peep_reset_ride_heading(peep); + } +} + +/* + * When the queue is full, peeps will ignore the ride when thinking about what to go on next. + * Does not effect peeps that walk up to the queue entrance. + * This flag is reset the next time a peep successfully joins the queue. + */ +static void peep_tried_to_enter_full_queue(rct_peep *peep, int rideIndex) +{ + rct_ride *ride = GET_RIDE(rideIndex); + + ride->lifecycle_flags |= RIDE_LIFECYCLE_QUEUE_FULL; + peep->previous_ride = rideIndex; + peep->previous_ride_time_out = 0; +} + +static bool peep_should_go_to_shop(rct_peep *peep, int rideIndex, bool peepAtShop) +{ + rct_ride *ride = GET_RIDE(rideIndex); + + // Peeps won't go to the same shop twice in a row. + if (rideIndex == peep->previous_ride) { + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtShop, true); + return false; + } + + if (ride->type == RIDE_TYPE_TOILETS) { + if (peep->bathroom < 70) { + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtShop, true); + return false; + } + + // The amount that peeps are willing to pay to use the Toilets scales with their bathroom stat. + // It effectively has a minimum of $0.10 (due to the check above) and a maximum of $0.60. + if (ride->price * 40 > peep->bathroom) { + if (peepAtShop) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_NOT_PAYING, rideIndex); + if (peep->happiness_growth_rate >= 60) { + peep->happiness_growth_rate -= 16; + } + ride_update_popularity(ride, 0); + } + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtShop, true); + return false; + } + } + + if (ride->type == RIDE_TYPE_FIRST_AID) { + if (peep->nausea < 128) { + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtShop, true); + return false; + } + } + + // Basic price checks + if (ride->price != 0 && ride->price > peep->cash_in_pocket) { + if (peepAtShop) { + if (peep->cash_in_pocket <= 0) { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_SPENT_MONEY, 255); + } + else { + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_CANT_AFFORD_0, rideIndex); + } + } + peep_chose_not_to_go_on_ride(peep, rideIndex, peepAtShop, true); + return false; + } + + if (peepAtShop) { + ride_update_popularity(ride, 1); + if (rideIndex == peep->guest_heading_to_ride_id) { + peep_reset_ride_heading(peep); + } + } + return true; +} + +/** + * + * rct2: 0x00695DD2 + */ +static void peep_pick_ride_to_go_on(rct_peep *peep) +{ + rct_ride *ride; + + if (peep->state != PEEP_STATE_WALKING) return; + if (peep->guest_heading_to_ride_id != 255) return; + if (peep->flags & PEEP_FLAGS_LEAVING_PARK) return; + if (peep_has_food(peep)) return; + if (peep->x == (sint16)0x8000) return; + + RCT2_GLOBAL(0x00F1AD98, uint32) = 0; + RCT2_GLOBAL(0x00F1AD9C, uint32) = 0; + RCT2_GLOBAL(0x00F1ADA0, uint32) = 0; + RCT2_GLOBAL(0x00F1ADA4, uint32) = 0; + RCT2_GLOBAL(0x00F1ADA8, uint32) = 0; + RCT2_GLOBAL(0x00F1ADAC, uint32) = 0; + RCT2_GLOBAL(0x00F1ADB0, uint32) = 0; + RCT2_GLOBAL(0x00F1ADB4, uint32) = 0; + + // FIX Originally checked for a toy, likely a mistake and should be a map, + // but then again this seems to only allow the peep to go on + // rides they haven't been on before. + if (peep->item_standard_flags & PEEP_ITEM_MAP) { + // Consider rides that peep hasn't been on yet + int i; + FOR_ALL_RIDES(i, ride) { + if (!peep_has_ridden(peep, i)) { + RCT2_ADDRESS(0x00F1AD98, uint32)[i >> 5] |= (1u << (i & 0x1F)); + } + } + } else { + // Take nearby rides into consideration + int cx = floor2(peep->x, 32); + int cy = floor2(peep->y, 32); + for (int x = cx - 320; x <= cx + 320; x += 32) { + for (int y = cy - 320; y <= cy + 320; y += 32) { + if (x >= 0 && y >= 0 && x < (256 * 32) && y < (256 * 32)) { + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) continue; + + int rideIndex = mapElement->properties.track.ride_index; + RCT2_ADDRESS(0x00F1AD98, uint32)[rideIndex >> 5] |= (1u << (rideIndex & 0x1F)); + } while (!map_element_is_last_for_tile(mapElement++)); + } + } + } + + // Always take the big rides into consideration (realistic as you can usually see them from anywhere in the park) + int i; + FOR_ALL_RIDES(i, ride) { + if (ride->lifecycle_flags == RIDE_LIFECYCLE_TESTED) continue; + if (ride->excitement == (ride_rating)0xFFFF) continue; + if (ride->highest_drop_height <= 66 && ride->excitement < RIDE_RATING(8,00)) continue; + + RCT2_ADDRESS(0x00F1AD98, uint32)[i >> 5] |= (1u << (i & 0x1F)); + } + } + + // Filter the considered rides + uint8 *potentialRides = (uint8*)0x00F1ADBC; + uint8 *nextPotentialRide = potentialRides; + int numPotentialRides = 0; + for (int i = 0; i < MAX_RIDES; i++) { + if (!(RCT2_ADDRESS(0x00F1AD98, uint32)[i >> 5] & (1u << (i & 0x1F)))) + continue; + + rct_ride *ride = GET_RIDE(i); + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_QUEUE_FULL)) { + if (peep_should_go_on_ride(peep, i, 0, PEEP_RIDE_DECISION_THINKING)) { + *nextPotentialRide++ = i; + numPotentialRides++; + } + } + } + + // Pick the most exciting ride + int mostExcitingRideIndex = -1; + ride_rating mostExcitingRideRating = 0; + for (int i = 0; i < numPotentialRides; i++) { + ride = GET_RIDE(potentialRides[i]); + if (ride->excitement == (ride_rating)0xFFFF) continue; + if (ride->excitement > mostExcitingRideRating) { + mostExcitingRideIndex = potentialRides[i]; + mostExcitingRideRating = ride->excitement; + } + } + if (mostExcitingRideIndex == -1) + return; + + // Head to that ride + peep->guest_heading_to_ride_id = mostExcitingRideIndex; + peep->peep_is_lost_countdown = 200; + sub_69A98C(peep); + + // Invalidate windows + rct_window *w = window_find_by_number(WC_PEEP, peep->sprite_index); + if (w != NULL) { + window_event_invalidate_call(w); + widget_invalidate(w, 12); + } + + // Make peep look at their map if they have one + if (peep->item_standard_flags & PEEP_ITEM_MAP) { + peep_read_map(peep); + } +} + +/** + * + * rct2: 0x00695B70 + */ +static void peep_head_for_nearest_ride_type(rct_peep *peep, int rideType) +{ + rct_ride *ride; + + if (peep->state != PEEP_STATE_SITTING && peep->state != PEEP_STATE_WATCHING && peep->state != PEEP_STATE_WALKING) { + return; + } + if (peep->flags & PEEP_FLAGS_LEAVING_PARK) return; + if (peep->x == (sint16)0x8000) return; + if (peep->guest_heading_to_ride_id != 255) { + ride = GET_RIDE(peep->guest_heading_to_ride_id); + if (ride->type == rideType) { + return; + } + } + + RCT2_GLOBAL(0x00F1AD98, uint32) = 0; + RCT2_GLOBAL(0x00F1AD9C, uint32) = 0; + RCT2_GLOBAL(0x00F1ADA0, uint32) = 0; + RCT2_GLOBAL(0x00F1ADA4, uint32) = 0; + RCT2_GLOBAL(0x00F1ADA8, uint32) = 0; + RCT2_GLOBAL(0x00F1ADAC, uint32) = 0; + RCT2_GLOBAL(0x00F1ADB0, uint32) = 0; + RCT2_GLOBAL(0x00F1ADB4, uint32) = 0; + + // FIX Originally checked for a toy,.likely a mistake and should be a map + if ((peep->item_standard_flags & PEEP_ITEM_MAP) && rideType != RIDE_TYPE_FIRST_AID) { + // Consider all rides in the park + int i; + FOR_ALL_RIDES(i, ride) { + if (ride->type == rideType) { + RCT2_ADDRESS(0x00F1AD98, uint32)[i >> 5] |= (1u << (i & 0x1F)); + } + } + } else { + // Take nearby rides into consideration + int cx = floor2(peep->x, 32); + int cy = floor2(peep->y, 32); + for (int x = cx - 320; x <= cx + 320; x += 32) { + for (int y = cy - 320; y <= cy + 320; y += 32) { + if (x >= 0 && y >= 0 && x < (256 * 32) && y < (256 * 32)) { + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) continue; + + int rideIndex = mapElement->properties.track.ride_index; + ride = GET_RIDE(rideIndex); + if (ride->type == rideType) { + RCT2_ADDRESS(0x00F1AD98, uint32)[rideIndex >> 5] |= (1u << (rideIndex & 0x1F)); + } + } while (!map_element_is_last_for_tile(mapElement++)); + } + } + } + } + + // Filter the considered rides + uint8 *potentialRides = (uint8*)0x00F1ADBC; + uint8 *nextPotentialRide = potentialRides; + int numPotentialRides = 0; + for (int i = 0; i < MAX_RIDES; i++) { + if (!(RCT2_ADDRESS(0x00F1AD98, uint32)[i >> 5] & (1u << (i & 0x1F)))) + continue; + + rct_ride *ride = GET_RIDE(i); + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_QUEUE_FULL)) { + if (peep_should_go_on_ride(peep, i, 0, PEEP_RIDE_DECISION_THINKING)) { + *nextPotentialRide++ = i; + numPotentialRides++; + } + } + } + + // Pick the closest ride + int closestRideIndex = -1; + int closestRideDistance = INT_MAX; + for (int i = 0; i < numPotentialRides; i++) { + ride = GET_RIDE(potentialRides[i]); + int rideX = (ride->station_starts[0] & 0xFF) * 32; + int rideY = (ride->station_starts[0] >> 8) * 32; + int distance = abs(rideX - peep->x) + abs(rideY - peep->y); + if (distance < closestRideDistance) { + closestRideIndex = potentialRides[i]; + closestRideDistance = distance; + } + } + if (closestRideIndex == -1) + return; + + // Head to that ride + peep->guest_heading_to_ride_id = closestRideIndex; + peep->peep_is_lost_countdown = 200; + sub_69A98C(peep); + + // Invalidate windows + rct_window *w = window_find_by_number(WC_PEEP, peep->sprite_index); + if (w != NULL) { + window_event_invalidate_call(w); + widget_invalidate(w, 12); + } + + peep->var_F4 = 0; +} + +/** + * + * rct2: 0x006958D0 + */ +static void peep_head_for_nearest_ride_with_flags(rct_peep *peep, int rideTypeFlags) +{ + rct_ride *ride; + + if (peep->state != PEEP_STATE_SITTING && peep->state != PEEP_STATE_WATCHING && peep->state != PEEP_STATE_WALKING) { + return; + } + if (peep->flags & PEEP_FLAGS_LEAVING_PARK) return; + if (peep->x == (sint16)0x8000) return; + if (peep->guest_heading_to_ride_id != 255) { + ride = GET_RIDE(peep->guest_heading_to_ride_id); + if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & 0x03800000) { + return; + } + } + + if ((rideTypeFlags & 0x002000000) && peep_has_food(peep)) { + return; + } + + RCT2_GLOBAL(0x00F1AD98, uint32) = 0; + RCT2_GLOBAL(0x00F1AD9C, uint32) = 0; + RCT2_GLOBAL(0x00F1ADA0, uint32) = 0; + RCT2_GLOBAL(0x00F1ADA4, uint32) = 0; + RCT2_GLOBAL(0x00F1ADA8, uint32) = 0; + RCT2_GLOBAL(0x00F1ADAC, uint32) = 0; + RCT2_GLOBAL(0x00F1ADB0, uint32) = 0; + RCT2_GLOBAL(0x00F1ADB4, uint32) = 0; + + // FIX Originally checked for a toy,.likely a mistake and should be a map + if (peep->item_standard_flags & PEEP_ITEM_MAP) { + // Consider all rides in the park + int i; + FOR_ALL_RIDES(i, ride) { + if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & rideTypeFlags) { + RCT2_ADDRESS(0x00F1AD98, uint32)[i >> 5] |= (1u << (i & 0x1F)); + } + } + } else { + // Take nearby rides into consideration + int cx = floor2(peep->x, 32); + int cy = floor2(peep->y, 32); + for (int x = cx - 320; x <= cx + 320; x += 32) { + for (int y = cy - 320; y <= cy + 320; y += 32) { + if (x >= 0 && y >= 0 && x < (256 * 32) && y < (256 * 32)) { + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) continue; + + int rideIndex = mapElement->properties.track.ride_index; + ride = GET_RIDE(rideIndex); + if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & rideTypeFlags) { + RCT2_ADDRESS(0x00F1AD98, uint32)[rideIndex >> 5] |= (1u << (rideIndex & 0x1F)); + } + } while (!map_element_is_last_for_tile(mapElement++)); + } + } + } + } + + // Filter the considered rides + uint8 *potentialRides = (uint8*)0x00F1ADBC; + uint8 *nextPotentialRide = potentialRides; + int numPotentialRides = 0; + for (int i = 0; i < MAX_RIDES; i++) { + if (!(RCT2_ADDRESS(0x00F1AD98, uint32)[i >> 5] & (1u << (i & 0x1F)))) + continue; + + rct_ride *ride = GET_RIDE(i); + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_QUEUE_FULL)) { + if (peep_should_go_on_ride(peep, i, 0, PEEP_RIDE_DECISION_THINKING)) { + *nextPotentialRide++ = i; + numPotentialRides++; + } + } + } + + // Pick the closest ride + int closestRideIndex = -1; + int closestRideDistance = INT_MAX; + for (int i = 0; i < numPotentialRides; i++) { + ride = GET_RIDE(potentialRides[i]); + int rideX = (ride->station_starts[0] & 0xFF) * 32; + int rideY = (ride->station_starts[0] >> 8) * 32; + int distance = abs(rideX - peep->x) + abs(rideY - peep->y); + if (distance < closestRideDistance) { + closestRideIndex = potentialRides[i]; + closestRideDistance = distance; + } + } + if (closestRideIndex == -1) + return; + + // Head to that ride + peep->guest_heading_to_ride_id = closestRideIndex; + peep->peep_is_lost_countdown = 200; + sub_69A98C(peep); + + // Invalidate windows + rct_window *w = window_find_by_number(WC_PEEP, peep->sprite_index); + if (w != NULL) { + window_event_invalidate_call(w); + } + widget_invalidate_by_number(WC_RIDE, closestRideIndex, 23); + + peep->var_F4 = 0; +} + +/** + * + * rct2: 0x0069C483 + */ +static void peep_give_real_name(rct_peep *peep) +{ + // Generate a name_string_idx from the peep id using bit twiddling + uint16 ax = (uint16)(peep->id + 0xF0B); + uint16 dx = 0; + dx |= ((ax & 0x400) ? 1 : 0) << 13; + dx |= ((ax & 0x2000) ? 1 : 0) << 12; + dx |= ((ax & 0x800) ? 1 : 0) << 11; + dx |= ((ax & 0x400) ? 1 : 0) << 10; + dx |= ((ax & 0x1) ? 1 : 0) << 9; + dx |= ((ax & 0x40) ? 1 : 0) << 8; + dx |= ((ax & 0x2) ? 1 : 0) << 7; + dx |= ((ax & 0x4) ? 1 : 0) << 6; + dx |= ((ax & 0x100) ? 1 : 0) << 5; + dx |= ((ax & 0x20) ? 1 : 0) << 4; + dx |= ((ax & 0x80) ? 1 : 0) << 3; + dx |= ((ax & 0x8) ? 1 : 0) << 2; + dx |= ((ax & 0x200) ? 1 : 0) << 1; + dx |= ((ax & 0x10) ? 1 : 0) << 0; + ax = dx & 0xF; + dx *= 4; + ax *= 4096; + dx += ax; + if (dx < ax) { + dx += 0x1000; + } + dx /= 4; + dx += 0xA000; + peep->name_string_idx = dx; +} + +/** + * + * rct2: 0x00699115 + */ +void peep_update_name_sort(rct_peep *peep) +{ + RCT2_CALLPROC_X(0x00699115, 0, 0, 0, 0, (int)peep, 0, 0); + + // This is required at the moment because this function reorders peeps in the sprite list + openrct2_reset_object_tween_locations(); +} + +/** + * + * rct2: 0x0069926C + */ +void peep_update_names(bool realNames) +{ + rct_peep *peep; + uint16 spriteIndex; + bool restart; + + if (realNames) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES; + do { + restart = false; + FOR_ALL_GUESTS(spriteIndex, peep) { + if (peep->name_string_idx == 767) { + peep_give_real_name(peep); + peep_update_name_sort(peep); + restart = true; + } + } + } while (restart); + gfx_invalidate_screen(); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_SHOW_REAL_GUEST_NAMES; + do { + restart = false; + FOR_ALL_GUESTS(spriteIndex, peep) { + if (peep->name_string_idx < 0xA000) + continue; + if (peep->name_string_idx >= 0xE000) + continue; + + peep->name_string_idx = 767; + peep_update_name_sort(peep); + restart = true; + } + } while (restart); + gfx_invalidate_screen(); + } +} + +static void peep_read_map(rct_peep *peep) +{ + if (peep->action == PEEP_ACTION_NONE_1 || peep->action == PEEP_ACTION_NONE_2) { + peep->action = PEEP_ACTION_READ_MAP; + peep->action_frame = 0; + peep->action_sprite_image_offset = 0; + sub_693B58(peep); + invalidate_sprite_2((rct_sprite*)peep); + } +} + +static bool peep_heading_for_ride_or_park_exit(rct_peep *peep) +{ + return (peep->flags & PEEP_FLAGS_LEAVING_PARK) || peep->guest_heading_to_ride_id != 0xFF; +} + +money32 set_peep_name(int flags, int state, uint16 sprite_index, uint8* text_1, uint8* text_2, uint8* text_3) { + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; + if (state == 1) { + RCT2_GLOBAL(0x00F1AEF4, uint16) = sprite_index; + } + + utf8* fullText = RCT2_ADDRESS(0x00F1AEF6, utf8); + //if (flags & GAME_COMMAND_FLAG_APPLY) { // this check seems to be useless and causes problems in multiplayer + uint8 position = (state - 1) % 3; + memcpy(fullText + position * 12, text_1, 4); + memcpy(fullText + 4 + position * 12, text_2, 4); + memcpy(fullText + 8 + position * 12, text_3, 4); + //} + + if (state != 0) + return 0; + + rct_peep* peep = GET_PEEP(sprite_index); + RCT2_GLOBAL(0x0013CE952, uint32) = peep->id; + utf8* curName = RCT2_ADDRESS(0x00141ED68, utf8); + rct_string_id curId = peep->name_string_idx; + format_string(curName, curId, RCT2_ADDRESS(0x0013CE952, void)); + + if (strcmp(curName, fullText) == 0) + return 0; + + if (*fullText == '\0') { + RCT2_GLOBAL(0x00141E9AC, rct_string_id) = 1455; + return MONEY32_UNDEFINED; + } + + rct_string_id newId = user_string_allocate(4, fullText); + if (newId == 0) { + return MONEY32_UNDEFINED; + } + + if (!(flags & GAME_COMMAND_FLAG_APPLY)) { + user_string_free(newId); + return 0; + } + + user_string_free(curId); + peep->name_string_idx = newId; + + peep_update_name_sort(peep); + + peep->flags &= ~PEEP_FLAGS_WAVING; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_KATIE_BRAYSHAW, peep)) { + peep->flags |= PEEP_FLAGS_WAVING; + } + + peep->flags &= ~PEEP_FLAGS_PHOTO; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_CHRIS_SAWYER, peep)) { + peep->flags |= PEEP_FLAGS_PHOTO; + } + + peep->flags &= ~PEEP_FLAGS_PAINTING; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_SIMON_FOSTER, peep)) { + peep->flags |= PEEP_FLAGS_PAINTING; + } + + peep->flags &= ~PEEP_FLAGS_WOW; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_JOHN_WARDLEY, peep)) { + peep->flags |= PEEP_FLAGS_WOW; + } + + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_MELANIE_WARN, peep)) { + peep->happiness = 250; + peep->happiness_growth_rate = 250; + peep->energy = 127; + peep->energy_growth_rate = 127; + peep->nausea = 0; + peep->nausea_growth_rate = 0; + } + + peep->flags &= ~PEEP_FLAGS_LITTER; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_LISA_STIRLING, peep)) { + peep->flags |= PEEP_FLAGS_LITTER; + } + + peep->flags &= ~PEEP_FLAGS_LOST; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_DONALD_MACRAE, peep)) { + peep->flags |= PEEP_FLAGS_LOST; + } + + peep->flags &= ~PEEP_FLAGS_HUNGER; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_KATHERINE_MCGOWAN, peep)) { + peep->flags |= PEEP_FLAGS_HUNGER; + } + + peep->flags &= ~PEEP_FLAGS_BATHROOM; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_FRANCES_MCGOWAN, peep)) { + peep->flags |= PEEP_FLAGS_BATHROOM; + } + + peep->flags &= ~PEEP_FLAGS_CROWDED; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_CORINA_MASSOURA, peep)) { + peep->flags |= PEEP_FLAGS_CROWDED; + } + + peep->flags &= ~PEEP_FLAGS_HAPPINESS; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_CAROL_YOUNG, peep)) { + peep->flags |= PEEP_FLAGS_HAPPINESS; + } + + peep->flags &= ~PEEP_FLAGS_NAUSEA; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_MIA_SHERIDAN, peep)) { + peep->flags |= PEEP_FLAGS_NAUSEA; + } + + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_KATIE_RODGER, peep)) { + peep->flags |= PEEP_FLAGS_LEAVING_PARK; + peep->flags &= ~PEEP_FLAGS_PARK_ENTRANCE_CHOSEN; + } + + peep->flags &= ~PEEP_FLAGS_PURPLE; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_EMMA_GARRELL, peep)) { + peep->flags |= PEEP_FLAGS_PURPLE; + } + + peep->flags &= ~PEEP_FLAGS_EATING; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_JOANNE_BARTON, peep)) { + peep->flags |= PEEP_FLAGS_EATING; + } + + peep->flags &= ~PEEP_FLAGS_CONTAGIOUS; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_FELICITY_ANDERSON, peep)) { + peep->flags |= PEEP_FLAGS_CONTAGIOUS; + } + + peep->flags &= ~PEEP_FLAGS_JOY; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_KATIE_SMITH, peep)) { + peep->flags |= PEEP_FLAGS_JOY; + } + + peep->flags &= ~PEEP_FLAGS_ANGRY; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_EILIDH_BELL, peep)) { + peep->flags |= PEEP_FLAGS_ANGRY; + } + + peep->flags &= ~PEEP_FLAGS_ICE_CREAM; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_NANCY_STILLWAGON, peep)) { + peep->flags |= PEEP_FLAGS_ICE_CREAM; + } + + peep->flags &= ~PEEP_FLAGS_NICE_RIDE; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_ANDY_HINE, peep)) { + peep->flags |= PEEP_FLAGS_NICE_RIDE; + } + + peep->flags &= ~PEEP_FLAGS_INTAMIN; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_ELISSA_WHITE, peep)) { + peep->flags |= PEEP_FLAGS_INTAMIN; + } + + peep->flags &= ~PEEP_FLAGS_HERE_WE_ARE; + if (peep_check_easteregg_name(EASTEREGG_PEEP_NAME_DAVID_ELLIS, peep)) { + peep->flags |= PEEP_FLAGS_HERE_WE_ARE; + } + + gfx_invalidate_screen(); + return 0; +} + +/* rct2: 0x00698D6C */ +void game_command_set_peep_name(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) { + *ebx = set_peep_name( + *ebx & 0xFF, + *eax & 0xFFFF, + *ecx & 0xFFFF, + (uint8*)edx, + (uint8*)ebp, + (uint8*)edi + ); +} diff --git a/src/peep/peep.h b/src/peep/peep.h index 837590b826..c758f335b7 100644 --- a/src/peep/peep.h +++ b/src/peep/peep.h @@ -22,6 +22,7 @@ #define _PEEP_H_ #include "../common.h" +#include "../world/map.h" #define PEEP_MAX_THOUGHTS 5 @@ -40,6 +41,7 @@ enum PEEP_TYPE { }; enum PEEP_THOUGHT_TYPE { + PEEP_THOUGHT_TYPE_CANT_AFFORD_0 = 0, // "I can't afford" PEEP_THOUGHT_TYPE_SPENT_MONEY = 1, // "I've spent all my money" PEEP_THOUGHT_TYPE_SICK = 2, // "I feel sick" PEEP_THOUGHT_TYPE_VERY_SICK = 3, // "I feel very sick" @@ -208,16 +210,16 @@ enum PEEP_STATE { PEEP_STATE_INSPECTING = 23 }; -enum PEEP_ACTION_EVENTS { +enum PEEP_ACTION_EVENTS { 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_EMPTY_POCKETS = 3, PEEP_ACTION_SITTING_EAT_FOOD = 4, PEEP_ACTION_SITTING_CHECK_WATCH = 4, PEEP_ACTION_SITTING_LOOK_AROUND_LEFT = 5, - PEEP_ACTION_SITTING_LOOK_AROUND_RIGHT = 6, + PEEP_ACTION_SITTING_LOOK_AROUND_RIGHT = 6, PEEP_ACTION_WOW = 7, PEEP_ACTION_THROW_UP = 8, PEEP_ACTION_JUMP = 9, @@ -230,6 +232,7 @@ enum PEEP_ACTION_EVENTS { PEEP_ACTION_STAFF_FIX_2 = 16, PEEP_ACTION_STAFF_FIX_GROUND = 17, PEEP_ACTION_STAFF_WATERING = 19, + PEEP_ACTION_READ_MAP = 21, PEEP_ACTION_WAVE = 22, PEEP_ACTION_STAFF_EMPTY_BIN = 23, PEEP_ACTION_WAVE_2 = 24, @@ -247,30 +250,33 @@ enum PEEP_ACTION_EVENTS { enum PEEP_FLAGS { PEEP_FLAGS_LEAVING_PARK = (1 << 0), PEEP_FLAGS_SLOW_WALK = (1 << 1), - + PEEP_FLAGS_2 = (1 << 2), PEEP_FLAGS_TRACKING = (1 << 3), PEEP_FLAGS_WAVING = (1 << 4), // Makes the peep wave - + PEEP_FLAGS_HAS_PAID_FOR_PARK_ENTRY = (1 << 5), // Set on paying to enter park PEEP_FLAGS_PHOTO = (1 << 6), // Makes the peep take a picture - PEEP_FLAGS_PAINTING = (1 << 7), - + PEEP_FLAGS_PAINTING = (1 << 7), + PEEP_FLAGS_WOW = (1 << 8), // Makes a peep WOW2 PEEP_FLAGS_LITTER = (1 << 9), // Makes the peep throw litter PEEP_FLAGS_LOST = (1 << 10), // Makes the peep feel lost (animation trigerred) PEEP_FLAGS_HUNGER = (1 << 11), // Makes the peep become hungry quicker PEEP_FLAGS_BATHROOM = (1 << 12), // Makes the peep want to go to the bathroom PEEP_FLAGS_CROWDED = (1 << 13), // The peep will start feeling crowded - + PEEP_FLAGS_HAPPINESS = (1 << 14), // The peep will start increasing happiness PEEP_FLAGS_NAUSEA = (1 << 15), // Makes the peep feel sick (e.g. after an extreme ride) - + PEEP_FLAGS_PURPLE = (1 << 16), // Makes surrounding peeps purple PEEP_FLAGS_EATING = (1 << 17), // Reduces hunger PEEP_FLAGS_EXPLODE = (1 << 18), - - PEEP_FLAGS_21 = (1<<21), - + PEEP_FLAGS_RIDE_SHOULD_BE_MARKED_AS_FAVOURITE = (1 << 19), + PEEP_FLAGS_PARK_ENTRANCE_CHOSEN = (1 << 20), //Set when the nearest park entrance has been chosen + PEEP_FLAGS_21 = (1 << 21), + PEEP_FLAGS_CONTAGIOUS = (1 << 22), // Makes any peeps in surrounding tiles sick 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), // Gives the peeps infront of them in queue ice cream + PEEP_FLAGS_NICE_RIDE = (1 << 26), // Makes the peep think "Nice ride! But not as good as the Phoenix..." on exiting a ride + PEEP_FLAGS_INTAMIN = (1 << 27), // Makes the peep think "I'm so excited - It's an Intamin ride!" while riding on a Intamin + PEEP_FLAGS_HERE_WE_ARE = (1 << 28), // Makes the peep think "...and here we are on X!" while riding a ride PEEP_FLAGS_TWITCH = (1 << 31) // Added for twitch integration }; @@ -337,6 +343,35 @@ enum PEEP_ITEM { PEEP_ITEM_EMPTY_BOWL_BLUE = (1 << 21) }; +enum { + PEEP_SPRITE_TYPE_NORMAL = 0, + PEEP_SPRITE_TYPE_3 = 3, + PEEP_SPRITE_TYPE_19 = 19, + PEEP_SPRITE_TYPE_UMBRELLA = 21, + PEEP_SPRITE_TYPE_23 = 23, + PEEP_SPRITE_TYPE_25 = 25, + PEEP_SPRITE_TYPE_26 = 26, + PEEP_SPRITE_TYPE_NAUSEOUS = 27, + PEEP_SPRITE_TYPE_VERY_NAUSEOUS = 28, + PEEP_SPRITE_TYPE_REQUIRE_BATHROOM = 29, + PEEP_SPRITE_TYPE_WATCHING = 38 +}; + +// Flags used by peep->window_invalidate_flags +enum { + PEEP_INVALIDATE_PEEP_THOUGHTS = 1, + PEEP_INVALIDATE_PEEP_STATS = 1 << 1, + PEEP_INVALIDATE_PEEP_2 = 1 << 2, + PEEP_INVALIDATE_PEEP_INVENTORY = 1 << 3, + PEEP_INVALIDATE_STAFF_STATS = 1 << 4, +}; + +// Flags used by peep_should_go_on_ride() +enum { + PEEP_RIDE_DECISION_AT_QUEUE = 1, + PEEP_RIDE_DECISION_THINKING = 1 << 2 +}; + typedef struct { uint8 type; //0 uint8 item; //1 @@ -373,19 +408,19 @@ typedef struct { uint16 next_y; // 0x26 uint8 next_z; // 0x28 uint8 next_var_29; // 0x29 - uint8 var_2A; + uint8 outside_of_park; uint8 state; // 0x2B uint8 sub_state; // 0x2C uint8 sprite_type; // 0x2D uint8 type; // 0x2E - union{ + union{ uint8 staff_type; // 0x2F uint8 no_of_rides; // 0x2F }; uint8 tshirt_colour; // 0x30 uint8 trousers_colour; // 0x31 uint16 destination_x; // 0x32 Location that the peep is trying to get to - uint16 destination_y; // 0x34 + uint16 destination_y; // 0x34 uint8 destination_tolerence; // 0x36 How close to destination before next action/state 0 = exact uint8 var_37; uint8 energy; // 0x38 @@ -399,16 +434,16 @@ typedef struct { uint8 bathroom; // 0x40 uint8 var_41; uint8 var_42; - uint8 intensity; // 0x43 + uint8 intensity; // 0x43 The max intensity is stored in the first 4 bits, and the min intensity in the second 4 bits uint8 nausea_tolerance; // 0x44 - uint8 var_45; // Some sort of flags? + uint8 window_invalidate_flags; // 0x45 money16 paid_on_drink; // 0x46 - uint8 var_48[16]; + uint8 ride_types_been_on[16]; // 0x48 uint32 item_extra_flags; // 0x58 uint8 photo2_ride_ref; // 0x5C uint8 photo3_ride_ref; // 0x5D uint8 photo4_ride_ref; // 0x5E - uint8 pad_5F[0x09]; // 0x5C + uint8 pad_5F[0x09]; // 0x5F uint8 current_ride; // 0x68 uint8 current_ride_station; // 0x69 uint8 current_train; // 0x6A @@ -438,11 +473,11 @@ typedef struct { uint8 pad_77; union{ uint8 maze_last_edge; // 0x78 - uint8 var_78; + uint8 var_78; //Direction ? }; uint8 var_79; uint16 time_in_queue; // 0x7A - uint8 rides_been_on[32]; // 0x7C + 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. uint32 id; // 0x9C @@ -454,23 +489,27 @@ typedef struct { uint16 previous_ride_time_out; // 0xAE rct_peep_thought thoughts[PEEP_MAX_THOUGHTS]; // 0xB0 uint8 var_C4; // 0xC4 - union // 0xC5 - { - uint8 staff_id; - uint8 guest_heading_to_ride_id; + union { + uint8 staff_id; // 0xC5 + uint8 guest_heading_to_ride_id; // 0xC5 }; - union{ - uint8 staff_orders; // 0xC6 - uint8 var_C6; + union { + uint8 staff_orders; // 0xC6 + uint8 peep_is_lost_countdown; // 0xC6 }; uint8 photo1_ride_ref; // 0xC7 uint32 flags; // 0xC8 - uint32 var_CC; - uint8 pad_D0[0x10]; + rct_xyzd8 var_CC; + rct_xyzd8 var_D0[4]; uint8 no_action_frame_no; // 0xE0 - uint8 var_E1; - uint8 var_E2; // 0xE2 - uint8 var_E3; + // 0x3F Litter Count split into lots of 3 with time, 0xC0 Time since last recalc + uint8 litter_count; // 0xE1 + union{ + uint8 time_on_ride; // 0xE2 + uint8 var_E2; // 0xE2 + }; + // 0x3F Sick Count split into lots of 3 with time, 0xC0 Time since last recalc + uint8 disgusting_count; // 0xE3 union{ money16 paid_to_enter; // 0xE4 uint16 staff_lawns_mown; // 0xE4 @@ -503,7 +542,7 @@ typedef struct { uint8 umbrella_colour; // 0xF7 uint8 hat_colour; // 0xF8 uint8 favourite_ride; // 0xF9 - uint8 var_FA; + uint8 favourite_ride_rating; // 0xFA uint8 pad_FB; uint32 item_standard_flags; // 0xFC } rct_peep; @@ -541,7 +580,7 @@ enum { #define GET_PEEP(sprite_index) &(g_sprite_list[sprite_index].peep) /** - * Helper macro loop for enumerating through all the non null rides. To avoid needing a end loop counterpart, statements are + * Helper macro loop for enumerating through all the peeps. To avoid needing a end loop counterpart, statements are * applied in tautology if statements. */ #define FOR_ALL_PEEPS(sprite_index, peep) \ @@ -571,9 +610,11 @@ int get_peep_face_sprite_large(rct_peep *peep); 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); +bool peep_has_item(rct_peep *peep, int peepItem); int peep_has_food(rct_peep* peep); void peep_sprite_remove(rct_peep* peep); void peep_remove(rct_peep* peep); +void peep_update_sprite_type(rct_peep* peep); void peep_window_state_update(rct_peep* peep); void peep_decrement_num_riders(rct_peep* peep); @@ -590,4 +631,10 @@ void sub_693B58(rct_peep* peep); void remove_peep_from_ride(rct_peep* peep); void remove_peep_from_queue(rct_peep* peep); +void sub_693BE5(rct_peep* peep, uint8 al); +void peep_update_name_sort(rct_peep *peep); +void peep_update_names(bool realNames); + +void game_command_set_peep_name(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); + #endif diff --git a/src/peep/staff.c b/src/peep/staff.c index f6fa857107..b187d632b3 100644 --- a/src/peep/staff.c +++ b/src/peep/staff.c @@ -29,6 +29,24 @@ #include "peep.h" #include "staff.h" +uint32 *gStaffPatrolAreas = (uint32*)RCT2_ADDRESS_STAFF_PATROL_AREAS; +uint8 *gStaffModes = (uint8*)RCT2_ADDRESS_STAFF_MODE_ARRAY; + +/** + * + * rct2: 0x006BD3A4 + */ +void staff_reset_modes() +{ + 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(); +} + /** * * rct2: 0x00669E55 @@ -38,7 +56,7 @@ void game_command_update_staff_colour(int *eax, int *ebx, int *ecx, int *edx, in uint8 staffType, colour; int spriteIndex; rct_peep *peep; - + staffType = (*ebx >> 8) & 0xFF; colour = (*edx >> 8) & 0xFF; @@ -67,9 +85,9 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, uint16 _ax = *eax & 0xFFFF, _cx = *ecx & 0xFFFF, _dx = *edx & 0xFFFF; 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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = _ax; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = _cx; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = _dx; if (RCT2_GLOBAL(0x13573C8, uint16) < 0x190) { *ebx = MONEY32_UNDEFINED; @@ -107,9 +125,9 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, sprite_remove((rct_sprite*)newPeep); } else { move_sprite_to_list((rct_sprite *)newPeep, SPRITE_LINKEDLIST_OFFSET_PEEP); - + newPeep->sprite_identifier = 1; - newPeep->var_45 = 0; + newPeep->window_invalidate_flags = 0; newPeep->action = PEEP_ACTION_NONE_2; newPeep->var_6D = 0; newPeep->action_sprite_image_offset = 0; @@ -117,19 +135,19 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, newPeep->action_sprite_type = 0; newPeep->var_C4 = 0; newPeep->type = PEEP_TYPE_STAFF; - newPeep->var_2A = 0; + newPeep->outside_of_park = 0; newPeep->flags = 0; newPeep->paid_to_enter = 0; newPeep->paid_on_rides = 0; newPeep->paid_on_food = 0; newPeep->paid_on_souvenirs = 0; - newPeep->var_C6 = 0; + newPeep->staff_orders = 0; if (staff_type == 0) { - newPeep->var_C6 = 7; + newPeep->staff_orders = 7; } else if (staff_type == 1) { - newPeep->var_C6 = 3; + newPeep->staff_orders = 3; } uint16 idSearchSpriteIndex; @@ -174,7 +192,7 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, sint16 x, y, z; uint32 count = 0; uint16 sprite_index; - rct_peep *guest; + rct_peep *guest = NULL; FOR_ALL_GUESTS(sprite_index, guest) if (guest->state == PEEP_STATE_WALKING) ++count; @@ -183,20 +201,13 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, 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 (RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[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; - + uint32 rand = scenario_rand_max(count); for (i = 0; i < 4; ++i) { - if (RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[i] != SPRITE_LOCATION_NULL) { + if (RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[i] != SPRITE_LOCATION_NULL) { if (rand == 0) break; --rand; } @@ -215,14 +226,7 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, 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; - + uint32 rand = scenario_rand_max(count); FOR_ALL_GUESTS(sprite_index, guest) if (guest->state == PEEP_STATE_WALKING) { if (rand == 0) break; @@ -235,38 +239,46 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, } sprite_move(x, y, z + 16, (rct_sprite*)newPeep); - invalidate_sprite((rct_sprite*)newPeep); + invalidate_sprite_2((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); + invalidate_sprite_2((rct_sprite*)newPeep); } newPeep->time_in_park = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16); - newPeep->var_CC = 0xFFFFFFFF; + newPeep->var_CC.x = 0xFF; + newPeep->var_CC.y = 0xFF; + newPeep->var_CC.z = 0xFF; + newPeep->var_CC.direction = 0xFF; uint8 colour = RCT2_ADDRESS(RCT2_ADDRESS_HANDYMAN_COLOUR, uint8)[staff_type > 2 ? 2 : staff_type]; newPeep->tshirt_colour = colour; newPeep->trousers_colour = colour; + // Staff energy determines their walking speed newPeep->energy = 0x60; newPeep->energy_growth_rate = 0x60; newPeep->var_E2 = 0; - RCT2_CALLPROC_X(0x00699115, (uint32)ebp & 0xFFFFFF3F, 0, 0, 0, (int)newPeep, 0, - (*ebp << 25) | (*ebp >> 6)); + peep_update_name_sort(newPeep); newPeep->staff_id = newStaffId; RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[newStaffId] = STAFF_MODE_WALK; for (int edi = 0; edi < 0x80; edi++) { - int addr = 0x013B0E72 + (newStaffId << 9) + edi * 4; + int addr = RCT2_ADDRESS_STAFF_PATROL_AREAS + (newStaffId << 9) + edi * 4; RCT2_GLOBAL(addr, uint32) = 0; } } + if(staff_type == STAFF_TYPE_HANDYMAN && gConfigGeneral.handymen_mow_default) { + int flags = ((newPeep->staff_orders ^ (1 << 3)) << 8) | 1; + game_do_command(newPeep->x, flags, newPeep->y, newPeep->sprite_index, GAME_COMMAND_SET_STAFF_ORDER, (int)newPeep, 0); + } + *ebx = 0; *edi = newPeep->sprite_index; } @@ -277,7 +289,7 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, */ 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; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_WAGES * 4; uint8 order_id = *ebx >> 8; uint16 sprite_id = *edx; if(*ebx & GAME_COMMAND_FLAG_APPLY){ @@ -292,7 +304,7 @@ void game_command_set_staff_order(int *eax, int *ebx, int *ecx, int *edx, int *e } peep->action_frame = 0; sub_693B58(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); window_invalidate_by_number(WC_PEEP, sprite_id); window_invalidate_by_class(WC_STAFF_LIST); }else{ @@ -320,12 +332,12 @@ void game_command_set_staff_patrol(int *eax, int *ebx, int *ecx, int *edx, int * int mask = 1 << (patrolIndex & 0x1F); int base = patrolIndex >> 5; - uint32 *patrolBits = (uint32*)(0x013B0E72 + patrolOffset + (base * 4)); + uint32 *patrolBits = (uint32*)(RCT2_ADDRESS_STAFF_PATROL_AREAS + patrolOffset + (base * 4)); *patrolBits ^= mask; int ispatrolling = 0; for(int i = 0; i < 128; i++){ - ispatrolling |= *(uint32*)(0x013B0E72 + patrolOffset + (i * 4)); + ispatrolling |= *(uint32*)(RCT2_ADDRESS_STAFF_PATROL_AREAS + patrolOffset + (i * 4)); } RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[peep->staff_id] &= ~2; @@ -349,7 +361,7 @@ void game_command_set_staff_patrol(int *eax, int *ebx, int *ecx, int *edx, int * */ 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; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_WAGES * 4; if(*ebx & GAME_COMMAND_FLAG_APPLY){ window_close_by_class(WC_FIRE_PROMPT); uint16 sprite_id = *edx; @@ -374,9 +386,10 @@ void update_staff_colour(uint8 staffType, uint16 colour) */ uint16 hire_new_staff_member(uint8 staffType) { - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_CANT_HIRE_NEW_STAFF; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_HIRE_NEW_STAFF; int eax, ebx, ecx, edx, esi, edi, ebp; + ecx = edx = esi = edi = ebp = 0; eax = 0x8000; ebx = staffType << 8 | GAME_COMMAND_FLAG_APPLY; @@ -399,8 +412,8 @@ void staff_update_greyed_patrol_areas() for (int staff_type = 0; staff_type < STAFF_TYPE_COUNT; ++staff_type) { for (int i = 0; i < 128; ++i) - RCT2_ADDRESS(0x13B0E72 + ((staff_type + STAFF_MAX_COUNT) * 512), uint32)[i] = 0; - + RCT2_ADDRESS(RCT2_ADDRESS_STAFF_PATROL_AREAS + ((staff_type + STAFF_MAX_COUNT) * 512), uint32)[i] = 0; + 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); @@ -408,7 +421,7 @@ void staff_update_greyed_patrol_areas() if (peep->type == PEEP_TYPE_STAFF && staff_type == peep->staff_type) { 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]; + RCT2_ADDRESS(RCT2_ADDRESS_STAFF_PATROL_AREAS + ((staff_type + STAFF_MAX_COUNT) * 512), uint32)[i] |= RCT2_ADDRESS(RCT2_ADDRESS_STAFF_PATROL_AREAS + (peep->staff_id * 512), uint32)[i]; } } @@ -425,7 +438,7 @@ int staff_is_location_in_patrol_area(rct_peep *peep, int x, int y) int mask = 1 << (patrolIndex & 0x1F); int base = patrolIndex >> 5; - uint32 *patrolBits = (uint32*)(0x013B0E72 + patrolOffset + (base * 4)); + uint32 *patrolBits = (uint32*)(RCT2_ADDRESS_STAFF_PATROL_AREAS + patrolOffset + (base * 4)); return (*patrolBits & mask) != 0; } @@ -464,4 +477,15 @@ void staff_reset_stats() peep->staff_litter_swept = 0; peep->staff_bins_emptied = 0; } -} \ No newline at end of file +} + +bool staff_is_patrol_area_set(int staffIndex, int x, int y) +{ + x = (x & 0x1F80) >> 7; + y = (y & 0x1F80) >> 1; + + int peepOffset = staffIndex * 128; + int offset = (x | y) >> 5; + int bitIndex = (x | y) & 0x1F; + return gStaffPatrolAreas[peepOffset + offset] & (1 << bitIndex); +} diff --git a/src/peep/staff.h b/src/peep/staff.h index 51467efecc..396246edd3 100644 --- a/src/peep/staff.h +++ b/src/peep/staff.h @@ -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 . *****************************************************************************/ @@ -49,16 +49,21 @@ enum STAFF_ORDERS{ STAFF_ORDERS_FIX_RIDES = (1 << 1) }; +extern uint32 *gStaffPatrolAreas; +extern uint8 *gStaffModes; + 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 staff_reset_modes(); 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(); +bool staff_is_patrol_area_set(int staffIndex, int x, int y); #endif \ No newline at end of file diff --git a/src/platform/linux.c b/src/platform/linux.c new file mode 100644 index 0000000000..7f9dcca4d3 --- /dev/null +++ b/src/platform/linux.c @@ -0,0 +1,59 @@ +/***************************************************************************** + * 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 . + *****************************************************************************/ + +#if defined(__linux__) + +#include "platform.h" +#include + +// See http://syprog.blogspot.ru/2011/12/listing-loaded-shared-objects-in-linux.html +struct lmap { + void* base_address; + char* path; + void* unused; + struct lmap *next, *prev; +}; + +struct dummy { + void* pointers[3]; + struct dummy* ptr; +}; + +bool platform_check_steam_overlay_attached() { + void* processHandle = dlopen(NULL, RTLD_NOW); + + struct dummy* p = (struct dummy*) processHandle; + p = p->ptr; + + struct lmap* pl = (struct lmap*) p->ptr; + + while (pl != NULL) { + if (strstr(pl->path, "gameoverlayrenderer.so") != NULL) { + dlclose(processHandle); + return true; + } + pl = pl->next; + } + dlclose(processHandle); + + return false; +} + +#endif diff --git a/src/platform/osx.c b/src/platform/osx.c index d16040f99d..c1928d0f02 100644 --- a/src/platform/osx.c +++ b/src/platform/osx.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 @@ -18,19 +18,13 @@ * along with this program. If not, see . *****************************************************************************/ -#ifdef __APPLE__ +#if defined(__APPLE__) && defined(__MACH__) -/** - * OSX entry point to OpenRCT2. - */ -// int main(char *argv[], int argc) -// { -// return 0; -// } +#include "platform.h" -char platform_get_path_separator() -{ - return '/'; +bool platform_check_steam_overlay_attached() { + STUB(); + return false; } -#endif \ No newline at end of file +#endif diff --git a/src/platform/platform.h b/src/platform/platform.h index ee3a146cd1..085fe0c645 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -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 @@ -17,10 +17,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ - + #ifndef _PLATFORM_H_ #define _PLATFORM_H_ +#ifdef _WIN32 +#define HAVE_MATH_H +#endif // _WIN32 + #include #include "../common.h" @@ -41,6 +45,19 @@ typedef struct { uint64 last_modified; } file_info; +typedef struct { + sint16 day; + sint16 month; + sint16 year; + sint16 day_of_week; +} rct2_date; + +typedef struct { + sint16 hour; + sint16 minute; + sint16 second; +} rct2_time; + typedef struct { int x, y; unsigned char left, middle, right, any; @@ -63,65 +80,110 @@ extern unsigned int gLastKeyPressed; extern int gTextInputCursorPosition; extern int gTextInputLength; +extern bool gTextInputCompositionActive; +extern utf8 gTextInputComposition[32]; +extern int gTextInputCompositionStart; +extern int gTextInputCompositionLength; + extern int gResolutionsAllowAnyAspectRatio; extern int gNumResolutions; extern resolution *gResolutions; extern SDL_Window *gWindow; +extern bool gHardwareDisplay; + +extern bool gSteamOverlayActive; + // 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_trigger_resize(); +void platform_update_palette(const uint8 *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_start_text_input(utf8 *buffer, int max_length); void platform_stop_text_input(); +void platform_get_date(rct2_date *out_date); +void platform_get_time(rct2_time *out_time); // Platform specific definitions char platform_get_path_separator(); -int platform_file_exists(const char *path); -int platform_directory_exists(const char *path); -int platform_ensure_directory_exists(const char *path); -int platform_lock_single_instance(); -int platform_enumerate_files_begin(const char *pattern); -int platform_enumerate_files_next(int handle, file_info *outFileInfo); +bool platform_file_exists(const utf8 *path); +bool platform_directory_exists(const utf8 *path); +bool platform_original_game_data_exists(const utf8 *path); +time_t platform_file_get_modified_time(const utf8* path); +bool platform_ensure_directory_exists(const utf8 *path); +bool platform_directory_delete(const utf8 *path); +bool platform_lock_single_instance(); +int platform_enumerate_files_begin(const utf8 *pattern); +bool 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); +int platform_enumerate_directories_begin(const utf8 *directory); +bool platform_enumerate_directories_next(int handle, utf8 *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); + +// Returns the bitmask of the GetLogicalDrives function for windows, 0 for other systems +int platform_get_drives(); + +bool platform_file_copy(const utf8 *srcPath, const utf8 *dstPath, bool overwrite); +bool platform_file_move(const utf8 *srcPath, const utf8 *dstPath); +bool platform_file_delete(const utf8 *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); +void platform_resolve_user_data_path(); +void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory); +void platform_show_messagebox(utf8 *message); +int platform_open_common_file_dialog(int type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName); +utf8 *platform_open_directory_browser(utf8 *title); uint8 platform_get_locale_currency(); uint16 platform_get_locale_language(); uint8 platform_get_locale_measurement_format(); uint8 platform_get_locale_temperature_format(); +bool platform_check_steam_overlay_attached(); + // 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 + #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 // _WIN32 -#endif \ No newline at end of file +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#include +#define STUB() log_warning("Function %s at %s:%d is a stub.\n", __PRETTY_FUNCTION__, __FILE__, __LINE__) +#define _strcmpi _stricmp +#define _stricmp(x, y) strcasecmp((x), (y)) +#define _strnicmp(x, y, n) strncasecmp((x), (y), (n)) +#define _strdup(x) strdup((x)) + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define RCT2_ENDIANESS __ORDER_LITTLE_ENDIAN__ +#define LOBYTE(w) ((uint8_t)(w)) +#define HIBYTE(w) ((uint8_t)(((uint16_t)(w)>>8)&0xFF)) +#endif // __BYTE_ORDER__ + +#ifndef RCT2_ENDIANESS +#error Unknown endianess! +#endif // RCT2_ENDIANESS + +#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) + +#if !(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700) + char *strndup(const char *src, size_t size); +#endif // !(POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700) + +#endif diff --git a/src/platform/posix.c b/src/platform/posix.c new file mode 100644 index 0000000000..98cffb1bd7 --- /dev/null +++ b/src/platform/posix.c @@ -0,0 +1,775 @@ +/***************************************************************************** + * 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 . + *****************************************************************************/ + +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) + +#include +#include +#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" +#include "../util/util.h" +#include +#include +#include + +// The name of the mutex used to prevent multiple instances of the game from running +#define SINGLE_INSTANCE_MUTEX_NAME "RollerCoaster Tycoon 2_GSKMUTEX" + +utf8 _userDataDirectoryPath[MAX_PATH] = { 0 }; + +/** + * The function that is called directly from the host application (rct2.exe)'s WinMain. This will be removed when OpenRCT2 can + * be built as a stand alone application. + */ +int main(int argc, const char **argv) +{ + //RCT2_GLOBAL(RCT2_ADDRESS_HINSTANCE, HINSTANCE) = hInstance; + //RCT2_GLOBAL(RCT2_ADDRESS_CMDLINE, LPSTR) = lpCmdLine; + + STUB(); + int run_game = cmdline_run(argv, argc); + if (run_game == 1) + { + openrct2_launch(); + } + + exit(gExitCode); + return gExitCode; +} + +void platform_get_date(rct2_date *out_date) +{ + assert(out_date != NULL); + time_t rawtime; + struct tm * timeinfo; + time(&rawtime); + timeinfo = gmtime(&rawtime); + out_date->day = timeinfo->tm_mday; + out_date->month = timeinfo->tm_mon; + out_date->year = timeinfo->tm_year; + out_date->day_of_week = timeinfo->tm_wday; +} + +void platform_get_time(rct2_time *out_time) +{ + assert(out_time != NULL); + time_t rawtime; + struct tm * timeinfo; + time(&rawtime); + timeinfo = gmtime(&rawtime); + out_time->second = timeinfo->tm_sec; + out_time->minute = timeinfo->tm_min; + out_time->hour = timeinfo->tm_hour; +} + +char platform_get_path_separator() +{ + return '/'; +} + +bool platform_file_exists(const utf8 *path) +{ + wchar_t *wPath = utf8_to_widechar(path); + int len = min(MAX_PATH - 1, utf8_length(path)); + char buffer[MAX_PATH]; + wcstombs(buffer, wPath, len); + buffer[len] = '\0'; + free(wPath); + bool exists = access(buffer, F_OK) != -1; + log_warning("file '%s' exists = %i", buffer, exists); + return exists; +} + +bool platform_directory_exists(const utf8 *path) +{ + wchar_t *wPath = utf8_to_widechar(path); + int len = min(MAX_PATH - 1, utf8_length(path)); + char buffer[MAX_PATH]; + wcstombs(buffer, wPath, len); + buffer[len] = '\0'; + free(wPath); + struct stat dirinfo; + int result = stat(buffer, &dirinfo); + log_verbose("checking dir %s, result = %d, is_dir = %d", buffer, result, S_ISDIR(dirinfo.st_mode)); + if ((result != 0) || !S_ISDIR(dirinfo.st_mode)) + { + return false; + } + return true; +} + +bool platform_original_game_data_exists(const utf8 *path) +{ + wchar_t *wPath = utf8_to_widechar(path); + int len = min(MAX_PATH - 1, utf8_length(path)); + char buffer[MAX_PATH]; + wcstombs(buffer, wPath, len); + buffer[len] = '\0'; + free(wPath); + char checkPath[MAX_PATH]; + sprintf(checkPath, "%s%c%s%c%s", buffer, platform_get_path_separator(), "Data", platform_get_path_separator(), "g1.dat"); + return platform_file_exists(checkPath); +} + +mode_t getumask() +{ + mode_t mask = umask(0); + umask(mask); + return 0777 & ~mask; // Keep in mind 0777 is octal +} + +bool platform_ensure_directory_exists(const utf8 *path) +{ + mode_t mask = getumask(); + + wchar_t *wPath = utf8_to_widechar(path); + int len = min(MAX_PATH, utf8_length(path)); + char buffer[MAX_PATH]; + wcstombs(buffer, wPath, len); + buffer[len - 1] = '\0'; + free(wPath); + log_verbose("%s", buffer); + const int result = mkdir(buffer, mask); + if (result == 0 || (result == -1 && errno == EEXIST)) + return true; + return false; +} + +bool platform_directory_delete(const utf8 *path) +{ + STUB(); + return true; +} + +bool platform_lock_single_instance() +{ + STUB(); + return true; +} + +typedef struct { + char active; + char pattern[MAX_PATH]; + struct dirent **fileListTemp; + char **paths; + int cnt; + int handle; + void* data; +} enumerate_file_info; +static enumerate_file_info _enumerateFileInfoList[8] = { 0 }; + +char *g_file_pattern; + +static int winfilter(const struct dirent *d) +{ + int entry_length = strnlen(d->d_name, MAX_PATH); + char *name_upper = malloc(entry_length + 1); + if (name_upper == NULL) + { + log_error("out of memory"); + return 0; + } + for (int i = 0; i < entry_length; i++) + { + name_upper[i] = (char)toupper(d->d_name[i]); + } + name_upper[entry_length] = '\0'; + bool match = fnmatch(g_file_pattern, name_upper, FNM_PATHNAME) == 0; + //log_warning("trying matching filename %s, result = %d", name_upper, match); + free(name_upper); + return match; +} + +int platform_enumerate_files_begin(const utf8 *pattern) +{ + enumerate_file_info *enumFileInfo; + wchar_t *wpattern = utf8_to_widechar(pattern); + int length = min(utf8_length(pattern), MAX_PATH); + char *npattern = malloc(length+1); + int converted; + converted = wcstombs(npattern, wpattern, length); + npattern[length] = '\0'; + if (converted == MAX_PATH) { + log_warning("truncated string %s", npattern); + } + log_warning("begin file search, pattern: %s", npattern); + + char *file_name = strrchr(npattern, platform_get_path_separator()); + char *dir_name; + if (file_name != NULL) + { + dir_name = strndup(npattern, file_name - npattern); + file_name = &file_name[1]; + } else { + file_name = npattern; + dir_name = strdup("."); + } + + + int pattern_length = strlen(file_name); + g_file_pattern = strndup(file_name, pattern_length); + for (int j = 0; j < pattern_length; j++) + { + g_file_pattern[j] = (char)toupper(g_file_pattern[j]); + } + log_warning("looking for file matching %s", g_file_pattern); + int cnt; + for (int i = 0; i < countof(_enumerateFileInfoList); i++) { + enumFileInfo = &_enumerateFileInfoList[i]; + if (!enumFileInfo->active) { + safe_strncpy(enumFileInfo->pattern, npattern, sizeof(enumFileInfo->pattern)); + cnt = scandir(dir_name, &enumFileInfo->fileListTemp, winfilter, alphasort); + if (cnt < 0) + { + break; + } + log_warning("found %d files matching in dir '%s'", cnt, dir_name); + enumFileInfo->cnt = cnt; + enumFileInfo->paths = malloc(cnt * sizeof(char *)); + char **paths = enumFileInfo->paths; + // 256 is size of dirent.d_name + const int buf_len = min(MAX_PATH, 256); + const int dir_name_len = strnlen(dir_name, MAX_PATH); + char separator[] = {platform_get_path_separator(), 0}; + for (int idx = 0; idx < cnt; idx++) + { + struct dirent *d = enumFileInfo->fileListTemp[idx]; + const int entry_len = strnlen(d->d_name, MAX_PATH); + // 1 for separator, 1 for trailing null + size_t path_len = sizeof(char) * min(MAX_PATH, entry_len + dir_name_len + 2); + paths[idx] = malloc(path_len); + paths[idx][0] = '\0'; + log_verbose("dir_name: %s", dir_name); + strncat(paths[idx], dir_name, path_len - 2); + strncat(paths[idx], separator, path_len - strnlen(paths[idx], path_len) - 1); + strncat(paths[idx], d->d_name, path_len - strnlen(paths[idx], path_len) - 1); + log_verbose("paths[%d] = %s", idx, paths[idx]); + } + enumFileInfo->handle = 0; + enumFileInfo->active = 1; + free(dir_name); + free(g_file_pattern); + g_file_pattern = NULL; + free(wpattern); + free(npattern); + return i; + } + } + + free(dir_name); + free(g_file_pattern); + g_file_pattern = NULL; + free(wpattern); + free(npattern); + return -1; +} + +bool platform_enumerate_files_next(int handle, file_info *outFileInfo) +{ + + if (handle < 0) + { + return false; + } + enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle]; + bool result; + + if (enumFileInfo->handle < enumFileInfo->cnt) { + result = true; + } else { + result = false; + } + + if (result) { + int entryIdx = enumFileInfo->handle++; + struct stat fileInfo; + log_verbose("trying handle %d", entryIdx); + char *fileName = enumFileInfo->paths[entryIdx]; + int statRes; + statRes = stat(fileName, &fileInfo); + if (statRes == -1) { + log_error("failed to stat file '%s'! errno = %i", fileName, errno); + return false; + } + outFileInfo->path = basename(fileName); + outFileInfo->size = fileInfo.st_size; + outFileInfo->last_modified = fileInfo.st_mtime; + return true; + } else { + return false; + } +} + +void platform_enumerate_files_end(int handle) +{ + if (handle < 0) + { + return; + } + enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle]; + int cnt = enumFileInfo->cnt; + for (int i = 0; i < cnt; i++) { + free(enumFileInfo->fileListTemp[i]); + free(enumFileInfo->paths[i]); + } + free(enumFileInfo->fileListTemp); + free(enumFileInfo->paths); + // FIXME: this here could have a bug + enumFileInfo->fileListTemp = NULL; + enumFileInfo->handle = 0; + enumFileInfo->active = 0; +} + +static int dirfilter(const struct dirent *d) +{ + if (d->d_name[0] == '.') { + return 0; + } +#if defined(_DIRENT_HAVE_D_TYPE) || defined(DT_UNKNOWN) + if (d->d_type == DT_DIR) + { + return 1; + } else { + return 0; + } +#else +#error implement dirfilter! +#endif // defined(_DIRENT_HAVE_D_TYPE) || defined(DT_UNKNOWN) +} + +int platform_enumerate_directories_begin(const utf8 *directory) +{ + enumerate_file_info *enumFileInfo; + wchar_t *wpattern = utf8_to_widechar(directory); + int length = min(utf8_length(directory), MAX_PATH); + char *npattern = malloc(length+1); + int converted; + converted = wcstombs(npattern, wpattern, length); + npattern[length] = '\0'; + if (converted == MAX_PATH) { + log_warning("truncated string %s", npattern); + } + log_warning("begin directory listing, path: %s", npattern); + + // TODO: add some checking for stringness and directoryness + + int cnt; + for (int i = 0; i < countof(_enumerateFileInfoList); i++) { + enumFileInfo = &_enumerateFileInfoList[i]; + if (!enumFileInfo->active) { + safe_strncpy(enumFileInfo->pattern, npattern, length); + cnt = scandir(npattern, &enumFileInfo->fileListTemp, dirfilter, alphasort); + if (cnt < 0) + { + break; + } + log_warning("found %d files in dir '%s'", cnt, npattern); + enumFileInfo->cnt = cnt; + enumFileInfo->paths = malloc(cnt * sizeof(char *)); + char **paths = enumFileInfo->paths; + // 256 is size of dirent.d_name + const int buf_len = min(MAX_PATH, 256); + const int dir_name_len = strnlen(npattern, MAX_PATH); + char separator[] = {platform_get_path_separator(), 0}; + for (int idx = 0; idx < cnt; idx++) + { + struct dirent *d = enumFileInfo->fileListTemp[idx]; + const int entry_len = strnlen(d->d_name, MAX_PATH); + // 1 for separator, 1 for trailing null + size_t path_len = sizeof(char) * min(MAX_PATH, entry_len + dir_name_len + 2); + paths[idx] = malloc(path_len); + paths[idx][0] = '\0'; + log_verbose("dir_name: %s", npattern); + strncat(paths[idx], npattern, path_len - 2); + strncat(paths[idx], separator, path_len - strnlen(paths[idx], path_len) - 1); + strncat(paths[idx], d->d_name, path_len - strnlen(paths[idx], path_len) - 1); + log_verbose("paths[%d] = %s", idx, paths[idx]); + } + enumFileInfo->handle = 0; + enumFileInfo->active = 1; + free(wpattern); + free(npattern); + return i; + } + } + + free(wpattern); + free(npattern); + return -1; +} + +bool platform_enumerate_directories_next(int handle, utf8 *path) +{ + if (handle < 0) + { + return false; + } + + bool result; + enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle]; + + log_verbose("handle = %d", handle); + if (enumFileInfo->handle < enumFileInfo->cnt) { + result = true; + } else { + result = false; + } + + if (result) { + int entryIdx = enumFileInfo->handle++; + struct stat fileInfo; + char *fileName = enumFileInfo->paths[entryIdx]; + int statRes; + statRes = stat(fileName, &fileInfo); + if (statRes == -1) { + log_error("failed to stat file '%s'! errno = %i", fileName, errno); + return false; + } + // so very, very wrong + safe_strncpy(path, basename(fileName), MAX_PATH); + strncat(path, "/", MAX_PATH - strlen(path) - 1); + return true; + } else { + return false; + } +} + +void platform_enumerate_directories_end(int handle) +{ + if (handle < 0) + { + return; + } + enumerate_file_info *enumFileInfo = &_enumerateFileInfoList[handle]; + int cnt = enumFileInfo->cnt; + for (int i = 0; i < cnt; i++) { + free(enumFileInfo->fileListTemp[i]); + free(enumFileInfo->paths[i]); + } + free(enumFileInfo->fileListTemp); + free(enumFileInfo->paths); + // FIXME: this here could have a bug + enumFileInfo->fileListTemp = NULL; + enumFileInfo->handle = 0; + enumFileInfo->active = 0; +} + +int platform_get_drives(){ + /* + return GetLogicalDrives(); + */ + STUB(); + return 0; +} + +bool platform_file_copy(const utf8 *srcPath, const utf8 *dstPath, bool overwrite) +{ + STUB(); + return 0; +} + +bool platform_file_move(const utf8 *srcPath, const utf8 *dstPath) +{ + STUB(); + return 0; +} + +bool platform_file_delete(const utf8 *path) +{ + STUB(); + return 0; +} + +wchar_t *regular_to_wchar(const char* src) +{ + int len = strnlen(src, MAX_PATH); + wchar_t *w_buffer = malloc((len + 1) * sizeof(wchar_t)); + mbtowc (NULL, NULL, 0); /* reset mbtowc */ + + int max = len; + int i = 0; + while (max > 0) + { + int length; + length = mbtowc(&w_buffer[i], &src[i], max); + if (length < 1) + { + w_buffer[i + 1] = '\0'; + break; + } + i += length; + max -= length; + } + return w_buffer; +} + +/** + * Default directory fallback is: + * - (command line argument) + * - $XDG_CONFIG_HOME/OpenRCT2 + * - /home/[uid]/.config/OpenRCT2 + */ +void platform_resolve_user_data_path() +{ + const char separator[2] = { platform_get_path_separator(), 0 }; + + if (gCustomUserDataPath[0] != 0) { + realpath(gCustomUserDataPath, _userDataDirectoryPath); + + // Ensure path ends with separator + int len = strlen(_userDataDirectoryPath); + if (_userDataDirectoryPath[len - 1] != separator[0]) { + strncat(_userDataDirectoryPath, separator, MAX_PATH - 1); + } + return; + } + + char buffer[MAX_PATH]; + buffer[0] = '\0'; + log_verbose("buffer = '%s'", buffer); + const char *homedir = getenv("XDG_CONFIG_HOME"); + log_verbose("homedir = '%s'", homedir); + if (homedir == NULL) + { + homedir = getpwuid(getuid())->pw_dir; + log_verbose("homedir was null, used getuid, now is = '%s'", homedir); + if (homedir == NULL) + { + log_fatal("Couldn't find user data directory"); + exit(-1); + return; + } + + strncat(buffer, homedir, MAX_PATH - 1); + strncat(buffer, separator, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); + strncat(buffer, ".config", MAX_PATH - strnlen(buffer, MAX_PATH) - 1); + } + else + { + strncat(buffer, homedir, MAX_PATH - 1); + } + strncat(buffer, separator, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); + strncat(buffer, "OpenRCT2", MAX_PATH - strnlen(buffer, MAX_PATH) - 1); + strncat(buffer, separator, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); + log_verbose("OpenRCT2 user data directory = '%s'", buffer); + int len = strnlen(buffer, MAX_PATH); + wchar_t *w_buffer = regular_to_wchar(buffer); + w_buffer[len] = '\0'; + utf8 *path = widechar_to_utf8(w_buffer); + free(w_buffer); + safe_strncpy(_userDataDirectoryPath, path, MAX_PATH); + free(path); +} + +void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory) +{ + const char separator[2] = { platform_get_path_separator(), 0 }; + char buffer[MAX_PATH]; + safe_strncpy(buffer, _userDataDirectoryPath, sizeof(buffer)); + if (subDirectory != NULL && subDirectory[0] != 0) { + log_verbose("adding subDirectory '%s'", subDirectory); + strncat(buffer, subDirectory, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); + strncat(buffer, separator, MAX_PATH - strnlen(buffer, MAX_PATH) - 1); + } + int len = strnlen(buffer, MAX_PATH); + wchar_t *w_buffer = regular_to_wchar(buffer); + w_buffer[len] = '\0'; + utf8 *path = widechar_to_utf8(w_buffer); + free(w_buffer); + safe_strncpy(outPath, path, MAX_PATH); + free(path); + log_verbose("outPath + subDirectory = '%s'", buffer); +} + +void platform_show_messagebox(char *message) +{ + STUB(); + log_warning(message); +} + +/** + * + * rct2: 0x004080EA + */ +int platform_open_common_file_dialog(int type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) +{ + STUB(); + return 0; +} + +utf8 *platform_open_directory_browser(utf8 *title) +{ + STUB(); + return NULL; +} + +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; + } + else if (strcmp(langCode, "POR") == 0){ + return LANGUAGE_PORTUGUESE_BR; + } + */ + STUB(); + return LANGUAGE_ENGLISH_UK; +} + +time_t platform_file_get_modified_time(const utf8* path){ + struct stat buf; + if (stat(path, &buf) == 0) { + return buf.st_mtime; + } + return 100; +} + +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; + } + */ + STUB(); + 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; + }*/ + STUB(); + return MEASUREMENT_FORMAT_METRIC; +} + +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; + } + */ + STUB(); + return TEMPERATURE_FORMAT_C; +} + +#endif diff --git a/src/platform/shared.c b/src/platform/shared.c index 6e2ea0cf26..bc92131204 100644 --- a/src/platform/shared.c +++ b/src/platform/shared.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 @@ -18,30 +18,39 @@ * along with this program. If not, see . *****************************************************************************/ -#include -#include #include "../addresses.h" +#include "../audio/audio.h" +#include "../audio/mixer.h" #include "../config.h" #include "../cursors.h" #include "../drawing/drawing.h" +#include "../game.h" #include "../interface/console.h" #include "../interface/keyboard_shortcut.h" #include "../interface/window.h" #include "../input.h" +#include "../localisation/localisation.h" #include "../openrct2.h" +#include "../title.h" +#include "../util/util.h" #include "platform.h" -typedef void(*update_palette_func)(char*, int, int); +typedef void(*update_palette_func)(const uint8*, int, int); openrct2_cursor gCursorState; const unsigned char *gKeysState; unsigned char *gKeysPressed; unsigned int gLastKeyPressed; -char* gTextInput; +utf8 *gTextInput; int gTextInputLength; int gTextInputMaxLength; int gTextInputCursorPosition = 0; +bool gTextInputCompositionActive; +utf8 gTextInputComposition[32]; +int gTextInputCompositionStart; +int gTextInputCompositionLength; + int gNumResolutions = 0; resolution *gResolutions = NULL; int gResolutionsAllowAnyAspectRatio = 0; @@ -52,9 +61,13 @@ SDL_Texture *gBufferTexture = NULL; SDL_PixelFormat *gBufferTextureFormat = NULL; SDL_Color gPalette[256]; uint32 gPaletteHWMapped[256]; +bool gHardwareDisplay; -static SDL_Surface *_surface; -static SDL_Palette *_palette; +bool gSteamOverlayActive = false; + +static SDL_Surface *_surface = NULL; +static SDL_Surface *_RGBASurface = NULL; +static SDL_Palette *_palette = NULL; static void *_screenBuffer; static int _screenBufferSize; @@ -67,6 +80,9 @@ static const int _fullscreen_modes[] = { 0, SDL_WINDOW_FULLSCREEN, SDL_WINDOW_FU static unsigned int _lastGestureTimestamp; static float _gestureRadius; +static uint32 _pixelBeforeOverlay; +static uint32 _pixelAfterOverlay; + static void platform_create_window(); static void platform_load_cursors(); static void platform_unload_cursors(); @@ -111,7 +127,7 @@ void platform_update_fullscreen_resolutions() 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; @@ -173,64 +189,126 @@ void platform_get_closest_resolution(int inWidth, int inHeight, int *outWidth, i } } +static void read_center_pixel(int width, int height, uint32 *pixel) { + SDL_Rect centerPixelRegion = {width / 2, height / 2, 1, 1}; + SDL_RenderReadPixels(gRenderer, ¢erPixelRegion, SDL_PIXELFORMAT_RGBA8888, pixel, sizeof(uint32)); +} + +// Should be called before SDL_RenderPresent to capture frame buffer before Steam overlay is drawn. +static void overlay_pre_render_check(int width, int height) { + read_center_pixel(width, height, &_pixelBeforeOverlay); +} + +// Should be called after SDL_RenderPresent, when Steam overlay has had the chance to be drawn. +static void overlay_post_render_check(int width, int height) { + static bool overlayActive = false; + static bool pausedBeforeOverlay = false; + + read_center_pixel(width, height, &_pixelAfterOverlay); + + // Detect an active Steam overlay by checking if the center pixel is changed by the gray fade. + // Will not be triggered by applications rendering to corners, like FRAPS, MSI Afterburner and Friends popups. + bool newOverlayActive = _pixelBeforeOverlay != _pixelAfterOverlay; + + // Toggle game pause state consistently with base pause state + if (!overlayActive && newOverlayActive) { + pausedBeforeOverlay = RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint32) & 1; + + if (!pausedBeforeOverlay) pause_toggle(); + } else if (overlayActive && !newOverlayActive && !pausedBeforeOverlay) { + pause_toggle(); + } + + overlayActive = newOverlayActive; +} + void platform_draw() { - int width = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); - int height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16); + int width = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); + int height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16); - 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; + if (!gOpenRCT2Headless) { + if (gHardwareDisplay) { + 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_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; + SDL_RenderCopy(gRenderer, gBufferTexture, NULL, NULL); + + if (gSteamOverlayActive && gConfigGeneral.steam_overlay_pause) { + overlay_pre_render_check(width, height); + } + + SDL_RenderPresent(gRenderer); + + if (gSteamOverlayActive && gConfigGeneral.steam_overlay_pause) { + overlay_post_render_check(width, height); } } + 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); + // 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); + // 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); + // Copy the surface to the window + if (gConfigGeneral.window_scale == 1 || gConfigGeneral.window_scale <= 0) + { + if (SDL_BlitSurface(_surface, NULL, SDL_GetWindowSurface(gWindow), NULL)) { + log_fatal("SDL_BlitSurface %s", SDL_GetError()); + exit(1); + } + } else { + // first blit to rgba surface to change the pixel format + if (SDL_BlitSurface(_surface, NULL, _RGBASurface, NULL)) { + log_fatal("SDL_BlitSurface %s", SDL_GetError()); + exit(1); + } + // then scale to window size. Without changing to RGBA first, SDL complains + // about blit configurations being incompatible. + if (SDL_BlitScaled(_RGBASurface, NULL, SDL_GetWindowSurface(gWindow), NULL)) { + log_fatal("SDL_BlitScaled %s", SDL_GetError()); + exit(1); + } + } + if (SDL_UpdateWindowSurface(gWindow)) { + log_fatal("SDL_UpdateWindowSurface %s", SDL_GetError()); + exit(1); + } } } } @@ -238,25 +316,29 @@ void platform_draw() static void platform_resize(int width, int height) { uint32 flags; + int dst_w = (int)(width / gConfigGeneral.window_scale); + int dst_h = (int)(height / gConfigGeneral.window_scale); - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) = width; - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) = height; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) = dst_w; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) = dst_h; platform_refresh_video(); flags = SDL_GetWindowFlags(gWindow); if ((flags & SDL_WINDOW_MINIMIZED) == 0) { - window_resize_gui(width, height); - window_relocate_windows(width, height); + window_resize_gui(dst_w, dst_h); + window_relocate_windows(dst_w, dst_h); } + title_fix_location(); 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) { + const int nonWindowFlags = + SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP; + if (!(flags & nonWindowFlags)) { if (width != gConfigGeneral.window_width || height != gConfigGeneral.window_height) { gConfigGeneral.window_width = width; gConfigGeneral.window_height = height; @@ -265,23 +347,62 @@ static void platform_resize(int width, int height) } } -void platform_update_palette(char* colours, int start_index, int num_colours) +void platform_trigger_resize() +{ + int w, h; + SDL_GetWindowSize(gWindow, &w, &h); + platform_resize(w, h); +} + +static uint8 soft_light(uint8 a, uint8 b) +{ + float fa = a / 255.0f; + float fb = b / 255.0f; + float fr; + if (fb < 0.5f) { + fr = (2 * fa * fb) + ((fa * fa) * (1 - (2 * fb))); + } else { + fr = (2 * fa * (1 - fb)) + (sqrtf(fa) * ((2 * fb) - 1)); + } + return (uint8)(clamp(0.0f, fr, 1.0f) * 255.0f); +} + +static uint8 lerp(uint8 a, uint8 b, float t) +{ + if (t <= 0) return a; + if (t >= 1) return b; + + int range = b - a; + int amount = (int)(range * t); + return (uint8)(a + amount); +} + +void platform_update_palette(const uint8* colours, int start_index, int num_colours) { SDL_Surface *surface; int i; + colours += start_index * 4; - for (i = 0; i < 256; i++) { + for (i = start_index; i < num_colours + start_index; i++) { gPalette[i].r = colours[2]; gPalette[i].g = colours[1]; gPalette[i].b = colours[0]; gPalette[i].a = 0; + + float night = gDayNightCycle; + if (night >= 0 && RCT2_GLOBAL(RCT2_ADDRESS_LIGHTNING_ACTIVE, uint8) == 0) { + gPalette[i].r = lerp(gPalette[i].r, soft_light(gPalette[i].r, 8), night); + gPalette[i].g = lerp(gPalette[i].g, soft_light(gPalette[i].g, 8), night); + gPalette[i].b = lerp(gPalette[i].b, soft_light(gPalette[i].b, 128), night); + } + colours += 4; if (gBufferTextureFormat != NULL) { gPaletteHWMapped[i] = SDL_MapRGB(gBufferTextureFormat, gPalette[i].r, gPalette[i].g, gPalette[i].b); } } - if (!gOpenRCT2Headless && !gConfigGeneral.hardware_display) { + if (!gOpenRCT2Headless && !gHardwareDisplay) { surface = SDL_GetWindowSurface(gWindow); if (!surface) { log_fatal("SDL_GetWindowSurface failed %s", SDL_GetError()); @@ -315,13 +436,21 @@ void platform_process_messages() case SDL_WINDOWEVENT: if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) platform_resize(e.window.data1, e.window.data2); + if (gConfigSound.audio_focus && gConfigSound.sound) { + if (e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) { + Mixer_SetVolume(1); + } + if (e.window.event == SDL_WINDOWEVENT_FOCUS_LOST) { + Mixer_SetVolume(0); + } + } break; case SDL_MOUSEMOTION: - RCT2_GLOBAL(0x0142406C, int) = e.motion.x; - RCT2_GLOBAL(0x01424070, int) = e.motion.y; + RCT2_GLOBAL(0x0142406C, int) = (int)(e.motion.x / gConfigGeneral.window_scale); + RCT2_GLOBAL(0x01424070, int) = (int)(e.motion.y / gConfigGeneral.window_scale); - gCursorState.x = e.motion.x; - gCursorState.y = e.motion.y; + gCursorState.x = (int)(e.motion.x / gConfigGeneral.window_scale); + gCursorState.y = (int)(e.motion.y / gConfigGeneral.window_scale); break; case SDL_MOUSEWHEEL: if (gConsoleOpen) { @@ -331,8 +460,8 @@ void platform_process_messages() gCursorState.wheel += e.wheel.y * 128; break; case SDL_MOUSEBUTTONDOWN: - RCT2_GLOBAL(0x01424318, int) = e.button.x; - RCT2_GLOBAL(0x0142431C, int) = e.button.y; + RCT2_GLOBAL(0x01424318, int) = (int)(e.button.x / gConfigGeneral.window_scale); + RCT2_GLOBAL(0x0142431C, int) = (int)(e.button.y / gConfigGeneral.window_scale); switch (e.button.button) { case SDL_BUTTON_LEFT: store_mouse_input(1); @@ -350,8 +479,8 @@ void platform_process_messages() } break; case SDL_MOUSEBUTTONUP: - RCT2_GLOBAL(0x01424318, int) = e.button.x; - RCT2_GLOBAL(0x0142431C, int) = e.button.y; + RCT2_GLOBAL(0x01424318, int) = (int)(e.button.x / gConfigGeneral.window_scale); + RCT2_GLOBAL(0x0142431C, int) = (int)(e.button.y / gConfigGeneral.window_scale); switch (e.button.button) { case SDL_BUTTON_LEFT: store_mouse_input(2); @@ -369,6 +498,8 @@ void platform_process_messages() } break; case SDL_KEYDOWN: + if (gTextInputCompositionActive) break; + if (e.key.keysym.sym == SDLK_KP_ENTER){ // Map Keypad enter to regular enter. e.key.keysym.scancode = SDL_SCANCODE_RETURN; @@ -387,14 +518,22 @@ void platform_process_messages() // 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){ + if (e.key.keysym.sym == SDLK_BACKSPACE && gTextInputLength > 0 && gTextInput != NULL && gTextInputCursorPosition) { + int dstIndex = gTextInputCursorPosition; + do { + if (dstIndex == 0) break; + dstIndex--; + } while (!utf8_is_codepoint_start(&gTextInput[dstIndex])); + int removedCodepointSize = gTextInputCursorPosition - dstIndex; + // 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 (gTextInputCursorPosition != gTextInputMaxLength) { + memmove(gTextInput + dstIndex, gTextInput + gTextInputCursorPosition, gTextInputMaxLength - dstIndex); + } + gTextInput[gTextInputLength - removedCodepointSize] = '\0'; + gTextInputCursorPosition -= removedCodepointSize; + gTextInputLength -= removedCodepointSize; console_refresh_caret(); window_update_textbox(); } @@ -402,46 +541,58 @@ void platform_process_messages() gTextInputCursorPosition = gTextInputLength; console_refresh_caret(); } - if (e.key.keysym.sym == SDLK_HOME){ + 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--; + if (e.key.keysym.sym == SDLK_DELETE && gTextInputLength > 0 && gTextInput != NULL && gTextInputCursorPosition != gTextInputLength) { + int dstIndex = gTextInputCursorPosition; + do { + if (dstIndex == gTextInputLength) break; + dstIndex++; + } while (!utf8_is_codepoint_start(&gTextInput[dstIndex])); + int removedCodepointSize = dstIndex - gTextInputCursorPosition; + + memmove(gTextInput + gTextInputCursorPosition, gTextInput + dstIndex, gTextInputMaxLength - dstIndex); + gTextInput[gTextInputMaxLength - removedCodepointSize] = '\0'; + gTextInputLength -= removedCodepointSize; console_refresh_caret(); window_update_textbox(); } - if (e.key.keysym.sym == SDLK_RETURN && gTextInput) { + if (e.key.keysym.sym == SDLK_RETURN && gTextInput != NULL) { window_cancel_textbox(); } - if (e.key.keysym.sym == SDLK_LEFT && gTextInput){ - if (gTextInputCursorPosition) gTextInputCursorPosition--; + if (e.key.keysym.sym == SDLK_LEFT && gTextInput != NULL) { + do { + if (gTextInputCursorPosition == 0) break; + gTextInputCursorPosition--; + } while (!utf8_is_codepoint_start(&gTextInput[gTextInputCursorPosition])); console_refresh_caret(); } - else if (e.key.keysym.sym == SDLK_RIGHT && gTextInput){ - if (gTextInputCursorPosition < gTextInputLength) gTextInputCursorPosition++; + else if (e.key.keysym.sym == SDLK_RIGHT && gTextInput != NULL) { + do { + if (gTextInputCursorPosition == gTextInputLength) break; + gTextInputCursorPosition++; + } while (!utf8_is_codepoint_start(&gTextInput[gTextInputCursorPosition])); console_refresh_caret(); } - // Checks GUI modifier key for Macs otherwise ctrl key + // 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 if (e.key.keysym.sym == SDLK_v && SDL_GetModState() & KMOD_GUI && gTextInput != NULL) { #else - else if (e.key.keysym.sym == SDLK_v && SDL_GetModState() & KMOD_CTRL && gTextInput) { + else if (e.key.keysym.sym == SDLK_v && SDL_GetModState() & KMOD_CTRL && gTextInput != NULL) { #endif if (SDL_HasClipboardText()) { - char* text = SDL_GetClipboardText(); - + utf8 *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]; } - else gTextInput[gTextInputLength++] = text[i]; - gTextInputCursorPosition++; } window_update_textbox(); @@ -457,7 +608,7 @@ void platform_process_messages() // Zoom gesture const int tolerance = 128; - int gesturePixels = (int)(_gestureRadius * RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16)); + int gesturePixels = (int)(_gestureRadius * RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16)); if (gesturePixels > tolerance) { _gestureRadius = 0; keyboard_shortcut_handle_command(SHORTCUT_ZOOM_VIEW_IN); @@ -467,29 +618,33 @@ void platform_process_messages() } } break; - + case SDL_TEXTEDITING: + safe_strncpy(gTextInputComposition, e.edit.text, min(e.edit.length, 32)); + gTextInputCompositionStart = e.edit.start; + gTextInputCompositionLength = e.edit.length; + gTextInputCompositionActive = gTextInputComposition[0] != 0; + break; case SDL_TEXTINPUT: if (gTextInputLength < gTextInputMaxLength && gTextInput){ - // Convert the utf-8 code into rct ascii - char new_char; + // HACK ` will close console, so don't input any text 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); + + utf8 *newText = e.text.text; + int newTextLength = strlen(newText); // 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++; + if (gTextInputLength > gTextInputCursorPosition) { + memmove(gTextInput + gTextInputCursorPosition + newTextLength, gTextInput + gTextInputCursorPosition, gTextInputMaxLength - gTextInputCursorPosition - newTextLength); + memcpy(&gTextInput[gTextInputCursorPosition], newText, newTextLength); + gTextInputLength += newTextLength; } else { - gTextInput[gTextInputLength++] = new_char; + memcpy(&gTextInput[gTextInputLength], newText, newTextLength); + gTextInputLength += newTextLength; gTextInput[gTextInputLength] = 0; } - gTextInputCursorPosition++; + gTextInputCursorPosition += newTextLength; console_refresh_caret(); window_update_textbox(); } @@ -514,6 +669,8 @@ static void platform_close_window() SDL_FreeSurface(_surface); if (_palette != NULL) SDL_FreePalette(_palette); + if (_RGBASurface != NULL) + SDL_FreeSurface(_RGBASurface); platform_unload_cursors(); } @@ -522,6 +679,14 @@ void platform_init() platform_create_window(); gKeysPressed = malloc(sizeof(unsigned char) * 256); memset(gKeysPressed, 0, sizeof(unsigned char) * 256); + + // Set the highest palette entry to white. + // This fixes a bug with the TT:rainbow road due to the + // image not using the correct white palette entry. + gPalette[255].a = 0; + gPalette[255].r = 255; + gPalette[255].g = 255; + gPalette[255].b = 255; } static void platform_create_window() @@ -534,6 +699,7 @@ static void platform_create_window() } SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, 0); + SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, gConfigGeneral.minimize_fullscreen_focus_loss ? "1" : "0"); platform_load_cursors(); @@ -549,6 +715,8 @@ static void platform_create_window() RCT2_GLOBAL(0x009E2D8C, sint32) = 0; + gHardwareDisplay = gConfigGeneral.hardware_display; + // 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 @@ -566,13 +734,16 @@ static void platform_create_window() platform_update_fullscreen_resolutions(); platform_set_fullscreen_mode(gConfigGeneral.fullscreen_mode); + + // Check if steam overlay renderer is loaded into the process + gSteamOverlayActive = platform_check_steam_overlay_attached(); } 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 + // 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') @@ -591,6 +762,10 @@ void platform_free() void platform_start_text_input(char* buffer, int max_length) { + // TODO This doesn't work, and position could be improved to where text entry is + SDL_Rect rect = { 10, 10, 100, 100 }; + SDL_SetTextInputRect(&rect); + SDL_StartTextInput(); gTextInputMaxLength = max_length - 1; gTextInput = buffer; @@ -645,6 +820,7 @@ void platform_set_fullscreen_mode(int mode) */ void platform_set_cursor(char cursor) { + RCT2_GLOBAL(RCT2_ADDRESS_CURENT_CURSOR, uint8) = cursor; SDL_SetCursor(_cursors[cursor]); } /** @@ -654,6 +830,7 @@ void platform_set_cursor(char cursor) static void platform_load_cursors() { RCT2_GLOBAL(0x14241BC, uint32) = 2; +#ifdef _WIN32 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)); @@ -682,6 +859,9 @@ static void platform_load_cursors() 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)); +#else + STUB(); +#endif // _WIN32 _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); @@ -714,26 +894,26 @@ static void platform_load_cursors() 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); + int width = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); + int height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16); - if (gConfigGeneral.hardware_display) { + SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, gConfigGeneral.minimize_fullscreen_focus_loss ? "1" : "0"); + + log_verbose("HardwareDisplay: %s", gHardwareDisplay ? "true" : "false"); + + if (gHardwareDisplay) { if (gRenderer == NULL) - gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED); + gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + + if (gRenderer == NULL) { + log_warning("SDL_CreateRenderer failed: %s", SDL_GetError()); + log_warning("Falling back to software rendering..."); + gHardwareDisplay = false; + platform_refresh_video(); // try again without hardware rendering + return; + } if (gBufferTexture != NULL) SDL_DestroyTexture(gBufferTexture); @@ -750,23 +930,31 @@ void platform_refresh_video() 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); + // Load the current palette into the HWmapped version. + for (int i = 0; i < 256; ++i) { + gPaletteHWMapped[i] = SDL_MapRGB(gBufferTextureFormat, gPalette[i].r, gPalette[i].g, gPalette[i].b); + } } else { if (_surface != NULL) SDL_FreeSurface(_surface); + if (_RGBASurface != NULL) + SDL_FreeSurface(_RGBASurface); if (_palette != NULL) SDL_FreePalette(_palette); _surface = SDL_CreateRGBSurface(0, width, height, 8, 0, 0, 0, 0); + _RGBASurface = SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0); + SDL_SetSurfaceBlendMode(_RGBASurface, SDL_BLENDMODE_NONE); _palette = SDL_AllocPalette(256); - if (!_surface || !_palette) { - log_fatal("%p || %p == NULL %s", _surface, _palette, SDL_GetError()); + if (!_surface || !_palette || !_RGBASurface) { + log_fatal("%p || %p || %p == NULL %s", _surface, _palette, _RGBASurface, SDL_GetError()); exit(-1); } @@ -826,8 +1014,33 @@ static void platform_refresh_screenbuffer(int width, int height, int pitch) 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 + RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_WIDTH, uint16) = 64; + RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_HEIGHT, uint16) = 8; + RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_COLUMNS, uint32) = (width >> 6) + 1; + RCT2_GLOBAL(RCT2_ADDRESS_DIRTY_BLOCK_ROWS, uint32) = (height >> 3) + 1; +} + +void platform_hide_cursor() +{ + SDL_ShowCursor(SDL_DISABLE); +} + +void platform_show_cursor() +{ + SDL_ShowCursor(SDL_ENABLE); +} + +void platform_get_cursor_position(int *x, int *y) +{ + SDL_GetMouseState(x, y); +} + +void platform_set_cursor_position(int x, int y) +{ + SDL_WarpMouseInWindow(NULL, x, y); +} + +unsigned int platform_get_ticks() +{ + return SDL_GetTicks(); +} diff --git a/src/platform/windows.c b/src/platform/windows.c index b090bae968..17f96bb738 100644 --- a/src/platform/windows.c +++ b/src/platform/windows.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 @@ -21,20 +21,25 @@ #ifdef _WIN32 #include +#include #include #include +#include #include "../addresses.h" #include "../cmdline.h" #include "../openrct2.h" #include "../localisation/language.h" #include "../localisation/currency.h" +#include "../util/util.h" #include "../config.h" #include "platform.h" // The name of the mutex used to prevent multiple instances of the game from running #define SINGLE_INSTANCE_MUTEX_NAME "RollerCoaster Tycoon 2_GSKMUTEX" -LPSTR *CommandLineToArgvA(LPSTR lpCmdLine, int *argc); +utf8 _userDataDirectoryPath[MAX_PATH] = { 0 }; + +utf8 **windows_get_command_line_args(int *outNumArgs); /** * Windows entry point to OpenRCT2 without a console window. @@ -72,43 +77,132 @@ __declspec(dllexport) int StartOpenRCT(HINSTANCE hInstance, HINSTANCE hPrevInsta RCT2_GLOBAL(RCT2_ADDRESS_HINSTANCE, HINSTANCE) = hInstance; RCT2_GLOBAL(RCT2_ADDRESS_CMDLINE, LPSTR) = lpCmdLine; - // Get command line arguments in standard form - argv = CommandLineToArgvA(lpCmdLine, &argc); - runGame = cmdline_run(argv, argc); - GlobalFree(argv); + // argv = CommandLineToArgvA(lpCmdLine, &argc); + argv = (char**)windows_get_command_line_args(&argc); + runGame = cmdline_run((const char **)argv, argc); - if (runGame) + // Free argv + for (int i = 0; i < argc; i++) { + free(argv[i]); + } + free(argv); + + if (runGame) { openrct2_launch(); + } exit(gExitCode); return gExitCode; } +utf8 **windows_get_command_line_args(int *outNumArgs) +{ + int argc; + + // Get command line arguments as widechar + LPWSTR commandLine = GetCommandLineW(); + LPWSTR *argvW = CommandLineToArgvW(commandLine, &argc); + + // Convert to UTF-8 + utf8 **argvUtf8 = (utf8**)malloc(argc * sizeof(utf8*)); + for (int i = 0; i < argc; i++) { + argvUtf8[i] = widechar_to_utf8(argvW[i]); + } + LocalFree(argvW); + + *outNumArgs = argc; + return argvUtf8; +} + +void platform_get_date(rct2_date *out_date) +{ + assert(out_date != NULL); + SYSTEMTIME systime; + + GetSystemTime(&systime); + out_date->day = systime.wDay; + out_date->month = systime.wMonth; + out_date->year = systime.wYear; + out_date->day_of_week = systime.wDayOfWeek; +} + +void platform_get_time(rct2_time *out_time) +{ + assert(out_time != NULL); + SYSTEMTIME systime; + GetLocalTime(&systime); + out_time->hour = systime.wHour; + out_time->minute = systime.wMinute; + out_time->second = systime.wSecond; +} + char platform_get_path_separator() { return '\\'; } -int platform_file_exists(const char *path) +bool platform_file_exists(const utf8 *path) { - return !(GetFileAttributes(path) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND); + wchar_t *wPath = utf8_to_widechar(path); + DWORD result = GetFileAttributesW(wPath); + DWORD error = GetLastError(); + free(wPath); + return !(result == INVALID_FILE_ATTRIBUTES && (error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND)); } -int platform_directory_exists(const char *path) +bool platform_directory_exists(const utf8 *path) { - DWORD dwAttrib = GetFileAttributes(path); + wchar_t *wPath = utf8_to_widechar(path); + DWORD dwAttrib = GetFileAttributesW(wPath); + free(wPath); return dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY); } -int platform_ensure_directory_exists(const char *path) +bool platform_original_game_data_exists(const utf8 *path) +{ + utf8 checkPath[MAX_PATH]; + sprintf(checkPath, "%s%c%s%c%s", path, platform_get_path_separator(), "Data", platform_get_path_separator(), "g1.dat"); + return platform_file_exists(checkPath); +} + +bool platform_ensure_directory_exists(const utf8 *path) { if (platform_directory_exists(path)) return 1; - return CreateDirectory(path, NULL); + wchar_t *wPath = utf8_to_widechar(path); + BOOL success = CreateDirectoryW(wPath, NULL); + free(wPath); + return success == TRUE; } -int platform_lock_single_instance() +bool platform_directory_delete(const utf8 *path) +{ + wchar_t pszFrom[MAX_PATH]; + + wchar_t *wPath = utf8_to_widechar(path); + wcsncpy(pszFrom, wPath, MAX_PATH); + free(wPath); + + // Needs to be double-null terminated for some weird reason + pszFrom[wcslen(wPath) + 1] = 0; + + SHFILEOPSTRUCTW fileop; + fileop.hwnd = NULL; // no status display + fileop.wFunc = FO_DELETE; // delete operation + fileop.pFrom = pszFrom; // source file name as double null terminated string + fileop.pTo = NULL; // no destination needed + fileop.fFlags = FOF_NOCONFIRMATION | FOF_SILENT; // do not prompt the user + + fileop.fAnyOperationsAborted = FALSE; + fileop.lpszProgressTitle = NULL; + fileop.hNameMappings = NULL; + + int ret = SHFileOperationW(&fileop); + return (ret == 0); +} + +bool platform_lock_single_instance() { HANDLE mutex, status; @@ -120,67 +214,74 @@ int platform_lock_single_instance() if (status == NULL) log_error("unable to create mutex\n"); - return 1; + return true; } else { // Already running CloseHandle(mutex); - return 0; + return false; } } typedef struct { - char active; - char pattern[MAX_PATH]; + bool active; + wchar_t pattern[MAX_PATH]; HANDLE handle; - WIN32_FIND_DATAA data; + WIN32_FIND_DATAW data; + utf8 *outFilename; } enumerate_file_info; static enumerate_file_info _enumerateFileInfoList[8] = { 0 }; -int platform_enumerate_files_begin(const char *pattern) +int platform_enumerate_files_begin(const utf8 *pattern) { int i; enumerate_file_info *enumFileInfo; + wchar_t *wPattern = utf8_to_widechar(pattern); + for (i = 0; i < countof(_enumerateFileInfoList); i++) { enumFileInfo = &_enumerateFileInfoList[i]; if (!enumFileInfo->active) { - strncpy(enumFileInfo->pattern, pattern, MAX_PATH); + wcsncpy(enumFileInfo->pattern, wPattern, MAX_PATH); enumFileInfo->handle = NULL; - enumFileInfo->active = 1; + enumFileInfo->active = true; + enumFileInfo->outFilename = NULL; + + free(wPattern); return i; } } + free(wPattern); return INVALID_HANDLE; } -int platform_enumerate_files_next(int handle, file_info *outFileInfo) +bool platform_enumerate_files_next(int handle, file_info *outFileInfo) { - int result; + bool result; enumerate_file_info *enumFileInfo; HANDLE findFileHandle; enumFileInfo = &_enumerateFileInfoList[handle]; if (enumFileInfo->handle == NULL) { - findFileHandle = FindFirstFile(enumFileInfo->pattern, &enumFileInfo->data); + findFileHandle = FindFirstFileW(enumFileInfo->pattern, &enumFileInfo->data); if (findFileHandle != INVALID_HANDLE_VALUE) { enumFileInfo->handle = findFileHandle; - result = 1; + result = true; } else { - result = 0; + result = false; } } else { - result = FindNextFile(enumFileInfo->handle, &enumFileInfo->data); + result = FindNextFileW(enumFileInfo->handle, &enumFileInfo->data); } if (result) { - outFileInfo->path = enumFileInfo->data.cFileName; + outFileInfo->path = enumFileInfo->outFilename = widechar_to_utf8(enumFileInfo->data.cFileName); outFileInfo->size = ((uint64)enumFileInfo->data.nFileSizeHigh << 32ULL) | (uint64)enumFileInfo->data.nFileSizeLow; outFileInfo->last_modified = ((uint64)enumFileInfo->data.ftLastWriteTime.dwHighDateTime << 32ULL) | (uint64)enumFileInfo->data.ftLastWriteTime.dwLowDateTime; - return 1; + return true; } else { - return 0; + return false; } } @@ -193,32 +294,39 @@ void platform_enumerate_files_end(int handle) FindClose(enumFileInfo->handle); enumFileInfo->handle = NULL; } - enumFileInfo->active = 0; + enumFileInfo->active = false; + SafeFree(enumFileInfo->outFilename); } -int platform_enumerate_directories_begin(const char *directory) +int platform_enumerate_directories_begin(const utf8 *directory) { int i; enumerate_file_info *enumFileInfo; - if (strlen(directory) + 3 >= MAX_PATH) + wchar_t *wDirectory = utf8_to_widechar(directory); + + if (wcslen(wDirectory) + 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); + wcsncpy(enumFileInfo->pattern, wDirectory, MAX_PATH); + wcsncat(enumFileInfo->pattern, L"*", MAX_PATH); enumFileInfo->handle = NULL; - enumFileInfo->active = 1; + enumFileInfo->active = true; + enumFileInfo->outFilename = NULL; + + free(wDirectory); return i; } } + free(wDirectory); return INVALID_HANDLE; } -int platform_enumerate_directories_next(int handle, char *path) +bool platform_enumerate_directories_next(int handle, utf8 *path) { enumerate_file_info *enumFileInfo; HANDLE fileHandle; @@ -226,31 +334,32 @@ int platform_enumerate_directories_next(int handle, char *path) enumFileInfo = &_enumerateFileInfoList[handle]; if (enumFileInfo->handle == NULL) { - fileHandle = FindFirstFile(enumFileInfo->pattern, &enumFileInfo->data); + fileHandle = FindFirstFileW(enumFileInfo->pattern, &enumFileInfo->data); if (fileHandle != 0) { enumFileInfo->handle = fileHandle; } else { - return 0; + return false; } } else { - if (!FindNextFile(enumFileInfo->handle, &enumFileInfo->data)) { - return 0; + if (!FindNextFileW(enumFileInfo->handle, &enumFileInfo->data)) { + return false; } } while ( - (enumFileInfo->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 - || strchr(enumFileInfo->data.cFileName, '.') != NULL + (enumFileInfo->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 || + wcschr(enumFileInfo->data.cFileName, '.') != NULL ) { - if (!FindNextFile(enumFileInfo->handle, &enumFileInfo->data)) { - return 0; + if (!FindNextFileW(enumFileInfo->handle, &enumFileInfo->data)) { + return false; } } - - memset(path, '\0', MAX_PATH); - strncpy(path, enumFileInfo->data.cFileName, MAX_PATH); + + utf8 *filename = widechar_to_utf8(enumFileInfo->data.cFileName); + strncpy(path, filename, MAX_PATH); strncat(path, "\\", MAX_PATH); - return 1; + free(filename); + return true; } void platform_enumerate_directories_end(int handle) @@ -262,71 +371,93 @@ void platform_enumerate_directories_end(int handle) FindClose(enumFileInfo->handle); enumFileInfo->handle = NULL; } - enumFileInfo->active = 0; + enumFileInfo->active = false; } -int platform_file_copy(const char *srcPath, const char *dstPath) +int platform_get_drives() { - return CopyFileA(srcPath, dstPath, TRUE); + return GetLogicalDrives(); } -int platform_file_move(const char *srcPath, const char *dstPath) +bool platform_file_copy(const utf8 *srcPath, const utf8 *dstPath, bool overwrite) { - return MoveFileA(srcPath, dstPath); + wchar_t *wSrcPath = utf8_to_widechar(srcPath); + wchar_t *wDstPath = utf8_to_widechar(dstPath); + BOOL success = CopyFileW(wSrcPath, wDstPath, overwrite ? FALSE : TRUE); + free(wSrcPath); + free(wDstPath); + return success == TRUE; } -int platform_file_delete(const char *path) +bool platform_file_move(const utf8 *srcPath, const utf8 *dstPath) { - return DeleteFileA(path); + wchar_t *wSrcPath = utf8_to_widechar(srcPath); + wchar_t *wDstPath = utf8_to_widechar(dstPath); + BOOL success = MoveFileW(wSrcPath, wDstPath); + free(wSrcPath); + free(wDstPath); + return success == TRUE; } -void platform_hide_cursor() +bool platform_file_delete(const utf8 *path) { - ShowCursor(FALSE); + wchar_t *wPath = utf8_to_widechar(path); + BOOL success = DeleteFileW(wPath); + free(wPath); + return success == TRUE; } -void platform_show_cursor() +/** + * Default directory fallback is: + * - (command line argument) + * - C:\Users\%USERNAME%\OpenRCT2 (as from SHGetFolderPathW) + */ +void platform_resolve_user_data_path() { - ShowCursor(TRUE); -} + wchar_t wOutPath[MAX_PATH]; + const char separator[2] = { platform_get_path_separator(), 0 }; -void platform_get_cursor_position(int *x, int *y) -{ - POINT point; + if (gCustomUserDataPath[0] != 0) { + wchar_t *customUserDataPathW = utf8_to_widechar(gCustomUserDataPath); + if (GetFullPathNameW(customUserDataPathW, countof(wOutPath), wOutPath, NULL) == 0) { + log_fatal("Unable to resolve path '%s'.", gCustomUserDataPath); + exit(-1); + } + utf8 *outPathTemp = widechar_to_utf8(wOutPath); + safe_strncpy(_userDataDirectoryPath, outPathTemp, sizeof(_userDataDirectoryPath)); + free(outPathTemp); + free(customUserDataPathW); + + // Ensure path ends with separator + int len = strlen(_userDataDirectoryPath); + if (_userDataDirectoryPath[len - 1] != separator[0]) { + strcat(_userDataDirectoryPath, separator); + } + return; + } - if (GetCursorPos(&point)) { - *x = point.x; - *y = point.y; + if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, wOutPath))) { + utf8 *outPathTemp = widechar_to_utf8(wOutPath); + safe_strncpy(_userDataDirectoryPath, outPathTemp, sizeof(_userDataDirectoryPath)); + free(outPathTemp); + + strcat(_userDataDirectoryPath, separator); + strcat(_userDataDirectoryPath, "OpenRCT2"); + strcat(_userDataDirectoryPath, separator); } else { - *x = INT32_MIN; - *y = INT32_MIN; + log_fatal("Unable to resolve user data path."); + exit(-1); } } -void platform_set_cursor_position(int x, int y) +void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory) { - SetCursorPos(x, y); -} + const char separator[2] = { platform_get_path_separator(), 0 }; -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; + strcpy(outPath, _userDataDirectoryPath); + if (subDirectory != NULL && subDirectory[0] != 0) { + strcat(outPath, subDirectory); + strcat(outPath, separator); } } @@ -336,48 +467,57 @@ void platform_show_messagebox(char *message) } /** - * + * * rct2: 0x004080EA */ -int platform_open_common_file_dialog(int type, char *title, char *filename, char *filterPattern, char *filterName) +int platform_open_common_file_dialog(int type, utf8 *title, utf8 *filename, utf8 *filterPattern, utf8 *filterName) { - char initialDirectory[MAX_PATH], *dotAddress, *slashAddress; - OPENFILENAME openFileName; + wchar_t wctitle[256], wcfilename[MAX_PATH], wcfilterPattern[256], wcfilterName[256]; + wchar_t initialDirectory[MAX_PATH], *dotAddress, *slashAddress; + OPENFILENAMEW openFileName; BOOL result; int tmp; DWORD commonFlags; + MultiByteToWideChar(CP_UTF8, 0, title, -1, wctitle, countof(wctitle)); + MultiByteToWideChar(CP_UTF8, 0, filename, -1, wcfilename, countof(wcfilename)); + MultiByteToWideChar(CP_UTF8, 0, filterPattern, -1, wcfilterPattern, countof(wcfilterPattern)); + MultiByteToWideChar(CP_UTF8, 0, filterName, -1, wcfilterName, countof(wcfilterName)); + // Get directory path from given filename - strcpy(initialDirectory, filename); - dotAddress = strrchr(initialDirectory, '.'); + lstrcpyW(initialDirectory, wcfilename); + dotAddress = wcsrchr(initialDirectory, '.'); if (dotAddress != NULL) { - slashAddress = strrchr(initialDirectory, '\\'); + slashAddress = wcsrchr(initialDirectory, '\\'); if (slashAddress < dotAddress) *(slashAddress + 1) = 0; } // Clear filename if (type != 0) - *filename = 0; + wcfilename[0] = 0; // Set open file name options - memset(&openFileName, 0, sizeof(OPENFILENAME)); - openFileName.lStructSize = sizeof(OPENFILENAME); + memset(&openFileName, 0, sizeof(OPENFILENAMEW)); + openFileName.lStructSize = sizeof(OPENFILENAMEW); openFileName.hwndOwner = windows_get_window_handle(); - openFileName.lpstrFile = filename; + openFileName.lpstrFile = wcfilename; openFileName.nMaxFile = MAX_PATH; openFileName.lpstrInitialDir = initialDirectory; - openFileName.lpstrTitle = title; + openFileName.lpstrTitle = wctitle; // Copy filter name - strcpy((char*)0x01423800, filterName); + lstrcpyW((wchar_t*)0x01423800, wcfilterName); // Copy filter pattern - strcpy((char*)0x01423800 + strlen(filterName) + 1, filterPattern); - *((char*)(0x01423800 + strlen(filterName) + 1 + strlen(filterPattern) + 1)) = 0; - openFileName.lpstrFilter = (char*)0x01423800; + int wcfilterNameLength = lstrlenW(wcfilterName); + int wcfilterPatternLength = lstrlenW(wcfilterPattern); - // + lstrcpyW((wchar_t*)0x01423800 + wcfilterNameLength + 1, wcfilterPattern); + *((wchar_t*)((wchar_t*)0x01423800 + wcfilterNameLength + 1 + wcfilterPatternLength + 1)) = 0; + openFileName.lpstrFilter = (wchar_t*)0x01423800; + + // tmp = RCT2_GLOBAL(0x009E2C74, uint32); if (RCT2_GLOBAL(0x009E2BB8, uint32) == 2 && RCT2_GLOBAL(0x009E1AF8, uint32) == 1) RCT2_GLOBAL(0x009E2C74, uint32) = 1; @@ -386,25 +526,29 @@ int platform_open_common_file_dialog(int type, char *title, char *filename, char commonFlags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR; if (type == 0) { openFileName.Flags = commonFlags | OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT; - result = GetSaveFileName(&openFileName); + result = GetSaveFileNameW(&openFileName); } else if (type == 1) { openFileName.Flags = commonFlags | OFN_NONETWORKBUTTON | OFN_FILEMUSTEXIST; - result = GetOpenFileName(&openFileName); + result = GetOpenFileNameW(&openFileName); } - // + // RCT2_GLOBAL(0x009E2C74, uint32) = tmp; + WideCharToMultiByte(CP_UTF8, 0, wcfilename, countof(wcfilename), filename, MAX_PATH, NULL, NULL); + return result; } -char *platform_open_directory_browser(char *title) +utf8 *platform_open_directory_browser(utf8 *title) { - BROWSEINFO bi; - char pszBuffer[MAX_PATH]; + BROWSEINFOW bi; + wchar_t pszBuffer[MAX_PATH], wctitle[256]; LPITEMIDLIST pidl; LPMALLOC lpMalloc; + MultiByteToWideChar(CP_UTF8, 0, title, -1, wctitle, countof(wctitle)); + // Initialize COM if (FAILED(CoInitializeEx(0, COINIT_APARTMENTTHREADED))) { CoUninitialize(); @@ -424,19 +568,20 @@ char *platform_open_directory_browser(char *title) bi.hwndOwner = NULL; bi.pidlRoot = NULL; bi.pszDisplayName = pszBuffer; - bi.lpszTitle = title; + bi.lpszTitle = wctitle; bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS; bi.lpfn = NULL; bi.lParam = 0; - char *outPath = NULL; + utf8 *outPath = NULL; - if (pidl = SHBrowseForFolder(&bi)) { + if (pidl = SHBrowseForFolderW(&bi)) { // Copy the path directory to the buffer - if (SHGetPathFromIDList(pidl, pszBuffer)) { + if (SHGetPathFromIDListW(pidl, pszBuffer)) { // Store pszBuffer (and the path) in the outPath - outPath = (char*) malloc(strlen(pszBuffer)+1); - strcpy(outPath, pszBuffer); + int outPathCapacity = lstrlenW(pszBuffer) * 4 + 1; + outPath = (utf8*)malloc(outPathCapacity); + WideCharToMultiByte(CP_UTF8, 0, pszBuffer, countof(pszBuffer), outPath, outPathCapacity, NULL, NULL); } } CoUninitialize(); @@ -444,7 +589,7 @@ char *platform_open_directory_browser(char *title) } /** - * + * * rct2: 0x00407978 */ int windows_get_registry_install_info(rct2_install_info *installInfo, char *source, char *font, uint8 charset) @@ -458,7 +603,7 @@ int windows_get_registry_install_info(rct2_install_info *installInfo, char *sour strcat(subkeyInfogrames, source); strcpy(subkeyFishTechGroup, "Software\\Fish Technology Group\\"); strcat(subkeyFishTechGroup, source); - + memset(&lf, 0, sizeof(lf)); lf.lfCharSet = charset; lf.lfHeight = 12; @@ -466,22 +611,22 @@ int windows_get_registry_install_info(rct2_install_info *installInfo, char *sour 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++) { @@ -507,95 +652,19 @@ HWND windows_get_window_handle() log_error("SDL_GetWindowWMInfo failed %s", SDL_GetError()); exit(-1); } - return wmInfo.info.win.window; + HWND handle = wmInfo.info.win.window; + #ifdef __MINGW32__ + assert(sizeof(HWND) == sizeof(uint32)); + HWND result = (((uint32)handle & 0xff000000) >> 8) | (((uint32)handle & 0xff0000) << 8) | (((uint32)handle & 0xff00) >> 8) | (((uint32)handle & 0xff) << 8); + log_warning("twisting bits of handle, a workaround for mingw/sdl bug"); + #else + HWND result = handle; + #endif // __MINGW32__ + return result; } -/** - * http://alter.org.ua/en/docs/win/args/ - */ -PCHAR *CommandLineToArgvA(PCHAR CmdLine, int *_argc) +uint16 platform_get_locale_language() { - PCHAR* argv; - PCHAR _argv; - ULONG len; - ULONG argc; - CHAR a; - ULONG i, j; - - BOOLEAN in_QM; - BOOLEAN in_TEXT; - BOOLEAN in_SPACE; - - len = strlen(CmdLine); - i = ((len + 2) / 2)*sizeof(PVOID) + sizeof(PVOID); - - argv = (PCHAR*)GlobalAlloc(GMEM_FIXED, - i + (len + 2)*sizeof(CHAR) + 1); - - _argv = (PCHAR)(((PUCHAR)argv) + i); - - // 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; - in_SPACE = TRUE; - i = 0; - j = 0; - - while (a = CmdLine[i]) { - if (in_QM) { - if (a == '\"') { - in_QM = FALSE; - } else { - _argv[j] = a; - j++; - } - } else { - switch (a) { - case '\"': - in_QM = TRUE; - in_TEXT = TRUE; - if (in_SPACE) { - argv[argc] = _argv + j; - argc++; - } - in_SPACE = FALSE; - break; - case ' ': - case '\t': - case '\n': - case '\r': - if (in_TEXT) { - _argv[j] = '\0'; - j++; - } - in_TEXT = FALSE; - in_SPACE = TRUE; - break; - default: - in_TEXT = TRUE; - if (in_SPACE) { - argv[argc] = _argv + j; - argc++; - } - _argv[j] = a; - j++; - in_SPACE = FALSE; - break; - } - } - i++; - } - _argv[j] = '\0'; - argv[argc] = NULL; - - (*_argc) = argc; - return argv; -} - -uint16 platform_get_locale_language(){ CHAR langCode[4]; if (GetLocaleInfo(LOCALE_USER_DEFAULT, @@ -635,16 +704,42 @@ uint16 platform_get_locale_language(){ else if (strcmp(langCode, "ITA") == 0){ return LANGUAGE_ITALIAN; } + else if (strcmp(langCode, "POR") == 0){ + return LANGUAGE_PORTUGUESE_BR; + } + else if (strcmp(langCode, "FIN") == 0){ + return LANGUAGE_FINNISH; + } return LANGUAGE_UNDEFINED; } -uint8 platform_get_locale_currency(){ +time_t platform_file_get_modified_time(const utf8* path) +{ + WIN32_FILE_ATTRIBUTE_DATA data; + + wchar_t *wPath = utf8_to_widechar(path); + BOOL result = GetFileAttributesExW(wPath, GetFileExInfoStandard, &data); + free(wPath); + + if (result) { + ULARGE_INTEGER ull; + ull.LowPart = data.ftLastWriteTime.dwLowDateTime; + ull.HighPart = data.ftLastWriteTime.dwHighDateTime; + return ull.QuadPart / 10000000ULL - 11644473600ULL; + } else { + return 0; + } +} + +uint8 platform_get_locale_currency() +{ CHAR currCode[4]; if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SINTLSYMBOL, (LPSTR)&currCode, - sizeof(currCode)) == 0){ + sizeof(currCode)) == 0 + ) { return CURRENCY_POUNDS; } if (strcmp(currCode, "GBP") == 0){ @@ -680,15 +775,18 @@ uint8 platform_get_locale_currency(){ return CURRENCY_POUNDS; } -uint8 platform_get_locale_measurement_format(){ +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){ + sizeof(measurement_system)) == 0 + ) { return MEASUREMENT_FORMAT_IMPERIAL; } - switch (measurement_system){ + + switch (measurement_system) { case 0: return MEASUREMENT_FORMAT_METRIC; case 1: @@ -697,16 +795,19 @@ uint8 platform_get_locale_measurement_format(){ } } -uint8 platform_get_locale_temperature_format(){ +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){ + sizeof(country)) == 0 + ) { return TEMPERATURE_FORMAT_C; } - switch (country){ + + switch (country) { case CTRY_UNITED_STATES: case CTRY_BELIZE: return TEMPERATURE_FORMAT_F; @@ -714,4 +815,24 @@ uint8 platform_get_locale_temperature_format(){ return TEMPERATURE_FORMAT_C; } } + +bool platform_check_steam_overlay_attached() +{ + return GetModuleHandle("GameOverlayRenderer.dll") != NULL; +} + +char *strndup(const char *src, size_t size) +{ + size_t len = strnlen(src, size); + char *dst = (char *)malloc(len + 1); + + if (dst == NULL) + { + return NULL; + } + + dst = memcpy(dst, src, len); + dst[len] = '\0'; + return (char *)dst; +} #endif diff --git a/src/rct1.c b/src/rct1.c index 794507fec8..90fe58171d 100644 --- a/src/rct1.c +++ b/src/rct1.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 @@ -19,17 +19,22 @@ *****************************************************************************/ #include "addresses.h" +#include "config.h" +#include "editor.h" #include "interface/viewport.h" #include "interface/window.h" #include "localisation/localisation.h" #include "management/finance.h" #include "object.h" #include "rct1.h" +#include "ride/ride.h" #include "scenario.h" #include "util/sawyercoding.h" #include "util/util.h" #include "world/climate.h" +#include "world/footpath.h" #include "world/map.h" +#include "world/map_animation.h" #include "world/scenery.h" typedef struct { @@ -37,8 +42,10 @@ typedef struct { int count; } RCT1DefaultObjectsGroup; -const uint8 RCT1TerrainConvertTable[16]; -const uint8 RCT1TerrainEdgeConvertTable[16]; +static const uint8 RCT1TerrainConvertTable[16]; +static const uint8 RCT1TerrainEdgeConvertTable[16]; +static const uint8 RCT1PathTypeConversionTable[96]; +static const uint8 RCT1PathAdditionConversionTable[15]; static const RCT1DefaultObjectsGroup RCT1DefaultObjects[10]; static void rct1_remove_rides(); @@ -48,21 +55,23 @@ 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); -} +static void rct1_process_scenario_flags(); +static void rct1_reset_park_entrance_path_type(); +static void rct1_clear_extra_sprite_entries(); +static void rct1_clear_extra_tile_entries(); +static void rct1_fix_colours(); +static void rct1_fix_z(); +static void rct1_fix_paths(); +static void rct1_fix_walls(); +static void sub_69E891(); bool rct1_read_sc4(const char *path, rct1_s4 *s4) { - char *buffer, *decodedBuffer; + uint8 *buffer, *decodedBuffer; long length, decodedLength; bool success; - if (!readentirefile(path, (void**)&buffer, &length)) { + if (!readentirefile(path, (void**)&buffer, (int*)&length)) { RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = 3011; return 0; @@ -88,11 +97,11 @@ bool rct1_read_sc4(const char *path, rct1_s4 *s4) bool rct1_read_sv4(const char *path, rct1_s4 *s4) { - char *buffer, *decodedBuffer; + uint8 *buffer, *decodedBuffer; long length, decodedLength; bool success; - if (!readentirefile(path, (void**)&buffer, &length)) { + if (!readentirefile(path, (void**)&buffer, (int*)&length)) { RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = 3011; return 0; @@ -121,15 +130,15 @@ void rct1_import_s4(rct1_s4 *s4) int i; rct_banner *banner; - read((void*)RCT2_ADDRESS_CURRENT_MONTH_YEAR, &s4->month, 16); + memcpy((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)); + memcpy((void*)RCT2_ADDRESS_MAP_ELEMENTS, s4->map_elements, sizeof(s4->map_elements)); + memcpy((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); + memcpy((void*)0x013573BC, &s4->next_sprite_index, 12424); for (i = 0; i < MAX_BANNERS; i++) { banner = &gBanners[i]; @@ -137,13 +146,13 @@ void rct1_import_s4(rct1_s4 *s4) 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)); + memcpy((void*)0x0135A8F4, &s4->string_table, 0x2F51C); + memset((void*)RCT2_ADDRESS_STAFF_MODE_ARRAY, 0, 204); + memcpy((void*)0x0138B580, &s4->map_animations, 0x258F2); + memcpy((void*)0x013C6A72, &s4->patrol_areas, sizeof(s4->patrol_areas)); char *esi = (char*)0x13C6A72; - char *edi = (char*)0x13B0E72; + char *edi = (char*)RCT2_ADDRESS_STAFF_PATROL_AREAS; int ebx, edx = 116; do { ebx = 32; @@ -154,7 +163,7 @@ void rct1_import_s4(rct1_s4 *s4) memset(edi, 0, 64); edi += 64; } while (--edx > 0); edi += 0xA800; - + edx = 4; do { ebx = 32; @@ -165,9 +174,9 @@ void rct1_import_s4(rct1_s4 *s4) 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); + memcpy((void*)RCT2_ADDRESS_STAFF_MODE_ARRAY, &s4->unk_1F42AA, 116); + memcpy((void*)0x013CA73A, &s4->unk_1F431E, 4); + memcpy((void*)0x013CA73E, &s4->unk_1F4322, 0x41EA); } /** @@ -180,7 +189,7 @@ void rct1_fix_landscape() rct_sprite *sprite; rct_ride *ride; - RCT2_CALLPROC_EBPSAFE(0x0069F007); + rct1_clear_extra_sprite_entries(); // Free sprite user strings for (i = 0; i < MAX_SPRITES; i++) { @@ -198,18 +207,18 @@ void rct1_fix_landscape() 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); + RCT2_GLOBAL(RCT2_ADDRESS_LAST_GUESTS_IN_PARK, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_CHANGE_MODIFIER, uint8) = 0; + rct1_clear_extra_tile_entries(); + rct1_process_scenario_flags(); + rct1_fix_colours(); + rct1_fix_z(); + rct1_fix_paths(); rct1_remove_rides(); object_unload_all(); rct1_load_default_objects(); reset_loaded_objects(); - RCT2_CALLPROC_EBPSAFE(0x006A2730); + rct1_fix_walls(); rct1_fix_scenery(); rct1_fix_terrain(); rct1_fix_entrance_positions(); @@ -226,7 +235,7 @@ void rct1_fix_landscape() rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4; rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; - s6Info->var_000 = 1; + s6Info->editor_step = EDITOR_STEP_LANDSCAPE_EDITOR; s6Info->category = 4; format_string(s6Info->details, STR_NO_DETAILS_YET, NULL); s6Info->name[0] = 0; @@ -250,8 +259,8 @@ void rct1_fix_landscape() MONEY(10000,00), RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32) ); - RCT2_CALLPROC_EBPSAFE(0x0069E89B); - sub_69E869(); + finance_reset_cash_to_initial(); + finance_update_loan_hash(); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32) = clamp( MONEY(0,00), @@ -294,13 +303,13 @@ static void rct1_remove_rides() case MAP_ELEMENT_TYPE_PATH: if (it.element->type & 1) { it.element->properties.path.type &= 0xF7; - it.element->properties.path.addition_status = 255; + it.element->properties.path.ride_index = 255; } break; case MAP_ELEMENT_TYPE_TRACK: sub_6A7594(); - sub_6A6AA7(it.x * 32, it.y * 32, it.element); + footpath_remove_edges_at(it.x * 32, it.y * 32, it.element); map_element_remove(it.element); map_element_iterator_restart_for_tile(&it); break; @@ -308,7 +317,7 @@ static void rct1_remove_rides() 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); + footpath_remove_edges_at(it.x * 32, it.y * 32, it.element); map_element_remove(it.element); map_element_iterator_restart_for_tile(&it); } @@ -317,6 +326,16 @@ static void rct1_remove_rides() } while (map_element_iterator_next(&it)); } +static bool is_object_name_blank(rct_object_entry *entry) +{ + for (int i = 0; i < 8; i++) { + if (entry->name[i] != ' ') { + return false; + } + } + return true; +} + /** * * rct2: 0x0069F53D @@ -326,6 +345,10 @@ 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 (is_object_name_blank(&entries[j])) { + continue; + } + if (!object_load(j, &entries[j], NULL)) { error_string_quit(0x99990000 + (i * 0x100) + j, -1); return; @@ -343,7 +366,7 @@ static void rct1_load_default_objects() } /** - * + * * rct2: 0x006A29B9 */ static void rct1_fix_terrain() @@ -357,7 +380,7 @@ static void rct1_fix_terrain() 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)]); @@ -400,7 +423,7 @@ 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; @@ -438,13 +461,13 @@ static void rct1_reset_research() rct_research_item *researchItem; researchItem = gResearchItems; - researchItem->entryIndex = RESEARCHED_ITEMS_SEPERATOR; + researchItem->entryIndex = RESEARCHED_ITEMS_SEPARATOR; 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; + RCT2_GLOBAL(RCT2_ADDRESS_LAST_RESEARCHED_ITEM_SUBJECT, sint32) = -1; news_item_init_queue(); } @@ -452,48 +475,38 @@ static void rct1_reset_research() * * rct2: 0x0069F06A */ -static void sub_69F06A() +static void rct1_process_scenario_flags() { - RCT2_CALLPROC_EBPSAFE(0x0069F06A); return; + uint32 scenarioFlags = RCT2_GLOBAL(0x013CE770, uint32); - // 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 (!(scenarioFlags & RCT1_SCENARIO_FLAG_ENABLE_BANNERS)) { + banner_init(); } - if (!(RCT2_GLOBAL(0x013CE770, uint32) & (1 << 6))) { - RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 6); - RCT2_CALLPROC_EBPSAFE(0x0069E891); + if (!(scenarioFlags & (1 << 6))) { + sub_69E891(); } - RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 7); - if (!(RCT2_GLOBAL(0x013CE770, uint32) & (1 << 8))) { - RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 8); - sub_666DFD(); + if (!(scenarioFlags & RCT1_SCENARIO_FLAG_CUSTOM_PARK_ENTRANCE_PATH)) { + rct1_reset_park_entrance_path_type(); } - if (!(RCT2_GLOBAL(0x013CE770, uint32) & (1 << 9))) { - RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 9); - RCT2_CALLPROC_EBPSAFE(0x0069E89B); + if (!(scenarioFlags & RCT1_SCENARIO_FLAG_NO_CASH_RESET)) { + finance_reset_cash_to_initial(); } - if (!(RCT2_GLOBAL(0x013CE770, uint32) & (1 << 13))) { - RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 13); + if (!(scenarioFlags & RCT1_SCENARIO_FLAG_CUSTOM_MAP_SIZE)) { 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_SIZE, uint16) = 128; RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16) = 4095; } - if (!(RCT2_GLOBAL(0x013CE770, uint32) & (1 << 15))) { - RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 15); + if (!(scenarioFlags & (1 << 15))) { RCT2_GLOBAL(0x01358838, uint32) = 0; } - RCT2_GLOBAL(0x013CE770, uint32) |= (1 << 16) | (1 << 18) | (1 << 19); } /** * * rct2: 0x00666DFD */ -static void sub_666DFD() +static void rct1_reset_park_entrance_path_type() { int x, y; rct_map_element *mapElement; @@ -503,9 +516,7 @@ static void sub_666DFD() if (x == (sint16)0x8000) return; - x /= 32; - y /= 32; - mapElement = map_get_first_element_at(x, y); + mapElement = map_get_first_element_at(x >> 5, y >> 5); do { if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_ENTRANCE) { if (mapElement->properties.entrance.type == ENTRANCE_TYPE_PARK_ENTRANCE) { @@ -516,9 +527,387 @@ static void sub_666DFD() } while (!map_element_is_last_for_tile(mapElement++)); } +/** + * + * rct2: 0x0069F007 + */ +static void rct1_clear_extra_sprite_entries() +{ + rct_unk_sprite *sprite; + + for (int i = 5000; i < MAX_SPRITES; i++) { + sprite = &(g_sprite_list[i].unknown); + + memset(&g_sprite_list[i], 0, sizeof(rct_sprite)); + + sprite->sprite_identifier = 255; + sprite->sprite_index = i; + sprite->linked_list_type_offset = SPRITE_LINKEDLIST_OFFSET_NULL; + sprite->previous = SPRITE_INDEX_NULL; + sprite->next = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_NEXT_INDEX, uint16); + RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_NEXT_INDEX, uint16) = i; + + sprite = &(g_sprite_list[sprite->next].unknown); + sprite->previous = i; + } + RCT2_GLOBAL(0x013573C8, uint16) += 5000; +} + +/** + * + * rct2: 0x0069F44B + */ +static void rct1_clear_extra_tile_entries() +{ + // Reset the map tile pointers + for (int i = 0; i < 0x10000; i++) { + gMapElementTilePointers[i] = (rct_map_element*)-1; + } + + // Get the first free map element + rct_map_element *nextFreeMapElement = gMapElements; + for (int i = 0; i < 128 * 128; i++) { + do { + + } while (!map_element_is_last_for_tile(nextFreeMapElement++)); + } + + rct_map_element *mapElement = gMapElements; + rct_map_element **tilePointer = gMapElementTilePointers; + + // 128 rows of map data from RCT1 map + for (int x = 0; x < 128; x++) { + // Assign the first half of this row + for (int y = 0; y < 128; y++) { + *tilePointer++ = mapElement; + do { + + } while (!map_element_is_last_for_tile(mapElement++)); + } + + // Fill the rest of the row with blank tiles + for (int y = 0; y < 128; y++) { + nextFreeMapElement->type = MAP_ELEMENT_TYPE_SURFACE; + nextFreeMapElement->flags = MAP_ELEMENT_FLAG_LAST_TILE; + nextFreeMapElement->base_height = 2; + nextFreeMapElement->clearance_height = 0; + nextFreeMapElement->properties.surface.slope = 0; + nextFreeMapElement->properties.surface.terrain = 0; + nextFreeMapElement->properties.surface.grass_length = GRASS_LENGTH_CLEAR_0; + nextFreeMapElement->properties.surface.ownership = 0; + *tilePointer++ = nextFreeMapElement++; + } + } + + // 128 extra rows left to fill with blank tiles + for (int y = 0; y < 128 * 256; y++) { + nextFreeMapElement->type = MAP_ELEMENT_TYPE_SURFACE; + nextFreeMapElement->flags = MAP_ELEMENT_FLAG_LAST_TILE; + nextFreeMapElement->base_height = 2; + nextFreeMapElement->clearance_height = 0; + nextFreeMapElement->properties.surface.slope = 0; + nextFreeMapElement->properties.surface.terrain = 0; + nextFreeMapElement->properties.surface.grass_length = GRASS_LENGTH_CLEAR_0; + nextFreeMapElement->properties.surface.ownership = 0; + *tilePointer++ = nextFreeMapElement++; + } + + RCT2_GLOBAL(0x0140E9A4, rct_map_element*) = nextFreeMapElement; +} + +/** + * + * rct2: 0x0069F143 + */ +static void rct1_fix_colours() +{ + int rideIndex, colour; + rct_ride *ride; + rct_unk_sprite *sprite; + rct_peep *peep; + rct_balloon *balloon; + rct_map_element *mapElement; + + FOR_ALL_RIDES(rideIndex, ride) { + for (int i = 0; i < 4; i++) { + ride->track_colour_main[i] = RCT1ColourConversionTable[ride->track_colour_main[i]]; + ride->track_colour_additional[i] = RCT1ColourConversionTable[ride->track_colour_additional[i]]; + ride->track_colour_supports[i] = RCT1ColourConversionTable[ride->track_colour_supports[i]]; + } + + for (int i = 0; i < 32; i++) { + ride->vehicle_colours[i].body_colour = RCT1ColourConversionTable[ride->vehicle_colours[i].body_colour]; + ride->vehicle_colours[i].trim_colour = RCT1ColourConversionTable[ride->vehicle_colours[i].trim_colour]; + } + } + + for (int i = 0; i < MAX_SPRITES; i++) { + sprite = &(g_sprite_list[i].unknown); + switch (sprite->sprite_identifier) { + case SPRITE_IDENTIFIER_PEEP: + peep = (rct_peep*)sprite; + peep->tshirt_colour = RCT1ColourConversionTable[peep->tshirt_colour]; + peep->trousers_colour = RCT1ColourConversionTable[peep->trousers_colour]; + peep->balloon_colour = RCT1ColourConversionTable[peep->balloon_colour]; + peep->umbrella_colour = RCT1ColourConversionTable[peep->umbrella_colour]; + peep->hat_colour = RCT1ColourConversionTable[peep->hat_colour]; + break; + case SPRITE_IDENTIFIER_MISC: + balloon = (rct_balloon*)sprite; + balloon->colour = RCT1ColourConversionTable[balloon->colour]; + balloon->var_2D = RCT1ColourConversionTable[balloon->var_2D]; + break; + } + } + + mapElement = gMapElements; + while (mapElement < RCT2_GLOBAL(0x0140E9A4, rct_map_element*)) { + if (mapElement->base_height != 255) { + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_SCENERY: + colour = RCT1ColourConversionTable[mapElement->properties.scenery.colour_1 & 0x1F]; + mapElement->properties.scenery.colour_1 &= 0xE0; + mapElement->properties.scenery.colour_1 |= colour; + break; + case MAP_ELEMENT_TYPE_FENCE: + colour = RCT1ColourConversionTable[ + ((mapElement->type & 0xC0) >> 3) | + ((mapElement->properties.fence.type & 0xE0) >> 5) + ]; + + mapElement->type &= 0x3F; + mapElement->properties.fence.type &= 0x1F; + mapElement->type |= (colour & 0x18) << 3; + mapElement->properties.fence.type |= (colour & 7) << 5; + break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + colour = RCT1ColourConversionTable[mapElement->properties.scenerymultiple.colour[0] & 0x1F]; + mapElement->properties.scenerymultiple.colour[0] &= 0xE0; + mapElement->properties.scenerymultiple.colour[0] |= colour; + + colour = RCT1ColourConversionTable[mapElement->properties.scenerymultiple.colour[1] & 0x1F]; + mapElement->properties.scenerymultiple.colour[1] &= 0xE0; + mapElement->properties.scenerymultiple.colour[1] |= colour; + break; + } + } + mapElement++; + } +} + +/** + * + * rct2: 0x0069F2D0 + */ +static void rct1_fix_z() +{ + int i; + rct_ride *ride; + rct_unk_sprite *sprite; + rct_peep *peep; + rct_ride_measurement *rideMeasurement; + rct_map_element *mapElement; + + FOR_ALL_RIDES(i, ride) { + for (int i = 0; i < 4; i++) { + ride->station_heights[i] /= 2; + } + ride->var_116 /= 2; + ride->highest_drop_height = 1; + if (ride->var_11F != 255) { + ride->var_11F /= 2; + } + ride->var_13E /= 2; + ride->var_13F /= 2; + } + + for (int i = 0; i < RCT2_GLOBAL(0x0138B580, uint16); i++) { + gAnimatedObjects[i].baseZ /= 2; + } + + for (int i = 0; i < MAX_SPRITES; i++) { + sprite = &(g_sprite_list[i].unknown); + if (sprite->sprite_identifier == SPRITE_IDENTIFIER_PEEP) { + peep = (rct_peep*)sprite; + peep->next_z /= 2; + RCT2_GLOBAL((int)peep + 0xCE, uint8) /= 2; + } + } + + for (int i = 0; i < MAX_RIDE_MEASUREMENTS; i++) { + rideMeasurement = GET_RIDE_MEASUREMENT(i); + if (rideMeasurement->ride_index == 255) + continue; + + for (int i = 0; i < RIDE_MEASUREMENT_MAX_ITEMS; i++) { + rideMeasurement->altitude[i] /= 2; + } + } + + mapElement = gMapElements; + while (mapElement < RCT2_GLOBAL(0x0140E9A4, rct_map_element*)) { + if (mapElement->base_height != 255) { + mapElement->base_height /= 2; + mapElement->clearance_height /= 2; + } + mapElement++; + } + RCT2_GLOBAL(0x01359208, uint16) = 7; +} + +/** + * + * rct2: 0x0069F3AB + */ +static void rct1_fix_paths() +{ + rct_map_element *mapElement; + int pathType, secondaryType, additions; + + mapElement = gMapElements; + while (mapElement < RCT2_GLOBAL(0x0140E9A4, rct_map_element*)) { + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_PATH: + // Type + pathType = ((mapElement->properties.path.type & 0xF0) >> 2) | (mapElement->type & 3); + secondaryType = (mapElement->flags & 0x60) >> 5; + pathType = RCT1PathTypeConversionTable[pathType * 4 + secondaryType]; + + mapElement->type &= 0xFC; + mapElement->flags &= ~0x60; + mapElement->properties.path.type &= 0x0F; + mapElement->properties.path.additions &= 0x7F; + if (pathType & 0x80) { + mapElement->type |= 1; + } + mapElement->properties.path.type |= pathType << 4; + + // Additions + additions = mapElement->properties.path.additions & 0x0F; + additions = RCT1PathAdditionConversionTable[additions]; + if (additions & 0x80) { + additions &= ~0x80; + mapElement->flags |= MAP_ELEMENT_FLAG_BROKEN; + } else { + mapElement->flags &= ~MAP_ELEMENT_FLAG_BROKEN; + } + mapElement->properties.path.additions &= 0xF0; + mapElement->properties.path.additions |= additions; + break; + case MAP_ELEMENT_TYPE_ENTRANCE: + if (mapElement->properties.entrance.type == ENTRANCE_TYPE_PARK_ENTRANCE) { + pathType = mapElement->properties.entrance.path_type; + mapElement->properties.entrance.path_type = RCT1PathTypeConversionTable[pathType * 4] & 0x7F; + } + break; + } + mapElement++; + } +} + +/** + * + * rct2: 0x006A28F5 + */ +static void rct1_convert_wall(int *type, int *colourA, int *colourB, int *colourC) +{ + switch (*type) { + case 12: // creepy gate + *colourA = 24; + break; + case 26: // medium brown castle wall + *type = 12; + *colourA = 25; + break; + case 27: // tall castle wall with grey window + *type = 12; + *colourA = 2; + case 50: // plate glass + *colourA = 24; + break; + case 13: + *colourB = *colourA; + *colourA = 24; + break; + case 11: // tall castle wall with grey gate + case 22: // brick wall with gate + *colourB = 2; + break; + case 35: // wood post fence + case 42: // tall grey castle wall + case 43: // wooden fence with snow + case 44: + case 45: + case 46: + *colourA = 1; + break; + } +} + +/** + * + * rct2: 0x006A2730 + */ +static void rct1_fix_walls() +{ + rct_map_element *mapElement, originalMapElement; + + for (int x = 0; x < 128; x++) { + for (int y = 0; y < 128; y++) { + mapElement = map_get_first_element_at(x, y); + do { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_FENCE) { + originalMapElement = *mapElement; + map_element_remove(mapElement); + + uint8 var_05 = originalMapElement.properties.fence.item[0]; + uint16 var_06 = ( + originalMapElement.properties.fence.item[1] | + (originalMapElement.properties.fence.item[2] << 8) + ); + + for (int edge = 0; edge < 4; edge++) { + int typeA = (var_05 >> (edge * 2)) & 3; + int typeB = (var_06 >> (edge * 4)) & 0x0F; + if (typeB != 0x0F) { + int type = typeA | (typeB << 2); + int colourA = ( + ((originalMapElement.type & 0xC0) >> 3) | + (originalMapElement.properties.fence.type >> 5) + ); + int colourB = 0; + int colourC = 0; + rct1_convert_wall(&type, &colourA, &colourB, &colourC); + map_place_fence(type, x * 32, y * 32, 0, edge, colourA, colourB, colourC, 169); + } + } + break; + } + } while (!map_element_is_last_for_tile(mapElement++)); + } + } +} + +/** + * + * rct2: 0x0069E891 + */ +static void sub_69E891() +{ + RCT2_GLOBAL(0x013587D8, uint16) = 63; +} + #pragma region Tables -const uint8 RCT1TerrainConvertTable[16] = { +// rct2: 0x0097F0BC & 0x0098BC60 +const uint8 RCT1ColourConversionTable[32] = { + 0, 1, 2, 4, 5, 6, 7, 9, + 11, 12, 13, 14, 15, 16, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, + 28, 30, 31, 29, 3, 10, 17, 8 +}; + +static const uint8 RCT1TerrainConvertTable[16] = { TERRAIN_GRASS, TERRAIN_SAND, TERRAIN_DIRT, @@ -537,7 +926,7 @@ const uint8 RCT1TerrainConvertTable[16] = { TERRAIN_GRID_GREEN }; -const uint8 RCT1TerrainEdgeConvertTable[16] = { +static const uint8 RCT1TerrainEdgeConvertTable[16] = { TERRAIN_EDGE_ROCK, TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_BRICK TERRAIN_EDGE_ROCK, // Originally TERRAIN_EDGE_IRON @@ -556,6 +945,42 @@ const uint8 RCT1TerrainEdgeConvertTable[16] = { TERRAIN_EDGE_ROCK // Unused }; +// rct2: 0x0098BC9F +static const uint8 RCT1PathTypeConversionTable[96] = { + 0x80 | 0, 0x80 | 1, 0x80 | 2, 0x80 | 3, + 0x80 | 0, 0x80 | 1, 0x80 | 2, 0x80 | 3, + 0x80 | 0, 0x80 | 1, 0x80 | 2, 0x80 | 3, + 0x80 | 0, 0x80 | 1, 0x80 | 2, 0x80 | 3, + 0, 0, 0, 0, + 2, 2, 2, 2, + 1, 1, 1, 1, + 0, 0, 0, 0, + 3, 3, 3, 3, + 6, 6, 6, 6, + 0, 0, 0, 0, + 0, 0, 0, 0, + 5, 5, 5, 5, + 5, 5, 5, 5, + 5, 5, 5, 5, + 5, 5, 5, 5, + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, +}; + +// rct2: 0x0098BCFF +static const uint8 RCT1PathAdditionConversionTable[15] = { + 0, + 1, 2, 3, 4, 5, 6, 7, + 0x80 | 1, 0x80 | 2, 0x80 | 3, 0x80 | 4, 0x80 | 6, 0x80 | 7, + 8, +}; + #pragma endregion #pragma region RCT1 Default Objects @@ -590,7 +1015,7 @@ static const rct_object_entry RCT1DefaultObjectsRides[] = { { 0x00008000, { "SWSH1 " }, 0 }, { 0x00008000, { "SWSH2 " }, 0 }, { 0x00008000, { "ICECR1 " }, 0 }, - { 0x00008000, { "CHPSH2 " }, 0 }, + { 0x00008000, { "CHPSH " }, 0 }, { 0x00008000, { "DRNKS " }, 0 }, { 0x00008000, { "CNDYF " }, 0 }, { 0x00008000, { "BURGB " }, 0 }, @@ -1090,7 +1515,7 @@ static const rct_object_entry RCT1DefaultObjectsWater[] = { }; static const RCT1DefaultObjectsGroup RCT1DefaultObjects[10] = { - { NULL, 0 }, + { RCT1DefaultObjectsRides, countof(RCT1DefaultObjectsRides) }, { RCT1DefaultObjectsSmallScenery, countof(RCT1DefaultObjectsSmallScenery) }, { RCT1DefaultObjectsLargeScenery, countof(RCT1DefaultObjectsLargeScenery) }, { RCT1DefaultObjectsWall, countof(RCT1DefaultObjectsWall) }, @@ -1102,4 +1527,299 @@ static const RCT1DefaultObjectsGroup RCT1DefaultObjects[10] = { { RCT1DefaultObjectsWater, countof(RCT1DefaultObjectsWater) } }; -#pragma endregion \ No newline at end of file +// Keep these in the same order as gVehicleHierarchies +const char *SpiralRCObjectOrder[] = { "SPDRCR "}; +const char *StandupRCObjectOrder[] = { "TOGST "}; +const char *SuspendedSWRCObjectOrder[] = { "ARRSW1 ", "VEKVAMP ", "ARRSW2 "}; +const char *InvertedRCObjectOrder[] = { "NEMT "}; +const char *JuniorCoasterObjectOrder[] = { "ZLDB ", "ZLOG "}; +const char *MiniatureRailwayObjectOrder[] = { "NRL ", "NRL2 ", "AML1 ", "TRAM1 "}; +const char *MonorailObjectOrder[] = { "MONO1 ", "MONO2 ", "MONO3 "}; +const char *MiniSuspendedRCObjectOrder[] = { "BATFL ", "SKYTR "}; +const char *BoatRideObjectOrder[] = { "RBOAT ", "BBOAT ", "CBOAT ", "SWANS ", "TRIKE ","JSKI "}; +const char *WoodenWMObjectOrder[] = { "WMOUSE ", "WMMINE "}; +const char *SteeplechaseObjectOrder[] = { "STEEP1 ", "STEEP2 ", "SBOX "}; +const char *CarRideObjectOrder[] = { "SPCAR ", "RCR ", "TRUCK1 ", "VCR ", "CTCAR "}; +const char *LaunchedFFObjectOrder[] = { "SSC1 "}; +const char *BobsleighRCObjectOrder[] = { "BOB1 ", "INTBOB "}; +const char *ObservationTowerObjectOrder[] = { "OBS1 ", "OBS2 "}; +const char *LoopingRCObjectOrder[] = { "SCHT1 "}; +const char *DinghySlideObjectOrder[] = { "DING1 "}; +const char *MineTrainRCObjectOrder[] = { "AMT1 "}; +const char *ChairliftObjectOrder[] = { "CLIFT1 ", "CLIFT2 "}; +const char *CorkscrewRCObjectOrder[] = { "ARRT1 ", "ARRT2 "}; +const char *GoKartsObjectOrder[] = { "KART1 "}; +const char *LogFlumeObjectOrder[] = { "LFB1 "}; +const char *RiverRapidsObjectOrder[] = { "RAPBOAT "}; +const char *ReverseFreefallRCObjectOrder[] = { "REVF1 "}; +const char *LiftObjectOrder[] = { "LIFT1 "}; +const char *VerticalDropRCObjectOrder[] = { "BMVD "}; +const char *GhostTrainObjectOrder[] = { "GTC ", "HMCAR "}; +const char *TwisterRCObjectOrder[] = { "BMSD ", "BMSU ", "BMFL ", "BMRB ", "GOLTR "}; +const char *WoodenRCObjectOrder[] = { "PTCT1 ", "MFT ", "PTCT2 "}; +const char *SideFrictionRCObjectOrder[] = { "SFRIC1 "}; +const char *SteelWildMouseObjectOrder[] = { "SMC1 ", "SMC2 ", "WMSPIN "}; +const char *MultiDimensionRCObjectOrder[] = { "ARRX "}; +const char *FlyingRCObjectOrder[] = { "BMAIR "}; +const char *VirginiaReelRCObjectOrder[] = { "VREEL "}; +const char *SplashBoatsObjectOrder[] = { "SPBOAT "}; +const char *MiniHelicoptersObjectOrder[] = { "HELICAR "}; +const char *LayDownRCObjectOrder[] = { "VEKST "}; +const char *SuspendedMonorailObjectOrder[] = { "SMONO "}; +const char *ReverserRCObjectOrder[] = { "REVCAR "}; +const char *HeartlineTwisterObjectOrder[] = { "UTCAR ", "UTCARR "}; +const char *GigaRCObjectOrder[] = { "INTST "}; +const char *RotoDropObjectOrder[] = { "GDROP1 "}; +const char *MonorailCyclesObjectOrder[] = { "MONBK "}; +const char *CompactInvertedRCObjectOrder[] = { "SLCT ", "SLCFO ", "VEKDV "}; +const char *WaterRCObjectOrder[] = { "CSTBOAT "}; +const char *AirPoweredRCObjectOrder[] = { "THCAR "}; +const char *InvertedHairpinRCObjectOrder[] = { "IVMC1 "}; +const char *SubmarineRideObjectOrder[] = { "SUBMAR "}; +const char *RiverRaftsObjectOrder[] = { "RFTBOAT "}; +const char *InvertedImpulseRCObjectOrder[] = { "INTINV "}; +const char *MiniRCObjectOrder[] = { "WCATC ", "RCKC ", "JSTAR1 "}; +const char *MineRideRCObjectOrder[] = { "PMT1 "}; +const char *LIMLaunchedRCObjectOrder[] = { "PREMT1 "}; + +typedef struct { + const char **entries; + int count; +} RCT1VehicleHierarchiesGroup; + +RCT1VehicleHierarchiesGroup gVehicleHierarchies[0x60] = { + { SpiralRCObjectOrder, countof(SpiralRCObjectOrder) }, // 0 Spiral Roller coaster + { StandupRCObjectOrder, countof(StandupRCObjectOrder) }, // 1 Stand Up Coaster + { SuspendedSWRCObjectOrder, countof(SuspendedSWRCObjectOrder) }, // 2 Suspended Swinging + { InvertedRCObjectOrder, countof(InvertedRCObjectOrder) }, // 3 Inverted + { JuniorCoasterObjectOrder, countof(JuniorCoasterObjectOrder) }, // 4 Junior RC / Steel Mini Coaster + { MiniatureRailwayObjectOrder, countof(MiniatureRailwayObjectOrder) }, // 5 Mini Railroad + { MonorailObjectOrder, countof(MonorailObjectOrder) }, // 6 Monorail + { MiniSuspendedRCObjectOrder, countof(MiniSuspendedRCObjectOrder) }, // 7 Mini Suspended Coaster + { BoatRideObjectOrder, countof(BoatRideObjectOrder) }, // 8 Boat ride + { WoodenWMObjectOrder, countof(WoodenWMObjectOrder) }, // 9 Wooden Wild Mine/Mouse + { SteeplechaseObjectOrder, countof(SteeplechaseObjectOrder) }, // a Steeplechase/Motorbike/Soap Box Derby + { CarRideObjectOrder, countof(CarRideObjectOrder) }, // b Car Ride + { LaunchedFFObjectOrder, countof(LaunchedFFObjectOrder) }, // c Launched Freefall + { BobsleighRCObjectOrder, countof(BobsleighRCObjectOrder) }, // d Bobsleigh Coaster + { ObservationTowerObjectOrder, countof(ObservationTowerObjectOrder) }, // e Observation Tower + { LoopingRCObjectOrder, countof(LoopingRCObjectOrder) }, // f Looping Roller Coaster + { DinghySlideObjectOrder, countof(DinghySlideObjectOrder) }, // 10 Dinghy Slide + { MineTrainRCObjectOrder, countof(MineTrainRCObjectOrder) }, // 11 Mine Train Coaster + { ChairliftObjectOrder, countof(ChairliftObjectOrder) }, // 12 Chairlift + { CorkscrewRCObjectOrder, countof(CorkscrewRCObjectOrder) }, // 13 Corkscrew Roller Coaster + { NULL, 0 }, // 14 Maze, N/A + { NULL, 0 }, // 15 Spiral Slide, N/A + { GoKartsObjectOrder, countof(GoKartsObjectOrder) }, // 16 Go Karts + { LogFlumeObjectOrder, countof(LogFlumeObjectOrder) }, // 17 Log Flume + { RiverRapidsObjectOrder, countof(RiverRapidsObjectOrder) }, // 18 River Rapids + { NULL, 0 }, // 19 Dodgems, N/A + { NULL, 0 }, // 1a Pirate Ship, N/A + { NULL, 0 }, // 1b Swinging Inverter Ship, N/A + { NULL, 0 }, // 1c Food Stall, N/A + { NULL, 0 }, // 1d (none), N/A + { NULL, 0 }, // 1e Drink Stall, N/A + { NULL, 0 }, // 1f (none), N/A + { NULL, 0 }, // 20 Shop (all types), N/A + { NULL, 0 }, // 21 Merry Go Round, N/A + { NULL, 0 }, // 22 Balloon Stall (maybe), N/A + { NULL, 0 }, // 23 Information Kiosk, N/A + { NULL, 0 }, // 24 Bathroom, N/A + { NULL, 0 }, // 25 Ferris Wheel, N/A + { NULL, 0 }, // 26 Motion Simulator, N/A + { NULL, 0 }, // 27 3D Cinema, N/A + { NULL, 0 }, // 28 Top Spin, N/A + { NULL, 0 }, // 29 Space Rings, N/A + { ReverseFreefallRCObjectOrder, countof(ReverseFreefallRCObjectOrder) }, // 2a Reverse Freefall Coaster + { LiftObjectOrder, countof(LiftObjectOrder) }, // 2b Lift + { VerticalDropRCObjectOrder, countof(VerticalDropRCObjectOrder) }, // 2c Vertical Drop Roller Coaster + { NULL, 0 }, // 2d ATM, N/A + { NULL, 0 }, // 2e Twist, N/A + { NULL, 0 }, // 2f Haunted House, N/A + { NULL, 0 }, // 30 First Aid, N/A + { NULL, 0 }, // 31 Circus Show, N/A + { GhostTrainObjectOrder, countof(GhostTrainObjectOrder) }, // 32 Ghost Train + { TwisterRCObjectOrder, countof(TwisterRCObjectOrder) }, // 33 Twister Roller Coaster + { WoodenRCObjectOrder, countof(WoodenRCObjectOrder) }, // 34 Wooden Roller Coaster + { SideFrictionRCObjectOrder, countof(SideFrictionRCObjectOrder) }, // 35 Side-Friction Roller Coaster + { SteelWildMouseObjectOrder, countof(SteelWildMouseObjectOrder) }, // 36 Steel Wild Mouse + { MultiDimensionRCObjectOrder, countof(MultiDimensionRCObjectOrder) }, // 37 Multi Dimension Coaster + { NULL, 0 }, // 38 (none), N/A + { FlyingRCObjectOrder, countof(FlyingRCObjectOrder) }, // 39 Flying Roller Coaster + { NULL, 0 }, // 3a (none), N/A + { VirginiaReelRCObjectOrder, countof(VirginiaReelRCObjectOrder) }, // 3b Virginia Reel + { SplashBoatsObjectOrder, countof(SplashBoatsObjectOrder) }, // 3c Splash Boats + { MiniHelicoptersObjectOrder, countof(MiniHelicoptersObjectOrder) }, // 3d Mini Helicopters + { LayDownRCObjectOrder, countof(LayDownRCObjectOrder) }, // 3e Lay-down Roller Coaster + { SuspendedMonorailObjectOrder, countof(SuspendedMonorailObjectOrder) }, // 3f Suspended Monorail + { NULL, 0 }, // 40 (none), N/A + { ReverserRCObjectOrder, countof(ReverserRCObjectOrder) }, // 41 Reverser Roller Coaster + { HeartlineTwisterObjectOrder, countof(HeartlineTwisterObjectOrder) }, // 42 Heartline Twister Roller Coaster + { NULL, 0 }, // 43 Mini Golf, N/A + { GigaRCObjectOrder, countof(GigaRCObjectOrder) }, // 44 Giga Coaster + { RotoDropObjectOrder, countof(RotoDropObjectOrder) }, // 45 Roto-Drop + { NULL, 0 }, // 46 Flying Saucers, N/A + { NULL, 0 }, // 47 Crooked House, N/A + { MonorailCyclesObjectOrder, countof(MonorailCyclesObjectOrder) }, // 48 Monorail Cycles + { CompactInvertedRCObjectOrder, countof(CompactInvertedRCObjectOrder) }, // 49 Compact Inverted Coaster + { WaterRCObjectOrder, countof(WaterRCObjectOrder) }, // 4a Water Coaster + { AirPoweredRCObjectOrder, countof(AirPoweredRCObjectOrder) }, // 4b Air Powered Vertical Coaster + { InvertedHairpinRCObjectOrder, countof(InvertedHairpinRCObjectOrder) }, // 4c Inverted Hairpin Coaster + { NULL, 0 }, // 4d Magic Carpet, N/A + { SubmarineRideObjectOrder, countof(SubmarineRideObjectOrder) }, // 4e Submarine Ride + { RiverRaftsObjectOrder, countof(RiverRaftsObjectOrder) }, // 4f River Rafts + { NULL, 0 }, // 50 (none), N/A + { NULL, 0 }, // 51 Enterprise, N/A + { NULL, 0 }, // 52 (none), N/A + { NULL, 0 }, // 53 (none), N/A + { NULL, 0 }, // 54 (none), N/A + { NULL, 0 }, // 55 (none), N/A + { InvertedImpulseRCObjectOrder, countof(InvertedImpulseRCObjectOrder) }, // 56 Inverted Impulse Coaster + { MiniRCObjectOrder, countof(MiniRCObjectOrder) }, // 57 Mini Roller Coaster + { MineRideRCObjectOrder, countof(MineRideRCObjectOrder) }, // 58 Mine Ride + { NULL, 0 }, // 59 Unknown Ride + { LIMLaunchedRCObjectOrder, countof(LIMLaunchedRCObjectOrder) }, // 60 LIM Launched Roller Coaster +}; + +const uint8 gRideCategories[0x60] = { + 2, // Spiral Roller coaster + 2, // Stand Up Coaster + 2, // Suspended Swinging + 2, // Inverted + 2, // Steel Mini Coaster + 0, // Mini Railroad + 0, // Monorail + 2, // Mini Suspended Coaster + 4, // Boat ride + 2, // Wooden Wild Mine/Mouse + 2, // Steeplechase/Motorbike/Soap Box Derby + 1, // Car Ride + 3, // Launched Freefall + 2, // Bobsleigh Coaster + 1, // Observation Tower + 2, // Looping Roller Coaster + 4, // Dinghy Slide + 2, // Mine Train Coaster + 0, // Chairlift + 2, // Corkscrew Roller Coaster + 1, // Maze + 1, // Spiral Slide + 3, // Go Karts + 4, // Log Flume + 4, // River Rapids + 1, // Dodgems + 3, // Pirate Ship + 3, // Swinging Inverter Ship + 5, // Food Stall + 255, // (none) + 5, // Drink Stall + 255, // (none) + 5, // Shop (all types) + 1, // Merry Go Round + 5, // Balloon Stall (maybe) + 5, // Information Kiosk + 5, // Bathroom + 1, // Ferris Wheel + 3, // Motion Simulator + 3, // 3D Cinema + 3, // Top Spin + 1, // Space Rings + 2, // Reverse Freefall Coaster + 0, // Elevator + 2, // Vertical Drop Roller Coaster + 5, // ATM + 3, // Twist + 1, // Haunted House + 5, // First Aid + 1, // Circus Show + 1, // Ghost Train + 2, // Twister Roller Coaster + 2, // Wooden Roller Coaster + 2, // Side-Friction Roller Coaster + 2, // Wild Mouse + 2, // Multi Dimension Coaster + 255, // (none) + 2, // Flying Roller Coaster + 255, // (none) + 2, // Virginia Reel + 4, // Splash Boats + 1, // Mini Helicopters + 2, // Lay-down Roller Coaster + 0, // Suspended Monorail + 255, // (none) + 2, // Reverser Roller Coaster + 2, // Heartline Twister Roller Coaster + 1, // Mini Golf + 2, // Giga Coaster + 3, // Roto-Drop + 1, // Flying Saucers + 1, // Crooked House + 1, // Monorail Cycles + 2, // Compact Inverted Coaster + 2, // Water Coaster + 2, // Air Powered Vertical Coaster + 2, // Inverted Hairpin Coaster + 3, // Magic Carpet + 4, // Submarine Ride + 4, // River Rafts + 255, // (none) + 3, // Enterprise + 255, // (none) + 255, // (none) + 255, // (none) + 255, // (none) + 2, // Inverted Impulse Coaster + 2, // Mini Roller Coaster + 2, // Mine Ride + 255, //59 Unknown Ride + 2 // LIM Launched Roller Coaster +}; + +/* This function keeps a list of the preferred vehicle for every generic track type, out of the available vehicle types in the current game. + It determines which picture is shown on the new ride tab and which train type is selected by default.*/ +bool vehicleIsHigherInHierarchy(int track_type, char *currentVehicleName, char *comparedVehicleName) +{ + if(currentVehicleName==NULL || comparedVehicleName==NULL || gVehicleHierarchies[track_type].entries==NULL) { + return false; + } + + int currentVehicleHierarchy; + int comparedVehicleHierarchy; + + currentVehicleHierarchy=255; + comparedVehicleHierarchy=255; + + for(int i = 0; i < gVehicleHierarchies[track_type].count; i++) { + if(gVehicleHierarchies[track_type].entries[i]==NULL) + continue; + + if(strcmp(comparedVehicleName,gVehicleHierarchies[track_type].entries[i])==0) + comparedVehicleHierarchy=i; + + if(strcmp(currentVehicleName,gVehicleHierarchies[track_type].entries[i])==0) + currentVehicleHierarchy=i; + } + + if(comparedVehicleHierarchyride_type[j], RIDE_TYPE_FLAG_FLAT_RIDE)) + remove_flag=false; + if(ride->ride_type[j]==RIDE_TYPE_MAZE || ride->ride_type[j]==RIDE_TYPE_MINI_GOLF) + remove_flag=false; + } + return remove_flag; +} + +#pragma endregion diff --git a/src/rct1.h b/src/rct1.h index d17fbbb7d8..4e1df84dac 100644 --- a/src/rct1.h +++ b/src/rct1.h @@ -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 . *****************************************************************************/ @@ -37,6 +37,131 @@ typedef struct { uint8 direction; } rct1_entrance; +/** + * RCT1 ride structure + * size: 0x260 + */ +typedef struct { + uint8 type; + uint8 vehicle_type; + uint16 lifecycle_flags; + uint8 operating_mode; + uint8 colour_scheme; + uint16 vehicle_colours[12]; + uint8 track_primary_colour; + uint8 track_secondary_colour; + uint8 track_support_colour; + uint8 status; + uint16 name; + uint16 name_argument_ride; + uint16 name_argument_number; + uint16 overall_view; + uint16 station_starts[4]; + uint8 station_height[4]; + uint8 station_length[4]; + uint8 station_light[4]; + uint8 station_depart[4]; + uint16 entrance[4]; + uint16 exit[4]; + uint16 last_peep_in_queue[4]; + uint8 num_peeps_in_queue[4]; + uint16 vehicles[12]; + uint8 depart_flags; + uint8 num_stations; + uint8 num_trains; + uint8 num_cars_per_train; + uint8 unk_7A; + uint8 unk_7B; + uint8 max_trains; + uint8 unk_7D; + uint8 min_waiting_time; + uint8 max_waiting_time; + uint8 operation_option; + uint8 unk_081[0x3]; + uint8 data_logging_index; + uint8 special_track_elements; + uint16 unk_86; + sint32 max_speed; + sint32 average_speed; + uint8 pad_090[4]; + sint32 length[4]; + uint16 time[4]; + fixed16_2dp max_positive_vertical_g; + fixed16_2dp max_negative_vertical_g; + fixed16_2dp max_lateral_g; + uint8 unk_B2[18]; + union { + uint8 num_inversions; + uint8 num_holes; + }; + uint8 num_drops; + uint8 unk_C6; + uint8 highest_drop_height; + sint32 sheltered_length; + uint8 unk_CC[2]; + uint8 num_sheltered_sections; + uint8 unk_CF; + sint16 unk_D0; + sint16 unk_D2; + sint16 customers_per_hour; + sint16 unk_D6; + sint16 unk_D8; + sint16 unk_DA; + sint16 unk_DC; + sint16 unk_DE; + uint16 age; + sint16 running_cost; + sint16 unk_E4; + sint16 unk_E6; + money16 price; + sint16 var_EA; + sint16 var_EC; + uint8 var_EE; + uint8 var_EF; + union { + rating_tuple ratings; + struct { + ride_rating excitement; + ride_rating intensity; + ride_rating nausea; + }; + }; + uint16 value; + uint16 var_F8; + uint8 satisfaction; + uint8 satisfaction_time_out; + uint8 satisfaction_next; + uint8 window_invalidate_flags; + uint8 unk_FE[2]; + uint32 total_customers; + money32 total_profit; + uint8 popularity; + uint8 popularity_time_out; + uint8 popularity_next; + uint8 num_riders; + uint8 unk_10C[36]; + sint16 build_date; + money16 upkeep_cost; + uint8 unk_134[15]; + uint8 breakdown_reason; + uint8 unk_144[2]; + uint16 reliability; + uint8 unreliability_factor; + uint8 unk_148; + uint8 inspection_interval; + uint8 last_inspection; + uint8 unk_14C[20]; + money32 income_per_hour; + money32 profit; + uint8 queue_time[4]; + uint8 track_colour_main[4]; + uint8 track_colour_additional[4]; + uint8 track_colour_supports[4]; + uint8 music; + uint8 entrance_style; + uint8 unk_17A[230]; +} rct1_ride; + /** * RCT1,AA,LL scenario / saved game structure. * size: 0x1F850C @@ -166,9 +291,9 @@ typedef struct { rct_research_item research_items_LL[180]; uint8 unk_19A020[5468]; rct_banner banners[100]; - char string_table[32][1024]; + char string_table[1024][32]; uint32 game_time_counter; - rct_ride rides[255]; + rct1_ride rides[255]; uint16 unk_game_time_counter; uint16 view_x; uint16 view_y; @@ -352,10 +477,38 @@ typedef struct{ uint16 start_track_data_AA_CF; // 0xC4 }rct_track_td4; // Information based off RCTTechDepot +enum { + RCT1_SCENARIO_FLAG_0 = 1 << 0, + RCT1_SCENARIO_FLAG_1 = 1 << 1, + RCT1_SCENARIO_FLAG_2 = 1 << 2, + RCT1_SCENARIO_FLAG_3 = 1 << 3, + RCT1_SCENARIO_FLAG_ENABLE_BANNERS = 1 << 4, + RCT1_SCENARIO_FLAG_5 = 1 << 5, + RCT1_SCENARIO_FLAG_6 = 1 << 6, + RCT1_SCENARIO_FLAG_7 = 1 << 7, + RCT1_SCENARIO_FLAG_CUSTOM_PARK_ENTRANCE_PATH = 1 << 8, + RCT1_SCENARIO_FLAG_NO_CASH_RESET = 1 << 9, + RCT1_SCENARIO_FLAG_10 = 1 << 10, + RCT1_SCENARIO_FLAG_11 = 1 << 11, + RCT1_SCENARIO_FLAG_12 = 1 << 12, + RCT1_SCENARIO_FLAG_CUSTOM_MAP_SIZE = 1 << 13, + RCT1_SCENARIO_FLAG_14 = 1 << 14, + RCT1_SCENARIO_FLAG_15 = 1 << 15, + RCT1_SCENARIO_FLAG_16 = 1 << 16, + RCT1_SCENARIO_FLAG_17 = 1 << 17, + RCT1_SCENARIO_FLAG_18 = 1 << 18, + RCT1_SCENARIO_FLAG_19 = 1 << 19, +}; + +extern const uint8 RCT1ColourConversionTable[32]; + +const uint8 gRideCategories[0x60]; + 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(); +bool vehicleIsHigherInHierarchy(int track_type, char *currentVehicleName, char *comparedVehicleName); +bool rideTypeShouldLoseSeparateFlag(rct_ride_type *ride); #endif - \ No newline at end of file diff --git a/src/rct2.c b/src/rct2.c index b174cfa7e8..23e2b88af6 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -1,9 +1,9 @@ /***************************************************************************** * Copyright (c) 2014 Ted John, Matthias Lanzinger * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * + * * This file is part of OpenRCT2. - * + * * OpenRCT2 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -21,6 +21,7 @@ #pragma warning(disable : 4996) // GetVersionExA deprecated #include +#include #include "addresses.h" #include "audio/audio.h" #include "audio/mixer.h" @@ -28,26 +29,33 @@ #include "drawing/drawing.h" #include "editor.h" #include "game.h" +#include "interface/chat.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/network.h" #include "network/twitch.h" #include "object.h" #include "openrct2.h" +#include "peep/staff.h" #include "platform/platform.h" +#include "rct1.h" #include "ride/ride.h" #include "ride/track.h" #include "scenario.h" #include "title.h" +#include "util/util.h" #include "world/map.h" #include "world/park.h" #include "world/climate.h" #include "world/scenery.h" #include "world/sprite.h" +uint32 gCurrentDrawCount = 0; + typedef struct tm tm_t; void print_launch_information(); @@ -69,10 +77,10 @@ int rct2_init() { log_verbose("initialising game"); - RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, int) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) = 0; RCT2_GLOBAL(0x009AC310, char*) = RCT2_GLOBAL(RCT2_ADDRESS_CMDLINE, char*); get_system_time(); - srand((unsigned int)time(0)); + util_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_MONTH, short); if (!rct2_init_directories()) @@ -94,10 +102,10 @@ int rct2_init() gfx_load_g1(); gfx_load_g2(); - gfx_load_character_widths(); + font_sprite_initialise_characters(); if (!gOpenRCT2Headless) { platform_init(); - audio_init1(); + audio_init_ride_sounds_and_info(); } viewport_init_all(); news_item_init_queue(); @@ -107,7 +115,7 @@ int rct2_init() reset_sprite_list(); ride_init_all(); window_guest_list_init_vars_a(); - sub_6BD3A4(); + staff_reset_modes(); map_init(150); park_init(); if (!gOpenRCT2Headless) @@ -130,7 +138,7 @@ int rct2_init() } /** - * + * * rct2: 0x00683499 */ int rct2_init_directories() @@ -138,33 +146,49 @@ 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(gConfigGeneral.game_path)) { - log_verbose("install directory does not exist, %s", gConfigGeneral.game_path); + if (!platform_original_game_data_exists(gConfigGeneral.game_path)) { + log_verbose("install directory does not exist or invalid directory selected, %s", gConfigGeneral.game_path); if (!config_find_or_browse_install_directory()) { log_fatal("Invalid RCT2 installation path. Please correct in config.ini."); return 0; } } + char separator[] = {platform_get_path_separator(), 0}; + 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), "\\"); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH_SLASH, char), separator); strcpy(RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH, char), RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char)); - strcat(RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH, char), "\\Saved Games\\"); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH, char), separator); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH, char), "Saved Games"); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH, char), separator); strcpy(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char)); - strcat(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), "\\Scenarios\\*.SC6"); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), separator); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), "Scenarios"); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), separator); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), "*.SC6"); strcpy(RCT2_ADDRESS(RCT2_ADDRESS_LANDSCAPES_PATH, char), RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char)); - strcat(RCT2_ADDRESS(RCT2_ADDRESS_LANDSCAPES_PATH, char), "\\Landscapes\\*.SC6"); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_LANDSCAPES_PATH, char), separator); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_LANDSCAPES_PATH, char), "Landscapes"); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_LANDSCAPES_PATH, char), separator); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_LANDSCAPES_PATH, char), "*.SC6"); strcpy(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char)); - strcat(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), "\\ObjData\\*.DAT"); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), separator); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), "ObjData"); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), separator); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), "*.DAT"); strcpy(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char)); - strcat(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), "\\Tracks\\*.TD?"); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), separator); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), "Tracks"); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), separator); + strcat(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), "*.TD?"); strcpy(RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH_2, char), RCT2_ADDRESS(RCT2_ADDRESS_SAVED_GAMES_PATH, char)); return 1; @@ -179,7 +203,7 @@ void subsitute_path(char *dest, const char *path, const char *filename) } /** - * + * * rct2: 0x00674B42 */ int rct2_startup_checks() @@ -189,7 +213,7 @@ int rct2_startup_checks() if (!check_files_integrity()) return 0; - + return 1; } @@ -205,8 +229,8 @@ void rct2_update() #else __asm__ ( "\ \n\ - mov eax, 0x009DE564 \n\ - mov [eax], esp \n\ + movl $0x009DE564, %%eax \n\ + movl %%esp, (%%eax) \n\ " : : : "eax" ); #endif @@ -214,6 +238,30 @@ void rct2_update() rct2_update_2(); } +void rct2_draw() +{ + redraw_rain(); + window_update_all(); + gfx_invalidate_pickedup_peep(); + gfx_draw_pickedup_peep(); + update_rain_animation(); + update_palette_effects(); + + chat_draw(); + console_draw(RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo)); + + if (RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) != 0) { + //intro + } else if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) { + //title + DrawOpenRCT2(0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - 20); + } else { + //game + } + + gCurrentDrawCount++; +} + int rct2_open_file(const char *path) { char *extension = strrchr(path, '.'); @@ -241,7 +289,7 @@ int rct2_open_file(const char *path) } /** - * + * * rct2: 0x00674C95 */ int check_file_paths() @@ -254,21 +302,21 @@ int check_file_paths() } /** - * + * * rct2: 0x00674CA5 */ int check_file_path(int pathId) { - const char * path = get_file_path(pathId); - HANDLE file = CreateFile(path, FILE_GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); + const utf8* path = get_file_path(pathId); + SDL_RWops *file = SDL_RWFromFile(path, "rb"); switch (pathId) { case PATH_ID_G1: - if (file == INVALID_HANDLE_VALUE) { + if (file == NULL) { // 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. // The file_on_cdrom[pathId] @ 0x009AA0B flag is set to 1 as well. - // For PATH_ID_SIXFLAGS_MAGICMOUNTAIN and PATH_ID_SIXFLAGS_BUILDYOUROWN, + // For PATH_ID_SIXFLAGS_MAGICMOUNTAIN (and the now removed PATH_ID_SIXFLAGS_BUILDYOUROWN), // the original implementation always assumes they are stored on CD-ROM. // This has been removed for now for the sake of simplicity and could be added // later in a more convenient way using the INI file. @@ -278,30 +326,31 @@ int check_file_path(int pathId) 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 + if (file != NULL) + gRideMusicInfoList[36]->length = (uint32)SDL_RWsize(file); // 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 + if (file != NULL) + gRideMusicInfoList[37]->length = (uint32)SDL_RWsize(file); // Store file size in music_custom2_size @ 0x009AF16E break; } - if (file != INVALID_HANDLE_VALUE) - CloseHandle(file); + if (file != NULL) + SDL_RWclose(file); return 1; } /** - * + * * rct2: 0x00674C0B */ int check_files_integrity() { int i; const char *path; +#ifdef _WIN32 HANDLE file; WIN32_FIND_DATA find_data; @@ -319,6 +368,9 @@ int check_files_integrity() FindClose(file); } +#else + STUB(); +#endif // _WIN32 return 1; } @@ -327,32 +379,36 @@ void rct2_update_2() { int tick, tick2; - tick = timeGetTime(); + tick = SDL_GetTicks(); - tick2 = tick - RCT2_GLOBAL(0x009DE580, sint32); - RCT2_GLOBAL(0x009DE588, sint16) = tick2 = min(tick2, 500); + tick2 = tick - RCT2_GLOBAL(RCT2_ADDRESS_LAST_TICK_COUNT, sint32); + RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_LAST_UPDATE, sint16) = tick2 = min(tick2, 500); - RCT2_GLOBAL(0x009DE580, sint32) = tick; + RCT2_GLOBAL(RCT2_ADDRESS_LAST_TICK_COUNT, sint32) = tick; 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; + RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_LAST_UPDATE, sint16) = 31; // TODO: screenshot countdown process + network_update(); + // check_cmdline_arg(); // Screens if (RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) != 0) intro_update(); - else if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 1) + else if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) title_update(); else game_update(); + //stop_completed_sounds(); // removes other sounds that are no longer playing in directsound + twitch_update(); + chat_update(); console_update(); - console_draw(RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo)); } void rct2_endupdate() @@ -361,12 +417,12 @@ void rct2_endupdate() } /** - * + * * rct2: 0x00674E6C */ -const char *get_file_path(int pathId) +const utf8 *get_file_path(int pathId) { - static char path[MAX_PATH]; // get_file_path_buffer @ 0x009E3605 + static utf8 path[MAX_PATH]; // get_file_path_buffer @ 0x009E3605 // 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 @@ -374,7 +430,7 @@ const char *get_file_path(int pathId) 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) == 0 || path[strlen(path) - 1] != platform_get_path_separator()) { if (strlen(path) >= MAX_PATH - 1) { @@ -383,7 +439,8 @@ const char *get_file_path(int pathId) return path; } - strcat(path, "\\"); + char separator[] = {platform_get_path_separator(), 0}; + strcat(path, separator); } // Concatenate file path @@ -393,8 +450,15 @@ const char *get_file_path(int pathId) return path; } + char *pathp = path + strnlen(path, sizeof(path)); + strcat(path, file_paths[pathId]); + while (*pathp) { + if (*pathp == '\\') *pathp = platform_get_path_separator(); + pathp++; + } + return path; } @@ -404,6 +468,7 @@ const char *get_file_path(int pathId) */ void get_system_info() { +#ifdef _WIN32 OSVERSIONINFO versionInfo; SYSTEM_INFO sysInfo; MEMORYSTATUS memInfo; @@ -415,10 +480,12 @@ void get_system_info() RCT2_GLOBAL(RCT2_ADDRESS_OS_MINOR_VERSION, uint32) = versionInfo.dwMinorVersion; RCT2_GLOBAL(RCT2_ADDRESS_OS_BUILD_NUMBER, uint32) = versionInfo.dwBuildNumber; } else { +#endif // _WIN32 RCT2_GLOBAL(RCT2_ADDRESS_OS_PLATFORM_ID, uint32) = -1; RCT2_GLOBAL(RCT2_ADDRESS_OS_MAJOR_VERSION, uint32) = 0; RCT2_GLOBAL(RCT2_ADDRESS_OS_MINOR_VERSION, uint32) = 0; RCT2_GLOBAL(RCT2_ADDRESS_OS_BUILD_NUMBER, uint32) = 0; +#ifdef _WIN32 } GetSystemInfo(&sysInfo); @@ -445,7 +512,7 @@ void get_system_info() HDC screenHandle = GetDC(NULL); if (screenHandle) { RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_CAP_BPP, sint32) = GetDeviceCaps(screenHandle, BITSPIXEL); - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_CAP_RASTER_STRETCH, sint32) = GetDeviceCaps(screenHandle, RASTERCAPS) >> 8; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_CAP_RASTER_STRETCH, sint32) = GetDeviceCaps(screenHandle, RASTERCAPS) >> 8; ReleaseDC(NULL, screenHandle); } else { RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_CAP_BPP, sint32) = 0; @@ -459,6 +526,9 @@ void get_system_info() RCT2_GLOBAL(0x1423C18, sint32) = 1; RCT2_GLOBAL(0x01423C20, uint32) = (SDL_HasMMX() == SDL_TRUE); +#else + STUB(); +#endif // _WIN32 } @@ -468,13 +538,12 @@ void get_system_info() */ void get_system_time() { - SYSTEMTIME systime; - - GetSystemTime(&systime); - RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_DAY, sint16) = systime.wDay; - RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_MONTH, sint16) = systime.wMonth; - RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_YEAR, sint16) = systime.wYear; - RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_DAYOFWEEK, sint16) = systime.wDayOfWeek; + rct2_date date; + platform_get_date(&date); + RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_DAY, sint16) = date.day; + RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_MONTH, sint16) = date.month; + RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_YEAR, sint16) = date.year; + RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_DAYOFWEEK, sint16) = date.day_of_week; } /** @@ -483,11 +552,10 @@ void get_system_time() */ void get_local_time() { - SYSTEMTIME systime; - GetLocalTime(&systime); - - RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_HOUR, sint16) = systime.wHour; - RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_MINUTE, sint16) = systime.wMinute; + rct2_time t; + platform_get_time(&t); + RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_HOUR, sint16) = t.hour; + RCT2_GLOBAL(RCT2_ADDRESS_OS_TIME_MINUTE, sint16) = t.minute; } /** @@ -497,7 +565,12 @@ void get_local_time() */ void *rct2_malloc(size_t numBytes) { + #ifdef _WIN32 return RCT2_CALLFUNC_1(0x004068B2, void*, size_t, numBytes); + #else + //log_warning("call rct's function"); + return malloc(numBytes); + #endif // _WIN32 } /** @@ -507,14 +580,24 @@ void *rct2_malloc(size_t numBytes) */ void *rct2_realloc(void *block, size_t numBytes) { + #ifdef _WIN32 return RCT2_CALLFUNC_2(0x004068BD, void*, void*, size_t, block, numBytes); + #else + //log_warning("call rct's function"); + return realloc(block, numBytes); + #endif // _WIN32 } /** * RCT2 and this DLL can not free each other's allocated memory blocks. Use this to free memory that was allocated by RCT2. - * rct2: 0x004068DE + * rct2: 0x004068CD */ void rct2_free(void *block) { - RCT2_CALLPROC_1(0x004068DE, void*, block); + #ifdef _WIN32 + RCT2_CALLPROC_1(0x004068CD, void*, block); + #else + //log_warning("call rct's function"); + free(block); + #endif // _WIN32 } diff --git a/src/rct2.h b/src/rct2.h index 0ea6a5665b..7fafed7633 100644 --- a/src/rct2.h +++ b/src/rct2.h @@ -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 @@ -17,12 +17,19 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ - + #ifndef _RCT2_H_ #define _RCT2_H_ +#ifndef _USE_MATH_DEFINES + #define _USE_MATH_DEFINES +#endif +#undef M_PI + #include #include +#include +#include #include #include #include @@ -66,6 +73,9 @@ typedef utf16* utf16string; #define sgn(x) ((x > 0) ? 1 : ((x < 0) ? -1 : 0)) #define clamp(l, x, h) (min(h, max(l, x))) +// Rounds an integer down to the given power of 2. y must be a power of 2. +#define floor2(x, y) ((x) & (~((y) - 1))) + #define countof(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) #ifndef _MSC_VER @@ -74,24 +84,40 @@ typedef utf16* utf16string; #endif #define OPENRCT2_NAME "OpenRCT2" -#define OPENRCT2_VERSION "0.0.2" +#define OPENRCT2_VERSION "0.0.3" #define OPENRCT2_ARCHITECTURE "x86" -#define OPENRCT2_PLATFORM "Windows" +#ifdef _WIN32 + #define OPENRCT2_PLATFORM "Windows" +#endif // _WIN32 +#ifdef __linux__ + #define OPENRCT2_PLATFORM "Linux" +#endif +#if defined(__APPLE__) && defined(__MACH__) + #define OPENRCT2_PLATFORM "OS X" +#endif +#ifndef OPENRCT2_PLATFORM + #error Unknown platform! +#endif #define OPENRCT2_TIMESTAMP __DATE__ " " __TIME__ // The following constants are for automated build servers +#define OPENRCT2_BUILD_NUMBER "" #define OPENRCT2_BUILD_SERVER "" #define OPENRCT2_BRANCH "" #define OPENRCT2_COMMIT_SHA1 "" #define OPENRCT2_COMMIT_SHA1_SHORT "" +#define OPENRCT2_MASTER_SERVER_URL "https://servers.openrct2.website" // Represent fixed point numbers. dp = decimal point +typedef uint8 fixed8_1dp; +typedef uint8 fixed8_2dp; typedef sint16 fixed16_1dp; typedef sint16 fixed16_2dp; typedef sint32 fixed32_1dp; typedef sint32 fixed32_2dp; // Money is stored as a multiple of 0.10. +typedef fixed8_1dp money8; typedef fixed16_1dp money16; typedef fixed32_1dp money32; @@ -146,22 +172,12 @@ enum { PATH_ID_CSS7, PATH_ID_CSS8, PATH_ID_CSS9, - PATH_ID_CSS10, PATH_ID_CSS11, PATH_ID_CSS12, PATH_ID_CSS13, PATH_ID_CSS14, PATH_ID_CSS15, - PATH_ID_CSS16, PATH_ID_CSS3, - PATH_ID_GAMECFG, - PATH_ID_TUT640A, - PATH_ID_TUT640B, - PATH_ID_TUT640C, - PATH_ID_TUT800A, - PATH_ID_TUT800B, - PATH_ID_TUT800C, - PATH_ID_KANJI, PATH_ID_CSS17, PATH_ID_CSS18, PATH_ID_CSS19, @@ -189,10 +205,8 @@ enum { PATH_ID_CUSTOM2, PATH_ID_CSS39, PATH_ID_CSS40, - PATH_ID_TRACKSIDX, PATH_ID_CSS41, PATH_ID_SIXFLAGS_MAGICMOUNTAIN, - PATH_ID_SIXFLAGS_BUILDYOUROWN, PATH_ID_CSS42, PATH_ID_CSS43, PATH_ID_CSS44, @@ -205,69 +219,57 @@ enum { // rct2 @ 0x0097F67C static const char * const file_paths[] = { - "Data\\G1.DAT", - "Data\\PLUGIN.DAT", - "Data\\CSS1.DAT", - "Data\\CSS2.DAT", - "Data\\CSS4.DAT", - "Data\\CSS5.DAT", - "Data\\CSS6.DAT", - "Data\\CSS7.DAT", - "Data\\CSS8.DAT", - "Data\\CSS9.DAT", - "Data\\CSS10.DAT", - "Data\\CSS11.DAT", - "Data\\CSS12.DAT", - "Data\\CSS13.DAT", - "Data\\CSS14.DAT", - "Data\\CSS15.DAT", - "Data\\CSS16.DAT", - "Data\\CSS3.DAT", - "Data\\GAME.CFG", - "Data\\TUT640A.DAT", - "Data\\TUT640B.DAT", - "Data\\TUT640C.DAT", - "Data\\TUT800A.DAT", - "Data\\TUT800B.DAT", - "Data\\TUT800C.DAT", - "Data\\KANJI.DAT", - "Data\\CSS17.DAT", - "Data\\CSS18.DAT", - "Data\\CSS19.DAT", - "Data\\CSS20.DAT", - "Data\\CSS21.DAT", - "Data\\CSS22.DAT", - "Saved Games\\scores.DAT", - "Data\\CSS23.DAT", - "Data\\CSS24.DAT", - "Data\\CSS25.DAT", - "Data\\CSS26.DAT", - "Data\\CSS27.DAT", - "Data\\CSS28.DAT", - "Data\\CSS29.DAT", - "Data\\CSS30.DAT", - "Data\\CSS31.DAT", - "Data\\CSS32.DAT", - "Data\\CSS33.DAT", - "Data\\CSS34.DAT", - "Data\\CSS35.DAT", - "Data\\CSS36.DAT", - "Data\\CSS37.DAT", - "Data\\CSS38.DAT", + "Data\\g1.dat", + "Data\\plugin.dat", + "Data\\css1.dat", + "Data\\css2.dat", + "Data\\css4.dat", + "Data\\css5.dat", + "Data\\css6.dat", + "Data\\css7.dat", + "Data\\css8.dat", + "Data\\css9.dat", + "Data\\css11.dat", + "Data\\css12.dat", + "Data\\css13.dat", + "Data\\css14.dat", + "Data\\css15.dat", + "Data\\css3.dat", + "Data\\css17.dat", + "Data\\css18.dat", + "Data\\css19.dat", + "Data\\css20.dat", + "Data\\css21.dat", + "Data\\css22.dat", + "Saved Games\\scores.dat", + "Data\\css23.dat", + "Data\\css24.dat", + "Data\\css25.dat", + "Data\\css26.dat", + "Data\\css27.dat", + "Data\\css28.dat", + "Data\\css29.dat", + "Data\\css30.dat", + "Data\\css31.dat", + "Data\\css32.dat", + "Data\\css33.dat", + "Data\\css34.dat", + "Data\\css35.dat", + "Data\\css36.dat", + "Data\\css37.dat", + "Data\\css38.dat", "Data\\CUSTOM1.WAV", "Data\\CUSTOM2.WAV", - "Data\\CSS39.DAT", - "Data\\CSS40.DAT", - "Tracks\\Tracks.IDX", - "Data\\CSS41.DAT", + "Data\\css39.dat", + "Data\\css40.dat", + "Data\\css41.dat", "Scenarios\\Six Flags Magic Mountain.SC6", - "Scenarios\\Build your own Six Flags Park.SC6", - "Data\\CSS42.DAT", - "Data\\CSS43.DAT", - "Data\\CSS44.DAT", - "Data\\CSS45.DAT", - "Data\\CSS46.DAT", - "Data\\CSS50.DAT" + "Data\\css42.dat", + "Data\\css43.dat", + "Data\\css44.dat", + "Data\\css45.dat", + "Data\\css46.dat", + "Data\\css50.dat" }; // Files to check (rct2 @ 0x0097FB5A) @@ -276,34 +278,14 @@ static const struct file_to_check int pathId; // ID of file unsigned int fileSize; // Expected size in bytes } files_to_check[] = { - { PATH_ID_CSS18, 8429568 }, - { PATH_ID_CSS19, 10143784 }, - { PATH_ID_CSS20, 12271656 }, - { PATH_ID_CSS21, 9680968 }, - { PATH_ID_CSS22, 10062056 }, - { PATH_ID_CSS23, 11067432 }, - { PATH_ID_CSS24, 12427456 }, - { PATH_ID_CSS25, 15181512 }, - { PATH_ID_CSS26, 10694816 }, - { PATH_ID_CSS27, 10421232 }, - { PATH_ID_CSS28, 13118376 }, - { PATH_ID_CSS29, 15310892 }, - { PATH_ID_CSS30, 10215464 }, - { PATH_ID_CSS31, 11510316 }, - { PATH_ID_CSS32, 11771944 }, - { PATH_ID_CSS33, 10759724 }, - { PATH_ID_CSS34, 14030716 }, - { PATH_ID_CSS35, 11642576 }, - { PATH_ID_CSS36, 8953764 }, - { PATH_ID_CSS37, 13303852 }, - { PATH_ID_CSS38, 10093888 }, - { PATH_ID_CSS39, 7531564 }, - { PATH_ID_CSS40, 5291306 }, { PATH_ID_END, 0 } }; +extern uint32 gCurrentDrawCount; + int rct2_init(); void rct2_update(); +void rct2_draw(); void rct2_endupdate(); void subsitute_path(char *dest, const char *path, const char *filename); int check_mutex(); diff --git a/src/ride/ride.c b/src/ride/ride.c index 519fd72bd4..7340a3e298 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.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,8 +21,10 @@ #include "../addresses.h" #include "../audio/audio.h" #include "../audio/mixer.h" +#include "../cheats.h" #include "../common.h" #include "../config.h" +#include "../editor.h" #include "../game.h" #include "../input.h" #include "../interface/window.h" @@ -31,17 +33,22 @@ #include "../management/finance.h" #include "../management/marketing.h" #include "../management/news_item.h" +#include "../network/network.h" #include "../peep/peep.h" #include "../peep/staff.h" +#include "../rct1.h" #include "../scenario.h" #include "../util/util.h" #include "../windows/error.h" #include "../world/banner.h" +#include "../world/footpath.h" #include "../world/map.h" +#include "../world/map_animation.h" #include "../world/sprite.h" #include "ride.h" #include "ride_data.h" #include "track.h" +#include "track_data.h" #include "station.h" #pragma region Ride classification table @@ -119,8 +126,14 @@ static const int RideInspectionInterval[] = { 10, 20, 30, 45, 60, 120, 0, 0 }; -rct_ride_type **gRideTypeList = RCT2_ADDRESS(0x009ACFA4, rct_ride_type*); +rct_ride_type **gRideTypeList = RCT2_ADDRESS(RCT2_ADDRESS_RIDE_ENTRIES, rct_ride_type*); rct_ride* g_ride_list = RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride); +bool gGotoStartPlacementMode = false; +int gRideRemoveTrackPieceCallbackX; +int gRideRemoveTrackPieceCallbackY; +int gRideRemoveTrackPieceCallbackZ; +int gRideRemoveTrackPieceCallbackDirection; +int gRideRemoveTrackPieceCallbackType; // Static function declarations rct_peep *find_closest_mechanic(int x, int y, int forInspection); @@ -138,6 +151,9 @@ 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); +static void ride_update_vehicle_colours(int rideIndex); +static void ride_set_vehicle_colours_to_random_preset(rct_ride *ride, uint8 preset_index); +static void maze_entrance_hedge_removal(int x, int y, rct_map_element *mapElement); rct_ride_type *ride_get_entry(rct_ride *ride) { @@ -230,6 +246,27 @@ money32 get_shop_item_cost(int shopItem) RCT2_GLOBAL(0x00982144 + (shopItem * 8), uint16); } +money16 get_shop_base_value(int shopItem) +{ + return shopItem < 32 ? + RCT2_GLOBAL((0x00982164 + 2) + (shopItem * 8), uint16) : + RCT2_GLOBAL((0x00982144 + 2) + (shopItem * 8), uint16); +} + +money16 get_shop_cold_value(int shopItem) +{ + return shopItem < 32 ? + RCT2_GLOBAL((0x00982164 + 4) + (shopItem * 8), uint16) : + RCT2_GLOBAL((0x00982144 + 4) + (shopItem * 8), uint16); +} + +money16 get_shop_hot_value(int shopItem) +{ + return shopItem < 32 ? + RCT2_GLOBAL((0x00982164 + 6) + (shopItem * 8), uint16) : + RCT2_GLOBAL((0x00982144 + 6) + (shopItem * 8), uint16); +} + /** * * rct2: 0x006AC3AB @@ -238,7 +275,7 @@ money32 ride_calculate_income_per_hour(rct_ride *ride) { rct_ride_type *entry; money32 incomePerHour, priceMinusCost; - int shopItem; + int currentShopItem; entry = GET_RIDE_ENTRY(ride->subtype); incomePerHour = @@ -255,16 +292,21 @@ money32 ride_calculate_income_per_hour(rct_ride *ride) incomePerHour *= 12; priceMinusCost = ride->price; - shopItem = entry->shop_item; - if (shopItem != 255) { - priceMinusCost -= get_shop_item_cost(shopItem); + currentShopItem = entry->shop_item; + if (currentShopItem != 255) { + priceMinusCost -= get_shop_item_cost(currentShopItem); + } - shopItem = entry->shop_item_secondary; - if (shopItem != 255) { - priceMinusCost += ride->price_secondary; - priceMinusCost -= get_shop_item_cost(shopItem); + currentShopItem = ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO ? + RCT2_GLOBAL(0x0097D7CB + (ride->type * 4), uint8) : + entry->shop_item_secondary; + + if (currentShopItem != 255) { + priceMinusCost += ride->price_secondary; + priceMinusCost -= get_shop_item_cost(currentShopItem); + + if(entry->shop_item!=255) priceMinusCost /= 2; - } } incomePerHour *= priceMinusCost; @@ -272,7 +314,7 @@ money32 ride_calculate_income_per_hour(rct_ride *ride) } /** - * + * * rct2: 0x006CAF80 * ax result x * bx result y @@ -325,26 +367,280 @@ int sub_6CAF80(int rideIndex, rct_xy_element *output) } /** - * - * rct2: 0x006C60C2 - */ -int track_get_next(rct_xy_element *input, rct_xy_element *output) +* +* rct2: 0x006C6096 +* Gets the next track block coordinates from the +* coordinates of the first of element of a track block. +* Use track_block_get_next if you are unsure if you are +* on the first element of a track block +*/ +bool track_block_get_next_from_zero(sint16 x, sint16 y, sint16 z_start, uint8 rideIndex, uint8 direction_start, rct_xy_element *output, int *z, int *direction) { - int eax, ebx, ecx, edx, esi, edi, ebp, result; + rct_ride* ride = GET_RIDE(rideIndex); + RCT2_GLOBAL(0x00F441D3, uint8) = direction_start; - 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; + if (!(direction_start & (1 << 2))){ + x += RCT2_ADDRESS(0x00993CCC, sint16)[RCT2_GLOBAL(0x00F441D3, uint8) * 2]; + y += RCT2_ADDRESS(0x00993CCE, sint16)[RCT2_GLOBAL(0x00F441D3, uint8) * 2]; + } - return (result & 0x100) == 0; + rct_map_element* mapElement = map_get_first_element_at(x / 32, y / 32); + if (mapElement == NULL){ + output->element = NULL; + output->x = (sint16)0x8000; + return 0; + } + + do{ + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + + if (mapElement->properties.track.ride_index != rideIndex) + continue; + + if ((mapElement->properties.track.sequence & 0xF) != 0) + continue; + + const rct_preview_track* nextTrackBlock = get_track_def_from_ride(ride, mapElement->properties.track.type); + const rct_track_coordinates* nextTrackCoordinate = get_track_coord_from_ride(ride, mapElement->properties.track.type); + + uint8 nextRotation = + ((nextTrackCoordinate->rotation_begin + + (mapElement->type & MAP_ELEMENT_DIRECTION_MASK)) & MAP_ELEMENT_DIRECTION_MASK) | + (nextTrackCoordinate->rotation_begin & (1 << 2)); + + if (nextRotation != RCT2_GLOBAL(0x00F441D3, uint8)) + continue; + + sint16 nextZ = nextTrackCoordinate->z_begin - nextTrackBlock->z + mapElement->base_height * 8; + if (nextZ != z_start) + continue; + + if (z != NULL) *z = mapElement->base_height * 8; + if (direction != NULL) *direction = nextRotation; + output->x = x; + output->y = y; + output->element = mapElement; + return 1; + } while (!map_element_is_last_for_tile(mapElement++)); + + if (direction != NULL) *direction = RCT2_GLOBAL(0x00F441D3, uint8); + if (z != NULL) *z = z_start; + output->x = x; + output->y = y; + output->element = --mapElement; + return 0; } /** - * + * + * rct2: 0x006C60C2 + */ +bool track_block_get_next(rct_xy_element *input, rct_xy_element *output, int *z, int *direction) +{ + uint8 rideIndex = input->element->properties.track.ride_index; + RCT2_GLOBAL(0x00F441D2, uint8) = rideIndex; + rct_ride* ride = GET_RIDE(rideIndex); + + const rct_preview_track* trackBlock = get_track_def_from_ride(ride, input->element->properties.track.type); + uint8 sequence = input->element->properties.track.sequence & 0xF; + trackBlock += sequence; + + const rct_track_coordinates* trackCoordinate = get_track_coord_from_ride(ride, input->element->properties.track.type); + + int x = input->x; + int y = input->y; + int OriginZ = input->element->base_height * 8; + + uint8 rotation = input->element->type & MAP_ELEMENT_DIRECTION_MASK; + switch (rotation){ + case 0: + x += trackCoordinate->x; + x -= trackBlock->x; + y += trackCoordinate->y; + y -= trackBlock->y; + break; + case 1: + x += trackCoordinate->y; + x -= trackBlock->y; + y -= trackCoordinate->x; + y += trackBlock->x; + break; + case 2: + x -= trackCoordinate->x; + x += trackBlock->x; + y -= trackCoordinate->y; + y += trackBlock->y; + break; + case 3: + x -= trackCoordinate->y; + x += trackBlock->y; + y += trackCoordinate->x; + y -= trackBlock->x; + break; + } + + OriginZ -= trackBlock->z; + OriginZ += trackCoordinate->z_end; + + uint8 directionStart = ((trackCoordinate->rotation_end + rotation) & MAP_ELEMENT_DIRECTION_MASK) | + (trackCoordinate->rotation_end & (1 << 2)); + + return track_block_get_next_from_zero(x, y, OriginZ, rideIndex, directionStart, output, z, direction); +} + +/* rct2: 0x006C63D6 + * Returns the begin position / direction and end position / direction of the track piece that procedes the given location. + * Gets the previous track block coordinates from the + * coordinates of the first of element of a track block. + * Use track_block_get_previous if you are unsure if you are + * on the first element of a track block + */ +bool track_block_get_previous_from_zero(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8 direction, track_begin_end *outTrackBeginEnd){ + rct_ride* ride = GET_RIDE(rideIndex); + + RCT2_GLOBAL(0x00F441D3, uint8) = direction; + direction ^= (1 << 1); + + if (!(direction & (1 << 2))){ + x += RCT2_ADDRESS(0x00993CCC, sint16)[direction * 2]; + y += RCT2_ADDRESS(0x00993CCE, sint16)[direction * 2]; + } + + rct_map_element* mapElement = map_get_first_element_at(x / 32, y / 32); + if (mapElement == NULL){ + outTrackBeginEnd->end_x = x; + outTrackBeginEnd->end_y = y; + outTrackBeginEnd->begin_element = NULL; + outTrackBeginEnd->begin_direction = RCT2_GLOBAL(0x00F441D3, uint8) ^ (1 << 1); + return 0; + } + + do{ + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + + if (mapElement->properties.track.ride_index != rideIndex) + continue; + + const rct_preview_track* nextTrackBlock = get_track_def_from_ride(ride, mapElement->properties.track.type); + const rct_track_coordinates* nextTrackCoordinate = get_track_coord_from_ride(ride, mapElement->properties.track.type); + + nextTrackBlock += mapElement->properties.track.sequence & 0xF; + if ((nextTrackBlock + 1)->index != 255) + continue; + + uint8 nextRotation = + ((nextTrackCoordinate->rotation_end + + (mapElement->type & MAP_ELEMENT_DIRECTION_MASK)) & MAP_ELEMENT_DIRECTION_MASK) | + (nextTrackCoordinate->rotation_end & (1 << 2)); + + if (nextRotation != RCT2_GLOBAL(0x00F441D3, uint8)) + continue; + + sint16 nextZ = nextTrackCoordinate->z_end - nextTrackBlock->z + mapElement->base_height * 8; + if (nextZ != z) + continue; + + nextRotation = + ((nextTrackCoordinate->rotation_begin + + (mapElement->type & MAP_ELEMENT_DIRECTION_MASK)) & MAP_ELEMENT_DIRECTION_MASK) | + (nextTrackCoordinate->rotation_begin & (1 << 2)); + outTrackBeginEnd->begin_element = mapElement; + outTrackBeginEnd->begin_x = x; + outTrackBeginEnd->begin_y = y; + outTrackBeginEnd->end_x = x; + outTrackBeginEnd->end_y = y; + switch (nextRotation & 3){ + case 0: + outTrackBeginEnd->begin_x -= nextTrackCoordinate->x; + outTrackBeginEnd->begin_y -= nextTrackCoordinate->y; + break; + case 1: + outTrackBeginEnd->begin_x -= nextTrackCoordinate->y; + outTrackBeginEnd->begin_y += nextTrackCoordinate->x; + break; + case 2: + outTrackBeginEnd->begin_x += nextTrackCoordinate->x; + outTrackBeginEnd->begin_y += nextTrackCoordinate->y; + break; + case 3: + outTrackBeginEnd->begin_x += nextTrackCoordinate->y; + outTrackBeginEnd->begin_y -= nextTrackCoordinate->x; + break; + } + + outTrackBeginEnd->begin_z = mapElement->base_height * 8; + outTrackBeginEnd->begin_z += + get_track_def_from_ride(ride, mapElement->properties.track.type)->z - + nextTrackBlock->z; + + outTrackBeginEnd->begin_direction = nextRotation; + outTrackBeginEnd->end_direction = RCT2_GLOBAL(0x00F441D3, uint8) ^ (1 << 1); + return 1; + } while (!map_element_is_last_for_tile(mapElement++)); + + outTrackBeginEnd->end_x = x; + outTrackBeginEnd->end_y = y; + outTrackBeginEnd->begin_z = z; + outTrackBeginEnd->begin_element = NULL; + outTrackBeginEnd->end_direction = RCT2_GLOBAL(0x00F441D3, uint8) ^ (1 << 1); + return 0; +} + +/** + * + * rct2: 0x006C6402 + * + * @remarks outTrackBeginEnd.begin_x and outTrackBeginEnd.begin_y will be in the higher two bytes of ecx and edx where as + outTrackBeginEnd.end_x and outTrackBeginEnd.end_y will be in the lower two bytes (cx and dx). + */ +bool track_block_get_previous(int x, int y, rct_map_element *mapElement, track_begin_end *outTrackBeginEnd) +{ + uint8 rideIndex = mapElement->properties.track.ride_index; + RCT2_GLOBAL(0x00F441D2, uint8) = rideIndex; + rct_ride* ride = GET_RIDE(rideIndex); + + const rct_preview_track* trackBlock = get_track_def_from_ride(ride, mapElement->properties.track.type); + uint8 sequence = mapElement->properties.track.sequence & 0xF; + trackBlock += sequence; + + const rct_track_coordinates* trackCoordinate = get_track_coord_from_ride(ride, mapElement->properties.track.type); + + int z = mapElement->base_height * 8; + + uint8 rotation = mapElement->type & MAP_ELEMENT_DIRECTION_MASK; + switch (rotation){ + case 0: + x -= trackBlock->x; + y -= trackBlock->y; + break; + case 1: + x -= trackBlock->y; + y += trackBlock->x; + break; + case 2: + x += trackBlock->x; + y += trackBlock->y; + break; + case 3: + x += trackBlock->y; + y -= trackBlock->x; + break; + } + + z -= trackBlock->z; + z += trackCoordinate->z_begin; + + rotation = + ((trackCoordinate->rotation_begin + rotation) & MAP_ELEMENT_DIRECTION_MASK) | + (trackCoordinate->rotation_begin & (1 << 2)); + + return track_block_get_previous_from_zero(x, y, z, rideIndex, rotation, outTrackBeginEnd); +} + +/** + * * Make sure to pass in the x and y of the start track element too. * rct2: 0x006CB02F * ax result x @@ -353,47 +649,38 @@ 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) { - int rideIndex; - rct_xy_element trackElement, nextTrackElement; - rct_map_element *loopTrackElement; - rct_ride *ride; rct_window *w; + rct_ride *ride; + track_circuit_iterator it; + int rideIndex; - trackElement = *input; - rideIndex = trackElement.element->properties.track.ride_index; + rideIndex = input->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) + if (w != NULL && _rideConstructionState != RIDE_CONSTRUCTION_STATE_0 && _currentRideIndex == rideIndex) sub_6C9627(); - loopTrackElement = NULL; - while (1) { - if (!track_get_next(&trackElement, &nextTrackElement)) { - *output = trackElement; + track_circuit_iterator_begin(&it, *input); + while (track_circuit_iterator_next(&it)) { + if (!track_is_connected_by_shape(it.last.element, it.current.element)) { + *output = it.current; 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; + } + if (!it.looped) { + *output = it.last; + return 1; } return 0; } /** - * + * * rct2: 0x006AF561 */ void ride_get_status(int rideIndex, int *formatSecondary, int *argument) @@ -456,7 +743,7 @@ int ride_get_total_time(rct_ride *ride) int ride_can_have_multiple_circuits(rct_ride *ride) { - if (!(RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint16) & 0x200)) + if (!(RideData4[ride->type].flags & RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS)) return 0; // Only allow circuit or launch modes @@ -467,7 +754,7 @@ int ride_can_have_multiple_circuits(rct_ride *ride) ) { return 0; } - + // Must have no more than one vehicle and one station if (ride->num_vehicles > 1 || ride->num_stations > 1) return 0; @@ -530,7 +817,7 @@ static int ride_check_if_construction_allowed(rct_ride *ride) if (ride->status != RIDE_STATUS_CLOSED) { RCT2_GLOBAL(0x013CE952 + 6, uint16) = ride->name; RCT2_GLOBAL(0x013CE952 + 8, uint32) = ride->name_arguments; - window_error_open(STR_CANT_START_CONSTRUCTION_ON, STR_MUST_BE_CLOSED_FIRST); + window_error_open(STR_CANT_START_CONSTRUCTION_ON, STR_MUST_BE_CLOSED_FIRST); return 0; } @@ -544,11 +831,11 @@ static rct_window *ride_create_or_find_construction_window(int rideIndex) w = window_find_by_class(WC_RIDE_CONSTRUCTION); if (w == NULL || w->number != rideIndex) { window_close_construction_windows(); - RCT2_GLOBAL(0x00F440A7, uint8) = rideIndex; - w = window_construction_open(rideIndex); + _currentRideIndex = rideIndex; + w = window_ride_construction_open(rideIndex); } else { sub_6C9627(); - RCT2_GLOBAL(0x00F440A7, uint8) = rideIndex; + _currentRideIndex = rideIndex; } return w; @@ -560,13 +847,14 @@ int ride_create_ride(ride_list_item listItem) edx = *((uint16*)&listItem); eax = 0; ecx = 0; - ebx = 1; + ebx = GAME_COMMAND_FLAG_APPLY; edi = 0; esi = 0; + ebp = 0; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 0x3DC; - esi = GAME_COMMAND_6; + esi = GAME_COMMAND_CREATE_RIDE; game_do_command_p(esi, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); return ebx == MONEY32_UNDEFINED ? -1 : edi; } @@ -579,9 +867,12 @@ void ride_construct_new(ride_list_item listItem) { int rideIndex; + game_command_callback = game_command_callback_ride_construct_new; rideIndex = ride_create_ride(listItem); - if (rideIndex != -1) - ride_construct(rideIndex); + + // moved to game_command_callback_ride_construct_new: + /*if (rideIndex != -1) + ride_construct(rideIndex);*/ } /** @@ -605,16 +896,7 @@ void ride_construct(int rideIndex) } /** - * - * rct2: 0x006C84CE - */ -static void sub_6C84CE() -{ - RCT2_CALLPROC_X(0x006C84CE, 0, 0, 0, 0, 0, 0, 0); -} - -/** - * + * * rct2: 0x006DD4D5 */ static void ride_remove_cable_lift(rct_ride *ride) @@ -626,8 +908,8 @@ static void ride_remove_cable_lift(rct_ride *ride) ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CABLE_LIFT; spriteIndex = ride->cable_lift; do { - vehicle = &(g_sprite_list[spriteIndex].vehicle); - invalidate_sprite((rct_sprite*)vehicle); + vehicle = GET_VEHICLE(spriteIndex); + invalidate_sprite_2((rct_sprite*)vehicle); sprite_remove((rct_sprite*)vehicle); spriteIndex = vehicle->next_vehicle_on_train; } while (spriteIndex != SPRITE_INDEX_NULL); @@ -635,7 +917,7 @@ static void ride_remove_cable_lift(rct_ride *ride) } /** - * + * * rct2: 0x006DD506 */ static void ride_remove_vehicles(rct_ride *ride) @@ -651,8 +933,8 @@ static void ride_remove_vehicles(rct_ride *ride) for (i = 0; i < 32; i++) { spriteIndex = ride->vehicles[i]; while (spriteIndex != SPRITE_INDEX_NULL) { - vehicle = &(g_sprite_list[spriteIndex].vehicle); - invalidate_sprite((rct_sprite*)vehicle); + vehicle = GET_VEHICLE(spriteIndex); + invalidate_sprite_2((rct_sprite*)vehicle); sprite_remove((rct_sprite*)vehicle); spriteIndex = vehicle->next_vehicle_on_train; } @@ -666,10 +948,10 @@ static void ride_remove_vehicles(rct_ride *ride) } /** - * + * * rct2: 0x006DD4AC */ -static void ride_clear_for_construction(int rideIndex) +void ride_clear_for_construction(int rideIndex) { rct_ride *ride; rct_window *w; @@ -677,7 +959,7 @@ static void ride_clear_for_construction(int rideIndex) ride = GET_RIDE(rideIndex); ride_measurement_clear(ride); - + ride->lifecycle_flags &= ~(RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN); ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; @@ -690,10 +972,10 @@ static void ride_clear_for_construction(int rideIndex) } /** - * + * * rct2: 0x006664DF */ -static void ride_remove_peeps(int rideIndex) +void ride_remove_peeps(int rideIndex) { int i, stationIndex, x, y, z, exitX, exitY, exitZ, exitDirection; uint16 xy, spriteIndex; @@ -749,7 +1031,7 @@ static void ride_remove_peeps(int rideIndex) if (peep->state == PEEP_STATE_QUEUING_FRONT && peep->sub_state == 0) remove_peep_from_queue(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); if (exitDirection == 255) { x = peep->next_x + 16; @@ -764,13 +1046,13 @@ static void ride_remove_peeps(int rideIndex) peep->sprite_direction = exitDirection; } - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); peep->state = PEEP_STATE_FALLING; - RCT2_CALLPROC_X(0x00693BE5, 0, 0, 0, 0, (int)peep, 0, 0); - + sub_693BE5(peep, 0); + peep->happiness = min(peep->happiness, peep->happiness_growth_rate) / 2; peep->happiness_growth_rate = peep->happiness; - peep->var_45 |= 2; + peep->window_invalidate_flags |= PEEP_INVALIDATE_PEEP_STATS; } } @@ -779,7 +1061,9 @@ static void ride_remove_peeps(int rideIndex) ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN; } -/* rct2: 0x006C683D +/** + * Gets the origin track element (sequence 0). Seems to do more than that though and even invalidates track. + * rct2: 0x006C683D * ax : x * bx : direction << 8, type * cx : y @@ -790,49 +1074,38 @@ static void ride_remove_peeps(int rideIndex) */ int sub_6C683D(int* x, int* y, int* z, int direction, int type, uint16 extra_params, rct_map_element** output_element, uint16 flags) { - rct_map_element* map_element = map_get_first_element_at(*x / 32, *y / 32); - rct_map_element* success_map = NULL; + rct_map_element *mapElement = map_get_first_element_at(*x / 32, *y / 32); + rct_map_element *successMapElement = NULL; - do{ - if (map_element->base_height != *z / 8) + do { + if (mapElement->base_height != *z / 8) continue; - if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_TRACK) + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) continue; - if ((map_element->type & MAP_ELEMENT_DIRECTION_MASK) != direction) + if ((mapElement->type & MAP_ELEMENT_DIRECTION_MASK) != direction) continue; - if (type != map_element->properties.track.type) + if (type != mapElement->properties.track.type) continue; - success_map = map_element; - if (!(map_element->properties.track.sequence & 0xF)) + successMapElement = mapElement; + if ((mapElement->properties.track.sequence & 0x0F) == 0) break; - }while(!map_element_is_last_for_tile(map_element++)); + } while (!map_element_is_last_for_tile(mapElement++)); - map_element = success_map; - - if (map_element == NULL){ + mapElement = successMapElement; + if (mapElement == NULL) return 1; - } - // Possibly z should be &0xF8 - rct_ride* ride = GET_RIDE(map_element->properties.track.ride_index); - rct_preview_track *trackBlock; + // Possibly z should be & 0xF8 + const rct_preview_track *trackBlock = get_track_def_from_ride_index(mapElement->properties.track.ride_index, type); - 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 = mapElement->properties.track.sequence & 0x0F; + uint8 mapDirection = mapElement->type & MAP_ELEMENT_DIRECTION_MASK; - int sequence = map_element->properties.track.sequence & 0xF; - - uint8 map_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; - - switch (map_direction){ + switch (mapDirection){ case MAP_ELEMENT_DIRECTION_WEST: *x -= trackBlock[sequence].x; *y -= trackBlock[sequence].y; @@ -850,17 +1123,13 @@ int sub_6C683D(int* x, int* y, int* z, int direction, int type, uint16 extra_par *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){ + for (int i = 0; trackBlock[i].index != 0xFF; ++i){ int cur_x = start_x, cur_y = start_y, cur_z = start_z; - - switch (map_direction){ + switch (mapDirection){ case MAP_ELEMENT_DIRECTION_WEST: cur_x += trackBlock[i].x; cur_y += trackBlock[i].y; @@ -878,112 +1147,162 @@ int sub_6C683D(int* x, int* y, int* z, int direction, int type, uint16 extra_par 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) + mapElement = map_get_first_element_at(cur_x / 32, cur_y / 32); + successMapElement = NULL; + do { + if (mapElement->base_height != cur_z / 8) continue; - if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_TRACK) + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) continue; - if ((map_element->type & MAP_ELEMENT_DIRECTION_MASK) != direction) + if ((mapElement->type & MAP_ELEMENT_DIRECTION_MASK) != direction) continue; - if ((map_element->properties.track.sequence & 0xF) != trackBlock[i].var_00) + if ((mapElement->properties.track.sequence & 0xF) != trackBlock[i].index) continue; - if (type == map_element->properties.track.type) - { - success_map = map_element; + if (type == mapElement->properties.track.type) { + successMapElement = mapElement; break; } - } while (!map_element_is_last_for_tile(map_element++)); + } while (!map_element_is_last_for_tile(mapElement++)); - if (success_map == NULL){ + if (successMapElement == 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 (i == 0 && output_element != NULL) { + *output_element = mapElement; + } + if (flags & (1 << 0)) { + // Switch highlight off + mapElement->type &= ~MAP_ELEMENT_TYPE_FLAG_HIGHLIGHT; + } + if (flags & (1 << 1)) { + // Switch highlight on + mapElement->type |= MAP_ELEMENT_TYPE_FLAG_HIGHLIGHT; + } + if (flags & (1 << 2)) { + mapElement->properties.track.colour &= 0xFC; + mapElement->properties.track.colour |= extra_params & 0xFF; + } + if (flags & (1 << 5)) { + // Seat rotation + mapElement->properties.track.colour &= 0x0F; + mapElement->properties.track.colour |= (extra_params & 0xFF) << 4; } - if (flags & (1 << 1)){ - // Quadrant related ?? - map_element->type |= (1 << 6); + if (flags & (1 << 3)) { + track_element_set_cable_lift(mapElement); } - - 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; + if (flags & (1 << 4)) { + track_element_clear_cable_lift(mapElement); } } return 0; } +/** + * + * rct2: 0x006C96C0 + */ void sub_6C96C0() { - RCT2_CALLPROC_X(0x006C96C0, 0, 0, 0, 0, 0, 0, 0); + rct_ride *ride; + int rideIndex, x, y, z, direction; + + if (_currentTrackSelectionFlags & 4) { + _currentTrackSelectionFlags &= ~4; + game_do_command( + RCT2_GLOBAL(0x00F440BF, uint16), + (GAME_COMMAND_FLAG_5 | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_APPLY), + RCT2_GLOBAL(0x00F440C1, uint16), + _currentRideIndex, + GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT, + RCT2_GLOBAL(0x00F440C4, uint8), + 0 + ); + } + if (_currentTrackSelectionFlags & 2) { + _currentTrackSelectionFlags &= ~2; + + rideIndex = _currentRideIndex; + RCT2_GLOBAL(0x00F441D2, uint8) = rideIndex; + + x = RCT2_GLOBAL(0x00F440C5, uint16); + y = RCT2_GLOBAL(0x00F440C7, uint16); + z = RCT2_GLOBAL(0x00F440C9, uint16); + + ride = GET_RIDE(rideIndex); + if (ride->type == RIDE_TYPE_MAZE) { + game_do_command(x , 41 | (0 << 8), y , rideIndex | (2 << 8), GAME_COMMAND_SET_MAZE_TRACK, z, 0); + game_do_command(x , 41 | (1 << 8), y + 16, rideIndex | (2 << 8), GAME_COMMAND_SET_MAZE_TRACK, z, 0); + game_do_command(x + 16, 41 | (2 << 8), y + 16, rideIndex | (2 << 8), GAME_COMMAND_SET_MAZE_TRACK, z, 0); + game_do_command(x + 16, 41 | (3 << 8), y , rideIndex | (2 << 8), GAME_COMMAND_SET_MAZE_TRACK, z, 0); + } else { + direction = RCT2_GLOBAL(0x00F440CB, uint8); + if (!(direction & 4)) { + x -= TileDirectionDelta[direction].x; + y -= TileDirectionDelta[direction].y; + } + rct_xy_element next_track; + + if (track_block_get_next_from_zero(x, y, z, rideIndex, direction, &next_track, &z, &direction)) { + game_do_command( + next_track.x, + 105 | ((direction & 3) << 8), + next_track.y, + next_track.element->properties.track.type | ((next_track.element->properties.track.sequence & 0x0F) << 8), + GAME_COMMAND_REMOVE_TRACK, + z, + 0 + ); + } + } + } } 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); + int x, y, z; + + switch (_rideConstructionState) { + case RIDE_CONSTRUCTION_STATE_SELECTED: + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; sub_6C683D( &x, &y, &z, - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) & 3, - RCT2_GLOBAL(0x00F440AF, uint8), - 0, + _currentTrackPieceDirection & 3, + _currentTrackPieceType, 0, + NULL, 1 - ); - } + ); break; - case 6: - case 7: - case 8: - if (RCT2_GLOBAL(0x00F440B0, uint8) & 1) { + case RIDE_CONSTRUCTION_STATE_MAZE_BUILD: + case RIDE_CONSTRUCTION_STATE_MAZE_MOVE: + case RIDE_CONSTRUCTION_STATE_MAZE_FILL: + if (_currentTrackSelectionFlags & 1) { map_invalidate_tile_full( - RCT2_GLOBAL(0x00F440A8, uint16) & 0xFFE0, - RCT2_GLOBAL(0x00F440AA, uint16) & 0xFFE0 + _currentTrackBeginX & 0xFFE0, + _currentTrackBeginY & 0xFFE0 ); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~4; } break; default: - if (RCT2_GLOBAL(0x00F440B0, uint8) & 1) { - RCT2_GLOBAL(0x00F440B0, uint8) &= ~1; + if (_currentTrackSelectionFlags & 1) { + _currentTrackSelectionFlags &= ~1; RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint8) &= ~4; - map_invalidate_tile_full(RCT2_GLOBAL(0x00F440A8, uint16), RCT2_GLOBAL(0x00F440AA, uint16)); + map_invalidate_tile_full(_currentTrackBeginX, _currentTrackBeginY); } sub_6C96C0(); break; @@ -991,25 +1310,267 @@ void sub_6C9627() } /** - * + * + * rct2: 0x006C9B19 + */ +static void ride_construction_reset_current_piece() +{ + rct_ride *ride; + + ride = GET_RIDE(_currentRideIndex); + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_15) || ride->num_stations == 0) { + _currentTrackCurve = RCT2_GLOBAL(0x0097CC68 + (ride->type * 2), uint8) | 0x100; + _currentTrackSlopeEnd = 0; + _currentTrackBankEnd = 0; + _currentTrackLiftHill = 0; + _currentTrackCovered = 0; + if (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_15) { + _currentTrackCovered |= 2; + } + _previousTrackSlopeEnd = 0; + _previousTrackBankEnd = 0; + } else { + _currentTrackCurve = 0xFFFF; + _rideConstructionState = RIDE_CONSTRUCTION_STATE_0; + } +} + +/** + * + * rct2: 0x006C9800 + */ +void ride_construction_set_default_next_piece() +{ + int x, y, z, direction, rideIndex, trackType, curve, bank, slope; + rct_ride *ride; + track_begin_end trackBeginEnd; + rct_xy_element xyElement; + rct_map_element *mapElement; + + _currentTrackPrice = MONEY32_UNDEFINED; + switch (_rideConstructionState) { + case RIDE_CONSTRUCTION_STATE_FRONT: + rideIndex = _currentRideIndex; + ride = GET_RIDE(rideIndex); + + RCT2_GLOBAL(0x00F441D2, uint8) = rideIndex; + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; + direction = _currentTrackPieceDirection; + if (!track_block_get_previous_from_zero(x, y, z, rideIndex, direction, &trackBeginEnd)) { + ride_construction_reset_current_piece(); + return; + } + mapElement = trackBeginEnd.begin_element; + trackType = mapElement->properties.track.type; + + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_15)) { + ride_construction_reset_current_piece(); + return; + } + + // Set whether track is covered + _currentTrackCovered &= ~2; + if (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_3) { + if (mapElement->properties.track.colour & 4) { + _currentTrackCovered |= 2; + } + } + + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { + curve = gFlatRideTrackCurveChain[trackType].next; + bank = gFlatRideTrackDefinitions[trackType].bank_end; + slope = gFlatRideTrackDefinitions[trackType].vangle_end; + } else { + curve = gTrackCurveChain[trackType].next; + bank = gTrackDefinitions[trackType].bank_end; + slope = gTrackDefinitions[trackType].vangle_end; + } + + // Set track curve + _currentTrackCurve = curve; + + // Set track banking + if (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_3) { + if (bank == TRACK_BANK_UPSIDE_DOWN) { + bank = TRACK_BANK_NONE; + _currentTrackCovered ^= 2; + } + } + _currentTrackBankEnd = bank; + _previousTrackBankEnd = bank; + + // Set track slope and lift hill + _currentTrackSlopeEnd = slope; + _previousTrackSlopeEnd = slope; + _currentTrackLiftHill = ((mapElement->type & 0x80) && slope != TRACK_SLOPE_DOWN_25 && slope != TRACK_SLOPE_DOWN_60) != 0; + break; + case RIDE_CONSTRUCTION_STATE_BACK: + rideIndex = _currentRideIndex; + ride = GET_RIDE(rideIndex); + + RCT2_GLOBAL(0x00F441D2, uint8) = rideIndex; + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; + direction = _currentTrackPieceDirection ^ 2; + if (!track_block_get_next_from_zero(x, y, z, rideIndex, direction, &xyElement, &z, &direction)) { + ride_construction_reset_current_piece(); + return; + } + mapElement = xyElement.element; + trackType = mapElement->properties.track.type; + + // Set whether track is covered + _currentTrackCovered &= ~2; + if (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_3) { + if (mapElement->properties.track.colour & 4) { + _currentTrackCovered |= 2; + } + } + + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { + curve = gFlatRideTrackCurveChain[trackType].previous; + bank = gFlatRideTrackDefinitions[trackType].bank_start; + slope = gFlatRideTrackDefinitions[trackType].vangle_start; + } else { + curve = gTrackCurveChain[trackType].previous; + bank = gTrackDefinitions[trackType].bank_start; + slope = gTrackDefinitions[trackType].vangle_start; + } + + // Set track curve + _currentTrackCurve = curve; + + // Set track banking + if (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_3) { + if (bank == TRACK_BANK_UPSIDE_DOWN) { + bank = TRACK_BANK_NONE; + _currentTrackCovered ^= 2; + } + } + _currentTrackBankEnd = bank; + _previousTrackBankEnd = bank; + + // Set track slope and lift hill + _currentTrackSlopeEnd = slope; + _previousTrackSlopeEnd = slope; + _currentTrackLiftHill = track_element_is_lift_hill(mapElement); + break; + } +} + +/** + * * rct2: 0x006C9296 */ -static void sub_6C9296() +void ride_select_next_section() { - RCT2_CALLPROC_X(0x006C9296, 0, 0, 0, 0, 0, 0, 0); + int x, y, z, direction, type; + rct_map_element *mapElement; + rct_xy_element inputElement, outputElement; + + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_SELECTED) { + sub_6C9627(); + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; + direction = _currentTrackPieceDirection; + type = _currentTrackPieceType; + if (sub_6C683D(&x, &y, &z, direction & 3, type, 0, &mapElement, 0)) { + _rideConstructionState = RIDE_CONSTRUCTION_STATE_0; + sub_6C84CE(); + return; + } + inputElement.x = x; + inputElement.y = y; + inputElement.element = mapElement; + if (track_block_get_next(&inputElement, &outputElement, &z, &direction)) { + x = outputElement.x; + y = outputElement.y; + mapElement = outputElement.element; + } else { + _rideConstructionState = RIDE_CONSTRUCTION_STATE_FRONT; + _currentTrackBeginX = outputElement.x; + _currentTrackBeginY = outputElement.y; + _currentTrackBeginZ = z; + _currentTrackPieceDirection = direction; + _currentTrackPieceType = mapElement->properties.track.type; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; + ride_construction_set_default_next_piece(); + sub_6C84CE(); + return; + } + + _currentTrackBeginX = x; + _currentTrackBeginY = y; + _currentTrackBeginZ = z; + _currentTrackPieceDirection = (mapElement->type & MAP_ELEMENT_DIRECTION_MASK); + _currentTrackPieceType = mapElement->properties.track.type; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; + sub_6C84CE(); + } else if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_BACK) { + if (ride_select_forwards_from_back()) { + sub_6C84CE(); + } + } } /** - * + * * rct2: 0x006C93B8 */ -static void sub_6C93B8() +void ride_select_previous_section() { - RCT2_CALLPROC_X(0x006C93B8, 0, 0, 0, 0, 0, 0, 0); + int x, y, z, direction, type; + rct_map_element *mapElement; + track_begin_end trackBeginEnd; + + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_SELECTED) { + sub_6C9627(); + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; + direction = _currentTrackPieceDirection; + type = _currentTrackPieceType; + if (sub_6C683D(&x, &y, &z, direction & 3, type, 0, &mapElement, 0)) { + _rideConstructionState = RIDE_CONSTRUCTION_STATE_0; + sub_6C84CE(); + return; + } + if (track_block_get_previous(x, y, mapElement, &trackBeginEnd)) { + _currentTrackBeginX = trackBeginEnd.begin_x; + _currentTrackBeginY = trackBeginEnd.begin_y; + _currentTrackBeginZ = trackBeginEnd.begin_z; + _currentTrackPieceDirection = trackBeginEnd.begin_direction; + _currentTrackPieceType = trackBeginEnd.begin_element->properties.track.type; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; + sub_6C84CE(); + } else { + _rideConstructionState = RIDE_CONSTRUCTION_STATE_BACK; + _currentTrackBeginX = trackBeginEnd.end_x; + _currentTrackBeginY = trackBeginEnd.end_y; + _currentTrackBeginZ = trackBeginEnd.begin_z; + _currentTrackPieceDirection = trackBeginEnd.end_direction; + _currentTrackPieceType = mapElement->properties.track.type; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; + ride_construction_set_default_next_piece(); + sub_6C84CE(); + } + } else if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_FRONT) { + if (ride_select_backwards_from_front()) { + sub_6C84CE(); + } + } } /** - * + * * rct2: 0x006CC2CA */ static int ride_modify_entrance_or_exit(rct_map_element *mapElement, int x, int y) @@ -1038,7 +1599,7 @@ static int ride_modify_entrance_or_exit(rct_map_element *mapElement, int x, int sub_6C9627(); if ( - RCT2_GLOBAL(0x00F440A6, uint8) != 5 || + _rideConstructionState != RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT || !(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint8) & INPUT_FLAG_TOOL_ACTIVE) || RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_RIDE_CONSTRUCTION ) { @@ -1048,44 +1609,43 @@ static int ride_modify_entrance_or_exit(rct_map_element *mapElement, int x, int RCT2_GLOBAL(0x00F44192, uint8) = rideIndex; RCT2_GLOBAL(0x00F44193, uint8) = bl; RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint8) |= INPUT_FLAG_6; - int al = RCT2_GLOBAL(0x00F440A6, uint8); - if (al != 5) { - RCT2_GLOBAL(0x00F440A6, uint8) = 5; - RCT2_GLOBAL(0x00F440CC, uint8) = al; + if (_rideConstructionState != RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT) { + RCT2_GLOBAL(0x00F440CC, uint8) = _rideConstructionState; + _rideConstructionState = RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT; } sub_6C84CE(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~2; } else { // Remove entrance / exit - game_do_command(x, 9, y, rideIndex, GAME_COMMAND_13, bl, 0); + game_do_command(x, (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_APPLY), y, rideIndex, GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT, bl, 0); RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) = entranceType == ENTRANCE_TYPE_RIDE_ENTRANCE ? 29 : 30; RCT2_GLOBAL(0x00F44191, uint8) = entranceType; } - + window_invalidate_by_class(WC_RIDE_CONSTRUCTION); return 1; } /** - * + * * rct2: 0x006CC287 */ int ride_modify_maze(rct_map_element *mapElement, int x, int y) { - RCT2_GLOBAL(0x00F440A7, uint8) = mapElement->properties.track.ride_index; - RCT2_GLOBAL(0x00F440A6, uint8) = 6; - RCT2_GLOBAL(0x00F440A8, uint16) = x; - RCT2_GLOBAL(0x00F440AA, uint16) = y; - RCT2_GLOBAL(0x00F440AC, uint16) = mapElement->base_height * 8; - RCT2_GLOBAL(0x00F440B0, uint8) = 0; - RCT2_GLOBAL(0x00F440B1, uint8) = 0; - RCT2_CALLPROC_X(0x006CD887, 0, 0, 0, 0, 0, 0, 0); + _currentRideIndex = mapElement->properties.track.ride_index; + _rideConstructionState = RIDE_CONSTRUCTION_STATE_MAZE_BUILD; + _currentTrackBeginX = x; + _currentTrackBeginY = y; + _currentTrackBeginZ = mapElement->base_height * 8; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; + window_maze_construction_update_pressed_widgets(); return 1; } /** - * + * * rct2: 0x006CC056 */ int ride_modify(rct_xy_element *input) @@ -1109,15 +1669,8 @@ int ride_modify(rct_xy_element *input) return 0; } - 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); - return 0; - } - - ride_clear_for_construction(rideIndex); - ride_remove_peeps(rideIndex); + // Stop the ride again to clear all vehicles and peeps (compatible with network games) + ride_set_status(rideIndex, RIDE_STATUS_CLOSED); // Check if element is a station entrance or exit if (map_element_get_type(mapElement.element) == MAP_ELEMENT_TYPE_ENTRANCE) @@ -1128,7 +1681,7 @@ int ride_modify(rct_xy_element *input) if (ride->type == RIDE_TYPE_MAZE) return ride_modify_maze(mapElement.element, mapElement.x, mapElement.y); - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_8)) { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_CANNOT_HAVE_GAPS)) { if (ride_find_track_gap(&mapElement, &endOfTrackElement)) mapElement = endOfTrackElement; } @@ -1138,51 +1691,51 @@ int ride_modify(rct_xy_element *input) 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)) + + if (sub_6C683D(&x, &y, &z, direction, type, 0, NULL, 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(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = direction; - RCT2_GLOBAL(0x00F440AF, uint8) = type; - RCT2_GLOBAL(0x00F440B0, uint8) = 0; - RCT2_GLOBAL(0x00F440B1, uint8) = 0; + _currentRideIndex = rideIndex; + _rideConstructionState = RIDE_CONSTRUCTION_STATE_SELECTED; + _currentTrackBeginX = x; + _currentTrackBeginY = y; + _currentTrackBeginZ = z; + _currentTrackPieceDirection = direction; + _currentTrackPieceType = type; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_15)) { sub_6C84CE(); return 1; } - sub_6C9296(); - if (RCT2_GLOBAL(0x00F440A6, uint8) == 1) { + ride_select_next_section(); + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_FRONT) { sub_6C84CE(); return 1; } - RCT2_GLOBAL(0x00F440A6, uint8) = 3; - RCT2_GLOBAL(0x00F440A8, uint16) = x; - RCT2_GLOBAL(0x00F440AA, uint16) = y; - RCT2_GLOBAL(0x00F440AC, uint16) = z; - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = direction; - RCT2_GLOBAL(0x00F440AF, uint8) = type; - RCT2_GLOBAL(0x00F440B0, uint8) = 0; - RCT2_GLOBAL(0x00F440B1, uint8) = 0; + _rideConstructionState = RIDE_CONSTRUCTION_STATE_SELECTED; + _currentTrackBeginX = x; + _currentTrackBeginY = y; + _currentTrackBeginZ = z; + _currentTrackPieceDirection = direction; + _currentTrackPieceType = type; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; - sub_6C93B8(); + ride_select_previous_section(); - if (RCT2_GLOBAL(0x00F440A6, uint8) != 2) { - RCT2_GLOBAL(0x00F440A6, uint8) = 3; - RCT2_GLOBAL(0x00F440A8, uint16) = x; - RCT2_GLOBAL(0x00F440AA, uint16) = y; - RCT2_GLOBAL(0x00F440AC, uint16) = z; - 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 (_rideConstructionState != RIDE_CONSTRUCTION_STATE_BACK) { + _rideConstructionState = RIDE_CONSTRUCTION_STATE_SELECTED; + _currentTrackBeginX = x; + _currentTrackBeginY = y; + _currentTrackBeginZ = z; + _currentTrackPieceDirection = direction; + _currentTrackPieceType = type; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; } sub_6C84CE(); @@ -1190,7 +1743,7 @@ int ride_modify(rct_xy_element *input) } /** - * + * * rct2: 0x006CC3FB */ int sub_6CC3FB(int rideIndex) @@ -1212,24 +1765,24 @@ int sub_6CC3FB(int rideIndex) tool_set(w, 23, 12); RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; - ride = GET_RIDE(RCT2_GLOBAL(0x00F440A7, uint8)); + ride = GET_RIDE(_currentRideIndex); - RCT2_GLOBAL(0x00F440A0, uint16) = RCT2_ADDRESS(0x0097CC68, uint8)[ride->type * 2] | 0x100; - RCT2_GLOBAL(0x00F440B2, uint8) = 0; + _currentTrackCurve = RCT2_ADDRESS(0x0097CC68, uint8)[ride->type * 2] | 0x100; + _currentTrackSlopeEnd = 0; RCT2_GLOBAL(0x00F440B3, uint8) = 0; - RCT2_GLOBAL(0x00F440B4, uint8) = 0; - RCT2_GLOBAL(0x00F440B5, uint8) = 0; + _currentTrackLiftHill = 0; + _currentTrackCovered = 0; - if (RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint16) & 0x8000) - RCT2_GLOBAL(0x00F440B5, uint8) |= 2; + if (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_15) + _currentTrackCovered |= 2; - RCT2_GLOBAL(0x00F440B6, uint8) = 0; - RCT2_GLOBAL(0x00F440B7, uint8) = 0; + _previousTrackBankEnd = 0; + _previousTrackSlopeEnd = 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; + _currentTrackPieceDirection = 0; + _rideConstructionState = RIDE_CONSTRUCTION_STATE_PLACE; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; RCT2_GLOBAL(0x00F44159, uint8) = 0; RCT2_GLOBAL(0x00F4415C, uint8) = 0; @@ -1253,7 +1806,7 @@ void ride_update_all() // Remove all rides if scenario editor if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) { - if (s6Info->var_000 <= 2) + if (s6Info->editor_step <= EDITOR_STEP_INVENTIONS_LIST_SET_UP) FOR_ALL_RIDES(i, ride) ride->type = RIDE_TYPE_NULL; return; @@ -1276,7 +1829,7 @@ static void ride_update(int rideIndex) { int i; rct_ride *ride = GET_RIDE(rideIndex); - + if (ride->var_1CA != 0) ride->var_1CA--; @@ -1327,20 +1880,9 @@ static void ride_update(int 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); + rct_vehicle *vehicle = GET_VEHICLE(ride->vehicles[i]); if (vehicle->status == VEHICLE_STATUS_CRASHED || vehicle->status == VEHICLE_STATUS_CRASHING) { ride_set_status(rideIndex, RIDE_STATUS_CLOSED); @@ -1377,12 +1919,12 @@ static void ride_chairlift_update(rct_ride *ride) x = (ride->var_13A & 0xFF) * 32; y = (ride->var_13A >> 8) * 32; z = ride->var_13E * 8; - map_invalidate_tile(x, y, z, z + (4 * 8)); + map_invalidate_tile_zoom1(x, y, z, z + (4 * 8)); x = (ride->var_13C & 0xFF) * 32; y = (ride->var_13C >> 8) * 32; z = ride->var_13F * 8; - map_invalidate_tile(x, y, z, z + (4 * 8)); + map_invalidate_tile_zoom1(x, y, z, z + (4 * 8)); } /** @@ -1452,13 +1994,13 @@ static void ride_spiral_slide_update(rct_ride *ride) z = ride->station_heights[i]; mapElement = ride_get_station_start_track_element(ride, i); - int rotation = ((mapElement->type & 3) << 2) | RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + int rotation = ((mapElement->type & 3) << 2) | get_current_rotation(); x *= 32; y *= 32; x += RCT2_GLOBAL(0x0098DDB8 + (rotation * 4), sint16); y += RCT2_GLOBAL(0x0098DDBA + (rotation * 4), sint16); - gfx_invalidate_tile_if_zoomed(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + map_invalidate_tile_zoom0(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); } } @@ -1554,7 +2096,7 @@ static void ride_breakdown_update(int rideIndex) return; if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) return; - + if (ride->lifecycle_flags & (RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED)) ride->var_19C++; @@ -1619,7 +2161,7 @@ static int ride_get_new_breakdown_problem(rct_ride *ride) entry = ride_get_entry(ride); if (entry->flags & RIDE_ENTRY_FLAG_14) return -1; - + availableBreakdownProblems = RideAvailableBreakdowns[ride->type]; // Calculate the total probability range for all possible breakdown problems @@ -1659,7 +2201,7 @@ static int ride_get_new_breakdown_problem(rct_ride *ride) return -1; monthsOld = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint8) - ride->build_date; - if (monthsOld < 16 || ride->reliability > (50 << 8) || ride->lifecycle_flags & RIDE_LIFECYCLE_SIX_FLAGS) + if (monthsOld < 16 || ride->reliability > (50 << 8)) return -1; return BREAKDOWN_BRAKES_FAILURE; @@ -1686,7 +2228,7 @@ void ride_prepare_breakdown(int rideIndex, int breakdownReason) ride->mechanic_status = RIDE_MECHANIC_STATUS_UNDEFINED; ride->var_1AC = 0; ride->var_1AD = 0; - + switch (breakdownReason) { case BREAKDOWN_SAFETY_CUT_OUT: case BREAKDOWN_CONTROL_FAILURE: @@ -1707,18 +2249,18 @@ void ride_prepare_breakdown(int rideIndex, int breakdownReason) ride->broken_car = scenario_rand() % ride->num_cars_per_train; // Set flag on broken car - vehicle = &(g_sprite_list[ride->vehicles[ride->broken_vehicle]].vehicle); + vehicle = GET_VEHICLE(ride->vehicles[ride->broken_vehicle]); 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); + vehicle = GET_VEHICLE(vehicle->next_vehicle_on_train); } } if (vehicle != NULL) - vehicle->var_48 |= 0x100; + vehicle->update_flags |= VEHICLE_UPDATE_FLAG_BROKEN_CAR; break; case BREAKDOWN_VEHICLE_MALFUNCTION: // Choose a random train @@ -1726,8 +2268,8 @@ void ride_prepare_breakdown(int rideIndex, int breakdownReason) ride->broken_car = 0; // Set flag on broken train, first car - vehicle = &(g_sprite_list[ride->vehicles[ride->broken_vehicle]].vehicle); - vehicle->var_48 |= 0x200; + vehicle = GET_VEHICLE(ride->vehicles[ride->broken_vehicle]); + vehicle->update_flags |= VEHICLE_UPDATE_FLAG_BROKEN_TRAIN; break; case BREAKDOWN_BRAKES_FAILURE: // Original code generates a random number but does not use it @@ -1791,7 +2333,7 @@ static void ride_mechanic_status_update(int rideIndex, int mechanicStatus) int breakdownReason; rct_ride *ride; rct_peep *mechanic; - + ride = GET_RIDE(rideIndex); switch (mechanicStatus) { case RIDE_MECHANIC_STATUS_UNDEFINED: @@ -1890,7 +2432,7 @@ rct_peep *ride_find_closest_mechanic(rct_ride *ride, int forInspection) int x, y, z, stationIndex, direction; uint16 xy; rct_map_element *mapElement; - + // Get either exit position or entrance position if there is no exit stationIndex = ride->inspection_station; xy = ride->exits[stationIndex]; @@ -1928,8 +2470,8 @@ rct_peep *find_closest_mechanic(int x, int y, int forInspection) { unsigned int closestDistance, distance; uint16 spriteIndex; - rct_peep *peep, *closestMechanic; - + rct_peep *peep, *closestMechanic = NULL; + closestDistance = -1; FOR_ALL_STAFF(spriteIndex, peep) { if (peep->staff_type != STAFF_TYPE_MECHANIC) @@ -1953,7 +2495,7 @@ rct_peep *find_closest_mechanic(int x, int y, int forInspection) if (map_is_location_in_park(x, y)) if (!mechanic_is_location_in_patrol(peep, x & 0xFFE0, y & 0xFFE0)) continue; - + if (peep->x == (sint16)0x8000) continue; @@ -2003,7 +2545,7 @@ uint8 *ride_music_style_tuneids[] = { 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(21), // MUSIC_STYLE_CIRCUS_SHOW MAKE_TUNEID_LIST(22), // MUSIC_STYLE_SPACE MAKE_TUNEID_LIST(23), // MUSIC_STYLE_HORROR MAKE_TUNEID_LIST(24), // MUSIC_STYLE_TECHNO @@ -2040,8 +2582,12 @@ static void ride_music_update(int rideIndex) rct_vehicle *vehicle; rct_ride *ride = GET_RIDE(rideIndex); - if (!(RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint16) & 6)) + if ( + !(RideData4[ride->type].flags & RIDE_TYPE_FLAG4_MUSIC_ON_DEFAULT) && + !(RideData4[ride->type].flags & RIDE_TYPE_FLAG4_ALLOW_MUSIC) + ) { return; + } if (ride->status != RIDE_STATUS_OPEN || !(ride->lifecycle_flags & RIDE_LIFECYCLE_MUSIC)) { ride->music_tune_id = 255; @@ -2049,14 +2595,14 @@ static void ride_music_update(int rideIndex) } if (ride->type == RIDE_TYPE_CIRCUS_SHOW) { - vehicle = &(g_sprite_list[ride->vehicles[0]].vehicle); + vehicle = GET_VEHICLE(ride->vehicles[0]); if (vehicle->status != VEHICLE_STATUS_DOING_CIRCUS_SHOW) { ride->music_tune_id = 255; return; } } - // Oscillate parameters for a power cut effect when breaking down + // Oscillate parameters for a power cut effect when breaking down if (ride->lifecycle_flags & (RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN)) { if (ride->breakdown_reason_pending == BREAKDOWN_CONTROL_FAILURE) { if (!(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 7)) @@ -2133,14 +2679,14 @@ void ride_measurement_update(rct_ride_measurement *measurement) uint16 spriteIndex; rct_ride *ride; rct_vehicle *vehicle; - int unk, velocity, altitude, verticalG, lateralG; + int velocity, altitude, verticalG, lateralG; ride = GET_RIDE(measurement->ride_index); spriteIndex = ride->vehicles[measurement->vehicle_index]; if (spriteIndex == SPRITE_INDEX_NULL) return; - vehicle = &(g_sprite_list[spriteIndex].vehicle); + vehicle = GET_VEHICLE(spriteIndex); if (measurement->flags & RIDE_MEASUREMENT_FLAG_UNLOADING) { if (vehicle->status != VEHICLE_STATUS_DEPARTING && vehicle->status != VEHICLE_STATUS_STOPPING) @@ -2156,8 +2702,8 @@ void ride_measurement_update(rct_ride_measurement *measurement) return; } - unk = (vehicle->var_36 / 4) & 0xFF; - if (unk == 216 || unk == 123 || unk == 9 || unk == 63 || unk == 147 || unk == 155) + uint8 trackType = (vehicle->track_type >> 2) & 0xFF; + if (trackType == 216 || trackType == 123 || trackType == 9 || trackType == 63 || trackType == 147 || trackType == 155) if (vehicle->velocity == 0) return; @@ -2228,7 +2774,7 @@ void ride_measurements_update() if (spriteIndex == SPRITE_INDEX_NULL) continue; - vehicle = &(g_sprite_list[spriteIndex].vehicle); + vehicle = GET_VEHICLE(spriteIndex); if (vehicle->status == VEHICLE_STATUS_DEPARTING || vehicle->status == VEHICLE_STATUS_STOPPING) { measurement->vehicle_index = j; measurement->current_station = vehicle->current_station; @@ -2272,7 +2818,7 @@ int ride_get_free_measurement() } /** - * + * * rct2: 0x006B66D9 */ rct_ride_measurement *ride_get_measurement(int rideIndex, rct_string_id *message) @@ -2314,7 +2860,7 @@ rct_ride_measurement *ride_get_measurement(int rideIndex, rct_string_id *message } else { measurement = GET_RIDE_MEASUREMENT(i); } - + measurement->ride_index = rideIndex; ride->measurement_index = i; measurement->flags = 0; @@ -2329,7 +2875,7 @@ rct_ride_measurement *ride_get_measurement(int rideIndex, rct_string_id *message if (message != NULL) *message = 0; return measurement; } else { - RCT2_GLOBAL(0x013CE952, uint16) = RideNameConvention[ride->type].vehicle_name; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = RideNameConvention[ride->type].vehicle_name; RCT2_GLOBAL(0x013CE952 + 2, uint16) = RideNameConvention[ride->type].station_name; if (message != NULL) *message = STR_DATA_LOGGING_WILL_START_WHEN_NEXT_LEAVES; return NULL; @@ -2358,6 +2904,62 @@ vehicle_colour ride_get_vehicle_colour(rct_ride *ride, int vehicleIndex) return result; } +static bool ride_does_vehicle_colour_exist(uint8 ride_sub_type, vehicle_colour *vehicleColour) +{ + int i; + rct_ride *ride2; + FOR_ALL_RIDES(i, ride2) { + if (ride2->subtype != ride_sub_type) continue; + if (ride2->vehicle_colours[0].body_colour != vehicleColour->main) continue; + return false; + } + return true; +} + +static int ride_get_unused_preset_vehicle_colour(uint8 ride_type, uint8 ride_sub_type) +{ + rct_ride_type *rideEntry = GET_RIDE_ENTRY(ride_sub_type); + vehicle_colour_preset_list *presetList = rideEntry->vehicle_preset_list; + if (presetList->count == 255) + return 255; + + for (int attempt = 0; attempt < 200; attempt++) { + uint8 numColourConfigurations = presetList->count; + int randomConfigIndex = util_rand() % numColourConfigurations; + vehicle_colour *preset = &presetList->list[randomConfigIndex]; + + if (ride_does_vehicle_colour_exist(ride_sub_type, preset)) { + return randomConfigIndex; + } + } + return 0; +} + +/** + * + * rct2: 0x006DE52C + */ +static void ride_set_vehicle_colours_to_random_preset(rct_ride *ride, uint8 preset_index) +{ + rct_ride_type *rideEntry = GET_RIDE_ENTRY(ride->subtype); + vehicle_colour_preset_list *presetList = rideEntry->vehicle_preset_list; + if (presetList->count != 255) { + ride->colour_scheme_type = RIDE_COLOUR_SCHEME_ALL_SAME; + vehicle_colour *preset = &presetList->list[preset_index]; + ride->vehicle_colours[0].body_colour = preset->main; + ride->vehicle_colours[0].trim_colour = preset->additional_1; + ride->vehicle_colours_extended[0] = preset->additional_2; + } else { + ride->colour_scheme_type = RIDE_COLOUR_SCHEME_DIFFERENT_PER_TRAIN; + for (int i = 0; i < 32; i++) { + vehicle_colour *preset = &presetList->list[i]; + ride->vehicle_colours[i].body_colour = preset->main; + ride->vehicle_colours[i].trim_colour = preset->additional_1; + ride->vehicle_colours_extended[i] = preset->additional_2; + } + } +} + #pragma endregion #pragma region Reachability @@ -2369,8 +2971,8 @@ void ride_check_all_reachable() { rct_ride *ride; int i; - - FOR_ALL_RIDES(i, ride) { + + FOR_ALL_RIDES(i, ride) { if (ride->connected_message_throttle != 0) ride->connected_message_throttle--; if (ride->status != RIDE_STATUS_OPEN || ride->connected_message_throttle != 0) @@ -2425,25 +3027,25 @@ static void ride_entrance_exit_connected(rct_ride* ride, int ride_idx) entrance = ride->entrances[i], exit = ride->exits[i]; - if (station_start == -1 ) + if (station_start == 0xFFFF ) continue; - if (entrance != -1 && !ride_entrance_exit_is_reachable(entrance, ride, i)) { + if (entrance != 0xFFFF && !ride_entrance_exit_is_reachable(entrance, ride, i)) { // name of ride is parameter of the format string - RCT2_GLOBAL(0x013CE952, uint16) = ride->name; - RCT2_GLOBAL(0x013CE954, uint32) = ride->name_arguments; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, 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; } - - if (exit != -1 && !ride_entrance_exit_is_reachable(exit, ride, i)) { + + if (exit != 0xFFFF && !ride_entrance_exit_is_reachable(exit, ride, i)) { // name of ride is parameter of the format string - RCT2_GLOBAL(0x013CE952, uint16) = ride->name; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = ride->name; RCT2_GLOBAL(0x013CE954, uint32) = ride->name_arguments; news_item_add_to_queue(1, STR_EXIT_NOT_CONNECTED, ride_idx); ride->connected_message_throttle = 3; } - } + } } static void ride_shop_connected(rct_ride* ride, int ride_idx) @@ -2457,7 +3059,7 @@ static void ride_shop_connected(rct_ride* ride, int ride_idx) x = (coordinate & 0xFF); y = (coordinate >> 8) & 0xFF; - + 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) @@ -2467,7 +3069,7 @@ static void ride_shop_connected(rct_ride* ride, int ride_idx) uint16 entrance_directions = 0; 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)) { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { entrance_directions = RCT2_ADDRESS(0x0099CA64, uint8)[track_type * 16]; } else { entrance_directions = RCT2_ADDRESS(0x0099BA64, uint8)[track_type * 16]; @@ -2503,7 +3105,7 @@ static void ride_shop_connected(rct_ride* ride, int ride_idx) } // Name of ride is parameter of the format string - RCT2_GLOBAL(0x013CE952, uint16) = ride->name; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = ride->name; RCT2_GLOBAL(0x013CE954, uint32) = ride->name_arguments; news_item_add_to_queue(1, STR_ENTRANCE_NOT_CONNECTED, ride_idx); @@ -2622,7 +3224,7 @@ void ride_set_map_tooltip(rct_map_element *mapElement) } /** - * + * * rct2: 0x006BC3AC * Update ride music parameters * @param x (ax) @@ -2636,25 +3238,11 @@ 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) { - /*{ - int a_eax, a_ebx, a_ecx, a_edx, a_esi, a_edi, a_ebp; - - a_eax = x; - a_ebx = (*tuneId << 8) | rideIndex; - a_ecx = y; - a_edx = z; - a_edi = sampleRate; - a_ebp = position; - RCT2_CALLFUNC_X(0x006BC3AC, &a_eax, &a_ebx, &a_ecx, &a_edx, &a_esi, &a_edi, &a_ebp); - - *tuneId = (a_ebx >> 8) & 0xFF; - return a_ebp; - }*/ - if(!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !RCT2_GLOBAL(0x009AF59C, uint8) && RCT2_GLOBAL(0x00F438A4, rct_viewport*) != (rct_viewport*)-1) { + if(!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gGameSoundsOff && RCT2_GLOBAL(0x00F438A4, rct_viewport*) != (rct_viewport*)-1) { RCT2_GLOBAL(0x009AF47C, uint16) = sampleRate; sint16 v11; sint16 v12; - switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) { + switch (get_current_rotation()) { case 0: v11 = y - x; v12 = ((y + x) / 2) - z; @@ -2693,7 +3281,7 @@ int ride_music_params_update(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint if (screenwidth < 64) { screenwidth = 64; } - int panx = ((x2 / screenwidth) - 0x8000) >> 4; + int pan_x = ((x2 / screenwidth) - 0x8000) >> 4; int y2 = RCT2_GLOBAL(0x00F438A4, rct_viewport*)->y + ((RCT2_GLOBAL(0x009AF5A2, sint16) - RCT2_GLOBAL(0x00F438A4, rct_viewport*)->view_y) >> RCT2_GLOBAL(0x00F438A4, rct_viewport*)->zoom); y2 <<= 16; @@ -2701,12 +3289,12 @@ int ride_music_params_update(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint if (screenheight < 64) { screenheight = 64; } - int pany = ((y2 / screenheight) - 0x8000) >> 4; + int pan_y = ((y2 / screenheight) - 0x8000) >> 4; uint8 vol1 = -1; uint8 vol2 = -1; - int panx2 = panx; - int pany2 = pany; + int panx2 = pan_x; + int pany2 = pan_y; if (pany2 < 0) { pany2 = -pany2; } @@ -2746,57 +3334,42 @@ int ride_music_params_update(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint } int v32 = -(((uint8)(-vol1 - 1) * (uint8)(-vol1 - 1)) / 16) - 700; if (vol1 && v32 >= -4000) { - if (panx > 10000) { - panx = 10000; + if (pan_x > 10000) { + pan_x = 10000; } - if (panx < -10000) { - panx = -10000; + if (pan_x < -10000) { + pan_x = -10000; } - if (!RCT2_GLOBAL(0x009AAC6D, uint8)) { - panx = 0; - } - rct_ride_music* ride_music = &gRideMusicList[0];//&RCT2_GLOBAL(0x009AF46C, rct_ride_music); + rct_ride_music* ride_music = &gRideMusicList[0]; int channel = 0; uint32 a1; - while (ride_music->rideid != rideIndex || ride_music->tuneid != *tuneId) { + while (ride_music->ride_id != rideIndex || ride_music->tune_id != *tuneId) { ride_music++; channel++; if (channel >= AUDIO_MAX_RIDE_MUSIC) { - rct_ride_music_info* ride_music_info = ride_music_info_list[*tuneId]; + rct_ride_music_info* ride_music_info = gRideMusicInfoList[*tuneId]; a1 = position + ride_music_info->offset; goto label51; } } -#ifdef USE_MIXER int playing = Mixer_Channel_IsPlaying(gRideMusicList[channel].sound_channel); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - int playing = sound_channel_is_playing(channel); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif if (!playing) { *tuneId = 0xFF; return 0; } -#ifdef USE_MIXER a1 = Mixer_Channel_GetOffset(gRideMusicList[channel].sound_channel); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - a1 = sub_401B46(channel); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif label51: - if (a1 < ride_music_info_list[*tuneId]->length) { + if (a1 < gRideMusicInfoList[*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*/) { - ride_music_params->rideid = rideIndex; - ride_music_params->tuneid = *tuneId; + rct_ride_music_params* ride_music_params = gRideMusicParamsListEnd; + if (ride_music_params < &gRideMusicParamsList[AUDIO_MAX_RIDE_MUSIC]) { + ride_music_params->ride_id = rideIndex; + ride_music_params->tune_id = *tuneId; ride_music_params->offset = a1; ride_music_params->volume = v32; - ride_music_params->pan = panx; - ride_music_params->freq = RCT2_GLOBAL(0x009AF47C, uint16); - gRideMusicParamsListEnd++;//RCT2_GLOBAL(0x009AF42C, rct_ride_music_params*)++; + ride_music_params->pan = pan_x; + ride_music_params->frequency = RCT2_GLOBAL(0x009AF47C, uint16); + gRideMusicParamsListEnd++; } } else { *tuneId = 0xFF; @@ -2805,7 +3378,7 @@ int ride_music_params_update(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint } else { label58: ; - rct_ride_music_info* ride_music_info = ride_music_info_list[*tuneId]; + rct_ride_music_info* ride_music_info = gRideMusicInfoList[*tuneId]; position += ride_music_info->offset; if (position < ride_music_info->length) { return position; @@ -2818,23 +3391,23 @@ 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} +#define INIT_MUSIC_INFO(path_id, offset, length, unknown) (rct_ride_music_info[]){length, offset, path_id, unknown} //0x009AF1C8 -rct_ride_music_info* ride_music_info_list[] = { +rct_ride_music_info* gRideMusicInfoList[NUM_DEFAULT_MUSIC_TRACKS] = { 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(0, 1378, 0, 0), // Referred to the nearly empty CSS10.DAT file 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(0, 1378, 0, 0), // Referred to the nearly empty CSS16.DAT file 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), @@ -2876,201 +3449,123 @@ rct_ride_music_info* ride_music_info_list[] = { */ void ride_music_update_final() { - rct_ride_music_params* edi; + rct_ride_music_params* edi = NULL; int ebx; if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2)) { - if ((RCT2_GLOBAL(0x009AF284, uint32) & (1 << 0))) { - if (!RCT2_GLOBAL(0x009AF59C, uint8) && RCT2_GLOBAL(0x009AF59D, uint8) & 1 && RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) && !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 1)) { - // set to stop music if volume <= 1 ? - while (1) { - int v8 = 0; - int v9 = 1; - 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 = 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) { - v9 = ride_music_params->volume; - edi = ride_music_params; - } - } - } - ride_music_params++; - } - if (v8 <= 1) { - break; - } - edi->rideid = -1; - } - while (1) { - int v8 = 0; - int v9 = 1; - 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) { + if (!gGameSoundsOff && gConfigSound.sound && gConfigSound.ride_music && !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 1)) { + // set to stop music if volume <= 1 ? + while (1) { + int v8 = 0; + int v9 = 1; + rct_ride_music_params* ride_music_params = &gRideMusicParamsList[0]; + while (ride_music_params < gRideMusicParamsListEnd) { + if (ride_music_params->ride_id != (uint8)-1) { + rct_ride_music_info* ride_music_info = gRideMusicInfoList[ride_music_params->tune_id]; + if (RCT2_ADDRESS(0x009AA0B1, uint8*)[ride_music_info->path_id]) { // file_on_cdrom[] v8++; if (v9 >= ride_music_params->volume) { v9 = ride_music_params->volume; edi = ride_music_params; } } + } + ride_music_params++; + } + if (v8 <= 1) { + break; + } + edi->ride_id = -1; + } + while (1) { + int v8 = 0; + int v9 = 1; + rct_ride_music_params* ride_music_params = &gRideMusicParamsList[0]; + while (ride_music_params < gRideMusicParamsListEnd) { + if (ride_music_params->ride_id != (uint8)-1) { + v8++; + if (v9 >= ride_music_params->volume) { + v9 = ride_music_params->volume; + edi = ride_music_params; + } + } + ride_music_params++; + } + if (v8 <= 2) { + break; + } + edi->ride_id = -1; + } + + // stop currently playing music that is not in music params list or not playing? + rct_ride_music* ride_music = &gRideMusicList[0]; + int channel = 0; + do { + if (ride_music->ride_id != (uint8)-1) { + rct_ride_music_params* ride_music_params = &gRideMusicParamsList[0]; + while (ride_music_params < gRideMusicParamsListEnd) { + if (ride_music_params->ride_id == ride_music->ride_id && ride_music_params->tune_id == ride_music->tune_id) { + int isplaying = Mixer_Channel_IsPlaying(gRideMusicList[channel].sound_channel); + if (isplaying) { + goto label32; + } + break; + } ride_music_params++; } - if (v8 <= 2) { - break; - } - edi->rideid = -1; + Mixer_Stop_Channel(gRideMusicList[channel].sound_channel); + ride_music->ride_id = -1; } + label32: + ride_music++; + channel++; + } while(channel < AUDIO_MAX_RIDE_MUSIC); - // stop currently playing music that is not in music params list or not playing? - rct_ride_music* ride_music = &gRideMusicList[0];//&RCT2_GLOBAL(0x009AF46C, rct_ride_music); - int channel = 0; - do { - if (ride_music->rideid != (uint8)-1) { - 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 == ride_music->rideid && ride_music_params->tuneid == ride_music->tuneid) { -#ifdef USE_MIXER - int isplaying = Mixer_Channel_IsPlaying(gRideMusicList[channel].sound_channel); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - int isplaying = sound_channel_is_playing(channel); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - if (isplaying) { - goto label32; - } - break; - } - ride_music_params++; + for (rct_ride_music_params* ride_music_params = &gRideMusicParamsList[0]; ride_music_params < gRideMusicParamsListEnd; ride_music_params++) { + if (ride_music_params->ride_id != (uint8)-1) { + rct_ride_music* ride_music = &gRideMusicList[0]; + int channel = 0; + while (ride_music_params->ride_id != ride_music->ride_id || ride_music_params->tune_id != ride_music->tune_id) { + if (ride_music->ride_id == (uint8)-1) { + ebx = channel; + } + ride_music++; + channel++; + if (channel >= AUDIO_MAX_RIDE_MUSIC) { + rct_ride_music_info* ride_music_info = gRideMusicInfoList[ride_music_params->tune_id]; + rct_ride_music* ride_music = &gRideMusicList[ebx]; + ride_music->sound_channel = Mixer_Play_Music(ride_music_info->path_id, MIXER_LOOP_NONE, true); + if (ride_music->sound_channel) { + ride_music->volume = ride_music_params->volume; + ride_music->pan = ride_music_params->pan; + ride_music->frequency = ride_music_params->frequency; + ride_music->ride_id = ride_music_params->ride_id; + ride_music->tune_id = ride_music_params->tune_id; + Mixer_Channel_Volume(ride_music->sound_channel, DStoMixerVolume(ride_music->volume)); + Mixer_Channel_Pan(ride_music->sound_channel, DStoMixerPan(ride_music->pan)); + Mixer_Channel_Rate(ride_music->sound_channel, DStoMixerRate(ride_music->frequency)); + int offset = ride_music_params->offset - 10000; + if (offset < 0) { + offset = 0; + } + Mixer_Channel_SetOffset(ride_music->sound_channel, offset); + } + return; } -#ifdef USE_MIXER - Mixer_Stop_Channel(gRideMusicList[channel].sound_channel); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_channel_stop(channel); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - ride_music->rideid = -1; } - label32: - ride_music++; - channel++; - } while(channel < AUDIO_MAX_RIDE_MUSIC); - - for (rct_ride_music_params* ride_music_params = &gRideMusicParamsList[0]/*&RCT2_GLOBAL(0x009AF430, rct_ride_music_params)*/; ride_music_params < gRideMusicParamsListEnd/*RCT2_GLOBAL(0x009AF42C, rct_ride_music_params*)*/; ride_music_params++) { - if (ride_music_params->rideid != (uint8)-1) { - rct_ride_music* ride_music = &gRideMusicList[0];//&RCT2_GLOBAL(0x009AF46C, rct_ride_music); - int channel = 0; - while (ride_music_params->rideid != ride_music->rideid || ride_music_params->tuneid != ride_music->tuneid) { - if (ride_music->rideid == (uint8)-1) { - ebx = channel; - } - ride_music++; - channel++; - if (channel >= AUDIO_MAX_RIDE_MUSIC) { - 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, MIXER_LOOP_NONE, true); - if (ride_music->sound_channel) { - ride_music->volume = ride_music_params->volume; - ride_music->pan = ride_music_params->pan; - ride_music->freq = ride_music_params->freq; - ride_music->rideid = ride_music_params->rideid; - ride_music->tuneid = ride_music_params->tuneid; - Mixer_Channel_Volume(ride_music->sound_channel, DStoMixerVolume(ride_music->volume)); - Mixer_Channel_Pan(ride_music->sound_channel, DStoMixerPan(ride_music->pan)); - Mixer_Channel_Rate(ride_music->sound_channel, DStoMixerRate(ride_music->freq)); - int offset = ride_music_params->offset - 10000; - if (offset < 0) { - offset = 0; - } - Mixer_Channel_SetOffset(ride_music->sound_channel, offset); - } else { - //RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) = 0; - } -#else - const char* filename = get_file_path(ride_music_info->pathid); - RCT2_GLOBAL(0x014241BC, uint32) = 3; - HANDLE hfile = osinterface_file_open(filename); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - if (hfile != INVALID_HANDLE_VALUE) { - RCT2_GLOBAL(0x014241BC, uint32) = 3; - osinterface_file_read(hfile, &RCT2_GLOBAL(0x009AF47E, uint32), 4); - RCT2_GLOBAL(0x014241BC, uint32) = 3; - osinterface_file_close(hfile); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - } - if (hfile == INVALID_HANDLE_VALUE || RCT2_GLOBAL(0x009AF47E, uint32) != 0x78787878) { - int offset = ride_music_params->offset - 10000; - if (offset < 0) { - offset = 0; - } - RCT2_GLOBAL(0x014241BC, uint32) = 1; - int musicloaded = sound_channel_load_file2(ebx, filename, offset & 0xFFFFFFF0); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - if (musicloaded) { - RCT2_GLOBAL(0x014241BC, uint32) = 1; - int musicplayed = sound_channel_play(ebx, 0, ride_music_params->volume, ride_music_params->pan, ride_music_params->freq); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - if (musicplayed) { - rct_ride_music_info* ride_music_info = &RCT2_GLOBAL(0x009AF1C8, rct_ride_music_info*)[ride_music_params->tuneid]; - if (ride_music_info->var_9) { - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sub_401AF3(ebx, get_file_path(ride_music_info->pathid), 1, 0); - RCT2_GLOBAL(0x014241BC, uint32) = 0; - } - rct_ride_music* ride_music = &gRideMusicList[ebx];//&RCT2_ADDRESS(0x009AF46C, rct_ride_music)[ebx]; - ride_music->volume = ride_music_params->volume; - ride_music->pan = ride_music_params->pan; - ride_music->freq = ride_music_params->freq; - ride_music->rideid = ride_music_params->rideid; - ride_music->tuneid = ride_music_params->tuneid; - } - } else { - RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) = 0; - } - } -#endif - return; - } - } - - if (ride_music_params->volume != ride_music->volume) { - ride_music->volume = ride_music_params->volume; -#ifdef USE_MIXER - Mixer_Channel_Volume(ride_music->sound_channel, DStoMixerVolume(ride_music->volume)); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_channel_set_volume(channel, ride_music_params->volume); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - } - if (ride_music_params->pan != ride_music->pan) { - ride_music->pan = ride_music_params->pan; -#ifdef USE_MIXER - Mixer_Channel_Pan(ride_music->sound_channel, DStoMixerPan(ride_music->pan)); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_channel_set_pan(channel, ride_music_params->pan); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - } - if (ride_music_params->freq != ride_music->freq) { - ride_music->freq = ride_music_params->freq; -#ifdef USE_MIXER - Mixer_Channel_Rate(ride_music->sound_channel, DStoMixerRate(ride_music->freq)); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_channel_set_frequency(channel, ride_music_params->freq); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - } + if (ride_music_params->volume != ride_music->volume) { + ride_music->volume = ride_music_params->volume; + Mixer_Channel_Volume(ride_music->sound_channel, DStoMixerVolume(ride_music->volume)); } + if (ride_music_params->pan != ride_music->pan) { + ride_music->pan = ride_music_params->pan; + Mixer_Channel_Pan(ride_music->sound_channel, DStoMixerPan(ride_music->pan)); + } + if (ride_music_params->frequency != ride_music->frequency) { + ride_music->frequency = ride_music_params->frequency; + Mixer_Channel_Rate(ride_music->sound_channel, DStoMixerRate(ride_music->frequency)); + } + } } } @@ -3082,8 +3577,8 @@ void ride_music_update_final() /* 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; - + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_RUNNING_COSTS * 4; + uint8 ride_id = *edx & 0xFF; rct_ride* ride = GET_RIDE(ride_id); @@ -3094,22 +3589,13 @@ void game_command_set_ride_setting(int *eax, int *ebx, int *ecx, int *edx, int * if (setting == 0){ if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN){ - RCT2_GLOBAL(0x141E9AC, uint16) = 1796; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING; *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; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_MUST_BE_CLOSED_FIRST; *ebx = MONEY32_UNDEFINED; return; } @@ -3118,7 +3604,7 @@ void game_command_set_ride_setting(int *eax, int *ebx, int *ecx, int *edx, int * if (setting == 9 && ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT && new_value > 1){ - RCT2_GLOBAL(0x141E9AC, uint16) = 3141; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_MULTICIRCUIT_NOT_POSSIBLE_WITH_CABLE_LIFT_HILL; *ebx = MONEY32_UNDEFINED; return; } @@ -3130,17 +3616,14 @@ void game_command_set_ride_setting(int *eax, int *ebx, int *ecx, int *edx, int * switch (setting){ case 0: - RCT2_CALLPROC_X(0x006B59C6, 0, 0, 0, ride_id, 0, 0, 0); + invalidate_test_results(ride_id); 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; + const uint8* available_modes = ride_seek_available_modes(ride); - for (int i = 0; i < ride->type; i++) { - while (*(available_modes++) != 255) {} - } - if (ride_entry->flags & RIDE_ENTRY_FLAG_17){ + if ((ride_entry->flags & RIDE_ENTRY_DISABLE_FIRST_TWO_OPERATING_MODES) && !gCheatsShowAllOperatingModes){ available_modes += 2; } @@ -3153,12 +3636,12 @@ void game_command_set_ride_setting(int *eax, int *ebx, int *ecx, int *edx, int * if (*available_modes == 0xFF) new_value = default_mode; if (available_modes[1] == 0xFF){ - if (ride_entry->flags & RIDE_ENTRY_FLAG_15) + if ((ride_entry->flags & RIDE_ENTRY_DISABLE_LAST_OPERATING_MODE) && !gCheatsShowAllOperatingModes) new_value = default_mode; } ride->mode = new_value; - RCT2_CALLPROC_X(0x6DD57D, 0, 0, 0, ride_id, 0, 0, 0); + ride_update_max_vehicles(ride_id); break; case 1: ride->depart_flags = new_value; @@ -3172,7 +3655,7 @@ void game_command_set_ride_setting(int *eax, int *ebx, int *ecx, int *edx, int * 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); + invalidate_test_results(ride_id); ride->time_limit = new_value; break; case 5: @@ -3193,13 +3676,13 @@ void game_command_set_ride_setting(int *eax, int *ebx, int *ecx, int *edx, int * 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); + invalidate_test_results(ride_id); } 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); + invalidate_test_results(ride_id); } break; } @@ -3209,7 +3692,7 @@ void game_command_set_ride_setting(int *eax, int *ebx, int *ecx, int *edx, int * } /** - * + * * rct2: 0x006B4CC1 */ int ride_mode_check_valid_station_numbers(rct_ride *ride) @@ -3225,17 +3708,17 @@ int ride_mode_check_valid_station_numbers(rct_ride *ride) case RIDE_MODE_POWERED_LAUNCH: case RIDE_MODE_LIM_POWERED_LAUNCH: if (no_stations <= 1) return 1; - RCT2_GLOBAL(0x141E9AC, uint16) = 1015; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_UNABLE_TO_OPERATE_WITH_MORE_THAN_ONE_STATION_IN_THIS_MODE; return 0; case RIDE_MODE_SHUTTLE: if (no_stations >= 2) return 1; - RCT2_GLOBAL(0x141E9AC, uint16) = 1016; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_UNABLE_TO_OPERATE_WITH_LESS_THAN_TWO_STATIONS_IN_THIS_MODE; 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; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_UNABLE_TO_OPERATE_WITH_MORE_THAN_ONE_STATION_IN_THIS_MODE; return 0; } @@ -3270,7 +3753,7 @@ int ride_mode_check_station_present(rct_ride* ride){ } /** - * + * * rct2: 0x006B5872 */ int ride_check_for_entrance_exit(int rideIndex) @@ -3290,11 +3773,11 @@ int ride_check_for_entrance_exit(int rideIndex) 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){ @@ -3304,12 +3787,12 @@ int ride_check_for_entrance_exit(int rideIndex) } if (entrance == 0){ - RCT2_GLOBAL(0x141E9AC, uint16) = 1146; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_ENTRANCE_NOT_YET_BUILT; return 0; } if (exit == 0){ - RCT2_GLOBAL(0x141E9AC, uint16) = 1147; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_EXIT_NOT_YET_BUILT; return 0; } @@ -3317,215 +3800,693 @@ int ride_check_for_entrance_exit(int rideIndex) } /** - * + * * rct2: 0x006B5952 */ void sub_6B5952(int rideIndex) { - RCT2_CALLPROC_X(0x006B5952, 0, 0, 0, rideIndex, 0, 0, 0); + rct_ride *ride = GET_RIDE(rideIndex); + + for (int i = 0; i < 4; i++) { + uint16 xy = ride->entrances[i]; + if (xy == 0xFFFF) + continue; + + int x = (xy & 0xFF) * 32; + int y = (xy >> 8) * 32; + int z = ride->station_heights[i]; + + rct_map_element *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; + + int direction = mapElement->type & MAP_ELEMENT_DIRECTION_MASK; + footpath_chain_ride_queue(rideIndex, i, x, y, mapElement, direction ^ 2); + } while (!map_element_is_last_for_tile(mapElement++)); + } } /** - * + * * 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; + track_circuit_iterator it; + int rideIndex, type; - trackElement = *input; - rideIndex = trackElement.element->properties.track.ride_index; + rideIndex = input->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) + if (w != NULL && _rideConstructionState != RIDE_CONSTRUCTION_STATE_0 && _currentRideIndex == 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; + track_circuit_iterator_begin(&it, *input); + while (track_circuit_iterator_next(&it)) { + if (it.current.element->properties.track.type == 216) { + type = it.last.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; + *output = it.current; 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; + *output = it.current; return 0; } - if ((trackElement.element->type & 0x80) && type != 209 && type != 210) { + if ((it.last.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; + *output = it.current; return 0; } } - - trackElement = nextTrackElement; - if (loopTrackElement == NULL) - loopTrackElement = trackElement.element; - else if (loopTrackElement == trackElement.element) - break; + } + if (!it.looped) { + // 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 = it.last; + return 0; } return 1; } /** - * + * Iterates along the track until an inversion (loop, corkscrew, barrel roll etc.) track piece is reached. + * @param input The start track element and position. + * @param output The first track element and position which is classified as an inversion. + * @returns true if an inversion track piece is found, otherwise false. * rct2: 0x006CB149 */ -int ride_check_track_suitability_a(rct_xy_element *input, rct_xy_element *output) +bool ride_check_track_contains_inversions(rct_xy_element *input, rct_xy_element *output) { - int eax, ebx, ecx, edx, esi, edi, ebp, result; + rct_window *w; + rct_ride *ride; + int rideIndex, trackType; + track_circuit_iterator it; - 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; + rideIndex = input->element->properties.track.ride_index; + ride = GET_RIDE(rideIndex); + if (ride->type == RIDE_TYPE_MAZE) + return true; - return (result & 0x100) != 0; + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != NULL && _rideConstructionState != RIDE_CONSTRUCTION_STATE_0 && rideIndex == _currentRideIndex) { + sub_6C9627(); + } + + track_circuit_iterator_begin(&it, *input); + while (track_circuit_iterator_next(&it)) { + trackType = it.current.element->properties.track.type; + if (RCT2_ADDRESS(0x0099423C, uint16)[trackType] & 0x4000) { + *output = it.current; + return true; + } + } + return false; } /** - * + * Iterates along the track until a banked track piece is reached. + * @param input The start track element and position. + * @param output The first track element and position which is banked. + * @returns true if a banked track piece is found, otherwise false. * rct2: 0x006CB1D3 */ -int ride_check_track_suitability_b(rct_xy_element *input, rct_xy_element *output) +bool ride_check_track_contains_banked(rct_xy_element *input, rct_xy_element *output) { - int eax, ebx, ecx, edx, esi, edi, ebp, result; + rct_window *w; + rct_ride *ride; + int rideIndex, trackType; + track_circuit_iterator it; - 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; + rideIndex = input->element->properties.track.ride_index; + ride = GET_RIDE(rideIndex); + if (ride->type == RIDE_TYPE_MAZE) + return true; - return (result & 0x100) != 0; + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != NULL && _rideConstructionState != RIDE_CONSTRUCTION_STATE_0 && rideIndex == _currentRideIndex) { + sub_6C9627(); + } + + track_circuit_iterator_begin(&it, *input); + while (track_circuit_iterator_next(&it)) { + trackType = output->element->properties.track.type; + if (RCT2_ADDRESS(0x0099423C, uint16)[trackType] & 0x8000) { + *output = it.current; + return true; + } + } + return false; } /** - * + * * rct2: 0x006CB25D */ int ride_check_station_length(rct_xy_element *input, rct_xy_element *output) { - int eax, ebx, ecx, edx, esi, edi, ebp, result; + rct_window* w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != 0 && + _rideConstructionState != RIDE_CONSTRUCTION_STATE_0 && + _currentRideIndex == input->element->properties.track.ride_index){ + sub_6C9627(); + } - // 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; + output->x = input->x; + output->y = input->y; + output->element = input->element; + track_begin_end trackBeginEnd; + while (track_block_get_previous(output->x, output->y, output->element, &trackBeginEnd)){ + output->x = trackBeginEnd.begin_x; + output->y = trackBeginEnd.begin_y; + output->element = trackBeginEnd.begin_element; + } - return (result & 0x100) != 0; + int num_station_elements = 0; + rct_xy_element last_good_station = *output; + + do{ + if (RCT2_ADDRESS(0x0099BA64, uint8)[output->element->properties.track.type * 16] & 0x10){ + num_station_elements++; + last_good_station = *output; + } + else{ + if (num_station_elements == 0) + continue; + if (num_station_elements == 1){ + return 0; + } + num_station_elements = 0; + } + } while (track_block_get_next(output, output, NULL, NULL)); + + // Prevent returning a pointer to a map element with no track. + *output = last_good_station; + if (num_station_elements == 1) + return 0; + + return 1; } /** - * + * * rct2: 0x006CB2DA */ -int ride_check_start_and_end_is_station(rct_xy_element *input, rct_xy_element *output) +bool ride_check_start_and_end_is_station(rct_xy_element *input, rct_xy_element *output) { - int eax, ebx, ecx, edx, esi, edi, ebp, result; + rct_window *w; + rct_ride *ride; + int rideIndex, trackType; + rct_xy_element trackBack, trackFront; - 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; + rideIndex = input->element->properties.track.ride_index; + ride = GET_RIDE(rideIndex); - return (result & 0x100) != 0; + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != NULL && _rideConstructionState != RIDE_CONSTRUCTION_STATE_0 && rideIndex == _currentRideIndex) { + sub_6C9627(); + } + + // Check back of the track + track_get_back(input, &trackBack); + trackType = trackBack.element->properties.track.type; + if (!(RCT2_GLOBAL(0x0099BA64 + (trackType * 16), uint32) & 0x10)) { + return false; + } + ride->var_13A = (trackBack.x >> 5) | ((trackBack.y >> 5) << 8); + ride->var_13E = trackBack.element->base_height; + + // Check front of the track + track_get_front(input, &trackFront); + trackType = trackFront.element->properties.track.type; + if (!(RCT2_GLOBAL(0x0099BA64 + (trackType * 16), uint32) & 0x10)) { + return false; + } + ride->var_13C = (trackFront.x >> 5) | ((trackFront.y >> 5) << 8); + ride->var_13F = trackFront.element->base_height; + return true; } /** - * + * Sets the position and direction of the returning point on the track of a boat hire ride. This will either be the end of the + * station or the last track piece from the end of the direction. + * rct2: 0x006B4D39 + */ +void ride_set_boat_hire_return_point(rct_ride *ride, rct_xy_element *startElement) +{ + int trackType = -1; + int returnX = startElement->x; + int returnY = startElement->y; + int startX = returnX; + int startY = returnY; + rct_map_element *returnTrackElement = startElement->element; + track_begin_end trackBeginEnd; + while (track_block_get_previous(returnX, returnY, returnTrackElement, &trackBeginEnd)) { + // If previous track is back to the starting x, y, then break loop (otherwise possible infinite loop) + if (trackType != -1 && startX == trackBeginEnd.begin_x && startY == trackBeginEnd.begin_y) break; + + int x = trackBeginEnd.begin_x; + int y = trackBeginEnd.begin_y; + int z = trackBeginEnd.begin_z; + int direction = trackBeginEnd.begin_direction; + trackType = trackBeginEnd.begin_element->properties.track.type; + sub_6C683D(&x, &y, &z, direction, trackType, 0, &returnTrackElement, 0); + returnX = x; + returnY = y; + }; + + trackType = returnTrackElement->properties.track.type; + int elementReturnDirection = RCT2_GLOBAL(0x009968BB + (trackType * 10), uint8); + ride->boat_hire_return_direction = (returnTrackElement->type + elementReturnDirection) & 3; + ride->boat_hire_return_position = (returnX >> 5) | ((returnY >> 5) << 8); +} + +/** + * + * rct2: 0x006B4D39 + */ +static void ride_set_maze_entrance_exit_points(rct_ride *ride) +{ + uint16 positions[9]; + + // Create a list of all the entrance and exit positions + uint16 *position = positions; + for (int i = 0; i < 4; i++) { + if (ride->entrances[i] != 0xFFFF) { + *position++ = ride->entrances[i]; + } + if (ride->exits[i] != 0xFFFF) { + *position++ = ride->exits[i]; + } + } + *position++ = 0xFFFF; + + // Enumerate entrance and exit positions + for (position = positions; *position != 0xFFFF; position++) { + int x = (*position & 0xFF) << 5; + int y = (*position >> 8) << 5; + int z = ride->station_heights[0]; + + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_ENTRANCE) continue; + if ( + mapElement->properties.entrance.type != ENTRANCE_TYPE_RIDE_ENTRANCE && + mapElement->properties.entrance.type != ENTRANCE_TYPE_RIDE_EXIT + ) { + continue; + } + if (mapElement->base_height != z) continue; + + maze_entrance_hedge_removal(x, y, mapElement); + } while (!map_element_is_last_for_tile(mapElement++)); + } +} + +/** + * Sets a flag on all the track elements that can be the start of a circuit block. i.e. where a train can start. + * rct2: 0x006B4E6B + */ +static void ride_set_block_points(rct_xy_element *startElement) +{ + rct_xy_element currentElement = *startElement; + do { + int trackType = currentElement.element->properties.track.type; + switch (trackType) { + case TRACK_ELEM_END_STATION: + case TRACK_ELEM_CABLE_LIFT_HILL: + case TRACK_ELEM_25_DEG_UP_TO_FLAT: + case TRACK_ELEM_60_DEG_UP_TO_FLAT: + case TRACK_ELEM_DIAG_25_DEG_UP_TO_FLAT: + case TRACK_ELEM_DIAG_60_DEG_UP_TO_FLAT: + case 216: // block brakes + currentElement.element->flags &= ~(1 << 5); + break; + } + } while (track_block_get_next(¤tElement, ¤tElement, NULL, NULL) && currentElement.element != startElement->element); +} + +/** + * * rct2: 0x006B4D26 */ -void sub_6B4D26(int rideIndex, rct_xy_element *startElement) +void ride_set_start_finish_points(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) { + rct_ride *ride = GET_RIDE(rideIndex); + switch (ride->type) { + case RIDE_TYPE_BOAT_RIDE: + ride_set_boat_hire_return_point(ride, startElement); + break; + case RIDE_TYPE_MAZE: + ride_set_maze_entrance_exit_points(ride); + break; } - 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; + if (ride_is_block_sectioned(ride) && !(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)) { + ride_set_block_points(startElement); + } +} + +/** + * + * rct2: 0x0069ED9E + */ +static int sub_69ED9E() +{ + int miscSpriteCount = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_COUNT_MISC, uint16); + int unkCount = RCT2_GLOBAL(0x013573C8, uint16); + return max(0, miscSpriteCount + unkCount - 300); +} + +void vehicle_unset_var_48_b1(rct_vehicle *head) +{ + uint16 spriteIndex; + rct_vehicle *vehicle = head; + while (true) { + vehicle->update_flags &= ~VEHICLE_UPDATE_FLAG_1; + spriteIndex = vehicle->next_vehicle_on_train; + if (spriteIndex == SPRITE_INDEX_NULL) { + break; + } + vehicle = GET_VEHICLE(spriteIndex); + } +} + +/** + * + * rct2: 0x006DDE9E + */ +void ride_create_vehicles_find_first_block(rct_ride *ride, rct_xy_element *outXYElement) +{ + rct_vehicle *vehicle = GET_VEHICLE(ride->vehicles[0]); + int firstX = vehicle->track_x; + int firstY = vehicle->track_y; + int firstZ = vehicle->track_z; + rct_map_element *firstElement = map_get_track_element_at(firstX, firstY, firstZ / 8); + + assert(firstElement != NULL); + + int x = firstX; + int y = firstY; + int z = firstZ; + rct_map_element *trackElement = firstElement; + track_begin_end trackBeginEnd; + while (track_block_get_previous(x, y, trackElement, &trackBeginEnd)) { + x = trackBeginEnd.begin_x; + y = trackBeginEnd.begin_y; + trackElement = trackBeginEnd.begin_element; + if (x == firstX && y == firstY && trackElement == firstElement) { + break; + } + + int trackType = trackElement->properties.track.type; + switch (trackType) { + case TRACK_ELEM_25_DEG_UP_TO_FLAT: + case TRACK_ELEM_60_DEG_UP_TO_FLAT: + if (track_element_is_lift_hill(trackElement)) { + outXYElement->x = x; + outXYElement->y = y; + outXYElement->element = trackElement; + return; + } + break; + case TRACK_ELEM_DIAG_25_DEG_UP_TO_FLAT: + case TRACK_ELEM_DIAG_60_DEG_UP_TO_FLAT: + if (track_element_is_lift_hill(trackElement)) { + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) continue; + if (mapElement->base_height != z) continue; + if ((mapElement->properties.track.sequence & 0x0F) != 0) continue; + if (mapElement->properties.track.type != trackType) continue; + break; + } while (!map_element_is_last_for_tile(mapElement)); + + outXYElement->x = x; + outXYElement->y = y; + outXYElement->element = mapElement; + return; + } + break; + case TRACK_ELEM_END_STATION: + case TRACK_ELEM_CABLE_LIFT_HILL: + case 216: + outXYElement->x = x; + outXYElement->y = y; + outXYElement->element = trackElement; + return; + } + } + + outXYElement->x = firstX; + outXYElement->y = firstY; + outXYElement->element = firstElement; +} + +/** + * + * rct2: 0x006DDF9C + */ +void loc_6DDF9C(rct_ride *ride, rct_map_element *mapElement) +{ + rct_vehicle *train, *car; + + for (int i = 0; i < ride->num_vehicles; i++) { + train = GET_VEHICLE(ride->vehicles[i]); + if (i == 0) { + sub_6DAB4C(train, NULL); + vehicle_unset_var_48_b1(train); + continue; + } + 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); + mapElement->flags |= (1 << 5); + car = train; + while (true) { + car->velocity = 0; + car->var_2C = 0; + car->var_4A = 0; + car->var_24 += 13962; + + uint16 spriteIndex = car->next_vehicle_on_train; + if (spriteIndex == SPRITE_INDEX_NULL) { + break; + } + car = GET_VEHICLE(spriteIndex); + } + } while (sub_6DAB4C(train, NULL) & 0x400); + + mapElement->flags |= (1 << 5); + car = train; + while (true) { + car->update_flags &= ~VEHICLE_UPDATE_FLAG_1; + car->status = VEHICLE_STATUS_TRAVELLING; + if ((car->track_type >> 2) == TRACK_ELEM_END_STATION) { + car->status = VEHICLE_STATUS_MOVING_TO_END_OF_STATION; + } + + uint16 spriteIndex = car->next_vehicle_on_train; + if (spriteIndex == SPRITE_INDEX_NULL) { break; } - } while (track_get_next(¤tElement, ¤tElement) && currentElement.element != startElement->element); + car = GET_VEHICLE(spriteIndex); + } } } /** - * + * * rct2: 0x006DD84C */ -int sub_6DD84C(rct_ride *ride, int rideIndex, rct_xy_element *element, int isApplying) +bool ride_create_vehicles(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; + bool b = !(RCT2_CALLPROC_X(0x006DD84C, element->x, isApplying, element->y, rideIndex, (int)ride, (int)element->element, 0) & 0x100); + return b; } /** - * + * + * rct2: 0x006D31A6 + * Checks and initialises the cable lift track + * returns false if unable to find appropriate track. + */ +static bool ride_initialise_cable_lift_track(rct_ride *ride, bool isApplying) +{ + uint16 xy; + int stationIndex; + for (stationIndex = 0; stationIndex < 4; stationIndex++) { + xy = ride->station_starts[stationIndex]; + if (xy != 0xFFFF) break; + if (stationIndex == 3) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CABLE_LIFT_HILL_MUST_START_IMMEDIATELY_AFTER_STATION; + return false; + } + } + + int x = (xy & 0xFF) * 32; + int y = (xy >> 8) * 32; + int z = ride->station_heights[stationIndex]; + + bool success = false; + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) continue; + if (mapElement->base_height != z) continue; + + int trackType = mapElement->properties.track.type; + if (!(RCT2_ADDRESS(0x0099BA64, uint8)[trackType * 16] & 0x10)) { + continue; + } + success = true; + break; + } while (!map_element_is_last_for_tile(mapElement++)); + + if (!success) + return false; + + enum { + STATE_FIND_CABLE_LIFT, + STATE_FIND_STATION, + STATE_REST_OF_TRACK + }; + int state = STATE_FIND_CABLE_LIFT; + + track_circuit_iterator it; + track_circuit_iterator_begin(&it, (rct_xy_element){ + .x = x, + .y = y, + .element = mapElement + }); + while (track_circuit_iterator_previous(&it)) { + mapElement = it.current.element; + int trackType = mapElement->properties.track.type; + + uint16 flags = 16; + switch (state) { + case STATE_FIND_CABLE_LIFT: + // Search for a cable lift hill track element + if (trackType == TRACK_ELEM_CABLE_LIFT_HILL) { + flags = 8; + state = STATE_FIND_STATION; + } + break; + case STATE_FIND_STATION: + // Search for the start of the hill + switch (trackType) { + case TRACK_ELEM_FLAT: + case TRACK_ELEM_25_DEG_UP: + case TRACK_ELEM_60_DEG_UP: + case TRACK_ELEM_FLAT_TO_25_DEG_UP: + case TRACK_ELEM_25_DEG_UP_TO_FLAT: + case TRACK_ELEM_25_DEG_UP_TO_60_DEG_UP: + case TRACK_ELEM_60_DEG_UP_TO_25_DEG_UP: + case TRACK_ELEM_FLAT_TO_60_DEG_UP_LONG_BASE: + flags = 8; + break; + case TRACK_ELEM_END_STATION: + state = STATE_REST_OF_TRACK; + break; + default: + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CABLE_LIFT_HILL_MUST_START_IMMEDIATELY_AFTER_STATION; + return false; + } + break; + } + if (isApplying) { + z = mapElement->base_height * 8; + int direction = mapElement->type & 3; + trackType = mapElement->properties.track.type; + x = it.current.x; + y = it.current.y; + sub_6C683D(&x, &y, &z, direction, trackType, 0, &mapElement, flags); + } + } + return true; +} + +/** + * * rct2: 0x006DF4D4 */ -int sub_6DF4D4(rct_ride *ride, rct_xy_element *element, int isApplying) +bool ride_create_cable_lift(int rideIndex, bool isApplying) { - return RCT2_CALLPROC_X(0x006DF4D4, element->x, isApplying, element->y, 0, (int)ride, (int)element->element, 0) & 0x100; + rct_ride *ride = GET_RIDE(rideIndex); + + if (ride->mode != RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED && + ride->mode != RIDE_MODE_CONTINUOUS_CIRCUIT + ) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CABLE_LIFT_UNABLE_TO_WORK_IN_THIS_OPERATING_MODE; + return false; + } + + if (ride->num_circuits > 1) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_MULTICIRCUIT_NOT_POSSIBLE_WITH_CABLE_LIFT_HILL; + return false; + } + + if (sub_69ED9E() <= 5) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_UNABLE_TO_CREATE_ENOUGH_VEHICLES; + return false; + } + + if (!ride_initialise_cable_lift_track(ride, isApplying)) { + return false; + } + + if (!isApplying) { + return true; + } + + int x = ride->cable_lift_x; + int y = ride->cable_lift_y; + int z = ride->cable_lift_z; + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) continue; + if (mapElement->base_height != z) continue; + break; + } while (!map_element_is_last_for_tile(mapElement++)); + int direction = mapElement->type & MAP_ELEMENT_DIRECTION_MASK; + + rct_vehicle *head = NULL; + rct_vehicle *tail = NULL; + uint32 ebx = 0; + for (int i = 0; i < 5; i++) { + uint32 edx = ror32(0x15478, 10); + uint16 var_44 = edx & 0xFFFF; + edx = rol32(edx, 10) >> 1; + ebx -= edx; + uint32 var_24 = ebx; + ebx -= edx; + + rct_vehicle *current = cable_lift_segment_create(rideIndex, x, y, z, direction, var_44, var_24, i == 0); + current->next_vehicle_on_train = SPRITE_INDEX_NULL; + if (i == 0) { + head = current; + } else { + tail->next_vehicle_on_train = current->sprite_index; + tail->next_vehicle_on_ride = current->sprite_index; + current->prev_vehicle_on_ride = tail->sprite_index; + } + tail = current; + } + head->prev_vehicle_on_ride = tail->sprite_index; + tail->next_vehicle_on_ride = head->sprite_index; + + ride->lifecycle_flags |= RIDE_LIFECYCLE_CABLE_LIFT; + sub_6DEF56(head); + return true; } /** - * + * * rct2: 0x006B51C0 */ void loc_6B51C0(int rideIndex) @@ -3580,7 +4541,7 @@ void loc_6B51C0(int rideIndex) } /** - * + * * rct2: 0x006B528A */ void loc_6B528A(rct_xy_element *trackElement) @@ -3602,7 +4563,7 @@ void loc_6B528A(rct_xy_element *trackElement) } /** - * + * * rct2: 0x006B4F6B */ rct_map_element *loc_6B4F6B(int rideIndex, int x, int y) @@ -3626,7 +4587,7 @@ rct_map_element *loc_6B4F6B(int rideIndex, int x, int y) if (mapElement->properties.track.ride_index == rideIndex) return mapElement; } while (!map_element_is_last_for_tile(mapElement++)); - + return NULL; } @@ -3638,7 +4599,7 @@ int ride_is_valid_for_test(int rideIndex, int goingToBeOpen, int isApplying) ride = GET_RIDE(rideIndex); - window_close_by_class(WC_RIDE_CONSTRUCTION); + window_close_by_number(WC_RIDE_CONSTRUCTION, rideIndex); stationIndex = ride_mode_check_station_present(ride); if (stationIndex == -1)return 0; @@ -3692,16 +4653,16 @@ int ride_is_valid_for_test(int rideIndex, int goingToBeOpen, int isApplying) if (ride->subtype != 255) { rct_ride_type *rideType = GET_RIDE_ENTRY(ride->subtype); - if (rideType->flags & RIDE_ENTRY_FLAG_1) { + if (rideType->flags & RIDE_ENTRY_FLAG_NO_INVERSIONS) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; - if (ride_check_track_suitability_a(&trackElement, &problematicTrackElement)) { + if (ride_check_track_contains_inversions(&trackElement, &problematicTrackElement)) { loc_6B528A(&problematicTrackElement); return 0; } } - if (rideType->flags & RIDE_ENTRY_FLAG_2) { + if (rideType->flags & RIDE_ENTRY_FLAG_NO_BANKED_TRACK) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; - if (ride_check_track_suitability_b(&trackElement, &problematicTrackElement)) { + if (ride_check_track_contains_banked(&trackElement, &problematicTrackElement)) { loc_6B528A(&problematicTrackElement); return 0; } @@ -3715,48 +4676,43 @@ int ride_is_valid_for_test(int rideIndex, int goingToBeOpen, int isApplying) } 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); + if (!ride_check_station_length(&trackElement, &problematicTrackElement)) { + 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)) { + if (!ride_check_start_and_end_is_station(&trackElement, &problematicTrackElement)) { loc_6B528A(&problematicTrackElement); return 0; } } if (isApplying) - sub_6B4D26(rideIndex, &trackElement); + ride_set_start_finish_points(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)) + ) { + if (!ride_create_vehicles(ride, rideIndex, &trackElement, isApplying)) { return 0; + } } if ( - (RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint32) & 0x400) && + (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_10) && (ride->lifecycle_flags & RIDE_LIFECYCLE_16) && !(ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT) ) { - if (sub_6DF4D4(ride, &trackElement, isApplying)) + if (!ride_create_cable_lift(rideIndex, isApplying)) return 0; } return 1; } /** - * + * * rct2: 0x006B4EEA */ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) @@ -3767,7 +4723,7 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) ride = GET_RIDE(rideIndex); - window_close_by_class(WC_RIDE_CONSTRUCTION); + window_close_by_number(WC_RIDE_CONSTRUCTION, rideIndex); stationIndex = ride_mode_check_station_present(ride); if (stationIndex == -1)return 0; @@ -3784,7 +4740,7 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int 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; @@ -3821,16 +4777,16 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) if (ride->subtype != 255) { rct_ride_type *rideType = GET_RIDE_ENTRY(ride->subtype); - if (rideType->flags & RIDE_ENTRY_FLAG_1) { + if (rideType->flags & RIDE_ENTRY_FLAG_NO_INVERSIONS) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; - if (ride_check_track_suitability_a(&trackElement, &problematicTrackElement)) { + if (ride_check_track_contains_inversions(&trackElement, &problematicTrackElement)) { loc_6B528A(&problematicTrackElement); return 0; } } - if (rideType->flags & RIDE_ENTRY_FLAG_2) { + if (rideType->flags & RIDE_ENTRY_FLAG_NO_BANKED_TRACK) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; - if (ride_check_track_suitability_b(&trackElement, &problematicTrackElement)) { + if (ride_check_track_contains_banked(&trackElement, &problematicTrackElement)) { loc_6B528A(&problematicTrackElement); return 0; } @@ -3844,41 +4800,36 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) } 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); + if (!ride_check_station_length(&trackElement, &problematicTrackElement)) { + 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)) { + if (!ride_check_start_and_end_is_station(&trackElement, &problematicTrackElement)) { loc_6B528A(&problematicTrackElement); return 0; } } if (isApplying) - sub_6B4D26(rideIndex, &trackElement); + ride_set_start_finish_points(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)) + if (!ride_create_vehicles(ride, rideIndex, &trackElement, isApplying)) { return 0; + } } if ( - (RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint32) & 0x400) && + (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_10) && (ride->lifecycle_flags & RIDE_LIFECYCLE_16) && !(ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT) ) { - if (sub_6DF4D4(ride, &trackElement, isApplying)) + if (!ride_create_cable_lift(rideIndex, isApplying)) return 0; } @@ -3891,7 +4842,7 @@ void ride_set_status(int rideIndex, int status) } /** - * + * * rct2: 0x006B4EA6 */ void game_command_set_ride_status(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) @@ -3902,7 +4853,7 @@ void game_command_set_ride_status(int *eax, int *ebx, int *ecx, int *edx, int *e rideIndex = *edx & 0xFF; targetStatus = (*edx >> 8) & 0xFF; - RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 4; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_RUNNING_COSTS * 4; ride = GET_RIDE(rideIndex); RCT2_GLOBAL(0x00F43484, uint32) = RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32); @@ -3917,7 +4868,7 @@ void game_command_set_ride_status(int *eax, int *ebx, int *ecx, int *edx, int *e ride_remove_peeps(rideIndex); } } - + ride->status = RIDE_STATUS_CLOSED; ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING; ride->race_winner = 0xFFFF; @@ -3965,7 +4916,7 @@ void ride_set_name(int rideIndex, const char *name) } /** - * + * * rct2: 0x006B578B */ void game_command_set_ride_name(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) @@ -3980,7 +4931,7 @@ void game_command_set_ride_name(int *eax, int *ebx, int *ecx, int *edx, int *esi 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) { + //if (*ebx & GAME_COMMAND_FLAG_APPLY) { // this check seems to be useless and causes problems in multiplayer int nameChunkOffset = nameChunkIndex - 1; if (nameChunkOffset < 0) nameChunkOffset = 2; @@ -3988,7 +4939,7 @@ void game_command_set_ride_name(int *eax, int *ebx, int *ecx, int *edx, int *esi 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; @@ -4034,96 +4985,630 @@ void game_command_set_ride_name(int *eax, int *ebx, int *ecx, int *edx, int *esi } /** - * + * * 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; + RCT2_GLOBAL(0x00F4413A, money32) = 0; - 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); + map_element_iterator it; - 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); + map_element_iterator_begin(&it); + while (map_element_iterator_next(&it)) { + if (map_element_get_type(it.element) != MAP_ELEMENT_TYPE_TRACK) + continue; - 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)); + if (it.element->properties.track.ride_index != ride_id) + continue; + + int x = it.x * 32, y = it.y * 32; + int z = it.element->base_height * 8; + + uint8 rotation = it.element->type & MAP_ELEMENT_DIRECTION_MASK; + uint8 type = it.element->properties.track.type; + + if (type != TRACK_ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP){ + RCT2_GLOBAL(0x00F4413A, money32) += game_do_command( + x, + GAME_COMMAND_FLAG_APPLY | (rotation << 8), + y, + type | ((it.element->properties.track.sequence & 0xF) << 8), + GAME_COMMAND_REMOVE_TRACK, + z, + 0); + map_element_iterator_restart_for_tile(&it); + continue; } + + RCT2_GLOBAL(0x00F4413A, money32) += game_do_command( + x, + GAME_COMMAND_FLAG_APPLY | (0 << 8), + y, + ride_id | (2 << 8), + GAME_COMMAND_SET_MAZE_TRACK, + z, + 0); + + RCT2_GLOBAL(0x00F4413A, money32) += game_do_command( + x, + GAME_COMMAND_FLAG_APPLY | (1 << 8), + y + 16, + ride_id | (2 << 8), + GAME_COMMAND_SET_MAZE_TRACK, + z, + 0); + + RCT2_GLOBAL(0x00F4413A, money32) += game_do_command( + x + 16, + GAME_COMMAND_FLAG_APPLY | (2 << 8), + y + 16, + ride_id | (2 << 8), + GAME_COMMAND_SET_MAZE_TRACK, + z, + 0); + + RCT2_GLOBAL(0x00F4413A, money32) += game_do_command( + x + 16, + GAME_COMMAND_FLAG_APPLY | (3 << 8), + y, + ride_id | (2 << 8), + GAME_COMMAND_SET_MAZE_TRACK, + z, + 0); + map_element_iterator_restart_for_tile(&it); } RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) = oldpaused; return RCT2_GLOBAL(0x00F4413A, int); } /** - * + * + * rct2: 0x00696707 + */ +static void ride_stop_peeps_queuing(int rideIndex) +{ + uint16 spriteIndex; + rct_peep *peep; + + FOR_ALL_PEEPS(spriteIndex, peep) { + if (peep->state != PEEP_STATE_QUEUING) + continue; + if (peep->current_ride != rideIndex) + continue; + + remove_peep_from_queue(peep); + peep_decrement_num_riders(peep); + + peep->state = PEEP_STATE_FALLING; + + peep_window_state_update(peep); + } +} + +static int ride_get_empty_slot() +{ + rct_ride *ride; + for (int i = 0; i < MAX_RIDES; i++) { + ride = GET_RIDE(i); + if (ride->type == RIDE_TYPE_NULL) { + return i; + } + } + return -1; +} + +static int ride_get_default_mode(rct_ride *ride) +{ + const rct_ride_type *rideEntry = GET_RIDE_ENTRY(ride->subtype); + const uint8 *availableModes = RideAvailableModes; + + for (int i = 0; i < ride->type; i++) { + while (*(availableModes++) != 255) {} + } + if (rideEntry->flags & RIDE_ENTRY_DISABLE_FIRST_TWO_OPERATING_MODES) { + availableModes += 2; + } + return availableModes[0]; +} + +static bool ride_with_colour_config_exists(uint8 ride_type, const track_colour *colours) +{ + rct_ride *ride; + int i; + + FOR_ALL_RIDES(i, ride) { + if (ride->type != ride_type) continue; + if (ride->track_colour_main[0] != colours->main) continue; + if (ride->track_colour_additional[0] != colours->additional) continue; + if (ride->track_colour_supports[0] != colours->supports) continue; + + return true; + } + return false; +} + +static bool ride_name_exists(char *name) +{ + char buffer[256]; + rct_ride *ride; + int i; + + FOR_ALL_RIDES(i, ride) { + format_string(buffer, ride->name, &ride->name_arguments); + if (strcmp(buffer, name) == 0) { + return true; + } + } + + return false; +} + +/** + * + * Based on rct2: 0x006B4776 + */ +static int ride_get_random_colour_preset_index(uint8 ride_type) +{ + const track_colour_preset_list *colourPresets; + const track_colour *colours; + + colourPresets = RCT2_ADDRESS(0x0097D934, track_colour_preset_list*)[ride_type]; + + // 200 attempts to find a colour preset that hasn't already been used in the park for this ride type + for (int i = 0; i < 200; i++) { + int listIndex = util_rand() % colourPresets->count; + colours = &colourPresets->list[listIndex]; + + if (!ride_with_colour_config_exists(ride_type, colours)) { + return listIndex; + } + } + return 0; +} + +/** + * + * Based on rct2: 0x006B4776 + */ +static void ride_set_colour_preset(rct_ride *ride, uint8 index) { + const track_colour_preset_list *colourPresets; + const track_colour *colours; + + colourPresets = RCT2_ADDRESS(0x0097D934, track_colour_preset_list*)[ride->type]; + colours = &colourPresets->list[index]; + for (int i = 0; i < 4; i++) { + ride->track_colour_main[i] = colours->main; + ride->track_colour_additional[i] = colours->additional; + ride->track_colour_supports[i] = colours->supports; + } + ride->colour_scheme_type = 0; +} + +static money32 ride_get_common_price(rct_ride *forRide) +{ + rct_ride *ride; + int i; + + FOR_ALL_RIDES(i, ride) { + if (ride->type == forRide->type && ride != forRide) { + return ride->price; + } + } + + return MONEY32_UNDEFINED; +} + +static money32 shop_item_get_common_price(rct_ride *forRide, int shopItem) +{ + rct_ride_type *rideEntry; + rct_ride *ride; + int i; + + FOR_ALL_RIDES(i, ride) { + if (ride != forRide) { + rideEntry = GET_RIDE_ENTRY(ride->subtype); + if (rideEntry->shop_item == shopItem) { + return ride->price; + } + if (rideEntry->shop_item_secondary == shopItem) { + return ride->price_secondary; + } + } + } + + return MONEY32_UNDEFINED; +} + +static bool shop_item_has_common_price(int shopItem) +{ + if (shopItem < 32) { + return RCT2_GLOBAL(0x01358838, uint32) & (1 << shopItem); + } else { + return RCT2_GLOBAL(0x0135934C, uint32) & (1 << (shopItem - 32)); + } +} + +/** + * + * rct2: 0x006B3F0F + */ +money32 ride_create(int type, int subType, int flags, int *outRideIndex, int *outRideColour) +{ + char rideNameBuffer[256]; + rct_ride *ride; + rct_ride_type *rideEntry; + int rideIndex, rideEntryIndex; + + if (subType == 255) { + uint8 *availableRideEntries = get_ride_entry_indices_for_ride_type(type); + for (uint8 *rei = availableRideEntries; *rei != 255; rei++) { + rideEntry = GET_RIDE_ENTRY(*rei); + if ((rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) && !rideTypeShouldLoseSeparateFlag(rideEntry)) { + subType = *rei; + goto foundRideEntry; + } + } + subType = availableRideEntries[0]; + } + +foundRideEntry: + rideEntryIndex = subType; + rideIndex = ride_get_empty_slot(); + if (rideIndex == -1) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_MANY_RIDES; + return MONEY32_UNDEFINED; + } + *outRideIndex = rideIndex; + + // Ride/vehicle colour is calcualted before applying to ensure + // correct colour is passed over the network. + if (!(flags & GAME_COMMAND_FLAG_APPLY) && !(flags & GAME_COMMAND_FLAG_NETWORKED)) { + *outRideColour = + ride_get_random_colour_preset_index(type) | + (ride_get_unused_preset_vehicle_colour(type, subType) << 8); + } + + if (!(flags & GAME_COMMAND_FLAG_APPLY)) { + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = 0x8000; + return 0; + } + + ride = GET_RIDE(rideIndex); + rideEntry = GET_RIDE_ENTRY(rideEntryIndex); + ride->type = type; + ride->subtype = rideEntryIndex; + ride_set_colour_preset(ride, *outRideColour & 0xFF); + ride->overall_view = 0xFFFF; + + // Ride name + if (rideEntryIndex == 255) { + useDefaultName: + ride->name = STR_NONE; + + struct { + uint16 type_name; + uint16 number; + } name_args; + name_args.type_name = 2 + ride->type; + name_args.number = 0; + do { + name_args.number++; + format_string(rideNameBuffer, 1, &name_args); + } while (ride_name_exists(rideNameBuffer)); + ride->name = 1; + ride->name_arguments_type_name = name_args.type_name; + ride->name_arguments_number = name_args.number; + } else { + if (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) || rideTypeShouldLoseSeparateFlag(rideEntry)) { + goto useDefaultName; + } + ride->name = 1; + ride->name_arguments_type_name = rideEntry->name; + ride->name_arguments_number = 0; + + rct_string_id rideNameStringId = 0; + for (int i = 0; i < 100; i++) { + ride->name_arguments_number++; + format_string(rideNameBuffer, ride->name, &ride->name_arguments); + + rideNameStringId = user_string_allocate(4, rideNameBuffer); + if (rideNameStringId != 0) { + ride->name = rideNameStringId; + break; + } + } + if (rideNameStringId == 0) { + goto useDefaultName; + } + } + + for (int i = 0; i < 4; i++) { + ride->station_starts[i] = 0xFFFF; + ride->entrances[i] = 0xFFFF; + ride->exits[i] = 0xFFFF; + ride->var_066[i] = 255; + ride->queue_time[i] = 0; + } + + for (int i = 0; i < 32; i++) { + ride->vehicles[i] = 0xFFFF; + } + + ride->status = RIDE_STATUS_CLOSED; + ride->lifecycle_flags = 0; + ride->var_1CA = 0; + ride->num_stations = 0; + ride->num_vehicles = 1; + ride->var_0CA = 32; + ride->max_trains = 32; + ride->num_cars_per_train = 1; + ride->var_0CB = 12; + ride->min_waiting_time = 10; + ride->max_waiting_time = 60; + ride->depart_flags = RIDE_DEPART_WAIT_FOR_MINIMUM_LENGTH | 3; + if (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_MUSIC_ON_DEFAULT) { + ride->lifecycle_flags |= RIDE_LIFECYCLE_MUSIC; + } + ride->music = RCT2_ADDRESS(0x0097D4F4, uint8)[ride->type * 8]; + + ride->operation_option = ( + RCT2_GLOBAL(0x0097CF40 + 4 + (ride->type * 8), uint8) + + RCT2_GLOBAL(0x0097CF40 + 4 + (ride->type * 8), uint8) + + RCT2_GLOBAL(0x0097CF40 + 4 + (ride->type * 8), uint8) + + RCT2_GLOBAL(0x0097CF40 + 5 + (ride->type * 8), uint8) + ) / 4; + + ride->lift_hill_speed = RCT2_ADDRESS(0x0097D7C9, uint8)[ride->type * 4]; + + ride->measurement_index = 255; + ride->excitement = (ride_rating)-1; + ride->var_120 = 0; + ride->var_122 = 0; + ride->var_148 = 0; + + ride->price = 0; + ride->price_secondary = 0; + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) { + ride->price = RCT2_GLOBAL(0x0097D4F0 + 0 + (ride->type * 8), uint8); + ride->price_secondary = RCT2_GLOBAL(0x0097D4F0 + 1 + (ride->type * 8), uint8); + + if (rideEntry->shop_item == 255) { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY)) { + ride->price = 0; + } + } else { + ride->price = DefaultShopItemPrice[rideEntry->shop_item]; + } + if (rideEntry->shop_item_secondary != 255) { + ride->price_secondary = DefaultShopItemPrice[rideEntry->shop_item_secondary]; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) == OBJECTIVE_BUILD_THE_BEST) { + ride->price = 0; + } + + if (ride->type == RIDE_TYPE_TOILETS) { + if (RCT2_GLOBAL(0x01358838, uint32) & (1 << 31)) { + money32 price = ride_get_common_price(ride); + if (price != MONEY32_UNDEFINED) { + ride->price = (money16)price; + } + } + } + + if (rideEntry->shop_item != 255) { + if (shop_item_has_common_price(rideEntry->shop_item)) { + money32 price = shop_item_get_common_price(ride, rideEntry->shop_item); + if (price != MONEY32_UNDEFINED) { + ride->price = (money16)price; + } + } + } + + if (rideEntry->shop_item_secondary != 255) { + if (shop_item_has_common_price(rideEntry->shop_item_secondary)) { + money32 price = shop_item_get_common_price(ride, rideEntry->shop_item_secondary); + if (price != MONEY32_UNDEFINED) { + ride->price_secondary = (money16)price; + } + } + } + } + + // The next 10 variables are treated like an array of 10 items + ride->var_124 = 0; + ride->var_124 = 0; + ride->var_126 = 0; + ride->var_128 = 0; + ride->var_12A = 0; + ride->var_12C = 0; + ride->var_12E = 0; + ride->age = 0; + ride->running_cost = 0; + ride->var_134 = 0; + ride->var_136 = 0; + + ride->value = 0xFFFF; + ride->satisfaction = 255; + ride->satisfaction_time_out = 0; + ride->satisfaction_next = 0; + ride->popularity = 255; + ride->popularity_time_out = 0; + ride->popularity_next = 0; + ride->window_invalidate_flags = 0; + ride->total_customers = 0; + ride->total_profit = 0; + ride->num_riders = 0; + ride->var_15D = 0; + ride->maze_tiles = 0; + ride->build_date = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16); + ride->music_tune_id = 255; + + ride->breakdown_reason = 255; + ride->upkeep_cost = (money16)-1; + ride->reliability = 0x64FF; + ride->unreliability_factor = 1; + ride->inspection_interval = RIDE_INSPECTION_EVERY_30_MINUTES; + ride->last_inspection = 0; + ride->downtime = 0; + ride->var_19C = 0; + ride->var_1A0 = 0; + ride->no_primary_items_sold = 0; + ride->no_secondary_items_sold = 0; + ride->last_crash_type = RIDE_CRASH_TYPE_NONE; + ride->income_per_hour = MONEY32_UNDEFINED; + ride->profit = MONEY32_UNDEFINED; + ride->connected_message_throttle = 0; + ride->entrance_style = RIDE_ENTRANCE_STYLE_PLAIN; + ride->num_block_brakes = 0; + ride->guests_favourite = 0; + + ride->num_circuits = 1; + ride->mode = ride_get_default_mode(ride); + ride->min_max_cars_per_train = (rideEntry->min_cars_in_train << 4) | rideEntry->max_cars_in_train; + ride_set_vehicle_colours_to_random_preset(ride, 0xFF & (*outRideColour >> 8)); + window_invalidate_by_class(WC_RIDE_LIST); + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = 0x8000; + return 0; +} + +/** + * + * rct2: 0x006B3F0F + */ +void game_command_create_ride(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + *ebx = ride_create(*edx & 0xFF, (*edx >> 8) & 0xFF, *ebx, edi, eax); +} + +void game_command_callback_ride_construct_new(int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp) +{ + int rideIndex = edi; + if (rideIndex != -1) + ride_construct(rideIndex); +} + +/** + * + * Network client callback when placing ride pieces + * Client does execute placing the piece on the same tick as mouse_up - waits for server command + * Re-executes function from ride_construction - window_ride_construction_construct() + * Only uses part that deals with construction state + */ + +void game_command_callback_ride_construct_placed_back(int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp) +{ + int trackDirection, x, y, z; + track_begin_end trackBeginEnd; + + RCT2_GLOBAL(0x00F441D2, uint8) = _currentRideIndex; + trackDirection = _currentTrackPieceDirection ^ 2; + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; + if (!(trackDirection & 4)) { + x += TileDirectionDelta[trackDirection].x; + y += TileDirectionDelta[trackDirection].y; + } + + if (track_block_get_previous_from_zero(x, y, z, _currentRideIndex, trackDirection, &trackBeginEnd)) { + _currentTrackBeginX = trackBeginEnd.begin_x; + _currentTrackBeginY = trackBeginEnd.begin_y; + _currentTrackBeginZ = trackBeginEnd.begin_z; + _currentTrackPieceDirection = trackBeginEnd.begin_direction; + _currentTrackPieceType = trackBeginEnd.begin_element->properties.track.type; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; + _rideConstructionState = RIDE_CONSTRUCTION_STATE_SELECTED; + ride_select_previous_section(); + } + else { + _rideConstructionState = RIDE_CONSTRUCTION_STATE_0; + } + + sub_6C84CE(); +} + +void game_command_callback_ride_construct_placed_front(int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp) +{ + int trackDirection, x, y, z; + + RCT2_GLOBAL(0x00F441D2, uint8) = _currentRideIndex; + trackDirection = _currentTrackPieceDirection; + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; + if (!(trackDirection & 4)) { + x -= TileDirectionDelta[trackDirection].x; + y -= TileDirectionDelta[trackDirection].y; + } + + rct_xy_element next_track; + if (track_block_get_next_from_zero(x, y, z, _currentRideIndex, trackDirection, &next_track, &z, &trackDirection)) { + _currentTrackBeginX = next_track.x; + _currentTrackBeginY = next_track.y; + _currentTrackBeginZ = z; + _currentTrackPieceDirection = next_track.element->type & MAP_ELEMENT_DIRECTION_MASK; + _currentTrackPieceType = next_track.element->properties.track.type; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; + _rideConstructionState = RIDE_CONSTRUCTION_STATE_SELECTED; + ride_select_next_section(); + } + else { + _rideConstructionState = RIDE_CONSTRUCTION_STATE_0; + } + + sub_6C84CE(); +} + +/** +* +* Network client callback when removing ride pieces +* Client does execute placing the piece on the same tick as mouse_up - waits for server command +* Re-executes function from ride_construction - window_ride_construction_mouseup_demolish() +* Only uses part that deals with construction state +*/ + +void game_command_callback_ride_remove_track_piece(int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp) +{ + int x, y, z, direction, type; + + x = gRideRemoveTrackPieceCallbackX; + y = gRideRemoveTrackPieceCallbackY; + z = gRideRemoveTrackPieceCallbackZ; + direction = gRideRemoveTrackPieceCallbackDirection; + type = gRideRemoveTrackPieceCallbackType; + + window_ride_construction_mouseup_demolish_next_piece(x, y, z, direction, type); +} + +/** + * * 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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, 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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, 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; @@ -4145,12 +5630,12 @@ void game_command_demolish_ride(int *eax, int *ebx, int *ecx, int *edx, int *esi } ride_clear_for_construction(ride_id); ride_remove_peeps(ride_id); - RCT2_CALLPROC_X(0x00696707, 0, 0, 0, ride_id, 0, 0, 0); + ride_stop_peeps_queuing(ride_id); *ebx = ride_get_refund_price(ride_id); - RCT2_CALLPROC_X(0x006CB945, 0, 0, 0, ride_id, 0, 0, 0); + sub_6CB945(ride_id); 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){ @@ -4160,9 +5645,9 @@ void game_command_demolish_ride(int *eax, int *ebx, int *ecx, int *edx, int *esi } uint16 spriteIndex; - rct_peep *peep; + rct_peep *peep; FOR_ALL_GUESTS(spriteIndex, peep){ - uint8 ride_id_bit = ride_id & 0x3; + uint8 ride_id_bit = ride_id % 8; 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){ @@ -4185,17 +5670,17 @@ void game_command_demolish_ride(int *eax, int *ebx, int *ecx, int *edx, int *esi peep->item_standard_flags &= ~PEEP_ITEM_PHOTO; } } - if(peep->item_extra_flags && PEEP_ITEM_PHOTO2){ + 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->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->item_extra_flags & PEEP_ITEM_PHOTO4){ if(peep->photo4_ride_ref == ride_id){ peep->item_extra_flags &= ~PEEP_ITEM_PHOTO4; } @@ -4219,21 +5704,21 @@ void game_command_demolish_ride(int *eax, int *ebx, int *ecx, int *edx, int *esi 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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = z; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION * 4; return; }else{ *ebx = 0; - RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION * 4; return; } } } /** - * + * * rct2: 0x006B2FC5 */ void game_command_set_ride_appearance(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) @@ -4255,11 +5740,11 @@ void game_command_set_ride_appearance(int *eax, int *ebx, int *ecx, int *edx, in break; case 2: *((uint8*)(&ride->vehicle_colours[index])) = value; - RCT2_CALLPROC_X(0x006DE102, 0, 0, 0, ride_id, 0, 0, 0); + ride_update_vehicle_colours(ride_id); break; case 3: *((uint8*)(&ride->vehicle_colours[index]) + 1) = value; - RCT2_CALLPROC_X(0x006DE102, 0, 0, 0, ride_id, 0, 0, 0); + ride_update_vehicle_colours(ride_id); break; case 4: ride->track_colour_supports[index] = value; @@ -4272,7 +5757,7 @@ void game_command_set_ride_appearance(int *eax, int *ebx, int *ecx, int *edx, in 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); + ride_update_vehicle_colours(ride_id); break; case 6: ride->entrance_style = value; @@ -4281,7 +5766,7 @@ void game_command_set_ride_appearance(int *eax, int *ebx, int *ecx, int *edx, in break; case 7: ride->vehicle_colours_extended[index] = value; - RCT2_CALLPROC_X(0x006DE102, 0, 0, 0, ride_id, 0, 0, 0); + ride_update_vehicle_colours(ride_id); break; } window_invalidate_by_number(WC_RIDE, ride_id); @@ -4290,7 +5775,7 @@ void game_command_set_ride_appearance(int *eax, int *ebx, int *ecx, int *edx, in } /** - * + * * rct2: 0x006B53E9 */ void game_command_set_ride_price(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) @@ -4301,7 +5786,7 @@ void game_command_set_ride_price(int *eax, int *ebx, int *ecx, int *edx, int *es rct_ride *ride; rct_ride_type *ride_type; bool secondary_price; - + flags = *ebx; ride_number = (*edx & 0xFF); ride = GET_RIDE(ride_number); @@ -4315,7 +5800,9 @@ void game_command_set_ride_price(int *eax, int *ebx, int *ecx, int *edx, int *es //edx ride_number //ebp ride_type - RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 0x14; + *ebx = 0; // for cost check - changing ride price does not cost anything + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_PARK_RIDE_TICKETS * 4; if (flags & 0x1) { if (!secondary_price) { shop_item = 0x1F; @@ -4473,6 +5960,13 @@ bool ride_is_powered_launched(rct_ride *ride) ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED; } +bool ride_is_block_sectioned(rct_ride *ride) +{ + return + ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || + ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED; +} + bool ride_has_any_track_elements(int rideIndex) { map_element_iterator it; @@ -4507,4 +6001,1348 @@ void ride_all_has_any_track_elements(bool *rideIndexArray) rideIndexArray[it.element->properties.track.ride_index] = true; } -} \ No newline at end of file +} + +/* rct2: 0x006847BA */ +void set_vehicle_type_image_max_sizes(rct_ride_type_vehicle* vehicle_type, int num_images){ + uint8 bitmap[200][200] = { 0 }; + + rct_drawpixelinfo dpi = { + .bits = (uint8*)bitmap, + .x = -100, + .y = -100, + .width = 200, + .height = 200, + .pitch = 0, + .zoom_level = 0 + }; + + for (int i = 0; i < num_images; ++i){ + gfx_draw_sprite(&dpi, vehicle_type->base_image_id + i, 0, 0, 0); + } + int al = -1; + for (int i = 99; i != 0; --i){ + for (int j = 0; j < 200; j++){ + if (bitmap[j][100 - i] != 0){ + al = i; + break; + } + } + + if (al != -1) + break; + + for (int j = 0; j < 200; j++){ + if (bitmap[j][100 + i] != 0){ + al = i; + break; + } + } + + if (al != -1) + break; + } + + al++; + int bl = -1; + + for (int i = 99; i != 0; --i){ + for (int j = 0; j < 200; j++){ + if (bitmap[100 - i][j] != 0){ + bl = i; + break; + } + } + + if (bl != -1) + break; + } + bl++; + + int bh = -1; + + for (int i = 99; i != 0; --i){ + for (int j = 0; j < 200; j++){ + if (bitmap[100 + i][j] != 0){ + bh = i; + break; + } + } + + if (bh != -1) + break; + } + bh++; + + // Moved from object paint + + if (vehicle_type->var_12 & 0x2000){ + bl += 16; + } + + vehicle_type->sprite_width = al; + vehicle_type->sprite_height_negative = bl; + vehicle_type->sprite_height_positive = bh; +} + +/** + * + * rct2: 0x006CA28C + */ +money32 ride_get_entrance_or_exit_price(int rideIndex, int x, int y, int direction, int dh, int di) +{ + sub_6C96C0(); + money32 result = game_do_command( + x, + 105 | (direction << 8), + y, + rideIndex | (dh << 8), + GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, + di, + 0 + ); + if (result != MONEY32_UNDEFINED) { + _currentTrackSelectionFlags |= (1 << 2); + RCT2_GLOBAL(0x00F440BF, uint16) = x; + RCT2_GLOBAL(0x00F440C1, uint16) = y; + RCT2_GLOBAL(0x00F440C3, uint8) = direction; + RCT2_GLOBAL(0x00F440C4, uint8) = di & 0xFF; + } + return result; +} + +int loc_6CD18E(short mapX, short mapY, short entranceMinX, short entranceMinY, short entranceMaxX, short entranceMaxY) +{ + int direction = 0; + if (mapX == entranceMinX) { + if (mapY > entranceMinY && mapY < entranceMaxY) { + return direction; + } + } + direction = 1; + if (mapY == entranceMaxY) { + if (mapX > entranceMinX && mapX < entranceMaxX) { + return direction; + } + } + direction = 2; + if (mapX == entranceMaxX) { + if (mapY > entranceMinY && mapY < entranceMaxY) { + return direction; + } + } + direction = 3; + if (mapY == entranceMinY) { + if (mapX > entranceMinX && mapX < entranceMaxX) { + return direction; + } + } + return -1; +} + +/** + * + * rct2: 0x006CCF70 + */ +void ride_get_entrance_or_exit_position_from_screen_position(int screenX, int screenY, int *outX, int *outY, int *outDirection) +{ + short mapX, mapY; + short entranceMinX, entranceMinY, entranceMaxX, entranceMaxY, word_F4418C, word_F4418E; + int interactionType, direction, stationHeight, stationDirection; + rct_map_element *mapElement; + rct_viewport *viewport; + rct_ride *ride; + + RCT2_GLOBAL(0x00F44194, uint8) = 255; + get_map_coordinates_from_pos(screenX, screenY, 0xFFFB, &mapX, &mapY, &interactionType, &mapElement, &viewport); + if (interactionType != 0) { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_TRACK) { + if (mapElement->properties.track.ride_index == RCT2_GLOBAL(0x00F44192, uint8)) { + if (RCT2_ADDRESS(0x0099BA64, uint8)[mapElement->properties.track.type << 4] & 0x10) { + if (mapElement->properties.track.type == 101) { + RCT2_GLOBAL(0x00F44193, uint8) = 0; + } else { + RCT2_GLOBAL(0x00F44193, uint8) = (mapElement->properties.track.sequence & 0x70) >> 4; + } + } + } + } + } + + ride = GET_RIDE(RCT2_GLOBAL(0x00F44192, uint8)); + stationHeight = ride->station_heights[RCT2_GLOBAL(0x00F44193, uint8)]; + + screen_get_map_xy_with_z(screenX, screenY, stationHeight * 8, &mapX, &mapY); + if (mapX == (short)0x8000) { + *outX = 0x8000; + return; + } + + word_F4418C = mapX; + word_F4418E = mapY; + RCT2_GLOBAL(0x00F44188, uint16) = floor2(mapX, 32); + RCT2_GLOBAL(0x00F4418A, uint16) = floor2(mapY, 32); + *outX = RCT2_GLOBAL(0x00F44188, uint16); + *outY = RCT2_GLOBAL(0x00F4418A, uint16); + + if (ride->type == RIDE_TYPE_NULL) + return; + + uint16 stationStartXY = ride->station_starts[RCT2_GLOBAL(0x00F44193, uint8)]; + if (stationStartXY == 0xFFFF) + return; + + RCT2_GLOBAL(0x00F44190, uint8) = stationHeight; + + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_3)) { + mapX = (word_F4418C & 0x1F) - 16; + mapY = (word_F4418E & 0x1F) - 16; + if (abs(mapX) < abs(mapY)) { + direction = mapY < 0 ? 3 : 1; + } else { + direction = mapX < 0 ? 0 : 2; + } + + for (int i = 0; i < 4; i++) { + mapX = RCT2_GLOBAL(0x00F44188, uint16) + TileDirectionDelta[direction].x; + mapY = RCT2_GLOBAL(0x00F4418A, uint16) + TileDirectionDelta[direction].y; + if (mapX >= 0 && mapY >= 0 && mapX < (256 * 32) && mapY < (256 * 32)) { + mapElement = map_get_first_element_at(mapX >> 5, mapY >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + if (mapElement->base_height != stationHeight) + continue; + if (mapElement->properties.track.ride_index != RCT2_GLOBAL(0x00F44192, uint8)) + continue; + if (mapElement->properties.track.type == 101) { + RCT2_GLOBAL(0x00F44194, uint8) = direction ^ 2; + *outDirection = direction ^ 2; + return; + } + if (map_get_station(mapElement) != RCT2_GLOBAL(0x00F44193, uint8)) + continue; + + int ebx = (mapElement->properties.track.type << 4) + (mapElement->properties.track.sequence & 0x0F); + int eax = (direction + 2 - mapElement->type) & MAP_ELEMENT_DIRECTION_MASK; + if (RCT2_ADDRESS(0x0099CA64, uint8)[ebx] & (1 << eax)) { + RCT2_GLOBAL(0x00F44194, uint8) = direction ^ 2; + *outDirection = direction ^ 2; + return; + } + } while (!map_element_is_last_for_tile(mapElement++)); + } + direction = (direction + 1) & 3; + } + RCT2_GLOBAL(0x00F44194, uint8) = 0xFF; + } else { + mapX = (stationStartXY & 0xFF) * 32; + mapY = (stationStartXY >> 8) * 32; + entranceMinX = mapX; + entranceMinY = mapY; + + mapElement = ride_get_station_start_track_element(ride, RCT2_GLOBAL(0x00F44193, uint8)); + direction = mapElement->type & MAP_ELEMENT_DIRECTION_MASK; + stationDirection = direction; + + nextTile: + entranceMaxX = mapX; + entranceMaxY = mapY; + mapX -= TileDirectionDelta[direction].x; + mapY -= TileDirectionDelta[direction].y; + mapElement = map_get_first_element_at(mapX >> 5, mapY >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + if (mapElement->properties.track.ride_index != RCT2_GLOBAL(0x00F44192, uint8)) + continue; + if (map_get_station(mapElement) != RCT2_GLOBAL(0x00F44193, uint8)) + continue; + + switch (mapElement->properties.track.type) { + case TRACK_ELEM_END_STATION: + case TRACK_ELEM_BEGIN_STATION: + case TRACK_ELEM_MIDDLE_STATION: + goto nextTile; + } + } while (!map_element_is_last_for_tile(mapElement++)); + + mapX = entranceMinX; + if (mapX > entranceMaxX) { + entranceMinX = entranceMaxX; + entranceMaxX = mapX; + } + + mapY = entranceMinY; + if (mapY > entranceMaxY) { + entranceMinY = entranceMaxY; + entranceMaxY = mapY; + } + + direction = loc_6CD18E(*outX, *outY, entranceMinX - 32, entranceMinY - 32, entranceMaxX + 32, entranceMaxY + 32); + if (direction != -1 && direction != stationDirection && direction != (stationDirection ^ 2)) { + RCT2_GLOBAL(0x00F44194, uint8) = direction; + *outDirection = direction; + return; + } + } +} + +bool ride_select_backwards_from_front() +{ + track_begin_end trackBeginEnd; + + sub_6C9627(); + RCT2_GLOBAL(0x00F441D2, uint8) = _currentRideIndex; + if (track_block_get_previous_from_zero(_currentTrackBeginX, _currentTrackBeginY, _currentTrackBeginZ, _currentRideIndex, _currentTrackPieceDirection, &trackBeginEnd)) { + _rideConstructionState = RIDE_CONSTRUCTION_STATE_SELECTED; + _currentTrackBeginX = trackBeginEnd.begin_x; + _currentTrackBeginY = trackBeginEnd.begin_y; + _currentTrackBeginZ = trackBeginEnd.begin_z; + _currentTrackPieceDirection = trackBeginEnd.begin_direction; + _currentTrackPieceType = trackBeginEnd.begin_element->properties.track.type; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; + return true; + } else { + return false; + } +} + +bool ride_select_forwards_from_back() +{ + int x, y, z, direction; + + sub_6C9627(); + RCT2_GLOBAL(0x00F441D2, uint8) = _currentRideIndex; + + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; + direction = _currentTrackPieceDirection ^ 2; + rct_xy_element next_track; + + if (track_block_get_next_from_zero(x, y, z, _currentRideIndex, direction, &next_track, &z, &direction)) { + _rideConstructionState = RIDE_CONSTRUCTION_STATE_SELECTED; + _currentTrackBeginX = next_track.x; + _currentTrackBeginY = next_track.y; + _currentTrackBeginZ = z; + _currentTrackPieceDirection = (next_track.element->type & MAP_ELEMENT_DIRECTION_MASK); + _currentTrackPieceType = next_track.element->properties.track.type; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; + return true; + } else { + return false; + } +} + +money32 ride_remove_track_piece(int x, int y, int z, int direction, int type) +{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_RIDE_CONSTRUCTION_CANT_REMOVE_THIS; + if (network_get_mode() == NETWORK_MODE_CLIENT) + { + game_command_callback = game_command_callback_ride_remove_track_piece; + } + return game_do_command(x, (GAME_COMMAND_FLAG_APPLY) | ((direction & 3) << 8), y, type, GAME_COMMAND_REMOVE_TRACK, z, 0); +} + +/** + * + * rct2: 0x006B58EF + */ +bool ride_are_all_possible_entrances_and_exits_built(rct_ride *ride) +{ + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP)) + return true; + + for (int i = 0; i < 4; i++) { + if (ride->station_starts[i] == 0xFFFF) continue; + if (ride->entrances[i] == 0xFFFF) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_ENTRANCE_NOT_YET_BUILT; + return false; + } + if (ride->exits[i] == 0xFFFF) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_EXIT_NOT_YET_BUILT; + return false; + } + } + return true; +} + +/** + * + * rct2: 0x006B59C6 + */ +void invalidate_test_results(int rideIndex) +{ + rct_ride *ride = GET_RIDE(rideIndex); + + ride_measurement_clear(ride); + ride->excitement = 0xFFFF; + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_TESTED; + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_TEST_IN_PROGRESS; + if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) { + for (int i = 0; i < ride->num_vehicles; i++) { + uint16 spriteIndex = ride->vehicles[i]; + if (spriteIndex != SPRITE_INDEX_NULL) { + rct_vehicle *vehicle = GET_VEHICLE(spriteIndex); + vehicle->update_flags &= ~VEHICLE_UPDATE_FLAG_TESTING; + } + } + } + window_invalidate_by_number(WC_RIDE, rideIndex); +} + +/** + * + * rct2: 0x006B7481 + */ +void ride_fix_breakdown(int rideIndex, int reliabilityIncreaseFactor) +{ + rct_ride *ride = GET_RIDE(rideIndex); + + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_BREAKDOWN_PENDING; + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_BROKEN_DOWN; + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_DUE_INSPECTION; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_CUSTOMER; + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) { + rct_vehicle *vehicle; + uint16 spriteIndex; + + for (int i = 0; i < ride->num_vehicles; i++) { + spriteIndex = ride->vehicles[i]; + while (spriteIndex != SPRITE_INDEX_NULL) { + vehicle = GET_VEHICLE(spriteIndex); + vehicle->update_flags &= ~VEHICLE_UPDATE_FLAG_7; + vehicle->update_flags &= ~VEHICLE_UPDATE_FLAG_BROKEN_CAR; + vehicle->update_flags &= ~VEHICLE_UPDATE_FLAG_BROKEN_TRAIN; + spriteIndex = vehicle->next_vehicle_on_train; + } + } + } + + uint8 unreliability = 100 - ((ride->reliability >> 8) & 0xFF); + ride->reliability += reliabilityIncreaseFactor * (unreliability / 2); +} + +/** + * + * rct2: 0x006DE102 + */ +static void ride_update_vehicle_colours(int rideIndex) +{ + rct_ride *ride; + rct_vehicle *vehicle; + rct_vehicle_colour colours = { 0 }; + uint16 spriteIndex; + uint8 coloursExtended = 0; + + ride = GET_RIDE(rideIndex); + if (ride->type == RIDE_TYPE_SPACE_RINGS || ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_16)) { + gfx_invalidate_screen(); + } + + for (int i = 0; i < 32; i++) { + int carIndex = 0; + spriteIndex = ride->vehicles[i]; + while (spriteIndex != SPRITE_INDEX_NULL) { + vehicle = GET_VEHICLE(spriteIndex); + switch (ride->colour_scheme_type & 3) { + case RIDE_COLOUR_SCHEME_ALL_SAME: + colours = ride->vehicle_colours[0]; + coloursExtended = ride->vehicle_colours_extended[0]; + break; + case RIDE_COLOUR_SCHEME_DIFFERENT_PER_TRAIN: + colours = ride->vehicle_colours[i]; + coloursExtended = ride->vehicle_colours_extended[i]; + break; + case RIDE_COLOUR_SCHEME_DIFFERENT_PER_CAR: + colours = ride->vehicle_colours[carIndex]; + coloursExtended = ride->vehicle_colours_extended[carIndex]; + break; + } + + vehicle->colours = colours; + vehicle->colours_extended = coloursExtended; + invalidate_sprite_2((rct_sprite*)vehicle); + spriteIndex = vehicle->next_vehicle_on_train; + carIndex++; + } + } +} + +/** + * + * rct2: 0x006DE4CD + * trainLayout: Originally fixed to 0x00F64E38. This no longer postfixes with 255. + */ +void ride_entry_get_train_layout(int rideEntryIndex, int numCarsPerTrain, uint8 *trainLayout) +{ + rct_ride_type *rideEntry = GET_RIDE_ENTRY(rideEntryIndex); + + for (int i = 0; i < numCarsPerTrain; i++) { + uint8 vehicleType = rideEntry->default_vehicle; + if (i == 0 && rideEntry->front_vehicle != 255) { + vehicleType = rideEntry->front_vehicle; + } else if (i == 1 && rideEntry->second_vehicle != 255) { + vehicleType = rideEntry->second_vehicle; + } else if (i == 2 && rideEntry->third_vehicle != 255) { + vehicleType = rideEntry->third_vehicle; + } else if (i == numCarsPerTrain - 1 && rideEntry->rear_vehicle != 255) { + vehicleType = rideEntry->rear_vehicle; + } + trainLayout[i] = vehicleType; + } +} + +int ride_get_smallest_station_length(rct_ride *ride) +{ + uint32 result = -1; + for (int i = 0; i < 4; i++) { + if (ride->station_starts[i] != 0xFFFF) { + result = min(result, (uint32)(ride->station_length[i] & 0x0F)); + } + } + return (int)result; +} + +/** + * + * rct2: 0x006CB3AA + */ +static int ride_get_track_length(rct_ride *ride) +{ + rct_window *w; + rct_map_element *mapElement; + track_circuit_iterator it; + int x, y, z, trackType, rideIndex, result; + + for (int i = 0; i < 4; i++) { + uint16 xy = ride->station_starts[i]; + if (xy == 0xFFFF) + continue; + + x = (xy & 0xFF) * 32; + y = (xy >> 8) * 32; + z = ride->station_heights[i]; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + + trackType = mapElement->properties.track.type; + if (!(RCT2_GLOBAL(0x0099BA64 + (trackType * 16), uint32) & 0x10)) + continue; + + if (mapElement->base_height != z) + continue; + + goto foundTrack; + } while (!map_element_is_last_for_tile(mapElement++)); + } + return 0; + +foundTrack: + rideIndex = mapElement->properties.track.ride_index; + + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != NULL && _rideConstructionState != RIDE_CONSTRUCTION_STATE_0 && _currentRideIndex == rideIndex) { + sub_6C9627(); + } + + result = 0; + track_circuit_iterator_begin(&it, (rct_xy_element){ x, y, mapElement }); + while (track_circuit_iterator_next(&it)) { + trackType = it.current.element->properties.track.type; + result += TrackPieceLengths[trackType]; + } + return result; +} + +/** + * + * rct2: 0x006DD57D + */ +void ride_update_max_vehicles(int rideIndex) +{ + rct_ride *ride; + rct_ride_type *rideEntry; + rct_ride_type_vehicle *vehicleEntry; + uint8 trainLayout[16], numCarsPerTrain, numVehicles; + int trainLength, maxNumTrains; + + ride = GET_RIDE(rideIndex); + if (ride->subtype == 0xFF) + return; + + rideEntry = GET_RIDE_ENTRY(ride->subtype); + if (rideEntry->cars_per_flat_ride == 0xFF) { + ride->num_cars_per_train = max(rideEntry->min_cars_in_train, ride->num_cars_per_train); + ride->min_max_cars_per_train = rideEntry->max_cars_in_train | (rideEntry->min_cars_in_train << 4); + + // Calculate maximum train length based on smallest station length + int stationLength = ride_get_smallest_station_length(ride); + if (stationLength == -1) + return; + + stationLength = (stationLength * 0x44180) - 0x16B2A; + int maxFriction = RCT2_GLOBAL(0x0097D21B + (ride->type * 8), uint8) << 8; + int maxCarsPerTrain = 1; + for (int numCars = rideEntry->max_cars_in_train; numCars > 0; numCars--) { + ride_entry_get_train_layout(ride->subtype, numCars, trainLayout); + trainLength = 0; + int totalFriction = 0; + for (int i = 0; i < numCars; i++) { + vehicleEntry = &rideEntry->vehicles[trainLayout[i]]; + trainLength += vehicleEntry->var_04; + totalFriction += vehicleEntry->car_friction; + } + + if (trainLength <= stationLength && totalFriction <= maxFriction) { + maxCarsPerTrain = numCars; + break; + } + } + int newCarsPerTrain = max(ride->var_0CB, rideEntry->min_cars_in_train); + maxCarsPerTrain = max(maxCarsPerTrain, rideEntry->min_cars_in_train); + newCarsPerTrain = min(maxCarsPerTrain, newCarsPerTrain); + ride->min_max_cars_per_train = maxCarsPerTrain | (rideEntry->min_cars_in_train << 4); + + switch (ride->mode) { + case RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED: + case RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED: + maxNumTrains = clamp(1, ride->num_stations + ride->num_block_brakes - 1, 31); + break; + case RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE: + case RIDE_MODE_POWERED_LAUNCH_PASSTROUGH: + case RIDE_MODE_SHUTTLE: + case RIDE_MODE_LIM_POWERED_LAUNCH: + case RIDE_MODE_POWERED_LAUNCH: + maxNumTrains = 1; + break; + default: + // Calculate maximum number of trains + ride_entry_get_train_layout(ride->subtype, newCarsPerTrain, trainLayout); + trainLength = 0; + for (int i = 0; i < newCarsPerTrain; i++) { + vehicleEntry = &rideEntry->vehicles[trainLayout[i]]; + trainLength += vehicleEntry->var_04; + } + + int totalLength = trainLength / 2; + if (newCarsPerTrain != 1) + totalLength /= 2; + + maxNumTrains = 0; + do { + maxNumTrains++; + totalLength += trainLength; + } while (totalLength <= stationLength); + + if ( + (ride->mode != RIDE_MODE_STATION_TO_STATION && ride->mode != RIDE_MODE_CONTINUOUS_CIRCUIT) || + !(RideData4[ride->type].flags & RIDE_TYPE_FLAG4_6) + ) { + maxNumTrains = min(maxNumTrains, 31); + } else { + ride_entry_get_train_layout(ride->subtype, newCarsPerTrain, trainLayout); + vehicleEntry = &rideEntry->vehicles[trainLayout[0]]; + int speed = vehicleEntry->powered_max_speed; + + int totalSpacing = 0; + for (int i = 0; i < newCarsPerTrain; i++) { + vehicleEntry = &rideEntry->vehicles[trainLayout[i]]; + totalSpacing += vehicleEntry->var_04; + } + + totalSpacing >>= 13; + int trackLength = ride_get_track_length(ride) / 4; + if (speed > 10) trackLength = (trackLength * 3) / 4; + if (speed > 25) trackLength = (trackLength * 3) / 4; + if (speed > 40) trackLength = (trackLength * 3) / 4; + + maxNumTrains = 0; + int length = 0; + do { + maxNumTrains++; + length += totalSpacing; + } while (maxNumTrains < 31 && length < trackLength); + } + break; + } + ride->max_trains = maxNumTrains; + + numCarsPerTrain = min(ride->var_0CB, newCarsPerTrain); + numVehicles = min(ride->var_0CA, maxNumTrains); + } else { + ride->max_trains = rideEntry->cars_per_flat_ride; + ride->min_max_cars_per_train = rideEntry->max_cars_in_train | (rideEntry->min_cars_in_train << 4); + numCarsPerTrain = rideEntry->max_cars_in_train; + numVehicles = min(ride->var_0CA, rideEntry->cars_per_flat_ride); + } + + // Refresh new current num vehicles / num cars per vehicle + if (numVehicles != ride->num_vehicles || numCarsPerTrain != ride->num_cars_per_train) { + ride->num_cars_per_train = numCarsPerTrain; + ride->num_vehicles = numVehicles; + window_invalidate_by_number(WC_RIDE, rideIndex); + } +} + +void ride_set_ride_entry(int rideIndex, int rideEntry) +{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_RIDE_SET_VEHICLE_TYPE_FAIL; + game_do_command( + 0, + GAME_COMMAND_FLAG_APPLY | (RIDE_SET_VEHICLES_COMMAND_TYPE_RIDE_ENTRY << 8), + 0, + (rideEntry << 8) | rideIndex, + GAME_COMMAND_SET_RIDE_VEHICLES, + 0, + 0 + ); +} + +void ride_set_num_vehicles(int rideIndex, int numVehicles) +{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_RIDE_SET_VEHICLE_SET_NUM_TRAINS_FAIL; + game_do_command( + 0, + GAME_COMMAND_FLAG_APPLY | (RIDE_SET_VEHICLES_COMMAND_TYPE_NUM_TRAINS << 8), + 0, + (numVehicles << 8) | rideIndex, + GAME_COMMAND_SET_RIDE_VEHICLES, + 0, + 0 + ); +} + +void ride_set_num_cars_per_vehicle(int rideIndex, int numCarsPerVehicle) +{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_RIDE_SET_VEHICLE_SET_NUM_CARS_PER_TRAIN_FAIL; + game_do_command( + 0, + GAME_COMMAND_FLAG_APPLY | (RIDE_SET_VEHICLES_COMMAND_TYPE_NUM_CARS_PER_TRAIN << 8), + 0, + (numCarsPerVehicle << 8) | rideIndex, + GAME_COMMAND_SET_RIDE_VEHICLES, + 0, + 0 + ); +} + +/** + * + * rct2: 0x006B52D4 + */ +void game_command_set_ride_vehicles(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + rct_ride *ride; + rct_ride_type *rideEntry; + rct_window *w; + int rideIndex, commandType, value; + + commandType = (*ebx >> 8) & 0xFF; + rideIndex = *edx & 0xFF; + value = (*edx >> 8) & 0xFF; + + ride = GET_RIDE(rideIndex); + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_RUNNING_COSTS * 4; + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_HAS_BROKEN_DOWN_AND_REQUIRES_FIXING; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (ride->status != RIDE_STATUS_CLOSED) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_MUST_BE_CLOSED_FIRST; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (!(*ebx & GAME_COMMAND_FLAG_APPLY) && !(*ebx & GAME_COMMAND_FLAG_NETWORKED)) { + *eax = + ride_get_unused_preset_vehicle_colour(ride->type, ride->subtype); + } + + if (!(*ebx & GAME_COMMAND_FLAG_APPLY)) { + *ebx = 0; + return; + } + + invalidate_test_results(rideIndex); + ride_clear_for_construction(rideIndex); + ride_remove_peeps(rideIndex); + ride->var_1CA = 100; + if (ride->type != RIDE_TYPE_ENTERPRISE) { + gfx_invalidate_screen(); + } + + switch (commandType) { + case RIDE_SET_VEHICLES_COMMAND_TYPE_NUM_TRAINS: + ride->var_0CA = value; + if (ride->type != RIDE_TYPE_SPACE_RINGS) { + gfx_invalidate_screen(); + } + break; + case RIDE_SET_VEHICLES_COMMAND_TYPE_NUM_CARS_PER_TRAIN: + rideEntry = GET_RIDE_ENTRY(ride->subtype); + value = clamp(rideEntry->min_cars_in_train, value, rideEntry->max_cars_in_train); + ride->var_0CB = value; + break; + case RIDE_SET_VEHICLES_COMMAND_TYPE_RIDE_ENTRY: + ride->subtype = value; + ride_set_vehicle_colours_to_random_preset(ride, *eax & 0xFF); + break; + } + + ride->num_circuits = 1; + ride_update_max_vehicles(rideIndex); + + w = window_find_by_number(WC_RIDE, rideIndex); + if (w != NULL) { + if (w->page == 4) { + w->var_48C = 0; + } + window_invalidate(w); + } + *ebx = 0; +} + +/** + * + * rct2: 0x006CB945 + */ +void sub_6CB945(int rideIndex) +{ + RCT2_CALLPROC_X(0x006CB945, 0, 0, 0, rideIndex, 0, 0, 0); +} + +/** + * + * rct2: 0x00666CBE + * Removes the hedge walls for an entrance placement. + */ +static void maze_entrance_hedge_removal(int x, int y, rct_map_element *mapElement) +{ + int direction = mapElement->type & MAP_ELEMENT_DIRECTION_MASK; + x += TileDirectionDelta[direction].x; + y += TileDirectionDelta[direction].y; + int z = mapElement->base_height; + int rideIndex = mapElement->properties.track.ride_index; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->type != MAP_ELEMENT_TYPE_TRACK) continue; + if (mapElement->properties.track.ride_index != rideIndex) continue; + if (mapElement->base_height != z) continue; + if (mapElement->properties.track.type != TRACK_ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP) continue; + + // Each maze element is split into 4 sections with 4 different walls + uint8 mazeSection = direction * 4; + // Remove the top outer wall + mapElement->properties.track.maze_entry &= ~(1 << ((mazeSection + 9) & 0x0F)); + // Remove the bottom outer wall + mapElement->properties.track.maze_entry &= ~(1 << ((mazeSection + 12) & 0x0F)); + // Remove the intersecting wall + mapElement->properties.track.maze_entry &= ~(1 << ((mazeSection + 10) & 0x0F)); + // Remove the top hedge section + mapElement->properties.track.maze_entry &= ~(1 << ((mazeSection + 11) & 0x0F)); + // Remove the bottom hedge section + mapElement->properties.track.maze_entry &= ~(1 << ((mazeSection + 15) & 0x0F)); + + map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + return; + } while (!map_element_is_last_for_tile(mapElement++)); +} + +/** + * + * rct2: 0x00666D6F + * Replaces the outer hedge walls for an entrance placement removal. + */ +static void maze_entrance_hedge_replacement(int x, int y, rct_map_element *mapElement) +{ + int direction = mapElement->type & MAP_ELEMENT_DIRECTION_MASK; + x += TileDirectionDelta[direction].x; + y += TileDirectionDelta[direction].y; + int z = mapElement->base_height; + int rideIndex = mapElement->properties.track.ride_index; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->type != MAP_ELEMENT_TYPE_TRACK) continue; + if (mapElement->properties.track.ride_index != rideIndex) continue; + if (mapElement->base_height != z) continue; + if (mapElement->properties.track.type != TRACK_ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP) continue; + + // Each maze element is split into 4 sections with 4 different walls + uint8 mazeSection = direction * 4; + // Add the top outer wall + mapElement->properties.track.maze_entry |= (1 << ((mazeSection + 9) & 0x0F)); + // Add the bottom outer wall + mapElement->properties.track.maze_entry |= (1 << ((mazeSection + 12) & 0x0F)); + + map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + return; + } while (!map_element_is_last_for_tile(mapElement++)); +} + +money32 place_ride_entrance_or_exit(sint16 x, sint16 y, sint16 z, uint8 direction, uint8 flags, uint8 rideIndex, uint8 station_num, uint8 is_exit) +{ + // Remember when in Unknown station num mode rideIndex is unknown and z is set + // When in known station num mode rideIndex is known and z is unknown + + RCT2_GLOBAL(0x009E32B8, uint32) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, sint16) = y; + + if (!sub_68B044()) { + return MONEY32_UNDEFINED; + } + + if (!(flags & GAME_COMMAND_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 (station_num == 0xFF) { + z *= 16; + if (flags & GAME_COMMAND_FLAG_APPLY) + return MONEY32_UNDEFINED; + + if (!gCheatsSandboxMode && !map_is_location_owned(x, y, z)) { + return MONEY32_UNDEFINED; + } + + sint16 clear_z = z / 8 + (is_exit ? 5 : 7); + RCT2_GLOBAL(0x009E32C4, sint16) = x; + RCT2_GLOBAL(0x009E32C6, sint16) = y; + + // Horrible hack until map_can_construct_with_clear_at is implemented. + RCT2_GLOBAL(0x009E32C8, uint8*) = (&flags) - 4; + + if (!gCheatsDisableClearanceChecks && !map_can_construct_with_clear_at(x, y, z / 8, clear_z, (void*)0x0066637E, 0xF)) { + return MONEY32_UNDEFINED; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) & (1 << 2)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_RIDE_CANT_BUILD_THIS_UNDERWATER; + return MONEY32_UNDEFINED; + } + + if (z > 1952) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_HIGH; + return MONEY32_UNDEFINED; + } + } else { + rct_ride* ride = GET_RIDE(rideIndex); + if (ride->status != RIDE_STATUS_CLOSED) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_MUST_BE_CLOSED_FIRST; + return MONEY32_UNDEFINED; + } + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_NOT_ALLOWED_TO_MODIFY_STATION; + return MONEY32_UNDEFINED; + } + + ride_clear_for_construction(rideIndex); + ride_remove_peeps(rideIndex); + + uint8 requires_remove = 0; + sint16 remove_x = 0; + sint16 remove_y = 0; + + if (is_exit) { + if (ride->exits[station_num] != 0xFFFF) { + if (flags & GAME_COMMAND_FLAG_GHOST) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = 0; + return MONEY32_UNDEFINED; + } + + remove_x = (ride->exits[station_num] & 0xFF) * 32; + remove_y = ((ride->exits[station_num] >> 8) & 0xFF) * 32; + requires_remove = 1; + } + } else if (ride->entrances[station_num] != 0xFFFF) { + if (flags & GAME_COMMAND_FLAG_GHOST) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = 0; + return MONEY32_UNDEFINED; + } + + remove_x = (ride->entrances[station_num] & 0xFF) * 32; + remove_y = ((ride->entrances[station_num] >> 8) & 0xFF) * 32; + requires_remove = 1; + } + + if (requires_remove) { + money32 success = game_do_command( + remove_x, + flags, + remove_y, + rideIndex, + GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT, + station_num, + 0 + ); + + if (success == MONEY32_UNDEFINED) { + return MONEY32_UNDEFINED; + } + } + + z = ride->station_heights[station_num] * 8; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, sint16) = z; + + if ( + (flags & GAME_COMMAND_FLAG_APPLY) && + !(flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED) && + !(flags & GAME_COMMAND_FLAG_GHOST) + ) { + footpath_remove_litter(x, y, z); + map_remove_walls_at_z(x, y, z); + } + + if (!gCheatsSandboxMode && !map_is_location_owned(x, y, z)) { + return MONEY32_UNDEFINED; + } + + sint8 clear_z = (z / 8) + (is_exit ? 5 : 7); + RCT2_GLOBAL(0x009E32C4, sint16) = x; + RCT2_GLOBAL(0x009E32C6, sint16) = y; + + // Horrible hack until map_can_construct_with_clear_at is implemented. + RCT2_GLOBAL(0x009E32C8, uint8*) = (&flags) - 4; + + if (!gCheatsDisableClearanceChecks && !map_can_construct_with_clear_at(x, y, z / 8, clear_z, (void*)0x0066637E, 0xF)) { + return MONEY32_UNDEFINED; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) & ELEMENT_IS_UNDERWATER) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_RIDE_CANT_BUILD_THIS_UNDERWATER; + return MONEY32_UNDEFINED; + } + + if (z / 8 > 244){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_HIGH; + return MONEY32_UNDEFINED; + } + + if (flags & GAME_COMMAND_FLAG_APPLY) { + rct_map_element* mapElement = map_element_insert(x / 32, y / 32, z / 8, 0xF); + mapElement->clearance_height = clear_z; + mapElement->properties.entrance.type = is_exit; + mapElement->properties.entrance.index = station_num << 4; + mapElement->properties.entrance.ride_index = rideIndex; + mapElement->type = MAP_ELEMENT_TYPE_ENTRANCE | direction; + + if (flags & GAME_COMMAND_FLAG_GHOST) { + mapElement->flags |= MAP_ELEMENT_FLAG_GHOST; + } + + if (is_exit) { + ride->exits[station_num] = (x / 32) | (y / 32 << 8); + } else { + ride->entrances[station_num] = (x / 32) | (y / 32 << 8); + ride->last_peep_in_queue[station_num] = 0xFFFF; + ride->queue_length[station_num] = 0; + + map_animation_create(MAP_ANIMATION_TYPE_RIDE_ENTRANCE, x, y, z / 8); + } + + sub_6A7594(); + if (!(flags & GAME_COMMAND_FLAG_GHOST)) { + maze_entrance_hedge_removal(x, y, mapElement); + } + footpath_connect_edges(x, y, mapElement, flags); + sub_6A759F(); + + map_invalidate_tile_full(x, y); + } + } + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION * 4; + return RCT2_GLOBAL(0x009E32B8, money32); +} + +/* rct2: 0x006660A8 */ +void game_command_place_ride_entrance_or_exit(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp){ + *ebx = place_ride_entrance_or_exit( + *eax & 0xFFFF, + *ecx & 0xFFFF, + *edx & 0xFF, + (*ebx >> 8) & 0xFF, + *ebx & 0xFF, + *edx & 0xFF, + *edi & 0xFF, + (*edx >> 8) & 0xFF + ); +} + +money32 remove_ride_entrance_or_exit(sint16 x, sint16 y, uint8 rideIndex, uint8 station_num, uint8 flags){ + rct_ride* ride = GET_RIDE(rideIndex); + + if (!(flags & GAME_COMMAND_FLAG_GHOST)){ + if (!(flags & GAME_COMMAND_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 (ride->status != RIDE_STATUS_CLOSED){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_MUST_BE_CLOSED_FIRST; + return MONEY32_UNDEFINED; + } + + if (flags & GAME_COMMAND_FLAG_APPLY){ + ride_clear_for_construction(rideIndex); + ride_remove_peeps(rideIndex); + invalidate_test_results(rideIndex); + + uint8 found = 0; + rct_map_element* 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 != ride->station_heights[station_num]) + continue; + + if (flags & (1 << 5) && !(mapElement->flags & MAP_ELEMENT_FLAG_GHOST)) + continue; + + found = 1; + break; + } while (!map_element_is_last_for_tile(mapElement++)); + + if (!found){ + return MONEY32_UNDEFINED; + } + + sub_6A7594(); + maze_entrance_hedge_replacement(x, y, mapElement); + footpath_remove_edges_at(x, y, mapElement); + + uint8 is_exit = mapElement->properties.entrance.type; + + map_element_remove(mapElement); + + if (is_exit){ + ride->exits[station_num] = 0xFFFF; + } + else{ + ride->entrances[station_num] = 0xFFFF; + } + + sub_6A759F(); + + map_invalidate_tile_full(x, y); + } + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION * 4; + return 0; +} + +/* rct2: 0x0066640B */ +void game_command_remove_ride_entrance_or_exit(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp){ + *ebx = remove_ride_entrance_or_exit( + *eax & 0xFFFF, + *ecx & 0xFFFF, + *edx & 0xFF, + *edi & 0xFF, + *ebx & 0xFF + ); +} + +/** + * + * rct2: 0x006B752C + */ +void ride_crash(int rideIndex, int vehicleIndex) +{ + rct_ride *ride; + rct_vehicle *vehicle; + rct_window *w; + + // TODO Remove these when hook is no longer used + rideIndex &= 0xFF; + vehicleIndex &= 0xFF; + + ride = GET_RIDE(rideIndex); + vehicle = GET_VEHICLE(ride->vehicles[vehicleIndex]); + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO)) { + // Open ride window for crashed vehicle + w = window_ride_open_vehicle(vehicle); + if (w->viewport != NULL) { + w->viewport->flags |= VIEWPORT_FLAG_SOUND_ON; + } + } + + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, rct_string_id) = ride->name; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 2, uint32) = ride->name_arguments; + news_item_add_to_queue(NEWS_ITEM_RIDE, STR_RIDE_HAS_CRASHED, rideIndex); +} + +bool ride_type_is_intamin(int rideType) +{ + return + rideType == RIDE_TYPE_HEARTLINE_TWISTER_COASTER || + rideType == RIDE_TYPE_GIGA_COASTER || + rideType == RIDE_TYPE_INVERTED_IMPULSE_COASTER; +} + +bool shop_item_is_food_or_drink(int shopItem) +{ + switch (shopItem) { + case SHOP_ITEM_DRINK: + case SHOP_ITEM_BURGER: + case SHOP_ITEM_FRIES: + case SHOP_ITEM_ICE_CREAM: + case SHOP_ITEM_COTTON_CANDY: + case SHOP_ITEM_PIZZA: + case SHOP_ITEM_POPCORN: + case SHOP_ITEM_HOT_DOG: + case SHOP_ITEM_TENTACLE: + case SHOP_ITEM_CANDY_APPLE: + case SHOP_ITEM_DONUT: + case SHOP_ITEM_COFFEE: + case SHOP_ITEM_CHICKEN: + case SHOP_ITEM_LEMONADE: + case SHOP_ITEM_PRETZEL: + case SHOP_ITEM_CHOCOLATE: + case SHOP_ITEM_ICED_TEA: + case SHOP_ITEM_FUNNEL_CAKE: + case SHOP_ITEM_BEEF_NOODLES: + case SHOP_ITEM_FRIED_RICE_NOODLES: + case SHOP_ITEM_WONTON_SOUP: + case SHOP_ITEM_MEATBALL_SOUP: + case SHOP_ITEM_FRUIT_JUICE: + case SHOP_ITEM_SOYBEAN_MILK: + case SHOP_ITEM_SU_JONGKWA: + case SHOP_ITEM_SUB_SANDWICH: + case SHOP_ITEM_COOKIE: + case SHOP_ITEM_ROAST_SAUSAGE: + return true; + default: + return false; + } +} + +bool shop_item_is_food(int shopItem) +{ + switch (shopItem) { + case SHOP_ITEM_BURGER: + case SHOP_ITEM_FRIES: + case SHOP_ITEM_ICE_CREAM: + case SHOP_ITEM_COTTON_CANDY: + case SHOP_ITEM_PIZZA: + case SHOP_ITEM_POPCORN: + case SHOP_ITEM_HOT_DOG: + case SHOP_ITEM_TENTACLE: + case SHOP_ITEM_CANDY_APPLE: + case SHOP_ITEM_DONUT: + case SHOP_ITEM_CHICKEN: + case SHOP_ITEM_PRETZEL: + case SHOP_ITEM_FUNNEL_CAKE: + case SHOP_ITEM_BEEF_NOODLES: + case SHOP_ITEM_FRIED_RICE_NOODLES: + case SHOP_ITEM_WONTON_SOUP: + case SHOP_ITEM_MEATBALL_SOUP: + case SHOP_ITEM_SUB_SANDWICH: + case SHOP_ITEM_COOKIE: + case SHOP_ITEM_ROAST_SAUSAGE: + return true; + default: + return false; + } +} + +bool shop_item_is_drink(int shopItem) +{ + switch (shopItem) { + case SHOP_ITEM_DRINK: + case SHOP_ITEM_COFFEE: + case SHOP_ITEM_LEMONADE: + case SHOP_ITEM_CHOCOLATE: + case SHOP_ITEM_ICED_TEA: + case SHOP_ITEM_FRUIT_JUICE: + case SHOP_ITEM_SOYBEAN_MILK: + case SHOP_ITEM_SU_JONGKWA: + return true; + default: + return false; + } +} + +bool shop_item_is_souvenir(int shopItem) +{ + switch (shopItem) { + case SHOP_ITEM_BALLOON: + case SHOP_ITEM_TOY: + case SHOP_ITEM_MAP: + case SHOP_ITEM_PHOTO: + case SHOP_ITEM_UMBRELLA: + case SHOP_ITEM_HAT: + case SHOP_ITEM_TSHIRT: + case SHOP_ITEM_PHOTO2: + case SHOP_ITEM_PHOTO3: + case SHOP_ITEM_PHOTO4: + case SHOP_ITEM_SUNGLASSES: + return true; + default: + return false; + } +} + +void ride_reset_all_names() +{ + int i; + rct_ride *ride; + char rideNameBuffer[256]; + + FOR_ALL_RIDES(i, ride) + { + ride->name = STR_NONE; + + struct { + uint16 type_name; + uint16 number; + } name_args; + name_args.type_name = 2 + ride->type; + name_args.number = 0; + do { + name_args.number++; + format_string(rideNameBuffer, 1, &name_args); + } while (ride_name_exists(rideNameBuffer)); + + ride->name = 1; + ride->name_arguments_type_name = name_args.type_name; + ride->name_arguments_number = name_args.number; + } +} + +const uint8* ride_seek_available_modes(rct_ride *ride) +{ + const uint8* availableModes; + + if(!gCheatsShowAllOperatingModes) { + availableModes = RideAvailableModes; + + for (int i = 0; i < ride->type; i++) { + while (*(availableModes++) != 255) { } + } + } + else + { + availableModes = AllRideModesAvailable; + } + + return availableModes; +} diff --git a/src/ride/ride.h b/src/ride/ride.h index 1916962a35..a54a49b105 100644 --- a/src/ride/ride.h +++ b/src/ride/ride.h @@ -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,6 +21,7 @@ #ifndef _RIDE_H_ #define _RIDE_H_ +#include "../addresses.h" #include "../common.h" #include "../peep/peep.h" #include "../world/map.h" @@ -47,84 +48,65 @@ 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; +typedef struct { + uint8 main; + uint8 additional; + uint8 supports; +} track_colour; + +typedef struct { + uint8 main; + uint8 additional_1; + uint8 additional_2; +} vehicle_colour; + +typedef struct { + uint8 count; + track_colour list[256]; +} track_colour_preset_list; + +typedef struct { + uint8 count; + vehicle_colour list[256]; +} vehicle_colour_preset_list; /** * Ride type structure. * size: unknown */ typedef struct { - 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 + 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_vehicle vehicles[4]; // 0x01A + vehicle_colour_preset_list *vehicle_preset_list; // 0x1AE + sint8 excitement_multipler; // 0x1B2 + sint8 intensity_multipler; // 0x1B3 + sint8 nausea_multipler; // 0x1B4 + uint8 max_height; // 0x1B5 + union { + uint64 enabledTrackPieces; // 0x1B6 + struct { + uint32 enabledTrackPiecesA; // 0x1B6 + uint32 enabledTrackPiecesB; // 0x1BA + }; + }; + uint8 category[2]; // 0x1BE + uint8 shop_item; // 0x1C0 + uint8 shop_item_secondary; // 0x1C1 } rct_ride_type; /** @@ -144,16 +126,22 @@ typedef struct { // 0 = closed, 1 = open, 2 = test uint8 status; // 0x049 rct_string_id name; // 0x04A - uint32 name_arguments; // 0x04C probably just for when a ride hasn't been named (e.g. Crooked House 1) + union { + uint32 name_arguments; // 0x04C + struct { + rct_string_id name_arguments_type_name; // 0x04C + uint16 name_arguments_number; // 0x04E + }; + }; uint16 overall_view; // 0x050 00XX = X, XX00 = Y (* 32 + 16) uint16 station_starts[4]; // 0x052 uint8 station_heights[4]; // 0x05A - uint8 pad_05E[0x4]; + uint8 station_length[4]; // 0x05E uint8 station_depart[4]; // 0x062 uint8 var_066[4]; uint16 entrances[4]; // 0x06A uint16 exits[4]; // 0x072 - uint16 first_peep_in_queue[4]; // 0x07A + uint16 last_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 @@ -162,9 +150,10 @@ typedef struct { uint8 num_stations; // 0x0C7 uint8 num_vehicles; // 0x0C8 uint8 num_cars_per_train; // 0x0C9 - uint8 pad_0CA[0x2]; - uint8 var_0CC; - uint8 var_0CD; + uint8 var_0CA; + uint8 var_0CB; + uint8 max_trains; // 0x0CC + uint8 min_max_cars_per_train; // 0x0CD uint8 min_waiting_time; // 0x0CE uint8 max_waiting_time; // 0x0CF union { @@ -175,7 +164,8 @@ typedef struct { uint8 speed; // 0x0D0 uint8 rotations; // 0x0D0 }; - uint8 pad_0D1[0x3]; + uint8 boat_hire_return_direction; // 0x0D1 + uint16 boat_hire_return_position; // 0x0D2 uint8 measurement_index; // 0x0D4 // bits 0 through 4 are the number of helix sections // bit 5: spinning tunnel, water splash, or rapids @@ -183,7 +173,7 @@ typedef struct { // bit 7: whirlpool uint8 special_track_elements; // 0x0D5 uint8 pad_0D6[2]; - // Divide this value by 29127 to get the human-readable max speed + // 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 @@ -200,9 +190,12 @@ typedef struct { union { uint8 inversions; // 0x114 (???X XXXX) uint8 holes; // 0x114 (???X XXXX) + // The undercover portion is a very rough approximation of how much of the ride is undercover. + // It reaches the maximum value of 7 at about 50% undercover and doesn't increase beyond that. + uint8 undercover_portion; // 0x114 (XXX?-????) }; uint8 drops; // 0x115 (??XX XXXX) - uint8 pad_116; + uint8 var_116; uint8 highest_drop_height; // 0x117 sint32 sheltered_length; // 0x118 uint8 pad_11C[0x2]; @@ -293,7 +286,7 @@ typedef struct { uint32 no_secondary_items_sold; // 0x1A8 uint8 var_1AC; uint8 var_1AD; - uint8 var_1AE; + uint8 last_crash_type; // 0x1AE uint8 connected_message_throttle; // 0x1AF money32 income_per_hour; // 0x1B0 money32 profit; // 0x1B4 @@ -312,7 +305,10 @@ typedef struct { uint16 total_air_time; // 0x1F4 uint8 pad_1F6; uint8 num_circuits; // 0x1F7 - uint8 pad_1F8[6]; + sint16 cable_lift_x; // 0x1F8 + sint16 cable_lift_y; // 0x1FA + uint8 cable_lift_z; // 0x1FC + uint8 pad_1FD; uint16 cable_lift; // 0x1FE uint16 queue_length[4]; // 0x200 uint8 pad_208[0x58]; @@ -338,6 +334,18 @@ typedef struct { uint8 altitude[RIDE_MEASUREMENT_MAX_ITEMS]; // 0x384C } rct_ride_measurement; +typedef struct { + int begin_x; + int begin_y; + int begin_z; + int begin_direction; + rct_map_element *begin_element; + int end_x; + int end_y; + int end_direction; + rct_map_element *end_element; +} track_begin_end; + enum { RIDE_CLASS_RIDE, RIDE_CLASS_SHOP_OR_STALL, @@ -355,7 +363,7 @@ enum { RIDE_LIFECYCLE_BREAKDOWN_PENDING = 1 << 6, RIDE_LIFECYCLE_BROKEN_DOWN = 1 << 7, RIDE_LIFECYCLE_DUE_INSPECTION = 1 << 8, - + RIDE_LIFECYCLE_QUEUE_FULL = 1 << 9, RIDE_LIFECYCLE_CRASHED = 1 << 10, RIDE_LIFECYCLE_11 = 1 << 11, RIDE_LIFECYCLE_EVER_BEEN_OPENED = 1 << 12, @@ -364,18 +372,15 @@ enum { RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK = 1 << 15, RIDE_LIFECYCLE_16 = 1 << 16, RIDE_LIFECYCLE_CABLE_LIFT = 1 << 17, - 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 + RIDE_LIFECYCLE_NOT_CUSTOM_DESIGN = 1 << 18, // Used for the Award for Best Custom-designed Rides + RIDE_LIFECYCLE_SIX_FLAGS_DEPRECATED = 1 << 19 // Not used anymore }; // 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_NO_INVERSIONS = 1 << 1, // 0x2 + RIDE_ENTRY_FLAG_NO_BANKED_TRACK = 1 << 2, // 0x4 RIDE_ENTRY_FLAG_3 = 1 << 3, // 0x8 RIDE_ENTRY_FLAG_4 = 1 << 4, // 0x10 RIDE_ENTRY_FLAG_5 = 1 << 5, // 0x20 @@ -385,12 +390,12 @@ enum { 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_SEPARATE_RIDE_NAME = 1 << 12, // 0x1000 + RIDE_ENTRY_FLAG_SEPARATE_RIDE = 1 << 13, // 0x2000 RIDE_ENTRY_FLAG_14 = 1 << 14, // 0x4000 - RIDE_ENTRY_FLAG_15 = 1 << 15, // 0x8000 + RIDE_ENTRY_DISABLE_LAST_OPERATING_MODE = 1 << 15, // 0x8000 RIDE_ENTRY_FLAG_16 = 1 << 16, // 0x10000 - RIDE_ENTRY_FLAG_17 = 1 << 17, // 0x20000 + RIDE_ENTRY_DISABLE_FIRST_TWO_OPERATING_MODES = 1 << 17, // 0x20000 RIDE_ENTRY_FLAG_18 = 1 << 18, // 0x40000 RIDE_ENTRY_FLAG_19 = 1 << 19, // 0x80000 RIDE_ENTRY_FLAG_20 = 1 << 20, // 0x100000 @@ -572,7 +577,7 @@ enum { MUSIC_STYLE_JUNGLE_DRUMS, MUSIC_STYLE_EGYPTIAN, MUSIC_STYLE_TOYLAND, - MUSIC_STYLE_8, + MUSIC_STYLE_CIRCUS_SHOW, MUSIC_STYLE_SPACE, MUSIC_STYLE_HORROR, MUSIC_STYLE_TECHNO, @@ -653,7 +658,10 @@ enum { RIDE_ENTRANCE_STYLE_ABSTRACT, RIDE_ENTRANCE_STYLE_SNOW_ICE, RIDE_ENTRANCE_STYLE_PAGODA, - RIDE_ENTRANCE_STYLE_SPACE + RIDE_ENTRANCE_STYLE_SPACE, + RIDE_ENTRANCE_STYLE_NONE, + + RIDE_ENTRANCE_STYLE_COUNT }; enum { @@ -676,18 +684,6 @@ enum { RIDE_INVALIDATE_RIDE_MAINTENANCE = 1 << 5, }; -typedef struct { - uint8 main; - uint8 additional; - uint8 supports; -} track_colour; - -typedef struct { - uint8 main; - uint8 additional_1; - uint8 additional_2; -} vehicle_colour; - enum { RIDE_MEASUREMENT_FLAG_RUNNING = 1 << 0, RIDE_MEASUREMENT_FLAG_UNLOADING = 1 << 1, @@ -708,34 +704,112 @@ enum { 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_6 = 1 << 6, // used only by boat ride and submarine ride 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_CANNOT_HAVE_GAPS = 1 << 8, // used by rides that can't have gaps, like those with a vertical tower, such as the observation tower 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_TRACK_ELEMENTS_HAVE_TWO_VARIETIES = 1 << 12, // used by rides with two variaties, like the u and o shapes of the dinghy slide and the dry and submerged track of the water coaster + RIDE_TYPE_FLAG_13 = 1 << 13, // used only by maze, spiral slide and shops 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_FLAT_RIDE = 1 << 19, RIDE_TYPE_FLAG_20 = 1 << 20, - RIDE_TYPE_FLAG_21 = 1 << 21, + RIDE_TYPE_FLAG_PEEP_SHOULD_GO_INSIDE_FACILITY = 1 << 21, // used by toilets and first aid to mark that peep should go inside the building (rather than 'buying' at the counter) 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_FOOD = 1 << 23, 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_29 = 1 << 29, // used only by lift RIDE_TYPE_FLAG_30 = 1 << 30, RIDE_TYPE_FLAG_SUPPORTS_MULTIPLE_TRACK_COLOUR = 1 << 31, }; +enum { + RIDE_CRASH_TYPE_NONE = 0, + RIDE_CRASH_TYPE_NO_FATALITIES = 2, + RIDE_CRASH_TYPE_FATALITIES = 8 +}; + +enum { + RIDE_CONSTRUCTION_STATE_0, + RIDE_CONSTRUCTION_STATE_FRONT, + RIDE_CONSTRUCTION_STATE_BACK, + RIDE_CONSTRUCTION_STATE_SELECTED, + RIDE_CONSTRUCTION_STATE_PLACE, + RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT, + RIDE_CONSTRUCTION_STATE_MAZE_BUILD, + RIDE_CONSTRUCTION_STATE_MAZE_MOVE, + RIDE_CONSTRUCTION_STATE_MAZE_FILL +}; + +enum { + RIDE_SET_VEHICLES_COMMAND_TYPE_NUM_TRAINS, + RIDE_SET_VEHICLES_COMMAND_TYPE_NUM_CARS_PER_TRAIN, + RIDE_SET_VEHICLES_COMMAND_TYPE_RIDE_ENTRY +}; + +enum { + SHOP_ITEM_BALLOON, + SHOP_ITEM_TOY, + SHOP_ITEM_MAP, + SHOP_ITEM_PHOTO, + SHOP_ITEM_UMBRELLA, + SHOP_ITEM_DRINK, + SHOP_ITEM_BURGER, + SHOP_ITEM_FRIES, + SHOP_ITEM_ICE_CREAM, + SHOP_ITEM_COTTON_CANDY, + SHOP_ITEM_EMPTY_CAN, + SHOP_ITEM_RUBBISH, + SHOP_ITEM_EMPTY_BURGER_BOX, + SHOP_ITEM_PIZZA, + SHOP_ITEM_VOUCHER, + SHOP_ITEM_POPCORN, + SHOP_ITEM_HOT_DOG, + SHOP_ITEM_TENTACLE, + SHOP_ITEM_HAT, + SHOP_ITEM_CANDY_APPLE, + SHOP_ITEM_TSHIRT, + SHOP_ITEM_DONUT, + SHOP_ITEM_COFFEE, + SHOP_ITEM_EMPTY_CUP, + SHOP_ITEM_CHICKEN, + SHOP_ITEM_LEMONADE, + SHOP_ITEM_EMPTY_BOX, + SHOP_ITEM_EMPTY_BOTTLE, + SHOP_ITEM_PHOTO2 = 32, + SHOP_ITEM_PHOTO3, + SHOP_ITEM_PHOTO4, + SHOP_ITEM_PRETZEL, + SHOP_ITEM_CHOCOLATE, + SHOP_ITEM_ICED_TEA, + SHOP_ITEM_FUNNEL_CAKE, + SHOP_ITEM_SUNGLASSES, + SHOP_ITEM_BEEF_NOODLES, + SHOP_ITEM_FRIED_RICE_NOODLES, + SHOP_ITEM_WONTON_SOUP, + SHOP_ITEM_MEATBALL_SOUP, + SHOP_ITEM_FRUIT_JUICE, + SHOP_ITEM_SOYBEAN_MILK, + SHOP_ITEM_SU_JONGKWA, + SHOP_ITEM_SUB_SANDWICH, + SHOP_ITEM_COOKIE, + SHOP_ITEM_EMPTY_BOWL_RED, + SHOP_ITEM_EMPTY_DRINK_CARTON, + SHOP_ITEM_EMPTY_JUICE_CUP, + SHOP_ITEM_ROAST_SAUSAGE, + SHOP_ITEM_EMPTY_BOWL_BLUE, + SHOP_ITEM_COUNT = 56 +}; + #define MAX_RIDES 255 #define MAX_RIDE_MEASUREMENTS 8 @@ -746,7 +820,7 @@ enum { #define STATION_DEPART_MASK (~STATION_DEPART_FLAG) // rct2: 0x009ACFA4 -rct_ride_type **gRideTypeList; +extern rct_ride_type **gRideTypeList; // rct2: 0x013628F8 extern rct_ride* g_ride_list; @@ -754,7 +828,7 @@ extern rct_ride* g_ride_list; /** Helper macros until rides are stored in this module. */ #define GET_RIDE(x) (&g_ride_list[x]) #define GET_RIDE_MEASUREMENT(x) (&(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_MEASUREMENTS, rct_ride_measurement)[x])) -#define GET_RIDE_ENTRY(x) RCT2_ADDRESS(RCT2_ADDRESS_RIDE_ENTRIES, rct_ride_type*)[x] +#define GET_RIDE_ENTRY(x) gRideTypeList[x] /** * Helper macro loop for enumerating through all the non null rides. @@ -765,6 +839,50 @@ extern rct_ride* g_ride_list; extern const uint8 gRideClassifications[255]; + +// Macros for very commonly used varaibles, eventually will be changed to locals or globals +#define _enabledRidePieces RCT2_GLOBAL(0x00F44048, uint64) +#define _enabledRidePiecesA RCT2_GLOBAL(0x00F44048, uint32) +#define _enabledRidePiecesB RCT2_GLOBAL(0x00F4404C, uint32) + +#define _currentTrackPrice RCT2_GLOBAL(0x00F44070, money32) + +#define _numCurrentPossibleRideConfigurations RCT2_GLOBAL(0x00F44078, uint16) +#define _numCurrentPossibleSpecialTrackPieces RCT2_GLOBAL(0x00F4407A, uint16) + +#define _currentTrackCurve RCT2_GLOBAL(0x00F440A0, uint16) +#define _currentTrackEndX RCT2_GLOBAL(0x00F440A2, uint16) +#define _currentTrackEndY RCT2_GLOBAL(0x00F440A4, uint16) +#define _rideConstructionState RCT2_GLOBAL(0x00F440A6, uint8) +#define _currentRideIndex RCT2_GLOBAL(0x00F440A7, uint8) +#define _currentTrackBeginX RCT2_GLOBAL(0x00F440A8, uint16) +#define _currentTrackBeginY RCT2_GLOBAL(0x00F440AA, uint16) +#define _currentTrackBeginZ RCT2_GLOBAL(0x00F440AC, uint16) +#define _currentTrackPieceDirection RCT2_GLOBAL(0x00F440AE, uint8) +#define _currentTrackPieceType RCT2_GLOBAL(0x00F440AF, uint8) +#define _currentTrackSelectionFlags RCT2_GLOBAL(0x00F440B0, uint8) +#define _rideConstructionArrowPulseTime RCT2_GLOBAL(0x00F440B1, sint8) +#define _currentTrackSlopeEnd RCT2_GLOBAL(0x00F440B2, uint8) +#define _currentTrackBankEnd RCT2_GLOBAL(0x00F440B3, uint8) +#define _currentTrackLiftHill RCT2_GLOBAL(0x00F440B4, uint8) +#define _currentTrackCovered RCT2_GLOBAL(0x00F440B5, uint8) + +#define _previousTrackBankEnd RCT2_GLOBAL(0x00F440B6, uint8) +#define _previousTrackSlopeEnd RCT2_GLOBAL(0x00F440B7, uint8) + +#define _previousTrackPieceX RCT2_GLOBAL(0x00F440B9, uint16) +#define _previousTrackPieceY RCT2_GLOBAL(0x00F440BB, uint16) +#define _previousTrackPieceZ RCT2_GLOBAL(0x00F440BD, uint16) + +#define _currentSeatRotationAngle RCT2_GLOBAL(0x00F440CF, uint8) + +extern bool gGotoStartPlacementMode; +extern int gRideRemoveTrackPieceCallbackX; +extern int gRideRemoveTrackPieceCallbackY; +extern int gRideRemoveTrackPieceCallbackZ; +extern int gRideRemoveTrackPieceCallbackDirection; +extern int gRideRemoveTrackPieceCallbackType; + int ride_get_count(); int ride_get_total_queue_length(rct_ride *ride); int ride_get_max_queue_time(rct_ride *ride); @@ -775,8 +893,11 @@ void ride_update_all(); void ride_check_all_reachable(); void ride_update_satisfaction(rct_ride* ride, uint8 happiness); void ride_update_popularity(rct_ride* ride, uint8 pop_amount); +money32 get_shop_item_cost(int shopItem); +money16 get_shop_base_value(int shopItem); +money16 get_shop_hot_value(int shopItem); +money16 get_shop_cold_value(int shopItem); 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); void ride_construct(int rideIndex); @@ -811,10 +932,20 @@ 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_create_ride(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_callback_ride_construct_new(int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp); +void game_command_callback_ride_construct_placed_front(int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp); +void game_command_callback_ride_construct_placed_back(int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp); +void game_command_callback_ride_remove_track_piece(int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp); 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); +void ride_clear_for_construction(int rideIndex); +void set_vehicle_type_image_max_sizes(rct_ride_type_vehicle* vehicle_type, int num_images); +void invalidate_test_results(int rideIndex); +void ride_select_next_section(); +void ride_select_previous_section(); int get_var_10E_unk_1(rct_ride* ride); int get_var_10E_unk_2(rct_ride* ride); @@ -837,7 +968,55 @@ 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_is_block_sectioned(rct_ride *ride); bool ride_has_any_track_elements(int rideIndex); void ride_all_has_any_track_elements(bool *rideIndexArray); +void ride_construction_set_default_next_piece(); + +bool track_block_get_next(rct_xy_element *input, rct_xy_element *output, int *z, int *direction); +bool track_block_get_next_from_zero(sint16 x, sint16 y, sint16 z_start, uint8 rideIndex, uint8 direction_start, rct_xy_element *output, int *z, int *direction); + +bool track_block_get_previous(int x, int y, rct_map_element *mapElement, track_begin_end *outTrackBeginEnd); +bool track_block_get_previous_from_zero(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8 direction, track_begin_end *outTrackBeginEnd); + +void sub_6C84CE(); +void sub_6C96C0(); +money32 ride_get_entrance_or_exit_price(int rideIndex, int x, int y, int direction, int dh, int di); +void ride_get_entrance_or_exit_position_from_screen_position(int x, int y, int *outX, int *outY, int *outDirection); + +bool ride_select_backwards_from_front(); +bool ride_select_forwards_from_back(); + +money32 ride_remove_track_piece(int x, int y, int z, int direction, int type); + +bool ride_are_all_possible_entrances_and_exits_built(rct_ride *ride); +void ride_fix_breakdown(int rideIndex, int reliabilityIncreaseFactor); + +void ride_entry_get_train_layout(int rideEntryIndex, int numCarsPerTrain, uint8 *trainLayout); +void ride_update_max_vehicles(int rideIndex); + +void ride_set_ride_entry(int rideIndex, int rideEntry); +void ride_set_num_vehicles(int rideIndex, int numVehicles); +void ride_set_num_cars_per_vehicle(int rideIndex, int numCarsPerVehicle); +void game_command_set_ride_vehicles(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); + +void game_command_place_ride_entrance_or_exit(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_remove_ride_entrance_or_exit(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); + +void sub_6CB945(int rideIndex); +void ride_crash(int rideIndex, int vehicleIndex); + +bool ride_type_is_intamin(int rideType); +void sub_6C94D8(); + +bool shop_item_is_food_or_drink(int shopItem); +bool shop_item_is_food(int shopItem); +bool shop_item_is_drink(int shopItem); +bool shop_item_is_souvenir(int shopItem); +void ride_reset_all_names(); +const uint8* ride_seek_available_modes(rct_ride *ride); + +void window_ride_construction_mouseup_demolish_next_piece(int x, int y, int z, int direction, int type); + #endif diff --git a/src/ride/ride_data.c b/src/ride/ride_data.c index 593eaac1c8..c7cc940212 100644 --- a/src/ride/ride_data.c +++ b/src/ride/ride_data.c @@ -4,10 +4,11 @@ * * Data source is 0x0097E3AC * - * Generating function is here + * Generating function is here * https://gist.github.com/kevinburke/eaeb1d8149a6eef0dcc1 */ +#include "../localisation/localisation.h" #include "ride.h" #include "ride_data.h" @@ -20,7 +21,7 @@ const bool hasRunningTrack[0x60] = { true, // 5 Mini Railroad true, // 6 Monorail true, // 7 Mini Suspended Coaster - false, // 8 Bumper Boats + false, // 8 Boat Ride true, // 9 Wooden Wild Mine/Mouse true, // a Steeplechase/Motorbike/Soap Box Derby true, // b Car Ride @@ -52,7 +53,7 @@ const bool hasRunningTrack[0x60] = { false, // 25 Ferris Wheel false, // 26 Motion Simulator false, // 27 3D Cinema - false, // 28 Gravitron + false, // 28 Topspin false, // 29 Space Rings true, // 2a Reverse Freefall Coaster true, // 2b Elevator @@ -120,7 +121,7 @@ const uint8 initialUpkeepCosts[0x60] = { 60, // 05 Mini Railroad 65, // 06 Monorail 40, // 07 Mini Suspended Coaster - 50, // 08 Bumper Boats + 50, // 08 Boat Ride 40, // 09 Wooden Wild Mine/Mouse 40, // 0a Steeplechase/Motorbike/Soap Box Derby 70, // 0b Car Ride @@ -152,7 +153,7 @@ const uint8 initialUpkeepCosts[0x60] = { 50, // 25 Ferris Wheel 50, // 26 Motion Simulator 50, // 27 3D Cinema - 50, // 28 Gravitron + 50, // 28 Topspin 50, // 29 Space Rings 80, // 2a Reverse Freefall Coaster 50, // 2b Elevator @@ -213,7 +214,7 @@ const uint8 costPerTrackPiece[0x60] = { 0, // 05 Mini Railroad 0, // 06 Monorail 80, // 07 Mini Suspended Coaster - 0, // 08 Bumper Boats + 0, // 08 Boat Ride 80, // 09 Wooden Wild Mine/Mouse 80, // 0a Steeplechase/Motorbike/Soap Box Derby 0, // 0b Car Ride @@ -245,7 +246,7 @@ const uint8 costPerTrackPiece[0x60] = { 0, // 25 Ferris Wheel 0, // 26 Motion Simulator 0, // 27 3D Cinema - 0, // 28 Gravitron + 0, // 28 Topspin 0, // 29 Space Rings 0, // 2a Reverse Freefall Coaster 0, // 2b Elevator @@ -309,7 +310,7 @@ const uint8 rideUnknownData1[0x60] = { 10, // 05 Mini Railroad 10, // 06 Monorail 10, // 07 Mini Suspended Coaster - 4, // 08 Bumper Boats + 4, // 08 Boat Ride 9, // 09 Wooden Wild Mine/Mouse 10, // 0a Steeplechase/Motorbike/Soap Box Derby 8, // 0b Car Ride @@ -341,7 +342,7 @@ const uint8 rideUnknownData1[0x60] = { 0, // 25 Ferris Wheel 0, // 26 Motion Simulator 0, // 27 3D Cinema - 0, // 28 Gravitron + 0, // 28 Topspin 0, // 29 Space Rings 0, // 2a Reverse Freefall Coaster 10, // 2b Elevator @@ -406,7 +407,7 @@ const bool rideUnknownData2[0x60] = { true, // 05 Mini Railroad true, // 06 Monorail true, // 07 Mini Suspended Coaster - false, // 08 Bumper Boats + false, // 08 Boat Ride true, // 09 Wooden Wild Mine/Mouse true, // 0a Steeplechase/Motorbike/Soap Box Derby true, // 0b Car Ride @@ -438,7 +439,7 @@ const bool rideUnknownData2[0x60] = { false, // 25 Ferris Wheel false, // 26 Motion Simulator false, // 27 3D Cinema - false, // 28 Gravitron + false, // 28 Topspin false, // 29 Space Rings false, // 2a Reverse Freefall Coaster false, // 2b Elevator @@ -500,7 +501,7 @@ const uint8 rideUnknownData3[0x60] = { 5, // 05 Mini Railroad 10, // 06 Monorail 10, // 07 Mini Suspended Coaster - 0, // 08 Bumper Boats + 0, // 08 Boat Ride 10, // 09 Wooden Wild Mine/Mouse 10, // 0a Steeplechase/Motorbike/Soap Box Derby 5, // 0b Car Ride @@ -532,7 +533,7 @@ const uint8 rideUnknownData3[0x60] = { 0, // 25 Ferris Wheel 0, // 26 Motion Simulator 0, // 27 3D Cinema - 0, // 28 Gravitron + 0, // 28 Topspin 0, // 29 Space Rings 10, // 2a Reverse Freefall Coaster 0, // 2b Elevator @@ -593,7 +594,7 @@ const rct_ride_name_convention RideNameConvention[96] = { { 1229, 1243, 1257, 0 }, // 05 Mini Railroad { 1229, 1243, 1257, 0 }, // 06 Monorail { 1264, 1243, 1257, 0 }, // 07 Mini Suspended Coaster - { 1236, 1250, 1250, 0 }, // 08 Bumper Boats + { 1236, 1250, 1250, 0 }, // 08 Boat Ride { 1264, 1243, 1257, 0 }, // 09 Wooden Wild Mine/Mouse { 1264, 1243, 1257, 0 }, // 0a Steeplechase/Motorbike/Soap Box Derby { 1264, 1243, 1257, 0 }, // 0b Car Ride @@ -625,7 +626,7 @@ const rct_ride_name_convention RideNameConvention[96] = { { 1299, 1278, 1257, 0 }, // 25 Ferris Wheel { 1264, 1278, 1257, 0 }, // 26 Motion Simulator { 1271, 1278, 1257, 0 }, // 27 3D Cinema - { 1264, 1278, 1257, 0 }, // 28 Gravitron + { 1264, 1278, 1257, 0 }, // 28 Topspin { 1306, 1278, 1257, 0 }, // 29 Space Rings { 1264, 1243, 1257, 0 }, // 2a Reverse Freefall Coaster { 1292, 1243, 1257, 0 }, // 2b Elevator @@ -684,11 +685,11 @@ const uint8 RideAvailableModes[] = { RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 01 Stand Up Coaster RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 02 Suspended Swinging RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 03 Inverted - RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 04 Steel Mini Coaster + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE, 0xFF, // 04 Steel Mini Coaster RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_SHUTTLE, 0xFF, // 05 Mini Railroad RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_SHUTTLE, 0xFF, // 06 Monorail RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 07 Mini Suspended Coaster - RIDE_MODE_BOAT_HIRE, 0xFF, // 08 Bumper Boats + RIDE_MODE_BOAT_HIRE, 0xFF, // 08 Boat Ride RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 09 Wooden Wild Mine/Mouse RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 0A Steeplechase/Motorbike/Soap Box Derby RIDE_MODE_CONTINUOUS_CIRCUIT, 0xFF, // 0B Car Ride @@ -720,7 +721,7 @@ const uint8 RideAvailableModes[] = { RIDE_MODE_FORWARD_ROTATION, RIDE_MODE_BACKWARD_ROTATION, 0xFF, // 25 Ferris Wheel RIDE_MODE_FILM_AVENGING_AVIATORS, RIDE_MODE_FILM_THRILL_RIDERS, 0xFF, // 26 Motion Simulator RIDE_MODE_3D_FILM_MOUSE_TAILS, RIDE_MODE_3D_FILM_STORM_CHASERS, RIDE_MODE_3D_FILM_SPACE_RAIDERS, 0xFF, // 27 3D Cinema - RIDE_MODE_BEGINNERS, RIDE_MODE_INTENSE, RIDE_MODE_BERSERK, 0xFF, // 28 Gravitron + RIDE_MODE_BEGINNERS, RIDE_MODE_INTENSE, RIDE_MODE_BERSERK, 0xFF, // 28 Topspin RIDE_MODE_SPACE_RINGS, 0xFF, // 29 Space Rings RIDE_MODE_LIM_POWERED_LAUNCH, 0xFF, // 2A Reverse Freefall Coaster RIDE_MODE_SHUTTLE, 0xFF, // 2B Elevator @@ -769,8 +770,12 @@ const uint8 RideAvailableModes[] = { 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_PASSTROUGH, RIDE_MODE_POWERED_LAUNCH, RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED, 0xFF // 60 (none) + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, 0xFF, // 59 Unknown + RIDE_MODE_POWERED_LAUNCH_PASSTROUGH, RIDE_MODE_POWERED_LAUNCH, RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED, 0xFF // 60 LIM Launched Roller Coaster +}; + +const uint8 AllRideModesAvailable[] = { + RIDE_MODE_CONTINUOUS_CIRCUIT, RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED, RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE, RIDE_MODE_POWERED_LAUNCH_PASSTROUGH, RIDE_MODE_SHUTTLE, RIDE_MODE_NORMAL, RIDE_MODE_BOAT_HIRE, RIDE_MODE_UPWARD_LAUNCH, RIDE_MODE_ROTATING_LIFT, RIDE_MODE_STATION_TO_STATION, RIDE_MODE_SINGLE_RIDE_PER_ADMISSION, RIDE_MODE_UNLIMITED_RIDES_PER_ADMISSION, RIDE_MODE_MAZE, RIDE_MODE_RACE, RIDE_MODE_BUMPERCAR, RIDE_MODE_SWING, RIDE_MODE_SHOP_STALL, RIDE_MODE_ROTATION, RIDE_MODE_FORWARD_ROTATION, RIDE_MODE_BACKWARD_ROTATION, RIDE_MODE_FILM_AVENGING_AVIATORS, RIDE_MODE_3D_FILM_MOUSE_TAILS, RIDE_MODE_SPACE_RINGS, RIDE_MODE_BEGINNERS, RIDE_MODE_LIM_POWERED_LAUNCH, RIDE_MODE_FILM_THRILL_RIDERS, RIDE_MODE_3D_FILM_STORM_CHASERS, RIDE_MODE_3D_FILM_SPACE_RAIDERS, RIDE_MODE_INTENSE, RIDE_MODE_BERSERK, RIDE_MODE_HAUNTED_HOUSE, RIDE_MODE_CIRCUS_SHOW, RIDE_MODE_DOWNWARD_LAUNCH, RIDE_MODE_CROOKED_HOUSE, RIDE_MODE_FREEFALL_DROP, RIDE_MODE_POWERED_LAUNCH, RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED, 0xFF }; const uint8 RideAvailableBreakdowns[] = { @@ -782,7 +787,7 @@ const uint8 RideAvailableBreakdowns[] = { (1 << BREAKDOWN_SAFETY_CUT_OUT) | (1 << BREAKDOWN_VEHICLE_MALFUNCTION), // 05 Mini Railroad (1 << BREAKDOWN_SAFETY_CUT_OUT) | (1 << BREAKDOWN_DOORS_STUCK_CLOSED) | (1 << BREAKDOWN_DOORS_STUCK_OPEN) | (1 << BREAKDOWN_VEHICLE_MALFUNCTION), // 06 Monorail (1 << BREAKDOWN_SAFETY_CUT_OUT) | (1 << BREAKDOWN_RESTRAINTS_STUCK_CLOSED) | (1 << BREAKDOWN_RESTRAINTS_STUCK_OPEN) | (1 << BREAKDOWN_VEHICLE_MALFUNCTION) | (1 << BREAKDOWN_BRAKES_FAILURE), // 07 Mini Suspended Coaster - (1 << BREAKDOWN_VEHICLE_MALFUNCTION), // 08 Bumper Boats + (1 << BREAKDOWN_VEHICLE_MALFUNCTION), // 08 Boat Ride (1 << BREAKDOWN_SAFETY_CUT_OUT) | (1 << BREAKDOWN_VEHICLE_MALFUNCTION) | (1 << BREAKDOWN_BRAKES_FAILURE), // 09 Wooden Wild Mine/Mouse (1 << BREAKDOWN_SAFETY_CUT_OUT) | (1 << BREAKDOWN_VEHICLE_MALFUNCTION) | (1 << BREAKDOWN_BRAKES_FAILURE), // 0A Steeplechase/Motorbike/Soap Box Derby (1 << BREAKDOWN_SAFETY_CUT_OUT) | (1 << BREAKDOWN_VEHICLE_MALFUNCTION), // 0B Car Ride @@ -814,7 +819,7 @@ const uint8 RideAvailableBreakdowns[] = { (1 << BREAKDOWN_SAFETY_CUT_OUT), // 25 Ferris Wheel (1 << BREAKDOWN_SAFETY_CUT_OUT), // 26 Motion Simulator (1 << BREAKDOWN_SAFETY_CUT_OUT), // 27 3D Cinema - (1 << BREAKDOWN_SAFETY_CUT_OUT), // 28 Gravitron + (1 << BREAKDOWN_SAFETY_CUT_OUT), // 28 Topspin (1 << BREAKDOWN_SAFETY_CUT_OUT), // 29 Space Rings (1 << BREAKDOWN_SAFETY_CUT_OUT) | (1 << BREAKDOWN_RESTRAINTS_STUCK_CLOSED) | (1 << BREAKDOWN_RESTRAINTS_STUCK_OPEN) | (1 << BREAKDOWN_VEHICLE_MALFUNCTION), // 2A Reverse Freefall Coaster (1 << BREAKDOWN_SAFETY_CUT_OUT) | (1 << BREAKDOWN_DOORS_STUCK_CLOSED) | (1 << BREAKDOWN_DOORS_STUCK_OPEN), // 2B Elevator @@ -863,115 +868,431 @@ const uint8 RideAvailableBreakdowns[] = { (1 << BREAKDOWN_SAFETY_CUT_OUT) | (1 << BREAKDOWN_RESTRAINTS_STUCK_CLOSED) | (1 << BREAKDOWN_RESTRAINTS_STUCK_OPEN) | (1 << BREAKDOWN_VEHICLE_MALFUNCTION), // 56 Inverted Impulse Coaster (1 << BREAKDOWN_SAFETY_CUT_OUT) | (1 << BREAKDOWN_RESTRAINTS_STUCK_CLOSED) | (1 << BREAKDOWN_RESTRAINTS_STUCK_OPEN) | (1 << BREAKDOWN_VEHICLE_MALFUNCTION) | (1 << BREAKDOWN_BRAKES_FAILURE), // 57 Mini Roller Coaster (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) + (1 << BREAKDOWN_SAFETY_CUT_OUT) | (1 << BREAKDOWN_RESTRAINTS_STUCK_CLOSED) | (1 << BREAKDOWN_RESTRAINTS_STUCK_OPEN) | (1 << BREAKDOWN_VEHICLE_MALFUNCTION) | (1 << BREAKDOWN_BRAKES_FAILURE), // 59 Unknown + (1 << BREAKDOWN_SAFETY_CUT_OUT) | (1 << BREAKDOWN_RESTRAINTS_STUCK_CLOSED) | (1 << BREAKDOWN_RESTRAINTS_STUCK_OPEN) | (1 << BREAKDOWN_VEHICLE_MALFUNCTION) | (1 << BREAKDOWN_BRAKES_FAILURE) // 60 LIM Launched Roller Coaster }; -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 +// rct2: 0x00993E7C and 0x00993E1C +const rct_ride_entrance_definition RideEntranceDefinitions[RIDE_ENTRANCE_STYLE_COUNT] = { + { 22664, 32, 2, STR_PLAIN_ENTRANCE, 0x00000000, 0, }, // RIDE_ENTRANCE_STYLE_PLAIN + { 22760, 31, 21, STR_WOODEN_ENTRANCE, 0x000057A1, 0, }, // RIDE_ENTRANCE_STYLE_WOODEN + { 22680, 43, 2, STR_CANVAS_TENT_ENTRANCE, 0x800057AD, 3, }, // RIDE_ENTRANCE_STYLE_CANVAS_TENT + { 22728, 43, 19, STR_CASTLE_ENTRANCE_GREY, 0x000057B9, 0, }, // RIDE_ENTRANCE_STYLE_CASTLE_GREY + { 22712, 43, 19, STR_CASTLE_ENTRANCE_BROWN, 0x000057C5, 0, }, // RIDE_ENTRANCE_STYLE_CASTLE_BROWN + { 22776, 33, 19, STR_JUNGLE_ENTRANCE, 0x000057D1, 0, }, // RIDE_ENTRANCE_STYLE_JUNGLE + { 22744, 32, 20, STR_LOG_CABIN_ENTRANCE, 0x000057DD, 0, }, // RIDE_ENTRANCE_STYLE_LOG_CABIN + { 22696, 34, 19, STR_CLASSICAL_ROMAN_ENTRANCE, 0x000057E9, 0, }, // RIDE_ENTRANCE_STYLE_CLASSICAL_ROMAN + { 22792, 40, 22, STR_ABSTRACT_ENTRANCE, 0x400057F5, 1, }, // RIDE_ENTRANCE_STYLE_ABSTRACT + { 22824, 35, 23, STR_SNOW_ICE_ENTRANCE, 0x0000580D, 0, }, // RIDE_ENTRANCE_STYLE_SNOW_ICE + { 22840, 33, 19, STR_PAGODA_ENTRANCE, 0x00005819, 0, }, // RIDE_ENTRANCE_STYLE_PAGODA + { 22856, 33, 2, STR_SPACE_ENTRANCE, 0x00005825, 0, }, // RIDE_ENTRANCE_STYLE_SPACE + { 0, 0, 2, STR_ENTRANCE_NONE, 0x00000000, 0, } // RIDE_ENTRANCE_STYLE_NONE }; // 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 + 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, // Boat Ride + 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, // Topspin + 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 +}; + +// rct2: 0x0097D4F2 +const rct_ride_data_4 RideData4[91] = { + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK_STYLE_3, 0, 0, 0, 20, 20 }, // RIDE_TYPE_SPIRAL_ROLLER_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_TECHNO, 0, 0, 0, 20, 20 }, // RIDE_TYPE_STAND_UP_ROLLER_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 20, 20 }, // RIDE_TYPE_SUSPENDED_SWINGING_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_TECHNO, 0, 0, 0, 20, 20 }, // RIDE_TYPE_INVERTED_ROLLER_COASTER + { RIDE_TYPE_FLAG4_0 | RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_SUMMER, 0, 0, 0, 10, 0 }, // RIDE_TYPE_JUNIOR_ROLLER_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_6 | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_TRANSPORT_RIDE, MUSIC_STYLE_SUMMER, 0, 0, 0, 10, 0 }, // RIDE_TYPE_MINIATURE_RAILWAY + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_6 | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_TRANSPORT_RIDE, MUSIC_STYLE_SUMMER, 0, 0, 0, 20, 20 }, // RIDE_TYPE_MONORAIL + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_WILD_WEST, 0, 0, 0, 10, 0 }, // RIDE_TYPE_MINI_SUSPENDED_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT, MUSIC_STYLE_WATER, 0, 0, 0, 20, 20 }, // RIDE_TYPE_BOAT_RIDE + { RIDE_TYPE_FLAG4_0 | RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_WILD_WEST, 0, 0, 0, 20, 20 }, // RIDE_TYPE_WOODEN_WILD_MOUSE + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 15, 0 }, // RIDE_TYPE_STEEPLECHASE + { RIDE_TYPE_FLAG4_0 | RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_6 | RIDE_TYPE_FLAG4_14, MUSIC_STYLE_SUMMER, 0, 0, 0, 20, 0 }, // RIDE_TYPE_CAR_RIDE + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_TECHNO, 0, 0, 0, 20, 20 }, // RIDE_TYPE_LAUNCHED_FREEFALL + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 10, 0 }, // RIDE_TYPE_BOBSLEIGH_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_14, MUSIC_STYLE_SUMMER, 0, 0, 0, 20, 20 }, // RIDE_TYPE_OBSERVATION_TOWER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 20, 20 }, // RIDE_TYPE_LOOPING_ROLLER_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_WATER, 0, 0, 0, 20, 20 }, // RIDE_TYPE_DINGHY_SLIDE + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_WILD_WEST, 0, 0, 0, 10, 0 }, // RIDE_TYPE_MINE_TRAIN_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_6 | RIDE_TYPE_FLAG4_TRANSPORT_RIDE | RIDE_TYPE_FLAG4_14, MUSIC_STYLE_SUMMER, 0, 0, 0, 20, 20 }, // RIDE_TYPE_CHAIRLIFT + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 10, 0 }, // RIDE_TYPE_CORKSCREW_ROLLER_COASTER + { RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT, MUSIC_STYLE_SUMMER, 0, 0, 0, 15, 0 }, // RIDE_TYPE_MAZE + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_SUMMER, 0, 0, 0, 20, 0 }, // RIDE_TYPE_SPIRAL_SLIDE + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_TECHNO, 0, 0, 0, 20, 20 }, // RIDE_TYPE_GO_KARTS + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_6 | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_WATER, 0, 0, 0, 20, 20 }, // RIDE_TYPE_LOG_FLUME + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_6 | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_WATER, 0, 0, 0, 15, 0 }, // RIDE_TYPE_RIVER_RAPIDS + { RIDE_TYPE_FLAG4_MUSIC_ON_DEFAULT | RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_14, MUSIC_STYLE_DODGEMS_BEAT, 0, 0, 0, 15, 0 }, // RIDE_TYPE_DODGEMS + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_PIRATES, 0, 0, 0, 15, 0 }, // RIDE_TYPE_PIRATE_SHIP + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_TECHNO, 0, 0, 0, 9, 0 }, // RIDE_TYPE_SWINGING_INVERTER_SHIP + { 0, MUSIC_STYLE_GENTLE, 0, 0, 0, 15, 0 }, // RIDE_TYPE_FOOD_STALL + { 0, MUSIC_STYLE_GENTLE, 0, 0, 0, 12, 0 }, // RIDE_TYPE_1D + { 0, MUSIC_STYLE_GENTLE, 0, 0, 0, 8, 0 }, // RIDE_TYPE_DRINK_STALL + { 0, MUSIC_STYLE_GENTLE, 0, 0, 0, 15, 0 }, // RIDE_TYPE_1F + { 0, MUSIC_STYLE_GENTLE, 0, 0, 0, 10, 0 }, // RIDE_TYPE_SHOP + { RIDE_TYPE_FLAG4_MUSIC_ON_DEFAULT | RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_FAIRGROUND_ORGAN, 0, 0, 0, 9, 0 }, // RIDE_TYPE_MERRY_GO_ROUND + { 0, MUSIC_STYLE_GENTLE, 0, 0, 0, 6, 25 }, // RIDE_TYPE_22 + { 0, MUSIC_STYLE_GENTLE, 0, 0, 0, 0, 0 }, // RIDE_TYPE_INFORMATION_KIOSK + { 0, MUSIC_STYLE_GENTLE, 0, 0, 0, 10, 0 }, // RIDE_TYPE_TOILETS + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION | RIDE_TYPE_FLAG4_14, MUSIC_STYLE_SUMMER, 0, 0, 0, 20, 0 }, // RIDE_TYPE_FERRIS_WHEEL + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION | RIDE_TYPE_FLAG4_14, MUSIC_STYLE_ROCK, 0, 0, 0, 20, 0 }, // RIDE_TYPE_MOTION_SIMULATOR + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION, MUSIC_STYLE_ROCK, 0, 0, 0, 20, 0 }, // RIDE_TYPE_3D_CINEMA + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 5, 0 }, // RIDE_TYPE_TOP_SPIN + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION | RIDE_TYPE_FLAG4_14, MUSIC_STYLE_GENTLE, 0, 0, 0, 20, 0 }, // RIDE_TYPE_SPACE_RINGS + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 10, 0 }, // RIDE_TYPE_REVERSE_FREEFALL_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_TRANSPORT_RIDE, MUSIC_STYLE_SUMMER, 0, 0, 0, 20, 20 }, // RIDE_TYPE_LIFT + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 0, 0 }, // RIDE_TYPE_VERTICAL_DROP_ROLLER_COASTER + { 0, MUSIC_STYLE_GENTLE, 0, 0, 0, 10, 0 }, // RIDE_TYPE_CASH_MACHINE + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_GENTLE, 0, 0, 0, 10, 0 }, // RIDE_TYPE_TWIST + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION, MUSIC_STYLE_HORROR, 0, 0, 0, 0, 0 }, // RIDE_TYPE_HAUNTED_HOUSE + { 0, MUSIC_STYLE_GENTLE, 0, 0, 0, 15, 0 }, // RIDE_TYPE_FIRST_AID + { RIDE_TYPE_FLAG4_MUSIC_ON_DEFAULT | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION, MUSIC_STYLE_CIRCUS_SHOW, 0, 0, 0, 15, 0 }, // RIDE_TYPE_CIRCUS_SHOW + { RIDE_TYPE_FLAG4_0 | RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_6 | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_HORROR, 0, 0, 0, 20, 20 }, // RIDE_TYPE_GHOST_TRAIN + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 20, 20 }, // RIDE_TYPE_TWISTER_ROLLER_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_WILD_WEST, 0, 0, 0, 20, 20 }, // RIDE_TYPE_WOODEN_ROLLER_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_GENTLE, 0, 0, 0, 20, 20 }, // RIDE_TYPE_SIDE_FRICTION_ROLLER_COASTER + { RIDE_TYPE_FLAG4_0 | RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 20, 20 }, // RIDE_TYPE_WILD_MOUSE + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | (1 << 3) | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK_STYLE_3, 56, 0, 0, 20, 20 }, // RIDE_TYPE_MULTI_DIMENSION_ROLLER_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_GENTLE, 0, 0, 0, 20, 20 }, // RIDE_TYPE_38 + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | (1 << 3) | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13 | RIDE_TYPE_FLAG4_15, MUSIC_STYLE_ROCK, 58, 0, 0, 20, 20 }, // RIDE_TYPE_FLYING_ROLLER_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_13 | (1 << 15), MUSIC_STYLE_GENTLE, 0, 0, 0, 20, 20 }, // RIDE_TYPE_3A + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 20, 20 }, // RIDE_TYPE_VIRGINIA_REEL + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_6 | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_14, MUSIC_STYLE_WATER, 0, 0, 0, 15, 0 }, // RIDE_TYPE_SPLASH_BOATS + { RIDE_TYPE_FLAG4_0 | RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_6 | RIDE_TYPE_FLAG4_14, MUSIC_STYLE_SUMMER, 0, 0, 0, 20, 20 }, // RIDE_TYPE_MINI_HELICOPTERS + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | (1 << 3) | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 64, 0, 0, 10, 0 }, // RIDE_TYPE_LAY_DOWN_ROLLER_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_6 | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_TRANSPORT_RIDE, MUSIC_STYLE_SUMMER, 0, 0, 0, 20, 20 }, // RIDE_TYPE_SUSPENDED_MONORAIL + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_GENTLE, 0, 0, 0, 20, 20 }, // RIDE_TYPE_40 + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_TECHNO, 0, 0, 0, 15, 20 }, // RIDE_TYPE_REVERSER_ROLLER_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_TECHNO, 0, 0, 0, 10, 0 }, // RIDE_TYPE_HEARTLINE_TWISTER_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_14, MUSIC_STYLE_SUMMER, 0, 0, 0, 20, 20 }, // RIDE_TYPE_MINI_GOLF + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_10 | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK_STYLE_3, 0, 0, 0, 20, 0 }, // RIDE_TYPE_GIGA_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 15, 0 }, // RIDE_TYPE_ROTO_DROP + { RIDE_TYPE_FLAG4_MUSIC_ON_DEFAULT | RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 10, 0 }, // RIDE_TYPE_FLYING_SAUCERS + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION, MUSIC_STYLE_GENTLE, 0, 0, 0, 15, 0 }, // RIDE_TYPE_CROOKED_HOUSE + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_14, MUSIC_STYLE_SUMMER, 0, 0, 0, 20, 20 }, // RIDE_TYPE_MONORAIL_CYCLES + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_TECHNO, 0, 0, 0, 20, 20 }, // RIDE_TYPE_COMPACT_INVERTED_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_WATER, 0, 0, 0, 20, 0 }, // RIDE_TYPE_WATER_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK_STYLE_2, 0, 0, 0, 20, 20 }, // RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK_STYLE_2, 0, 0, 0, 15, 0 }, // RIDE_TYPE_INVERTED_HAIRPIN_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_EGYPTIAN, 0, 0, 0, 10, 0 }, // RIDE_TYPE_MAGIC_CARPET + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_6, MUSIC_STYLE_WATER, 0, 0, 0, 10, 20 }, // RIDE_TYPE_SUBMARINE_RIDE + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_6 | RIDE_TYPE_FLAG4_14, MUSIC_STYLE_GENTLE, 0, 0, 0, 7, 0 }, // RIDE_TYPE_RIVER_RAFTS + { 0, MUSIC_STYLE_GENTLE, 0, 0, 0, 20, 0 }, // RIDE_TYPE_50 + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_SINGLE_SESSION | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK_STYLE_2, 0, 0, 0, 12, 0 }, // RIDE_TYPE_ENTERPRISE + { 0, MUSIC_STYLE_GENTLE, 0, 0, 0, 15, 0 }, // RIDE_TYPE_52 + { 0, MUSIC_STYLE_GENTLE, 0, 0, 0, 12, 0 }, // RIDE_TYPE_53 + { 0, MUSIC_STYLE_GENTLE, 0, 0, 0, 20, 20 }, // RIDE_TYPE_54 + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 20, 20 }, // RIDE_TYPE_55 + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 20, 20 }, // RIDE_TYPE_INVERTED_IMPULSE_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_SUMMER, 0, 0, 0, 20, 20 }, // RIDE_TYPE_MINI_ROLLER_COASTER + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_WILD_WEST, 0, 0, 0, 20, 20 }, // RIDE_TYPE_MINE_RIDE + { RIDE_TYPE_FLAG4_0 | RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK_STYLE_2, 0, 0, 0, 20, 20 }, // RIDE_TYPE_59 + { RIDE_TYPE_FLAG4_ALLOW_MUSIC | RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES | RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT | RIDE_TYPE_FLAG4_HAS_AIR_TIME | RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS | RIDE_TYPE_FLAG4_11 | RIDE_TYPE_FLAG4_13, MUSIC_STYLE_ROCK, 0, 0, 0, 12, 7 }, // RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER +}; + +// rct2: 0x00982358 +const money8 DefaultShopItemPrice[SHOP_ITEM_COUNT] = { + MONEY(0,90), // SHOP_ITEM_BALLOON + MONEY(2,50), // SHOP_ITEM_TOY + MONEY(0,60), // SHOP_ITEM_MAP + MONEY(0,00), // SHOP_ITEM_PHOTO + MONEY(2,50), // SHOP_ITEM_UMBRELLA + MONEY(1,20), // SHOP_ITEM_DRINK + MONEY(1,50), // SHOP_ITEM_BURGER + MONEY(1,50), // SHOP_ITEM_FRIES + MONEY(0,90), // SHOP_ITEM_ICE_CREAM + MONEY(0,80), // SHOP_ITEM_COTTON_CANDY + MONEY(0,00), // SHOP_ITEM_EMPTY_CAN + MONEY(0,00), // SHOP_ITEM_RUBBISH + MONEY(0,00), // SHOP_ITEM_EMPTY_BURGER_BOX + MONEY(1,60), // SHOP_ITEM_PIZZA + MONEY(0,00), // SHOP_ITEM_VOUCHER + MONEY(1,20), // SHOP_ITEM_POPCORN + MONEY(1,00), // SHOP_ITEM_HOT_DOG + MONEY(1,50), // SHOP_ITEM_TENTACLE + MONEY(1,50), // SHOP_ITEM_HAT + MONEY(0,70), // SHOP_ITEM_CANDY_APPLE + MONEY(3,00), // SHOP_ITEM_TSHIRT + MONEY(0,70), // SHOP_ITEM_DONUT + MONEY(1,20), // SHOP_ITEM_COFFEE + MONEY(0,00), // SHOP_ITEM_EMPTY_CUP + MONEY(1,50), // SHOP_ITEM_CHICKEN + MONEY(1,20), // SHOP_ITEM_LEMONADE + MONEY(0,00), // SHOP_ITEM_EMPTY_BOX + MONEY(0,00), // SHOP_ITEM_EMPTY_BOTTLE + MONEY(0,00), // 28 + MONEY(0,00), // 29 + MONEY(0,00), // 30 + MONEY(0,00), // 31 + MONEY(0,00), // SHOP_ITEM_PHOTO2 + MONEY(0,00), // SHOP_ITEM_PHOTO3 + MONEY(0,00), // SHOP_ITEM_PHOTO4 + MONEY(1,10), // SHOP_ITEM_PRETZEL + MONEY(1,20), // SHOP_ITEM_CHOCOLATE + MONEY(1,10), // SHOP_ITEM_ICED_TEA + MONEY(1,20), // SHOP_ITEM_FUNNEL_CAKE + MONEY(1,50), // SHOP_ITEM_SUNGLASSES + MONEY(1,50), // SHOP_ITEM_BEEF_NOODLES + MONEY(1,50), // SHOP_ITEM_FRIED_RICE_NOODLES + MONEY(1,50), // SHOP_ITEM_WONTON_SOUP + MONEY(1,50), // SHOP_ITEM_MEATBALL_SOUP + MONEY(1,20), // SHOP_ITEM_FRUIT_JUICE + MONEY(1,20), // SHOP_ITEM_SOYBEAN_MILK + MONEY(1,20), // SHOP_ITEM_SU_JONGKWA + MONEY(1,50), // SHOP_ITEM_SUB_SANDWICH + MONEY(0,70), // SHOP_ITEM_COOKIE + MONEY(0,00), // SHOP_ITEM_EMPTY_BOWL_RED + MONEY(0,00), // SHOP_ITEM_EMPTY_DRINK_CARTON + MONEY(0,00), // SHOP_ITEM_EMPTY_JUICE_CUP + MONEY(1,50), // SHOP_ITEM_ROAST_SAUSAGE + MONEY(0,00), // SHOP_ITEM_EMPTY_BOWL_BLUE + MONEY(0,00), // 54 + MONEY(0,00), // 55 +}; + +const rct_shop_item_string_types ShopItemStringIds[SHOP_ITEM_COUNT] = { + { STR_SHOP_ITEM_SINGULAR_BALLOON, STR_SHOP_ITEM_PLURAL_BALLOON, STR_SHOP_ITEM_INDEFINITE_BALLOON, STR_SHOP_ITEM_DISPLAY_BALLOON }, + { STR_SHOP_ITEM_SINGULAR_CUDDLY_TOY, STR_SHOP_ITEM_PLURAL_CUDDLY_TOY, STR_SHOP_ITEM_INDEFINITE_CUDDLY_TOY, STR_SHOP_ITEM_DISPLAY_CUDDLY_TOY }, + { STR_SHOP_ITEM_SINGULAR_PARK_MAP, STR_SHOP_ITEM_PLURAL_PARK_MAP, STR_SHOP_ITEM_INDEFINITE_PARK_MAP, STR_SHOP_ITEM_DISPLAY_PARK_MAP }, + { STR_SHOP_ITEM_SINGULAR_ON_RIDE_PHOTO, STR_SHOP_ITEM_PLURAL_ON_RIDE_PHOTO, STR_SHOP_ITEM_INDEFINITE_ON_RIDE_PHOTO, STR_SHOP_ITEM_DISPLAY_ON_RIDE_PHOTO }, + { STR_SHOP_ITEM_SINGULAR_UMBRELLA, STR_SHOP_ITEM_PLURAL_UMBRELLA, STR_SHOP_ITEM_INDEFINITE_UMBRELLA, STR_SHOP_ITEM_DISPLAY_UMBRELLA }, + { STR_SHOP_ITEM_SINGULAR_DRINK, STR_SHOP_ITEM_PLURAL_DRINK, STR_SHOP_ITEM_INDEFINITE_DRINK, STR_SHOP_ITEM_DISPLAY_DRINK }, + { STR_SHOP_ITEM_SINGULAR_BURGER, STR_SHOP_ITEM_PLURAL_BURGER, STR_SHOP_ITEM_INDEFINITE_BURGER, STR_SHOP_ITEM_DISPLAY_BURGER }, + { STR_SHOP_ITEM_SINGULAR_CHIPS, STR_SHOP_ITEM_PLURAL_CHIPS, STR_SHOP_ITEM_INDEFINITE_CHIPS, STR_SHOP_ITEM_DISPLAY_CHIPS }, + { STR_SHOP_ITEM_SINGULAR_ICE_CREAM, STR_SHOP_ITEM_PLURAL_ICE_CREAM, STR_SHOP_ITEM_INDEFINITE_ICE_CREAM, STR_SHOP_ITEM_DISPLAY_ICE_CREAM }, + { STR_SHOP_ITEM_SINGULAR_CANDYFLOSS, STR_SHOP_ITEM_PLURAL_CANDYFLOSS, STR_SHOP_ITEM_INDEFINITE_CANDYFLOSS, STR_SHOP_ITEM_DISPLAY_CANDYFLOSS }, + { STR_SHOP_ITEM_SINGULAR_EMPTY_CAN, STR_SHOP_ITEM_PLURAL_EMPTY_CAN, STR_SHOP_ITEM_INDEFINITE_EMPTY_CAN, STR_SHOP_ITEM_DISPLAY_EMPTY_CAN }, + { STR_SHOP_ITEM_SINGULAR_RUBBISH, STR_SHOP_ITEM_PLURAL_RUBBISH, STR_SHOP_ITEM_INDEFINITE_RUBBISH, STR_SHOP_ITEM_DISPLAY_RUBBISH }, + { STR_SHOP_ITEM_SINGULAR_EMPTY_BURGER_BOX, STR_SHOP_ITEM_PLURAL_EMPTY_BURGER_BOX, STR_SHOP_ITEM_INDEFINITE_EMPTY_BURGER_BOX, STR_SHOP_ITEM_DISPLAY_EMPTY_BURGER_BOX }, + { STR_SHOP_ITEM_SINGULAR_PIZZA, STR_SHOP_ITEM_PLURAL_PIZZA, STR_SHOP_ITEM_INDEFINITE_PIZZA, STR_SHOP_ITEM_DISPLAY_PIZZA }, + { STR_SHOP_ITEM_SINGULAR_VOUCHER, STR_SHOP_ITEM_PLURAL_VOUCHER, STR_SHOP_ITEM_INDEFINITE_VOUCHER, STR_SHOP_ITEM_DISPLAY_VOUCHER }, + { STR_SHOP_ITEM_SINGULAR_POPCORN, STR_SHOP_ITEM_PLURAL_POPCORN, STR_SHOP_ITEM_INDEFINITE_POPCORN, STR_SHOP_ITEM_DISPLAY_POPCORN }, + { STR_SHOP_ITEM_SINGULAR_HOT_DOG, STR_SHOP_ITEM_PLURAL_HOT_DOG, STR_SHOP_ITEM_INDEFINITE_HOT_DOG, STR_SHOP_ITEM_DISPLAY_HOT_DOG }, + { STR_SHOP_ITEM_SINGULAR_TENTACLE, STR_SHOP_ITEM_PLURAL_TENTACLE, STR_SHOP_ITEM_INDEFINITE_TENTACLE, STR_SHOP_ITEM_DISPLAY_TENTACLE }, + { STR_SHOP_ITEM_SINGULAR_HAT, STR_SHOP_ITEM_PLURAL_HAT, STR_SHOP_ITEM_INDEFINITE_HAT, STR_SHOP_ITEM_DISPLAY_HAT }, + { STR_SHOP_ITEM_SINGULAR_TOFFEE_APPLE, STR_SHOP_ITEM_PLURAL_TOFFEE_APPLE, STR_SHOP_ITEM_INDEFINITE_TOFFEE_APPLE, STR_SHOP_ITEM_DISPLAY_TOFFEE_APPLE }, + { STR_SHOP_ITEM_SINGULAR_T_SHIRT, STR_SHOP_ITEM_PLURAL_T_SHIRT, STR_SHOP_ITEM_INDEFINITE_T_SHIRT, STR_SHOP_ITEM_DISPLAY_T_SHIRT }, + { STR_SHOP_ITEM_SINGULAR_DOUGHNUT, STR_SHOP_ITEM_PLURAL_DOUGHNUT, STR_SHOP_ITEM_INDEFINITE_DOUGHNUT, STR_SHOP_ITEM_DISPLAY_DOUGHNUT }, + { STR_SHOP_ITEM_SINGULAR_COFFEE, STR_SHOP_ITEM_PLURAL_COFFEE, STR_SHOP_ITEM_INDEFINITE_COFFEE, STR_SHOP_ITEM_DISPLAY_COFFEE }, + { STR_SHOP_ITEM_SINGULAR_EMPTY_CUP, STR_SHOP_ITEM_PLURAL_EMPTY_CUP, STR_SHOP_ITEM_INDEFINITE_EMPTY_CUP, STR_SHOP_ITEM_DISPLAY_EMPTY_CUP }, + { STR_SHOP_ITEM_SINGULAR_FRIED_CHICKEN, STR_SHOP_ITEM_PLURAL_FRIED_CHICKEN, STR_SHOP_ITEM_INDEFINITE_FRIED_CHICKEN, STR_SHOP_ITEM_DISPLAY_FRIED_CHICKEN }, + { STR_SHOP_ITEM_SINGULAR_LEMONADE, STR_SHOP_ITEM_PLURAL_LEMONADE, STR_SHOP_ITEM_INDEFINITE_LEMONADE, STR_SHOP_ITEM_DISPLAY_LEMONADE }, + { STR_SHOP_ITEM_SINGULAR_EMPTY_BOX, STR_SHOP_ITEM_PLURAL_EMPTY_BOX, STR_SHOP_ITEM_INDEFINITE_EMPTY_BOX, STR_SHOP_ITEM_DISPLAY_EMPTY_BOX }, + { STR_SHOP_ITEM_SINGULAR_EMPTY_BOTTLE, STR_SHOP_ITEM_PLURAL_EMPTY_BOTTLE, STR_SHOP_ITEM_INDEFINITE_EMPTY_BOTTLE, STR_SHOP_ITEM_DISPLAY_EMPTY_BOTTLE }, + { STR_NONE, STR_NONE, STR_NONE, STR_NONE }, + { STR_NONE, STR_NONE, STR_NONE, STR_NONE }, + { STR_NONE, STR_NONE, STR_NONE, STR_NONE }, + { STR_NONE, STR_NONE, STR_NONE, STR_NONE }, + { STR_SHOP_ITEM_SINGULAR_ON_RIDE_PHOTO, STR_SHOP_ITEM_PLURAL_ON_RIDE_PHOTO, STR_SHOP_ITEM_INDEFINITE_ON_RIDE_PHOTO, STR_SHOP_ITEM_DISPLAY_ON_RIDE_PHOTO }, + { STR_SHOP_ITEM_SINGULAR_ON_RIDE_PHOTO, STR_SHOP_ITEM_PLURAL_ON_RIDE_PHOTO, STR_SHOP_ITEM_INDEFINITE_ON_RIDE_PHOTO, STR_SHOP_ITEM_DISPLAY_ON_RIDE_PHOTO }, + { STR_SHOP_ITEM_SINGULAR_ON_RIDE_PHOTO, STR_SHOP_ITEM_PLURAL_ON_RIDE_PHOTO, STR_SHOP_ITEM_INDEFINITE_ON_RIDE_PHOTO, STR_SHOP_ITEM_DISPLAY_ON_RIDE_PHOTO }, + { STR_SHOP_ITEM_SINGULAR_PRETZEL, STR_SHOP_ITEM_PLURAL_PRETZEL, STR_SHOP_ITEM_INDEFINITE_PRETZEL, STR_SHOP_ITEM_DISPLAY_PRETZEL }, + { STR_SHOP_ITEM_SINGULAR_HOT_CHOCOLATE, STR_SHOP_ITEM_PLURAL_HOT_CHOCOLATE, STR_SHOP_ITEM_INDEFINITE_HOT_CHOCOLATE, STR_SHOP_ITEM_DISPLAY_HOT_CHOCOLATE }, + { STR_SHOP_ITEM_SINGULAR_ICED_TEA, STR_SHOP_ITEM_PLURAL_ICED_TEA, STR_SHOP_ITEM_INDEFINITE_ICED_TEA, STR_SHOP_ITEM_DISPLAY_ICED_TEA }, + { STR_SHOP_ITEM_SINGULAR_FUNNEL_CAKE, STR_SHOP_ITEM_PLURAL_FUNNEL_CAKE, STR_SHOP_ITEM_INDEFINITE_FUNNEL_CAKE, STR_SHOP_ITEM_DISPLAY_FUNNEL_CAKE }, + { STR_SHOP_ITEM_SINGULAR_SUNGLASSES, STR_SHOP_ITEM_PLURAL_SUNGLASSES, STR_SHOP_ITEM_INDEFINITE_SUNGLASSES, STR_SHOP_ITEM_DISPLAY_SUNGLASSES }, + { STR_SHOP_ITEM_SINGULAR_BEEF_NOODLES, STR_SHOP_ITEM_PLURAL_BEEF_NOODLES, STR_SHOP_ITEM_INDEFINITE_BEEF_NOODLES, STR_SHOP_ITEM_DISPLAY_BEEF_NOODLES }, + { STR_SHOP_ITEM_SINGULAR_FRIED_RICE_NOODLES, STR_SHOP_ITEM_PLURAL_FRIED_RICE_NOODLES, STR_SHOP_ITEM_INDEFINITE_FRIED_RICE_NOODLES, STR_SHOP_ITEM_DISPLAY_FRIED_RICE_NOODLES }, + { STR_SHOP_ITEM_SINGULAR_WONTON_SOUP, STR_SHOP_ITEM_PLURAL_WONTON_SOUP, STR_SHOP_ITEM_INDEFINITE_WONTON_SOUP, STR_SHOP_ITEM_DISPLAY_WONTON_SOUP }, + { STR_SHOP_ITEM_SINGULAR_MEATBALL_SOUP, STR_SHOP_ITEM_PLURAL_MEATBALL_SOUP, STR_SHOP_ITEM_INDEFINITE_MEATBALL_SOUP, STR_SHOP_ITEM_DISPLAY_MEATBALL_SOUP }, + { STR_SHOP_ITEM_SINGULAR_FRUIT_JUICE, STR_SHOP_ITEM_PLURAL_FRUIT_JUICE, STR_SHOP_ITEM_INDEFINITE_FRUIT_JUICE, STR_SHOP_ITEM_DISPLAY_FRUIT_JUICE }, + { STR_SHOP_ITEM_SINGULAR_SOYBEAN_MILK, STR_SHOP_ITEM_PLURAL_SOYBEAN_MILK, STR_SHOP_ITEM_INDEFINITE_SOYBEAN_MILK, STR_SHOP_ITEM_DISPLAY_SOYBEAN_MILK }, + { STR_SHOP_ITEM_SINGULAR_SUJONGKWA, STR_SHOP_ITEM_PLURAL_SUJONGKWA, STR_SHOP_ITEM_INDEFINITE_SUJONGKWA, STR_SHOP_ITEM_DISPLAY_SUJONGKWA }, + { STR_SHOP_ITEM_SINGULAR_SUB_SANDWICH, STR_SHOP_ITEM_PLURAL_SUB_SANDWICH, STR_SHOP_ITEM_INDEFINITE_SUB_SANDWICH, STR_SHOP_ITEM_DISPLAY_SUB_SANDWICH }, + { STR_SHOP_ITEM_SINGULAR_COOKIE, STR_SHOP_ITEM_PLURAL_COOKIE, STR_SHOP_ITEM_INDEFINITE_COOKIE, STR_SHOP_ITEM_DISPLAY_COOKIE }, + { STR_SHOP_ITEM_SINGULAR_EMPTY_BOWL_RED, STR_SHOP_ITEM_PLURAL_EMPTY_BOWL_RED, STR_SHOP_ITEM_INDEFINITE_EMPTY_BOWL_RED, STR_SHOP_ITEM_DISPLAY_EMPTY_BOWL_RED }, + { STR_SHOP_ITEM_SINGULAR_EMPTY_DRINK_CARTON, STR_SHOP_ITEM_PLURAL_EMPTY_DRINK_CARTON, STR_SHOP_ITEM_INDEFINITE_EMPTY_DRINK_CARTON, STR_SHOP_ITEM_DISPLAY_EMPTY_DRINK_CARTON }, + { STR_SHOP_ITEM_SINGULAR_EMPTY_JUICE_CUP, STR_SHOP_ITEM_PLURAL_EMPTY_JUICE_CUP, STR_SHOP_ITEM_INDEFINITE_EMPTY_JUICE_CUP, STR_SHOP_ITEM_DISPLAY_EMPTY_JUICE_CUP }, + { STR_SHOP_ITEM_SINGULAR_ROAST_SAUSAGE, STR_SHOP_ITEM_PLURAL_ROAST_SAUSAGE, STR_SHOP_ITEM_INDEFINITE_ROAST_SAUSAGE, STR_SHOP_ITEM_DISPLAY_ROAST_SAUSAGE }, + { STR_SHOP_ITEM_SINGULAR_EMPTY_BOWL_BLUE, STR_SHOP_ITEM_PLURAL_EMPTY_BOWL_BLUE, STR_SHOP_ITEM_INDEFINITE_EMPTY_BOWL_BLUE, STR_SHOP_ITEM_DISPLAY_EMPTY_BOWL_BLUE }, +}; + +const uint32 ShopItemImage[SHOP_ITEM_COUNT] = { + 5061, // SHOP_ITEM_BALLOON + 5062, // SHOP_ITEM_TOY + 5063, // SHOP_ITEM_MAP + 5064, // SHOP_ITEM_PHOTO + 5065, // SHOP_ITEM_UMBRELLA + 5066, // SHOP_ITEM_DRINK + 5067, // SHOP_ITEM_BURGER + 5068, // SHOP_ITEM_FRIES + 5069, // SHOP_ITEM_ICE_CREAM + 5070, // SHOP_ITEM_COTTON_CANDY + 5071, // SHOP_ITEM_EMPTY_CAN + 5072, // SHOP_ITEM_RUBBISH + 5073, // SHOP_ITEM_EMPTY_BURGER_BOX + 5074, // SHOP_ITEM_PIZZA + 5075, // SHOP_ITEM_VOUCHER + 5076, // SHOP_ITEM_POPCORN + 5077, // SHOP_ITEM_HOT_DOG + 5078, // SHOP_ITEM_TENTACLE + 5079, // SHOP_ITEM_HAT + 5080, // SHOP_ITEM_CANDY_APPLE + 5081, // SHOP_ITEM_TSHIRT + 5082, // SHOP_ITEM_DONUT + 5083, // SHOP_ITEM_COFFEE + 5084, // SHOP_ITEM_EMPTY_CUP + 5085, // SHOP_ITEM_CHICKEN + 5086, // SHOP_ITEM_LEMONADE + 5087, // SHOP_ITEM_EMPTY_BOX + 5088, // SHOP_ITEM_EMPTY_BOTTLE + 0, // 28 + 0, // 29 + 0, // 30 + 0, // 31 + 5089, // SHOP_ITEM_PHOTO2 + 5090, // SHOP_ITEM_PHOTO3 + 5091, // SHOP_ITEM_PHOTO4 + 5092, // SHOP_ITEM_PRETZEL + 5093, // SHOP_ITEM_CHOCOLATE + 5094, // SHOP_ITEM_ICED_TEA + 5095, // SHOP_ITEM_FUNNEL_CAKE + 5096, // SHOP_ITEM_SUNGLASSES + 5097, // SHOP_ITEM_BEEF_NOODLES + 5098, // SHOP_ITEM_FRIED_RICE_NOODLES + 5099, // SHOP_ITEM_WONTON_SOUP + 5100, // SHOP_ITEM_MEATBALL_SOUP + 5101, // SHOP_ITEM_FRUIT_JUICE + 5102, // SHOP_ITEM_SOYBEAN_MILK + 5103, // SHOP_ITEM_SU_JONGKWA + 5104, // SHOP_ITEM_SUB_SANDWICH + 5105, // SHOP_ITEM_COOKIE + 5106, // SHOP_ITEM_EMPTY_BOWL_RED + 5107, // SHOP_ITEM_EMPTY_DRINK_CARTON + 5108, // SHOP_ITEM_EMPTY_JUICE_CUP + 5109, // SHOP_ITEM_ROAST_SAUSAGE + 5110, // SHOP_ITEM_EMPTY_BOWL_BLUE +}; + +const rct_ride_type_vehicle CableLiftVehicle = { + .rotation_frame_mask = 31, + .var_02 = 0, + .var_03 = 0, + .var_04 = 0, + .car_friction = 0, + .tab_height = 0, + .num_seats = 0, + .sprite_flags = 0x7, + .sprite_width = 0, + .sprite_height_negative = 0, + .sprite_height_positive = 0, + .var_11 = 0, + .var_12 = 0, + .var_14 = 0, + .var_16 = 1, + .base_image_id = 29110, + .var_1C = 0, + .var_20 = 29142, + .var_24 = 29214, + .var_28 = 0, + .var_2C = 0, + .var_30 = 0, + .var_34 = 0, + .var_38 = 0, + .var_3C = 0, + .var_40 = 0, + .var_44 = 0, + .var_48 = 0, + .var_4C = 0, + .no_vehicle_images = 0, + .no_seating_rows = 0, + .spinning_inertia = 0, + .spinning_friction = 255, + .pad_57 = { 0,0,0 }, + .var_5A = 0, + .powered_acceleration = 0, + .powered_max_speed = 0, + .car_visual = 0, + .pad_5E = 1, + .draw_order = 14, + .special_frames = 0, + .peep_loading_positions = NULL }; diff --git a/src/ride/ride_data.h b/src/ride/ride_data.h index f4173d6547..bd124525b5 100644 --- a/src/ride/ride_data.h +++ b/src/ride/ride_data.h @@ -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,7 @@ #define _RIDE_DATA_H_ #include "../common.h" +#include "ride.h" typedef struct { rct_string_id vehicle_name; @@ -31,11 +32,47 @@ typedef struct { } rct_ride_name_convention; typedef struct { - uint32 spriteIndex; + uint32 sprite_index; uint16 height; - uint16 var_06; + uint16 scrolling_mode; + rct_string_id string_id; + uint32 flags; + uint16 colour_use_flags; } rct_ride_entrance_definition; +typedef struct { + rct_string_id singular; // Balloon + rct_string_id plural; // Balloons + rct_string_id indefinite; // a Balloon + rct_string_id display; // "Diamond Heights" Balloon +} rct_shop_item_string_types; + +typedef struct { + uint16 flags; + uint8 default_music; + uint8 var_3; + uint8 pad[4]; +} rct_ride_data_4; + +enum { + RIDE_TYPE_FLAG4_0 = (1 << 0), + RIDE_TYPE_FLAG4_MUSIC_ON_DEFAULT = (1 << 1), + RIDE_TYPE_FLAG4_ALLOW_MUSIC = (1 << 2), + RIDE_TYPE_FLAG4_3 = (1 << 3), + RIDE_TYPE_FLAG4_PEEP_CHECK_GFORCES = (1 << 4), + RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT = (1 << 5), + RIDE_TYPE_FLAG4_6 = (1 << 6), + RIDE_TYPE_FLAG4_HAS_AIR_TIME = (1 << 7), + RIDE_TYPE_FLAG4_SINGLE_SESSION = (1 << 8), + RIDE_TYPE_FLAG4_ALLOW_MULTIPLE_CIRCUITS = (1 << 9), + RIDE_TYPE_FLAG4_10 = (1 << 10), + RIDE_TYPE_FLAG4_11 = (1 << 11), + RIDE_TYPE_FLAG4_TRANSPORT_RIDE = (1 << 12), + RIDE_TYPE_FLAG4_13 = (1 << 13), + RIDE_TYPE_FLAG4_14 = (1 << 14), + RIDE_TYPE_FLAG4_15 = (1 << 15), +}; + extern const bool hasRunningTrack[0x60]; extern const uint8 initialUpkeepCosts[0x60]; extern const uint8 costPerTrackPiece[0x60]; @@ -46,9 +83,18 @@ extern const uint8 rideUnknownData3[0x60]; extern const rct_ride_name_convention RideNameConvention[96]; extern const uint8 RideAvailableModes[]; +extern const uint8 AllRideModesAvailable[]; extern const uint8 RideAvailableBreakdowns[]; -extern const rct_ride_entrance_definition RideEntranceDefinitions[12]; +extern const rct_ride_entrance_definition RideEntranceDefinitions[RIDE_ENTRANCE_STYLE_COUNT]; extern const uint8 RideLiftHillAdjustments[0x60]; +extern const rct_ride_data_4 RideData4[91]; + +extern const money8 DefaultShopItemPrice[SHOP_ITEM_COUNT]; +extern const rct_shop_item_string_types ShopItemStringIds[SHOP_ITEM_COUNT]; +extern const uint32 ShopItemImage[SHOP_ITEM_COUNT]; + +extern const rct_ride_type_vehicle CableLiftVehicle; + #endif diff --git a/src/ride/ride_ratings.c b/src/ride/ride_ratings.c index ed26aac9d2..5b04920885 100644 --- a/src/ride/ride_ratings.c +++ b/src/ride/ride_ratings.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 . *****************************************************************************/ @@ -24,6 +24,7 @@ #include "ride.h" #include "ride_data.h" #include "ride_ratings.h" +#include "track.h" enum { RIDE_RATINGS_STATE_FIND_NEXT_RIDE, @@ -34,10 +35,51 @@ enum { RIDE_RATINGS_STATE_5 }; +enum { + PROXIMITY_WATER_OVER, // 0x0138B596 + PROXIMITY_WATER_TOUCH, // 0x0138B598 + PROXIMITY_WATER_LOW, // 0x0138B59A + PROXIMITY_WATER_HIGH, // 0x0138B59C + PROXIMITY_SURFACE_TOUCH, // 0x0138B59E + PROXIMITY_PATH_OVER, // 0x0138B5A0 + PROXIMITY_PATH_TOUCH_ABOVE, // 0x0138B5A2 + PROXIMITY_PATH_TOUCH_UNDER, // 0x0138B5A4 + PROXIMITY_138B5A6, // 0x0138B5A6 + PROXIMITY_138B5A8, // 0x0138B5A8 + PROXIMITY_OWN_TRACK_TOUCH_ABOVE, // 0x0138B5AA + PROXIMITY_OWN_TRACK_CLOSE_ABOVE, // 0x0138B5AC + PROXIMITY_FOREIGN_TRACK_ABOVE_OR_BELOW, // 0x0138B5AE + PROXIMITY_FOREIGN_TRACK_TOUCH_ABOVE, // 0x0138B5B0 + PROXIMITY_FOREIGN_TRACK_CLOSE_ABOVE, // 0x0138B5B2 + PROXIMITY_SCENERY_SIDE_BELOW, // 0x0138B5B4 + PROXIMITY_SCENERY_SIDE_ABOVE, // 0x0138B5B6 + PROXIMITY_OWN_STATION_TOUCH_ABOVE, // 0x0138B5B8 + PROXIMITY_OWN_STATION_CLOSE_ABOVE, // 0x0138B5BA + PROXIMITY_TRACK_THROUGH_VERTICAL_LOOP, // 0x0138B5BC + PROXIMITY_PATH_TROUGH_VERTICAL_LOOP, // 0x0138B5BE + PROXIMITY_INTERSECTING_VERTICAL_LOOP, // 0x0138B5C0 + PROXIMITY_THROUGH_VERTICAL_LOOP, // 0x0138B5C2 + PROXIMITY_PATH_SIDE_CLOSE, // 0x0138B5C4 + PROXIMITY_FOREIGN_TRACK_SIDE_CLOSE, // 0x0138B5C6 + PROXIMITY_SURFACE_SIDE_CLOSE, // 0x0138B5C8 + PROXIMITY_COUNT +}; + typedef void (*ride_ratings_calculation)(rct_ride *ride); -#define _rideRatingsState RCT2_GLOBAL(0x0138B591, uint8) -#define _rideRatingsCurrentRide RCT2_GLOBAL(0x0138B590, uint8) +#define _rideRatingsProximityX RCT2_GLOBAL(0x0138B584, uint16) +#define _rideRatingsProximityY RCT2_GLOBAL(0x0138B586, uint16) +#define _rideRatingsProximityZ RCT2_GLOBAL(0x0138B588, uint16) +#define _rideRatingsCurrentRide RCT2_GLOBAL(0x0138B590, uint8) +#define _rideRatingsState RCT2_GLOBAL(0x0138B591, uint8) +#define _rideRatingsProximityTrackType RCT2_GLOBAL(0x0138B592, uint8) +#define _rideRatingsProximityBaseHeight RCT2_GLOBAL(0x0138B593, uint8) +#define _rideRatingsProximityTotal RCT2_GLOBAL(0x0138B594, uint16) +#define _rideRatingsProximityStartX RCT2_GLOBAL(0x0138B58A, uint16) +#define _rideRatingsProximityStartY RCT2_GLOBAL(0x0138B58C, uint16) +#define _rideRatingsProximityStartZ RCT2_GLOBAL(0x0138B58E, uint16) + +static uint16 *_proximityScores = (uint16*)0x0138B596; static const ride_ratings_calculation ride_ratings_calculate_func_table[91]; @@ -47,24 +89,10 @@ static void ride_ratings_update_state_2(); static void ride_ratings_update_state_3(); static void ride_ratings_update_state_4(); static void ride_ratings_update_state_5(); -static void loc_6B5BB2(); +static void ride_ratings_begin_proximity_loop(); static void ride_ratings_calculate(rct_ride *ride); static void ride_ratings_calculate_value(rct_ride *ride); - -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; - int result = RCT2_CALLFUNC_X(0x006C6402, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - *x = *((uint16*)&eax); - *y = *((uint16*)&ecx); - *z = *((uint8*)&edx); - *mapElement = (rct_map_element*)esi; - return result & (0x100); -} +static void ride_ratings_score_close_proximity(rct_map_element *mapElement); /** * @@ -120,45 +148,176 @@ static void ride_ratings_update_state_0() */ static void ride_ratings_update_state_1() { - RCT2_GLOBAL(0x0138B594, uint16) = 0; - RCT2_GLOBAL(0x0138B596, uint16) = 0; - RCT2_GLOBAL(0x0138B598, uint16) = 0; - RCT2_GLOBAL(0x0138B59A, uint16) = 0; - RCT2_GLOBAL(0x0138B59C, uint16) = 0; - RCT2_GLOBAL(0x0138B59E, uint16) = 0; - RCT2_GLOBAL(0x0138B5A0, uint16) = 0; - RCT2_GLOBAL(0x0138B5A2, uint16) = 0; - RCT2_GLOBAL(0x0138B5A4, uint16) = 0; - RCT2_GLOBAL(0x0138B5A6, uint16) = 0; - RCT2_GLOBAL(0x0138B5A8, uint16) = 0; - RCT2_GLOBAL(0x0138B5AA, uint16) = 0; - RCT2_GLOBAL(0x0138B5AC, uint16) = 0; - RCT2_GLOBAL(0x0138B5AE, uint16) = 0; - RCT2_GLOBAL(0x0138B5B0, uint16) = 0; - RCT2_GLOBAL(0x0138B5B2, uint16) = 0; - RCT2_GLOBAL(0x0138B5B4, uint16) = 0; - RCT2_GLOBAL(0x0138B5B6, uint16) = 0; - RCT2_GLOBAL(0x0138B5B8, uint16) = 0; - RCT2_GLOBAL(0x0138B5BA, uint16) = 0; - RCT2_GLOBAL(0x0138B5BC, uint16) = 0; - RCT2_GLOBAL(0x0138B5BE, uint16) = 0; - RCT2_GLOBAL(0x0138B5C0, uint16) = 0; - RCT2_GLOBAL(0x0138B5C2, uint16) = 0; - RCT2_GLOBAL(0x0138B5C4, uint16) = 0; - RCT2_GLOBAL(0x0138B5C6, uint16) = 0; - RCT2_GLOBAL(0x0138B5C8, uint16) = 0; + _rideRatingsProximityTotal = 0; + for (int i = 0; i < PROXIMITY_COUNT; i++) { + _proximityScores[i] = 0; + } RCT2_GLOBAL(0x0138B5CA, uint16) = 0; RCT2_GLOBAL(0x0138B5CC, uint16) = 0; _rideRatingsState = RIDE_RATINGS_STATE_2; RCT2_GLOBAL(0x0138B5CE, uint16) = 0; - loc_6B5BB2(); + ride_ratings_begin_proximity_loop(); +} + +/** + * + * rct2: 0x006B5C66 + */ +static void ride_ratings_update_state_2() +{ + rct_ride *ride; + rct_map_element *mapElement; + rct_xy_element trackElement, nextTrackElement; + int x, y, z, trackType, entranceIndex; + + ride = GET_RIDE(_rideRatingsCurrentRide); + if (ride->type == RIDE_TYPE_NULL || ride->status == RIDE_STATUS_CLOSED) { + _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; + return; + } + + x = _rideRatingsProximityX / 32; + y = _rideRatingsProximityY / 32; + z = _rideRatingsProximityZ / 8; + trackType = _rideRatingsProximityTrackType; + + mapElement = map_get_first_element_at(x, y); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + if (mapElement->base_height != z) + continue; + + if (trackType == 255 || ((mapElement->properties.track.sequence & 0x0F) == 0 && trackType == mapElement->properties.track.type)) { + if (trackType == TRACK_ELEM_END_STATION) { + entranceIndex = (mapElement->properties.track.sequence >> 4) & 7; + RCT2_GLOBAL(0x0138B5CE, uint16) &= ~1; + if (ride->entrances[entranceIndex] == 0xFFFF) + RCT2_GLOBAL(0x0138B5CE, uint16) |= 1; + } + + ride_ratings_score_close_proximity(mapElement); + + trackElement.x = _rideRatingsProximityX; + trackElement.y = _rideRatingsProximityY; + trackElement.element = mapElement; + if (!track_block_get_next(&trackElement, &nextTrackElement, NULL, NULL)) { + _rideRatingsState = RIDE_RATINGS_STATE_4; + return; + } + + x = nextTrackElement.x; + y = nextTrackElement.y; + z = nextTrackElement.element->base_height * 8; + mapElement = nextTrackElement.element; + if (x == _rideRatingsProximityStartX && y == _rideRatingsProximityStartY && z == _rideRatingsProximityStartZ) { + _rideRatingsState = RIDE_RATINGS_STATE_CALCULATE; + return; + } + _rideRatingsProximityX = x; + _rideRatingsProximityY = y; + _rideRatingsProximityZ = z; + _rideRatingsProximityTrackType = mapElement->properties.track.type; + return; + } + } while (!map_element_is_last_for_tile(mapElement++)); + + _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; +} + +/** + * + * rct2: 0x006B5E4D + */ +static void ride_ratings_update_state_3() +{ + rct_ride *ride; + + ride = GET_RIDE(_rideRatingsCurrentRide); + if (ride->type == RIDE_TYPE_NULL || ride->status == RIDE_STATUS_CLOSED) { + _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; + return; + } + + ride_ratings_calculate(ride); + ride_ratings_calculate_value(ride); + + window_invalidate_by_number(WC_RIDE, _rideRatingsCurrentRide); + _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; +} + +/** + * + * rct2: 0x006B5BAB + */ +static void ride_ratings_update_state_4() +{ + _rideRatingsState = RIDE_RATINGS_STATE_5; + ride_ratings_begin_proximity_loop(); +} + +/** + * + * rct2: 0x006B5D72 + */ +static void ride_ratings_update_state_5() +{ + rct_ride *ride; + rct_map_element *mapElement; + track_begin_end trackBeginEnd; + int x, y, z, trackType; + + ride = GET_RIDE(_rideRatingsCurrentRide); + if (ride->type == RIDE_TYPE_NULL || ride->status == RIDE_STATUS_CLOSED) { + _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; + return; + } + + x = _rideRatingsProximityX / 32; + y = _rideRatingsProximityY / 32; + z = _rideRatingsProximityZ / 8; + trackType = _rideRatingsProximityTrackType; + + mapElement = map_get_first_element_at(x, y); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + if (mapElement->base_height != z) + continue; + + if (trackType == 255 || trackType == mapElement->properties.track.type) { + ride_ratings_score_close_proximity(mapElement); + + x = _rideRatingsProximityX; + y = _rideRatingsProximityY; + if (!track_block_get_previous(x, y, mapElement, &trackBeginEnd)) { + _rideRatingsState = RIDE_RATINGS_STATE_CALCULATE; + return; + } + + x = trackBeginEnd.begin_x; + y = trackBeginEnd.begin_y; + z = trackBeginEnd.begin_z; + if (x == _rideRatingsProximityStartX && y == _rideRatingsProximityStartY && z == _rideRatingsProximityStartZ) { + _rideRatingsState = RIDE_RATINGS_STATE_CALCULATE; + return; + } + _rideRatingsProximityX = x; + _rideRatingsProximityY = y; + _rideRatingsProximityZ = z; + _rideRatingsProximityTrackType = trackBeginEnd.begin_element->properties.track.type; + return; + } + } while (!map_element_is_last_for_tile(mapElement++)); + + _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; } /** * * rct2: 0x006B5BB2 */ -static void loc_6B5BB2() +static void ride_ratings_begin_proximity_loop() { rct_ride *ride; int i, x, y, z; @@ -184,13 +343,13 @@ static void loc_6B5BB2() y = (ride->station_starts[i] >> 8) * 32; z = ride->station_heights[i] * 8; - RCT2_GLOBAL(0x0138B584, uint16) = x; - RCT2_GLOBAL(0x0138B586, uint16) = y; - RCT2_GLOBAL(0x0138B588, uint16) = z; - RCT2_GLOBAL(0x0138B592, uint8) = 255; - RCT2_GLOBAL(0x0138B58A, uint16) = x; - RCT2_GLOBAL(0x0138B58C, uint16) = y; - RCT2_GLOBAL(0x0138B58E, uint16) = z; + _rideRatingsProximityX = x; + _rideRatingsProximityY = y; + _rideRatingsProximityZ = z; + _rideRatingsProximityTrackType = 255; + _rideRatingsProximityStartX = x; + _rideRatingsProximityStartY = y; + _rideRatingsProximityStartZ = z; return; } } @@ -198,166 +357,262 @@ static void loc_6B5BB2() _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; } +static void proximity_score_increment(int type) +{ + _proximityScores[type]++; +} + /** * - * rct2: 0x006B5C66 + * rct2: 0x006B6207 */ -static void ride_ratings_update_state_2() +static void ride_ratings_score_close_proximity_in_direction(rct_map_element *inputMapElement, int direction) { - // 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; + int x, y; - ride = GET_RIDE(_rideRatingsCurrentRide); - if (ride->type == RIDE_TYPE_NULL || ride->status == RIDE_STATUS_CLOSED) { - _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; + x = _rideRatingsProximityX + TileDirectionDelta[direction].x; + y = _rideRatingsProximityY + TileDirectionDelta[direction].y; + if (x < 0 || y < 0 || x >= (32 * 256) || y >= (32 * 256)) return; - } - - x = RCT2_GLOBAL(0x0138B584, uint16) / 32; - y = RCT2_GLOBAL(0x0138B586, uint16) / 32; - z = RCT2_GLOBAL(0x0138B588, uint16) / 8; - - mapElement = map_get_first_element_at(x, y); - trackType = RCT2_GLOBAL(0x0138B592, uint8); + mapElement = map_get_first_element_at(x >> 5, y >> 5); do { - if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) - continue; - if (mapElement->base_height != z) - continue; - - if (trackType == 255 || (!(mapElement->properties.track.sequence & 0x0F) && trackType == mapElement->properties.track.type)) { - if (trackType == 1) { - entranceIndex = (mapElement->properties.track.sequence >> 4) & 7; - RCT2_GLOBAL(0x0138B5CE, uint16) &= ~1; - if (ride->entrances[entranceIndex] == 0xFFFF) - RCT2_GLOBAL(0x0138B5CE, uint16) |= 1; + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_SURFACE: + if (_rideRatingsProximityBaseHeight <= inputMapElement->base_height) { + if (inputMapElement->clearance_height <= mapElement->base_height) { + proximity_score_increment(PROXIMITY_SURFACE_SIDE_CLOSE); + } } - - RCT2_CALLPROC_X(0x006B5F9D, 0, 0, 0, 0, (int)mapElement, 0, 0); - - 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; + break; + case MAP_ELEMENT_TYPE_PATH: + if (abs((int)inputMapElement->base_height - (int)mapElement->base_height) <= 2) { + proximity_score_increment(PROXIMITY_PATH_SIDE_CLOSE); } - - 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; + break; + case MAP_ELEMENT_TYPE_TRACK: + if (inputMapElement->properties.track.ride_index != mapElement->properties.track.ride_index) { + if (abs((int)inputMapElement->base_height - (int)mapElement->base_height) <= 2) { + proximity_score_increment(PROXIMITY_FOREIGN_TRACK_SIDE_CLOSE); + } } - RCT2_GLOBAL(0x0138B584, uint16) = x; - RCT2_GLOBAL(0x0138B586, uint16) = y; - RCT2_GLOBAL(0x0138B588, uint16) = z; - RCT2_GLOBAL(0x0138B592, uint8) = mapElement->properties.track.type; + break; + case MAP_ELEMENT_TYPE_SCENERY: + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + if (mapElement->base_height < inputMapElement->clearance_height) { + if (inputMapElement->base_height > mapElement->clearance_height) { + proximity_score_increment(PROXIMITY_SCENERY_SIDE_ABOVE); + } else { + proximity_score_increment(PROXIMITY_SCENERY_SIDE_BELOW); + } + } + break; } } while (!map_element_is_last_for_tile(mapElement++)); - _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; } -/** - * - * rct2: 0x006B5E4D - */ -static void ride_ratings_update_state_3() +static void ride_ratings_score_close_proximity_loops_helper(rct_map_element *inputMapElement, int x, int y) { - rct_ride *ride; - - ride = GET_RIDE(_rideRatingsCurrentRide); - if (ride->type == RIDE_TYPE_NULL || ride->status == RIDE_STATUS_CLOSED) { - _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; - return; - } - - ride_ratings_calculate(ride); - RCT2_CALLPROC_X(0x00655F64, 0, 0, 0, 0, 0, (int)ride, 0); - ride_ratings_calculate_value(ride); - - window_invalidate_by_number(WC_RIDE, _rideRatingsCurrentRide); - _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; -} - -/** - * - * rct2: 0x006B5BAB - */ -static void ride_ratings_update_state_4() -{ - _rideRatingsState = RIDE_RATINGS_STATE_5; - loc_6B5BB2(); -} - -/** - * - * rct2: 0x006B5D72 - */ -static void ride_ratings_update_state_5() -{ - // sub_6C6402 returns a carry, CALLFUNC doesn't support this - // so have to wait for sub_6C6402 to be decompiled - RCT2_CALLPROC_EBPSAFE(0x006B5D72); - return; - - rct_ride *ride; rct_map_element *mapElement; - int x, y, z, trackType; - - ride = GET_RIDE(_rideRatingsCurrentRide); - if (ride->type == RIDE_TYPE_NULL || ride->status == RIDE_STATUS_CLOSED) { - _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; - return; - } - - x = RCT2_GLOBAL(0x0138B584, uint16) / 32; - y = RCT2_GLOBAL(0x0138B586, uint16) / 32; - z = RCT2_GLOBAL(0x0138B588, uint16) / 8; - - mapElement = map_get_first_element_at(x, y); - trackType = RCT2_GLOBAL(0x0138B592, uint8); + int zDiff, unk; + mapElement = map_get_first_element_at(x >> 5, y >> 5); do { - if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) - continue; - if (mapElement->base_height != z) - continue; - - if (trackType == 255 || trackType == mapElement->properties.track.type) { - RCT2_CALLPROC_X(0x006B5F9D, 0, 0, 0, 0, (int)mapElement, 0, 0); - - x = RCT2_GLOBAL(0x0138B584, uint16); - y = RCT2_GLOBAL(0x0138B586, uint16); - if (!sub_6C6402(&mapElement, &x, &y, &z)) { - _rideRatingsState = RIDE_RATINGS_STATE_CALCULATE; - return; + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_PATH: + zDiff = (int)mapElement->base_height - (int)inputMapElement->base_height; + if (zDiff >= 0 && zDiff <= 16) { + proximity_score_increment(PROXIMITY_PATH_TROUGH_VERTICAL_LOOP); } - - x >>= 16; - y >>= 16; - if (x == RCT2_GLOBAL(0x0138B58A, uint16) && y == RCT2_GLOBAL(0x0138B58C, uint16) && z == RCT2_GLOBAL(0x0138B58E, uint16)) { - _rideRatingsState = RIDE_RATINGS_STATE_CALCULATE; - return; + break; + case MAP_ELEMENT_TYPE_TRACK: + unk = (mapElement->type ^ inputMapElement->type) & 1; + if (unk != 0) { + zDiff = (int)mapElement->base_height - (int)inputMapElement->base_height; + if (zDiff >= 0 && zDiff <= 16) { + proximity_score_increment(PROXIMITY_TRACK_THROUGH_VERTICAL_LOOP); + if ( + mapElement->properties.track.type == TRACK_ELEM_LEFT_VERTICAL_LOOP || + mapElement->properties.track.type == TRACK_ELEM_RIGHT_VERTICAL_LOOP + ) { + proximity_score_increment(PROXIMITY_INTERSECTING_VERTICAL_LOOP); + } + } } - RCT2_GLOBAL(0x0138B584, uint16) = x; - RCT2_GLOBAL(0x0138B586, uint16) = y; - RCT2_GLOBAL(0x0138B588, uint16) = z; - RCT2_GLOBAL(0x0138B592, uint8) = mapElement->properties.track.type; + break; + } + } while (!map_element_is_last_for_tile(mapElement++)); +} + +/** + * + * rct2: 0x006B62DA + */ +static void ride_ratings_score_close_proximity_loops(rct_map_element *inputMapElement) +{ + int x, y, direction, trackType; + + trackType = inputMapElement->properties.track.type; + if (trackType == TRACK_ELEM_LEFT_VERTICAL_LOOP || trackType == TRACK_ELEM_RIGHT_VERTICAL_LOOP) { + x = _rideRatingsProximityX; + y = _rideRatingsProximityY; + ride_ratings_score_close_proximity_loops_helper(inputMapElement, _rideRatingsProximityX, _rideRatingsProximityY); + + direction = inputMapElement->type & MAP_ELEMENT_DIRECTION_MASK; + x = _rideRatingsProximityX + TileDirectionDelta[direction].x; + y = _rideRatingsProximityY + TileDirectionDelta[direction].y; + ride_ratings_score_close_proximity_loops_helper(inputMapElement, x, y); + } +} + +/** + * + * rct2: 0x006B5F9D + */ +static void ride_ratings_score_close_proximity(rct_map_element *inputMapElement) +{ + rct_map_element *mapElement; + int x, y, z, direction, waterHeight, trackType, sequence; + bool isStation; + + if (RCT2_GLOBAL(0x0138B5CE, uint16) & 1) + return; + + _rideRatingsProximityTotal++; + x = _rideRatingsProximityX; + y = _rideRatingsProximityY; + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_SURFACE: + _rideRatingsProximityBaseHeight = mapElement->base_height; + if (mapElement->base_height * 8 == _rideRatingsProximityZ) { + proximity_score_increment(PROXIMITY_SURFACE_TOUCH); + } + waterHeight = (mapElement->properties.surface.terrain & 0x1F); + if (waterHeight != 0) { + z = waterHeight * 16; + if (z <= _rideRatingsProximityZ) { + proximity_score_increment(PROXIMITY_WATER_OVER); + if (z == _rideRatingsProximityZ) { + proximity_score_increment(PROXIMITY_WATER_TOUCH); + } + z += 16; + if (z == _rideRatingsProximityZ) { + proximity_score_increment(PROXIMITY_WATER_LOW); + } + z += 112; + if (z <= _rideRatingsProximityZ) { + proximity_score_increment(PROXIMITY_WATER_HIGH); + } + } + } + break; + case MAP_ELEMENT_TYPE_PATH: + if (mapElement->properties.path.type & 0xF0) { + if (mapElement->clearance_height == inputMapElement->base_height) { + proximity_score_increment(PROXIMITY_138B5A6); + } + if (mapElement->base_height == inputMapElement->clearance_height) { + proximity_score_increment(PROXIMITY_138B5A8); + } + } else { + if (mapElement->clearance_height <= inputMapElement->base_height) { + proximity_score_increment(PROXIMITY_PATH_OVER); + } + if (mapElement->clearance_height == inputMapElement->base_height) { + proximity_score_increment(PROXIMITY_PATH_TOUCH_ABOVE); + } + if (mapElement->base_height == inputMapElement->clearance_height) { + proximity_score_increment(PROXIMITY_PATH_TOUCH_UNDER); + } + } + break; + case MAP_ELEMENT_TYPE_TRACK: + trackType = mapElement->properties.track.type; + if (trackType == TRACK_ELEM_LEFT_VERTICAL_LOOP || trackType == TRACK_ELEM_RIGHT_VERTICAL_LOOP) { + sequence = mapElement->properties.track.sequence & 0x0F; + if (sequence == 3 || sequence == 6) { + if (mapElement->base_height - inputMapElement->clearance_height <= 10) { + proximity_score_increment(PROXIMITY_THROUGH_VERTICAL_LOOP); + } + } + } + if (inputMapElement->properties.track.ride_index != mapElement->properties.track.ride_index) { + proximity_score_increment(PROXIMITY_FOREIGN_TRACK_ABOVE_OR_BELOW); + if (mapElement->clearance_height == inputMapElement->base_height) { + proximity_score_increment(PROXIMITY_FOREIGN_TRACK_TOUCH_ABOVE); + } + if (mapElement->clearance_height + 2 <= inputMapElement->base_height) { + if (mapElement->clearance_height + 10 >= inputMapElement->base_height) { + proximity_score_increment(PROXIMITY_FOREIGN_TRACK_CLOSE_ABOVE); + } + } + if (inputMapElement->clearance_height == mapElement->base_height) { + proximity_score_increment(PROXIMITY_FOREIGN_TRACK_TOUCH_ABOVE); + } + if (inputMapElement->clearance_height + 2 == mapElement->base_height) { + if (inputMapElement->clearance_height + 10 >= mapElement->base_height) { + proximity_score_increment(PROXIMITY_FOREIGN_TRACK_CLOSE_ABOVE); + } + } + } else { + trackType = mapElement->properties.track.type; + isStation = ( + trackType == TRACK_ELEM_END_STATION || + trackType == TRACK_ELEM_MIDDLE_STATION || + trackType == TRACK_ELEM_BEGIN_STATION + ); + if (mapElement->clearance_height == inputMapElement->base_height) { + proximity_score_increment(PROXIMITY_OWN_TRACK_TOUCH_ABOVE); + if (isStation) { + proximity_score_increment(PROXIMITY_OWN_STATION_TOUCH_ABOVE); + } + } + if (mapElement->clearance_height + 2 <= inputMapElement->base_height) { + if (mapElement->clearance_height + 10 >= inputMapElement->base_height) { + proximity_score_increment(PROXIMITY_OWN_TRACK_CLOSE_ABOVE); + if (isStation) { + proximity_score_increment(PROXIMITY_OWN_STATION_CLOSE_ABOVE); + } + } + } + + if (inputMapElement->clearance_height == mapElement->base_height) { + proximity_score_increment(PROXIMITY_OWN_TRACK_TOUCH_ABOVE); + if (isStation) { + proximity_score_increment(PROXIMITY_OWN_STATION_TOUCH_ABOVE); + } + } + if (inputMapElement->clearance_height + 2 <= mapElement->base_height) { + if (inputMapElement->clearance_height + 10 >= mapElement->base_height) { + proximity_score_increment(PROXIMITY_OWN_TRACK_CLOSE_ABOVE); + if (isStation) { + proximity_score_increment(PROXIMITY_OWN_STATION_CLOSE_ABOVE); + } + } + } + } + break; } } while (!map_element_is_last_for_tile(mapElement++)); - _rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE; + direction = inputMapElement->type & MAP_ELEMENT_DIRECTION_MASK; + ride_ratings_score_close_proximity_in_direction(inputMapElement, (direction + 1) & 3); + ride_ratings_score_close_proximity_in_direction(inputMapElement, (direction - 1) & 3); + ride_ratings_score_close_proximity_loops(inputMapElement); + + switch (_rideRatingsProximityTrackType) { + case TRACK_ELEM_BRAKES: + RCT2_GLOBAL(0x0138B5CA, uint16)++; + break; + case 211: + case 212: + RCT2_GLOBAL(0x0138B5CC, uint16)++; + break; + } } static void ride_ratings_calculate(rct_ride *ride) @@ -365,12 +620,22 @@ static void ride_ratings_calculate(rct_ride *ride) ride_ratings_calculation calcFunc; calcFunc = ride_ratings_calculate_func_table[ride->type]; - if (calcFunc != NULL) + if (calcFunc != NULL) { calcFunc(ride); + } + + #ifdef ORIGINAL_RATINGS + if (ride->ratings.excitement != -1) { + // Address underflows allowed by original RCT2 code + ride->ratings.excitement = max(0, ride->ratings.excitement); + ride->ratings.intensity = max(0, ride->ratings.intensity); + ride->ratings.nausea = max(0, ride->ratings.nausea); + } + #endif // 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); + // RCT2 CALLPROC X((int)calcFunc, 0, 0, 0, 0, 0, (int)ride, 0); } static void ride_ratings_calculate_value(rct_ride *ride) @@ -498,7 +763,7 @@ static uint16 ride_compute_upkeep(rct_ride *ride) upkeep += 160; } else if (ride->mode == RIDE_MODE_LIM_POWERED_LAUNCH) { upkeep += 320; - } else if (ride->mode == RIDE_MODE_POWERED_LAUNCH || + } else if (ride->mode == RIDE_MODE_POWERED_LAUNCH || ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED) { upkeep += 220; } @@ -521,7 +786,7 @@ static uint16 ride_compute_upkeep(rct_ride *ride) static void ride_ratings_apply_adjustments(rct_ride *ride, rating_tuple *ratings) { rct_ride_type *rideEntry; - + rideEntry = gRideTypeList[ride->subtype]; // Apply ride entry multipliers @@ -529,11 +794,9 @@ static void ride_ratings_apply_adjustments(rct_ride *ride, rating_tuple *ratings ratings->intensity += ((ratings->intensity * rideEntry->intensity_multipler ) >> 7); ratings->nausea += ((ratings->nausea * rideEntry->nausea_multipler ) >> 7); - // As far as I can tell, this flag detects whether the ride is a roller - // coaster, or a log flume or rapids. Everything else it's not set. - // more detail: https://gist.github.com/kevinburke/d951e74e678b235eef3e - uint16 flags = RCT2_GLOBAL(0x0097D4F2 + ride->type * 8, uint16); - if (flags & 0x80) { + // Apply total air time + #ifdef ORIGINAL_RATINGS + if (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_HAS_AIR_TIME) { uint16 totalAirTime = ride->total_air_time; if (rideEntry->flags & RIDE_ENTRY_FLAG_11) { if (totalAirTime >= 96) { @@ -546,6 +809,17 @@ static void ride_ratings_apply_adjustments(rct_ride *ride, rating_tuple *ratings ratings->nausea += totalAirTime / 16; } } + #else + if (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_HAS_AIR_TIME) { + if (rideEntry->flags & RIDE_ENTRY_FLAG_11) { + // Limit airtime bonus for heartline twister coaster (see issues #2031 and #2064) + ratings->excitement += min(ride->total_air_time, 96) / 8; + } else { + ratings->excitement += ride->total_air_time / 8; + } + ratings->nausea += ride->total_air_time / 16; + } + #endif } /** @@ -577,15 +851,57 @@ static void set_unreliability_factor(rct_ride *ride) ride->unreliability_factor += (ride->lift_hill_speed - lift_speed_adjustment) * 2; } +static uint32 get_proximity_score_helper_1(uint16 x, uint16 max, uint32 multiplier) +{ + return (min(x, max) * multiplier) >> 16; +} + +static uint32 get_proximity_score_helper_2(uint16 x, uint16 additionIfNotZero, uint16 max, uint32 multiplier) +{ + uint32 result = x; + if (result != 0) result += additionIfNotZero; + return (min(result, max) * multiplier) >> 16; +} + +static uint32 get_proximity_score_helper_3(uint16 x, uint16 resultIfNotZero) +{ + return x == 0 ? 0 : resultIfNotZero; +} + /** * * rct2: 0x0065E277 */ -static int sub_65E277() +static uint32 ride_ratings_get_proximity_score() { - int eax, ebx, ecx, edx, esi, edi, ebp; - RCT2_CALLFUNC_X(0x0065E277, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - return ebx; + uint32 result = 0; + result += get_proximity_score_helper_1(_proximityScores[PROXIMITY_WATER_OVER ] , 60, 0x00AAAA); + result += get_proximity_score_helper_1(_proximityScores[PROXIMITY_WATER_TOUCH ] , 22, 0x0245D1); + result += get_proximity_score_helper_1(_proximityScores[PROXIMITY_WATER_LOW ] , 10, 0x020000); + result += get_proximity_score_helper_1(_proximityScores[PROXIMITY_WATER_HIGH ] , 40, 0x00A000); + result += get_proximity_score_helper_1(_proximityScores[PROXIMITY_SURFACE_TOUCH ] , 70, 0x01B6DB); + result += get_proximity_score_helper_1(_proximityScores[PROXIMITY_PATH_OVER ] + 8, 12, 0x064000); + result += get_proximity_score_helper_3(_proximityScores[PROXIMITY_PATH_TOUCH_ABOVE ] , 40 ); + result += get_proximity_score_helper_3(_proximityScores[PROXIMITY_PATH_TOUCH_UNDER ] , 45 ); + result += get_proximity_score_helper_2(_proximityScores[PROXIMITY_138B5A6 ] , 10, 20, 0x03C000); + result += get_proximity_score_helper_2(_proximityScores[PROXIMITY_138B5A8 ] , 10, 20, 0x044000); + result += get_proximity_score_helper_2(_proximityScores[PROXIMITY_OWN_TRACK_TOUCH_ABOVE ] , 10, 15, 0x035555); + result += get_proximity_score_helper_1(_proximityScores[PROXIMITY_OWN_TRACK_CLOSE_ABOVE ] , 5, 0x060000); + result += get_proximity_score_helper_2(_proximityScores[PROXIMITY_FOREIGN_TRACK_ABOVE_OR_BELOW] , 10, 15, 0x02AAAA); + result += get_proximity_score_helper_2(_proximityScores[PROXIMITY_FOREIGN_TRACK_TOUCH_ABOVE ] , 10, 15, 0x04AAAA); + result += get_proximity_score_helper_1(_proximityScores[PROXIMITY_FOREIGN_TRACK_CLOSE_ABOVE ] , 5, 0x090000); + result += get_proximity_score_helper_1(_proximityScores[PROXIMITY_SCENERY_SIDE_BELOW ] , 35, 0x016DB6); + result += get_proximity_score_helper_1(_proximityScores[PROXIMITY_SCENERY_SIDE_ABOVE ] , 35, 0x00DB6D); + result += get_proximity_score_helper_3(_proximityScores[PROXIMITY_OWN_STATION_TOUCH_ABOVE ] , 55 ); + result += get_proximity_score_helper_3(_proximityScores[PROXIMITY_OWN_STATION_CLOSE_ABOVE ] , 25 ); + result += get_proximity_score_helper_2(_proximityScores[PROXIMITY_TRACK_THROUGH_VERTICAL_LOOP ] , 4, 6, 0x140000); + result += get_proximity_score_helper_2(_proximityScores[PROXIMITY_PATH_TROUGH_VERTICAL_LOOP ] , 4, 6, 0x0F0000); + result += get_proximity_score_helper_3(_proximityScores[PROXIMITY_INTERSECTING_VERTICAL_LOOP ] , 100 ); + result += get_proximity_score_helper_2(_proximityScores[PROXIMITY_THROUGH_VERTICAL_LOOP ] , 4, 6, 0x0A0000); + result += get_proximity_score_helper_2(_proximityScores[PROXIMITY_PATH_SIDE_CLOSE ] , 10, 20, 0x01C000); + result += get_proximity_score_helper_2(_proximityScores[PROXIMITY_FOREIGN_TRACK_SIDE_CLOSE ] , 10, 20, 0x024000); + result += get_proximity_score_helper_2(_proximityScores[PROXIMITY_SURFACE_SIDE_CLOSE ] , 10, 20, 0x028000); + return result; } /** @@ -724,7 +1040,7 @@ static rating_tuple get_special_track_elements_rating(uint8 type, rct_ride *ride excitement += 50; intensity += 30; nausea += 20; - } + } if (ride_has_waterfall(ride)) { excitement += 55; intensity += 30; @@ -1026,9 +1342,9 @@ static void ride_ratings_apply_operation_option(rating_tuple *ratings, rct_ride ratings->nausea += (ride->operation_option * nauseaMultiplier) >> 16; } -static void ride_ratings_apply_65E277(rating_tuple *ratings, rct_ride *ride, int excitementMultiplier) +static void ride_ratings_apply_proximity(rating_tuple *ratings, rct_ride *ride, int excitementMultiplier) { - ratings->excitement += (sub_65E277() * excitementMultiplier) >> 16; + ratings->excitement += (ride_ratings_get_proximity_score() * excitementMultiplier) >> 16; } static void ride_ratings_apply_scenery(rating_tuple *ratings, rct_ride *ride, int excitementMultiplier) @@ -1100,7 +1416,7 @@ static void ride_ratings_calculate_spiral_roller_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 14; set_unreliability_factor(ride); @@ -1115,14 +1431,14 @@ static void ride_ratings_calculate_spiral_roller_coaster(rct_ride *ride) 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_proximity(&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); @@ -1146,7 +1462,7 @@ static void ride_ratings_calculate_stand_up_roller_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 17; set_unreliability_factor(ride); @@ -1161,7 +1477,7 @@ static void ride_ratings_calculate_stand_up_roller_coaster(rct_ride *ride) 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_proximity(&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); @@ -1185,7 +1501,7 @@ static void ride_ratings_calculate_suspended_swinging_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 18; set_unreliability_factor(ride); @@ -1200,7 +1516,7 @@ static void ride_ratings_calculate_suspended_swinging_coaster(rct_ride *ride) 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_proximity(&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); @@ -1226,7 +1542,7 @@ static void ride_ratings_calculate_inverted_roller_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 17; set_unreliability_factor(ride); @@ -1241,14 +1557,14 @@ static void ride_ratings_calculate_inverted_roller_coaster(rct_ride *ride) 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_proximity(&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); @@ -1270,7 +1586,7 @@ static void ride_ratings_calculate_junior_roller_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 13; set_unreliability_factor(ride); @@ -1285,7 +1601,7 @@ static void ride_ratings_calculate_junior_roller_coaster(rct_ride *ride) 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_proximity(&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); @@ -1320,7 +1636,7 @@ static void ride_ratings_calculate_miniature_railway(rct_ride *ride) 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_proximity(&ratings, ride, 8946); ride_ratings_apply_scenery(&ratings, ride, 20915); ride_ratings_apply_first_length_penalty(&ratings, ride, 0xC80000, 2, 2, 2); @@ -1357,7 +1673,7 @@ static void ride_ratings_calculate_monorail(rct_ride *ride) 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_proximity(&ratings, ride, 8946); ride_ratings_apply_scenery(&ratings, ride, 16732); ride_ratings_apply_first_length_penalty(&ratings, ride, 0xAA0000, 2, 2, 2); @@ -1383,7 +1699,7 @@ static void ride_ratings_calculate_mini_suspended_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 15; set_unreliability_factor(ride); @@ -1398,7 +1714,7 @@ static void ride_ratings_calculate_mini_suspended_coaster(rct_ride *ride) 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_proximity(&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); @@ -1434,7 +1750,7 @@ static void ride_ratings_calculate_boat_ride(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) ratings.excitement += RIDE_RATING(0,20); - ride_ratings_apply_65E277(&ratings, ride, 11183); + ride_ratings_apply_proximity(&ratings, ride, 11183); ride_ratings_apply_scenery(&ratings, ride, 22310); ride_ratings_apply_intensity_penalty(&ratings); @@ -1455,7 +1771,7 @@ static void ride_ratings_calculate_wooden_wild_mouse(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 14; set_unreliability_factor(ride); @@ -1470,9 +1786,9 @@ static void ride_ratings_calculate_wooden_wild_mouse(rct_ride *ride) 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_proximity(&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_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); @@ -1497,7 +1813,7 @@ static void ride_ratings_calculate_steeplechase(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 14; set_unreliability_factor(ride); @@ -1512,7 +1828,7 @@ static void ride_ratings_calculate_steeplechase(rct_ride *ride) 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_proximity(&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); @@ -1552,7 +1868,7 @@ static void ride_ratings_calculate_car_ride(rct_ride *ride) 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_proximity(&ratings, ride, 11183); ride_ratings_apply_scenery(&ratings, ride, 8366); ride_ratings_apply_first_length_penalty(&ratings, ride, 0xC80000, 8, 2, 2); @@ -1587,8 +1903,17 @@ static void ride_ratings_calculate_launched_freefall(rct_ride *ride) } ratings.excitement += ((ride_get_total_length(ride) >> 16) * 32768) >> 16; + + #ifdef ORIGINAL_RATINGS ride_ratings_apply_operation_option(&ratings, ride, 0, 1355917, 451972); - ride_ratings_apply_65E277(&ratings, ride, 20130); + #else + // Only apply "launch speed" effects when the setting can be modified + if (ride->mode == RIDE_MODE_UPWARD_LAUNCH) { + ride_ratings_apply_operation_option(&ratings, ride, 0, 1355917, 451972); + } + #endif + + ride_ratings_apply_proximity(&ratings, ride, 20130); ride_ratings_apply_scenery(&ratings, ride, 25098); ride_ratings_apply_intensity_penalty(&ratings); @@ -1609,7 +1934,7 @@ static void ride_ratings_calculate_bobsleigh_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 16; set_unreliability_factor(ride); @@ -1624,7 +1949,7 @@ static void ride_ratings_calculate_bobsleigh_coaster(rct_ride *ride) 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_proximity(&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); @@ -1655,7 +1980,7 @@ static void ride_ratings_calculate_observation_tower(rct_ride *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_proximity(&ratings, ride, 20130); ride_ratings_apply_scenery(&ratings, ride, 83662); ride_ratings_apply_intensity_penalty(&ratings); @@ -1680,7 +2005,7 @@ static void ride_ratings_calculate_looping_roller_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = ride_is_powered_launched(ride) ? 20 : 15; set_unreliability_factor(ride); @@ -1695,14 +2020,14 @@ static void ride_ratings_calculate_looping_roller_coaster(rct_ride *ride) 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_proximity(&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); @@ -1726,7 +2051,7 @@ static void ride_ratings_calculate_dinghy_slide(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 13; set_unreliability_factor(ride); @@ -1741,7 +2066,7 @@ static void ride_ratings_calculate_dinghy_slide(rct_ride *ride) 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_proximity(&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); @@ -1765,7 +2090,7 @@ static void ride_ratings_calculate_mine_train_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 16; set_unreliability_factor(ride); @@ -1780,7 +2105,7 @@ static void ride_ratings_calculate_mine_train_coaster(rct_ride *ride) 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_proximity(&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); @@ -1818,10 +2143,10 @@ static void ride_ratings_calculate_chairlift(rct_ride *ride) 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_proximity(&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); @@ -1849,7 +2174,7 @@ static void ride_ratings_calculate_corkscrew_roller_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 16; set_unreliability_factor(ride); @@ -1864,7 +2189,7 @@ static void ride_ratings_calculate_corkscrew_roller_coaster(rct_ride *ride) 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_proximity(&ratings, ride, 20130); ride_ratings_apply_scenery(&ratings, ride, 6693); if ((ride->inversions & 0x1F) == 0) @@ -1903,7 +2228,7 @@ static void ride_ratings_calculate_maze(rct_ride *ride) int size = min(ride->maze_tiles, 100); ratings.excitement += size; ratings.intensity += size * 2; - + ride_ratings_apply_scenery(&ratings, ride, 22310); ride_ratings_apply_intensity_penalty(&ratings); @@ -1962,7 +2287,7 @@ static void ride_ratings_calculate_go_karts(rct_ride *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); @@ -1975,7 +2300,7 @@ static void ride_ratings_calculate_go_karts(rct_ride *ride) 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_proximity(&ratings, ride, 11183); ride_ratings_apply_scenery(&ratings, ride, 16732); ride_ratings_apply_intensity_penalty(&ratings); @@ -2013,7 +2338,7 @@ static void ride_ratings_calculate_log_flume(rct_ride *ride) 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_proximity(&ratings, ride, 22367); ride_ratings_apply_scenery(&ratings, ride, 11155); ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 2, 2, 2, 2); @@ -2047,7 +2372,7 @@ static void ride_ratings_calculate_river_rapids(rct_ride *ride) 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_proximity(&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); @@ -2392,7 +2717,7 @@ static void ride_ratings_calculate_reverse_freefall_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 25; set_unreliability_factor(ride); @@ -2402,7 +2727,7 @@ static void ride_ratings_calculate_reverse_freefall_coaster(rct_ride *ride) 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_proximity(&ratings, ride, 17893); ride_ratings_apply_scenery(&ratings, ride, 11155); ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 34, 2, 2, 2); @@ -2435,7 +2760,7 @@ static void ride_ratings_calculate_lift(rct_ride *ride) ratings.excitement += (totalLength * 45875) >> 16; ratings.nausea += (totalLength * 26214) >> 16; - ride_ratings_apply_65E277(&ratings, ride, 11183); + ride_ratings_apply_proximity(&ratings, ride, 11183); ride_ratings_apply_scenery(&ratings, ride, 83662); ride_ratings_apply_intensity_penalty(&ratings); @@ -2459,7 +2784,7 @@ static void ride_ratings_calculate_vertical_drop_roller_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 16; set_unreliability_factor(ride); @@ -2473,7 +2798,7 @@ static void ride_ratings_calculate_vertical_drop_roller_coaster(rct_ride *ride) 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_proximity(&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); @@ -2514,10 +2839,10 @@ static void ride_ratings_calculate_twist(rct_ride *ride) ratings.nausea += ride->rotations * 20; ride_ratings_apply_scenery(&ratings, ride, 13943); - + ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); - + ride->ratings = ratings; ride->upkeep_cost = ride_compute_upkeep(ride); @@ -2558,7 +2883,7 @@ static void ride_ratings_calculate_flying_roller_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 17; set_unreliability_factor(ride); @@ -2573,7 +2898,7 @@ static void ride_ratings_calculate_flying_roller_coaster(rct_ride *ride) 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_proximity(&ratings, ride, 20130); ride_ratings_apply_scenery(&ratings, ride, 6693); if ((ride->inversions & 0x1F) == 0) @@ -2604,7 +2929,7 @@ static void ride_ratings_calculate_virginia_reel(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 19; set_unreliability_factor(ride); @@ -2619,7 +2944,7 @@ static void ride_ratings_calculate_virginia_reel(rct_ride *ride) 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_proximity(&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); @@ -2654,7 +2979,7 @@ static void ride_ratings_calculate_splash_boats(rct_ride *ride) 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_proximity(&ratings, ride, 22367); ride_ratings_apply_scenery(&ratings, ride, 11155); ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 6, 2, 2, 2); @@ -2690,7 +3015,7 @@ static void ride_ratings_calculate_mini_helicopters(rct_ride *ride) 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_proximity(&ratings, ride, 8946); ride_ratings_apply_scenery(&ratings, ride, 8366); ride_ratings_apply_first_length_penalty(&ratings, ride, 0xA00000, 2, 2, 2); @@ -2712,7 +3037,7 @@ static void ride_ratings_calculate_lay_down_roller_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 18; set_unreliability_factor(ride); @@ -2727,7 +3052,7 @@ static void ride_ratings_calculate_lay_down_roller_coaster(rct_ride *ride) 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_proximity(&ratings, ride, 20130); ride_ratings_apply_scenery(&ratings, ride, 6693); if ((ride->inversions & 0x1F) == 0) { @@ -2772,7 +3097,7 @@ static void ride_ratings_calculate_suspended_monorail(rct_ride *ride) 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_proximity(&ratings, ride, 12525); ride_ratings_apply_scenery(&ratings, ride, 25098); ride_ratings_apply_first_length_penalty(&ratings, ride, 0xAA0000, 2, 2, 2); @@ -2798,7 +3123,7 @@ static void ride_ratings_calculate_reverser_roller_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 19; set_unreliability_factor(ride); @@ -2819,7 +3144,7 @@ static void ride_ratings_calculate_reverser_roller_coaster(rct_ride *ride) 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_proximity(&ratings, ride, 22367); ride_ratings_apply_scenery(&ratings, ride, 11155); if (RCT2_GLOBAL(0x0138B5CC, uint16) < 1) @@ -2846,7 +3171,7 @@ static void ride_ratings_calculate_heartline_twister_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 18; set_unreliability_factor(ride); @@ -2861,7 +3186,7 @@ static void ride_ratings_calculate_heartline_twister_coaster(rct_ride *ride) 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_proximity(&ratings, ride, 9841); ride_ratings_apply_scenery(&ratings, ride, 3904); if ((ride->inversions & 0x1F) == 0) @@ -2895,7 +3220,7 @@ static void ride_ratings_calculate_mini_golf(rct_ride *ride) 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_proximity(&ratings, ride, 15657); ride_ratings_apply_scenery(&ratings, ride, 27887); // Apply golf holes factor @@ -2970,7 +3295,7 @@ static void ride_ratings_calculate_ghost_train(rct_ride *ride) 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_proximity(&ratings, ride, 11183); ride_ratings_apply_scenery(&ratings, ride, 8366); ride_ratings_apply_first_length_penalty(&ratings, ride, 0xB40000, 2, 2, 2); @@ -2992,7 +3317,7 @@ static void ride_ratings_calculate_twister_roller_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 15; set_unreliability_factor(ride); @@ -3007,7 +3332,7 @@ static void ride_ratings_calculate_twister_roller_coaster(rct_ride *ride) 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_proximity(&ratings, ride, 20130); ride_ratings_apply_scenery(&ratings, ride, 6693); if ((ride->inversions & 0x1F) == 0) @@ -3038,7 +3363,7 @@ static void ride_ratings_calculate_wooden_roller_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 19; set_unreliability_factor(ride); @@ -3053,7 +3378,7 @@ static void ride_ratings_calculate_wooden_roller_coaster(rct_ride *ride) 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_proximity(&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); @@ -3079,7 +3404,7 @@ static void ride_ratings_calculate_side_friction_roller_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 19; set_unreliability_factor(ride); @@ -3094,7 +3419,7 @@ static void ride_ratings_calculate_side_friction_roller_coaster(rct_ride *ride) 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_proximity(&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); @@ -3119,7 +3444,7 @@ static void ride_ratings_calculate_wild_mouse(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 14; set_unreliability_factor(ride); @@ -3134,7 +3459,7 @@ static void ride_ratings_calculate_wild_mouse(rct_ride *ride) 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_proximity(&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); @@ -3160,7 +3485,7 @@ static void ride_ratings_calculate_multi_dimension_roller_coaster(rct_ride *ride if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 18; set_unreliability_factor(ride); @@ -3175,7 +3500,7 @@ static void ride_ratings_calculate_multi_dimension_roller_coaster(rct_ride *ride 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_proximity(&ratings, ride, 20130); ride_ratings_apply_scenery(&ratings, ride, 6693); if ((ride->inversions & 0x1F) == 0) @@ -3206,7 +3531,7 @@ static void ride_ratings_calculate_giga_coaster(rct_ride *ride) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) return; - + ride->unreliability_factor = 14; set_unreliability_factor(ride); @@ -3221,14 +3546,14 @@ static void ride_ratings_calculate_giga_coaster(rct_ride *ride) 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_proximity(&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); @@ -3263,7 +3588,7 @@ static void ride_ratings_calculate_roto_drop(rct_ride *ride) ratings.intensity += lengthFactor * 2; ratings.nausea += lengthFactor * 2; - ride_ratings_apply_65E277(&ratings, ride, 11183); + ride_ratings_apply_proximity(&ratings, ride, 11183); ride_ratings_apply_scenery(&ratings, ride, 25098); ride_ratings_apply_intensity_penalty(&ratings); @@ -3359,7 +3684,7 @@ static void ride_ratings_calculate_monorail_cycles(rct_ride *ride) 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_proximity(&ratings, ride, 8946); ride_ratings_apply_scenery(&ratings, ride, 11155); ride_ratings_apply_first_length_penalty(&ratings, ride, 0x8C0000, 2, 2, 2); @@ -3396,7 +3721,7 @@ static void ride_ratings_calculate_compact_inverted_coaster(rct_ride *ride) 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_proximity(&ratings, ride, 15657); ride_ratings_apply_scenery(&ratings, ride, 8366); if ((ride->inversions & 0x1F) == 0) @@ -3440,7 +3765,7 @@ static void ride_ratings_calculate_water_coaster(rct_ride *ride) 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_proximity(&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); @@ -3477,7 +3802,7 @@ static void ride_ratings_calculate_air_powered_vertical_coaster(rct_ride *ride) 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_proximity(&ratings, ride, 17893); ride_ratings_apply_scenery(&ratings, ride, 11155); ride_ratings_apply_highest_drop_height_penalty(&ratings, ride, 34, 2, 1, 1); @@ -3514,7 +3839,7 @@ static void ride_ratings_calculate_inverted_hairpin_coaster(rct_ride *ride) 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_proximity(&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); @@ -3551,7 +3876,7 @@ static void ride_ratings_calculate_magic_carpet(rct_ride *ride) ratings.nausea += ride->operation_option * 20; ride_ratings_apply_scenery(&ratings, ride, 11155); - + ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); @@ -3575,7 +3900,7 @@ static void ride_ratings_calculate_submarine_ride(rct_ride *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_proximity(&ratings, ride, 11183); ride_ratings_apply_scenery(&ratings, ride, 22310); ride_ratings_apply_intensity_penalty(&ratings); @@ -3607,9 +3932,9 @@ static void ride_ratings_calculate_river_rafts(rct_ride *ride) 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_proximity(&ratings, ride, 13420); ride_ratings_apply_scenery(&ratings, ride, 11155); - + ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); @@ -3641,7 +3966,7 @@ static void ride_ratings_calculate_enterprise(rct_ride *ride) ratings.nausea += ride->operation_option * 16; ride_ratings_apply_scenery(&ratings, ride, 19521); - + ride_ratings_apply_intensity_penalty(&ratings); ride_ratings_apply_adjustments(ride, &ratings); @@ -3675,7 +4000,7 @@ static void ride_ratings_calculate_inverted_impulse_coaster(rct_ride *ride) 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_proximity(&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); @@ -3713,7 +4038,7 @@ static void ride_ratings_calculate_mini_roller_coaster(rct_ride *ride) 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_proximity(&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); @@ -3753,7 +4078,7 @@ static void ride_ratings_calculate_mine_ride(rct_ride *ride) 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_proximity(&ratings, ride, 21472); ride_ratings_apply_scenery(&ratings, ride, 16732); ride_ratings_apply_first_length_penalty(&ratings, ride, 0x10E0000, 2, 2, 2); @@ -3790,7 +4115,7 @@ static void ride_ratings_calculate_lim_launched_roller_coaster(rct_ride *ride) 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_proximity(&ratings, ride, 20130); ride_ratings_apply_scenery(&ratings, ride, 6693); if ((ride->inversions & 0x1F) == 0) diff --git a/src/ride/ride_ratings.h b/src/ride/ride_ratings.h index 467b2c23a8..29c5c92fff 100644 --- a/src/ride/ride_ratings.h +++ b/src/ride/ride_ratings.h @@ -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 . *****************************************************************************/ @@ -25,6 +25,5 @@ #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 c982a44757..91f25949fb 100644 --- a/src/ride/station.c +++ b/src/ride/station.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 . *****************************************************************************/ @@ -222,7 +222,7 @@ static void ride_update_station_race(rct_ride *ride, int stationIndex) return; } } - + // Begin the race ride_race_init_vehicle_speeds(ride); ride->lifecycle_flags |= RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING; @@ -248,11 +248,11 @@ static void ride_race_init_vehicle_speeds(rct_ride *ride) for (i = 0; i < ride->num_vehicles; i++) { vehicle = &g_sprite_list[ride->vehicles[i]].vehicle; - vehicle->var_48 &= ~(1 << 6); + vehicle->update_flags &= ~VEHICLE_UPDATE_FLAG_6; rideEntry = GET_RIDE_ENTRY(vehicle->ride_subtype); - vehicle->speed = (scenario_rand() & 16) - 8 + rideEntry->vehicles[vehicle->vehicle_type].var_5C; + vehicle->speed = (scenario_rand() & 16) - 8 + rideEntry->vehicles[vehicle->vehicle_type].powered_max_speed; if (vehicle->num_peeps != 0) { rct_peep *peep = &g_sprite_list[vehicle->peep[0]].peep; @@ -300,7 +300,7 @@ static void ride_invalidate_station_start(rct_ride *ride, int stationIndex, int mapElement->properties.track.sequence |= 0x80; // Invalidate map tile - map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + map_invalidate_tile_zoom1(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); } rct_map_element *ride_get_station_start_track_element(rct_ride *ride, int stationIndex) diff --git a/src/ride/station.h b/src/ride/station.h index b71f1dc27d..8614e5b059 100644 --- a/src/ride/station.h +++ b/src/ride/station.h @@ -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 . *****************************************************************************/ diff --git a/src/ride/track.c b/src/ride/track.c index 0b90178d55..ff7bf11948 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -20,20 +20,24 @@ #include "../addresses.h" #include "../audio/audio.h" +#include "../cheats.h" #include "../config.h" #include "../game.h" #include "../interface/viewport.h" #include "../localisation/localisation.h" +#include "../management/finance.h" #include "../platform/platform.h" #include "../rct1.h" #include "../util/sawyercoding.h" #include "../util/util.h" +#include "../world/map_animation.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 "ride_data.h" +#include "ride_ratings.h" #include "track.h" #include "track_data.h" @@ -42,202 +46,207 @@ * rct2: 0x00997C9D */ const rct_trackdefinition *gTrackDefinitions = (rct_trackdefinition*)0x00997C9D; +const rct_trackdefinition *gFlatRideTrackDefinitions = (rct_trackdefinition*)0x0099849D; // 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 - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_BEGIN_STATION - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_MIDDLE_STATION - { TRACK_FLAT, TRACK_UP_25, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP - { TRACK_FLAT, TRACK_UP_60, TRACK_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP - { TRACK_FLAT, TRACK_UP_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_25_DEG_UP - { TRACK_FLAT, TRACK_UP_60, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP_TO_60_DEG_UP - { TRACK_FLAT, TRACK_UP_25, TRACK_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP_TO_25_DEG_UP - { TRACK_FLAT, TRACK_NONE, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP_TO_FLAT - { TRACK_FLAT, TRACK_DOWN_25, TRACK_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN - { TRACK_FLAT, TRACK_DOWN_60, TRACK_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_DOWN - { TRACK_FLAT, TRACK_DOWN_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_DOWN_60, TRACK_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN_TO_60_DEG_DOWN - { TRACK_FLAT, TRACK_DOWN_25, TRACK_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_DOWN_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_NONE, TRACK_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN_TO_FLAT - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_5_TILES - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_5_TILES - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_LEFT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_LEFT_BANK - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_RIGHT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_RIGHT_BANK - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_BANK_TO_FLAT - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_BANK_TO_FLAT - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_BANKED_LEFT_QUARTER_TURN_5_TILES - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_BANKED_RIGHT_QUARTER_TURN_5_TILES - { TRACK_FLAT, TRACK_UP_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_BANK_TO_25_DEG_UP - { TRACK_FLAT, TRACK_UP_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_BANK_TO_25_DEG_UP - { TRACK_FLAT, TRACK_NONE, TRACK_UP_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP_TO_LEFT_BANK - { TRACK_FLAT, TRACK_NONE, TRACK_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP_TO_RIGHT_BANK - { TRACK_FLAT, TRACK_DOWN_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_BANK_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_DOWN_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_BANK_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_NONE, TRACK_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN_TO_LEFT_BANK - { TRACK_FLAT, TRACK_NONE, TRACK_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN_TO_RIGHT_BANK - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_BANK - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_BANK - { TRACK_FLAT, TRACK_UP_25, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_UP - { TRACK_FLAT, TRACK_UP_25, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_UP - { TRACK_FLAT, TRACK_DOWN_25, TRACK_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_DOWN - { TRACK_FLAT, TRACK_DOWN_25, TRACK_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_DOWN - { TRACK_S_BEND, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_S_BEND_LEFT - { TRACK_S_BEND, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_S_BEND_RIGHT - { TRACK_VERTICAL_LOOP, TRACK_DOWN_25, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_UNKNOWN_VERTICAL_LOOP }, // ELEM_LEFT_VERTICAL_LOOP - { TRACK_VERTICAL_LOOP, TRACK_DOWN_25, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_UNKNOWN_VERTICAL_LOOP }, // ELEM_RIGHT_VERTICAL_LOOP - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_3_TILES - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_3_TILES - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_3_TILES_BANK - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_BANK - { TRACK_FLAT, TRACK_UP_25, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP - { TRACK_FLAT, TRACK_UP_25, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP - { TRACK_FLAT, TRACK_DOWN_25, TRACK_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN - { TRACK_FLAT, TRACK_DOWN_25, TRACK_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_1_TILE - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_1_TILE - { TRACK_TWIST, TRACK_NONE, TRACK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_TWIST_DOWN_TO_UP - { TRACK_TWIST, TRACK_NONE, TRACK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_TWIST_DOWN_TO_UP - { TRACK_TWIST, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_NONE }, // ELEM_LEFT_TWIST_UP_TO_DOWN - { TRACK_TWIST, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_NONE }, // ELEM_RIGHT_TWIST_UP_TO_DOWN - { TRACK_HALF_LOOP, TRACK_NONE, TRACK_UP_25, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_HALF_LOOP_UP }, // ELEM_HALF_LOOP_UP - { TRACK_HALF_LOOP, TRACK_DOWN_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_HALF_LOOP_DOWN }, // ELEM_HALF_LOOP_DOWN - { TRACK_CORKSCREW, TRACK_NONE, TRACK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_CORKSCREW_UP - { TRACK_CORKSCREW, TRACK_NONE, TRACK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_CORKSCREW_UP - { TRACK_CORKSCREW, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_CORKSCREW_DOWN }, // ELEM_LEFT_CORKSCREW_DOWN - { TRACK_CORKSCREW, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_CORKSCREW_DOWN }, // ELEM_RIGHT_CORKSCREW_DOWN - { TRACK_FLAT, TRACK_UP_60, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_60_DEG_UP - { TRACK_FLAT, TRACK_NONE, TRACK_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP_TO_FLAT - { TRACK_FLAT, TRACK_DOWN_60, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_60_DEG_DOWN - { TRACK_FLAT, TRACK_NONE, TRACK_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_DOWN_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_END_STATION + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_BEGIN_STATION + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_MIDDLE_STATION + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP_TO_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN_TO_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_DOWN_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_5_TILES + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_5_TILES + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_RIGHT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_BANK_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_BANK_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_BANKED_LEFT_QUARTER_TURN_5_TILES + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_BANKED_RIGHT_QUARTER_TURN_5_TILES + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_BANK_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_BANK_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP_TO_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP_TO_RIGHT_BANK + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_BANK_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_BANK_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN_TO_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN_TO_RIGHT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_BANK + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_DOWN + { TRACK_S_BEND, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_S_BEND_LEFT + { TRACK_S_BEND, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_S_BEND_RIGHT + { TRACK_VERTICAL_LOOP, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_UNKNOWN_VERTICAL_LOOP }, // ELEM_LEFT_VERTICAL_LOOP + { TRACK_VERTICAL_LOOP, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_UNKNOWN_VERTICAL_LOOP }, // ELEM_RIGHT_VERTICAL_LOOP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_3_TILES + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_3_TILES + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_3_TILES_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_BANK + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_1_TILE + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_1_TILE + { TRACK_TWIST, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_TWIST_DOWN_TO_UP + { TRACK_TWIST, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_TWIST_DOWN_TO_UP + { TRACK_TWIST, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_NONE }, // ELEM_LEFT_TWIST_UP_TO_DOWN + { TRACK_TWIST, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_NONE }, // ELEM_RIGHT_TWIST_UP_TO_DOWN + { TRACK_HALF_LOOP, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_HALF_LOOP_UP }, // ELEM_HALF_LOOP_UP + { TRACK_HALF_LOOP, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_HALF_LOOP_DOWN }, // ELEM_HALF_LOOP_DOWN + { TRACK_CORKSCREW, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_CORKSCREW_UP + { TRACK_CORKSCREW, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_CORKSCREW_UP + { TRACK_CORKSCREW, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_CORKSCREW_DOWN }, // ELEM_LEFT_CORKSCREW_DOWN + { TRACK_CORKSCREW, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_CORKSCREW_DOWN }, // ELEM_RIGHT_CORKSCREW_DOWN + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_DOWN_TO_FLAT { TRACK_TOWER_BASE, TRACK_VANGLE_TOWER, TRACK_VANGLE_TOWER, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_TOWER_BASE { TRACK_TOWER_BASE, TRACK_VANGLE_TOWER, TRACK_VANGLE_TOWER, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_TOWER_SECTION - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_COVERED - { TRACK_FLAT, TRACK_UP_25, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP_COVERED - { TRACK_FLAT, TRACK_UP_60, TRACK_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP_COVERED - { TRACK_FLAT, TRACK_UP_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_25_DEG_UP_COVERED - { TRACK_FLAT, TRACK_UP_60, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP_TO_60_DEG_UP_COVERED - { TRACK_FLAT, TRACK_UP_25, TRACK_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP_TO_25_DEG_UP_COVERED - { TRACK_FLAT, TRACK_NONE, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP_TO_FLAT_COVERED - { TRACK_FLAT, TRACK_DOWN_25, TRACK_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN_COVERED - { TRACK_FLAT, TRACK_DOWN_60, TRACK_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_DOWN_COVERED - { TRACK_FLAT, TRACK_DOWN_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_25_DEG_DOWN_COVERED - { TRACK_FLAT, TRACK_DOWN_60, TRACK_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN_TO_60_DEG_DOWN_COVERED - { TRACK_FLAT, TRACK_DOWN_25, TRACK_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_DOWN_TO_25_DEG_DOWN_COVERED - { TRACK_FLAT, TRACK_NONE, TRACK_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN_TO_FLAT_COVERED - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_5_TILES_COVERED - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_5_TILES_COVERED - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_S_BEND_LEFT_COVERED - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_S_BEND_RIGHT_COVERED - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_3_TILES_COVERED - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_COVERED - { TRACK_HELIX_SMALL, TRACK_NONE, TRACK_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_HALF_BANKED_HELIX_UP_SMALL - { TRACK_HELIX_SMALL, TRACK_NONE, TRACK_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_HALF_BANKED_HELIX_UP_SMALL - { TRACK_HELIX_SMALL, TRACK_NONE, TRACK_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_HALF_BANKED_HELIX_DOWN_SMALL - { TRACK_HELIX_SMALL, TRACK_NONE, TRACK_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_SMALL - { TRACK_HELIX_SMALL, TRACK_NONE, TRACK_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_HALF_BANKED_HELIX_UP_LARGE - { TRACK_HELIX_SMALL, TRACK_NONE, TRACK_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_HALF_BANKED_HELIX_UP_LARGE - { TRACK_HELIX_SMALL, TRACK_NONE, TRACK_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_HALF_BANKED_HELIX_DOWN_LARGE - { TRACK_HELIX_SMALL, TRACK_NONE, TRACK_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_LARGE - { TRACK_FLAT, TRACK_UP_60, TRACK_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_UP - { TRACK_FLAT, TRACK_UP_60, TRACK_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_UP - { TRACK_FLAT, TRACK_DOWN_60, TRACK_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_DOWN - { TRACK_FLAT, TRACK_DOWN_60, TRACK_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_DOWN - { TRACK_BRAKES, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_BRAKES - { TRACK_ROTATION_CONTROL_TOGGLE,TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_ROTATION_CONTROL_TOGGLE - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP - { TRACK_HELIX_LARGE, TRACK_NONE, TRACK_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_UP - { TRACK_HELIX_LARGE, TRACK_NONE, TRACK_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_UP - { TRACK_HELIX_LARGE, TRACK_NONE, TRACK_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_DOWN - { TRACK_HELIX_LARGE, TRACK_NONE, TRACK_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_DOWN - { TRACK_HELIX_LARGE_UNBANKED, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_HELIX_LARGE_UP - { TRACK_HELIX_LARGE_UNBANKED, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_HELIX_LARGE_UP - { TRACK_HELIX_LARGE_UNBANKED, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_HELIX_LARGE_DOWN - { TRACK_HELIX_LARGE_UNBANKED, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_HELIX_LARGE_DOWN - { TRACK_FLAT, TRACK_UP_25, TRACK_UP_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_25_DEG_UP_LEFT_BANKED - { TRACK_FLAT, TRACK_UP_25, TRACK_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_25_DEG_UP_RIGHT_BANKED - { TRACK_WATERFALL, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_WATERFALL - { TRACK_RAPIDS, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RAPIDS - { TRACK_ON_RIDE_PHOTO, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_ON_RIDE_PHOTO - { TRACK_FLAT, TRACK_DOWN_25, TRACK_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_25_DEG_DOWN_LEFT_BANKED - { TRACK_FLAT, TRACK_DOWN_25, TRACK_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_25_DEG_DOWN_RIGHT_BANKED - { TRACK_WATER_SPLASH, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_WATER_SPLASH - { TRACK_FLAT, TRACK_UP_60, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_60_DEG_UP_LONG_BASE - { TRACK_FLAT, TRACK_NONE, TRACK_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP_TO_FLAT_LONG_BASE - { TRACK_WHIRLPOOL, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_WHIRLPOOL - { TRACK_FLAT, TRACK_NONE, TRACK_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_60_DEG_DOWN_LONG_BASE - { TRACK_FLAT, TRACK_DOWN_60, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP_TO_FLAT_LONG_BASE - { TRACK_LIFT_HILL, TRACK_DOWN_60, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_CABLE_LIFT_HILL - { TRACK_WHOA_BELLY, TRACK_VANGLE_WHOA_BELLY, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_REVERSE_WHOA_BELLY_SLOPE + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_COVERED + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP_COVERED + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP_COVERED + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_25_DEG_UP_COVERED + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP_TO_60_DEG_UP_COVERED + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP_TO_25_DEG_UP_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_UP_TO_FLAT_COVERED + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN_COVERED + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_DOWN_COVERED + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_25_DEG_DOWN_COVERED + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN_TO_60_DEG_DOWN_COVERED + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_DOWN_TO_25_DEG_DOWN_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_25_DEG_DOWN_TO_FLAT_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_5_TILES_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_5_TILES_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_S_BEND_LEFT_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_S_BEND_RIGHT_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_3_TILES_COVERED + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_COVERED + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_HALF_BANKED_HELIX_UP_SMALL + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_HALF_BANKED_HELIX_UP_SMALL + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_HALF_BANKED_HELIX_DOWN_SMALL + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_SMALL + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_HALF_BANKED_HELIX_UP_LARGE + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_HALF_BANKED_HELIX_UP_LARGE + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_HALF_BANKED_HELIX_DOWN_LARGE + { TRACK_HELIX_SMALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_LARGE + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_DOWN + { TRACK_BRAKES, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_BRAKES + { TRACK_ROTATION_CONTROL_TOGGLE,TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_ROTATION_CONTROL_TOGGLE + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP + { TRACK_HELIX_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_UP + { TRACK_HELIX_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_UP + { TRACK_HELIX_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_DOWN + { TRACK_HELIX_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_DOWN + { TRACK_HELIX_LARGE_UNBANKED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_HELIX_LARGE_UP + { TRACK_HELIX_LARGE_UNBANKED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_HELIX_LARGE_UP + { TRACK_HELIX_LARGE_UNBANKED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_HELIX_LARGE_DOWN + { TRACK_HELIX_LARGE_UNBANKED, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_HELIX_LARGE_DOWN + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_25_DEG_UP_LEFT_BANKED + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_25_DEG_UP_RIGHT_BANKED + { TRACK_WATERFALL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_WATERFALL + { TRACK_RAPIDS, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RAPIDS + { TRACK_ON_RIDE_PHOTO, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_ON_RIDE_PHOTO + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_25_DEG_DOWN_LEFT_BANKED + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_25_DEG_DOWN_RIGHT_BANKED + { TRACK_WATER_SPLASH, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_WATER_SPLASH + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_60_DEG_UP_LONG_BASE + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP_TO_FLAT_LONG_BASE + { TRACK_WHIRLPOOL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_WHIRLPOOL + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT_TO_60_DEG_DOWN_LONG_BASE + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP_TO_FLAT_LONG_BASE + { TRACK_LIFT_HILL, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_CABLE_LIFT_HILL + { TRACK_WHOA_BELLY, TRACK_VANGLE_WHOA_BELLY, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_REVERSE_WHOA_BELLY_SLOPE { TRACK_WHOA_BELLY, TRACK_VANGLE_WHOA_BELLY, TRACK_VANGLE_WHOA_BELLY, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_REVERSE_WHOA_BELLY_VERTICAL - { TRACK_FLAT, TRACK_UP_90, TRACK_UP_90, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_90_DEG_UP - { TRACK_FLAT, TRACK_DOWN_90, TRACK_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_90_DEG_DOWN - { TRACK_FLAT, TRACK_UP_90, TRACK_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP_TO_90_DEG_UP - { TRACK_FLAT, TRACK_DOWN_60, TRACK_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_90_DEG_DOWN_TO_60_DEG_DOWN - { TRACK_FLAT, TRACK_UP_60, TRACK_UP_90, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_90_DEG_UP_TO_60_DEG_UP - { TRACK_FLAT, TRACK_DOWN_90, TRACK_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_DOWN_TO_90_DEG_DOWN - { TRACK_BRAKE_FOR_DROP, TRACK_DOWN_60, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_BRAKE_FOR_DROP - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_EIGHTH_TO_DIAG - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_EIGHTH_TO_DIAG - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_EIGHTH_TO_ORTHOGONAL - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_EIGHTH_TO_ORTHOGONAL - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_EIGHTH_BANK_TO_DIAG - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_EIGHTH_BANK_TO_DIAG - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_EIGHTH_BANK_TO_ORTHOGONAL - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_EIGHTH_BANK_TO_ORTHOGONAL - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_FLAT - { TRACK_FLAT, TRACK_UP_25, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_UP - { TRACK_FLAT, TRACK_UP_60, TRACK_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_60_DEG_UP - { TRACK_FLAT, TRACK_UP_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_FLAT_TO_25_DEG_UP - { TRACK_FLAT, TRACK_UP_60, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_UP_TO_60_DEG_UP - { TRACK_FLAT, TRACK_UP_25, TRACK_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_60_DEG_UP_TO_25_DEG_UP - { TRACK_FLAT, TRACK_NONE, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_UP_TO_FLAT - { TRACK_FLAT, TRACK_DOWN_25, TRACK_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_DOWN - { TRACK_FLAT, TRACK_DOWN_60, TRACK_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_60_DEG_DOWN - { TRACK_FLAT, TRACK_DOWN_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_FLAT_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_DOWN_60, TRACK_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_DOWN_TO_60_DEG_DOWN - { TRACK_FLAT, TRACK_DOWN_25, TRACK_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_60_DEG_DOWN_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_NONE, TRACK_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_DOWN_TO_FLAT - { TRACK_FLAT, TRACK_UP_60, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_FLAT_TO_60_DEG_UP - { TRACK_FLAT, TRACK_NONE, TRACK_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_60_DEG_UP_TO_FLAT - { TRACK_FLAT, TRACK_DOWN_60, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_FLAT_TO_60_DEG_DOWN - { TRACK_FLAT, TRACK_NONE, TRACK_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_60_DEG_DOWN_TO_FLAT - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_LEFT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_FLAT_TO_LEFT_BANK - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_RIGHT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_FLAT_TO_RIGHT_BANK - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_DIAG_LEFT_BANK_TO_FLAT - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_DIAG_RIGHT_BANK_TO_FLAT - { TRACK_FLAT, TRACK_UP_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_DIAG_LEFT_BANK_TO_25_DEG_UP - { TRACK_FLAT, TRACK_UP_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_DIAG_RIGHT_BANK_TO_25_DEG_UP - { TRACK_FLAT, TRACK_NONE, TRACK_UP_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_UP_TO_LEFT_BANK - { TRACK_FLAT, TRACK_NONE, TRACK_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_UP_TO_RIGHT_BANK - { TRACK_FLAT, TRACK_DOWN_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_DIAG_LEFT_BANK_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_DOWN_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_DIAG_RIGHT_BANK_TO_25_DEG_DOWN - { TRACK_FLAT, TRACK_NONE, TRACK_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_DOWN_TO_LEFT_BANK - { TRACK_FLAT, TRACK_NONE, TRACK_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_DOWN_TO_RIGHT_BANK - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_DIAG_LEFT_BANK - { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_DIAG_RIGHT_BANK - { TRACK_LOG_FLUME_REVERSER, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LOG_FLUME_REVERSER - { TRACK_SPINNING_TUNNEL, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_SPINNING_TUNNEL - { TRACK_BARREL_ROLL, TRACK_NONE, TRACK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_BARREL_ROLL_UP_TO_DOWN - { TRACK_BARREL_ROLL, TRACK_NONE, TRACK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_BARREL_ROLL_UP_TO_DOWN - { TRACK_BARREL_ROLL, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_NONE }, // ELEM_LEFT_BARREL_ROLL_DOWN_TO_UP - { TRACK_BARREL_ROLL, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_NONE }, // ELEM_RIGHT_BARREL_ROLL_DOWN_TO_UP - { TRACK_FLAT, TRACK_UP_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_BANK_TO_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP - { TRACK_FLAT, TRACK_UP_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_BANK_TO_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP - { TRACK_FLAT, TRACK_NONE, TRACK_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_LEFT_BANK - { TRACK_FLAT, TRACK_NONE, TRACK_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_RIGHT_BANK - { TRACK_POWERED_LIFT, TRACK_UP_25, TRACK_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_POWERED_LIFT - { TRACK_HALF_LOOP_2, TRACK_NONE, TRACK_UP_25, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_HALF_LOOP_UP }, // ELEM_LEFT_LARGE_HALF_LOOP_UP - { TRACK_HALF_LOOP_2, TRACK_NONE, TRACK_UP_25, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_HALF_LOOP_UP }, // ELEM_RIGHT_LARGE_HALF_LOOP_UP - { TRACK_HALF_LOOP_2, TRACK_DOWN_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_HALF_LOOP_DOWN }, // ELEM_RIGHT_LARGE_HALF_LOOP_DOWN - { 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 + { TRACK_FLAT, TRACK_SLOPE_UP_90, TRACK_SLOPE_UP_90, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_90_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_90_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_UP_90, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_UP_TO_90_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_90, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_90_DEG_DOWN_TO_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_90, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_90_DEG_UP_TO_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_DOWN_90, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_60_DEG_DOWN_TO_90_DEG_DOWN + { TRACK_BRAKE_FOR_DROP, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_BRAKE_FOR_DROP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_EIGHTH_TO_DIAG + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_EIGHTH_TO_DIAG + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_EIGHTH_TO_ORTHOGONAL + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_EIGHTH_TO_ORTHOGONAL + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_EIGHTH_BANK_TO_DIAG + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_EIGHTH_BANK_TO_DIAG + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_EIGHTH_BANK_TO_ORTHOGONAL + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_EIGHTH_BANK_TO_ORTHOGONAL + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_FLAT + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_FLAT_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_UP_TO_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_60_DEG_UP_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_UP_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_FLAT_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_DOWN_TO_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_60_DEG_DOWN_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_DOWN_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_UP_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_FLAT_TO_60_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_60_DEG_UP_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_DOWN_60, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_FLAT_TO_60_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_60, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_60_DEG_DOWN_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_FLAT_TO_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_FLAT_TO_RIGHT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_DIAG_LEFT_BANK_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_DIAG_RIGHT_BANK_TO_FLAT + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_DIAG_LEFT_BANK_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_DIAG_RIGHT_BANK_TO_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_UP_TO_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_UP_TO_RIGHT_BANK + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_DIAG_LEFT_BANK_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_DIAG_RIGHT_BANK_TO_25_DEG_DOWN + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_DOWN_TO_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_DIAG_25_DEG_DOWN_TO_RIGHT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_LEFT, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_DIAG_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_RIGHT, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_DIAG_RIGHT_BANK + { TRACK_LOG_FLUME_REVERSER, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LOG_FLUME_REVERSER + { TRACK_SPINNING_TUNNEL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_SPINNING_TUNNEL + { TRACK_BARREL_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_BARREL_ROLL_UP_TO_DOWN + { TRACK_BARREL_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_BARREL_ROLL_UP_TO_DOWN + { TRACK_BARREL_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_NONE }, // ELEM_LEFT_BARREL_ROLL_DOWN_TO_UP + { TRACK_BARREL_ROLL, TRACK_SLOPE_NONE, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_NONE }, // ELEM_RIGHT_BARREL_ROLL_DOWN_TO_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_LEFT, TRACK_NONE }, // ELEM_LEFT_BANK_TO_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_UP_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_RIGHT, TRACK_NONE }, // ELEM_RIGHT_BANK_TO_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_LEFT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_LEFT_BANK + { TRACK_FLAT, TRACK_SLOPE_NONE, TRACK_SLOPE_DOWN_25, TRACK_BANK_RIGHT, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_RIGHT_BANK + { TRACK_POWERED_LIFT, TRACK_SLOPE_UP_25, TRACK_SLOPE_UP_25, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_POWERED_LIFT + { TRACK_HALF_LOOP_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_HALF_LOOP_UP }, // ELEM_LEFT_LARGE_HALF_LOOP_UP + { TRACK_HALF_LOOP_LARGE, TRACK_SLOPE_NONE, TRACK_SLOPE_UP_25, TRACK_BANK_UPSIDE_DOWN, TRACK_BANK_NONE, TRACK_HALF_LOOP_UP }, // ELEM_RIGHT_LARGE_HALF_LOOP_UP + { TRACK_HALF_LOOP_LARGE, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_HALF_LOOP_DOWN }, // ELEM_RIGHT_LARGE_HALF_LOOP_DOWN + { TRACK_HALF_LOOP_LARGE, TRACK_SLOPE_DOWN_25, TRACK_SLOPE_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_HALF_LOOP_DOWN }, // ELEM_LEFT_LARGE_HALF_LOOP_DOWN }; +#define TRACK_MAX_SAVED_MAP_ELEMENTS 1500 + +rct_map_element **gTrackSavedMapElements = (rct_map_element**)0x00F63674; + 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); +static bool track_save_add_map_element(int interactionType, 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); @@ -271,33 +280,36 @@ static void track_list_query_directory(int *outTotalFiles){ platform_enumerate_files_end(enumFileHandle); } -static int track_list_cache_save(int fileCount, uint8* track_list_cache, uint32 track_list_size){ +static int track_list_cache_save(int fileCount, uint8* track_list_cache, uint32 track_list_size) +{ char path[MAX_PATH]; - FILE *file; + SDL_RWops *file; log_verbose("saving track list cache (tracks.idx)"); get_track_idx_path(path); - file = fopen(path, "wb"); + + file = SDL_RWFromFile(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); + SDL_RWwrite(file, &fileCount, sizeof(int), 1); + SDL_RWwrite(file, track_list_cache, track_list_size, 1); uint8 last_entry = 0xFE; - fwrite(&last_entry, 1, 1, file); - fclose(file); + SDL_RWwrite(file, &last_entry, 1, 1); + SDL_RWclose(file); return 1; } -static uint8* track_list_cache_load(int totalFiles){ +static uint8* track_list_cache_load(int totalFiles) +{ char path[MAX_PATH]; - FILE *file; + SDL_RWops *file; log_verbose("loading track list cache (tracks.idx)"); get_track_idx_path(path); - file = fopen(path, "rb"); + file = SDL_RWFromFile(path, "rb"); if (file == NULL) { log_error("Failed to load %s", path); return 0; @@ -306,19 +318,21 @@ static uint8* track_list_cache_load(int totalFiles){ uint8* track_list_cache; uint32 fileCount; // Remove 4 for the file count variable - long track_list_size = fsize(file) - 4; + long track_list_size = (long)SDL_RWsize(file) - 4; if (track_list_size < 0) return 0; - fread(&fileCount, 4, 1, file); - + SDL_RWread(file, &fileCount, 4, 1); + if (fileCount != totalFiles){ + SDL_RWclose(file); 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); + SDL_RWread(file, track_list_cache, track_list_size, 1); + SDL_RWclose(file); return track_list_cache; } @@ -327,7 +341,7 @@ void track_list_populate(ride_list_item item, uint8* 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_pointer += strlen((const char *)track_pointer) + 1, track_type = *track_pointer++){ rct_object_entry* track_object = (rct_object_entry*)track_pointer; track_pointer += sizeof(rct_object_entry); @@ -345,9 +359,8 @@ void track_list_populate(ride_list_item item, uint8* track_list_cache){ } 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)) + if ((GET_RIDE_ENTRY(entry_index)->flags & (RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME | RIDE_ENTRY_FLAG_SEPARATE_RIDE)) && + !rideTypeShouldLoseSeparateFlag(GET_RIDE_ENTRY(entry_index))) continue; } else{ @@ -366,7 +379,7 @@ void track_list_populate(ride_list_item item, uint8* track_list_cache){ 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){ + if (strcicmp((const char *)track_pointer, &RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, const char)[track_entry_index * 128]) < 0){ isBelow = 1; break; } @@ -374,17 +387,16 @@ void track_list_populate(ride_list_item item, uint8* track_list_cache){ 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], + &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); + strcpy(&RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, char)[track_entry_index * 128], (const char *)track_pointer); cur_track_entry_index++; } RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[cur_track_entry_index * 128] = '\0'; - free(track_list_cache); } /** @@ -397,13 +409,13 @@ void track_load_list(ride_list_item item) if (item.type < 0x80){ rct_ride_type* ride_type = gRideTypeList[item.entry_index]; - if (!(ride_type->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE)){ + if (!(ride_type->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) || rideTypeShouldLoseSeparateFlag(ride_type)){ item.entry_index = 0xFF; } } int totalFiles; - + track_list_query_directory(&totalFiles); uint8* track_list_cache; @@ -418,7 +430,10 @@ void track_load_list(ride_list_item item) int enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char)); if (enumFileHandle == INVALID_HANDLE) + { + free(new_file_pointer); return; + } while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { if (new_file_pointer > new_track_file + 0x3FF00)break; @@ -443,7 +458,7 @@ void track_load_list(ride_list_item item) new_file_pointer += sizeof(rct_object_entry); int file_name_length = strlen(enumFileInfo.path); - strcpy(new_file_pointer, enumFileInfo.path); + strcpy((char *)new_file_pointer, enumFileInfo.path); new_file_pointer += file_name_length + 1; } platform_enumerate_files_end(enumFileHandle); @@ -465,13 +480,13 @@ void track_load_list(ride_list_item item) free(track_list_cache); } -static void read(void *dst, char **src, int length) +static void copy(void *dst, uint8 **src, int length) { memcpy(dst, *src, length); *src += length; } -/* rct2: 0x00677530 +/* rct2: 0x00677530 * Returns 1 if it has booster track elements */ uint8 td4_track_has_boosters(rct_track_td6* track_design, uint8* track_elements){ @@ -495,31 +510,32 @@ uint8 td4_track_has_boosters(rct_track_td6* track_design, uint8* track_elements) */ rct_track_td6* load_track_design(const char *path) { - FILE *fp; - long fpLength; - char *fpBuffer, *decoded, *src; + SDL_RWops *fp; + int fpLength; + uint8 *fpBuffer, *decoded, *src; int i, decodedLength; uint8* edi; RCT2_GLOBAL(0x009AAC54, uint8) = 1; - - fp = fopen(path, "rb"); + + fp = SDL_RWFromFile(path, "rb"); if (fp == NULL) return 0; char* track_name_pointer = (char*)path; while (*track_name_pointer++ != '\0'); - while (*--track_name_pointer != '\\'); + const char separator = platform_get_path_separator(); + while (*--track_name_pointer != separator); 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); + fpLength = (int)SDL_RWsize(fp); fpBuffer = malloc(fpLength); - fread(fpBuffer, fpLength, 1, fp); - fclose(fp); + SDL_RWread(fp, fpBuffer, fpLength, 1); + SDL_RWclose(fp); // Validate the checksum // Not the same checksum algorithm as scenarios and saved games @@ -531,7 +547,11 @@ rct_track_td6* load_track_design(const char *path) // Decode the track data decoded = malloc(0x10000); decodedLength = sawyercoding_decode_td6(fpBuffer, decoded, fpLength); - realloc(decoded, decodedLength); + decoded = realloc(decoded, decodedLength); + if (decoded == NULL) { + log_error("failed to realloc"); + return 0; + } free(fpBuffer); rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); @@ -540,7 +560,7 @@ rct_track_td6* load_track_design(const char *path) // 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); + copy(track_design, &src, 32); uint8 version = track_design->version_and_colour_scheme >> 2; @@ -549,22 +569,23 @@ rct_track_td6* load_track_design(const char *path) return NULL; } - // In td6 there are 32 sets of two byte vehicle colour specifiers + // 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); + copy(&track_design->vehicle_colours[12], &src, 40); - read(&track_design->pad_48, &src, 24); + copy(&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); + copy(&track_design->track_spine_colour, &src, version == 1 ? 140 : 67); uint8* track_elements = RCT2_ADDRESS(0x9D821B, uint8); + int len = decodedLength - (src - decoded); // Read the actual track data. - read(track_elements, &src, 24572); - - uint8* final_track_element_location = track_elements + 24572; + copy(track_elements, &src, len); + + uint8* final_track_element_location = track_elements + len; free(decoded); // td4 files require some work to be recognised as td6. @@ -585,19 +606,19 @@ rct_track_td6* load_track_design(const char *path) track_element++; } memset(((uint8*)track_element) + 1, 255, final_track_element_location - (uint8*)track_element); - + } // 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]; + *edi = RCT1ColourConversionTable[*edi]; // 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]; + *edi = RCT1ColourConversionTable[*edi]; // Highest drop height is 1bit = 3/4 a meter in td6 // Highest drop height is 1bit = 1/3 a meter in td4 @@ -615,14 +636,16 @@ rct_track_td6* load_track_design(const char *path) 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; } } + // All TD4s that use powered launch use the type that doesn't pass the station. + if (track_design->ride_mode == RCT1_RIDE_MODE_POWERED_LAUNCH) + track_design->ride_mode = RIDE_MODE_POWERED_LAUNCH; + rct_object_entry* vehicle_object; if (track_design->type == RIDE_TYPE_MAZE) { vehicle_object = RCT2_ADDRESS(0x0097F66C, rct_object_entry); @@ -634,9 +657,14 @@ rct_track_td6* load_track_design(const char *path) } memcpy(&track_design->vehicle_object, vehicle_object, sizeof(rct_object_entry)); - for (i = 0; i < 32; i++) + for (i = 0; i < 32; i++) { track_design->vehicle_additional_colour[i] = track_design->vehicle_colours[i].trim_colour; + // RCT1 river rapids always had black seats. + if (track_design->type == RCT1_RIDE_TYPE_RIVER_RAPIDS) + track_design->vehicle_colours[i].trim_colour = 0; + } + track_design->space_required_x = 255; track_design->space_required_y = 255; track_design->lift_hill_speed_num_circuits = 5; @@ -663,7 +691,7 @@ void reset_track_list_cache(){ 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*)); @@ -688,7 +716,7 @@ int backup_map(){ *(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); + *(uint32*)(backup_info + 10) = get_current_rotation(); return 1; } @@ -1031,8 +1059,8 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o entry_type = 0xFF; entry_index = 0; - for (rct_path_type* path = g_pathTypeEntries[0]; - entry_index < object_entry_group_counts[OBJECT_TYPE_PATHS]; + 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) @@ -1111,7 +1139,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o RCT2_GLOBAL(0x00F44129, sint16) = z; } } - + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1 || RCT2_GLOBAL(0x00F440D4, uint8) == 2 || RCT2_GLOBAL(0x00F440D4, uint8) == 3 || @@ -1169,7 +1197,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 0xE9; if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0x80; - RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 1161; + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = STR_CANT_POSITION_THIS_HERE; cost = game_do_command( mapCoord.x, @@ -1228,15 +1256,15 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 105; if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0; - RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 1811; + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = STR_CANT_BUILD_PARK_ENTRANCE_HERE; cost = game_do_command( - mapCoord.x, - bl | (entry_index << 8), - mapCoord.y, - rotation | (scenery->primary_colour << 8), - GAME_COMMAND_41, - z, + mapCoord.x, + bl | (entry_index << 8), + mapCoord.y, + rotation | (scenery->primary_colour << 8), + GAME_COMMAND_PLACE_FENCE, + z, scenery->secondary_colour | ((scenery->flags & 0xFC) << 6) ); @@ -1268,8 +1296,8 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o 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); + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; + cost = game_do_command(mapCoord.x, bl | (bh << 8), mapCoord.y, z | (entry_index << 8), GAME_COMMAND_PLACE_PATH_FROM_TRACK, 0, 0); } else{ if (RCT2_GLOBAL(0x00F440D4, uint8) == 1) @@ -1281,13 +1309,13 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o continue; sub_6A7594(); - sub_6A6AA7(mapCoord.x, mapCoord.y, map_element); + footpath_remove_edges_at(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); + footpath_connect_edges(mapCoord.x, mapCoord.y, map_element, bl); sub_6A759F(); continue; } @@ -1321,11 +1349,11 @@ int track_place_maze(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac { if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ gMapSelectionTiles->x = -1; - RCT2_GLOBAL(0x009DEA48, sint16) = x; - RCT2_GLOBAL(0x009DEA4A, sint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_X, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_Y, 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(RCT2_ADDRESS_MAP_ARROW_Z, sint16) = map_element_height(x, y) & 0xFFFF; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_DIRECTION, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); } RCT2_GLOBAL(0x00F440D5, uint32) = 0; @@ -1387,7 +1415,7 @@ int track_place_maze(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac RCT2_GLOBAL(0x00F440D4, uint8) == 4 || RCT2_GLOBAL(0x00F440D4, uint8) == 5){ - uint8 bl; + uint8 bl; money32 cost = 0; uint16 maze_entry; @@ -1397,15 +1425,15 @@ int track_place_maze(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac rotation += maze->unk_2; rotation &= 3; - RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; 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); + cost = game_do_command(mapCoord.x, 0 | rotation << 8, mapCoord.y, (z / 16) & 0xFF, GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, -1, 0); } else{ - cost = game_do_command(mapCoord.x, bl | rotation << 8, mapCoord.y, rideIndex, GAME_COMMAND_12, 0, 0); + cost = game_do_command(mapCoord.x, bl | rotation << 8, mapCoord.y, rideIndex, GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, 0, 0); } if (cost != MONEY32_UNDEFINED){ RCT2_GLOBAL(0x00F4414E, uint8) |= (1 << 0); @@ -1416,15 +1444,15 @@ int track_place_maze(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac rotation += maze->unk_2; rotation &= 3; - RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; 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); + cost = game_do_command(mapCoord.x, 0 | rotation << 8, mapCoord.y, ((z / 16) & 0xFF) | (1 << 8), GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, -1, 0); } else{ - cost = game_do_command(mapCoord.x, bl | rotation << 8, mapCoord.y, rideIndex | (1 << 8), GAME_COMMAND_12, 0, 0); + cost = game_do_command(mapCoord.x, bl | rotation << 8, mapCoord.y, rideIndex | (1 << 8), GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, 0, 0); } if (cost != MONEY32_UNDEFINED){ RCT2_GLOBAL(0x00F4414E, uint8) |= (1 << 0); @@ -1438,9 +1466,9 @@ int track_place_maze(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 0x69; if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0; - RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; - cost = game_do_command(mapCoord.x, bl | (maze_entry & 0xFF) << 8, mapCoord.y, rideIndex | (maze_entry & 0xFF00), GAME_COMMAND_49, z, 0); + cost = game_do_command(mapCoord.x, bl | (maze_entry & 0xFF) << 8, mapCoord.y, rideIndex | (maze_entry & 0xFF00), GAME_COMMAND_PLACE_MAZE_DESIGN, z, 0); break; } @@ -1487,7 +1515,7 @@ int track_place_maze(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac } if (RCT2_GLOBAL(0x00F440D4, uint8) == 6){ - game_do_command(0, 0x69, 0, rideIndex, GAME_COMMAND_7, 0, 0); + game_do_command(0, 0x69, 0, rideIndex, GAME_COMMAND_DEMOLISH_RIDE, 0, 0); } RCT2_GLOBAL(0x00F44142, sint16) = x; @@ -1506,11 +1534,11 @@ int track_place_ride(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ gMapSelectionTiles->x = -1; - RCT2_GLOBAL(0x009DEA48, sint16) = x; - RCT2_GLOBAL(0x009DEA4A, sint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_X, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_Y, 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(RCT2_ADDRESS_MAP_ARROW_Z, sint16) = map_element_height(x, y) & 0xFFFF; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_DIRECTION, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); } RCT2_GLOBAL(0x00F440D5, uint32) = 0; @@ -1526,8 +1554,8 @@ int track_place_ride(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac 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; + for (const rct_preview_track* trackBlock = TrackBlocks[track_type]; + trackBlock->index != 0xFF; trackBlock++){ rct_xy16 tile; tile.x = x; @@ -1580,13 +1608,13 @@ int track_place_ride(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac //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 -= track_coordinates->z_begin; + const rct_preview_track* trackBlock = TrackBlocks[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); + game_do_command(x, 0x69 | ((rotation & 3) << 8), y, track_type, GAME_COMMAND_REMOVE_TRACK, temp_z, 0); } if (RCT2_GLOBAL(0x00F440D4, uint8) == 1 || @@ -1597,7 +1625,7 @@ int track_place_ride(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac //di int temp_z = z; - temp_z -= track_coordinates->z_negative; + temp_z -= track_coordinates->z_begin; uint32 edi = ((track->flags & 0xF) << 17) | ((track->flags & 0xF) << 28) | (((track->flags >> 4) & 0x3) << 24) | @@ -1613,8 +1641,8 @@ int track_place_ride(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac 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(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; + money32 cost = game_do_command(x, bl | (rotation << 8), y, edx, GAME_COMMAND_PLACE_TRACK, edi, 0); RCT2_GLOBAL(0x00F440D5, money32) += cost; if (cost == MONEY32_UNDEFINED){ @@ -1624,8 +1652,8 @@ int track_place_ride(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac } if (RCT2_GLOBAL(0x00F440D4, uint8) == 3){ - for (rct_preview_track* trackBlock = RCT2_ADDRESS(0x00994638, rct_preview_track*)[track_type]; - trackBlock->var_00 != 0xFF; + for (const rct_preview_track* trackBlock = TrackBlocks[track_type]; + trackBlock->index != 0xFF; trackBlock++){ rct_xy16 tile; tile.x = x; @@ -1711,12 +1739,12 @@ int track_place_ride(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac break; } - z -= track_coordinates->z_negative; - z += track_coordinates->z_positive; + z -= track_coordinates->z_begin; + z += track_coordinates->z_end; - rotation += track_coordinates->rotation_positive - track_coordinates->rotation_negative; + rotation += track_coordinates->rotation_end - track_coordinates->rotation_begin; rotation &= 3; - if (track_coordinates->rotation_positive & (1 << 2)) + if (track_coordinates->rotation_end & (1 << 2)) rotation |= (1 << 2); if (!(rotation & (1 << 2))){ @@ -1819,8 +1847,8 @@ int track_place_ride(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac 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(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; + money32 cost = game_do_command(x, bl | (rotation << 8), y, rideIndex | (is_exit << 8), GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, di, 0); RCT2_GLOBAL(0x00F440D5, money32) += cost; if (cost == MONEY32_UNDEFINED){ @@ -1838,8 +1866,8 @@ int track_place_ride(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac 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(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; + money32 cost = game_do_command(x, 0 | (rotation << 8), y, z | (is_exit << 8), GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, -1, 0); RCT2_GLOBAL(0x00F440D5, money32) += cost; if (cost == MONEY32_UNDEFINED){ @@ -1852,7 +1880,7 @@ int track_place_ride(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac } if (RCT2_GLOBAL(0x00F440D4, uint8) == 6){ - RCT2_CALLPROC_X(0x006CB945, 0, 0, 0, RCT2_GLOBAL(0x00F440A7, uint8), 0, 0, 0); + sub_6CB945(RCT2_GLOBAL(0x00F440A7, uint8)); rct_ride* ride = GET_RIDE(RCT2_GLOBAL(0x00F440A7, uint8)); user_string_free(ride->name); ride->type = RIDE_TYPE_NULL; @@ -1864,8 +1892,8 @@ int track_place_ride(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac } /** -* 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. +* 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, @@ -1943,7 +1971,7 @@ int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) return ebx; } -/* rct2: 0x006D2189 +/* rct2: 0x006D2189 * ebx = ride_id * cost = edi */ @@ -1951,23 +1979,23 @@ 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; + ebx = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_5; edx = track_design->type | (entry_index << 8); - esi = GAME_COMMAND_6; + esi = GAME_COMMAND_CREATE_RIDE; - if (MONEY32_UNDEFINED == game_do_command_p(GAME_COMMAND_6, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp)) return 1; + if (MONEY32_UNDEFINED == game_do_command_p(GAME_COMMAND_CREATE_RIDE, &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); + const utf8* ride_name = RCT2_ADDRESS(0x9E3504, const utf8); rct_string_id new_ride_name = user_string_allocate(132, ride_name); if (new_ride_name){ @@ -2081,7 +2109,7 @@ void draw_track_preview(uint8** preview){ width = height; int zoom_level = 1; - + if (width > 1120) zoom_level = 2; @@ -2113,7 +2141,7 @@ void draw_track_preview(uint8** preview){ dpi->width = 370; dpi->height = 217; dpi->pitch = 0; - dpi->bits = (char*)preview; + dpi->bits = (uint8*)preview; top = y; left = x; @@ -2172,7 +2200,7 @@ void draw_track_preview(uint8** preview){ } /** - * + * * I don't think preview is a necessary output argument. It can be obtained easily using the track design structure. * rct2: 0x006D1DEC */ @@ -2201,7 +2229,7 @@ rct_track_design *track_get_info(int index, uint8** preview) 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)); + subsitute_path(track_path, (char*)RCT2_ADDRESS_TRACKS_PATH, (char *)trackDesignList + (index * 128)); rct_track_td6* loaded_track = NULL; @@ -2221,7 +2249,6 @@ rct_track_design *track_get_info(int index, uint8** preview) 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->track_td6.cost = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_COST, money32); trackDesign->track_td6.track_flags = RCT2_GLOBAL(0x00F44151, uint8) & 7; @@ -2235,7 +2262,7 @@ rct_track_design *track_get_info(int index, uint8** preview) } /** - * + * * rct2: 0x006D3664 */ int track_rename(const char *text) @@ -2250,7 +2277,7 @@ int track_rename(const char *text) case '*': case '?': // Invalid characters - RCT2_GLOBAL(0x141E9AC, uint16) = 3353; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_NEW_NAME_CONTAINS_INVALID_CHARACTERS; return 0; } txt_chr++; @@ -2266,7 +2293,7 @@ int track_rename(const char *text) 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; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_ANOTHER_FILE_EXISTS_WITH_NAME_OR_FILE_IS_WRITE_PROTECTED; return 0; } @@ -2278,13 +2305,13 @@ int track_rename(const char *text) track_load_list(item); reset_track_list_cache(); - + window_invalidate(w); return 1; } /** - * + * * rct2: 0x006D3761 */ int track_delete() @@ -2295,7 +2322,7 @@ int track_delete() 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; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_FILE_IS_WRITE_PROTECTED_OR_LOCKED; return 0; } @@ -2324,7 +2351,7 @@ int track_is_connected_by_shape(rct_map_element *a, rct_map_element *b) 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 (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_3) { if (a->properties.track.colour & 4) { if (aBank == TRACK_BANK_NONE) aBank = TRACK_BANK_UPSIDE_DOWN; @@ -2337,7 +2364,7 @@ int track_is_connected_by_shape(rct_map_element *a, rct_map_element *b) 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 (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_3) { if (b->properties.track.colour & 4) { if (bBank == TRACK_BANK_NONE) bBank = TRACK_BANK_UPSIDE_DOWN; @@ -2425,7 +2452,7 @@ int copy_scenery_to_track(uint8** track_pointer){ y /= 32; if (x > 127 || y > 127 || x < -126 || y < -126){ - window_error_open(3346, 3347); + window_error_open(3346, STR_TRACK_TOO_LARGE_OR_TOO_MUCH_SCENERY); return 0; } @@ -2437,7 +2464,7 @@ int copy_scenery_to_track(uint8** track_pointer){ z /= 8; if (z > 127 || z < -126){ - window_error_open(3346, 3347); + window_error_open(3346, STR_TRACK_TOO_LARGE_OR_TOO_MUCH_SCENERY); return 0; } @@ -2455,7 +2482,7 @@ int copy_scenery_to_track(uint8** track_pointer){ /* rct2: 0x006CEAAE */ int maze_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* track_elements){ - rct_map_element* map_element; + rct_map_element* map_element = NULL; uint8 map_found = 0; sint16 start_x, start_y; @@ -2481,7 +2508,7 @@ int maze_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* track_ } if (map_found == 0){ - RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_TOO_LARGE_OR_TOO_MUCH_SCENERY; return 0; } @@ -2510,7 +2537,7 @@ int maze_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* track_ maze++; if (maze >= RCT2_ADDRESS(0x009DA151, rct_maze_element)){ - RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_TOO_LARGE_OR_TOO_MUCH_SCENERY; return 0; } } while (!map_element_is_last_for_tile(map_element++)); @@ -2523,7 +2550,7 @@ int maze_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* track_ uint16 location = ride->entrances[0]; if (location == 0xFFFF){ - RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_TOO_LARGE_OR_TOO_MUCH_SCENERY; return 0; } @@ -2554,7 +2581,7 @@ int maze_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* track_ location = ride->exits[0]; if (location == 0xFFFF){ - RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_TOO_LARGE_OR_TOO_MUCH_SCENERY; return 0; } @@ -2590,7 +2617,7 @@ int maze_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* track_ RCT2_GLOBAL(0x00F44058, uint8*) = track_elements; - // Previously you had to save start_x, y, z but + // Previously you had to save start_x, y, z but // no need since global vars not used sub_6D01B3(0, 0, 4096, 4096, 0); @@ -2615,31 +2642,34 @@ int maze_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* track_ } /* rct2: 0x006CE68D */ -int tracked_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* track_elements){ +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; + track_begin_end trackBeginEnd; if (sub_6CAF80(rideIndex, &trackElement) == 0){ - RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_TOO_LARGE_OR_TOO_MUCH_SCENERY; return 0; } int z = 0; - //6ce69e - if (!(sub_6C6402(&trackElement.element, &trackElement.x, &trackElement.y, &z))){ + // Find the start of the track. + // It has to do this as a backwards loop incase this is an incomplete track. + if (track_block_get_previous(trackElement.x, trackElement.y, trackElement.element, &trackBeginEnd)) { 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)){ + rct_xy_element lastGood = { + .element = trackBeginEnd.begin_element, + .x = trackBeginEnd.begin_x, + .y = trackBeginEnd.begin_y + }; + + if (!track_block_get_previous(trackBeginEnd.begin_x, trackBeginEnd.begin_y, trackBeginEnd.begin_element, &trackBeginEnd)) { + trackElement = lastGood; break; } - trackElement.x = x; - trackElement.y = y; - trackElement.element = map_element; - } while (initial_map != trackElement.element); + } while (initial_map != trackBeginEnd.begin_element); } z = trackElement.element->base_height * 8; @@ -2648,7 +2678,7 @@ int tracked_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* tra 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; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_TOO_LARGE_OR_TOO_MUCH_SCENERY; return 0; } @@ -2660,7 +2690,7 @@ int tracked_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* tra sint16 start_x = trackElement.x; sint16 start_y = trackElement.y; - sint16 start_z = z + trackCoordinates->z_negative; + sint16 start_z = z + trackCoordinates->z_begin; RCT2_GLOBAL(0x00F44142, sint16) = start_x; RCT2_GLOBAL(0x00F44144, sint16) = start_y; RCT2_GLOBAL(0x00F44146, sint16) = start_z; @@ -2710,7 +2740,7 @@ int tracked_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* tra track_design->flags |= (1 << 31); if (track->type == TRACK_ELEM_LOG_FLUME_REVERSER) - track_design->var_6C |= (1 << 1); + track_design->flags2 |= TRACK_FLAGS2_CONTAINS_LOG_FLUME_REVERSER; uint8 bh; if (track->type == TRACK_ELEM_BRAKES){ @@ -2720,18 +2750,20 @@ int tracked_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* tra bh = trackElement.element->properties.track.colour >> 4; } - uint8 flags = trackElement.element->type & (1 << 7) | bh; + 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)){ + if ( + RideData4[ride->type].flags & RIDE_TYPE_FLAG4_3 && + trackElement.element->properties.track.colour & (1 << 2) + ) { flags |= (1 << 6); } track->flags = flags; track++; - if (!track_get_next(&trackElement, &trackElement)) + if (!track_block_get_next(&trackElement, &trackElement, NULL, NULL)) break; z = trackElement.element->base_height * 8; @@ -2817,7 +2849,7 @@ int tracked_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* tra z /= 8; if (z > 127 || z < -126){ - RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_TOO_LARGE_OR_TOO_MUCH_SCENERY; return 0; } @@ -2875,7 +2907,7 @@ int ride_to_td6(uint8 rideIndex){ 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 + // 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)); @@ -2928,10 +2960,7 @@ int ride_to_td6(uint8 rideIndex){ 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); + track_design->flags2 = 0; uint8* track_elements = RCT2_ADDRESS(0x9D821B, uint8); memset(track_elements, 0, 8000); @@ -2946,25 +2975,26 @@ int ride_to_td6(uint8 rideIndex){ /* rct2: 0x006771DC but not really its branched from that * quite far. */ -int save_track_to_file(rct_track_td6* track_design, char* path){ +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); + int length = sawyercoding_encode_td6((uint8 *)track_design, track_file, 0x609F); - FILE *file; + SDL_RWops *file; log_verbose("saving track %s", path); - file = fopen(path, "wb"); + file = SDL_RWFromFile(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); + SDL_RWwrite(file, track_file, length, 1); + SDL_RWclose(file); free(track_file); return 1; @@ -2975,22 +3005,22 @@ 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)); + window_error_open(STR_CANT_SAVE_TRACK_DESIGN, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id)); return 0; } - if (ride->ratings.excitement == 0xFFFF){ - window_error_open(3346, RCT2_GLOBAL(0x141E9AC, rct_string_id)); + if (ride->ratings.excitement == (ride_rating)0xFFFF){ + window_error_open(STR_CANT_SAVE_TRACK_DESIGN, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, 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)); + window_error_open(STR_CANT_SAVE_TRACK_DESIGN, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id)); return 0; } if (!ride_to_td6(rideIndex)){ - window_error_open(3346, RCT2_GLOBAL(0x141E9AC, rct_string_id)); + window_error_open(STR_CANT_SAVE_TRACK_DESIGN, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id)); return 0; } @@ -3017,16 +3047,16 @@ int save_track_design(uint8 rideIndex){ // Track design files format_string(RCT2_ADDRESS(0x141EE68, char), 2305, NULL); - pause_sounds(); + audio_pause_sounds(); int result = platform_open_common_file_dialog( - 0, - RCT2_ADDRESS(0x141ED68, char), - path, - "*.TD?", + 0, + RCT2_ADDRESS(0x141ED68, char), + path, + "*.TD?", RCT2_ADDRESS(0x141EE68, char)); - unpause_sounds(); + audio_unpause_sounds(); if (result == 0){ ride_list_item item = { .type = 0xFD, .entry_index = 0 }; @@ -3034,6 +3064,8 @@ int save_track_design(uint8 rideIndex){ return 1; } + path_set_extension(path, "TD6"); + save_track_to_file(RCT2_ADDRESS(0x009D8178, rct_track_td6), path); ride_list_item item = { .type = 0xFC, .entry_index = 0 }; @@ -3111,20 +3143,24 @@ rct_track_design *temp_track_get_info(char* path, uint8** preview) return trackDesign; } -void window_track_list_format_name(char *dst, const char *src, char colour, char quotes) +void window_track_list_format_name(utf8 *dst, const utf8 *src, int colour, bool quotes) { - if (colour != 0) - *dst++ = colour; + const utf8 *ch; + int codepoint; - if (quotes != 0) - *dst++ = FORMAT_OPENQUOTES; - - while (*src != '.' && *src != 0) { - *dst++ = *src++; + if (colour != 0) { + dst = utf8_write_codepoint(dst, colour); } - if (quotes != 0) - *dst++ = FORMAT_ENDQUOTES; + if (quotes) dst = utf8_write_codepoint(dst, FORMAT_OPENQUOTES); + + ch = src; + while ((codepoint = utf8_get_next(ch, &ch)) != 0) { + if (codepoint == '.') break; + dst = utf8_write_codepoint(dst, codepoint); + } + + if (quotes) dst = utf8_write_codepoint(dst, FORMAT_ENDQUOTES); *dst = 0; } @@ -3167,23 +3203,23 @@ int install_track(char* source_path, char* dest_name){ // 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); + return platform_file_copy(source_path, dest_path, false); } /* rct2: 0x006D13FE */ -void game_command_place_track(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp){ +void game_command_place_track_design(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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, sint16) = x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, sint16) = y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, sint16) = z; - if (!(flags & (1 << 3))){ + if (!(flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED)){ 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; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; *ebx = MONEY32_UNDEFINED; return; } @@ -3200,17 +3236,17 @@ void game_command_place_track(int* eax, int* ebx, int* ecx, int* edx, int* esi, 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, + int _eax = 0, + _ebx = GAME_COMMAND_FLAG_APPLY, + _ecx = 0, + _edx = track_design->type | (entry_index << 8), + _esi = GAME_COMMAND_CREATE_RIDE, + _edi = 0, _ebp = 0; - game_do_command_p(GAME_COMMAND_6, &_eax, &_ebx, &_ecx, &_edx, &_esi, &_edi, &_ebp); + game_do_command_p(GAME_COMMAND_CREATE_RIDE, &_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(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION * 4; RCT2_GLOBAL(0x00F44121, money32) = MONEY32_UNDEFINED; return; } @@ -3228,7 +3264,7 @@ void game_command_place_track(int* eax, int* ebx, int* ecx, int* edx, int* esi, } else{ uint8 bl = 0; - if (flags & (1 << 6)){ + if (flags & GAME_COMMAND_FLAG_GHOST){ bl = 4; } else{ @@ -3238,26 +3274,26 @@ void game_command_place_track(int* eax, int* ebx, int* ecx, int* edx, int* esi, cost = sub_6D01B3(bl, rideIndex, x, y, z); } - if (cost == MONEY32_UNDEFINED || + 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); + rct_string_id error_reason = RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id); + game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, rideIndex, GAME_COMMAND_DEMOLISH_RIDE, 0, 0); *ebx = cost; - RCT2_GLOBAL(0x00141E9AC, rct_string_id) = error_reason; - RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = error_reason; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION * 4; 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 | (2 << 8), 0, rideIndex | (entry_index << 8), GAME_COMMAND_SET_RIDE_VEHICLES, 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 | (0 << 8), 0, rideIndex | (track_design->number_of_trains << 8), GAME_COMMAND_SET_RIDE_VEHICLES, 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 | (1 << 8), 0, rideIndex | (track_design->number_of_cars_per_train << 8), GAME_COMMAND_SET_RIDE_VEHICLES, 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); @@ -3275,11 +3311,7 @@ void game_command_place_track(int* eax, int* ebx, int* ecx, int* edx, int* esi, 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->lifecycle_flags |= RIDE_LIFECYCLE_NOT_CUSTOM_DESIGN; ride->colour_scheme_type = track_design->version_and_colour_scheme & 3; @@ -3288,7 +3320,7 @@ void game_command_place_track(int* eax, int* ebx, int* ecx, int* edx, int* esi, ride->entrance_style = track_design->entrance_style; } - if (version > 1){ + 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]; @@ -3311,26 +3343,467 @@ void game_command_place_track(int* eax, int* ebx, int* ecx, int* edx, int* esi, ride_set_name(rideIndex, RCT2_ADDRESS(0x009E3504,const char)); - RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION * 4; *ebx = RCT2_GLOBAL(0x00F44121, money32); *edi = rideIndex; } /** - * + * + * rct2: 0x006CDEE4 + */ +void game_command_place_maze_design(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + RCT2_CALLFUNC_X(0x006CDEE4, eax, ebx, ecx, edx, esi, edi, ebp); +} + +/** + * * 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; + gTrackSavedMapElements[0] = (rct_map_element*)0xFFFFFFFF; gfx_invalidate_screen(); } +static bool track_save_contains_map_element(rct_map_element *mapElement) +{ + rct_map_element **savedMapElement; + + savedMapElement = gTrackSavedMapElements; + do { + if (*savedMapElement == mapElement) { + return true; + } + } while (*savedMapElement++ != (rct_map_element*)-1); + return false; +} + +static int map_element_get_total_element_count(rct_map_element *mapElement) +{ + int elementCount; + rct_scenery_entry *sceneryEntry; + rct_large_scenery_tile *tile; + + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_PATH: + case MAP_ELEMENT_TYPE_SCENERY: + case MAP_ELEMENT_TYPE_FENCE: + return 1; + + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + sceneryEntry = g_largeSceneryEntries[mapElement->properties.scenerymultiple.type & 0x3FF]; + tile = sceneryEntry->large_scenery.tiles; + elementCount = 0; + do { + tile++; + elementCount++; + } while (tile->x_offset != (sint16)0xFFFF); + return elementCount; + + default: + return 0; + } +} + +static bool track_scenery_is_null(rct_track_scenery *trackScenery) +{ + return *((uint8*)trackScenery) == 0xFF; +} + +static void track_scenery_set_to_null(rct_track_scenery *trackScenery) +{ + *((uint8*)trackScenery) = 0xFF; +} + +static rct_map_element **track_get_next_spare_saved_map_element() +{ + rct_map_element **savedMapElement = gTrackSavedMapElements; + while (*savedMapElement != (rct_map_element*)0xFFFFFFFF) { + savedMapElement++; + } + return savedMapElement; +} + /** - * + * + * rct2: 0x006D2ED2 + */ +static bool track_save_can_add_map_element(rct_map_element *mapElement) +{ + int newElementCount = map_element_get_total_element_count(mapElement); + if (newElementCount == 0) { + return false; + } + + // Get number of saved elements so far + rct_map_element **savedMapElement = track_get_next_spare_saved_map_element(); + + // Get number of spare elements left + int numSavedElements = savedMapElement - gTrackSavedMapElements; + int spareSavedElements = TRACK_MAX_SAVED_MAP_ELEMENTS - numSavedElements; + if (newElementCount > spareSavedElements) { + // No more spare saved elements left + return false; + } + + // Probably checking for spare elements in the TD6 struct + rct_track_scenery *trackScenery = (rct_track_scenery*)0x009DA193; + while (!track_scenery_is_null(trackScenery)) { trackScenery++; } + if (trackScenery >= (rct_track_scenery*)0x9DE207) { + return false; + } + + return true; +} + +/** + * + * rct2: 0x006D2F4C + */ +static void track_save_push_map_element(int x, int y, rct_map_element *mapElement) +{ + rct_map_element **savedMapElement; + + map_invalidate_tile_full(x, y); + savedMapElement = track_get_next_spare_saved_map_element(); + *savedMapElement = mapElement; + *(savedMapElement + 1) = (rct_map_element*)0xFFFFFFFF; +} + +/** + * + * rct2: 0x006D2FA7 + */ +static void track_save_push_map_element_desc(rct_object_entry *entry, int x, int y, int z, uint8 flags, uint8 primaryColour, uint8 secondaryColour) +{ + rct_track_scenery *item = (rct_track_scenery*)0x009DA193; + while (!track_scenery_is_null(item)) { item++; } + + item->scenery_object = *entry; + item->x = x / 32; + item->y = y / 32; + item->z = z; + item->flags = flags; + item->primary_colour = primaryColour; + item->secondary_colour = secondaryColour; + + track_scenery_set_to_null(item + 1); +} + +static void track_save_add_scenery(int x, int y, rct_map_element *mapElement) +{ + int entryType = mapElement->properties.scenery.type; + rct_object_entry *entry = (rct_object_entry*)&object_entry_groups[OBJECT_TYPE_SMALL_SCENERY].entries[entryType]; + + uint8 flags = 0; + flags |= mapElement->type & 3; + flags |= (mapElement->type & 0xC0) >> 4; + + uint8 primaryColour = mapElement->properties.scenery.colour_1 & 0x1F; + uint8 secondaryColour = mapElement->properties.scenery.colour_2 & 0x1F; + + track_save_push_map_element(x, y, mapElement); + track_save_push_map_element_desc(entry, x, y, mapElement->base_height, flags, primaryColour, secondaryColour); +} + +static void track_save_add_large_scenery(int x, int y, rct_map_element *mapElement) +{ + rct_large_scenery_tile *sceneryTiles, *tile; + int x0, y0, z0, z; + int direction, sequence; + + int entryType = mapElement->properties.scenerymultiple.type & 0x3FF; + rct_object_entry *entry = (rct_object_entry*)&object_entry_groups[OBJECT_TYPE_LARGE_SCENERY].entries[entryType]; + sceneryTiles = g_largeSceneryEntries[entryType]->large_scenery.tiles; + + z = mapElement->base_height; + direction = mapElement->type & 3; + sequence = mapElement->properties.scenerymultiple.type >> 10; + + if (!map_large_scenery_get_origin(x, y, z, direction, sequence, &x0, &y0, &z0, NULL)) { + return; + } + + // Iterate through each tile of the large scenery element + sequence = 0; + for (tile = sceneryTiles; tile->x_offset != -1; tile++, sequence++) { + sint16 offsetX = tile->x_offset; + sint16 offsetY = tile->y_offset; + rotate_map_coordinates(&offsetX, &offsetY, direction); + + x = x0 + offsetX; + y = y0 + offsetY; + z = (z0 + tile->z_offset) / 8; + mapElement = map_get_large_scenery_segment(x, y, z, direction, sequence); + if (mapElement != NULL) { + if (sequence == 0) { + uint8 flags = mapElement->type & 3; + uint8 primaryColour = mapElement->properties.scenerymultiple.colour[0] & 0x1F; + uint8 secondaryColour = mapElement->properties.scenerymultiple.colour[1] & 0x1F; + + track_save_push_map_element_desc(entry, x, y, z, flags, primaryColour, secondaryColour); + } + track_save_push_map_element(x, y, mapElement); + } + } +} + +static void track_save_add_wall(int x, int y, rct_map_element *mapElement) +{ + int entryType = mapElement->properties.fence.type; + rct_object_entry *entry = (rct_object_entry*)&object_entry_groups[OBJECT_TYPE_WALLS].entries[entryType]; + + uint8 flags = 0; + flags |= mapElement->type & 3; + flags |= mapElement->properties.fence.item[0] << 2; + + uint8 secondaryColour = ((mapElement->flags & 0x60) >> 2) | (mapElement->properties.fence.item[1] >> 5); + uint8 primaryColour = mapElement->properties.fence.item[1] & 0x1F; + + track_save_push_map_element(x, y, mapElement); + track_save_push_map_element_desc(entry, x, y, mapElement->base_height, flags, primaryColour, secondaryColour); +} + +static void track_save_add_footpath(int x, int y, rct_map_element *mapElement) +{ + int entryType = mapElement->properties.path.type >> 4; + rct_object_entry *entry = (rct_object_entry*)&object_entry_groups[OBJECT_TYPE_PATHS].entries[entryType]; + + uint8 flags = 0; + flags |= mapElement->properties.path.edges & 0x0F; + flags |= (mapElement->properties.path.type & 4) << 2; + flags |= (mapElement->properties.path.type & 3) << 5; + flags |= (mapElement->type & 1) << 7; + + track_save_push_map_element(x, y, mapElement); + track_save_push_map_element_desc(entry, x, y, mapElement->base_height, flags, 0, 0); +} + +/** + * + * rct2: 0x006D2B3C + */ +static bool track_save_add_map_element(int interactionType, int x, int y, rct_map_element *mapElement) +{ + if (!track_save_can_add_map_element(mapElement)) { + return false; + } + + switch (interactionType) { + case VIEWPORT_INTERACTION_ITEM_SCENERY: + track_save_add_scenery(x, y, mapElement); + return true; + case VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY: + track_save_add_large_scenery(x, y, mapElement); + return true; + case VIEWPORT_INTERACTION_ITEM_WALL: + track_save_add_wall(x, y, mapElement); + return true; + case VIEWPORT_INTERACTION_ITEM_FOOTPATH: + track_save_add_footpath(x, y, mapElement); + return true; + default: + return false; + } +} + +/** + * + * rct2: 0x006D2F78 + */ +static void track_save_pop_map_element(int x, int y, rct_map_element *mapElement) +{ + map_invalidate_tile_full(x, y); + + // Find map element and total of saved elements + int removeIndex = -1; + int numSavedElements = 0; + rct_map_element **savedMapElement = gTrackSavedMapElements; + while (*savedMapElement != (rct_map_element*)0xFFFFFFFF) { + if (*savedMapElement == mapElement) { + removeIndex = numSavedElements; + } + savedMapElement++; + numSavedElements++; + } + + if (removeIndex == -1) { + return; + } + + // Remove item and shift rest up one item + if (removeIndex < numSavedElements - 1) { + memmove(&gTrackSavedMapElements[removeIndex], &gTrackSavedMapElements[removeIndex + 1], (numSavedElements - removeIndex - 1) * sizeof(rct_map_element*)); + } + gTrackSavedMapElements[numSavedElements - 1] = (rct_map_element*)0xFFFFFFFF; +} + +/** + * + * rct2: 0x006D2FDD + */ +static void track_save_pop_map_element_desc(rct_object_entry *entry, int x, int y, int z, uint8 flags, uint8 primaryColour, uint8 secondaryColour) +{ + int removeIndex = -1; + int totalItems = 0; + + rct_track_scenery *items = (rct_track_scenery*)0x009DA193; + rct_track_scenery *item = items; + for (; !track_scenery_is_null(item); item++, totalItems++) { + if (item->x != x / 32) continue; + if (item->y != y / 32) continue; + if (item->z != z) continue; + if (item->flags != flags) continue; + if (!object_entry_compare(&item->scenery_object, entry)) continue; + + removeIndex = totalItems; + } + + if (removeIndex == -1) { + return; + } + + // Remove item and shift rest up one item + if (removeIndex < totalItems - 1) { + memmove(&items[removeIndex], &items[removeIndex + 1], (totalItems - removeIndex - 1) * sizeof(rct_track_scenery)); + } + track_scenery_set_to_null(&items[totalItems - 1]); +} + +static void track_save_remove_scenery(int x, int y, rct_map_element *mapElement) +{ + int entryType = mapElement->properties.scenery.type; + rct_object_entry *entry = (rct_object_entry*)&object_entry_groups[OBJECT_TYPE_SMALL_SCENERY].entries[entryType]; + + uint8 flags = 0; + flags |= mapElement->type & 3; + flags |= (mapElement->type & 0xC0) >> 4; + + uint8 primaryColour = mapElement->properties.scenery.colour_1 & 0x1F; + uint8 secondaryColour = mapElement->properties.scenery.colour_2 & 0x1F; + + track_save_pop_map_element(x, y, mapElement); + track_save_pop_map_element_desc(entry, x, y, mapElement->base_height, flags, primaryColour, secondaryColour); +} + +static void track_save_remove_large_scenery(int x, int y, rct_map_element *mapElement) +{ + rct_large_scenery_tile *sceneryTiles, *tile; + int x0, y0, z0, z; + int direction, sequence; + + int entryType = mapElement->properties.scenerymultiple.type & 0x3FF; + rct_object_entry *entry = (rct_object_entry*)&object_entry_groups[OBJECT_TYPE_LARGE_SCENERY].entries[entryType]; + sceneryTiles = g_largeSceneryEntries[entryType]->large_scenery.tiles; + + z = mapElement->base_height; + direction = mapElement->type & 3; + sequence = mapElement->properties.scenerymultiple.type >> 10; + + if (!map_large_scenery_get_origin(x, y, z, direction, sequence, &x0, &y0, &z0, NULL)) { + return; + } + + // Iterate through each tile of the large scenery element + sequence = 0; + for (tile = sceneryTiles; tile->x_offset != -1; tile++, sequence++) { + sint16 offsetX = tile->x_offset; + sint16 offsetY = tile->y_offset; + rotate_map_coordinates(&offsetX, &offsetY, direction); + + x = x0 + offsetX; + y = y0 + offsetY; + z = (z0 + tile->z_offset) / 8; + mapElement = map_get_large_scenery_segment(x, y, z, direction, sequence); + if (mapElement != NULL) { + if (sequence == 0) { + uint8 flags = mapElement->type & 3; + uint8 primaryColour = mapElement->properties.scenerymultiple.colour[0] & 0x1F; + uint8 secondaryColour = mapElement->properties.scenerymultiple.colour[1] & 0x1F; + + track_save_pop_map_element_desc(entry, x, y, z, flags, primaryColour, secondaryColour); + } + track_save_pop_map_element(x, y, mapElement); + } + } +} + +static void track_save_remove_wall(int x, int y, rct_map_element *mapElement) +{ + int entryType = mapElement->properties.fence.type; + rct_object_entry *entry = (rct_object_entry*)&object_entry_groups[OBJECT_TYPE_WALLS].entries[entryType]; + + uint8 flags = 0; + flags |= mapElement->type & 3; + flags |= mapElement->properties.fence.item[0] << 2; + + uint8 secondaryColour = ((mapElement->flags & 0x60) >> 2) | (mapElement->properties.fence.item[1] >> 5); + uint8 primaryColour = mapElement->properties.fence.item[1] & 0x1F; + + track_save_pop_map_element(x, y, mapElement); + track_save_pop_map_element_desc(entry, x, y, mapElement->base_height, flags, primaryColour, secondaryColour); +} + +static void track_save_remove_footpath(int x, int y, rct_map_element *mapElement) +{ + int entryType = mapElement->properties.path.type >> 4; + rct_object_entry *entry = (rct_object_entry*)&object_entry_groups[OBJECT_TYPE_PATHS].entries[entryType]; + + uint8 flags = 0; + flags |= mapElement->properties.path.edges & 0x0F; + flags |= (mapElement->properties.path.type & 4) << 2; + flags |= (mapElement->properties.path.type & 3) << 5; + flags |= (mapElement->type & 1) << 7; + + track_save_pop_map_element(x, y, mapElement); + track_save_pop_map_element_desc(entry, x, y, mapElement->base_height, flags, 0, 0); +} + +/** + * + * rct2: 0x006D2B3C + */ +static void track_save_remove_map_element(int interactionType, int x, int y, rct_map_element *mapElement) +{ + switch (interactionType) { + case VIEWPORT_INTERACTION_ITEM_SCENERY: + track_save_remove_scenery(x, y, mapElement); + break; + case VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY: + track_save_remove_large_scenery(x, y, mapElement); + break; + case VIEWPORT_INTERACTION_ITEM_WALL: + track_save_remove_wall(x, y, mapElement); + break; + case VIEWPORT_INTERACTION_ITEM_FOOTPATH: + track_save_remove_footpath(x, y, mapElement); + break; + } +} + +/** + * + * rct2: 0x006D2B07 + */ +void track_save_toggle_map_element(int interactionType, int x, int y, rct_map_element *mapElement) +{ + if (track_save_contains_map_element(mapElement)) { + track_save_remove_map_element(interactionType, x, y, mapElement); + } else { + if (!track_save_add_map_element(interactionType, x, y, mapElement)) { + window_error_open( + STR_SAVE_TRACK_SCENERY_UNABLE_TO_SELECT_ADDITIONAL_ITEM_OF_SCENERY, + STR_SAVE_TRACK_SCENERY_TOO_MANY_ITEMS_SELECTED + ); + } + } +} + +/** + * * rct2: 0x006D303D */ void track_save_select_nearby_scenery(int rideIndex) @@ -3382,49 +3855,1024 @@ static void track_save_select_nearby_scenery_for_tile(int rideIndex, int cx, int for (int x = cx - 1; x <= cx + 1; x++) { mapElement = map_get_first_element_at(x, y); do { - int mapElementSelectType = 0; + int interactionType = VIEWPORT_INTERACTION_ITEM_NONE; switch (map_element_get_type(mapElement)) { case MAP_ELEMENT_TYPE_PATH: if (!(mapElement->type & 1)) - mapElementSelectType = 6; + interactionType = VIEWPORT_INTERACTION_ITEM_FOOTPATH; else if (mapElement->properties.path.addition_status == rideIndex) - mapElementSelectType = 6; + interactionType = VIEWPORT_INTERACTION_ITEM_FOOTPATH; break; case MAP_ELEMENT_TYPE_SCENERY: - mapElementSelectType = 5; + interactionType = VIEWPORT_INTERACTION_ITEM_SCENERY; break; case MAP_ELEMENT_TYPE_FENCE: - mapElementSelectType = 9; + interactionType = VIEWPORT_INTERACTION_ITEM_WALL; break; case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: - mapElementSelectType = 10; + interactionType = VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY; 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 (interactionType != VIEWPORT_INTERACTION_ITEM_NONE) { + if (!track_save_contains_map_element(mapElement)) { + track_save_add_map_element(interactionType, x * 32, y * 32, mapElement); } - - 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) +const rct_preview_track *get_track_def_from_ride(rct_ride *ride, int trackType) { - RCT2_CALLPROC_X(0x006D2B3C, x, mapElementSelectType, y, (int)mapElement, 0, 0, 0); + return ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE) ? + FlatRideTrackBlocks[trackType] : + TrackBlocks[trackType]; +} + +const rct_track_coordinates *get_track_coord_from_ride(rct_ride *ride, int trackType){ + return ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE) ? + &FlatTrackCoordinates[trackType] : + &TrackCoordinates[trackType]; +} + +const rct_preview_track *get_track_def_from_ride_index(int rideIndex, int trackType) +{ + return get_track_def_from_ride(GET_RIDE(rideIndex), trackType); +} + +/** + * + * rct2: 0x006C4D89 + */ +static bool sub_6C4D89(int x, int y, int z, int direction, int rideIndex, int flags) +{ + return !(RCT2_CALLPROC_X(0x006C4D89, x, flags | (rideIndex << 8), y, z | (direction << 8), 0, 0, 0) & 0x100); +} + +static money32 track_place(int rideIndex, int type, int originX, int originY, int originZ, int direction, int properties_1, int properties_2, int properties_3, int edx_flags, int flags) +{ + rct_ride *ride = GET_RIDE(rideIndex); + rct_ride_type *rideEntry = GET_RIDE_ENTRY(ride->subtype); + rct_map_element *mapElement; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION * 4; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = originX + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = originY + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = originZ; + direction &= 3; + RCT2_GLOBAL(0x00F441D5, uint32) = properties_1; + RCT2_GLOBAL(0x00F441D9, uint32) = properties_2; + RCT2_GLOBAL(0x00F441DD, uint32) = properties_3; + RCT2_GLOBAL(RCT2_ADDRESS_ABOVE_GROUND_FLAGS, uint8) = 0; + + uint64 enabledTrackPieces = 0; + enabledTrackPieces |= rideEntry->enabledTrackPiecesB & RCT2_ADDRESS(0x01357644, uint32)[ride->type]; + enabledTrackPieces <<= 32; + enabledTrackPieces |= rideEntry->enabledTrackPiecesA & RCT2_ADDRESS(0x01357444, uint32)[ride->type]; + uint32 rideTypeFlags = RCT2_GLOBAL(0x0097CF40 + (ride->type * 8), uint32); + RCT2_GLOBAL(0x00F44068, uint32) = rideTypeFlags; + + if ((ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) && type == 1) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_NOT_ALLOWED_TO_MODIFY_STATION; + return MONEY32_UNDEFINED; + } + if (!sub_68B044()) { + return MONEY32_UNDEFINED; + } + if (!(flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED)) { + 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 (type == TRACK_ELEM_ON_RIDE_PHOTO) { + if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_ONLY_ONE_ON_RIDE_PHOTO_PER_RIDE; + return MONEY32_UNDEFINED; + } + } + else if (type == TRACK_ELEM_CABLE_LIFT_HILL) { + if (ride->lifecycle_flags & RIDE_LIFECYCLE_16) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_ONLY_ONE_CABLE_LIFT_HILL_PER_RIDE; + return MONEY32_UNDEFINED; + } + } + + if ((edx_flags & (1 << 0)) && !(enabledTrackPieces & (1ULL << TRACK_LIFT_HILL_STEEP))) { + if (RCT2_ADDRESS(0x0099423C, uint16)[type] & 0x400) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_STEEP_FOR_LIFT_HILL; + return MONEY32_UNDEFINED; + } + } + + if (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE){ + RCT2_GLOBAL(0x00F44054, uint8*) = &RCT2_ADDRESS(0x0099AA94, uint8)[type * 16]; + } + else{ + RCT2_GLOBAL(0x00F44054, uint8*) = &RCT2_ADDRESS(0x00999A94, uint8)[type * 16]; + } + + money32 cost = 0; + const rct_preview_track *trackBlock = get_track_def_from_ride(ride, type); + + // First check if any of the track pieces are outside the park + for (; trackBlock->index != 0xFF; trackBlock++) { + int x, y, z, offsetX, offsetY; + + switch (direction) { + case 0: + offsetX = trackBlock->x; + offsetY = trackBlock->y; + break; + case 1: + offsetX = trackBlock->y; + offsetY = -trackBlock->x; + break; + case 2: + offsetX = -trackBlock->x; + offsetY = -trackBlock->y; + break; + case 3: + offsetX = -trackBlock->y; + offsetY = trackBlock->x; + break; + } + + x = originX + offsetX; + y = originY + offsetY; + z = originZ + trackBlock->z; + + if (!map_is_location_owned(x, y, z) && !gCheatsSandboxMode) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_LAND_NOT_OWNED_BY_PARK; + return MONEY32_UNDEFINED; + } + } + + uint16 *trackFlags = (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) ? + RCT2_ADDRESS(0x0099443C, uint16) : + RCT2_ADDRESS(0x0099423C, uint16); + if (trackFlags[type] & 0x100) { + if ((originZ & 0x0F) != 8) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = 954; + return MONEY32_UNDEFINED; + } + } else { + if ((originZ & 0x0F) != 0) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = 954; + return MONEY32_UNDEFINED; + } + } + + // If that is not the case, then perform the remaining checks + trackBlock = get_track_def_from_ride(ride, type); + + for (; trackBlock->index != 0xFF; trackBlock++, RCT2_GLOBAL(0x00F44054, uint8*)++) { + int x, y, z, offsetX, offsetY; + int bl = trackBlock->var_08; + int bh; + switch (direction) { + case 0: + offsetX = trackBlock->x; + offsetY = trackBlock->y; + break; + case 1: + offsetX = trackBlock->y; + offsetY = -trackBlock->x; + bl = rol8(bl, 1); + bh = bl; + bh = ror8(bh, 4); + bl &= 0xEE; + bh &= 0x11; + bl |= bh; + break; + case 2: + offsetX = -trackBlock->x; + offsetY = -trackBlock->y; + bl = rol8(bl, 2); + bh = bl; + bh = ror8(bh, 4); + bl &= 0xCC; + bh &= 0x33; + bl |= bh; + break; + case 3: + offsetX = -trackBlock->y; + offsetY = trackBlock->x; + bl = rol8(bl, 3); + bh = bl; + bh = ror8(bh, 4); + bl &= 0x88; + bh &= 0x77; + bl |= bh; + break; + } + x = originX + offsetX; + y = originY + offsetY; + z = originZ + trackBlock->z; + + if (z < 16) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_LOW; + return MONEY32_UNDEFINED; + } + + int baseZ = (originZ + trackBlock->z) / 8; + + int clearanceZ = trackBlock->var_07; + if (trackBlock->var_09 & (1 << 2) && RCT2_GLOBAL(0x0097D219 + (ride->type * 8), uint8) > 24){ + clearanceZ += 24; + } + else{ + clearanceZ += RCT2_GLOBAL(0x0097D219 + (ride->type * 8), uint8); + } + + clearanceZ = (clearanceZ / 8) + baseZ; + + if (clearanceZ >= 255) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_HIGH; + return MONEY32_UNDEFINED; + } + + _currentTrackEndX = x; + _currentTrackEndY = y; + + // Until 0x006C5A5F is implemented use this hacky struct. + struct{ + money32 cost; //0 + uint8 pad[0x10];//4 + uint8 flags;//14 + } clearance_struct; + clearance_struct.cost = cost; + clearance_struct.flags = flags; + + RCT2_GLOBAL(0x00F44060, void*) = &clearance_struct; + + if (!gCheatsDisableClearanceChecks || flags & GAME_COMMAND_FLAG_GHOST){ + if (!map_can_construct_with_clear_at(x, y, baseZ, clearanceZ, (void*)0x006C5A5F, bl)) + return MONEY32_UNDEFINED; + } + // Again when 0x006C5A5F implemented remove this. + cost = clearance_struct.cost; + + //6c53dc + // push baseZ and clearanceZ + int cur_z = baseZ * 8; + + if ((flags & GAME_COMMAND_FLAG_APPLY) && !(flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED)) { + footpath_remove_litter(x, y, z); + // push bl bh?? + if (rideTypeFlags & RIDE_TYPE_FLAG_18) { + map_remove_walls_at(x, y, baseZ * 8, clearanceZ * 8); + } + else { + uint8 _bl = *RCT2_GLOBAL(0x00F44054, uint8*); + _bl ^= 0x0F; + + for (int dl = bitscanforward(_bl); dl != -1; dl = bitscanforward(_bl)){ + _bl &= ~(1 << dl); + map_remove_intersecting_walls(x, y, baseZ, clearanceZ, direction & 3); + } + } + } + + bh = RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) & 3; + if (RCT2_GLOBAL(RCT2_ADDRESS_ABOVE_GROUND_FLAGS, uint8) != 0 && (RCT2_GLOBAL(RCT2_ADDRESS_ABOVE_GROUND_FLAGS, uint8) & bh) == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CANT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_GROUND; + return MONEY32_UNDEFINED; + } + + RCT2_GLOBAL(RCT2_ADDRESS_ABOVE_GROUND_FLAGS, uint8) = bh; + if (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) { + if (RCT2_ADDRESS(0x0099443C, uint16)[type] & 0x200) { + if (RCT2_GLOBAL(RCT2_ADDRESS_ABOVE_GROUND_FLAGS, uint8) & TRACK_ELEMENT_LOCATION_IS_UNDERGROUND) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + return MONEY32_UNDEFINED; + } + } + } + else { + if (RCT2_ADDRESS(0x0099423C, uint16)[type] & 0x200) { + if (RCT2_GLOBAL(RCT2_ADDRESS_ABOVE_GROUND_FLAGS, uint8) & TRACK_ELEMENT_LOCATION_IS_UNDERGROUND) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + return MONEY32_UNDEFINED; + } + } + } + + if (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) { + if (RCT2_ADDRESS(0x0099443C, uint16)[type] & 1) { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) & ELEMENT_IS_UNDERWATER)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CAN_ONLY_BUILD_THIS_UNDERWATER; + return MONEY32_UNDEFINED; + } + } + } + else { + if (RCT2_ADDRESS(0x0099423C, uint16)[type] & 1) { + if (RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) & ELEMENT_IS_UNDERWATER) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CAN_ONLY_BUILD_THIS_UNDERWATER; + return MONEY32_UNDEFINED; + } + } + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) & ELEMENT_IS_UNDERWATER) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_RIDE_CANT_BUILD_THIS_UNDERWATER; + return MONEY32_UNDEFINED; + } + + if ((rideTypeFlags & RIDE_TYPE_FLAG_6) && !(RCT2_GLOBAL(0x009D8150, uint8) & 1)) { + mapElement = map_get_surface_element_at(x / 32, y / 32); + + uint8 water_height = 2 * (mapElement->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK); + if (water_height == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CAN_ONLY_BUILD_THIS_ON_WATER; + return MONEY32_UNDEFINED; + } + + if (water_height != baseZ) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CAN_ONLY_BUILD_THIS_ON_WATER; + return MONEY32_UNDEFINED; + } + water_height -= 2; + if (water_height == mapElement->base_height) { + bh = mapElement->properties.surface.slope & 0x0F; + if (bh == 7 || bh == 11 || bh == 13 || bh == 14) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CAN_ONLY_BUILD_THIS_ON_WATER; + return MONEY32_UNDEFINED; + } + } + } + + int entranceDirections; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { + entranceDirections = RCT2_ADDRESS(0x0099CA64, uint8)[type * 16]; + } + else { + entranceDirections = RCT2_ADDRESS(0x0099BA64, uint8)[type * 16]; + } + if ((entranceDirections & 0x10) && trackBlock->index == 0) { + if (!sub_6C4D89(x, y, baseZ, direction, rideIndex, 0)) { + return MONEY32_UNDEFINED; + } + } + //6c55be + if (entranceDirections & 0x20) { + entranceDirections &= 0x0F; + if (entranceDirections != 0) { + if (!(flags & GAME_COMMAND_FLAG_APPLY) && !(flags & GAME_COMMAND_FLAG_GHOST)) { + uint8 _bl = entranceDirections; + for (int dl = bitscanforward(_bl); dl != -1; dl = bitscanforward(_bl)){ + _bl &= ~(1 << dl); + int temp_x = x, temp_y = y; + int temp_direction = (direction + dl) & 3; + temp_x += RCT2_ADDRESS(0x00993CCC, sint16)[temp_direction * 2]; + temp_y += RCT2_ADDRESS(0x00993CCE, sint16)[temp_direction * 2]; + temp_direction ^= (1 << 1); + map_remove_intersecting_walls(temp_x, temp_y, baseZ, clearanceZ, temp_direction & 3); + } + } + } + } + //6c5648 12 push + mapElement = map_get_surface_element_at(x / 32, y / 32); + if (!gCheatsDisableSupportLimits){ + int ride_height = clearanceZ - mapElement->base_height; + if (ride_height >= 0) { + int maxHeight = rideEntry->max_height; + if (maxHeight == 0) { + maxHeight = RCT2_GLOBAL(0x0097D218 + (ride->type * 8), uint8); + } + ride_height /= 2; + if (ride_height > maxHeight && !(RCT2_GLOBAL(0x009D8150, uint8) & 1)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_HIGH_FOR_SUPPORTS; + return MONEY32_UNDEFINED; + } + } + } + + int support_height = baseZ - mapElement->base_height; + if (support_height < 0) { + support_height = 10; + } + + cost += (support_height / 2) * RCT2_ADDRESS(0x0097DD7A, uint16)[ride->type * 2]; + //6c56d3 + + if (!(flags & GAME_COMMAND_FLAG_APPLY)) + continue; + + invalidate_test_results(rideIndex); + switch (type){ + case TRACK_ELEM_ON_RIDE_PHOTO: + ride->lifecycle_flags |= RIDE_LIFECYCLE_ON_RIDE_PHOTO; + break; + case TRACK_ELEM_CABLE_LIFT_HILL: + if (trackBlock->index != 0) + break; + ride->lifecycle_flags |= RIDE_LIFECYCLE_16; + ride->cable_lift_x = x; + ride->cable_lift_y = y; + ride->cable_lift_z = baseZ; + break; + case 0xD8: + ride->num_block_brakes++; + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_OPERATING; + ride->mode = RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED; + if (ride->type == RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER) + ride->mode = RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED; + break; + } + + if (trackBlock->index == 0){ + switch (type){ + case TRACK_ELEM_25_DEG_UP_TO_FLAT: + case TRACK_ELEM_60_DEG_UP_TO_FLAT: + case TRACK_ELEM_DIAG_25_DEG_UP_TO_FLAT: + case TRACK_ELEM_DIAG_60_DEG_UP_TO_FLAT: + if (!(edx_flags & 1)) + break; + //Fall Through + case TRACK_ELEM_CABLE_LIFT_HILL: + ride->num_block_brakes++; + break; + } + } + + entranceDirections = 0; + if (ride->overall_view != 0xFFFF){ + if (!(flags & GAME_COMMAND_FLAG_5)){ + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { + entranceDirections = RCT2_ADDRESS(0x0099CA64, uint8)[type * 16]; + } + else { + entranceDirections = RCT2_ADDRESS(0x0099BA64, uint8)[type * 16]; + } + } + } + if (entranceDirections & (1 << 4) || ride->overall_view == 0xFFFF){ + ride->overall_view = (x >> 5) | (y << 3); + } + + mapElement = map_element_insert(x / 32, y / 32, baseZ, bl & 0xF); + mapElement->clearance_height = clearanceZ; + + uint8 map_type = direction; + map_type |= MAP_ELEMENT_TYPE_TRACK; + if (edx_flags & 1){ + map_type |= (1 << 7); + } + mapElement->type = map_type; + + mapElement->properties.track.sequence = trackBlock->index; + mapElement->properties.track.ride_index = rideIndex; + mapElement->properties.track.type = type; + mapElement->properties.track.colour = 0; + if (flags & GAME_COMMAND_FLAG_GHOST){ + mapElement->flags |= MAP_ELEMENT_FLAG_GHOST; + } + + switch (type) { + case TRACK_ELEM_WATERFALL: + map_animation_create(MAP_ANIMATION_TYPE_TRACK_WATERFALL, x, y, mapElement->base_height); + break; + case TRACK_ELEM_RAPIDS: + map_animation_create(MAP_ANIMATION_TYPE_TRACK_RAPIDS, x, y, mapElement->base_height); + break; + case TRACK_ELEM_WHIRLPOOL: + map_animation_create(MAP_ANIMATION_TYPE_TRACK_WHIRLPOOL, x, y, mapElement->base_height); + break; + case TRACK_ELEM_SPINNING_TUNNEL: + map_animation_create(MAP_ANIMATION_TYPE_TRACK_SPINNINGTUNNEL, x, y, mapElement->base_height); + break; + } + if (type == TRACK_ELEM_BRAKES) { + mapElement->properties.track.sequence = (properties_1 >> 1) << 4; + } + else { + mapElement->properties.track.colour = properties_3 << 4; + } + + uint8 colour = properties_2; + if (edx_flags & (1 << 1)){ + colour |= (1 << 2); + } + mapElement->properties.track.colour |= colour; + + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { + entranceDirections = RCT2_ADDRESS(0x0099CA64, uint8)[type * 16]; + } + else { + entranceDirections = RCT2_ADDRESS(0x0099BA64, uint8)[type * 16]; + } + + if (entranceDirections & (1 << 4)) { + if (trackBlock->index == 0) { + sub_6C4D89(x, y, baseZ, direction, rideIndex, GAME_COMMAND_FLAG_APPLY); + } + sub_6CB945(rideIndex); + ride_update_max_vehicles(rideIndex); + } + + if (rideTypeFlags & RIDE_TYPE_FLAG_6){ + rct_map_element* surfaceElement = map_get_surface_element_at(x / 32, y / 32); + surfaceElement->type |= (1 << 6); + mapElement = surfaceElement; + } + + if (!gCheatsDisableClearanceChecks || !(flags & (1 << 6))) { + footpath_connect_edges(x, y, mapElement, flags); + } + map_invalidate_tile_full(x, y); + } + + money32 price = RCT2_ADDRESS(0x0097DD78, money16)[ride->type * 2]; + price *= (rideTypeFlags & RIDE_TYPE_FLAG_FLAT_RIDE) ? + RCT2_ADDRESS(0x0099DE34, money32)[type] : + RCT2_ADDRESS(0x0099DA34, money32)[type]; + + price >>= 16; + price = ((cost + price) / 2) * 10; + + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) { + return 0; + } + else { + return price; + } +} + +/** + * + * rct2: 0x006C511D + */ +void game_command_place_track(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + *ebx = track_place( + *edx & 0xFF, + (*edx >> 8) & 0xFF, + *eax & 0xFFFF, + *ecx & 0xFFFF, + *edi & 0xFFFF, + (*ebx >> 8) & 0xFF, + (*edi >> 16) & 0xFF, + (*edi >> 24) & 0x0F, + (*edi >> 28) & 0x0F, + (*edx >> 16), + *ebx & 0xFF + ); +} + +/** + * + * rct2: 0x006C494B + */ +static bool sub_6C494B(int x, int y, int z, int direction, int rideIndex, int flags) +{ + return !(RCT2_CALLPROC_X(0x006C494B, x, flags | (rideIndex << 8), y, z | (direction << 8), 0, 0, 0) & 0x100); +} + +money32 track_remove(uint8 type, uint8 sequence, sint16 originX, sint16 originY, sint16 originZ, uint8 rotation, uint8 flags){ + RCT2_GLOBAL(0x00141F56C, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, sint16) = originX + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, sint16) = originY + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, sint16) = originZ; + RCT2_GLOBAL(0x00F440E1, uint8) = sequence; + + switch (type){ + case TRACK_ELEM_BEGIN_STATION: + case TRACK_ELEM_MIDDLE_STATION: + type = TRACK_ELEM_END_STATION; + break; + } + + if (!(flags & (1 << 3)) && 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; + } + + uint8 found = 0; + rct_map_element* mapElement = map_get_first_element_at(originX / 32, originY / 32); + do{ + if (mapElement->base_height * 8 != originZ) + continue; + + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + + if ((mapElement->type & MAP_ELEMENT_DIRECTION_MASK) != rotation) + continue; + + if ((mapElement->properties.track.sequence & 0xF) != sequence) + continue; + + // Probably should add a check for ghost here as well! + + uint8 track_type = mapElement->properties.track.type; + switch (track_type){ + case TRACK_ELEM_BEGIN_STATION: + case TRACK_ELEM_MIDDLE_STATION: + track_type = TRACK_ELEM_END_STATION; + break; + } + + if (track_type != type) + continue; + + found = 1; + break; + } while (!map_element_is_last_for_tile(mapElement++)); + + if (!found){ + return MONEY32_UNDEFINED; + } + + if (mapElement->flags & (1 << 6)){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_YOU_ARE_NOT_ALLOWED_TO_REMOVE_THIS_SECTION; + return MONEY32_UNDEFINED; + } + + uint8 rideIndex = mapElement->properties.track.ride_index; + type = mapElement->properties.track.type; + RCT2_GLOBAL(0x00F44139, uint8) = type; + RCT2_GLOBAL(0x00F44138, uint8) = rideIndex; + RCT2_GLOBAL(0x00F4414C, uint8) = mapElement->type; + + rct_ride* ride = GET_RIDE(rideIndex); + const rct_preview_track* trackBlock = get_track_def_from_ride(ride, type); + trackBlock += mapElement->properties.track.sequence & 0xF; + + uint8 originDirection = mapElement->type & MAP_ELEMENT_DIRECTION_MASK; + switch (originDirection){ + case 0: + originX -= trackBlock->x; + originY -= trackBlock->y; + break; + case 1: + originX -= trackBlock->y; + originY += trackBlock->x; + break; + case 2: + originX += trackBlock->x; + originY += trackBlock->y; + break; + case 3: + originX += trackBlock->y; + originY -= trackBlock->x; + break; + } + + originZ -= trackBlock->z; + + money32 cost = 0; + + trackBlock = get_track_def_from_ride(ride, type); + for (; trackBlock->index != 255; trackBlock++){ + sint16 x = originX, y = originY, z = originZ; + + switch (originDirection){ + case 0: + x += trackBlock->x; + y += trackBlock->y; + break; + case 1: + x += trackBlock->y; + y -= trackBlock->x; + break; + case 2: + x -= trackBlock->x; + y -= trackBlock->y; + break; + case 3: + x -= trackBlock->y; + y += trackBlock->x; + break; + } + + z += trackBlock->z; + + map_invalidate_tile_full(x, y); + RCT2_GLOBAL(0x00F441C4, sint16) = x; + RCT2_GLOBAL(0x00F441C6, sint16) = y; + + found = 0; + mapElement = map_get_first_element_at(x / 32, y / 32); + do{ + if (mapElement->base_height != z / 8) + continue; + + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + + if ((mapElement->type & MAP_ELEMENT_DIRECTION_MASK) != rotation) + continue; + + if ((mapElement->properties.track.sequence & 0xF) != trackBlock->index) + continue; + + if (mapElement->properties.track.type != type) + continue; + + found = 1; + break; + } while (!map_element_is_last_for_tile(mapElement++)); + + if (!found){ + log_error("Track map element part not found!"); + return MONEY32_UNDEFINED; + } + + int entranceDirections; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { + entranceDirections = RCT2_ADDRESS(0x0099CA64, uint8)[type * 16]; + } + else { + entranceDirections = RCT2_ADDRESS(0x0099BA64, uint8)[type * 16]; + } + + if (entranceDirections & (1 << 4) && ((mapElement->properties.track.sequence & 0xF) == 0)){ + if (!sub_6C494B(x, y, z / 8, rotation, rideIndex, 0)) { + return MONEY32_UNDEFINED; + } + } + + rct_map_element* surfaceElement = map_get_surface_element_at(x / 32, y / 32); + if (surfaceElement == NULL){ + return MONEY32_UNDEFINED; + } + + sint8 support_height = mapElement->base_height - surfaceElement->base_height; + if (support_height < 0){ + support_height = 10; + } + + cost += (support_height / 2) * RCT2_ADDRESS(0x0097DD7A, uint16)[ride->type * 2]; + + if (!(flags & GAME_COMMAND_FLAG_APPLY)) + continue; + + if (entranceDirections & (1 << 4) && ((mapElement->properties.track.sequence & 0xF) == 0)){ + if (!sub_6C494B(x, y, z / 8, rotation, rideIndex, GAME_COMMAND_FLAG_APPLY)) { + return MONEY32_UNDEFINED; + } + } + + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_6)){ + surfaceElement->type &= ~(1 << 6); + } + + invalidate_test_results(rideIndex); + sub_6A7594(); + if (!gCheatsDisableClearanceChecks || !(mapElement->flags & MAP_ELEMENT_FLAG_GHOST)) { + footpath_remove_edges_at(x, y, mapElement); + } + map_element_remove(mapElement); + sub_6CB945(rideIndex); + if (!(flags & (1 << 6))){ + ride_update_max_vehicles(rideIndex); + } + } + + if (flags & GAME_COMMAND_FLAG_APPLY){ + switch (type){ + case TRACK_ELEM_ON_RIDE_PHOTO: + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_ON_RIDE_PHOTO; + break; + case TRACK_ELEM_CABLE_LIFT_HILL: + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_16; + break; + case 216: + ride->num_block_brakes--; + if (ride->num_block_brakes == 0){ + ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_OPERATING; + ride->mode = RIDE_MODE_CONTINUOUS_CIRCUIT; + if (ride->type == RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER){ + ride->mode = RIDE_MODE_POWERED_LAUNCH; + } + } + break; + } + + switch (type){ + case TRACK_ELEM_25_DEG_UP_TO_FLAT: + case TRACK_ELEM_60_DEG_UP_TO_FLAT: + case TRACK_ELEM_DIAG_25_DEG_UP_TO_FLAT: + case TRACK_ELEM_DIAG_60_DEG_UP_TO_FLAT: + if (!(RCT2_GLOBAL(0x00F4414C, uint8) & (1 << 7))) + break; + // Fall through + case TRACK_ELEM_CABLE_LIFT_HILL: + ride->num_block_brakes--; + break; + } + } + + money32 price = RCT2_ADDRESS(0x0097DD78, money16)[ride->type * 2];; + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { + price *= RCT2_ADDRESS(0x0099DE34, money32)[type]; + } + else { + price *= RCT2_ADDRESS(0x0099DA34, money32)[type]; + } + price >>= 16; + price = (price + cost) / 2; + if (ride->lifecycle_flags & RIDE_LIFECYCLE_EVER_BEEN_OPENED) + price *= -7; + else + price *= -10; + + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) + return 0; + else + return price; +} + +/** + * + * rct2: 0x006C5B69 + */ +void game_command_remove_track(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + *ebx = track_remove( + *edx & 0xFF, + (*edx >> 8) & 0xFF, + *eax & 0xFFFF, + *ecx & 0xFFFF, + *edi & 0xFFFF, + (*ebx >> 8) & 0xFF, + *ebx & 0xFF + ); + return; +} + +/** + * + * rct2: 0x006CD8CE + */ +void game_command_set_maze_track(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + RCT2_CALLFUNC_X(0x006CD8CE, eax, ebx, ecx, edx, esi, edi, ebp); +} + +/** + * + * rct2: 0x006C5AE9 + */ +void game_command_set_brakes_speed(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + rct_map_element *mapElement; + int x, y, z, trackType, brakesSpeed; + + x = (*eax & 0xFFFF); + y = (*ecx & 0xFFFF); + z = (*edi & 0xFFFF); + trackType = (*edx & 0xFF); + brakesSpeed = ((*ebx >> 8) & 0xFF); + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION * 4; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint8) = x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint8) = y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint8) = z; + + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + *ebx = 0; + return; + } + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (mapElement->base_height * 8 != z) + continue; + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + if (mapElement->properties.track.type != trackType) + continue; + + mapElement->properties.track.sequence = + (mapElement->properties.track.sequence & 0x0F) | + ((brakesSpeed >> 1) << 4); + + break; + } while (!map_element_is_last_for_tile(mapElement++)); + + *ebx = 0; +} + +void track_circuit_iterator_begin(track_circuit_iterator *it, rct_xy_element first) +{ + it->last = first; + it->first = NULL; + it->firstIteration = true; + it->looped = false; +} + +bool track_circuit_iterator_previous(track_circuit_iterator *it) +{ + track_begin_end trackBeginEnd; + + if (it->first == NULL) { + if (!track_block_get_previous(it->last.x, it->last.y, it->last.element, &trackBeginEnd)) + return false; + + it->current.x = trackBeginEnd.begin_x; + it->current.y = trackBeginEnd.begin_y; + it->current.element = trackBeginEnd.begin_element; + it->currentZ = trackBeginEnd.begin_z; + it->currentDirection = trackBeginEnd.begin_direction; + + it->first = it->current.element; + return true; + } else { + if (!it->firstIteration && it->first == it->current.element) { + it->looped = true; + return false; + } + + it->firstIteration = false; + it->last = it->current; + + if (track_block_get_previous(it->last.x, it->last.y, it->last.element, &trackBeginEnd)) { + it->current.x = trackBeginEnd.end_x; + it->current.y = trackBeginEnd.end_y; + it->current.element = trackBeginEnd.begin_element; + it->currentZ = trackBeginEnd.begin_z; + it->currentDirection = trackBeginEnd.begin_direction; + return true; + } else { + return false; + } + } +} + +bool track_circuit_iterator_next(track_circuit_iterator *it) +{ + if (it->first == NULL) { + if (!track_block_get_next(&it->last, &it->current, &it->currentZ, &it->currentDirection)) + return false; + + it->first = it->current.element; + return true; + } else { + if (!it->firstIteration && it->first == it->current.element) { + it->looped = true; + return false; + } + + it->firstIteration = false; + it->last = it->current; + return track_block_get_next(&it->last, &it->current, &it->currentZ, &it->currentDirection); + } +} + +void track_get_back(rct_xy_element *input, rct_xy_element *output) +{ + rct_xy_element lastTrack; + track_begin_end currentTrack; + bool result; + + lastTrack = *input; + do { + result = track_block_get_previous(lastTrack.x, lastTrack.y, lastTrack.element, ¤tTrack); + if (result) { + lastTrack.x = currentTrack.begin_x; + lastTrack.y = currentTrack.begin_y; + lastTrack.element = currentTrack.begin_element; + } + } while (result); + *output = lastTrack; +} + +void track_get_front(rct_xy_element *input, rct_xy_element *output) +{ + rct_xy_element lastTrack, currentTrack; + int z, direction; + bool result; + + lastTrack = *input; + do { + result = track_block_get_next(&lastTrack, ¤tTrack, &z, &direction); + if (result) { + lastTrack = currentTrack; + } + } while (result); + *output = lastTrack; +} + +bool track_element_is_lift_hill(rct_map_element *trackElement) +{ + return trackElement->type & 0x80; +} + +bool track_element_is_cable_lift(rct_map_element *trackElement) { + return trackElement->properties.track.colour & TRACK_ELEMENT_COLOUR_FLAG_CABLE_LIFT; +} + +void track_element_set_cable_lift(rct_map_element *trackElement) { + trackElement->properties.track.colour |= TRACK_ELEMENT_COLOUR_FLAG_CABLE_LIFT; +} + +void track_element_clear_cable_lift(rct_map_element *trackElement) { + trackElement->properties.track.colour &= ~TRACK_ELEMENT_COLOUR_FLAG_CABLE_LIFT; } diff --git a/src/ride/track.h b/src/ride/track.h index dc5e8acb64..5690767666 100644 --- a/src/ride/track.h +++ b/src/ride/track.h @@ -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 . *****************************************************************************/ @@ -39,15 +39,25 @@ typedef struct { * Size: 0x0A */ typedef struct { - uint8 var_00; + uint8 index; // 0x00 sint16 x; // 0x01 sint16 y; // 0x03 - sint16 z; - uint8 pad_07; + sint16 z; // 0x05 + uint8 var_07; uint8 var_08; uint8 var_09; } rct_preview_track; +/* size 0x0A */ +typedef struct{ + sint8 rotation_begin; // 0x00 + sint8 rotation_end; // 0x01 + sint16 z_begin; // 0x02 + sint16 z_end; // 0x04 + sint16 x; // 0x06 + sint16 y; // 0x08 +}rct_track_coordinates; + /** * Size: 0x04 */ @@ -99,6 +109,12 @@ enum{ TRACK_ELEMENT_FLAG_TERMINAL_STATION = (1<<3), }; +enum { + // Not anything to do with colour but uses + // that field in the map element + TRACK_ELEMENT_COLOUR_FLAG_CABLE_LIFT = (1 << 3), +}; + #define TRACK_ELEMENT_FLAG_MAGNITUDE_MASK 0x0F #define TRACK_ELEMENT_FLAG_COLOUR_MASK 0x30 #define TRACK_ELEMENT_FLAG_STATION_NO_MASK 0x02 @@ -119,7 +135,7 @@ typedef struct { uint32 flags; // 0x02 }; union{ - // After loading the track this is converted to + // After loading the track this is converted to // a flags register uint8 ride_mode; // 0x06 uint8 track_flags; // 0x06 @@ -163,7 +179,7 @@ typedef struct { uint8 track_spine_colour[4]; // 0x60 uint8 track_rail_colour[4]; // 0x64 uint8 track_support_colour[4]; // 0x68 - uint32 var_6C; + uint32 flags2; // 0x6C rct_object_entry vehicle_object; // 0x70 uint8 space_required_x; // 0x80 uint8 space_required_y; // 0x81 @@ -176,45 +192,95 @@ typedef struct{ uint8 preview[4][TRACK_PREVIEW_IMAGE_SIZE]; // 0xA3 } rct_track_design; +enum { + TRACK_FLAGS2_CONTAINS_LOG_FLUME_REVERSER = (1 << 1), + TRACK_FLAGS2_SIX_FLAGS_RIDE_DEPRECATED = (1 << 31) // Not used anymore. +}; enum { TRACK_NONE = 0, TRACK_FLAT = 0, - TRACK_STATION_END = 2, - TRACK_VERTICAL_LOOP = 7, - TRACK_S_BEND = 13, - TRACK_TWIST = 17, - TRACK_HALF_LOOP = 18, - TRACK_CORKSCREW = 19, - TRACK_TOWER_BASE = 20, - TRACK_HELIX_SMALL= 21, - TRACK_HELIX_LARGE= 22, - TRACK_HELIX_LARGE_UNBANKED = 23, - TRACK_BRAKES = 24, - TRACK_ON_RIDE_PHOTO = 26, - TRACK_WATER_SPLASH = 27, - TRACK_BARREL_ROLL = 29, - TRACK_POWERED_LIFT = 30, - TRACK_HALF_LOOP_2 = 31, // ? - TRACK_LOG_FLUME_REVERSER = 33, - TRACK_WHOA_BELLY = 36, - TRACK_LIFT_HILL = 43, - TRACK_SPINNING_TUNNEL = 46, - TRACK_ROTATION_CONTROL_TOGGLE = 47, - TRACK_RAPIDS = 52, + TRACK_STRAIGHT, + TRACK_STATION_END, + TRACK_LIFT_HILL, + TRACK_LIFT_HILL_STEEP, + TRACK_LIFT_HILL_CURVE, + TRACK_FLAT_ROLL_BANKING, + TRACK_VERTICAL_LOOP, + TRACK_SLOPE, + TRACK_SLOPE_STEEP, + TRACK_SLOPE_LONG, + TRACK_SLOPE_CURVE, + TRACK_SLOPE_CURVE_STEEP, + TRACK_S_BEND, + TRACK_CURVE_VERY_SMALL, + TRACK_CURVE_SMALL, + TRACK_CURVE, + TRACK_TWIST, + TRACK_HALF_LOOP, + TRACK_CORKSCREW, + TRACK_TOWER_BASE, + TRACK_HELIX_SMALL, + TRACK_HELIX_LARGE, + TRACK_HELIX_LARGE_UNBANKED, + TRACK_BRAKES, + TRACK_25, + TRACK_ON_RIDE_PHOTO, + TRACK_WATER_SPLASH, + TRACK_SLOPE_VERTICAL, + TRACK_BARREL_ROLL, + TRACK_POWERED_LIFT, + TRACK_HALF_LOOP_LARGE, + TRACK_SLOPE_CURVE_BANKED, + TRACK_LOG_FLUME_REVERSER, + TRACK_HEARTLINE_ROLL, + TRACK_REVERSER, + TRACK_WHOA_BELLY, + TRACK_SLOPE_TO_FLAT, + TRACK_BLOCK_BRAKES, + TRACK_SLOPE_ROLL_BANKING, + TRACK_SLOPE_STEEP_LONG, + TRACK_CURVE_VERTICAL, + TRACK_42, + TRACK_LIFT_HILL_CABLE, + TRACK_LIFT_HILL_CURVED, + TRACK_QUARTER_LOOP, + TRACK_SPINNING_TUNNEL, + TRACK_ROTATION_CONTROL_TOGGLE, + TRACK_INLINE_TWIST_UNINVERTED, + TRACK_INLINE_TWIST_INVERTED, + TRACK_QUARTER_LOOP_UNINVERTED, + TRACK_QUARTER_LOOP_INVERTED, + TRACK_RAPIDS, + TRACK_HALF_LOOP_UNINVERTED, + TRACK_HALF_LOOP_INVERTED, + TRACK_WATERFALL = 152, TRACK_WHIRLPOOL = 152, TRACK_BRAKE_FOR_DROP = 172 }; enum { - TRACK_UP_25 = 2, - TRACK_UP_60 = 4, - TRACK_DOWN_25 = 6, - TRACK_DOWN_60 = 8, - TRACK_UP_90 = 10, - TRACK_DOWN_90 = 18, + TRACK_CURVE_LEFT_VERY_SMALL = 5, + TRACK_CURVE_LEFT_SMALL = 3, + TRACK_CURVE_LEFT = 1, + TRACK_CURVE_LEFT_LARGE = 7, + TRACK_CURVE_NONE = 0, + TRACK_CURVE_RIGHT_LARGE = 8, + TRACK_CURVE_RIGHT = 2, + TRACK_CURVE_RIGHT_SMALL = 4, + TRACK_CURVE_RIGHT_VERY_SMALL = 6 +}; + +enum { + TRACK_SLOPE_NONE = 0, + TRACK_SLOPE_UP_25 = 2, + TRACK_SLOPE_UP_60 = 4, + TRACK_SLOPE_DOWN_25 = 6, + TRACK_SLOPE_DOWN_60 = 8, + TRACK_SLOPE_UP_90 = 10, + TRACK_SLOPE_DOWN_90 = 18, TRACK_VANGLE_TOWER = 10, TRACK_VANGLE_WHOA_BELLY = 10 @@ -424,8 +490,25 @@ enum { TRACK_ELEM_LEFT_LARGE_HALF_LOOP_DOWN }; +enum { + TRACK_ELEMENT_LOCATION_IS_UNDERGROUND = 2, +}; + +typedef struct { + rct_xy_element last; + rct_xy_element current; + int currentZ; + int currentDirection; + rct_map_element *first; + bool firstIteration; + bool looped; +} track_circuit_iterator; + +extern const rct_trackdefinition *gFlatRideTrackDefinitions; extern const rct_trackdefinition *gTrackDefinitions; +extern rct_map_element **gTrackSavedMapElements; + void track_load_list(ride_list_item item); int sub_67726A(const char *path); rct_track_design *track_get_info(int index, uint8** preview); @@ -439,10 +522,34 @@ 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); +void window_track_list_format_name(utf8 *dst, const utf8 *src, int colour, bool quotes); +void game_command_place_track_design(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_place_maze_design(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); void track_save_reset_scenery(); void track_save_select_nearby_scenery(int rideIndex); +void track_save_toggle_map_element(int interactionType, int x, int y, rct_map_element *mapElement); + +const rct_preview_track *get_track_def_from_ride(rct_ride *ride, int trackType); +const rct_preview_track *get_track_def_from_ride_index(int rideIndex, int trackType); +const rct_track_coordinates *get_track_coord_from_ride(rct_ride *ride, int trackType); + +void game_command_place_track(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_remove_track(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_set_maze_track(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_set_brakes_speed(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); + +void track_circuit_iterator_begin(track_circuit_iterator *it, rct_xy_element first); +bool track_circuit_iterator_previous(track_circuit_iterator *it); +bool track_circuit_iterator_next(track_circuit_iterator *it); + +void track_get_back(rct_xy_element *input, rct_xy_element *output); +void track_get_front(rct_xy_element *input, rct_xy_element *output); + +bool track_element_is_lift_hill(rct_map_element *trackElement); + +bool track_element_is_cable_lift(rct_map_element *trackElement); +void track_element_set_cable_lift(rct_map_element *trackElement); +void track_element_clear_cable_lift(rct_map_element *trackElement); #endif diff --git a/src/ride/track_data.c b/src/ride/track_data.c index 636cb95522..17efa05e0a 100644 --- a/src/ride/track_data.c +++ b/src/ride/track_data.c @@ -18,228 +18,232 @@ * along with this program. If not, see . *****************************************************************************/ +#include "track.h" #include "track_data.h" +#include "track_paint.h" + +const rct_track_coordinates* FlatTrackCoordinates = RCT2_ADDRESS(0x009972BB, const rct_track_coordinates); 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, 0, 0, 0, 0, 0 }, // ELEM_FLAT + { 0, 0, 0, 0, 0, 0 }, // ELEM_END_STATION + { 0, 0, 0, 0, 0, 0 }, // ELEM_BEGIN_STATION + { 0, 0, 0, 0, 0, 0 }, // ELEM_MIDDLE_STATION + { 0, 0, 0, 16, 0, 0 }, // ELEM_25_DEG_UP + { 0, 0, 0, 64, 0, 0 }, // ELEM_60_DEG_UP + { 0, 0, 0, 8, 0, 0 }, // ELEM_FLAT_TO_25_DEG_UP + { 0, 0, 0, 32, 0, 0 }, // ELEM_25_DEG_UP_TO_60_DEG_UP + { 0, 0, 0, 32, 0, 0 }, // ELEM_60_DEG_UP_TO_25_DEG_UP + { 0, 0, 0, 8, 0, 0 }, // ELEM_25_DEG_UP_TO_FLAT + { 0, 0, 16, 0, 0, 0 }, // ELEM_25_DEG_DOWN + { 0, 0, 64, 0, 0, 0 }, // ELEM_60_DEG_DOWN + { 0, 0, 8, 0, 0, 0 }, // ELEM_FLAT_TO_25_DEG_DOWN + { 0, 0, 32, 0, 0, 0 }, // ELEM_25_DEG_DOWN_TO_60_DEG_DOWN + { 0, 0, 32, 0, 0, 0 }, // ELEM_60_DEG_DOWN_TO_25_DEG_DOWN + { 0, 0, 8, 0, 0, 0 }, // ELEM_25_DEG_DOWN_TO_FLAT + { 0, 3, 0, 0, -64, -64 }, // ELEM_LEFT_QUARTER_TURN_5_TILES + { 0, 1, 0, 0, -64, 64 }, // ELEM_RIGHT_QUARTER_TURN_5_TILES + { 0, 0, 0, 0, 0, 0 }, // ELEM_FLAT_TO_LEFT_BANK + { 0, 0, 0, 0, 0, 0 }, // ELEM_FLAT_TO_RIGHT_BANK + { 0, 0, 0, 0, 0, 0 }, // ELEM_LEFT_BANK_TO_FLAT + { 0, 0, 0, 0, 0, 0 }, // ELEM_RIGHT_BANK_TO_FLAT + { 0, 3, 0, 0, -64, -64 }, // ELEM_BANKED_LEFT_QUARTER_TURN_5_TILES + { 0, 1, 0, 0, -64, 64 }, // ELEM_BANKED_RIGHT_QUARTER_TURN_5_TILES + { 0, 0, 0, 8, 0, 0 }, // ELEM_LEFT_BANK_TO_25_DEG_UP + { 0, 0, 0, 8, 0, 0 }, // ELEM_RIGHT_BANK_TO_25_DEG_UP + { 0, 0, 0, 8, 0, 0 }, // ELEM_25_DEG_UP_TO_LEFT_BANK + { 0, 0, 0, 8, 0, 0 }, // ELEM_25_DEG_UP_TO_RIGHT_BANK + { 0, 0, 8, 0, 0, 0 }, // ELEM_LEFT_BANK_TO_25_DEG_DOWN + { 0, 0, 8, 0, 0, 0 }, // ELEM_RIGHT_BANK_TO_25_DEG_DOWN + { 0, 0, 8, 0, 0, 0 }, // ELEM_25_DEG_DOWN_TO_LEFT_BANK + { 0, 0, 8, 0, 0, 0 }, // ELEM_25_DEG_DOWN_TO_RIGHT_BANK + { 0, 0, 0, 0, 0, 0 }, // ELEM_LEFT_BANK + { 0, 0, 0, 0, 0, 0 }, // ELEM_RIGHT_BANK + { 0, 3, 0, 64, -64, -64 }, // ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_UP + { 0, 1, 0, 64, -64, 64 }, // ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_UP + { 0, 3, 64, 0, -64, -64 }, // ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_DOWN + { 0, 1, 64, 0, -64, 64 }, // ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_DOWN + { 0, 0, 0, 0, -64, -32 }, // ELEM_S_BEND_LEFT + { 0, 0, 0, 0, -64, 32 }, // ELEM_S_BEND_RIGHT + { 0, 0, 0, 0, -32, -32 }, // ELEM_LEFT_VERTICAL_LOOP + { 0, 0, 0, 0, -32, 32 }, // ELEM_RIGHT_VERTICAL_LOOP + { 0, 3, 0, 0, -32, -32 }, // ELEM_LEFT_QUARTER_TURN_3_TILES + { 0, 1, 0, 0, -32, 32 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES + { 0, 3, 0, 0, -32, -32 }, // ELEM_LEFT_QUARTER_TURN_3_TILES_BANK + { 0, 1, 0, 0, -32, 32 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_BANK + { 0, 3, 0, 32, -32, -32 }, // ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP + { 0, 1, 0, 32, -32, 32 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP + { 0, 3, 32, 0, -32, -32 }, // ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN + { 0, 1, 32, 0, -32, 32 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN + { 0, 3, 0, 0, 0, 0 }, // ELEM_LEFT_QUARTER_TURN_1_TILE + { 0, 1, 0, 0, 0, 0 }, // ELEM_RIGHT_QUARTER_TURN_1_TILE + { 0, 0, 0, 16, -64, 0 }, // ELEM_LEFT_TWIST_DOWN_TO_UP + { 0, 0, 0, 16, -64, 0 }, // ELEM_RIGHT_TWIST_DOWN_TO_UP + { 0, 0, 0, -16, -64, 0 }, // ELEM_LEFT_TWIST_UP_TO_DOWN + { 0, 0, 0, -16, -64, 0 }, // ELEM_RIGHT_TWIST_UP_TO_DOWN + { 0, 2, 0, 152, -32, 0 }, // ELEM_HALF_LOOP_UP + { 0, 2, 0, -152, 32, 0 }, // ELEM_HALF_LOOP_DOWN + { 0, 3, 0, 80, -32, -32 }, // ELEM_LEFT_CORKSCREW_UP + { 0, 1, 0, 80, -32, 32 }, // ELEM_RIGHT_CORKSCREW_UP + { 0, 3, 0, -80, -32, -32 }, // ELEM_LEFT_CORKSCREW_DOWN + { 0, 1, 0, -80, -32, 32 }, // ELEM_RIGHT_CORKSCREW_DOWN + { 0, 0, 0, 24, 0, 0 }, // ELEM_FLAT_TO_60_DEG_UP + { 0, 0, 0, 24, 0, 0 }, // ELEM_60_DEG_UP_TO_FLAT + { 0, 0, 24, 0, 0, 0 }, // ELEM_FLAT_TO_60_DEG_DOWN + { 0, 0, 24, 0, 0, 0 }, // ELEM_60_DEG_DOWN_TO_FLAT + { 0, 0, 0, 96, 32, 0 }, // ELEM_TOWER_BASE + { 0, 0, 0, 32, 32, 0 }, // ELEM_TOWER_SECTION + { 0, 0, 0, 0, 0, 0 }, // ELEM_FLAT_COVERED + { 0, 0, 0, 16, 0, 0 }, // ELEM_25_DEG_UP_COVERED + { 0, 0, 0, 64, 0, 0 }, // ELEM_60_DEG_UP_COVERED + { 0, 0, 0, 8, 0, 0 }, // ELEM_FLAT_TO_25_DEG_UP_COVERED + { 0, 0, 0, 32, 0, 0 }, // ELEM_25_DEG_UP_TO_60_DEG_UP_COVERED + { 0, 0, 0, 32, 0, 0 }, // ELEM_60_DEG_UP_TO_25_DEG_UP_COVERED + { 0, 0, 0, 8, 0, 0 }, // ELEM_25_DEG_UP_TO_FLAT_COVERED + { 0, 0, 16, 0, 0, 0 }, // ELEM_25_DEG_DOWN_COVERED + { 0, 0, 64, 0, 0, 0 }, // ELEM_60_DEG_DOWN_COVERED + { 0, 0, 8, 0, 0, 0 }, // ELEM_FLAT_TO_25_DEG_DOWN_COVERED + { 0, 0, 32, 0, 0, 0 }, // ELEM_25_DEG_DOWN_TO_60_DEG_DOWN_COVERED + { 0, 0, 32, 0, 0, 0 }, // ELEM_60_DEG_DOWN_TO_25_DEG_DOWN_COVERED + { 0, 0, 8, 0, 0, 0 }, // ELEM_25_DEG_DOWN_TO_FLAT_COVERED + { 0, 3, 0, 0, -64, -64 }, // ELEM_LEFT_QUARTER_TURN_5_TILES_COVERED + { 0, 1, 0, 0, -64, 64 }, // ELEM_RIGHT_QUARTER_TURN_5_TILES_COVERED + { 0, 0, 0, 0, -64, -32 }, // ELEM_S_BEND_LEFT_COVERED + { 0, 0, 0, 0, -64, 32 }, // ELEM_S_BEND_RIGHT_COVERED + { 0, 3, 0, 0, -32, -32 }, // ELEM_LEFT_QUARTER_TURN_3_TILES_COVERED + { 0, 1, 0, 0, -32, 32 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_COVERED + { 0, 2, 0, 16, 0, -96 }, // ELEM_LEFT_HALF_BANKED_HELIX_UP_SMALL + { 0, 2, 0, 16, 0, 96 }, // ELEM_RIGHT_HALF_BANKED_HELIX_UP_SMALL + { 0, 2, 16, 0, 0, -96 }, // ELEM_LEFT_HALF_BANKED_HELIX_DOWN_SMALL + { 0, 2, 16, 0, 0, 96 }, // ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_SMALL + { 0, 2, 0, 16, 0, -160 }, // ELEM_LEFT_HALF_BANKED_HELIX_UP_LARGE + { 0, 2, 0, 16, 0, 160 }, // ELEM_RIGHT_HALF_BANKED_HELIX_UP_LARGE + { 0, 2, 16, 0, 0, -160 }, // ELEM_LEFT_HALF_BANKED_HELIX_DOWN_LARGE + { 0, 2, 16, 0, 0, 160 }, // ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_LARGE + { 0, 3, 0, 64, 0, 0 }, // ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_UP + { 0, 1, 0, 64, 0, 0 }, // ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_UP + { 0, 3, 64, 0, 0, 0 }, // ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_DOWN + { 0, 1, 64, 0, 0, 0 }, // ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_DOWN + { 0, 0, 0, 0, 0, 0 }, // ELEM_BRAKES + { 0, 0, 0, 0, 0, 0 }, // ELEM_ROTATION_CONTROL_TOGGLE + { 0, 0, 0, 0, 0, 0 }, // ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP + { 0, 3, 0, 16, -64, -64 }, // ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_UP + { 0, 1, 0, 16, -64, 64 }, // ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_UP + { 0, 3, 16, 0, -64, -64 }, // ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_DOWN + { 0, 1, 16, 0, -64, 64 }, // ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_DOWN + { 0, 3, 0, 16, -64, -64 }, // ELEM_LEFT_QUARTER_HELIX_LARGE_UP + { 0, 1, 0, 16, -64, 64 }, // ELEM_RIGHT_QUARTER_HELIX_LARGE_UP + { 0, 3, 16, 0, -64, -64 }, // ELEM_LEFT_QUARTER_HELIX_LARGE_DOWN + { 0, 1, 16, 0, -64, 64 }, // ELEM_RIGHT_QUARTER_HELIX_LARGE_DOWN + { 0, 0, 0, 16, 0, 0 }, // ELEM_25_DEG_UP_LEFT_BANKED + { 0, 0, 0, 16, 0, 0 }, // ELEM_25_DEG_UP_RIGHT_BANKED + { 0, 0, 0, 0, 0, 0 }, // ELEM_WATERFALL + { 0, 0, 0, 0, 0, 0 }, // ELEM_RAPIDS + { 0, 0, 0, 0, 0, 0 }, // ELEM_ON_RIDE_PHOTO + { 0, 0, 16, 0, 0, 0 }, // ELEM_25_DEG_DOWN_LEFT_BANKED + { 0, 0, 16, 0, 0, 0 }, // ELEM_25_DEG_DOWN_RIGHT_BANKED + { 0, 0, 16, 16, -128, 0 }, // ELEM_WATER_SPLASH + { 0, 0, 0, 88, -96, 0 }, // ELEM_FLAT_TO_60_DEG_UP_LONG_BASE + { 0, 0, 0, 88, -96, 0 }, // ELEM_60_DEG_UP_TO_FLAT_LONG_BASE + { 0, 0, 0, 0, 0, 0 }, // ELEM_WHIRLPOOL + { 0, 0, 88, 0, -96, 0 }, // ELEM_60_DEG_DOWN_TO_FLAT_LONG_BASE + { 0, 0, 88, 0, -96, 0 }, // ELEM_FLAT_TO_60_DEG_DOWN_LONG_BASE + { 0, 0, 0, -96, -96, 0 }, // ELEM_CABLE_LIFT_HILL + { 0, 0, 0, 240, -160, 0 }, // ELEM_REVERSE_WHOA_BELLY_SLOPE + { 0, 0, 0, 80, 32, 0 }, // ELEM_REVERSE_WHOA_BELLY_VERTICAL + { 0, 0, 0, 32, 32, 0 }, // ELEM_90_DEG_UP + { 0, 0, 32, 0, 32, 0 }, // ELEM_90_DEG_DOWN + { 0, 0, 0, 56, 32, 0 }, // ELEM_60_DEG_UP_TO_90_DEG_UP + { 0, 0, 56, 0, 0, 0 }, // ELEM_90_DEG_DOWN_TO_60_DEG_DOWN + { 0, 0, 0, 56, 0, 0 }, // ELEM_90_DEG_UP_TO_60_DEG_UP + { 0, 0, 56, 0, 32, 0 }, // ELEM_60_DEG_DOWN_TO_90_DEG_DOWN + { 0, 0, 24, 0, 0, 0 }, // ELEM_BRAKE_FOR_DROP + { 0, 7, 0, 0, -64, -32 }, // ELEM_LEFT_EIGHTH_TO_DIAG + { 0, 4, 0, 0, -64, 32 }, // ELEM_RIGHT_EIGHTH_TO_DIAG + { 4, 0, 0, 0, -64, 32 }, // ELEM_LEFT_EIGHTH_TO_ORTHOGONAL + { 4, 1, 0, 0, -32, 64 }, // ELEM_RIGHT_EIGHTH_TO_ORTHOGONAL + { 0, 7, 0, 0, -64, -32 }, // ELEM_LEFT_EIGHTH_BANK_TO_DIAG + { 0, 4, 0, 0, -64, 32 }, // ELEM_RIGHT_EIGHTH_BANK_TO_DIAG + { 4, 0, 0, 0, -64, 32 }, // ELEM_LEFT_EIGHTH_BANK_TO_ORTHOGONAL + { 4, 1, 0, 0, -32, 64 }, // ELEM_RIGHT_EIGHTH_BANK_TO_ORTHOGONAL + { 4, 4, 0, 0, -32, 32 }, // ELEM_DIAG_FLAT + { 4, 4, 0, 16, -32, 32 }, // ELEM_DIAG_25_DEG_UP + { 4, 4, 0, 64, -32, 32 }, // ELEM_DIAG_60_DEG_UP + { 4, 4, 0, 8, -32, 32 }, // ELEM_DIAG_FLAT_TO_25_DEG_UP + { 4, 4, 0, 32, -32, 32 }, // ELEM_DIAG_25_DEG_UP_TO_60_DEG_UP + { 4, 4, 0, 32, -32, 32 }, // ELEM_DIAG_60_DEG_UP_TO_25_DEG_UP + { 4, 4, 0, 8, -32, 32 }, // ELEM_DIAG_25_DEG_UP_TO_FLAT + { 4, 4, 16, 0, -32, 32 }, // ELEM_DIAG_25_DEG_DOWN + { 4, 4, 64, 0, -32, 32 }, // ELEM_DIAG_60_DEG_DOWN + { 4, 4, 8, 0, -32, 32 }, // ELEM_DIAG_FLAT_TO_25_DEG_DOWN + { 4, 4, 32, 0, -32, 32 }, // ELEM_DIAG_25_DEG_DOWN_TO_60_DEG_DOWN + { 4, 4, 32, 0, -32, 32 }, // ELEM_DIAG_60_DEG_DOWN_TO_25_DEG_DOWN + { 4, 4, 8, 0, -32, 32 }, // ELEM_DIAG_25_DEG_DOWN_TO_FLAT + { 4, 4, 0, 24, -32, 32 }, // ELEM_DIAG_FLAT_TO_60_DEG_UP + { 4, 4, 0, 24, -32, 32 }, // ELEM_DIAG_60_DEG_UP_TO_FLAT + { 4, 4, 24, 0, -32, 32 }, // ELEM_DIAG_FLAT_TO_60_DEG_DOWN + { 4, 4, 24, 0, -32, 32 }, // ELEM_DIAG_60_DEG_DOWN_TO_FLAT + { 4, 4, 0, 0, -32, 32 }, // ELEM_DIAG_FLAT_TO_LEFT_BANK + { 4, 4, 0, 0, -32, 32 }, // ELEM_DIAG_FLAT_TO_RIGHT_BANK + { 4, 4, 0, 0, -32, 32 }, // ELEM_DIAG_LEFT_BANK_TO_FLAT + { 4, 4, 0, 0, -32, 32 }, // ELEM_DIAG_RIGHT_BANK_TO_FLAT + { 4, 4, 0, 8, -32, 32 }, // ELEM_DIAG_LEFT_BANK_TO_25_DEG_UP + { 4, 4, 0, 8, -32, 32 }, // ELEM_DIAG_RIGHT_BANK_TO_25_DEG_UP + { 4, 4, 0, 8, -32, 32 }, // ELEM_DIAG_25_DEG_UP_TO_LEFT_BANK + { 4, 4, 0, 8, -32, 32 }, // ELEM_DIAG_25_DEG_UP_TO_RIGHT_BANK + { 4, 4, 8, 0, -32, 32 }, // ELEM_DIAG_LEFT_BANK_TO_25_DEG_DOWN + { 4, 4, 8, 0, -32, 32 }, // ELEM_DIAG_RIGHT_BANK_TO_25_DEG_DOWN + { 4, 4, 8, 0, -32, 32 }, // ELEM_DIAG_25_DEG_DOWN_TO_LEFT_BANK + { 4, 4, 8, 0, -32, 32 }, // ELEM_DIAG_25_DEG_DOWN_TO_RIGHT_BANK + { 4, 4, 0, 0, -32, 32 }, // ELEM_DIAG_LEFT_BANK + { 4, 4, 0, 0, -32, 32 }, // ELEM_DIAG_RIGHT_BANK + { 0, 0, 0, 0, 0, 0 }, // ELEM_LOG_FLUME_REVERSER + { 0, 0, 0, 0, 0, 0 }, // ELEM_SPINNING_TUNNEL + { 0, 0, 0, 32, -64, 0 }, // ELEM_LEFT_BARREL_ROLL_UP_TO_DOWN + { 0, 0, 0, 32, -64, 0 }, // ELEM_RIGHT_BARREL_ROLL_UP_TO_DOWN + { 0, 0, 0, -32, -64, 0 }, // ELEM_LEFT_BARREL_ROLL_DOWN_TO_UP + { 0, 0, 0, -32, -64, 0 }, // ELEM_RIGHT_BARREL_ROLL_DOWN_TO_UP + { 0, 3, 0, 24, -32, -32 }, // ELEM_LEFT_BANK_TO_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP + { 0, 1, 0, 24, -32, 32 }, // ELEM_RIGHT_BANK_TO_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP + { 0, 3, 24, 0, -32, -32 }, // ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_LEFT_BANK + { 0, 1, 24, 0, -32, 32 }, // ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_RIGHT_BANK + { 0, 0, 0, 16, 0, 0 }, // ELEM_POWERED_LIFT + { 0, 2, 0, 280, -64, -32 }, // ELEM_LEFT_LARGE_HALF_LOOP_UP + { 0, 2, 0, 280, -64, 32 }, // ELEM_RIGHT_LARGE_HALF_LOOP_UP + { 0, 2, 0, -280, 64, -32 }, // ELEM_RIGHT_LARGE_HALF_LOOP_DOWN + { 0, 2, 0, -280, 64, 32 }, // ELEM_LEFT_LARGE_HALF_LOOP_DOWN + { 0, 0, 0, -16, -64, 0 }, // ELEM_LEFT_FLYER_TWIST_UP_TO_DOWN + { 0, 0, 0, -16, -64, 0 }, // ELEM_RIGHT_FLYER_TWIST_UP_TO_DOWN + { 0, 0, 0, 16, -64, 0 }, // ELEM_LEFT_FLYER_TWIST_DOWN_TO_UP + { 0, 0, 0, 16, -64, 0 }, // ELEM_RIGHT_FLYER_TWIST_DOWN_TO_UP + { 0, 2, 0, 120, -32, 0 }, // ELEM_FLYER_HALF_LOOP_UP + { 0, 2, 0, -120, 32, 0 }, // ELEM_FLYER_HALF_LOOP_DOWN + { 0, 3, 0, 48, -32, -32 }, // ELEM_LEFT_FLY_CORKSCREW_UP_TO_DOWN + { 0, 1, 0, 48, -32, 32 }, // ELEM_RIGHT_FLY_CORKSCREW_UP_TO_DOWN + { 0, 3, 0, -48, -32, -32 }, // ELEM_LEFT_FLY_CORKSCREW_DOWN_TO_UP + { 0, 1, 0, -48, -32, 32 }, // ELEM_RIGHT_FLY_CORKSCREW_DOWN_TO_UP + { 0, 2, 0, 32, 0, 0 }, // ELEM_HEARTLINE_TRANSFER_UP + { 0, 2, 0, -32, 0, 0 }, // ELEM_HEARTLINE_TRANSFER_DOWN + { 0, 0, 0, 0, -160, 0 }, // ELEM_LEFT_HEARTLINE_ROLL + { 0, 0, 0, 0, -160, 0 }, // ELEM_RIGHT_HEARTLINE_ROLL + { 0, 0, 0, 0, -32, 0 }, // ELEM_MINI_GOLF_HOLE_A + { 0, 0, 0, 0, -32, 0 }, // ELEM_MINI_GOLF_HOLE_B + { 0, 0, 0, 0, -32, 0 }, // ELEM_MINI_GOLF_HOLE_C + { 0, 1, 0, 0, -32, 32 }, // ELEM_MINI_GOLF_HOLE_D + { 0, 3, 0, 0, -32, -32 }, // ELEM_MINI_GOLF_HOLE_E + { 0, 2, 0, -96, -96, 0 }, // ELEM_INVERTED_FLAT_TO_90_DEG_DOWN_QUARTER_LOOP + { 0, 2, 0, 128, 64, 0 }, // ELEM_90_DEG_UP_QUARTER_LOOP_TO_INVERTED + { 0, 2, 0, -128, -96, 0 }, // ELEM_QUARTER_LOOP_INVERT_TO_90_DEG_DOWN + { 0, 3, 0, 16, -32, -32 }, // ELEM_LEFT_CURVED_LIFT_HILL + { 0, 1, 0, 16, -32, 32 }, // ELEM_RIGHT_CURVED_LIFT_HILL + { 0, 0, 0, 0, -64, 0 }, // ELEM_LEFT_REVERSER + { 0, 0, 0, 0, -64, 0 }, // ELEM_RIGHT_REVERSER + { 0, 0, 0, 0, -32, 0 }, // ELEM_AIR_THRUST_TOP_CAP + { 0, 0, 80, 0, 32, 0 }, // ELEM_AIR_THRUST_VERTICAL_DOWN + { 0, 0, 240, 0, -160, 0 }, // ELEM_AIR_THRUST_VERTICAL_DOWN_TO_LEVEL + { 0, 0, 0, 0, 0, 0 }, // ELEM_BLOCK_BRAKES + { 0, 3, 0, 32, -32, -32 }, // ELEM_BANKED_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP + { 0, 1, 0, 32, -32, 32 }, // ELEM_BANKED_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP { 0, 3, 32, 0, -32, -32 }, { 0, 1, 32, 0, -32, 32 }, { 0, 3, 0, 64, -64, -64 }, @@ -277,4 +281,5380 @@ const rct_track_coordinates TrackCoordinates[256] = { { 0, 2, 0, 96, 64, 0 }, { 0, 2, 0, -128, -96, 0 }, { 0, 2, 0, 128, 64, 0 } -}; \ No newline at end of file +}; + +// rct2: 0x0097C468 (0 - 31) and 0x0097C5D4 (32 - 63) +const uint64 RideTypePossibleTrackConfigurations[91] = { + /* RIDE_TYPE_SPIRAL_ROLLER_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_FLAT_ROLL_BANKING | TRACK_VERTICAL_LOOP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HELIX_SMALL | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO, + /* RIDE_TYPE_STAND_UP_ROLLER_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_VERTICAL_LOOP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HALF_LOOP | TRACK_CORKSCREW | TRACK_HELIX_SMALL | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO, + /* RIDE_TYPE_SUSPENDED_SWINGING_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HELIX_LARGE_UNBANKED | TRACK_BRAKES, + /* RIDE_TYPE_INVERTED_ROLLER_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_VERTICAL_LOOP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_TWIST | TRACK_HALF_LOOP | TRACK_CORKSCREW | TRACK_HELIX_LARGE | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO | TRACK_HALF_LOOP_LARGE, + /* RIDE_TYPE_JUNIOR_ROLLER_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_LIFT_HILL_CURVE | TRACK_FLAT_ROLL_BANKING | TRACK_SLOPE | TRACK_SLOPE_CURVE | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HELIX_SMALL | TRACK_BRAKES, + /* RIDE_TYPE_MINIATURE_RAILWAY */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_SLOPE | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE, + /* RIDE_TYPE_MONORAIL */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_SLOPE | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE, + /* RIDE_TYPE_MINI_SUSPENDED_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_SLOPE | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE, + /* RIDE_TYPE_BOAT_RIDE */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_CURVE_VERY_SMALL, + /* RIDE_TYPE_WOODEN_WILD_MOUSE */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_LIFT_HILL_STEEP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_LONG | TRACK_CURVE_VERY_SMALL | TRACK_CURVE_SMALL, + /* RIDE_TYPE_STEEPLECHASE */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_SLOPE | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_BRAKES, + /* RIDE_TYPE_CAR_RIDE */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_CURVE_VERY_SMALL | TRACK_CURVE_SMALL | TRACK_TOWER_BASE, + /* RIDE_TYPE_LAUNCHED_FREEFALL */ TRACK_TOWER_BASE, + /* RIDE_TYPE_BOBSLEIGH_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_SLOPE | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HELIX_SMALL | TRACK_BRAKES, + /* RIDE_TYPE_OBSERVATION_TOWER */ TRACK_TOWER_BASE, + /* RIDE_TYPE_LOOPING_ROLLER_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_VERTICAL_LOOP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HELIX_SMALL | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO, + /* RIDE_TYPE_DINGHY_SLIDE */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE, + /* RIDE_TYPE_MINE_TRAIN_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HELIX_SMALL | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO, + /* RIDE_TYPE_CHAIRLIFT */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_SLOPE | TRACK_CURVE_VERY_SMALL, + /* RIDE_TYPE_CORKSCREW_ROLLER_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_VERTICAL_LOOP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HALF_LOOP | TRACK_CORKSCREW | TRACK_HELIX_SMALL | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO, + /* RIDE_TYPE_MAZE */ 0, + /* RIDE_TYPE_SPIRAL_SLIDE */ 0, + /* RIDE_TYPE_GO_KARTS */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_SLOPE | TRACK_CURVE_VERY_SMALL, + /* RIDE_TYPE_LOG_FLUME */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_SLOPE | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_ON_RIDE_PHOTO, + /* RIDE_TYPE_RIVER_RAPIDS */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_SLOPE | TRACK_CURVE_VERY_SMALL | TRACK_TOWER_BASE | TRACK_ON_RIDE_PHOTO, + /* RIDE_TYPE_DODGEMS */ 0, + /* RIDE_TYPE_PIRATE_SHIP */ 0, + /* RIDE_TYPE_SWINGING_INVERTER_SHIP */ 0, + /* RIDE_TYPE_FOOD_STALL */ 0, + /* RIDE_TYPE_1D */ 0, + /* RIDE_TYPE_DRINK_STALL */ 0, + /* RIDE_TYPE_1F */ 0, + /* RIDE_TYPE_SHOP */ 0, + /* RIDE_TYPE_MERRY_GO_ROUND */ 0, + /* RIDE_TYPE_22 */ 0, + /* RIDE_TYPE_INFORMATION_KIOSK */ 0, + /* RIDE_TYPE_TOILETS */ 0, + /* RIDE_TYPE_FERRIS_WHEEL */ 0, + /* RIDE_TYPE_MOTION_SIMULATOR */ 0, + /* RIDE_TYPE_3D_CINEMA */ 0, + /* RIDE_TYPE_TOP_SPIN */ 0, + /* RIDE_TYPE_SPACE_RINGS */ 0, + /* RIDE_TYPE_REVERSE_FREEFALL_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL_STEEP, + /* RIDE_TYPE_LIFT */ TRACK_TOWER_BASE, + /* RIDE_TYPE_VERTICAL_DROP_ROLLER_COASTER */ TRACK_FLAT | TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_LIFT_HILL_STEEP | TRACK_FLAT_ROLL_BANKING | TRACK_VERTICAL_LOOP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_LONG | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HELIX_SMALL | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO | TRACK_SLOPE_VERTICAL, + /* RIDE_TYPE_CASH_MACHINE */ 0, + /* RIDE_TYPE_TWIST */ 0, + /* RIDE_TYPE_HAUNTED_HOUSE */ 0, + /* RIDE_TYPE_FIRST_AID */ 0, + /* RIDE_TYPE_CIRCUS_SHOW */ 0, + /* RIDE_TYPE_GHOST_TRAIN */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_SLOPE | TRACK_CURVE_VERY_SMALL | TRACK_CURVE_SMALL | TRACK_BRAKES, + /* RIDE_TYPE_TWISTER_ROLLER_COASTER */ TRACK_FLAT | TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_VERTICAL_LOOP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HALF_LOOP | TRACK_CORKSCREW | TRACK_HELIX_SMALL | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO | TRACK_SLOPE_VERTICAL | TRACK_BARREL_ROLL | TRACK_POWERED_LIFT | TRACK_HALF_LOOP_LARGE, + /* RIDE_TYPE_WOODEN_ROLLER_COASTER */ TRACK_FLAT | TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_VERTICAL_LOOP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HELIX_SMALL | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO | TRACK_WATER_SPLASH, + /* RIDE_TYPE_SIDE_FRICTION_ROLLER_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_SLOPE | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_BRAKES, + /* RIDE_TYPE_WILD_MOUSE */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_LIFT_HILL_STEEP | TRACK_FLAT_ROLL_BANKING | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_LONG | TRACK_SLOPE_CURVE | TRACK_CURVE_VERY_SMALL | TRACK_CURVE_SMALL | TRACK_BRAKES, + /* RIDE_TYPE_MULTI_DIMENSION_ROLLER_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HALF_LOOP | TRACK_HELIX_SMALL | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO | TRACK_SLOPE_VERTICAL, + /* RIDE_TYPE_38 */ TRACK_STRAIGHT | TRACK_FLAT_ROLL_BANKING | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_TWIST | TRACK_CORKSCREW | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO | TRACK_SLOPE_VERTICAL, + /* RIDE_TYPE_FLYING_ROLLER_COASTER */ TRACK_STRAIGHT | TRACK_FLAT_ROLL_BANKING | TRACK_VERTICAL_LOOP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HELIX_SMALL | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO, + /* RIDE_TYPE_3A */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_VERTICAL_LOOP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_TWIST | TRACK_HELIX_LARGE | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO, + /* RIDE_TYPE_VIRGINIA_REEL */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_SLOPE | TRACK_CURVE_VERY_SMALL | TRACK_CURVE_SMALL, + /* RIDE_TYPE_SPLASH_BOATS */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_S_BEND | TRACK_CURVE, + /* RIDE_TYPE_MINI_HELICOPTERS */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_SLOPE | TRACK_CURVE_VERY_SMALL | TRACK_CURVE_SMALL, + /* RIDE_TYPE_LAY_DOWN_ROLLER_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_VERTICAL_LOOP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HELIX_SMALL | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO, + /* RIDE_TYPE_SUSPENDED_MONORAIL */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_SLOPE | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE, + /* RIDE_TYPE_40 */ TRACK_STRAIGHT | TRACK_FLAT_ROLL_BANKING | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_TWIST | TRACK_HELIX_LARGE | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO, + /* RIDE_TYPE_REVERSER_ROLLER_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_SLOPE | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_BRAKES, + /* RIDE_TYPE_HEARTLINE_TWISTER_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_LIFT_HILL_STEEP | TRACK_SLOPE | TRACK_SLOPE_STEEP, + /* RIDE_TYPE_MINI_GOLF */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_SLOPE | TRACK_CURVE_VERY_SMALL, + /* RIDE_TYPE_GIGA_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_VERTICAL_LOOP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HELIX_SMALL | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO, + /* RIDE_TYPE_ROTO_DROP */ TRACK_TOWER_BASE, + /* RIDE_TYPE_FLYING_SAUCERS */ 0, + /* RIDE_TYPE_CROOKED_HOUSE */ 0, + /* RIDE_TYPE_MONORAIL_CYCLES */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE, + /* RIDE_TYPE_COMPACT_INVERTED_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_VERTICAL_LOOP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_TWIST | TRACK_HALF_LOOP | TRACK_CORKSCREW | TRACK_HELIX_LARGE | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO | TRACK_SLOPE_VERTICAL, + /* RIDE_TYPE_WATER_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HELIX_SMALL | TRACK_BRAKES, + /* RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL_STEEP | TRACK_LIFT_HILL_CURVE | TRACK_FLAT_ROLL_BANKING | TRACK_CURVE | TRACK_BRAKES, + /* RIDE_TYPE_INVERTED_HAIRPIN_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_LIFT_HILL_STEEP | TRACK_FLAT_ROLL_BANKING | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_LONG | TRACK_SLOPE_CURVE | TRACK_CURVE_VERY_SMALL | TRACK_CURVE_SMALL | TRACK_BRAKES, + /* RIDE_TYPE_MAGIC_CARPET */ 0, + /* RIDE_TYPE_SUBMARINE_RIDE */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_CURVE_VERY_SMALL | TRACK_CURVE_SMALL, + /* RIDE_TYPE_RIVER_RAFTS */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_S_BEND | TRACK_CURVE, + /* RIDE_TYPE_50 */ 0, + /* RIDE_TYPE_ENTERPRISE */ 0, + /* RIDE_TYPE_52 */ 0, + /* RIDE_TYPE_53 */ 0, + /* RIDE_TYPE_54 */ 0, + /* RIDE_TYPE_55 */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HELIX_SMALL | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO, + /* RIDE_TYPE_INVERTED_IMPULSE_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_VERTICAL, + /* RIDE_TYPE_MINI_ROLLER_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_VERTICAL_LOOP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HELIX_SMALL | TRACK_BRAKES, + /* RIDE_TYPE_MINE_RIDE */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_FLAT_ROLL_BANKING | TRACK_SLOPE | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_HELIX_SMALL | TRACK_ON_RIDE_PHOTO, + /* RIDE_TYPE_59 */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_LIFT_HILL | TRACK_FLAT_ROLL_BANKING | TRACK_SLOPE | TRACK_CURVE_VERY_SMALL | TRACK_CURVE_SMALL | TRACK_BRAKES, + /* RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER */ TRACK_STRAIGHT | TRACK_STATION_END | TRACK_FLAT_ROLL_BANKING | TRACK_VERTICAL_LOOP | TRACK_SLOPE | TRACK_SLOPE_STEEP | TRACK_SLOPE_CURVE | TRACK_SLOPE_CURVE_STEEP | TRACK_S_BEND | TRACK_CURVE_SMALL | TRACK_CURVE | TRACK_TWIST | TRACK_CORKSCREW | TRACK_HELIX_SMALL | TRACK_BRAKES | TRACK_ON_RIDE_PHOTO | TRACK_SLOPE_VERTICAL +}; + +#define TRACK_BLOCK_END { 255, 255, 255, 255, 255, 255, 255 } + +static const rct_preview_track TrackBlocks000[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks001[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks002[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks003[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks004[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks005[] = { + { 0, 0, 0, 0, 64, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks006[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks007[] = { + { 0, 0, 0, 0, 32, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks008[] = { + { 0, 0, 0, 0, 32, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks009[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks010[] = { + { 0, 0, 0, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks011[] = { + { 0, 0, 0, 0, 64, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks012[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks013[] = { + { 0, 0, 0, 0, 32, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks014[] = { + { 0, 0, 0, 0, 32, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks015[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks016[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 0, 8, 1 }, + { 5, -64, -32, 0, 0, 7, 0 }, + { 6, -64, -64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks017[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 0, 4, 1 }, + { 5, -64, 32, 0, 0, 11, 0 }, + { 6, -64, 64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks018[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks019[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks020[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks021[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks022[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 0, 8, 1 }, + { 5, -64, -32, 0, 0, 7, 0 }, + { 6, -64, -64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks023[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 0, 4, 1 }, + { 5, -64, 32, 0, 0, 11, 0 }, + { 6, -64, 64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks024[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks025[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks026[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks027[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks028[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks029[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks030[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks031[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks032[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks033[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks034[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + { 1, 0, -32, 16, 0, 8, 1 }, + { 2, -32, 0, 16, 16, 71, 0 }, + { 3, -32, -32, 24, 16, 13, 0 }, + { 4, -32, -64, 48, 0, 8, 1 }, + { 5, -64, -32, 32, 16, 71, 0 }, + { 6, -64, -64, 48, 16, 111, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks035[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + { 1, 0, 32, 16, 0, 4, 1 }, + { 2, -32, 0, 16, 16, 139, 0 }, + { 3, -32, 32, 24, 16, 14, 0 }, + { 4, -32, 64, 48, 0, 4, 1 }, + { 5, -64, 32, 32, 16, 139, 0 }, + { 6, -64, 64, 48, 16, 159, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks036[] = { + { 0, 0, 0, 48, 16, 63, 0 }, + { 1, 0, -32, 48, 0, 8, 1 }, + { 2, -32, 0, 32, 16, 23, 0 }, + { 3, -32, -32, 24, 16, 13, 0 }, + { 4, -32, -64, 16, 0, 8, 1 }, + { 5, -64, -32, 16, 16, 23, 0 }, + { 6, -64, -64, 0, 16, 159, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks037[] = { + { 0, 0, 0, 48, 16, 63, 0 }, + { 1, 0, 32, 48, 0, 4, 1 }, + { 2, -32, 0, 32, 16, 43, 0 }, + { 3, -32, 32, 24, 16, 14, 0 }, + { 4, -32, 64, 16, 0, 4, 1 }, + { 5, -64, 32, 16, 16, 43, 0 }, + { 6, -64, 64, 0, 16, 111, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks038[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 7, 0 }, + { 2, -32, -32, 0, 0, 13, 0 }, + { 3, -64, -32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks039[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 11, 0 }, + { 2, -32, 32, 0, 0, 14, 0 }, + { 3, -64, 32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks040[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + { 1, -32, 0, 16, 16, 207, 0 }, + { 2, -64, 0, 32, 96, 2, 0 }, + { 3, -32, 0, 120, 16, 6, 0 }, + { 4, -32, -32, 120, 0, 0, 0 }, + { 5, 0, 0, 120, 0, 0, 0 }, + { 6, 0, -32, 120, 16, 9, 0 }, + { 7, 32, -32, 32, 96, 8, 0 }, + { 8, 0, -32, 16, 16, 63, 0 }, + { 9, -32, -32, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks041[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + { 1, -32, 0, 16, 16, 207, 0 }, + { 2, -64, 0, 32, 96, 1, 0 }, + { 3, -32, 0, 120, 16, 9, 0 }, + { 4, -32, 32, 120, 0, 0, 0 }, + { 5, 0, 0, 120, 0, 0, 0 }, + { 6, 0, 32, 120, 16, 6, 0 }, + { 7, 32, 32, 32, 96, 4, 0 }, + { 8, 0, 32, 16, 16, 63, 0 }, + { 9, -32, 32, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks042[] = { + { 0, 0, 0, 0, 0, 7, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 2, 0 }, + { 3, -32, -32, 0, 0, 7, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks043[] = { + { 0, 0, 0, 0, 0, 11, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 0 }, + { 3, -32, 32, 0, 0, 11, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks044[] = { + { 0, 0, 0, 0, 0, 7, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 2, 0 }, + { 3, -32, -32, 0, 0, 7, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks045[] = { + { 0, 0, 0, 0, 0, 11, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 0 }, + { 3, -32, 32, 0, 0, 11, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks046[] = { + { 0, 0, 0, 0, 16, 71, 0 }, + { 1, 0, -32, 16, 0, 8, 1 }, + { 2, -32, 0, 16, 0, 2, 0 }, + { 3, -32, -32, 16, 16, 103, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks047[] = { + { 0, 0, 0, 0, 16, 139, 0 }, + { 1, 0, 32, 16, 0, 4, 1 }, + { 2, -32, 0, 16, 0, 1, 0 }, + { 3, -32, 32, 16, 16, 155, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks048[] = { + { 0, 0, 0, 16, 16, 55, 0 }, + { 1, 0, -32, 16, 0, 8, 1 }, + { 2, -32, 0, 16, 0, 2, 0 }, + { 3, -32, -32, 0, 16, 23, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks049[] = { + { 0, 0, 0, 16, 16, 59, 0 }, + { 1, 0, 32, 16, 0, 4, 1 }, + { 2, -32, 0, 16, 0, 1, 0 }, + { 3, -32, 32, 0, 16, 43, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks050[] = { + { 0, 0, 0, 0, 0, 7, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks051[] = { + { 0, 0, 0, 0, 0, 11, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks052[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 16, 15, 0 }, + { 2, -64, 0, 16, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks053[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 16, 15, 0 }, + { 2, -64, 0, 16, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks054[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, -16, 16, 15, 0 }, + { 2, -64, 0, -16, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks055[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, -16, 16, 15, 0 }, + { 2, -64, 0, -16, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks056[] = { + { 0, 0, 0, 0, 32, 207, 0 }, + { 1, -32, 0, 16, 16, 207, 0 }, + { 2, -64, 0, 32, 96, 3, 0 }, + { 3, -32, 0, 120, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks057[] = { + { 0, 0, 0, -32, 32, 15, 0 }, + { 1, -32, 0, -120, 96, 3, 0 }, + { 2, 0, 0, -136, 16, 207, 0 }, + { 3, 32, 0, -152, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks058[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 24, 32, 7, 0 }, + { 2, -32, -32, 48, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks059[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 24, 32, 11, 0 }, + { 2, -32, 32, 48, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks060[] = { + { 0, 0, 0, -32, 16, 15, 0 }, + { 1, -32, 0, -56, 32, 7, 0 }, + { 2, -32, -32, -80, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks061[] = { + { 0, 0, 0, -32, 16, 15, 0 }, + { 1, -32, 0, -56, 32, 11, 0 }, + { 2, -32, 32, -80, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks062[] = { + { 0, 0, 0, 0, 24, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks063[] = { + { 0, 0, 0, 0, 24, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks064[] = { + { 0, 0, 0, 0, 24, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks065[] = { + { 0, 0, 0, 0, 24, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks066[] = { + { 0, 0, 0, 0, 64, 15, 0 }, + { 1, -32, -32, 0, 0, 15, 0 }, + { 2, -32, 0, 0, 0, 15, 0 }, + { 3, -32, 32, 0, 0, 15, 0 }, + { 4, 0, -32, 0, 0, 15, 0 }, + { 5, 0, 32, 0, 0, 15, 0 }, + { 6, 32, -32, 0, 0, 15, 0 }, + { 7, 32, 32, 0, 0, 15, 0 }, + { 8, 32, 0, 0, 0, 15, 2 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks067[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 32, 0, 0, 0, 0, 3 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks068[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks069[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks070[] = { + { 0, 0, 0, 0, 64, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks071[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks072[] = { + { 0, 0, 0, 0, 32, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks073[] = { + { 0, 0, 0, 0, 32, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks074[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks075[] = { + { 0, 0, 0, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks076[] = { + { 0, 0, 0, 0, 64, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks077[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks078[] = { + { 0, 0, 0, 0, 32, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks079[] = { + { 0, 0, 0, 0, 32, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks080[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks081[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 0, 8, 1 }, + { 5, -64, -32, 0, 0, 7, 0 }, + { 6, -64, -64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks082[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 0, 4, 1 }, + { 5, -64, 32, 0, 0, 11, 0 }, + { 6, -64, 64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks083[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 7, 0 }, + { 2, -32, -32, 0, 0, 13, 0 }, + { 3, -64, -32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks084[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 11, 0 }, + { 2, -32, 32, 0, 0, 14, 0 }, + { 3, -64, 32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks085[] = { + { 0, 0, 0, 0, 0, 7, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 2, 0 }, + { 3, -32, -32, 0, 0, 7, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks086[] = { + { 0, 0, 0, 0, 0, 11, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 0 }, + { 3, -32, 32, 0, 0, 11, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks087[] = { + { 0, 0, 0, 0, 0, 7, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 4, 2, 0 }, + { 3, -32, -32, 0, 4, 7, 0 }, + { 4, -32, -64, 8, 0, 11, 0 }, + { 5, 0, -64, 8, 0, 4, 1 }, + { 6, -32, -96, 8, 4, 1, 0 }, + { 7, 0, -96, 8, 4, 11, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks088[] = { + { 0, 0, 0, 0, 0, 11, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 4, 1, 0 }, + { 3, -32, 32, 0, 4, 11, 0 }, + { 4, -32, 64, 8, 0, 7, 0 }, + { 5, 0, 64, 8, 0, 8, 1 }, + { 6, -32, 96, 8, 4, 2, 0 }, + { 7, 0, 96, 8, 4, 7, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks089[] = { + { 0, 0, 0, 8, 4, 7, 0 }, + { 1, 0, -32, 8, 4, 8, 1 }, + { 2, -32, 0, 8, 0, 2, 0 }, + { 3, -32, -32, 8, 0, 7, 0 }, + { 4, -32, -64, 0, 4, 11, 0 }, + { 5, 0, -64, 0, 4, 4, 1 }, + { 6, -32, -96, 0, 0, 1, 0 }, + { 7, 0, -96, 0, 0, 11, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks090[] = { + { 0, 0, 0, 8, 4, 11, 0 }, + { 1, 0, 32, 8, 4, 4, 1 }, + { 2, -32, 0, 8, 0, 1, 0 }, + { 3, -32, 32, 8, 0, 11, 0 }, + { 4, -32, 64, 0, 4, 7, 0 }, + { 5, 0, 64, 0, 4, 8, 1 }, + { 6, -32, 96, 0, 0, 2, 0 }, + { 7, 0, 96, 0, 0, 7, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks091[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 4, 8, 1 }, + { 5, -64, -32, 0, 4, 7, 0 }, + { 6, -64, -64, 0, 4, 15, 0 }, + { 7, -64, -96, 8, 0, 15, 0 }, + { 8, -32, -96, 8, 0, 4, 1 }, + { 9, -64, -128, 8, 0, 11, 0 }, + { 10, -32, -128, 8, 0, 14, 0 }, + { 11, 0, -128, 8, 4, 4, 1 }, + { 12, -32, -160, 8, 4, 11, 0 }, + { 13, 0, -160, 8, 4, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks092[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 4, 4, 1 }, + { 5, -64, 32, 0, 4, 11, 0 }, + { 6, -64, 64, 0, 4, 15, 0 }, + { 7, -64, 96, 8, 0, 15, 0 }, + { 8, -32, 96, 8, 0, 8, 1 }, + { 9, -64, 128, 8, 0, 7, 0 }, + { 10, -32, 128, 8, 0, 13, 0 }, + { 11, 0, 128, 8, 4, 8, 1 }, + { 12, -32, 160, 8, 4, 7, 0 }, + { 13, 0, 160, 8, 4, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks093[] = { + { 0, 0, 0, 8, 4, 15, 0 }, + { 1, 0, -32, 8, 4, 8, 1 }, + { 2, -32, 0, 8, 4, 7, 0 }, + { 3, -32, -32, 8, 0, 13, 0 }, + { 4, -32, -64, 8, 0, 8, 1 }, + { 5, -64, -32, 8, 0, 7, 0 }, + { 6, -64, -64, 8, 0, 15, 0 }, + { 7, -64, -96, 0, 4, 15, 0 }, + { 8, -32, -96, 0, 4, 4, 1 }, + { 9, -64, -128, 0, 4, 11, 0 }, + { 10, -32, -128, 0, 0, 14, 0 }, + { 11, 0, -128, 0, 0, 4, 1 }, + { 12, -32, -160, 0, 0, 11, 0 }, + { 13, 0, -160, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks094[] = { + { 0, 0, 0, 8, 4, 15, 0 }, + { 1, 0, 32, 8, 4, 4, 1 }, + { 2, -32, 0, 8, 4, 11, 0 }, + { 3, -32, 32, 8, 0, 14, 0 }, + { 4, -32, 64, 8, 0, 4, 1 }, + { 5, -64, 32, 8, 0, 11, 0 }, + { 6, -64, 64, 8, 0, 15, 0 }, + { 7, -64, 96, 0, 4, 15, 0 }, + { 8, -32, 96, 0, 4, 8, 1 }, + { 9, -64, 128, 0, 4, 7, 0 }, + { 10, -32, 128, 0, 0, 13, 0 }, + { 11, 0, 128, 0, 0, 8, 1 }, + { 12, -32, 160, 0, 0, 7, 0 }, + { 13, 0, 160, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks095[] = { + { 0, 0, 0, 0, 64, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks096[] = { + { 0, 0, 0, 0, 64, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks097[] = { + { 0, 0, 0, 0, 64, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks098[] = { + { 0, 0, 0, 0, 64, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks099[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks100[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks101[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks102[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 12, 8, 1 }, + { 5, -64, -32, 0, 12, 7, 0 }, + { 6, -64, -64, 0, 12, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks103[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 12, 4, 1 }, + { 5, -64, 32, 0, 12, 11, 0 }, + { 6, -64, 64, 0, 12, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks104[] = { + { 0, 0, 0, 0, 12, 15, 0 }, + { 1, 0, -32, 0, 12, 8, 1 }, + { 2, -32, 0, 0, 12, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 0, 8, 1 }, + { 5, -64, -32, 0, 0, 7, 0 }, + { 6, -64, -64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks105[] = { + { 0, 0, 0, 0, 12, 15, 0 }, + { 1, 0, 32, 0, 12, 4, 1 }, + { 2, -32, 0, 0, 12, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 0, 4, 1 }, + { 5, -64, 32, 0, 0, 11, 0 }, + { 6, -64, 64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks106[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 12, 8, 1 }, + { 5, -64, -32, 0, 12, 7, 0 }, + { 6, -64, -64, 0, 12, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks107[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 12, 4, 1 }, + { 5, -64, 32, 0, 12, 11, 0 }, + { 6, -64, 64, 0, 12, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks108[] = { + { 0, 0, 0, 0, 12, 15, 0 }, + { 1, 0, -32, 0, 12, 8, 1 }, + { 2, -32, 0, 0, 12, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 0, 8, 1 }, + { 5, -64, -32, 0, 0, 7, 0 }, + { 6, -64, -64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks109[] = { + { 0, 0, 0, 0, 12, 15, 0 }, + { 1, 0, 32, 0, 12, 4, 1 }, + { 2, -32, 0, 0, 12, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 0, 4, 1 }, + { 5, -64, 32, 0, 0, 11, 0 }, + { 6, -64, 64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks110[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks111[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks112[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks113[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks114[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks115[] = { + { 0, 0, 0, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks116[] = { + { 0, 0, 0, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks117[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 0, 16, 15, 0 }, + { 2, -64, 0, 0, 16, 15, 0 }, + { 3, -96, 0, 0, 16, 15, 0 }, + { 4, -128, 0, 0, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks118[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + { 1, -32, 0, 0, 16, 15, 0 }, + { 2, -64, 0, 16, 24, 15, 0 }, + { 3, -96, 0, 40, 48, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks119[] = { + { 0, 0, 0, 0, 48, 15, 0 }, + { 1, -32, 0, 40, 48, 15, 0 }, + { 2, -64, 0, 64, 24, 15, 0 }, + { 3, -96, 0, 80, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks120[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks121[] = { + { 0, 0, 0, 40, 48, 15, 0 }, + { 1, -32, 0, 16, 24, 15, 0 }, + { 2, -64, 0, 0, 16, 15, 0 }, + { 3, -96, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks122[] = { + { 0, 0, 0, 80, 8, 15, 0 }, + { 1, -32, 0, 64, 24, 15, 0 }, + { 2, -64, 0, 40, 48, 15, 0 }, + { 3, -96, 0, 0, 48, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks123[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + { 1, -32, 0, 0, 8, 63, 0 }, + { 2, -64, 0, -32, 32, 63, 0 }, + { 3, -96, 0, -96, 64, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks124[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 0, 32, 15, 0 }, + { 2, -64, 0, 0, 48, 15, 0 }, + { 3, -96, 0, 0, 80, 15, 0 }, + { 4, -128, 0, 0, 160, 15, 0 }, + { 5, -192, 0, 0, 208, 15, 0 }, + { 6, -160, 0, 0, 208, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks125[] = { + { 0, 0, 0, 0, 48, 15, 0 }, + { 1, 32, 0, 0, 48, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks126[] = { + { 0, 0, 0, 0, 8, 15, 4 }, + { 1, 32, 0, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks127[] = { + { 0, 0, 0, 0, 8, 15, 4 }, + { 1, 32, 0, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks128[] = { + { 0, 0, 0, 0, 32, 207, 4 }, + { 1, 32, 0, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks129[] = { + { 0, 0, 0, 0, 32, 63, 4 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks130[] = { + { 0, 0, 0, 0, 56, 15, 4 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks131[] = { + { 0, 0, 0, 0, 56, 15, 4 }, + { 1, 32, 0, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks132[] = { + { 0, 0, 0, 0, 24, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks133[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -32, -32, 0, 0, 8, 0 }, + { 3, -64, 0, 0, 0, 2, 1 }, + { 4, -64, -32, 0, 0, 1, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks134[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -32, 32, 0, 0, 4, 0 }, + { 3, -64, 0, 0, 0, 1, 1 }, + { 4, -64, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks135[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, -32, 0, 0, 0, 1, 0 }, + { 2, 0, 32, 0, 0, 4, 1 }, + { 3, -32, 32, 0, 0, 15, 0 }, + { 4, -64, 32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks136[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 0 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 15, 0 }, + { 4, -32, 64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks137[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -32, -32, 0, 0, 8, 0 }, + { 3, -64, 0, 0, 0, 2, 1 }, + { 4, -64, -32, 0, 0, 1, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks138[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -32, 32, 0, 0, 4, 0 }, + { 3, -64, 0, 0, 0, 1, 1 }, + { 4, -64, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks139[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, -32, 0, 0, 0, 1, 0 }, + { 2, 0, 32, 0, 0, 4, 1 }, + { 3, -32, 32, 0, 0, 15, 0 }, + { 4, -64, 32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks140[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 0 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 15, 0 }, + { 4, -32, 64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks141[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks142[] = { + { 0, 0, 0, 0, 16, 13, 0 }, + { 1, 0, 32, 0, 16, 4, 1 }, + { 2, -32, 0, 0, 16, 1, 1 }, + { 3, -32, 32, 0, 16, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks143[] = { + { 0, 0, 0, 0, 64, 13, 0 }, + { 1, 0, 32, 0, 64, 4, 1 }, + { 2, -32, 0, 0, 64, 1, 1 }, + { 3, -32, 32, 0, 64, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks144[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks145[] = { + { 0, 0, 0, 0, 32, 13, 0 }, + { 1, 0, 32, 0, 32, 4, 1 }, + { 2, -32, 0, 0, 32, 1, 1 }, + { 3, -32, 32, 0, 32, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks146[] = { + { 0, 0, 0, 0, 32, 13, 0 }, + { 1, 0, 32, 0, 32, 4, 1 }, + { 2, -32, 0, 0, 32, 1, 1 }, + { 3, -32, 32, 0, 32, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks147[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks148[] = { + { 0, 0, 0, 0, 16, 13, 0 }, + { 1, 0, 32, 0, 16, 4, 1 }, + { 2, -32, 0, 0, 16, 1, 1 }, + { 3, -32, 32, 0, 16, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks149[] = { + { 0, 0, 0, 0, 64, 13, 0 }, + { 1, 0, 32, 0, 64, 4, 1 }, + { 2, -32, 0, 0, 64, 1, 1 }, + { 3, -32, 32, 0, 64, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks150[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks151[] = { + { 0, 0, 0, 0, 32, 13, 0 }, + { 1, 0, 32, 0, 32, 4, 1 }, + { 2, -32, 0, 0, 32, 1, 1 }, + { 3, -32, 32, 0, 32, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks152[] = { + { 0, 0, 0, 0, 32, 13, 0 }, + { 1, 0, 32, 0, 32, 4, 1 }, + { 2, -32, 0, 0, 32, 1, 1 }, + { 3, -32, 32, 0, 32, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks153[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks154[] = { + { 0, 0, 0, 0, 24, 13, 0 }, + { 1, 0, 32, 0, 24, 4, 1 }, + { 2, -32, 0, 0, 24, 1, 1 }, + { 3, -32, 32, 0, 24, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks155[] = { + { 0, 0, 0, 0, 24, 13, 0 }, + { 1, 0, 32, 0, 24, 4, 1 }, + { 2, -32, 0, 0, 24, 1, 1 }, + { 3, -32, 32, 0, 24, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks156[] = { + { 0, 0, 0, 0, 24, 13, 0 }, + { 1, 0, 32, 0, 24, 4, 1 }, + { 2, -32, 0, 0, 24, 1, 1 }, + { 3, -32, 32, 0, 24, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks157[] = { + { 0, 0, 0, 0, 24, 13, 0 }, + { 1, 0, 32, 0, 24, 4, 1 }, + { 2, -32, 0, 0, 24, 1, 1 }, + { 3, -32, 32, 0, 24, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks158[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks159[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks160[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks161[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks162[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks163[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks164[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks165[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks166[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks167[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks168[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks169[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks170[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks171[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks172[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks173[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks174[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 16, 15, 0 }, + { 2, -64, 0, 0, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks175[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 16, 15, 0 }, + { 2, -64, 0, 0, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks176[] = { + { 0, 0, 0, -32, 16, 15, 0 }, + { 1, -32, 0, -32, 16, 15, 0 }, + { 2, -64, 0, -32, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks177[] = { + { 0, 0, 0, -32, 16, 15, 0 }, + { 1, -32, 0, -32, 16, 15, 0 }, + { 2, -64, 0, -32, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks178[] = { + { 0, 0, 0, 0, 0, 71, 0 }, + { 1, 0, -32, 0, 16, 8, 1 }, + { 2, -32, 0, 0, 16, 2, 0 }, + { 3, -32, -32, 16, 16, 103, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks179[] = { + { 0, 0, 0, 0, 16, 139, 0 }, + { 1, 0, 32, 0, 16, 4, 1 }, + { 2, -32, 0, 0, 16, 1, 0 }, + { 3, -32, 32, 16, 16, 155, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks180[] = { + { 0, 0, 0, 16, 16, 55, 0 }, + { 1, 0, -32, 0, 16, 8, 1 }, + { 2, -32, 0, 0, 16, 2, 0 }, + { 3, -32, -32, 0, 0, 23, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks181[] = { + { 0, 0, 0, 16, 16, 59, 0 }, + { 1, 0, 32, 0, 16, 4, 1 }, + { 2, -32, 0, 0, 16, 1, 0 }, + { 3, -32, 32, 0, 0, 43, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks182[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks183[] = { + { 0, 0, 0, 0, 24, 207, 0 }, + { 1, -32, 0, 16, 40, 207, 0 }, + { 2, -64, 0, 32, 56, 15, 0 }, + { 3, -96, 0, 64, 192, 15, 0 }, + { 4, -128, -32, 120, 96, 15, 0 }, + { 5, -96, -32, 64, 192, 15, 0 }, + { 6, -64, -32, 248, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks184[] = { + { 0, 0, 0, 0, 24, 207, 0 }, + { 1, -32, 0, 16, 40, 207, 0 }, + { 2, -64, 0, 32, 56, 15, 0 }, + { 3, -96, 0, 64, 192, 15, 0 }, + { 4, -128, 32, 120, 96, 15, 0 }, + { 5, -96, 32, 64, 192, 15, 0 }, + { 6, -64, 32, 248, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks185[] = { + { 0, 0, 0, -32, 24, 15, 0 }, + { 1, -32, 0, -216, 192, 15, 0 }, + { 2, -64, 0, -160, 96, 15, 0 }, + { 3, -32, -32, -216, 192, 15, 0 }, + { 4, 0, -32, -248, 56, 15, 0 }, + { 5, 32, -32, -264, 40, 207, 0 }, + { 6, 64, -32, -280, 24, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks186[] = { + { 0, 0, 0, -32, 24, 15, 0 }, + { 1, -32, 0, -216, 192, 15, 0 }, + { 2, -64, 0, -160, 96, 15, 0 }, + { 3, -32, 32, -216, 192, 15, 0 }, + { 4, 0, 32, -248, 56, 15, 0 }, + { 5, 32, 32, -264, 40, 207, 0 }, + { 6, 64, 32, -280, 24, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks187[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, -16, 16, 15, 0 }, + { 2, -64, 0, -16, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks188[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, -16, 16, 15, 0 }, + { 2, -64, 0, -16, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks189[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 0, 16, 15, 0 }, + { 2, -64, 0, 16, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks190[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 0, 16, 15, 0 }, + { 2, -64, 0, 16, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks191[] = { + { 0, 0, 0, 0, 32, 207, 0 }, + { 1, -32, 0, 16, 16, 207, 0 }, + { 2, -64, 0, 32, 96, 3, 0 }, + { 3, -32, 0, 120, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks192[] = { + { 0, 0, 0, 0, 32, 15, 0 }, + { 1, -32, 0, -88, 96, 3, 0 }, + { 2, 0, 0, -104, 16, 207, 0 }, + { 3, 32, 0, -120, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks193[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 24, 32, 7, 0 }, + { 2, -32, -32, 48, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks194[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 24, 32, 11, 0 }, + { 2, -32, 32, 48, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks195[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, -24, 32, 7, 0 }, + { 2, -32, -32, -48, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks196[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, -24, 32, 11, 0 }, + { 2, -32, 32, -48, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks197[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 32, 15, 0 }, + { 2, -64, 0, 16, 0, 15, 0 }, + { 3, 0, 0, 32, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks198[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, -32, 32, 15, 0 }, + { 2, -64, 0, -16, 0, 15, 0 }, + { 3, 0, 0, -32, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks199[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -64, 0, 0, 0, 15, 0 }, + { 3, -96, 0, 0, 0, 15, 0 }, + { 4, -128, 0, 0, 0, 15, 0 }, + { 5, -160, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks200[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -64, 0, 0, 0, 15, 0 }, + { 3, -96, 0, 0, 0, 15, 0 }, + { 4, -128, 0, 0, 0, 15, 0 }, + { 5, -160, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks201[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks202[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks203[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks204[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -32, 32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks205[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -32, -32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks206[] = { + { 0, 0, 0, 0, 16, 15, 4 }, + { 1, -32, 0, -40, 32, 15, 4 }, + { 2, -64, 0, -96, 56, 15, 4 }, + { 3, -96, 0, -96, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks207[] = { + { 0, 0, 0, 0, 56, 15, 4 }, + { 1, 32, 0, 56, 32, 15, 4 }, + { 2, 64, 0, 96, 16, 15, 4 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks208[] = { + { 0, 0, 0, -32, 16, 15, 4 }, + { 1, -32, 0, -72, 32, 15, 4 }, + { 2, -64, 0, -128, 56, 15, 4 }, + { 3, -96, 0, -128, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks209[] = { + { 0, 0, 0, 0, 0, 7, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 8, 2, 0 }, + { 3, -32, -32, 0, 8, 7, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks210[] = { + { 0, 0, 0, 0, 0, 11, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 0 }, + { 3, -32, 32, 0, 8, 11, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks211[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, -32, 0, 0, 15, 0 }, + { 2, -32, -32, 0, 0, 15, 0 }, + { 3, -64, -32, 0, 0, 15, 0 }, + { 4, -32, 0, 0, 0, 15, 0 }, + { 5, -64, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks212[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 15, 0 }, + { 2, -32, 32, 0, 0, 15, 0 }, + { 3, -64, 32, 0, 0, 15, 0 }, + { 4, -32, 0, 0, 0, 15, 0 }, + { 5, -64, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks213[] = { + { 0, 0, 0, 0, 32, 15, 0 }, + { 1, 32, 0, 0, 32, 15, 0 }, + { 2, -64, 0, 0, 32, 15, 0 }, + { 3, -32, 0, 0, 32, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks214[] = { + { 0, 0, 0, 0, 48, 15, 0 }, + { 1, 32, 0, 0, 48, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks215[] = { + { 0, 0, 0, 0, 208, 15, 0 }, + { 1, 32, 0, 0, 208, 15, 0 }, + { 2, -32, 0, 0, 160, 15, 0 }, + { 3, -64, 0, 0, 80, 15, 0 }, + { 4, -96, 0, 0, 48, 15, 0 }, + { 5, -128, 0, 0, 32, 15, 0 }, + { 6, -160, 0, 0, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks216[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks217[] = { + { 0, 0, 0, 0, 16, 71, 0 }, + { 1, 0, -32, 16, 0, 8, 1 }, + { 2, -32, 0, 16, 0, 2, 0 }, + { 3, -32, -32, 16, 16, 103, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks218[] = { + { 0, 0, 0, 0, 16, 139, 0 }, + { 1, 0, 32, 16, 0, 4, 1 }, + { 2, -32, 0, 16, 0, 1, 0 }, + { 3, -32, 32, 16, 16, 155, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks219[] = { + { 0, 0, 0, 16, 16, 55, 0 }, + { 1, 0, -32, 16, 0, 8, 1 }, + { 2, -32, 0, 16, 0, 2, 0 }, + { 3, -32, -32, 0, 16, 23, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks220[] = { + { 0, 0, 0, 16, 16, 59, 0 }, + { 1, 0, 32, 16, 0, 4, 1 }, + { 2, -32, 0, 16, 0, 1, 0 }, + { 3, -32, 32, 0, 16, 43, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks221[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + { 1, 0, -32, 16, 0, 8, 1 }, + { 2, -32, 0, 16, 16, 71, 0 }, + { 3, -32, -32, 24, 16, 13, 0 }, + { 4, -32, -64, 48, 0, 8, 1 }, + { 5, -64, -32, 32, 16, 71, 0 }, + { 6, -64, -64, 48, 16, 111, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks222[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + { 1, 0, 32, 16, 0, 4, 1 }, + { 2, -32, 0, 16, 16, 139, 0 }, + { 3, -32, 32, 24, 16, 14, 0 }, + { 4, -32, 64, 48, 0, 4, 1 }, + { 5, -64, 32, 32, 16, 139, 0 }, + { 6, -64, 64, 48, 16, 159, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks223[] = { + { 0, 0, 0, 48, 16, 63, 0 }, + { 1, 0, -32, 48, 0, 8, 1 }, + { 2, -32, 0, 32, 16, 23, 0 }, + { 3, -32, -32, 24, 16, 13, 0 }, + { 4, -32, -64, 16, 0, 8, 1 }, + { 5, -64, -32, 16, 16, 23, 0 }, + { 6, -64, -64, 0, 16, 159, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks224[] = { + { 0, 0, 0, 48, 16, 63, 0 }, + { 1, 0, 32, 48, 0, 4, 1 }, + { 2, -32, 0, 32, 16, 43, 0 }, + { 3, -32, 32, 24, 16, 14, 0 }, + { 4, -32, 64, 16, 0, 4, 1 }, + { 5, -64, 32, 16, 16, 43, 0 }, + { 6, -64, 64, 0, 16, 111, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks225[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks226[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks227[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks228[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks229[] = { + { 0, 0, 0, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks230[] = { + { 0, 0, 0, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks231[] = { + { 0, 0, 0, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks232[] = { + { 0, 0, 0, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks233[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks234[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks235[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks236[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks237[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks238[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks239[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks240[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks241[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks242[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks243[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks244[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks245[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks246[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks247[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks248[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks249[] = { + { 0, 0, 0, 0, 72, 15, 4 }, + { 1, 0, 32, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks250[] = { + { 0, 0, 0, 0, 72, 15, 4 }, + { 1, 0, -32, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks251[] = { + { 0, 0, 0, 0, 72, 15, 4 }, + { 1, 0, 32, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks252[] = { + { 0, 0, 0, 0, 72, 15, 4 }, + { 1, 0, -32, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks253[] = { + { 0, 0, 0, 0, 56, 15, 4 }, + { 1, 32, 0, 56, 32, 15, 4 }, + { 2, 64, 0, 96, 16, 15, 4 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks254[] = { + { 0, 0, 0, -32, 16, 15, 4 }, + { 1, -32, 0, -72, 32, 15, 4 }, + { 2, -64, 0, -128, 56, 15, 4 }, + { 3, -96, 0, -128, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track TrackBlocks255[] = { + { 0, 0, 0, 32, 56, 15, 4 }, + { 1, 32, 0, 88, 32, 15, 4 }, + { 2, 64, 0, 128, 16, 15, 4 }, + TRACK_BLOCK_END +}; + +// rct2: 0x00994638 +const rct_preview_track *TrackBlocks[256] = { + TrackBlocks000, + TrackBlocks001, + TrackBlocks002, + TrackBlocks003, + TrackBlocks004, + TrackBlocks005, + TrackBlocks006, + TrackBlocks007, + TrackBlocks008, + TrackBlocks009, + TrackBlocks010, + TrackBlocks011, + TrackBlocks012, + TrackBlocks013, + TrackBlocks014, + TrackBlocks015, + TrackBlocks016, + TrackBlocks017, + TrackBlocks018, + TrackBlocks019, + TrackBlocks020, + TrackBlocks021, + TrackBlocks022, + TrackBlocks023, + TrackBlocks024, + TrackBlocks025, + TrackBlocks026, + TrackBlocks027, + TrackBlocks028, + TrackBlocks029, + TrackBlocks030, + TrackBlocks031, + TrackBlocks032, + TrackBlocks033, + TrackBlocks034, + TrackBlocks035, + TrackBlocks036, + TrackBlocks037, + TrackBlocks038, + TrackBlocks039, + TrackBlocks040, + TrackBlocks041, + TrackBlocks042, + TrackBlocks043, + TrackBlocks044, + TrackBlocks045, + TrackBlocks046, + TrackBlocks047, + TrackBlocks048, + TrackBlocks049, + TrackBlocks050, + TrackBlocks051, + TrackBlocks052, + TrackBlocks053, + TrackBlocks054, + TrackBlocks055, + TrackBlocks056, + TrackBlocks057, + TrackBlocks058, + TrackBlocks059, + TrackBlocks060, + TrackBlocks061, + TrackBlocks062, + TrackBlocks063, + TrackBlocks064, + TrackBlocks065, + TrackBlocks066, + TrackBlocks067, + TrackBlocks068, + TrackBlocks069, + TrackBlocks070, + TrackBlocks071, + TrackBlocks072, + TrackBlocks073, + TrackBlocks074, + TrackBlocks075, + TrackBlocks076, + TrackBlocks077, + TrackBlocks078, + TrackBlocks079, + TrackBlocks080, + TrackBlocks081, + TrackBlocks082, + TrackBlocks083, + TrackBlocks084, + TrackBlocks085, + TrackBlocks086, + TrackBlocks087, + TrackBlocks088, + TrackBlocks089, + TrackBlocks090, + TrackBlocks091, + TrackBlocks092, + TrackBlocks093, + TrackBlocks094, + TrackBlocks095, + TrackBlocks096, + TrackBlocks097, + TrackBlocks098, + TrackBlocks099, + TrackBlocks100, + TrackBlocks101, + TrackBlocks102, + TrackBlocks103, + TrackBlocks104, + TrackBlocks105, + TrackBlocks106, + TrackBlocks107, + TrackBlocks108, + TrackBlocks109, + TrackBlocks110, + TrackBlocks111, + TrackBlocks112, + TrackBlocks113, + TrackBlocks114, + TrackBlocks115, + TrackBlocks116, + TrackBlocks117, + TrackBlocks118, + TrackBlocks119, + TrackBlocks120, + TrackBlocks121, + TrackBlocks122, + TrackBlocks123, + TrackBlocks124, + TrackBlocks125, + TrackBlocks126, + TrackBlocks127, + TrackBlocks128, + TrackBlocks129, + TrackBlocks130, + TrackBlocks131, + TrackBlocks132, + TrackBlocks133, + TrackBlocks134, + TrackBlocks135, + TrackBlocks136, + TrackBlocks137, + TrackBlocks138, + TrackBlocks139, + TrackBlocks140, + TrackBlocks141, + TrackBlocks142, + TrackBlocks143, + TrackBlocks144, + TrackBlocks145, + TrackBlocks146, + TrackBlocks147, + TrackBlocks148, + TrackBlocks149, + TrackBlocks150, + TrackBlocks151, + TrackBlocks152, + TrackBlocks153, + TrackBlocks154, + TrackBlocks155, + TrackBlocks156, + TrackBlocks157, + TrackBlocks158, + TrackBlocks159, + TrackBlocks160, + TrackBlocks161, + TrackBlocks162, + TrackBlocks163, + TrackBlocks164, + TrackBlocks165, + TrackBlocks166, + TrackBlocks167, + TrackBlocks168, + TrackBlocks169, + TrackBlocks170, + TrackBlocks171, + TrackBlocks172, + TrackBlocks173, + TrackBlocks174, + TrackBlocks175, + TrackBlocks176, + TrackBlocks177, + TrackBlocks178, + TrackBlocks179, + TrackBlocks180, + TrackBlocks181, + TrackBlocks182, + TrackBlocks183, + TrackBlocks184, + TrackBlocks185, + TrackBlocks186, + TrackBlocks187, + TrackBlocks188, + TrackBlocks189, + TrackBlocks190, + TrackBlocks191, + TrackBlocks192, + TrackBlocks193, + TrackBlocks194, + TrackBlocks195, + TrackBlocks196, + TrackBlocks197, + TrackBlocks198, + TrackBlocks199, + TrackBlocks200, + TrackBlocks201, + TrackBlocks202, + TrackBlocks203, + TrackBlocks204, + TrackBlocks205, + TrackBlocks206, + TrackBlocks207, + TrackBlocks208, + TrackBlocks209, + TrackBlocks210, + TrackBlocks211, + TrackBlocks212, + TrackBlocks213, + TrackBlocks214, + TrackBlocks215, + TrackBlocks216, + TrackBlocks217, + TrackBlocks218, + TrackBlocks219, + TrackBlocks220, + TrackBlocks221, + TrackBlocks222, + TrackBlocks223, + TrackBlocks224, + TrackBlocks225, + TrackBlocks226, + TrackBlocks227, + TrackBlocks228, + TrackBlocks229, + TrackBlocks230, + TrackBlocks231, + TrackBlocks232, + TrackBlocks233, + TrackBlocks234, + TrackBlocks235, + TrackBlocks236, + TrackBlocks237, + TrackBlocks238, + TrackBlocks239, + TrackBlocks240, + TrackBlocks241, + TrackBlocks242, + TrackBlocks243, + TrackBlocks244, + TrackBlocks245, + TrackBlocks246, + TrackBlocks247, + TrackBlocks248, + TrackBlocks249, + TrackBlocks250, + TrackBlocks251, + TrackBlocks252, + TrackBlocks253, + TrackBlocks254, + TrackBlocks255 +}; + +static const rct_preview_track FlatRideTrackBlocks000[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks001[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks002[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks003[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks004[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks005[] = { + { 0, 0, 0, 0, 64, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks006[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks007[] = { + { 0, 0, 0, 0, 32, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks008[] = { + { 0, 0, 0, 0, 32, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks009[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks010[] = { + { 0, 0, 0, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks011[] = { + { 0, 0, 0, 0, 64, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks012[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks013[] = { + { 0, 0, 0, 0, 32, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks014[] = { + { 0, 0, 0, 0, 32, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks015[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks016[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 0, 8, 1 }, + { 5, -64, -32, 0, 0, 7, 0 }, + { 6, -64, -64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks017[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 0, 4, 1 }, + { 5, -64, 32, 0, 0, 11, 0 }, + { 6, -64, 64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks018[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks019[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks020[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks021[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks022[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 0, 8, 1 }, + { 5, -64, -32, 0, 0, 7, 0 }, + { 6, -64, -64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks023[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 0, 4, 1 }, + { 5, -64, 32, 0, 0, 11, 0 }, + { 6, -64, 64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks024[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks025[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks026[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks027[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks028[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks029[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks030[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks031[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks032[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks033[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks034[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + { 1, 0, -32, 16, 0, 8, 1 }, + { 2, -32, 0, 16, 16, 71, 0 }, + { 3, -32, -32, 24, 16, 13, 0 }, + { 4, -32, -64, 48, 0, 8, 1 }, + { 5, -64, -32, 32, 16, 71, 0 }, + { 6, -64, -64, 48, 16, 111, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks035[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + { 1, 0, 32, 16, 0, 4, 1 }, + { 2, -32, 0, 16, 16, 139, 0 }, + { 3, -32, 32, 24, 16, 14, 0 }, + { 4, -32, 64, 48, 0, 4, 1 }, + { 5, -64, 32, 32, 16, 139, 0 }, + { 6, -64, 64, 48, 16, 159, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks036[] = { + { 0, 0, 0, 48, 16, 63, 0 }, + { 1, 0, -32, 48, 0, 8, 1 }, + { 2, -32, 0, 32, 16, 23, 0 }, + { 3, -32, -32, 24, 16, 13, 0 }, + { 4, -32, -64, 16, 0, 8, 1 }, + { 5, -64, -32, 16, 16, 23, 0 }, + { 6, -64, -64, 0, 16, 159, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks037[] = { + { 0, 0, 0, 48, 16, 63, 0 }, + { 1, 0, 32, 48, 0, 4, 1 }, + { 2, -32, 0, 32, 16, 43, 0 }, + { 3, -32, 32, 24, 16, 14, 0 }, + { 4, -32, 64, 16, 0, 4, 1 }, + { 5, -64, 32, 16, 16, 43, 0 }, + { 6, -64, 64, 0, 16, 111, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks038[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 7, 0 }, + { 2, -32, -32, 0, 0, 13, 0 }, + { 3, -64, -32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks039[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 11, 0 }, + { 2, -32, 32, 0, 0, 14, 0 }, + { 3, -64, 32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks040[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + { 1, -32, 0, 16, 16, 207, 0 }, + { 2, -64, 0, 32, 96, 2, 0 }, + { 3, -32, 0, 120, 16, 6, 0 }, + { 4, -32, -32, 120, 0, 0, 0 }, + { 5, 0, 0, 120, 0, 0, 0 }, + { 6, 0, -32, 120, 16, 9, 0 }, + { 7, 32, -32, 32, 96, 8, 0 }, + { 8, 0, -32, 16, 16, 63, 0 }, + { 9, -32, -32, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks041[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + { 1, -32, 0, 16, 16, 207, 0 }, + { 2, -64, 0, 32, 96, 1, 0 }, + { 3, -32, 0, 120, 16, 9, 0 }, + { 4, -32, 32, 120, 0, 0, 0 }, + { 5, 0, 0, 120, 0, 0, 0 }, + { 6, 0, 32, 120, 16, 6, 0 }, + { 7, 32, 32, 32, 96, 4, 0 }, + { 8, 0, 32, 16, 16, 63, 0 }, + { 9, -32, 32, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks042[] = { + { 0, 0, 0, 0, 0, 7, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 2, 0 }, + { 3, -32, -32, 0, 0, 7, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks043[] = { + { 0, 0, 0, 0, 0, 11, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 0 }, + { 3, -32, 32, 0, 0, 11, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks044[] = { + { 0, 0, 0, 0, 0, 7, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 2, 0 }, + { 3, -32, -32, 0, 0, 7, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks045[] = { + { 0, 0, 0, 0, 0, 11, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 0 }, + { 3, -32, 32, 0, 0, 11, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks046[] = { + { 0, 0, 0, 0, 16, 71, 0 }, + { 1, 0, -32, 16, 0, 8, 1 }, + { 2, -32, 0, 16, 0, 2, 0 }, + { 3, -32, -32, 16, 16, 103, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks047[] = { + { 0, 0, 0, 0, 16, 139, 0 }, + { 1, 0, 32, 16, 0, 4, 1 }, + { 2, -32, 0, 16, 0, 1, 0 }, + { 3, -32, 32, 16, 16, 155, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks048[] = { + { 0, 0, 0, 16, 16, 55, 0 }, + { 1, 0, -32, 16, 0, 8, 1 }, + { 2, -32, 0, 16, 0, 2, 0 }, + { 3, -32, -32, 0, 16, 23, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks049[] = { + { 0, 0, 0, 16, 16, 59, 0 }, + { 1, 0, 32, 16, 0, 4, 1 }, + { 2, -32, 0, 16, 0, 1, 0 }, + { 3, -32, 32, 0, 16, 43, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks050[] = { + { 0, 0, 0, 0, 0, 7, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks051[] = { + { 0, 0, 0, 0, 0, 11, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks052[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 16, 15, 0 }, + { 2, -64, 0, 16, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks053[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 16, 15, 0 }, + { 2, -64, 0, 16, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks054[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, -16, 16, 15, 0 }, + { 2, -64, 0, -16, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks055[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, -16, 16, 15, 0 }, + { 2, -64, 0, -16, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks056[] = { + { 0, 0, 0, 0, 32, 207, 0 }, + { 1, -32, 0, 16, 16, 207, 0 }, + { 2, -64, 0, 32, 96, 3, 0 }, + { 3, -32, 0, 120, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks057[] = { + { 0, 0, 0, -32, 32, 15, 0 }, + { 1, -32, 0, -120, 96, 3, 0 }, + { 2, 0, 0, -136, 16, 207, 0 }, + { 3, 32, 0, -152, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks058[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 24, 32, 7, 0 }, + { 2, -32, -32, 48, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks059[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 24, 32, 11, 0 }, + { 2, -32, 32, 48, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks060[] = { + { 0, 0, 0, -32, 16, 15, 0 }, + { 1, -32, 0, -56, 32, 7, 0 }, + { 2, -32, -32, -80, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks061[] = { + { 0, 0, 0, -32, 16, 15, 0 }, + { 1, -32, 0, -56, 32, 11, 0 }, + { 2, -32, 32, -80, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks062[] = { + { 0, 0, 0, 0, 24, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks063[] = { + { 0, 0, 0, 0, 24, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks064[] = { + { 0, 0, 0, 0, 24, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks065[] = { + { 0, 0, 0, 0, 24, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks066[] = { + { 0, 0, 0, 0, 64, 15, 0 }, + { 1, -32, -32, 0, 0, 15, 0 }, + { 2, -32, 0, 0, 0, 15, 0 }, + { 3, -32, 32, 0, 0, 15, 0 }, + { 4, 0, -32, 0, 0, 15, 0 }, + { 5, 0, 32, 0, 0, 15, 0 }, + { 6, 32, -32, 0, 0, 15, 0 }, + { 7, 32, 32, 0, 0, 15, 0 }, + { 8, 32, 0, 0, 0, 15, 2 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks067[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 32, 0, 0, 0, 0, 3 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks068[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks069[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks070[] = { + { 0, 0, 0, 0, 64, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks071[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks072[] = { + { 0, 0, 0, 0, 32, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks073[] = { + { 0, 0, 0, 0, 32, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks074[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks075[] = { + { 0, 0, 0, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks076[] = { + { 0, 0, 0, 0, 64, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks077[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks078[] = { + { 0, 0, 0, 0, 32, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks079[] = { + { 0, 0, 0, 0, 32, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks080[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks081[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 0, 8, 1 }, + { 5, -64, -32, 0, 0, 7, 0 }, + { 6, -64, -64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks082[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 0, 4, 1 }, + { 5, -64, 32, 0, 0, 11, 0 }, + { 6, -64, 64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks083[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 7, 0 }, + { 2, -32, -32, 0, 0, 13, 0 }, + { 3, -64, -32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks084[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 11, 0 }, + { 2, -32, 32, 0, 0, 14, 0 }, + { 3, -64, 32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks085[] = { + { 0, 0, 0, 0, 0, 7, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 2, 0 }, + { 3, -32, -32, 0, 0, 7, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks086[] = { + { 0, 0, 0, 0, 0, 11, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 0 }, + { 3, -32, 32, 0, 0, 11, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks087[] = { + { 0, 0, 0, 0, 0, 7, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 4, 2, 0 }, + { 3, -32, -32, 0, 4, 7, 0 }, + { 4, -32, -64, 8, 0, 11, 0 }, + { 5, 0, -64, 8, 0, 4, 1 }, + { 6, -32, -96, 8, 4, 1, 0 }, + { 7, 0, -96, 8, 4, 11, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks088[] = { + { 0, 0, 0, 0, 0, 11, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 4, 1, 0 }, + { 3, -32, 32, 0, 4, 11, 0 }, + { 4, -32, 64, 8, 0, 7, 0 }, + { 5, 0, 64, 8, 0, 8, 1 }, + { 6, -32, 96, 8, 4, 2, 0 }, + { 7, 0, 96, 8, 4, 7, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks089[] = { + { 0, 0, 0, 8, 4, 7, 0 }, + { 1, 0, -32, 8, 4, 8, 1 }, + { 2, -32, 0, 8, 0, 2, 0 }, + { 3, -32, -32, 8, 0, 7, 0 }, + { 4, -32, -64, 0, 4, 11, 0 }, + { 5, 0, -64, 0, 4, 4, 1 }, + { 6, -32, -96, 0, 0, 1, 0 }, + { 7, 0, -96, 0, 0, 11, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks090[] = { + { 0, 0, 0, 8, 4, 11, 0 }, + { 1, 0, 32, 8, 4, 4, 1 }, + { 2, -32, 0, 8, 0, 1, 0 }, + { 3, -32, 32, 8, 0, 11, 0 }, + { 4, -32, 64, 0, 4, 7, 0 }, + { 5, 0, 64, 0, 4, 8, 1 }, + { 6, -32, 96, 0, 0, 2, 0 }, + { 7, 0, 96, 0, 0, 7, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks091[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 4, 8, 1 }, + { 5, -64, -32, 0, 4, 7, 0 }, + { 6, -64, -64, 0, 4, 15, 0 }, + { 7, -64, -96, 8, 0, 15, 0 }, + { 8, -32, -96, 8, 0, 4, 1 }, + { 9, -64, -128, 8, 0, 11, 0 }, + { 10, -32, -128, 8, 0, 14, 0 }, + { 11, 0, -128, 8, 4, 4, 1 }, + { 12, -32, -160, 8, 4, 11, 0 }, + { 13, 0, -160, 8, 4, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks092[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 4, 4, 1 }, + { 5, -64, 32, 0, 4, 11, 0 }, + { 6, -64, 64, 0, 4, 15, 0 }, + { 7, -64, 96, 8, 0, 15, 0 }, + { 8, -32, 96, 8, 0, 8, 1 }, + { 9, -64, 128, 8, 0, 7, 0 }, + { 10, -32, 128, 8, 0, 13, 0 }, + { 11, 0, 128, 8, 4, 8, 1 }, + { 12, -32, 160, 8, 4, 7, 0 }, + { 13, 0, 160, 8, 4, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks093[] = { + { 0, 0, 0, 8, 4, 15, 0 }, + { 1, 0, -32, 8, 4, 8, 1 }, + { 2, -32, 0, 8, 4, 7, 0 }, + { 3, -32, -32, 8, 0, 13, 0 }, + { 4, -32, -64, 8, 0, 8, 1 }, + { 5, -64, -32, 8, 0, 7, 0 }, + { 6, -64, -64, 8, 0, 15, 0 }, + { 7, -64, -96, 0, 4, 15, 0 }, + { 8, -32, -96, 0, 4, 4, 1 }, + { 9, -64, -128, 0, 4, 11, 0 }, + { 10, -32, -128, 0, 0, 14, 0 }, + { 11, 0, -128, 0, 0, 4, 1 }, + { 12, -32, -160, 0, 0, 11, 0 }, + { 13, 0, -160, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks094[] = { + { 0, 0, 0, 8, 4, 15, 0 }, + { 1, 0, 32, 8, 4, 4, 1 }, + { 2, -32, 0, 8, 4, 11, 0 }, + { 3, -32, 32, 8, 0, 14, 0 }, + { 4, -32, 64, 8, 0, 4, 1 }, + { 5, -64, 32, 8, 0, 11, 0 }, + { 6, -64, 64, 8, 0, 15, 0 }, + { 7, -64, 96, 0, 4, 15, 0 }, + { 8, -32, 96, 0, 4, 8, 1 }, + { 9, -64, 128, 0, 4, 7, 0 }, + { 10, -32, 128, 0, 0, 13, 0 }, + { 11, 0, 128, 0, 0, 8, 1 }, + { 12, -32, 160, 0, 0, 7, 0 }, + { 13, 0, 160, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks095[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -64, 0, 0, 0, 15, 0 }, + { 2, -32, 0, 0, 0, 15, 0 }, + { 3, 32, 0, 0, 0, 15, 2 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks096[] = { + { 0, 0, 0, 0, 64, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks097[] = { + { 0, 0, 0, 0, 64, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks098[] = { + { 0, 0, 0, 0, 64, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks099[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks100[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks101[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks102[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 12, 8, 1 }, + { 5, -64, -32, 0, 12, 7, 0 }, + { 6, -64, -64, 0, 12, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks103[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 12, 4, 1 }, + { 5, -64, 32, 0, 12, 11, 0 }, + { 6, -64, 64, 0, 12, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks104[] = { + { 0, 0, 0, 0, 12, 15, 0 }, + { 1, 0, -32, 0, 12, 8, 1 }, + { 2, -32, 0, 0, 12, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 0, 8, 1 }, + { 5, -64, -32, 0, 0, 7, 0 }, + { 6, -64, -64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks105[] = { + { 0, 0, 0, 0, 12, 15, 0 }, + { 1, 0, 32, 0, 12, 4, 1 }, + { 2, -32, 0, 0, 12, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 0, 4, 1 }, + { 5, -64, 32, 0, 0, 11, 0 }, + { 6, -64, 64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks106[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 0, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 12, 8, 1 }, + { 5, -64, -32, 0, 12, 7, 0 }, + { 6, -64, -64, 0, 12, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks107[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 12, 4, 1 }, + { 5, -64, 32, 0, 12, 11, 0 }, + { 6, -64, 64, 0, 12, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks108[] = { + { 0, 0, 0, 0, 12, 15, 0 }, + { 1, 0, -32, 0, 12, 8, 1 }, + { 2, -32, 0, 0, 12, 7, 0 }, + { 3, -32, -32, 0, 0, 13, 0 }, + { 4, -32, -64, 0, 0, 8, 1 }, + { 5, -64, -32, 0, 0, 7, 0 }, + { 6, -64, -64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks109[] = { + { 0, 0, 0, 0, 12, 15, 0 }, + { 1, 0, 32, 0, 12, 4, 1 }, + { 2, -32, 0, 0, 12, 11, 0 }, + { 3, -32, 32, 0, 0, 14, 0 }, + { 4, -32, 64, 0, 0, 4, 1 }, + { 5, -64, 32, 0, 0, 11, 0 }, + { 6, -64, 64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks110[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 15, 0 }, + { 2, 32, 0, 0, 0, 15, 0 }, + { 3, 32, 32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks111[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 15, 0 }, + { 2, 0, 64, 0, 0, 15, 0 }, + { 3, 0, 96, 0, 0, 15, 0 }, + { 4, 32, 0, 0, 0, 15, 0 }, + { 5, 32, 32, 0, 0, 15, 0 }, + { 6, 32, 64, 0, 0, 15, 0 }, + { 7, 32, 96, 0, 0, 15, 0 }, + { 8, 64, 0, 0, 0, 15, 0 }, + { 9, 64, 32, 0, 0, 15, 0 }, + { 10, 64, 64, 0, 0, 15, 0 }, + { 11, 64, 96, 0, 0, 15, 0 }, + { 12, 96, 0, 0, 0, 15, 0 }, + { 13, 96, 32, 0, 0, 15, 0 }, + { 14, 96, 64, 0, 0, 15, 0 }, + { 15, 96, 96, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks112[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks113[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks114[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks115[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 15, 0 }, + { 2, 0, 64, 0, 0, 15, 0 }, + { 3, 0, 96, 0, 0, 15, 0 }, + { 4, 32, 0, 0, 0, 15, 0 }, + { 5, 32, 32, 0, 0, 15, 0 }, + { 6, 32, 64, 0, 0, 15, 0 }, + { 7, 32, 96, 0, 0, 15, 2 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks116[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -64, 0, 0, 0, 15, 0 }, + { 2, -32, 0, 0, 0, 15, 0 }, + { 3, 32, 0, 0, 0, 15, 0 }, + { 4, 64, 0, 0, 0, 15, 2 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks117[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 0, 16, 15, 0 }, + { 2, -64, 0, 0, 16, 15, 0 }, + { 3, -96, 0, 0, 16, 15, 0 }, + { 4, -128, 0, 0, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks118[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks119[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -64, 0, 0, 0, 15, 0 }, + { 2, -32, 0, 0, 0, 15, 0 }, + { 3, 32, 0, 0, 0, 15, 2 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks120[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks121[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks122[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -64, 0, 0, 0, 15, 0 }, + { 2, -32, 0, 0, 0, 15, 0 }, + { 3, 32, 0, 0, 0, 15, 2 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks123[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, -32, 0, 0, 15, 0 }, + { 2, -32, 0, 0, 0, 15, 0 }, + { 3, -32, 32, 0, 0, 15, 0 }, + { 4, 0, -32, 0, 0, 15, 0 }, + { 5, 0, 32, 0, 0, 15, 0 }, + { 6, 32, -32, 0, 0, 15, 0 }, + { 7, 32, 32, 0, 0, 15, 0 }, + { 8, 32, 0, 0, 0, 15, 2 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks124[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 0, 32, 15, 0 }, + { 2, -64, 0, 0, 48, 15, 0 }, + { 3, -96, 0, 0, 80, 15, 0 }, + { 4, -128, 0, 0, 160, 15, 0 }, + { 5, -192, 0, 0, 208, 15, 0 }, + { 6, -160, 0, 0, 208, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks125[] = { + { 0, 0, 0, 0, 48, 15, 0 }, + { 1, 32, 0, 0, 48, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks126[] = { + { 0, 0, 0, 0, 8, 15, 4 }, + { 1, 32, 0, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks127[] = { + { 0, 0, 0, 0, 8, 15, 4 }, + { 1, 32, 0, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks128[] = { + { 0, 0, 0, 0, 32, 207, 4 }, + { 1, 32, 0, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks129[] = { + { 0, 0, 0, 0, 32, 63, 4 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks130[] = { + { 0, 0, 0, 0, 56, 15, 4 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks131[] = { + { 0, 0, 0, 0, 56, 15, 4 }, + { 1, 32, 0, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks132[] = { + { 0, 0, 0, 0, 24, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks133[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -32, -32, 0, 0, 8, 0 }, + { 3, -64, 0, 0, 0, 2, 1 }, + { 4, -64, -32, 0, 0, 1, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks134[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -32, 32, 0, 0, 4, 0 }, + { 3, -64, 0, 0, 0, 1, 1 }, + { 4, -64, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks135[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, -32, 0, 0, 0, 1, 0 }, + { 2, 0, 32, 0, 0, 4, 1 }, + { 3, -32, 32, 0, 0, 15, 0 }, + { 4, -64, 32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks136[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 0 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 15, 0 }, + { 4, -32, 64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks137[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -32, -32, 0, 0, 8, 0 }, + { 3, -64, 0, 0, 0, 2, 1 }, + { 4, -64, -32, 0, 0, 1, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks138[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -32, 32, 0, 0, 4, 0 }, + { 3, -64, 0, 0, 0, 1, 1 }, + { 4, -64, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks139[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, -32, 0, 0, 0, 1, 0 }, + { 2, 0, 32, 0, 0, 4, 1 }, + { 3, -32, 32, 0, 0, 15, 0 }, + { 4, -64, 32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks140[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 0 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 15, 0 }, + { 4, -32, 64, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks141[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks142[] = { + { 0, 0, 0, 0, 16, 13, 0 }, + { 1, 0, 32, 0, 16, 4, 1 }, + { 2, -32, 0, 0, 16, 1, 1 }, + { 3, -32, 32, 0, 16, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks143[] = { + { 0, 0, 0, 0, 64, 13, 0 }, + { 1, 0, 32, 0, 64, 4, 1 }, + { 2, -32, 0, 0, 64, 1, 1 }, + { 3, -32, 32, 0, 64, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks144[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks145[] = { + { 0, 0, 0, 0, 32, 13, 0 }, + { 1, 0, 32, 0, 32, 4, 1 }, + { 2, -32, 0, 0, 32, 1, 1 }, + { 3, -32, 32, 0, 32, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks146[] = { + { 0, 0, 0, 0, 32, 13, 0 }, + { 1, 0, 32, 0, 32, 4, 1 }, + { 2, -32, 0, 0, 32, 1, 1 }, + { 3, -32, 32, 0, 32, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks147[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks148[] = { + { 0, 0, 0, 0, 16, 13, 0 }, + { 1, 0, 32, 0, 16, 4, 1 }, + { 2, -32, 0, 0, 16, 1, 1 }, + { 3, -32, 32, 0, 16, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks149[] = { + { 0, 0, 0, 0, 64, 13, 0 }, + { 1, 0, 32, 0, 64, 4, 1 }, + { 2, -32, 0, 0, 64, 1, 1 }, + { 3, -32, 32, 0, 64, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks150[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks151[] = { + { 0, 0, 0, 0, 32, 13, 0 }, + { 1, 0, 32, 0, 32, 4, 1 }, + { 2, -32, 0, 0, 32, 1, 1 }, + { 3, -32, 32, 0, 32, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks152[] = { + { 0, 0, 0, 0, 32, 13, 0 }, + { 1, 0, 32, 0, 32, 4, 1 }, + { 2, -32, 0, 0, 32, 1, 1 }, + { 3, -32, 32, 0, 32, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks153[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks154[] = { + { 0, 0, 0, 0, 24, 13, 0 }, + { 1, 0, 32, 0, 24, 4, 1 }, + { 2, -32, 0, 0, 24, 1, 1 }, + { 3, -32, 32, 0, 24, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks155[] = { + { 0, 0, 0, 0, 24, 13, 0 }, + { 1, 0, 32, 0, 24, 4, 1 }, + { 2, -32, 0, 0, 24, 1, 1 }, + { 3, -32, 32, 0, 24, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks156[] = { + { 0, 0, 0, 0, 24, 13, 0 }, + { 1, 0, 32, 0, 24, 4, 1 }, + { 2, -32, 0, 0, 24, 1, 1 }, + { 3, -32, 32, 0, 24, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks157[] = { + { 0, 0, 0, 0, 24, 13, 0 }, + { 1, 0, 32, 0, 24, 4, 1 }, + { 2, -32, 0, 0, 24, 1, 1 }, + { 3, -32, 32, 0, 24, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks158[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks159[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks160[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks161[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks162[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks163[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks164[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks165[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks166[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks167[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks168[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks169[] = { + { 0, 0, 0, 0, 8, 13, 0 }, + { 1, 0, 32, 0, 8, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 1 }, + { 3, -32, 32, 0, 8, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks170[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks171[] = { + { 0, 0, 0, 0, 0, 13, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 0, 1, 1 }, + { 3, -32, 32, 0, 0, 2, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks172[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks173[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks174[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 16, 15, 0 }, + { 2, -64, 0, 0, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks175[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 16, 15, 0 }, + { 2, -64, 0, 0, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks176[] = { + { 0, 0, 0, -32, 16, 15, 0 }, + { 1, -32, 0, -32, 16, 15, 0 }, + { 2, -64, 0, -32, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks177[] = { + { 0, 0, 0, -32, 16, 15, 0 }, + { 1, -32, 0, -32, 16, 15, 0 }, + { 2, -64, 0, -32, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks178[] = { + { 0, 0, 0, 0, 0, 71, 0 }, + { 1, 0, -32, 0, 16, 8, 1 }, + { 2, -32, 0, 0, 16, 2, 0 }, + { 3, -32, -32, 16, 16, 103, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks179[] = { + { 0, 0, 0, 0, 16, 139, 0 }, + { 1, 0, 32, 0, 16, 4, 1 }, + { 2, -32, 0, 0, 16, 1, 0 }, + { 3, -32, 32, 16, 16, 155, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks180[] = { + { 0, 0, 0, 16, 16, 55, 0 }, + { 1, 0, -32, 0, 16, 8, 1 }, + { 2, -32, 0, 0, 16, 2, 0 }, + { 3, -32, -32, 0, 0, 23, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks181[] = { + { 0, 0, 0, 16, 16, 59, 0 }, + { 1, 0, 32, 0, 16, 4, 1 }, + { 2, -32, 0, 0, 16, 1, 0 }, + { 3, -32, 32, 0, 0, 43, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks182[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks183[] = { + { 0, 0, 0, 0, 24, 207, 0 }, + { 1, -32, 0, 16, 40, 207, 0 }, + { 2, -64, 0, 32, 56, 15, 0 }, + { 3, -96, 0, 64, 192, 15, 0 }, + { 4, -128, -32, 120, 96, 15, 0 }, + { 5, -96, -32, 64, 192, 15, 0 }, + { 6, -64, -32, 248, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks184[] = { + { 0, 0, 0, 0, 24, 207, 0 }, + { 1, -32, 0, 16, 40, 207, 0 }, + { 2, -64, 0, 32, 56, 15, 0 }, + { 3, -96, 0, 64, 192, 15, 0 }, + { 4, -128, 32, 120, 96, 15, 0 }, + { 5, -96, 32, 64, 192, 15, 0 }, + { 6, -64, 32, 248, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks185[] = { + { 0, 0, 0, -32, 24, 15, 0 }, + { 1, -32, 0, -216, 192, 15, 0 }, + { 2, -64, 0, -160, 96, 15, 0 }, + { 3, -32, -32, -216, 192, 15, 0 }, + { 4, 0, -32, -248, 56, 15, 0 }, + { 5, 32, -32, -264, 40, 207, 0 }, + { 6, 64, -32, -280, 24, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks186[] = { + { 0, 0, 0, -32, 24, 15, 0 }, + { 1, -32, 0, -216, 192, 15, 0 }, + { 2, -64, 0, -160, 96, 15, 0 }, + { 3, -32, 32, -216, 192, 15, 0 }, + { 4, 0, 32, -248, 56, 15, 0 }, + { 5, 32, 32, -264, 40, 207, 0 }, + { 6, 64, 32, -280, 24, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks187[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, -16, 16, 15, 0 }, + { 2, -64, 0, -16, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks188[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, -16, 16, 15, 0 }, + { 2, -64, 0, -16, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks189[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 0, 16, 15, 0 }, + { 2, -64, 0, 16, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks190[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 0, 16, 15, 0 }, + { 2, -64, 0, 16, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks191[] = { + { 0, 0, 0, 0, 32, 207, 0 }, + { 1, -32, 0, 16, 16, 207, 0 }, + { 2, -64, 0, 32, 96, 3, 0 }, + { 3, -32, 0, 120, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks192[] = { + { 0, 0, 0, 0, 32, 15, 0 }, + { 1, -32, 0, -88, 96, 3, 0 }, + { 2, 0, 0, -104, 16, 207, 0 }, + { 3, 32, 0, -120, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks193[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 24, 32, 7, 0 }, + { 2, -32, -32, 48, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks194[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, 24, 32, 11, 0 }, + { 2, -32, 32, 48, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks195[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, -24, 32, 7, 0 }, + { 2, -32, -32, -48, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks196[] = { + { 0, 0, 0, 0, 16, 15, 0 }, + { 1, -32, 0, -24, 32, 11, 0 }, + { 2, -32, 32, -48, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks197[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 32, 15, 0 }, + { 2, -64, 0, 16, 0, 15, 0 }, + { 3, 0, 0, 32, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks198[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, -32, 32, 15, 0 }, + { 2, -64, 0, -16, 0, 15, 0 }, + { 3, 0, 0, -32, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks199[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -64, 0, 0, 0, 15, 0 }, + { 3, -96, 0, 0, 0, 15, 0 }, + { 4, -128, 0, 0, 0, 15, 0 }, + { 5, -160, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks200[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -64, 0, 0, 0, 15, 0 }, + { 3, -96, 0, 0, 0, 15, 0 }, + { 4, -128, 0, 0, 0, 15, 0 }, + { 5, -160, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks201[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks202[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks203[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks204[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -32, 32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks205[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, -32, 0, 0, 0, 15, 0 }, + { 2, -32, -32, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks206[] = { + { 0, 0, 0, 0, 16, 15, 4 }, + { 1, -32, 0, -40, 32, 15, 4 }, + { 2, -64, 0, -96, 56, 15, 4 }, + { 3, -96, 0, -96, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks207[] = { + { 0, 0, 0, 0, 56, 15, 4 }, + { 1, 32, 0, 56, 32, 15, 4 }, + { 2, 64, 0, 96, 16, 15, 4 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks208[] = { + { 0, 0, 0, -32, 16, 15, 4 }, + { 1, -32, 0, -72, 32, 15, 4 }, + { 2, -64, 0, -128, 56, 15, 4 }, + { 3, -96, 0, -128, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks209[] = { + { 0, 0, 0, 0, 0, 7, 0 }, + { 1, 0, -32, 0, 0, 8, 1 }, + { 2, -32, 0, 0, 8, 2, 0 }, + { 3, -32, -32, 0, 8, 7, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks210[] = { + { 0, 0, 0, 0, 0, 11, 0 }, + { 1, 0, 32, 0, 0, 4, 1 }, + { 2, -32, 0, 0, 8, 1, 0 }, + { 3, -32, 32, 0, 8, 11, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks211[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, -32, 0, 0, 15, 0 }, + { 2, -32, -32, 0, 0, 15, 0 }, + { 3, -64, -32, 0, 0, 15, 0 }, + { 4, -32, 0, 0, 0, 15, 0 }, + { 5, -64, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks212[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + { 1, 0, 32, 0, 0, 15, 0 }, + { 2, -32, 32, 0, 0, 15, 0 }, + { 3, -64, 32, 0, 0, 15, 0 }, + { 4, -32, 0, 0, 0, 15, 0 }, + { 5, -64, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks213[] = { + { 0, 0, 0, 0, 32, 15, 0 }, + { 1, 32, 0, 0, 32, 15, 0 }, + { 2, -64, 0, 0, 32, 15, 0 }, + { 3, -32, 0, 0, 32, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks214[] = { + { 0, 0, 0, 0, 48, 15, 0 }, + { 1, 32, 0, 0, 48, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks215[] = { + { 0, 0, 0, 0, 208, 15, 0 }, + { 1, 32, 0, 0, 208, 15, 0 }, + { 2, -32, 0, 0, 160, 15, 0 }, + { 3, -64, 0, 0, 80, 15, 0 }, + { 4, -96, 0, 0, 48, 15, 0 }, + { 5, -128, 0, 0, 32, 15, 0 }, + { 6, -160, 0, 0, 16, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks216[] = { + { 0, 0, 0, 0, 0, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks217[] = { + { 0, 0, 0, 0, 16, 71, 0 }, + { 1, 0, -32, 16, 0, 8, 1 }, + { 2, -32, 0, 16, 0, 2, 0 }, + { 3, -32, -32, 16, 16, 103, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks218[] = { + { 0, 0, 0, 0, 16, 139, 0 }, + { 1, 0, 32, 16, 0, 4, 1 }, + { 2, -32, 0, 16, 0, 1, 0 }, + { 3, -32, 32, 16, 16, 155, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks219[] = { + { 0, 0, 0, 16, 16, 55, 0 }, + { 1, 0, -32, 16, 0, 8, 1 }, + { 2, -32, 0, 16, 0, 2, 0 }, + { 3, -32, -32, 0, 16, 23, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks220[] = { + { 0, 0, 0, 16, 16, 59, 0 }, + { 1, 0, 32, 16, 0, 4, 1 }, + { 2, -32, 0, 16, 0, 1, 0 }, + { 3, -32, 32, 0, 16, 43, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks221[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + { 1, 0, -32, 16, 0, 8, 1 }, + { 2, -32, 0, 16, 16, 71, 0 }, + { 3, -32, -32, 24, 16, 13, 0 }, + { 4, -32, -64, 48, 0, 8, 1 }, + { 5, -64, -32, 32, 16, 71, 0 }, + { 6, -64, -64, 48, 16, 111, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks222[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + { 1, 0, 32, 16, 0, 4, 1 }, + { 2, -32, 0, 16, 16, 139, 0 }, + { 3, -32, 32, 24, 16, 14, 0 }, + { 4, -32, 64, 48, 0, 4, 1 }, + { 5, -64, 32, 32, 16, 139, 0 }, + { 6, -64, 64, 48, 16, 159, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks223[] = { + { 0, 0, 0, 48, 16, 63, 0 }, + { 1, 0, -32, 48, 0, 8, 1 }, + { 2, -32, 0, 32, 16, 23, 0 }, + { 3, -32, -32, 24, 16, 13, 0 }, + { 4, -32, -64, 16, 0, 8, 1 }, + { 5, -64, -32, 16, 16, 23, 0 }, + { 6, -64, -64, 0, 16, 159, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks224[] = { + { 0, 0, 0, 48, 16, 63, 0 }, + { 1, 0, 32, 48, 0, 4, 1 }, + { 2, -32, 0, 32, 16, 43, 0 }, + { 3, -32, 32, 24, 16, 14, 0 }, + { 4, -32, 64, 16, 0, 4, 1 }, + { 5, -64, 32, 16, 16, 43, 0 }, + { 6, -64, 64, 0, 16, 111, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks225[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks226[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks227[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks228[] = { + { 0, 0, 0, 0, 16, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks229[] = { + { 0, 0, 0, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks230[] = { + { 0, 0, 0, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks231[] = { + { 0, 0, 0, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks232[] = { + { 0, 0, 0, 0, 16, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks233[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks234[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks235[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks236[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks237[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks238[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks239[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks240[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks241[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks242[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks243[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks244[] = { + { 0, 0, 0, 0, 8, 207, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks245[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks246[] = { + { 0, 0, 0, 0, 8, 63, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks247[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks248[] = { + { 0, 0, 0, 0, 8, 15, 0 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks249[] = { + { 0, 0, 0, 0, 72, 15, 4 }, + { 1, 0, 32, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks250[] = { + { 0, 0, 0, 0, 72, 15, 4 }, + { 1, 0, -32, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks251[] = { + { 0, 0, 0, 0, 72, 15, 4 }, + { 1, 0, 32, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks252[] = { + { 0, 0, 0, 0, 72, 15, 4 }, + { 1, 0, -32, 0, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks253[] = { + { 0, 0, 0, 0, 56, 15, 4 }, + { 1, 32, 0, 56, 32, 15, 4 }, + { 2, 64, 0, 96, 16, 15, 4 }, + TRACK_BLOCK_END +}; + +static const rct_preview_track FlatRideTrackBlocks254[] = { + { 0, 0, 0, -32, 16, 15, 4 }, + { 1, -32, 0, -72, 32, 15, 4 }, + { 2, -64, 0, -128, 56, 15, 4 }, + { 3, -96, 0, -128, 0, 0, 5 }, + TRACK_BLOCK_END +}; + +// rct2: 0x00994A38 +const rct_preview_track *FlatRideTrackBlocks[255] = { + FlatRideTrackBlocks000, + FlatRideTrackBlocks001, + FlatRideTrackBlocks002, + FlatRideTrackBlocks003, + FlatRideTrackBlocks004, + FlatRideTrackBlocks005, + FlatRideTrackBlocks006, + FlatRideTrackBlocks007, + FlatRideTrackBlocks008, + FlatRideTrackBlocks009, + FlatRideTrackBlocks010, + FlatRideTrackBlocks011, + FlatRideTrackBlocks012, + FlatRideTrackBlocks013, + FlatRideTrackBlocks014, + FlatRideTrackBlocks015, + FlatRideTrackBlocks016, + FlatRideTrackBlocks017, + FlatRideTrackBlocks018, + FlatRideTrackBlocks019, + FlatRideTrackBlocks020, + FlatRideTrackBlocks021, + FlatRideTrackBlocks022, + FlatRideTrackBlocks023, + FlatRideTrackBlocks024, + FlatRideTrackBlocks025, + FlatRideTrackBlocks026, + FlatRideTrackBlocks027, + FlatRideTrackBlocks028, + FlatRideTrackBlocks029, + FlatRideTrackBlocks030, + FlatRideTrackBlocks031, + FlatRideTrackBlocks032, + FlatRideTrackBlocks033, + FlatRideTrackBlocks034, + FlatRideTrackBlocks035, + FlatRideTrackBlocks036, + FlatRideTrackBlocks037, + FlatRideTrackBlocks038, + FlatRideTrackBlocks039, + FlatRideTrackBlocks040, + FlatRideTrackBlocks041, + FlatRideTrackBlocks042, + FlatRideTrackBlocks043, + FlatRideTrackBlocks044, + FlatRideTrackBlocks045, + FlatRideTrackBlocks046, + FlatRideTrackBlocks047, + FlatRideTrackBlocks048, + FlatRideTrackBlocks049, + FlatRideTrackBlocks050, + FlatRideTrackBlocks051, + FlatRideTrackBlocks052, + FlatRideTrackBlocks053, + FlatRideTrackBlocks054, + FlatRideTrackBlocks055, + FlatRideTrackBlocks056, + FlatRideTrackBlocks057, + FlatRideTrackBlocks058, + FlatRideTrackBlocks059, + FlatRideTrackBlocks060, + FlatRideTrackBlocks061, + FlatRideTrackBlocks062, + FlatRideTrackBlocks063, + FlatRideTrackBlocks064, + FlatRideTrackBlocks065, + FlatRideTrackBlocks066, + FlatRideTrackBlocks067, + FlatRideTrackBlocks068, + FlatRideTrackBlocks069, + FlatRideTrackBlocks070, + FlatRideTrackBlocks071, + FlatRideTrackBlocks072, + FlatRideTrackBlocks073, + FlatRideTrackBlocks074, + FlatRideTrackBlocks075, + FlatRideTrackBlocks076, + FlatRideTrackBlocks077, + FlatRideTrackBlocks078, + FlatRideTrackBlocks079, + FlatRideTrackBlocks080, + FlatRideTrackBlocks081, + FlatRideTrackBlocks082, + FlatRideTrackBlocks083, + FlatRideTrackBlocks084, + FlatRideTrackBlocks085, + FlatRideTrackBlocks086, + FlatRideTrackBlocks087, + FlatRideTrackBlocks088, + FlatRideTrackBlocks089, + FlatRideTrackBlocks090, + FlatRideTrackBlocks091, + FlatRideTrackBlocks092, + FlatRideTrackBlocks093, + FlatRideTrackBlocks094, + FlatRideTrackBlocks095, + FlatRideTrackBlocks096, + FlatRideTrackBlocks097, + FlatRideTrackBlocks098, + FlatRideTrackBlocks099, + FlatRideTrackBlocks100, + FlatRideTrackBlocks101, + FlatRideTrackBlocks102, + FlatRideTrackBlocks103, + FlatRideTrackBlocks104, + FlatRideTrackBlocks105, + FlatRideTrackBlocks106, + FlatRideTrackBlocks107, + FlatRideTrackBlocks108, + FlatRideTrackBlocks109, + FlatRideTrackBlocks110, + FlatRideTrackBlocks111, + FlatRideTrackBlocks112, + FlatRideTrackBlocks113, + FlatRideTrackBlocks114, + FlatRideTrackBlocks115, + FlatRideTrackBlocks116, + FlatRideTrackBlocks117, + FlatRideTrackBlocks118, + FlatRideTrackBlocks119, + FlatRideTrackBlocks120, + FlatRideTrackBlocks121, + FlatRideTrackBlocks122, + FlatRideTrackBlocks123, + FlatRideTrackBlocks124, + FlatRideTrackBlocks125, + FlatRideTrackBlocks126, + FlatRideTrackBlocks127, + FlatRideTrackBlocks128, + FlatRideTrackBlocks129, + FlatRideTrackBlocks130, + FlatRideTrackBlocks131, + FlatRideTrackBlocks132, + FlatRideTrackBlocks133, + FlatRideTrackBlocks134, + FlatRideTrackBlocks135, + FlatRideTrackBlocks136, + FlatRideTrackBlocks137, + FlatRideTrackBlocks138, + FlatRideTrackBlocks139, + FlatRideTrackBlocks140, + FlatRideTrackBlocks141, + FlatRideTrackBlocks142, + FlatRideTrackBlocks143, + FlatRideTrackBlocks144, + FlatRideTrackBlocks145, + FlatRideTrackBlocks146, + FlatRideTrackBlocks147, + FlatRideTrackBlocks148, + FlatRideTrackBlocks149, + FlatRideTrackBlocks150, + FlatRideTrackBlocks151, + FlatRideTrackBlocks152, + FlatRideTrackBlocks153, + FlatRideTrackBlocks154, + FlatRideTrackBlocks155, + FlatRideTrackBlocks156, + FlatRideTrackBlocks157, + FlatRideTrackBlocks158, + FlatRideTrackBlocks159, + FlatRideTrackBlocks160, + FlatRideTrackBlocks161, + FlatRideTrackBlocks162, + FlatRideTrackBlocks163, + FlatRideTrackBlocks164, + FlatRideTrackBlocks165, + FlatRideTrackBlocks166, + FlatRideTrackBlocks167, + FlatRideTrackBlocks168, + FlatRideTrackBlocks169, + FlatRideTrackBlocks170, + FlatRideTrackBlocks171, + FlatRideTrackBlocks172, + FlatRideTrackBlocks173, + FlatRideTrackBlocks174, + FlatRideTrackBlocks175, + FlatRideTrackBlocks176, + FlatRideTrackBlocks177, + FlatRideTrackBlocks178, + FlatRideTrackBlocks179, + FlatRideTrackBlocks180, + FlatRideTrackBlocks181, + FlatRideTrackBlocks182, + FlatRideTrackBlocks183, + FlatRideTrackBlocks184, + FlatRideTrackBlocks185, + FlatRideTrackBlocks186, + FlatRideTrackBlocks187, + FlatRideTrackBlocks188, + FlatRideTrackBlocks189, + FlatRideTrackBlocks190, + FlatRideTrackBlocks191, + FlatRideTrackBlocks192, + FlatRideTrackBlocks193, + FlatRideTrackBlocks194, + FlatRideTrackBlocks195, + FlatRideTrackBlocks196, + FlatRideTrackBlocks197, + FlatRideTrackBlocks198, + FlatRideTrackBlocks199, + FlatRideTrackBlocks200, + FlatRideTrackBlocks201, + FlatRideTrackBlocks202, + FlatRideTrackBlocks203, + FlatRideTrackBlocks204, + FlatRideTrackBlocks205, + FlatRideTrackBlocks206, + FlatRideTrackBlocks207, + FlatRideTrackBlocks208, + FlatRideTrackBlocks209, + FlatRideTrackBlocks210, + FlatRideTrackBlocks211, + FlatRideTrackBlocks212, + FlatRideTrackBlocks213, + FlatRideTrackBlocks214, + FlatRideTrackBlocks215, + FlatRideTrackBlocks216, + FlatRideTrackBlocks217, + FlatRideTrackBlocks218, + FlatRideTrackBlocks219, + FlatRideTrackBlocks220, + FlatRideTrackBlocks221, + FlatRideTrackBlocks222, + FlatRideTrackBlocks223, + FlatRideTrackBlocks224, + FlatRideTrackBlocks225, + FlatRideTrackBlocks226, + FlatRideTrackBlocks227, + FlatRideTrackBlocks228, + FlatRideTrackBlocks229, + FlatRideTrackBlocks230, + FlatRideTrackBlocks231, + FlatRideTrackBlocks232, + FlatRideTrackBlocks233, + FlatRideTrackBlocks234, + FlatRideTrackBlocks235, + FlatRideTrackBlocks236, + FlatRideTrackBlocks237, + FlatRideTrackBlocks238, + FlatRideTrackBlocks239, + FlatRideTrackBlocks240, + FlatRideTrackBlocks241, + FlatRideTrackBlocks242, + FlatRideTrackBlocks243, + FlatRideTrackBlocks244, + FlatRideTrackBlocks245, + FlatRideTrackBlocks246, + FlatRideTrackBlocks247, + FlatRideTrackBlocks248, + FlatRideTrackBlocks249, + FlatRideTrackBlocks250, + FlatRideTrackBlocks251, + FlatRideTrackBlocks252, + FlatRideTrackBlocks253, + FlatRideTrackBlocks254 +}; + +const uint8 TrackPieceLengths[256] = { + 32, // TRACK_ELEM_FLAT + 32, // TRACK_ELEM_END_STATION + 32, // TRACK_ELEM_BEGIN_STATION + 32, // TRACK_ELEM_MIDDLE_STATION + 33, // TRACK_ELEM_25_DEG_UP + 40, // TRACK_ELEM_60_DEG_UP + 32, // TRACK_ELEM_FLAT_TO_25_DEG_UP + 34, // TRACK_ELEM_25_DEG_UP_TO_60_DEG_UP + 34, // TRACK_ELEM_60_DEG_UP_TO_25_DEG_UP + 32, // TRACK_ELEM_25_DEG_UP_TO_FLAT + 33, // TRACK_ELEM_25_DEG_DOWN + 40, // TRACK_ELEM_60_DEG_DOWN + 32, // TRACK_ELEM_FLAT_TO_25_DEG_DOWN + 34, // TRACK_ELEM_25_DEG_DOWN_TO_60_DEG_DOWN + 34, // TRACK_ELEM_60_DEG_DOWN_TO_25_DEG_DOWN + 32, // TRACK_ELEM_25_DEG_DOWN_TO_FLAT + 124, // TRACK_ELEM_LEFT_QUARTER_TURN_5_TILES + 124, // TRACK_ELEM_RIGHT_QUARTER_TURN_5_TILES + 32, // TRACK_ELEM_FLAT_TO_LEFT_BANK + 32, // TRACK_ELEM_FLAT_TO_RIGHT_BANK + 32, // TRACK_ELEM_LEFT_BANK_TO_FLAT + 32, // TRACK_ELEM_RIGHT_BANK_TO_FLAT + 124, // TRACK_ELEM_BANKED_LEFT_QUARTER_TURN_5_TILES + 124, // TRACK_ELEM_BANKED_RIGHT_QUARTER_TURN_5_TILES + 32, // TRACK_ELEM_LEFT_BANK_TO_25_DEG_UP + 32, // TRACK_ELEM_RIGHT_BANK_TO_25_DEG_UP + 32, // TRACK_ELEM_25_DEG_UP_TO_LEFT_BANK + 32, // TRACK_ELEM_25_DEG_UP_TO_RIGHT_BANK + 32, // TRACK_ELEM_LEFT_BANK_TO_25_DEG_DOWN + 32, // TRACK_ELEM_RIGHT_BANK_TO_25_DEG_DOWN + 32, // TRACK_ELEM_25_DEG_DOWN_TO_LEFT_BANK + 32, // TRACK_ELEM_25_DEG_DOWN_TO_RIGHT_BANK + 32, // TRACK_ELEM_LEFT_BANK + 32, // TRACK_ELEM_RIGHT_BANK + 130, // TRACK_ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_UP + 130, // TRACK_ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_UP + 130, // TRACK_ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_DOWN + 130, // TRACK_ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_DOWN + 96, // TRACK_ELEM_S_BEND_LEFT + 96, // TRACK_ELEM_S_BEND_RIGHT + 120, // TRACK_ELEM_LEFT_VERTICAL_LOOP + 120, // TRACK_ELEM_RIGHT_VERTICAL_LOOP + 75, // TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES + 75, // TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES + 75, // TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES_BANK + 75, // TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_BANK + 77, // TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP + 77, // TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP + 77, // TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN + 77, // TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN + 24, // TRACK_ELEM_LEFT_QUARTER_TURN_1_TILE + 24, // TRACK_ELEM_RIGHT_QUARTER_TURN_1_TILE + 96, // TRACK_ELEM_LEFT_TWIST_DOWN_TO_UP + 96, // TRACK_ELEM_RIGHT_TWIST_DOWN_TO_UP + 96, // TRACK_ELEM_LEFT_TWIST_UP_TO_DOWN + 96, // TRACK_ELEM_RIGHT_TWIST_UP_TO_DOWN + 60, // TRACK_ELEM_HALF_LOOP_UP + 60, // TRACK_ELEM_HALF_LOOP_DOWN + 55, // TRACK_ELEM_LEFT_CORKSCREW_UP + 55, // TRACK_ELEM_RIGHT_CORKSCREW_UP + 55, // TRACK_ELEM_LEFT_CORKSCREW_DOWN + 55, // TRACK_ELEM_RIGHT_CORKSCREW_DOWN + 36, // TRACK_ELEM_FLAT_TO_60_DEG_UP + 36, // TRACK_ELEM_60_DEG_UP_TO_FLAT + 36, // TRACK_ELEM_FLAT_TO_60_DEG_DOWN + 36, // TRACK_ELEM_60_DEG_DOWN_TO_FLAT + 32, // TRACK_ELEM_TOWER_BASE + 32, // TRACK_ELEM_TOWER_SECTION + 32, // TRACK_ELEM_FLAT_COVERED + 33, // TRACK_ELEM_25_DEG_UP_COVERED + 40, // TRACK_ELEM_60_DEG_UP_COVERED + 32, // TRACK_ELEM_FLAT_TO_25_DEG_UP_COVERED + 34, // TRACK_ELEM_25_DEG_UP_TO_60_DEG_UP_COVERED + 34, // TRACK_ELEM_60_DEG_UP_TO_25_DEG_UP_COVERED + 32, // TRACK_ELEM_25_DEG_UP_TO_FLAT_COVERED + 33, // TRACK_ELEM_25_DEG_DOWN_COVERED + 40, // TRACK_ELEM_60_DEG_DOWN_COVERED + 32, // TRACK_ELEM_FLAT_TO_25_DEG_DOWN_COVERED + 34, // TRACK_ELEM_25_DEG_DOWN_TO_60_DEG_DOWN_COVERED + 34, // TRACK_ELEM_60_DEG_DOWN_TO_25_DEG_DOWN_COVERED + 32, // TRACK_ELEM_25_DEG_DOWN_TO_FLAT_COVERED + 124, // TRACK_ELEM_LEFT_QUARTER_TURN_5_TILES_COVERED + 124, // TRACK_ELEM_RIGHT_QUARTER_TURN_5_TILES_COVERED + 96, // TRACK_ELEM_S_BEND_LEFT_COVERED + 96, // TRACK_ELEM_S_BEND_RIGHT_COVERED + 75, // TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES_COVERED + 75, // TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_COVERED + 150, // TRACK_ELEM_LEFT_HALF_BANKED_HELIX_UP_SMALL + 150, // TRACK_ELEM_RIGHT_HALF_BANKED_HELIX_UP_SMALL + 150, // TRACK_ELEM_LEFT_HALF_BANKED_HELIX_DOWN_SMALL + 150, // TRACK_ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_SMALL + 248, // TRACK_ELEM_LEFT_HALF_BANKED_HELIX_UP_LARGE + 248, // TRACK_ELEM_RIGHT_HALF_BANKED_HELIX_UP_LARGE + 248, // TRACK_ELEM_LEFT_HALF_BANKED_HELIX_DOWN_LARGE + 248, // TRACK_ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_LARGE + 64, // TRACK_ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_UP + 64, // TRACK_ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_UP + 64, // TRACK_ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_DOWN + 64, // TRACK_ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_DOWN + 32, // TRACK_ELEM_BRAKES + 32, // TRACK_ELEM_ROTATION_CONTROL_TOGGLE + 32, // TRACK_ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP + 124, // TRACK_ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_UP + 124, // TRACK_ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_UP + 124, // TRACK_ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_DOWN + 124, // TRACK_ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_DOWN + 124, // TRACK_ELEM_LEFT_QUARTER_HELIX_LARGE_UP + 124, // TRACK_ELEM_RIGHT_QUARTER_HELIX_LARGE_UP + 124, // TRACK_ELEM_LEFT_QUARTER_HELIX_LARGE_DOWN + 124, // TRACK_ELEM_RIGHT_QUARTER_HELIX_LARGE_DOWN + 33, // TRACK_ELEM_25_DEG_UP_LEFT_BANKED + 33, // TRACK_ELEM_25_DEG_UP_RIGHT_BANKED + 32, // TRACK_ELEM_WATERFALL + 32, // TRACK_ELEM_RAPIDS + 32, // TRACK_ELEM_ON_RIDE_PHOTO + 33, // TRACK_ELEM_25_DEG_DOWN_LEFT_BANKED + 33, // TRACK_ELEM_25_DEG_DOWN_RIGHT_BANKED + 128, // TRACK_ELEM_WATER_SPLASH + 165, // TRACK_ELEM_FLAT_TO_60_DEG_UP_LONG_BASE + 165, // TRACK_ELEM_60_DEG_UP_TO_FLAT_LONG_BASE + 32, // TRACK_ELEM_WHIRLPOOL + 165, // TRACK_ELEM_FLAT_TO_60_DEG_DOWN_LONG_BASE + 165, // TRACK_ELEM_60_DEG_UP_TO_FLAT_LONG_BASE_122 + 138, // TRACK_ELEM_CABLE_LIFT_HILL + 32, // TRACK_ELEM_REVERSE_WHOA_BELLY_SLOPE + 32, // TRACK_ELEM_REVERSE_WHOA_BELLY_VERTICAL + 32, // TRACK_ELEM_90_DEG_UP + 32, // TRACK_ELEM_90_DEG_DOWN + 32, // TRACK_ELEM_60_DEG_UP_TO_90_DEG_UP + 32, // TRACK_ELEM_90_DEG_DOWN_TO_60_DEG_DOWN + 32, // TRACK_ELEM_90_DEG_UP_TO_60_DEG_UP + 32, // TRACK_ELEM_60_DEG_DOWN_TO_90_DEG_DOWN + 32, // TRACK_ELEM_BRAKE_FOR_DROP + 87, // TRACK_ELEM_LEFT_EIGHTH_TO_DIAG + 87, // TRACK_ELEM_RIGHT_EIGHTH_TO_DIAG + 87, // TRACK_ELEM_LEFT_EIGHTH_TO_ORTHOGONAL + 87, // TRACK_ELEM_RIGHT_EIGHTH_TO_ORTHOGONAL + 87, // TRACK_ELEM_LEFT_EIGHTH_BANK_TO_DIAG + 87, // TRACK_ELEM_RIGHT_EIGHTH_BANK_TO_DIAG + 87, // TRACK_ELEM_LEFT_EIGHTH_BANK_TO_ORTHOGONAL + 87, // TRACK_ELEM_RIGHT_EIGHTH_BANK_TO_ORTHOGONAL + 45, // TRACK_ELEM_DIAG_FLAT + 45, // TRACK_ELEM_DIAG_25_DEG_UP + 45, // TRACK_ELEM_DIAG_60_DEG_UP + 45, // TRACK_ELEM_DIAG_FLAT_TO_25_DEG_UP + 45, // TRACK_ELEM_DIAG_25_DEG_UP_TO_60_DEG_UP + 45, // TRACK_ELEM_DIAG_60_DEG_UP_TO_25_DEG_UP + 45, // TRACK_ELEM_DIAG_25_DEG_UP_TO_FLAT + 45, // TRACK_ELEM_DIAG_25_DEG_DOWN + 45, // TRACK_ELEM_DIAG_60_DEG_DOWN + 45, // TRACK_ELEM_DIAG_FLAT_TO_25_DEG_DOWN + 45, // TRACK_ELEM_DIAG_25_DEG_DOWN_TO_60_DEG_DOWN + 45, // TRACK_ELEM_DIAG_60_DEG_DOWN_TO_25_DEG_DOWN + 45, // TRACK_ELEM_DIAG_25_DEG_DOWN_TO_FLAT + 45, // TRACK_ELEM_DIAG_FLAT_TO_60_DEG_UP + 45, // TRACK_ELEM_DIAG_60_DEG_UP_TO_FLAT + 45, // TRACK_ELEM_DIAG_FLAT_TO_60_DEG_DOWN + 45, // TRACK_ELEM_DIAG_60_DEG_DOWN_TO_FLAT + 45, // TRACK_ELEM_DIAG_FLAT_TO_LEFT_BANK + 45, // TRACK_ELEM_DIAG_FLAT_TO_RIGHT_BANK + 45, // TRACK_ELEM_DIAG_LEFT_BANK_TO_FLAT + 45, // TRACK_ELEM_DIAG_RIGHT_BANK_TO_FLAT + 45, // TRACK_ELEM_DIAG_LEFT_BANK_TO_25_DEG_UP + 45, // TRACK_ELEM_DIAG_RIGHT_BANK_TO_25_DEG_UP + 45, // TRACK_ELEM_DIAG_25_DEG_UP_TO_LEFT_BANK + 45, // TRACK_ELEM_DIAG_25_DEG_UP_TO_RIGHT_BANK + 45, // TRACK_ELEM_DIAG_LEFT_BANK_TO_25_DEG_DOWN + 45, // TRACK_ELEM_DIAG_RIGHT_BANK_TO_25_DEG_DOWN + 45, // TRACK_ELEM_DIAG_25_DEG_DOWN_TO_LEFT_BANK + 45, // TRACK_ELEM_DIAG_25_DEG_DOWN_TO_RIGHT_BANK + 45, // TRACK_ELEM_DIAG_LEFT_BANK + 45, // TRACK_ELEM_DIAG_RIGHT_BANK + 16, // TRACK_ELEM_LOG_FLUME_REVERSER + 32, // TRACK_ELEM_SPINNING_TUNNEL + 96, // TRACK_ELEM_LEFT_BARREL_ROLL_UP_TO_DOWN + 96, // TRACK_ELEM_RIGHT_BARREL_ROLL_UP_TO_DOWN + 96, // TRACK_ELEM_LEFT_BARREL_ROLL_DOWN_TO_UP + 96, // TRACK_ELEM_RIGHT_BARREL_ROLL_DOWN_TO_UP + 64, // TRACK_ELEM_LEFT_BANK_TO_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP + 64, // TRACK_ELEM_RIGHT_BANK_TO_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP + 64, // TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_LEFT_BANK + 64, // TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_RIGHT_BANK + 32, // TRACK_ELEM_POWERED_LIFT + 100, // TRACK_ELEM_LEFT_LARGE_HALF_LOOP_UP + 100, // TRACK_ELEM_RIGHT_LARGE_HALF_LOOP_UP + 100, // TRACK_ELEM_RIGHT_LARGE_HALF_LOOP_DOWN + 100, // TRACK_ELEM_LEFT_LARGE_HALF_LOOP_DOWN + 96, // + 96, // + 96, // + 96, // + 64, // + 64, // + 64, // + 64, // + 64, // + 64, // + 16, // + 16, // + 64, // + 64, // + 32, // + 32, // + 32, // + 32, // + 32, // + 80, // + 80, // + 80, // + 64, // + 64, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 32, // + 80, // + 80, // + 80, // +}; + +// rct2: 0x00998C95 +const track_curve_chain gTrackCurveChain[256] = { + { 0, 0 }, + { 257, 257 }, + { 257, 257 }, + { 257, 257 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 1, 1 }, + { 2, 2 }, + { 1, 0 }, + { 2, 0 }, + { 0, 1 }, + { 0, 2 }, + { 1, 1 }, + { 2, 2 }, + { 0, 1 }, + { 0, 2 }, + { 1, 0 }, + { 2, 0 }, + { 0, 1 }, + { 0, 2 }, + { 1, 0 }, + { 2, 0 }, + { 1, 1 }, + { 2, 2 }, + { 1, 1 }, + { 2, 2 }, + { 1, 1 }, + { 2, 2 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 3, 3 }, + { 4, 4 }, + { 3, 3 }, + { 4, 4 }, + { 3, 3 }, + { 4, 4 }, + { 3, 3 }, + { 4, 4 }, + { 5, 5 }, + { 6, 6 }, + { 310, 0 }, + { 311, 0 }, + { 0, 308 }, + { 0, 309 }, + { 313, 0 }, + { 0, 312 }, + { 317, 0 }, + { 316, 0 }, + { 0, 315 }, + { 0, 314 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 323, 0 }, + { 323, 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 }, + { 1, 1 }, + { 2, 2 }, + { 0, 0 }, + { 0, 0 }, + { 3, 3 }, + { 4, 4 }, + { 343, 343 }, + { 344, 344 }, + { 345, 345 }, + { 346, 346 }, + { 347, 347 }, + { 348, 348 }, + { 349, 349 }, + { 350, 350 }, + { 3, 3 }, + { 4, 4 }, + { 3, 3 }, + { 4, 4 }, + { 355, 355 }, + { 0, 0 }, + { 0, 0 }, + { 358, 358 }, + { 359, 359 }, + { 360, 360 }, + { 361, 361 }, + { 362, 362 }, + { 363, 363 }, + { 364, 364 }, + { 365, 365 }, + { 1, 1 }, + { 2, 2 }, + { 368, 368 }, + { 369, 369 }, + { 0, 0 }, + { 1, 1 }, + { 2, 2 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 381, 0 }, + { 381, 381 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 7, 7 }, + { 8, 8 }, + { 7, 7 }, + { 8, 8 }, + { 7, 7 }, + { 8, 8 }, + { 7, 7 }, + { 8, 8 }, + { 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, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 7, 0 }, + { 8, 0 }, + { 0, 7 }, + { 0, 8 }, + { 0, 7 }, + { 0, 8 }, + { 7, 0 }, + { 8, 0 }, + { 0, 7 }, + { 0, 8 }, + { 7, 0 }, + { 8, 0 }, + { 7, 7 }, + { 8, 8 }, + { 0, 0 }, + { 0, 0 }, + { 432, 0 }, + { 433, 0 }, + { 0, 430 }, + { 0, 431 }, + { 3, 3 }, + { 4, 4 }, + { 3, 3 }, + { 4, 4 }, + { 438, 438 }, + { 442, 0 }, + { 441, 0 }, + { 0, 440 }, + { 0, 439 }, + { 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, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 464, 0 }, + { 0, 463 }, + { 465, 465 }, + { 466, 466 }, + { 0, 0 }, + { 0, 0 }, + { 470, 381 }, + { 470, 470 }, + { 0, 470 }, + { 0, 0 }, + { 3, 3 }, + { 4, 4 }, + { 3, 3 }, + { 4, 4 }, + { 1, 1 }, + { 2, 2 }, + { 1, 1 }, + { 2, 2 }, + { 1, 0 }, + { 2, 0 }, + { 0, 1 }, + { 0, 2 }, + { 1, 0 }, + { 2, 0 }, + { 0, 1 }, + { 0, 2 }, + { 1, 1 }, + { 2, 2 }, + { 1, 1 }, + { 2, 2 }, + { 1, 1 }, + { 2, 2 }, + { 1, 1 }, + { 2, 2 }, + { 1, 0 }, + { 2, 0 }, + { 0, 1 }, + { 0, 2 }, + { 1, 0 }, + { 2, 0 }, + { 0, 1 }, + { 0, 2 }, + { 3, 3 }, + { 4, 4 }, + { 3, 3 }, + { 4, 4 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, +}; + +// rct2: 0x00999095 +const track_curve_chain gFlatRideTrackCurveChain[256] = { + { 0, 0 }, + { 257, 257 }, + { 257, 257 }, + { 257, 257 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 1, 1 }, + { 2, 2 }, + { 1, 0 }, + { 2, 0 }, + { 0, 1 }, + { 0, 2 }, + { 1, 1 }, + { 2, 2 }, + { 0, 1 }, + { 0, 2 }, + { 1, 0 }, + { 2, 0 }, + { 0, 1 }, + { 0, 2 }, + { 1, 0 }, + { 2, 0 }, + { 1, 1 }, + { 2, 2 }, + { 1, 1 }, + { 2, 2 }, + { 1, 1 }, + { 2, 2 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 3, 3 }, + { 4, 4 }, + { 3, 3 }, + { 4, 4 }, + { 3, 3 }, + { 4, 4 }, + { 3, 3 }, + { 4, 4 }, + { 5, 5 }, + { 6, 6 }, + { 310, 0 }, + { 311, 0 }, + { 0, 308 }, + { 0, 309 }, + { 313, 0 }, + { 0, 312 }, + { 317, 0 }, + { 316, 0 }, + { 0, 315 }, + { 0, 314 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 323, 0 }, + { 323, 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 }, + { 1, 1 }, + { 2, 2 }, + { 0, 0 }, + { 0, 0 }, + { 3, 3 }, + { 4, 4 }, + { 343, 343 }, + { 344, 344 }, + { 345, 345 }, + { 346, 346 }, + { 347, 347 }, + { 348, 348 }, + { 349, 349 }, + { 350, 350 }, + { 65535, 65535 }, + { 4, 4 }, + { 3, 3 }, + { 4, 4 }, + { 355, 355 }, + { 0, 0 }, + { 0, 0 }, + { 358, 358 }, + { 359, 359 }, + { 360, 360 }, + { 361, 361 }, + { 362, 362 }, + { 363, 363 }, + { 364, 364 }, + { 365, 365 }, + { 65535, 65535 }, + { 65535, 65535 }, + { 368, 368 }, + { 369, 369 }, + { 0, 0 }, + { 65535, 65535 }, + { 65535, 65535 }, + { 0, 0 }, + { 65535, 65535 }, + { 65535, 65535 }, + { 0, 0 }, + { 65535, 65535 }, + { 65535, 65535 }, + { 65535, 65535 }, + { 381, 0 }, + { 381, 381 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 7, 7 }, + { 8, 8 }, + { 7, 7 }, + { 8, 8 }, + { 7, 7 }, + { 8, 8 }, + { 7, 7 }, + { 8, 8 }, + { 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, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 7, 0 }, + { 8, 0 }, + { 0, 7 }, + { 0, 8 }, + { 0, 7 }, + { 0, 8 }, + { 7, 0 }, + { 8, 0 }, + { 0, 7 }, + { 0, 8 }, + { 7, 0 }, + { 8, 0 }, + { 7, 7 }, + { 8, 8 }, + { 0, 0 }, + { 0, 0 }, + { 432, 0 }, + { 433, 0 }, + { 0, 430 }, + { 0, 431 }, + { 3, 3 }, + { 4, 4 }, + { 3, 3 }, + { 4, 4 }, + { 438, 190 }, + { 442, 0 }, + { 441, 0 }, + { 0, 440 }, + { 0, 439 }, + { 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, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 465, 465 }, + { 466, 466 }, + { 0, 0 }, + { 0, 0 }, + { 470, 381 }, + { 470, 470 }, + { 0, 470 }, + { 0, 0 }, + { 3, 3 }, + { 4, 4 }, + { 3, 3 }, + { 4, 4 }, + { 1, 1 }, + { 2, 2 }, + { 1, 1 }, + { 2, 2 }, + { 1, 0 }, + { 2, 0 }, + { 0, 1 }, + { 0, 1 }, + { 1, 0 }, + { 2, 0 }, + { 0, 1 }, + { 0, 2 }, + { 1, 1 }, + { 2, 2 }, + { 1, 1 }, + { 2, 2 }, + { 1, 1 }, + { 2, 2 }, + { 1, 1 }, + { 2, 2 }, + { 1, 0 }, + { 2, 0 }, + { 0, 1 }, + { 0, 2 }, + { 1, 0 }, + { 2, 0 }, + { 0, 1 }, + { 0, 2 }, + { 3, 3 }, + { 4, 4 }, + { 3, 3 }, + { 4, 4 }, + { 0, 0 }, + { 0, 0 }, + { 0, 57088 }, +}; + +const uint32 RideTypeTrackPaintFunctionsOld[91] = { + 0x008A42F4, // RIDE_TYPE_SPIRAL_ROLLER_COASTER + 0x008A6DB0, // RIDE_TYPE_STAND_UP_ROLLER_COASTER + 0x008A85E4, // RIDE_TYPE_SUSPENDED_SWINGING_COASTER + 0x008A8EE4, // RIDE_TYPE_INVERTED_ROLLER_COASTER + 0x008AAA0C, // RIDE_TYPE_JUNIOR_ROLLER_COASTER + 0x008ACE48, // RIDE_TYPE_MINIATURE_RAILWAY + 0x008ADF34, // RIDE_TYPE_MONORAIL + 0x008AFC24, // RIDE_TYPE_MINI_SUSPENDED_COASTER + 0x008B0D60, // RIDE_TYPE_BOAT_RIDE + 0x008A534C, // RIDE_TYPE_WOODEN_WILD_MOUSE + 0x008A5634, // RIDE_TYPE_STEEPLECHASE + 0x006F7000, // RIDE_TYPE_CAR_RIDE + 0x006FD0E8, // RIDE_TYPE_LAUNCHED_FREEFALL + 0x006FE240, // RIDE_TYPE_BOBSLEIGH_COASTER + 0x0070DC5C, // RIDE_TYPE_OBSERVATION_TOWER + 0x008A5B88, // RIDE_TYPE_LOOPING_ROLLER_COASTER + 0x0070EDB4, // RIDE_TYPE_DINGHY_SLIDE + 0x0071BC40, // RIDE_TYPE_MINE_TRAIN_COASTER + 0x00743EC8, // RIDE_TYPE_CHAIRLIFT + 0x008A7784, // RIDE_TYPE_CORKSCREW_ROLLER_COASTER + 0x008A81E8, // RIDE_TYPE_MAZE + 0x0074840C, // RIDE_TYPE_SPIRAL_SLIDE + 0x0074A668, // RIDE_TYPE_GO_KARTS + 0x0074DDEC, // RIDE_TYPE_LOG_FLUME + 0x0075745C, // RIDE_TYPE_RIVER_RAPIDS + 0x0075C9D0, // RIDE_TYPE_DODGEMS + 0x008A83E0, // RIDE_TYPE_PIRATE_SHIP + 0x00760070, // RIDE_TYPE_SWINGING_INVERTER_SHIP + 0, // RIDE_TYPE_FOOD_STALL + 0, // RIDE_TYPE_1D + 0, // RIDE_TYPE_DRINK_STALL + 0, // RIDE_TYPE_1F + 0, // RIDE_TYPE_SHOP + 0x0076190C, // RIDE_TYPE_MERRY_GO_ROUND + 0, // RIDE_TYPE_22 + 0, // RIDE_TYPE_INFORMATION_KIOSK + 0x00762D44, // RIDE_TYPE_TOILETS + 0x008A8CC8, // RIDE_TYPE_FERRIS_WHEEL + 0x00763520, // RIDE_TYPE_MOTION_SIMULATOR + 0x0076554C, // RIDE_TYPE_3D_CINEMA + 0, // RIDE_TYPE_TOP_SPIN + 0x00767A40, // RIDE_TYPE_SPACE_RINGS + 0x00768BAC, // RIDE_TYPE_REVERSE_FREEFALL_COASTER + 0x0076C5BC, // RIDE_TYPE_LIFT + 0x008A9C08, // RIDE_TYPE_VERTICAL_DROP_ROLLER_COASTER + 0, // RIDE_TYPE_CASH_MACHINE + 0x0076D658, // RIDE_TYPE_TWIST + 0x0076E7B0, // RIDE_TYPE_HAUNTED_HOUSE + 0x00762D44, // RIDE_TYPE_FIRST_AID + 0x0076F8D4, // RIDE_TYPE_CIRCUS_SHOW + 0x00770924, // RIDE_TYPE_GHOST_TRAIN + 0x008AB2A0, // RIDE_TYPE_TWISTER_ROLLER_COASTER + 0x008AC164, // RIDE_TYPE_WOODEN_ROLLER_COASTER + 0x00778124, // RIDE_TYPE_SIDE_FRICTION_ROLLER_COASTER + 0x0078AE80, // RIDE_TYPE_WILD_MOUSE + 0x00792978, // RIDE_TYPE_MULTI_DIMENSION_ROLLER_COASTER + 0x00792978, // RIDE_TYPE_38 + 0x007C6C00, // RIDE_TYPE_FLYING_ROLLER_COASTER + 0x007C6C00, // RIDE_TYPE_3A + 0x00811184, // RIDE_TYPE_VIRGINIA_REEL + 0x008164AC, // RIDE_TYPE_SPLASH_BOATS + 0x0081F268, // RIDE_TYPE_MINI_HELICOPTERS + 0x008245A8, // RIDE_TYPE_LAY_DOWN_ROLLER_COASTER + 0x0086347C, // RIDE_TYPE_SUSPENDED_MONORAIL + 0x008245A8, // RIDE_TYPE_40 + 0x0086E2F8, // RIDE_TYPE_REVERSER_ROLLER_COASTER + 0x00876618, // RIDE_TYPE_HEARTLINE_TWISTER_COASTER + 0x0087EDC4, // RIDE_TYPE_MINI_GOLF + 0x008AD280, // RIDE_TYPE_GIGA_COASTER + 0x00886074, // RIDE_TYPE_ROTO_DROP + 0x00887208, // RIDE_TYPE_FLYING_SAUCERS + 0x00889C28, // RIDE_TYPE_CROOKED_HOUSE + 0x0088AC88, // RIDE_TYPE_MONORAIL_CYCLES + 0x008AE36C, // RIDE_TYPE_COMPACT_INVERTED_COASTER + 0x008AEDE0, // RIDE_TYPE_WATER_COASTER + 0x008AF764, // RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER + 0x00890940, // RIDE_TYPE_INVERTED_HAIRPIN_COASTER + 0x00898384, // RIDE_TYPE_MAGIC_CARPET + 0x008995D4, // RIDE_TYPE_SUBMARINE_RIDE + 0x0089B0C0, // RIDE_TYPE_RIVER_RAFTS + 0x00761160, // RIDE_TYPE_50 + 0x008A13B4, // RIDE_TYPE_ENTERPRISE + 0x00761160, // RIDE_TYPE_52 + 0x00761160, // RIDE_TYPE_53 + 0x00761160, // RIDE_TYPE_54 + 0x00000000, // RIDE_TYPE_55 + 0x008B005C, // RIDE_TYPE_INVERTED_IMPULSE_COASTER + 0x008A46D8, // RIDE_TYPE_MINI_ROLLER_COASTER + 0x008B0610, // RIDE_TYPE_MINE_RIDE + 0x00000000, // RIDE_TYPE_59 + 0x008A5F6C, // RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER +}; + + +const uint32 RideTypeTrackPaintFunctions[91] = { + 0, // RIDE_TYPE_SPIRAL_ROLLER_COASTER + 0, // RIDE_TYPE_STAND_UP_ROLLER_COASTER + 0, // RIDE_TYPE_SUSPENDED_SWINGING_COASTER + 0, // RIDE_TYPE_INVERTED_ROLLER_COASTER + 0, // RIDE_TYPE_JUNIOR_ROLLER_COASTER + 0, // RIDE_TYPE_MINIATURE_RAILWAY + 0, // RIDE_TYPE_MONORAIL + 0, // RIDE_TYPE_MINI_SUSPENDED_COASTER + 0, // RIDE_TYPE_BOAT_RIDE + 0, // RIDE_TYPE_WOODEN_WILD_MOUSE + 0, // RIDE_TYPE_STEEPLECHASE + 0, // RIDE_TYPE_CAR_RIDE + 0, // RIDE_TYPE_LAUNCHED_FREEFALL + 0, // RIDE_TYPE_BOBSLEIGH_COASTER + 0, // RIDE_TYPE_OBSERVATION_TOWER + 0, // RIDE_TYPE_LOOPING_ROLLER_COASTER + 0, // RIDE_TYPE_DINGHY_SLIDE + 0, // RIDE_TYPE_MINE_TRAIN_COASTER + 0, // RIDE_TYPE_CHAIRLIFT + 0, // RIDE_TYPE_CORKSCREW_ROLLER_COASTER + 0, // RIDE_TYPE_MAZE + 0, // RIDE_TYPE_SPIRAL_SLIDE + 0, // RIDE_TYPE_GO_KARTS + 0, // RIDE_TYPE_LOG_FLUME + 0, // RIDE_TYPE_RIVER_RAPIDS + 0, // RIDE_TYPE_DODGEMS + 0, // RIDE_TYPE_PIRATE_SHIP + 0, // RIDE_TYPE_SWINGING_INVERTER_SHIP + (uint32)shop_track_paint_functions, // RIDE_TYPE_FOOD_STALL + (uint32)shop_track_paint_functions, // RIDE_TYPE_1D + (uint32)shop_track_paint_functions, // RIDE_TYPE_DRINK_STALL + (uint32)shop_track_paint_functions, // RIDE_TYPE_1F + (uint32)shop_track_paint_functions, // RIDE_TYPE_SHOP + 0, // RIDE_TYPE_MERRY_GO_ROUND + (uint32)shop_track_paint_functions, // RIDE_TYPE_22 + (uint32)shop_track_paint_functions, // RIDE_TYPE_INFORMATION_KIOSK + (uint32)shop_track_paint_functions, // RIDE_TYPE_TOILETS + 0, // RIDE_TYPE_FERRIS_WHEEL + 0, // RIDE_TYPE_MOTION_SIMULATOR + 0, // RIDE_TYPE_3D_CINEMA + (uint32)top_spin_track_paint_functions, // RIDE_TYPE_TOP_SPIN + 0, // RIDE_TYPE_SPACE_RINGS + 0, // RIDE_TYPE_REVERSE_FREEFALL_COASTER + 0, // RIDE_TYPE_LIFT + 0, // RIDE_TYPE_VERTICAL_DROP_ROLLER_COASTER + (uint32)shop_track_paint_functions, // RIDE_TYPE_CASH_MACHINE + 0, // RIDE_TYPE_TWIST + 0, // RIDE_TYPE_HAUNTED_HOUSE + 0, // RIDE_TYPE_FIRST_AID + 0, // RIDE_TYPE_CIRCUS_SHOW + 0, // RIDE_TYPE_GHOST_TRAIN + 0, // RIDE_TYPE_TWISTER_ROLLER_COASTER + 0, // RIDE_TYPE_WOODEN_ROLLER_COASTER + 0, // RIDE_TYPE_SIDE_FRICTION_ROLLER_COASTER + 0, // RIDE_TYPE_WILD_MOUSE + 0, // RIDE_TYPE_MULTI_DIMENSION_ROLLER_COASTER + 0, // RIDE_TYPE_38 + 0, // RIDE_TYPE_FLYING_ROLLER_COASTER + 0, // RIDE_TYPE_3A + 0, // RIDE_TYPE_VIRGINIA_REEL + 0, // RIDE_TYPE_SPLASH_BOATS + 0, // RIDE_TYPE_MINI_HELICOPTERS + 0, // RIDE_TYPE_LAY_DOWN_ROLLER_COASTER + 0, // RIDE_TYPE_SUSPENDED_MONORAIL + 0, // RIDE_TYPE_40 + 0, // RIDE_TYPE_REVERSER_ROLLER_COASTER + 0, // RIDE_TYPE_HEARTLINE_TWISTER_COASTER + 0, // RIDE_TYPE_MINI_GOLF + 0, // RIDE_TYPE_GIGA_COASTER + 0, // RIDE_TYPE_ROTO_DROP + 0, // RIDE_TYPE_FLYING_SAUCERS + 0, // RIDE_TYPE_CROOKED_HOUSE + 0, // RIDE_TYPE_MONORAIL_CYCLES + 0, // RIDE_TYPE_COMPACT_INVERTED_COASTER + 0, // RIDE_TYPE_WATER_COASTER + 0, // RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER + 0, // RIDE_TYPE_INVERTED_HAIRPIN_COASTER + 0, // RIDE_TYPE_MAGIC_CARPET + 0, // RIDE_TYPE_SUBMARINE_RIDE + 0, // RIDE_TYPE_RIVER_RAFTS + 0, // RIDE_TYPE_50 + 0, // RIDE_TYPE_ENTERPRISE + 0, // RIDE_TYPE_52 + 0, // RIDE_TYPE_53 + 0, // RIDE_TYPE_54 + 0, // RIDE_TYPE_55 + 0, // RIDE_TYPE_INVERTED_IMPULSE_COASTER + 0, // RIDE_TYPE_MINI_ROLLER_COASTER + 0, // RIDE_TYPE_MINE_RIDE + 0, // RIDE_TYPE_59 + 0, // RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER +}; diff --git a/src/ride/track_data.h b/src/ride/track_data.h index c10ad9bd3d..366e642589 100644 --- a/src/ride/track_data.h +++ b/src/ride/track_data.h @@ -17,17 +17,28 @@ * 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; +#include "../common.h" +#include "track.h" // 0x009968BB, 0x009968BC, 0x009968BD, 0x009968BF, 0x009968C1, 0x009968C3 -extern const rct_track_coordinates TrackCoordinates[256]; \ No newline at end of file +extern const rct_track_coordinates TrackCoordinates[256]; +// 0x009972BB, 0x009972BC, 0x009972BD, 0x009972BF, 0x009972C1, 0x009972C3 +extern const rct_track_coordinates* FlatTrackCoordinates; + +extern const uint64 RideTypePossibleTrackConfigurations[91]; +extern const rct_preview_track *TrackBlocks[256]; +extern const rct_preview_track *FlatRideTrackBlocks[255]; + +extern const uint8 TrackPieceLengths[256]; + +typedef struct { + uint16 next; + uint16 previous; +} track_curve_chain; + +extern const track_curve_chain gTrackCurveChain[256]; +extern const track_curve_chain gFlatRideTrackCurveChain[256]; + +extern const uint32 RideTypeTrackPaintFunctions[91]; +extern const uint32 RideTypeTrackPaintFunctionsOld[91]; diff --git a/src/ride/track_paint.c b/src/ride/track_paint.c new file mode 100644 index 0000000000..44d14d0a8d --- /dev/null +++ b/src/ride/track_paint.c @@ -0,0 +1,1264 @@ +/***************************************************************************** +* 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 "../drawing/drawing.h" +#include "../localisation/localisation.h" +#include "ride_data.h" +#include "track_data.h" +#include "../sprites.h" +#include "../world/map.h" +#include "../world/sprite.h" +#include "../interface/viewport.h" +#include "../interface/window.h" +#include "track_paint.h" + +void top_spin_paint_setup_rot_0(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement); +void top_spin_paint_setup_rot_1(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement); +void top_spin_paint_setup_rot_2(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement); +void top_spin_paint_setup_rot_3(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement); + +/* 0x0076679C */ +TRACK_PAINT_FUNCTION top_spin_base_functions[] = { + top_spin_paint_setup_rot_0, + top_spin_paint_setup_rot_1, + top_spin_paint_setup_rot_2, + top_spin_paint_setup_rot_3, +}; + +TRACK_PAINT_FUNCTION* top_spin_track_paint_functions[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + top_spin_base_functions // 123 +}; + +/* rct2: 0x0076687C */ +void top_spin_paint_tile_0(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement) { + uint32 image_id = RCT2_GLOBAL(0x00F441A0, uint32); + sub_6629BC(height, 0, image_id, direction & 1); + + image_id = 22137 | RCT2_GLOBAL(0x00F44198, uint32); + + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 0; + RCT2_GLOBAL(0x009DEA56, uint16) = height; + sub_98197C(0, 1, image_id, 0, height, 32, 32, get_current_rotation()); + + RCT2_GLOBAL(0x141E9B4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9B8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9BC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9CC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D4, uint16) = 0xFFFF; + + height += 112; + if (RCT2_GLOBAL(0x141E9D8, sint16) < height) { + RCT2_GLOBAL(0x141E9D8, sint16) = height; + RCT2_GLOBAL(0x141E9DA, uint8) = 32; + } +} + +/* rct2:0x007667AE */ +rct_xy16 loc_7667AE[] = { + { .x = 0, .y = -1 }, + { .x = 1, .y = 0 }, + { .x = 0, .y = 1}, + { .x = -1, .y = 0 }, +}; + +/* rct2:0x007667AC */ +rct_xy16 loc_7667AC[] = { + { .x = -1, .y = 0 }, + { .x = 0, .y = -1 }, + { .x = 1, .y = 0 }, + { .x = 0, .y = 1 }, +}; + +/* rct2: 0x0142811C + * Can be calculated as Rounddown(34*sin(x)+0.5) + * where x is in 7.5 deg segments. + */ +static sint8 TopSpinSeatPositionOffset[] = { + 0, 4, 9, 13, 17, 21, 24, 27, 29, 31, 33, 34, 34, 34, 33, 31, + 29, 27, 24, 21, 17, 13, 9, 4, 0, -3, -8, -12, -16, -20, -23, -26, + -28, -30, -32, -33, -33, -33, -32, -30, -28, -26, -23, -20, -16, -12, -8, -3, + 0 +}; + +/* rct2: 0x0076750D */ +void top_spin_paint_vehicle(sint8 al, sint8 cl, uint8 rideIndex, uint8 direction, int height, rct_map_element* mapElement) { + // As we will be drawing a vehicle we need to backup the mapElement that + // is assigned to the drawings. + rct_map_element* curMapElement = RCT2_GLOBAL(0x009DE578, rct_map_element*); + + height += 3; + + rct_ride* ride = GET_RIDE(rideIndex); + rct_ride_type* rideEntry = GET_RIDE_ENTRY(ride->subtype); + rct_vehicle* vehicle = NULL; + + uint8 seatRotation = 0; + sint8 armRotation = 0; + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK && + ride->vehicles[0] != SPRITE_INDEX_NULL) { + vehicle = GET_VEHICLE(ride->vehicles[0]); + + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8) = VIEWPORT_INTERACTION_ITEM_SPRITE; + RCT2_GLOBAL(0x009DE578, rct_vehicle*) = vehicle; + + armRotation = vehicle->var_1F; + seatRotation = vehicle->var_20; + } + + RCT2_GLOBAL(0x009DEA52, sint16) = al + 16; + RCT2_GLOBAL(0x009DEA54, sint16) = cl + 16; + RCT2_GLOBAL(0x009DEA56, sint16) = height; + + //di + uint8 lengthX = 24; + //si + uint8 lengthY = 24; + + uint32 image_id = RCT2_GLOBAL(0x00F441A0, uint32); + if (image_id == 0x20000000) { + image_id = + 0xA0000000 | + (ride->track_colour_main[0] << 19) | + (ride->track_colour_supports[0] << 24); + } + + image_id += (direction & 1) << 1; + image_id += rideEntry->vehicles[0].base_image_id; + // Left back bottom support + image_id += 572; + + sub_98197C(al, 90, image_id, cl, height, lengthY, lengthX, get_current_rotation()); + + image_id = RCT2_GLOBAL(0x00F441A0, uint32); + if (image_id == 0x20000000) { + image_id = + 0xA0000000 | + (ride->track_colour_main[0] << 19) | + (ride->track_colour_additional[0] << 24); + } + + sint32 var_1F = armRotation; + if (direction & 2) { + var_1F = -var_1F; + if (var_1F != 0) + var_1F += 48; + } + image_id += var_1F; + image_id += (direction & 1) * 48; + image_id += rideEntry->vehicles[0].base_image_id; + // Left hand arm + image_id += 380; + + sub_98199C( + al, + 90, + image_id, + cl, + height, + lengthY, + lengthX, + 0); + + uint32 seatImageId; + + if (vehicle != NULL && vehicle->var_B5 >= 64) { + // Open Restraints + image_id = (vehicle->var_B5 - 64) >> 6; + image_id += direction * 3; + image_id += rideEntry->vehicles[0].base_image_id; + image_id += 64; + seatImageId = image_id; + } + else { + image_id = direction * 16; + // Var_20 Rotation of seats + image_id += seatRotation; + image_id += rideEntry->vehicles[0].base_image_id; + seatImageId = image_id; + } + + image_id = RCT2_GLOBAL(0x00F441A0, uint32); + if (image_id == 0x20000000) { + image_id = + 0xA0000000 | + (ride->vehicle_colours[0].body_colour << 19) | + (ride->vehicle_colours[0].trim_colour << 24); + } + image_id += seatImageId; + + rct_xyz16 seatCoords = { + .x = al, + .y = cl, + .z = height + }; + seatCoords.z += RCT2_ADDRESS(0x14280BC, sint16)[armRotation]; + + assert(armRotation < sizeof(TopSpinSeatPositionOffset)); + switch (direction) { + case 0: + seatCoords.x -= TopSpinSeatPositionOffset[armRotation]; + break; + case 1: + seatCoords.y += TopSpinSeatPositionOffset[armRotation]; + break; + case 2: + seatCoords.x += TopSpinSeatPositionOffset[armRotation]; + break; + case 3: + seatCoords.y -= TopSpinSeatPositionOffset[armRotation]; + break; + } + + RCT2_GLOBAL(0x014280B8, sint8) = (sint8)seatCoords.x; + RCT2_GLOBAL(0x014280B9, sint8) = (sint8)seatCoords.y; + RCT2_GLOBAL(0x014280BA, sint16) = seatCoords.z; + + sub_98199C( + (sint8)seatCoords.x, + 90, + image_id, + (sint8)seatCoords.y, + seatCoords.z, + lengthY, + lengthX, + 0); + + rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*); + if (dpi->zoom_level < 2 && vehicle != NULL && vehicle->num_peeps != 0) { + image_id = + (vehicle->peep_tshirt_colours[0] << 19) | + (vehicle->peep_tshirt_colours[1] << 24); + image_id += seatImageId; + image_id += 0xA0000000; + image_id += 76; + + sub_98199C((sint8)seatCoords.x, 90, image_id, (sint8)seatCoords.y, seatCoords.z, lengthY, lengthX, 0); + + if (vehicle->num_peeps > 2) { + image_id = + (vehicle->peep_tshirt_colours[2] << 19) | + (vehicle->peep_tshirt_colours[3] << 24); + image_id += seatImageId; + image_id += 0xA0000000; + image_id += 152; + + sub_98199C((sint8)seatCoords.x, 90, image_id, (sint8)seatCoords.y, seatCoords.z, lengthY, lengthX, 0); + } + + if (vehicle->num_peeps > 4) { + image_id = + (vehicle->peep_tshirt_colours[4] << 19) | + (vehicle->peep_tshirt_colours[5] << 24); + image_id += seatImageId; + image_id += 0xA0000000; + image_id += 228; + + sub_98199C((sint8)seatCoords.x, 90, image_id, (sint8)seatCoords.y, seatCoords.z, lengthY, lengthX, 0); + } + + if (vehicle->num_peeps > 6) { + image_id = + (vehicle->peep_tshirt_colours[6] << 19) | + (vehicle->peep_tshirt_colours[7] << 24); + image_id += seatImageId; + image_id += 0xA0000000; + image_id += 304; + + sub_98199C((sint8)seatCoords.x, 90, image_id, (sint8)seatCoords.y, seatCoords.z, lengthY, lengthX, 0); + } + } + + image_id = RCT2_GLOBAL(0x00F441A0, uint32); + if (image_id == 0x20000000) { + image_id = + 0xA0000000 | + (ride->track_colour_main[0] << 19) | + (ride->track_colour_additional[0] << 24); + } + + image_id += var_1F; + image_id += (direction & 1) * 48; + image_id += rideEntry->vehicles[0].base_image_id; + // Right hand arm + image_id += 476; + + sub_98199C( + al, + 90, + image_id, + cl, + height, + lengthY, + lengthX, + 0); + + image_id = RCT2_GLOBAL(0x00F441A0, uint32); + if (image_id == 0x20000000) { + image_id = + 0xA0000000 | + (ride->track_colour_main[0] << 19) | + (ride->track_colour_supports[0] << 24); + } + + image_id += (direction & 1) << 1; + image_id += rideEntry->vehicles[0].base_image_id; + // Right back bottom support + image_id += 573; + + sub_98199C( + al, + 90, + image_id, + cl, + height, + lengthY, + lengthX, + 0); + + RCT2_GLOBAL(0x009DE578, rct_map_element*) = curMapElement; + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_SETUP_CURRENT_TYPE, uint8) = VIEWPORT_INTERACTION_ITEM_RIDE; +} + +/* rct2: 0x0076693F */ +void top_spin_paint_tile_1(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement) { + uint32 image_id = RCT2_GLOBAL(0x00F441A0, uint32); + sub_6629BC(height, 0, image_id, direction & 1); + + image_id = 22137 | RCT2_GLOBAL(0x00F44198, uint32); + + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 0; + RCT2_GLOBAL(0x009DEA56, uint16) = height; + sub_98197C(0, 1, image_id, 0, height, 32, 32, get_current_rotation()); + + sint16 x = RCT2_GLOBAL(0x009DE56A, sint16), y = RCT2_GLOBAL(0x009DE56E, sint16); + uint16 entranceLoc = + ((x / 32) + loc_7667AE[get_current_rotation()].x) | + (((y / 32) + loc_7667AE[get_current_rotation()].y) << 8); + + uint8 entranceId = (mapElement->properties.track.sequence & 0x70) >> 4; + rct_ride* ride = GET_RIDE(rideIndex); + + if (ride->entrances[entranceId] != entranceLoc && ride->exits[entranceId] != entranceLoc) { + + image_id = 22141 | RCT2_GLOBAL(0x00F441A0, uint32); + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 2; + RCT2_GLOBAL(0x009DEA56, uint16) = height + 2; + + sub_98199C(0, 7, image_id, 0, height, 1, 32, 0); + } + + entranceLoc = + ((x / 32) + loc_7667AC[get_current_rotation()].x) | + (((y / 32) + loc_7667AC[get_current_rotation()].y) << 8); + + if (ride->entrances[entranceId] != entranceLoc && ride->exits[entranceId] != entranceLoc) { + + image_id = 22138 | RCT2_GLOBAL(0x00F441A0, uint32); + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 2; + RCT2_GLOBAL(0x009DEA56, uint16) = height + 2; + + sub_98199C(0, 7, image_id, 0, height, 32, 1, 0); + } + + top_spin_paint_vehicle(32, 32, rideIndex, direction, height, mapElement); + + RCT2_GLOBAL(0x141E9B4, uint16) = height + 2; + RCT2_GLOBAL(0x141E9B6, uint16) = 32; + RCT2_GLOBAL(0x141E9B8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9BC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C8, uint16) = height + 2; + RCT2_GLOBAL(0x141E9CA, uint16) = 32; + RCT2_GLOBAL(0x141E9CC, uint16) = height + 2; + RCT2_GLOBAL(0x141E9CE, uint16) = 32; + RCT2_GLOBAL(0x141E9D0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D4, uint16) = 0xFFFF; + + height += 110; + if (RCT2_GLOBAL(0x141E9D8, sint16) < height) { + RCT2_GLOBAL(0x141E9D8, sint16) = height; + RCT2_GLOBAL(0x141E9DA, uint8) = 32; + } +} + +/* rct2: 0x00767033 */ +void top_spin_paint_tile_2(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement) { + uint32 image_id = RCT2_GLOBAL(0x00F441A0, uint32); + sub_6629BC(height, 0, image_id, direction & 1); + + image_id = 22137 | RCT2_GLOBAL(0x00F44198, uint32); + + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 0; + RCT2_GLOBAL(0x009DEA56, uint16) = height; + sub_98197C(0, 1, image_id, 0, height, 32, 32, get_current_rotation()); + + sint16 x = RCT2_GLOBAL(0x009DE56A, sint16), y = RCT2_GLOBAL(0x009DE56E, sint16); + uint16 entranceLoc = + ((x / 32) + loc_7667AC[get_current_rotation()].x) | + (((y / 32) + loc_7667AC[get_current_rotation()].y) << 8); + + uint8 entranceId = (mapElement->properties.track.sequence & 0x70) >> 4; + rct_ride* ride = GET_RIDE(rideIndex); + + if (ride->entrances[entranceId] != entranceLoc && ride->exits[entranceId] != entranceLoc) { + + image_id = 22138 | RCT2_GLOBAL(0x00F441A0, uint32); + RCT2_GLOBAL(0x009DEA52, uint16) = 2; + RCT2_GLOBAL(0x009DEA54, uint16) = 0; + RCT2_GLOBAL(0x009DEA56, uint16) = height + 2; + + sub_98199C(0, 7, image_id, 0, height, 32, 1, 0); + } + + RCT2_GLOBAL(0x141E9B4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9B8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9BC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9CC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D4, uint16) = 0xFFFF; + + height += 110; + if (RCT2_GLOBAL(0x141E9D8, sint16) < height) { + RCT2_GLOBAL(0x141E9D8, sint16) = height; + RCT2_GLOBAL(0x141E9DA, uint8) = 32; + } +} + +/* rct2: 0x0076718D */ +void top_spin_paint_tile_4(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement) { + uint32 image_id = RCT2_GLOBAL(0x00F441A0, uint32); + sub_6629BC(height, 0, image_id, direction & 1); + + image_id = 22137 | RCT2_GLOBAL(0x00F44198, uint32); + + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 0; + RCT2_GLOBAL(0x009DEA56, uint16) = height; + sub_98197C(0, 1, image_id, 0, height, 32, 32, get_current_rotation()); + + sint16 x = RCT2_GLOBAL(0x009DE56A, sint16), y = RCT2_GLOBAL(0x009DE56E, sint16); + uint16 entranceLoc = + ((x / 32) + loc_7667AE[get_current_rotation()].x) | + (((y / 32) + loc_7667AE[get_current_rotation()].y) << 8); + + uint8 entranceId = (mapElement->properties.track.sequence & 0x70) >> 4; + rct_ride* ride = GET_RIDE(rideIndex); + + if (ride->entrances[entranceId] != entranceLoc && ride->exits[entranceId] != entranceLoc) { + + image_id = 22141 | RCT2_GLOBAL(0x00F441A0, uint32); + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 2; + RCT2_GLOBAL(0x009DEA56, uint16) = height + 2; + + sub_98199C(0, 7, image_id, 0, height, 1, 32, 0); + } + + RCT2_GLOBAL(0x141E9B4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9B8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9BC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9CC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D4, uint16) = 0xFFFF; + + height += 110; + if (RCT2_GLOBAL(0x141E9D8, sint16) < height) { + RCT2_GLOBAL(0x141E9D8, sint16) = height; + RCT2_GLOBAL(0x141E9DA, uint8) = 32; + } +} + +/* rct2: 0x00766B4C */ +void top_spin_paint_tile_3(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement) { + uint32 image_id = RCT2_GLOBAL(0x00F441A0, uint32); + sub_6629BC(height, 0, image_id, direction & 1); + + image_id = 22136 | RCT2_GLOBAL(0x00F44198, uint32); + + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 0; + RCT2_GLOBAL(0x009DEA56, uint16) = height; + sub_98197C(0, 1, image_id, 0, height, 32, 32, get_current_rotation()); + + sint16 x = RCT2_GLOBAL(0x009DE56A, sint16), y = RCT2_GLOBAL(0x009DE56E, sint16); + uint16 entranceLoc = + ((x / 32) + loc_7667AC[get_current_rotation()].x) | + (((y / 32) + loc_7667AC[get_current_rotation()].y) << 8); + + uint8 entranceId = (mapElement->properties.track.sequence & 0x70) >> 4; + rct_ride* ride = GET_RIDE(rideIndex); + + if (ride->entrances[entranceId] != entranceLoc && ride->exits[entranceId] != entranceLoc) { + + image_id = 22138 | RCT2_GLOBAL(0x00F441A0, uint32); + RCT2_GLOBAL(0x009DEA52, uint16) = 2; + RCT2_GLOBAL(0x009DEA54, uint16) = 0; + RCT2_GLOBAL(0x009DEA56, uint16) = height + 2; + + sub_98199C(0, 7, image_id, 0, height, 32, 1, 0); + } + + entranceLoc = + ((x / 32) + loc_7667AC[(get_current_rotation() + 3) & 3].x) | + (((y / 32) + loc_7667AC[(get_current_rotation() + 3) & 3].y) << 8); + + if (ride->entrances[entranceId] != entranceLoc && ride->exits[entranceId] != entranceLoc) { + + image_id = 22139 | RCT2_GLOBAL(0x00F441A0, uint32); + + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 30; + RCT2_GLOBAL(0x009DEA56, uint16) = height + 2; + sub_98197C(0, 7, image_id, 0, height, 1, 32, get_current_rotation()); + } + + top_spin_paint_vehicle(32, -32, rideIndex, direction, height, mapElement); + + RCT2_GLOBAL(0x141E9B4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9B8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9BC, uint16) = height + 2; + RCT2_GLOBAL(0x141E9BE, uint16) = 32; + RCT2_GLOBAL(0x141E9C0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9CC, uint16) = height + 2; + RCT2_GLOBAL(0x141E9CE, uint16) = 32; + RCT2_GLOBAL(0x141E9D0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D4, uint16) = height + 2; + RCT2_GLOBAL(0x141E9D6, uint16) = 32; + + height += 110; + if (RCT2_GLOBAL(0x141E9D8, sint16) < height) { + RCT2_GLOBAL(0x141E9D8, sint16) = height; + RCT2_GLOBAL(0x141E9DA, uint8) = 32; + } +} + +/* rct2: 0x007672E7 */ +void top_spin_paint_tile_5(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement) { + uint32 image_id = RCT2_GLOBAL(0x00F441A0, uint32); + sub_6629BC(height, 0, image_id, direction & 1); + + image_id = 22136 | RCT2_GLOBAL(0x00F44198, uint32); + + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 0; + RCT2_GLOBAL(0x009DEA56, uint16) = height; + sub_98197C(0, 1, image_id, 0, height, 32, 32, get_current_rotation()); + + sint16 x = RCT2_GLOBAL(0x009DE56A, sint16), y = RCT2_GLOBAL(0x009DE56E, sint16); + uint8 entranceId = (mapElement->properties.track.sequence & 0x70) >> 4; + rct_ride* ride = GET_RIDE(rideIndex); + + uint16 entranceLoc = + ((x / 32) + loc_7667AC[(get_current_rotation() + 3) & 3].x) | + (((y / 32) + loc_7667AC[(get_current_rotation() + 3) & 3].y) << 8); + + if (ride->entrances[entranceId] != entranceLoc && ride->exits[entranceId] != entranceLoc) { + image_id = 22139 | RCT2_GLOBAL(0x00F441A0, uint32); + + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 30; + RCT2_GLOBAL(0x009DEA56, uint16) = height + 2; + sub_98197C(0, 7, image_id, 0, height, 1, 32, get_current_rotation()); + } + + top_spin_paint_vehicle(0, -32, rideIndex, direction, height, mapElement); + + RCT2_GLOBAL(0x141E9B4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9B8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9BC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9CC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D4, uint16) = 0xFFFF; + + height += 112; + if (RCT2_GLOBAL(0x141E9D8, sint16) < height) { + RCT2_GLOBAL(0x141E9D8, sint16) = height; + RCT2_GLOBAL(0x141E9DA, uint8) = 32; + } +} + +/* rct2: 0x00766D09 */ +void top_spin_paint_tile_6(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement) { + uint32 image_id = RCT2_GLOBAL(0x00F441A0, uint32); + sub_6629BC(height, 0, image_id, direction & 1); + + image_id = 22135 | RCT2_GLOBAL(0x00F44198, uint32); + + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 0; + RCT2_GLOBAL(0x009DEA56, uint16) = height; + sub_98197C(0, 1, image_id, 0, height, 32, 32, get_current_rotation()); + + sint16 x = RCT2_GLOBAL(0x009DE56A, sint16), y = RCT2_GLOBAL(0x009DE56E, sint16); + uint16 entranceLoc = + ((x / 32) + loc_7667AE[get_current_rotation()].x) | + (((y / 32) + loc_7667AE[get_current_rotation()].y) << 8); + + uint8 entranceId = (mapElement->properties.track.sequence & 0x70) >> 4; + rct_ride* ride = GET_RIDE(rideIndex); + + if (ride->entrances[entranceId] != entranceLoc && ride->exits[entranceId] != entranceLoc) { + + image_id = 22141 | RCT2_GLOBAL(0x00F441A0, uint32); + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 2; + RCT2_GLOBAL(0x009DEA56, uint16) = height + 2; + + sub_98199C(0, 7, image_id, 0, height, 1, 32, 0); + } + + entranceLoc = + ((x / 32) + loc_7667AE[(get_current_rotation() + 1) & 3].x) | + (((y / 32) + loc_7667AE[(get_current_rotation() + 1) & 3].y) << 8); + + if (ride->entrances[entranceId] != entranceLoc && ride->exits[entranceId] != entranceLoc) { + + image_id = 22140 | RCT2_GLOBAL(0x00F441A0, uint32); + RCT2_GLOBAL(0x009DEA52, uint16) = 30; + RCT2_GLOBAL(0x009DEA54, uint16) = 2; + RCT2_GLOBAL(0x009DEA56, uint16) = height + 2; + + sub_98197C(0, 7, image_id, 0, height, 32, 1, get_current_rotation()); + } + + top_spin_paint_vehicle(-32, 32, rideIndex, direction, height, mapElement); + + RCT2_GLOBAL(0x141E9B4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9B8, uint16) = height + 2; + RCT2_GLOBAL(0x141E9BA, uint16) = 32; + RCT2_GLOBAL(0x141E9BC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C8, uint16) = height + 2; + RCT2_GLOBAL(0x141E9CA, uint16) = 32; + RCT2_GLOBAL(0x141E9CC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D0, uint16) = height + 2; + RCT2_GLOBAL(0x141E9D0, uint16) = 32; + RCT2_GLOBAL(0x141E9D4, uint16) = 0xFFFF; + + height += 110; + if (RCT2_GLOBAL(0x141E9D8, sint16) < height) { + RCT2_GLOBAL(0x141E9D8, sint16) = height; + RCT2_GLOBAL(0x141E9DA, uint8) = 32; + } +} + +/* rct2: 0x00766EC6 */ +void top_spin_paint_tile_7(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement) { + uint32 image_id = RCT2_GLOBAL(0x00F441A0, uint32); + sub_6629BC(height, 0, image_id, direction & 1); + + image_id = 22134 | RCT2_GLOBAL(0x00F44198, uint32); + + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 0; + RCT2_GLOBAL(0x009DEA56, uint16) = height; + sub_98197C(0, 1, image_id, 0, height, 32, 32, get_current_rotation()); + + sint16 x = RCT2_GLOBAL(0x009DE56A, sint16), y = RCT2_GLOBAL(0x009DE56E, sint16); + uint8 entranceId = (mapElement->properties.track.sequence & 0x70) >> 4; + rct_ride* ride = GET_RIDE(rideIndex); + + uint16 entranceLoc = + ((x / 32) + loc_7667AE[(get_current_rotation() + 1) & 3].x) | + (((y / 32) + loc_7667AE[(get_current_rotation() + 1) & 3].y) << 8); + + if (ride->entrances[entranceId] != entranceLoc && ride->exits[entranceId] != entranceLoc) { + + image_id = 22140 | RCT2_GLOBAL(0x00F441A0, uint32); + + RCT2_GLOBAL(0x009DEA52, uint16) = 29; + RCT2_GLOBAL(0x009DEA54, uint16) = 0; + RCT2_GLOBAL(0x009DEA56, uint16) = height + 3; + sub_98197C(0, 7, image_id, 0, height, 28, 1, get_current_rotation()); + } + + entranceLoc = + ((x / 32) + loc_7667AC[(get_current_rotation() + 3) & 3].x) | + (((y / 32) + loc_7667AC[(get_current_rotation() + 3) & 3].y) << 8); + + if (ride->entrances[entranceId] != entranceLoc && ride->exits[entranceId] != entranceLoc) { + + image_id = 22139 | RCT2_GLOBAL(0x00F441A0, uint32); + + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 29; + RCT2_GLOBAL(0x009DEA56, uint16) = height + 3; + sub_98197C(0, 7, image_id, 0, height, 1, 28, get_current_rotation()); + } + + top_spin_paint_vehicle(-32, -32, rideIndex, direction, height, mapElement); + + RCT2_GLOBAL(0x141E9B4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9B8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9BC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C0, uint16) = height + 2; + RCT2_GLOBAL(0x141E9C2, uint16) = 32; + RCT2_GLOBAL(0x141E9C4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9CC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D0, uint16) = height + 2; + RCT2_GLOBAL(0x141E9D2, uint16) = 32; + RCT2_GLOBAL(0x141E9D4, uint16) = height + 2; + RCT2_GLOBAL(0x141E9D6, uint16) = 32; + + height += 110; + if (RCT2_GLOBAL(0x141E9D8, sint16) < height) { + RCT2_GLOBAL(0x141E9D8, sint16) = height; + RCT2_GLOBAL(0x141E9DA, uint8) = 32; + } +} + +/* rct2: 0x007673FA */ +void top_spin_paint_tile_8(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement) { + uint32 image_id = RCT2_GLOBAL(0x00F441A0, uint32); + sub_6629BC(height, 0, image_id, direction & 1); + + image_id = 22135 | RCT2_GLOBAL(0x00F44198, uint32); + + RCT2_GLOBAL(0x009DEA52, uint16) = 0; + RCT2_GLOBAL(0x009DEA54, uint16) = 0; + RCT2_GLOBAL(0x009DEA56, uint16) = height; + sub_98197C(0, 1, image_id, 0, height, 32, 32, get_current_rotation()); + + sint16 x = RCT2_GLOBAL(0x009DE56A, sint16), y = RCT2_GLOBAL(0x009DE56E, sint16); + uint8 entranceId = (mapElement->properties.track.sequence & 0x70) >> 4; + rct_ride* ride = GET_RIDE(rideIndex); + + uint16 entranceLoc = + ((x / 32) + loc_7667AE[(get_current_rotation() + 1) & 3].x) | + (((y / 32) + loc_7667AE[(get_current_rotation() + 1) & 3].y) << 8); + + if (ride->entrances[entranceId] != entranceLoc && ride->exits[entranceId] != entranceLoc) { + + image_id = 22140 | RCT2_GLOBAL(0x00F441A0, uint32); + RCT2_GLOBAL(0x009DEA52, uint16) = 30; + RCT2_GLOBAL(0x009DEA54, uint16) = 0; + RCT2_GLOBAL(0x009DEA56, uint16) = height + 2; + + sub_98197C(0, 7, image_id, 0, height, 32, 1, get_current_rotation()); + } + top_spin_paint_vehicle(-32, 0, rideIndex, direction, height, mapElement); + + RCT2_GLOBAL(0x141E9B4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9B8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9BC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C4, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9C8, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9CC, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D0, uint16) = 0xFFFF; + RCT2_GLOBAL(0x141E9D4, uint16) = 0xFFFF; + + height += 112; + if (RCT2_GLOBAL(0x141E9D8, sint16) < height) { + RCT2_GLOBAL(0x141E9D8, sint16) = height; + RCT2_GLOBAL(0x141E9DA, uint8) = 32; + } +} + +/* rct2: 0x007667BC + */ +void top_spin_paint_setup_rot_0(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement) { + switch (trackSequence) + { + case 0: + top_spin_paint_tile_0(rideIndex, trackSequence, direction, height, mapElement); + break; + case 1: + top_spin_paint_tile_1(rideIndex, trackSequence, direction, height, mapElement); + break; + case 2: + top_spin_paint_tile_2(rideIndex, trackSequence, direction, height, mapElement); + break; + case 3: + top_spin_paint_tile_3(rideIndex, trackSequence, direction, height, mapElement); + break; + case 4: + top_spin_paint_tile_4(rideIndex, trackSequence, direction, height, mapElement); + break; + case 5: + top_spin_paint_tile_5(rideIndex, trackSequence, direction, height, mapElement); + break; + case 6: + top_spin_paint_tile_6(rideIndex, trackSequence, direction, height, mapElement); + break; + case 7: + top_spin_paint_tile_7(rideIndex, trackSequence, direction, height, mapElement); + break; + case 8: + top_spin_paint_tile_8(rideIndex, trackSequence, direction, height, mapElement); + break; + } + return; +} + +/* rct2: 0x007667EC +*/ +void top_spin_paint_setup_rot_1(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement) { + switch (trackSequence) + { + case 0: + top_spin_paint_tile_0(rideIndex, trackSequence, direction, height, mapElement); + break; + case 1: + top_spin_paint_tile_3(rideIndex, trackSequence, direction, height, mapElement); + break; + case 2: + top_spin_paint_tile_5(rideIndex, trackSequence, direction, height, mapElement); + break; + case 3: + top_spin_paint_tile_7(rideIndex, trackSequence, direction, height, mapElement); + break; + case 4: + top_spin_paint_tile_2(rideIndex, trackSequence, direction, height, mapElement); + break; + case 5: + top_spin_paint_tile_8(rideIndex, trackSequence, direction, height, mapElement); + break; + case 6: + top_spin_paint_tile_1(rideIndex, trackSequence, direction, height, mapElement); + break; + case 7: + top_spin_paint_tile_6(rideIndex, trackSequence, direction, height, mapElement); + break; + case 8: + top_spin_paint_tile_4(rideIndex, trackSequence, direction, height, mapElement); + break; + } + return; +} + +/* rct2: 0x0076681C +*/ +void top_spin_paint_setup_rot_2(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement) { + switch (trackSequence) + { + case 0: + top_spin_paint_tile_0(rideIndex, trackSequence, direction, height, mapElement); + break; + case 1: + top_spin_paint_tile_7(rideIndex, trackSequence, direction, height, mapElement); + break; + case 2: + top_spin_paint_tile_8(rideIndex, trackSequence, direction, height, mapElement); + break; + case 3: + top_spin_paint_tile_6(rideIndex, trackSequence, direction, height, mapElement); + break; + case 4: + top_spin_paint_tile_5(rideIndex, trackSequence, direction, height, mapElement); + break; + case 5: + top_spin_paint_tile_4(rideIndex, trackSequence, direction, height, mapElement); + break; + case 6: + top_spin_paint_tile_3(rideIndex, trackSequence, direction, height, mapElement); + break; + case 7: + top_spin_paint_tile_1(rideIndex, trackSequence, direction, height, mapElement); + break; + case 8: + top_spin_paint_tile_2(rideIndex, trackSequence, direction, height, mapElement); + break; + } + return; +} + +/* rct2: 0x0076684C +*/ +void top_spin_paint_setup_rot_3(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement) { + switch (trackSequence) + { + case 0: + top_spin_paint_tile_0(rideIndex, trackSequence, direction, height, mapElement); + break; + case 1: + top_spin_paint_tile_6(rideIndex, trackSequence, direction, height, mapElement); + break; + case 2: + top_spin_paint_tile_4(rideIndex, trackSequence, direction, height, mapElement); + break; + case 3: + top_spin_paint_tile_1(rideIndex, trackSequence, direction, height, mapElement); + break; + case 4: + top_spin_paint_tile_8(rideIndex, trackSequence, direction, height, mapElement); + break; + case 5: + top_spin_paint_tile_2(rideIndex, trackSequence, direction, height, mapElement); + break; + case 6: + top_spin_paint_tile_7(rideIndex, trackSequence, direction, height, mapElement); + break; + case 7: + top_spin_paint_tile_3(rideIndex, trackSequence, direction, height, mapElement); + break; + case 8: + top_spin_paint_tile_5(rideIndex, trackSequence, direction, height, mapElement); + break; + } + return; +} + +void shop_paint_setup(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement); + +/* 0x00761358 */ +TRACK_PAINT_FUNCTION shop_base_functions[] = { + shop_paint_setup, + shop_paint_setup, + shop_paint_setup, + shop_paint_setup, +}; + +/* 0x00761160 */ +TRACK_PAINT_FUNCTION* shop_track_paint_functions[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + shop_base_functions, // 118 + NULL, + NULL, + shop_base_functions // 121 +}; + +/** + * + * rct2: 0x00761378 + * rct2: 0x007614DB + * rct2: 0x0076163F + * rct2: 0x007617A5 + */ +void shop_paint_setup(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement) +{ + bool hasSupports = sub_6629BC(height, 0, RCT2_GLOBAL(0x00F441A4, uint32), direction & 1); + + RCT2_GLOBAL(0x0141E9D0, sint16) = -1; + RCT2_GLOBAL(0x0141E9C4, sint16) = -1; + RCT2_GLOBAL(0x0141E9CC, sint16) = -1; + RCT2_GLOBAL(0x0141E9B8, sint16) = -1; + RCT2_GLOBAL(0x0141E9BC, sint16) = -1; + RCT2_GLOBAL(0x0141E9B4, sint16) = -1; + RCT2_GLOBAL(0x0141E9C0, sint16) = -1; + RCT2_GLOBAL(0x0141E9C8, sint16) = -1; + RCT2_GLOBAL(0x0141E9D4, sint16) = -1; + + rct_ride *ride = GET_RIDE(rideIndex); + rct_ride_type *rideEntry = GET_RIDE_ENTRY(ride->subtype); + rct_ride_type_vehicle *firstVehicleEntry = &rideEntry->vehicles[0]; + + uint32 imageId = RCT2_GLOBAL(0x00F44198, uint32); + if (imageId & 0x80000000) { + imageId &= 0x60FFFFFF; + } + imageId += firstVehicleEntry->base_image_id; + imageId += direction; + + sint16 height16 = (sint16)height; + int rotation = get_current_rotation(); + if (hasSupports) { + uint32 foundationImageId = RCT2_GLOBAL(0x00F441A4, uint32); + foundationImageId |= 3395; + + RCT2_GLOBAL(0x009DEA52, uint16) = 2; + RCT2_GLOBAL(0x009DEA54, uint16) = 2; + RCT2_GLOBAL(0x009DEA56, sint16) = height16; + sub_98197C(0, 45, foundationImageId, 0, height, 28, 28, rotation); + + RCT2_GLOBAL(0x009DEA52, uint16) = 2; + RCT2_GLOBAL(0x009DEA54, uint16) = 2; + RCT2_GLOBAL(0x009DEA56, sint16) = height16; + sub_98199C(0, 45, imageId, 0, height, 28, 28, rotation); + } else { + RCT2_GLOBAL(0x009DEA52, uint16) = 2; + RCT2_GLOBAL(0x009DEA54, uint16) = 2; + RCT2_GLOBAL(0x009DEA56, sint16) = height16; + sub_98197C(0, 45, imageId, 0, height, 28, 28, rotation); + } + + height16 += 48; + if (RCT2_GLOBAL(0x00141E9D8, sint16) < height16) { + RCT2_GLOBAL(0x00141E9D8, sint16) = height16; + RCT2_GLOBAL(0x00141E9DA, sint16) = 32; + } +} diff --git a/src/ride/track_paint.h b/src/ride/track_paint.h new file mode 100644 index 0000000000..cea5f99250 --- /dev/null +++ b/src/ride/track_paint.h @@ -0,0 +1,11 @@ +#ifndef _TRACK_PAINT_H +#define _TRACK_PAINT_H + +#include "../common.h" + +typedef void (*TRACK_PAINT_FUNCTION)(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element* mapElement); + +extern TRACK_PAINT_FUNCTION* top_spin_track_paint_functions[]; +extern TRACK_PAINT_FUNCTION* shop_track_paint_functions[]; + +#endif \ No newline at end of file diff --git a/src/ride/vehicle.c b/src/ride/vehicle.c index 3536ea1985..4f66083e0b 100644 --- a/src/ride/vehicle.c +++ b/src/ride/vehicle.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,10 +21,14 @@ #include "../addresses.h" #include "../audio/audio.h" #include "../audio/mixer.h" +#include "../config.h" +#include "../hook.h" #include "../interface/viewport.h" +#include "../openrct2.h" #include "../world/sprite.h" #include "ride.h" #include "ride_data.h" +#include "track.h" #include "vehicle.h" static void vehicle_update(rct_vehicle *vehicle); @@ -60,42 +64,36 @@ void vehicle_update_sound_params(rct_vehicle* vehicle) if (t8 >= RCT2_GLOBAL(0x009AF5A0, sint16) && t9 >= RCT2_GLOBAL(0x009AF5A2, sint16)) { uint16 v9 = sub_6BC2F3(vehicle); rct_vehicle_sound_params* i; - //for (i = RCT2_ADDRESS(0x00F438B4, rct_vehicle_sound_params); i < RCT2_GLOBAL(0x00F438B0, rct_vehicle_sound_params*) && v9 <= i->var_A; i++); for (i = &gVehicleSoundParamsList[0]; i < gVehicleSoundParamsListEnd && v9 <= i->var_A; i++); - //if (i < RCT2_ADDRESS(0x00F43908, rct_vehicle_sound_params)) { // 0x00F43908 is end of rct_vehicle_sound_params list, which has 7 elements, not to be confused with variable at 0x00F43908 if (i < &gVehicleSoundParamsList[countof(gVehicleSoundParamsList)]) { - //if (RCT2_GLOBAL(0x00F438B0, rct_vehicle_sound_params*) < RCT2_ADDRESS(0x00F43908, rct_vehicle_sound_params)) { - // RCT2_GLOBAL(0x00F438B0, rct_vehicle_sound_params*)++; - //} if (gVehicleSoundParamsListEnd < &gVehicleSoundParamsList[countof(gVehicleSoundParamsList)]) { gVehicleSoundParamsListEnd++; } - //rct_vehicle_sound_params* j = RCT2_GLOBAL(0x00F438B0, rct_vehicle_sound_params*) - 1; rct_vehicle_sound_params* j = gVehicleSoundParamsListEnd - 1; while (j >= i) { j--; *(j + 1) = *j; } i->var_A = v9; - int panx = (RCT2_GLOBAL(0x009AF5A0, sint16) / 2) + (RCT2_GLOBAL(0x009AF5A4, sint16) / 2) - RCT2_GLOBAL(0x00F438A4, rct_viewport*)->view_x; - panx >>= RCT2_GLOBAL(0x00F438A4, rct_viewport*)->zoom; - panx += RCT2_GLOBAL(0x00F438A4, rct_viewport*)->x; + int pan_x = (RCT2_GLOBAL(0x009AF5A0, sint16) / 2) + (RCT2_GLOBAL(0x009AF5A4, sint16) / 2) - RCT2_GLOBAL(0x00F438A4, rct_viewport*)->view_x; + pan_x >>= RCT2_GLOBAL(0x00F438A4, rct_viewport*)->zoom; + pan_x += RCT2_GLOBAL(0x00F438A4, rct_viewport*)->x; uint16 screenwidth = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); if (screenwidth < 64) { screenwidth = 64; } - i->panx = ((((panx << 16) / screenwidth) - 0x8000) >> 4); + i->pan_x = ((((pan_x << 16) / screenwidth) - 0x8000) >> 4); - int pany = (RCT2_GLOBAL(0x009AF5A2, sint16) / 2) + (RCT2_GLOBAL(0x009AF5A6, sint16) / 2) - RCT2_GLOBAL(0x00F438A4, rct_viewport*)->view_y; - pany >>= RCT2_GLOBAL(0x00F438A4, rct_viewport*)->zoom; - pany += RCT2_GLOBAL(0x00F438A4, rct_viewport*)->y; + int pan_y = (RCT2_GLOBAL(0x009AF5A2, sint16) / 2) + (RCT2_GLOBAL(0x009AF5A6, sint16) / 2) - RCT2_GLOBAL(0x00F438A4, rct_viewport*)->view_y; + pan_y >>= RCT2_GLOBAL(0x00F438A4, rct_viewport*)->zoom; + pan_y += RCT2_GLOBAL(0x00F438A4, rct_viewport*)->y; uint16 screenheight = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16); if (screenheight < 64) { screenheight = 64; } - i->pany = ((((pany << 16) / screenheight) - 0x8000) >> 4); + i->pan_y = ((((pan_y << 16) / screenheight) - 0x8000) >> 4); sint32 v19 = vehicle->velocity; @@ -141,7 +139,7 @@ int sub_6BC2F3(rct_vehicle* vehicle) int result = 0; rct_vehicle* vehicle_temp = vehicle; do { - result += vehicle_temp->var_46; + result += vehicle_temp->friction; } while (vehicle_temp->next_vehicle_on_train != (uint16)-1 && (vehicle_temp = GET_VEHICLE(vehicle_temp->next_vehicle_on_train))); sint32 v4 = vehicle->velocity; if (v4 < 0) { @@ -149,10 +147,10 @@ int sub_6BC2F3(rct_vehicle* vehicle) } result += ((uint16)v4) >> 13; rct_vehicle_sound* vehicle_sound = &gVehicleSoundList[0]; - //rct_vehicle_sound* vehicle_sound = RCT2_ADDRESS(RCT2_ADDRESS_VEHICLE_SOUND_LIST, rct_vehicle_sound); + while (vehicle_sound->id != vehicle->sprite_index) { vehicle_sound++; - //if (vehicle_sound >= RCT2_GLOBAL(0x009AF42C, rct_vehicle_sound*)) { + if (vehicle_sound >= &gVehicleSoundList[countof(gVehicleSoundList)]) { return result; } @@ -166,7 +164,7 @@ int sub_6BC2F3(rct_vehicle* vehicle) */ void vehicle_sounds_update() { - if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) != -1 && !RCT2_GLOBAL(0x009AF59C, uint8) && RCT2_GLOBAL(0x009AF59D, uint8) & 1) { + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) != -1 && !gGameSoundsOff && gConfigSound.sound && !gOpenRCT2Headless) { RCT2_GLOBAL(0x00F438A4, rct_viewport*) = (rct_viewport*)-1; rct_viewport* viewport = (rct_viewport*)-1; rct_window* window = RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); @@ -192,39 +190,23 @@ void vehicle_sounds_update() } } } - //label12: - //RCT2_GLOBAL(0x00F438B0, rct_vehicle_sound_params**) = &RCT2_GLOBAL(0x00F438B4, rct_vehicle_sound_params*); gVehicleSoundParamsListEnd = &gVehicleSoundParamsList[0]; for (uint16 i = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_VEHICLE, uint16); i != SPRITE_INDEX_NULL; i = g_sprite_list[i].vehicle.next) { vehicle_update_sound_params(&g_sprite_list[i].vehicle); } - //for (rct_vehicle_sound* vehicle_sound = &RCT2_GLOBAL(RCT2_ADDRESS_VEHICLE_SOUND_LIST, rct_vehicle_sound); vehicle_sound != &RCT2_GLOBAL(0x009AF42C, rct_vehicle_sound); vehicle_sound++) { for(int i = 0; i < countof(gVehicleSoundList); i++){ rct_vehicle_sound* vehicle_sound = &gVehicleSoundList[i]; if (vehicle_sound->id != (uint16)-1) { - //for (rct_vehicle_sound_params* vehicle_sound_params = &RCT2_GLOBAL(0x00F438B4, rct_vehicle_sound_params); vehicle_sound_params != RCT2_GLOBAL(0x00F438B0, rct_vehicle_sound_params*); vehicle_sound_params++) { for (rct_vehicle_sound_params* vehicle_sound_params = &gVehicleSoundParamsList[0]; vehicle_sound_params != gVehicleSoundParamsListEnd; vehicle_sound_params++) { if (vehicle_sound->id == vehicle_sound_params->id) { goto label26; } } if (vehicle_sound->sound1_id != (uint16)-1) { -#ifdef USE_MIXER Mixer_Stop_Channel(vehicle_sound->sound1_channel); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_stop(&vehicle_sound->sound1); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif } if (vehicle_sound->sound2_id != (uint16)-1) { -#ifdef USE_MIXER Mixer_Stop_Channel(vehicle_sound->sound2_channel); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_stop(&vehicle_sound->sound2); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif } vehicle_sound->id = (uint16)-1; } @@ -232,52 +214,50 @@ void vehicle_sounds_update() ; } - //for (rct_vehicle_sound_params* vehicle_sound_params = &RCT2_GLOBAL(0x00F438B4, rct_vehicle_sound_params); ; vehicle_sound_params++) { for (rct_vehicle_sound_params* vehicle_sound_params = &gVehicleSoundParamsList[0]; ; vehicle_sound_params++) { label28: - //if (vehicle_sound_params >= RCT2_GLOBAL(0x00F438B0, rct_vehicle_sound_params*)) { if (vehicle_sound_params >= gVehicleSoundParamsListEnd) { return; } uint8 vol1 = 0xFF; uint8 vol2 = 0xFF; - sint16 pany = vehicle_sound_params->pany; - if (pany < 0) { - pany = -pany; + sint16 pan_y = vehicle_sound_params->pan_y; + if (pan_y < 0) { + pan_y = -pan_y; } - if (pany > 0xFFF) { - pany = 0xFFF; + if (pan_y > 0xFFF) { + pan_y = 0xFFF; } - pany -= 0x800; - if (pany > 0) { - pany -= 0x400; - pany = -pany; - pany = pany / 4; - vol1 = LOBYTE(pany); - if ((sint8)HIBYTE(pany) != 0) { + pan_y -= 0x800; + if (pan_y > 0) { + pan_y -= 0x400; + pan_y = -pan_y; + pan_y = pan_y / 4; + vol1 = LOBYTE(pan_y); + if ((sint8)HIBYTE(pan_y) != 0) { vol1 = 0xFF; - if ((sint8)HIBYTE(pany) < 0) { + if ((sint8)HIBYTE(pan_y) < 0) { vol1 = 0; } } } - sint16 panx = vehicle_sound_params->panx; - if (panx < 0) { - panx = -panx; + sint16 pan_x = vehicle_sound_params->pan_x; + if (pan_x < 0) { + pan_x = -pan_x; } - if (panx > 0xFFF) { - panx = 0xFFF; + if (pan_x > 0xFFF) { + pan_x = 0xFFF; } - panx -= 0x800; - if (panx > 0) { - panx -= 0x400; - panx = -panx; - panx = panx / 4; - vol2 = LOBYTE(panx); - if ((sint8)HIBYTE(panx) != 0) { + pan_x -= 0x800; + if (pan_x > 0) { + pan_x -= 0x400; + pan_x = -pan_x; + pan_x = pan_x / 4; + vol2 = LOBYTE(pan_x); + if ((sint8)HIBYTE(pan_x) != 0) { vol2 = 0xFF; - if ((sint8)HIBYTE(panx) < 0) { + if ((sint8)HIBYTE(pan_x) < 0) { vol2 = 0; } } @@ -293,18 +273,15 @@ void vehicle_sounds_update() } rct_vehicle_sound* vehicle_sound = &gVehicleSoundList[0]; - //rct_vehicle_sound* vehicle_sound = &RCT2_GLOBAL(RCT2_ADDRESS_VEHICLE_SOUND_LIST, rct_vehicle_sound); while (vehicle_sound_params->id != vehicle_sound->id) { - vehicle_sound++; // went here 2x - //if (vehicle_sound >= &RCT2_GLOBAL(0x009AF42C, rct_vehicle_sound)) { + vehicle_sound++; if (vehicle_sound >= &gVehicleSoundList[countof(gVehicleSoundList)]) { - //vehicle_sound = &RCT2_GLOBAL(RCT2_ADDRESS_VEHICLE_SOUND_LIST, rct_vehicle_sound); vehicle_sound = &gVehicleSoundList[0]; int i = 0; while (vehicle_sound->id != (uint16)-1) { vehicle_sound++; i++; - if (i >= countof(gVehicleSoundList)/*i >= RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MAX_VEHICLE_SOUNDS, uint8)*/) { + if (i >= countof(gVehicleSoundList)) { vehicle_sound_params = (rct_vehicle_sound_params*)((int)vehicle_sound_params + 10); goto label28; } @@ -344,34 +321,17 @@ void vehicle_sounds_update() if (sprite->vehicle.sound1_id == (uint8)-1) { if (vehicle_sound->sound1_id != (uint16)-1) { vehicle_sound->sound1_id = -1; -#ifdef USE_MIXER Mixer_Stop_Channel(vehicle_sound->sound1_channel); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_stop(&vehicle_sound->sound1); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif } } else { if (vehicle_sound->sound1_id == (uint16)-1) { goto label69; } if (sprite->vehicle.sound1_id != vehicle_sound->sound1_id) { -#ifdef USE_MIXER Mixer_Stop_Channel(vehicle_sound->sound1_channel); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_stop(&vehicle_sound->sound1); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif label69: vehicle_sound->sound1_id = sprite->vehicle.sound1_id; -#ifndef USE_MIXER - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_prepare(sprite->vehicle.sound1_id, &vehicle_sound->sound1, 1, RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, uint32)); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - vehicle_sound->sound1_pan = vehicle_sound_params->panx; + vehicle_sound->sound1_pan = vehicle_sound_params->pan_x; vehicle_sound->sound1_volume = volume; vehicle_sound->sound1_freq = vehicle_sound_params->frequency; uint16 frequency = vehicle_sound_params->frequency; @@ -379,40 +339,17 @@ void vehicle_sounds_update() frequency = (frequency / 2) + 4000; } uint8 looping = RCT2_ADDRESS(0x009AF51E, uint8)[2 * sprite->vehicle.sound1_id]; - int pan = vehicle_sound_params->panx; - if (!RCT2_GLOBAL(0x009AAC6D, uint8)) { - pan = 0; - } -#ifdef USE_MIXER + int pan = vehicle_sound_params->pan_x; vehicle_sound->sound1_channel = Mixer_Play_Effect(sprite->vehicle.sound1_id, looping ? MIXER_LOOP_INFINITE : MIXER_LOOP_NONE, DStoMixerVolume(volume), DStoMixerPan(pan), DStoMixerRate(frequency), 0); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_play(&vehicle_sound->sound1, looping, volume, pan, frequency); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif goto label87; } if (volume != vehicle_sound->sound1_volume) { vehicle_sound->sound1_volume = volume; -#ifdef USE_MIXER Mixer_Channel_Volume(vehicle_sound->sound1_channel, DStoMixerVolume(volume)); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_set_volume(&vehicle_sound->sound1, volume); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif } - if (vehicle_sound_params->panx != vehicle_sound->sound1_pan) { - vehicle_sound->sound1_pan = vehicle_sound_params->panx; - if (RCT2_GLOBAL(0x009AAC6D, uint8)) { -#ifdef USE_MIXER - Mixer_Channel_Pan(vehicle_sound->sound1_channel, DStoMixerPan(vehicle_sound_params->panx)); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_set_pan(&vehicle_sound->sound1, vehicle_sound_params->panx); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - } + if (vehicle_sound_params->pan_x != vehicle_sound->sound1_pan) { + vehicle_sound->sound1_pan = vehicle_sound_params->pan_x; + Mixer_Channel_Pan(vehicle_sound->sound1_channel, DStoMixerPan(vehicle_sound_params->pan_x)); } if (!(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 3) && vehicle_sound_params->frequency != vehicle_sound->sound1_freq) { vehicle_sound->sound1_freq = vehicle_sound_params->frequency; @@ -420,13 +357,7 @@ void vehicle_sounds_update() if (RCT2_GLOBAL(0x009AF51F, uint8*)[2 * sprite->vehicle.sound1_id] & 2) { frequency = (frequency / 2) + 4000; } -#ifdef USE_MIXER Mixer_Channel_Rate(vehicle_sound->sound1_channel, DStoMixerRate(frequency)); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_set_frequency(&vehicle_sound->sound1, frequency); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif } } label87: // do sound2 stuff, screams @@ -441,34 +372,17 @@ void vehicle_sounds_update() if (sprite->vehicle.sound2_id == (uint8)-1) { if (vehicle_sound->sound2_id != (uint16)-1) { vehicle_sound->sound2_id = -1; -#ifdef USE_MIXER Mixer_Stop_Channel(vehicle_sound->sound2_channel); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_stop(&vehicle_sound->sound2); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif } } else { if (vehicle_sound->sound2_id == (uint16)-1) { goto label93; } if (sprite->vehicle.sound2_id != vehicle_sound->sound2_id) { -#ifdef USE_MIXER Mixer_Stop_Channel(vehicle_sound->sound2_channel); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_stop(&vehicle_sound->sound2); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif label93: vehicle_sound->sound2_id = sprite->vehicle.sound2_id; -#ifndef USE_MIXER - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_prepare(sprite->vehicle.sound2_id, &vehicle_sound->sound2, 1, RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, uint32)); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - vehicle_sound->sound2_pan = vehicle_sound_params->panx; + vehicle_sound->sound2_pan = vehicle_sound_params->pan_x; vehicle_sound->sound2_volume = volume; vehicle_sound->sound2_freq = vehicle_sound_params->frequency; uint16 frequency = vehicle_sound_params->frequency; @@ -480,40 +394,17 @@ void vehicle_sounds_update() frequency = 25700; } uint8 looping = RCT2_ADDRESS(0x009AF51E, uint8)[2 * sprite->vehicle.sound2_id]; - int pan = vehicle_sound_params->panx; - if (!RCT2_GLOBAL(0x009AAC6D, uint8)) { - pan = 0; - } -#ifdef USE_MIXER + int pan = vehicle_sound_params->pan_x; vehicle_sound->sound2_channel = Mixer_Play_Effect(sprite->vehicle.sound2_id, looping ? MIXER_LOOP_INFINITE : MIXER_LOOP_NONE, DStoMixerVolume(volume), DStoMixerPan(pan), DStoMixerRate(frequency), 0); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_play(&vehicle_sound->sound2, looping, volume, pan, frequency); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif goto label114; } if (volume != vehicle_sound->sound2_volume) { -#ifdef USE_MIXER Mixer_Channel_Volume(vehicle_sound->sound2_channel, DStoMixerVolume(volume)); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_set_volume(&vehicle_sound->sound2, volume); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif vehicle_sound->sound2_volume = volume; } - if (vehicle_sound_params->panx != vehicle_sound->sound2_pan) { - vehicle_sound->sound2_pan = vehicle_sound_params->panx; - if (RCT2_GLOBAL(0x009AAC6D, uint8)) { -#ifdef USE_MIXER - Mixer_Channel_Pan(vehicle_sound->sound2_channel, DStoMixerPan(vehicle_sound_params->panx)); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_set_pan(&vehicle_sound->sound2, vehicle_sound_params->panx); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - } + if (vehicle_sound_params->pan_x != vehicle_sound->sound2_pan) { + vehicle_sound->sound2_pan = vehicle_sound_params->pan_x; + Mixer_Channel_Pan(vehicle_sound->sound2_channel, DStoMixerPan(vehicle_sound_params->pan_x)); } if (!(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 3) && vehicle_sound_params->frequency != vehicle_sound->sound2_freq) { vehicle_sound->sound2_freq = vehicle_sound_params->frequency; @@ -522,14 +413,7 @@ void vehicle_sounds_update() if (frequency > 25700) { frequency = 25700; } -#ifdef USE_MIXER Mixer_Channel_Rate(vehicle_sound->sound2_channel, DStoMixerRate(frequency)); -#else - RCT2_GLOBAL(0x014241BC, uint32) = 1; - sound_set_frequency(&vehicle_sound->sound2, frequency); - RCT2_GLOBAL(0x014241BC, uint32) = 0; -#endif - } } } @@ -541,7 +425,7 @@ void vehicle_sounds_update() } /** - * + * * rct2: 0x006D4204 */ void vehicle_update_all() @@ -566,7 +450,7 @@ void vehicle_update_all() } /** - * + * * rct2: 0x006D77F2 */ static void vehicle_update(rct_vehicle *vehicle) @@ -575,7 +459,7 @@ static void vehicle_update(rct_vehicle *vehicle) } /** - * + * * rct2: 0x006D73D0 * ax: verticalG * dx: lateralG @@ -587,7 +471,7 @@ void vehicle_get_g_forces(rct_vehicle *vehicle, int *verticalG, int *lateralG) esi = (int)vehicle; RCT2_CALLFUNC_X(0x006D73D0, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - + if (verticalG != NULL) *verticalG = (sint16)(eax & 0xFFFF); if (lateralG != NULL) *lateralG = (sint16)(edx & 0xFFFF); } @@ -599,8 +483,9 @@ void vehicle_set_map_toolbar(rct_vehicle *vehicle) ride = GET_RIDE(vehicle->ride); - while (vehicle->var_01 != 0) - vehicle = &(g_sprite_list[vehicle->prev_vehicle_on_train].vehicle); + while (vehicle->is_child) { + vehicle = GET_VEHICLE(vehicle->prev_vehicle_on_ride); + } for (vehicleIndex = 0; vehicleIndex < 32; vehicleIndex++) if (ride->vehicles[vehicleIndex] == vehicle->sprite_index) @@ -624,7 +509,7 @@ rct_vehicle *vehicle_get_head(rct_vehicle *vehicle) rct_vehicle *prevVehicle; for (;;) { - prevVehicle = &(g_sprite_list[vehicle->prev_vehicle_on_train].vehicle); + prevVehicle = GET_VEHICLE(vehicle->prev_vehicle_on_ride); if (prevVehicle->next_vehicle_on_train == SPRITE_INDEX_NULL) break; @@ -634,7 +519,120 @@ rct_vehicle *vehicle_get_head(rct_vehicle *vehicle) return vehicle; } +rct_vehicle *vehicle_get_tail(rct_vehicle *vehicle) +{ + uint16 spriteIndex; + + while ((spriteIndex = vehicle->next_vehicle_on_train) != SPRITE_INDEX_NULL) { + vehicle = GET_VEHICLE(spriteIndex); + } + 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 +} + +/** + * + * rct2: 0x006DEF56 + */ +void sub_6DEF56(rct_vehicle *cableLift) +{ + RCT2_CALLPROC_X(0x006DEF56, 0, 0, 0, 0, (int)cableLift, 0, 0); +} + +rct_vehicle *cable_lift_segment_create(int rideIndex, int x, int y, int z, int direction, uint16 var_44, uint32 var_24, bool head) +{ + rct_ride *ride = GET_RIDE(rideIndex); + rct_vehicle *current = &(create_sprite(1)->vehicle); + current->sprite_identifier = SPRITE_IDENTIFIER_VEHICLE; + current->ride = rideIndex; + current->ride_subtype = 0xFF; + if (head) { + move_sprite_to_list((rct_sprite*)current, SPRITE_LINKEDLIST_OFFSET_VEHICLE); + ride->cable_lift = current->sprite_index; + } + current->is_child = head ? 0 : 1; + current->var_44 = var_44; + current->var_24 = var_24; + current->sprite_width = 10; + current->sprite_height_negative = 10; + current->sprite_height_positive = 10; + current->friction = 100; + current->num_seats = 0; + current->speed = 20; + current->acceleration = 80; + current->velocity = 0; + current->var_2C = 0; + current->var_4A = 0; + current->var_4C = 0; + current->var_4E = 0; + current->var_B5 = 0; + current->var_BA = 0; + current->var_B6 = 0; + current->var_B8 = 0; + current->sound1_id = 0xFF; + current->sound2_id = 0xFF; + current->var_C4 = 0; + current->var_C5 = 0; + current->var_C8 = 0; + current->scream_sound_id = 0xFF; + current->var_1F = 0; + current->var_20 = 0; + for (int j = 0; j < 32; j++) { + current->peep[j] = SPRITE_INDEX_NULL; + } + current->var_CD = 0; + current->sprite_direction = direction << 3; + current->track_x = x; + current->track_y = y; + + z = z * 8; + current->track_z = z; + z += RCT2_GLOBAL(0x0097D21A + (ride->type * 8), uint8); + + sprite_move(16, 16, z, (rct_sprite*)current); + current->track_type = (TRACK_ELEM_CABLE_LIFT_HILL << 2) | (current->sprite_direction >> 3); + current->var_34 = 164; + current->update_flags = VEHICLE_UPDATE_FLAG_1; + current->status = VEHICLE_STATUS_MOVING_TO_END_OF_STATION; + current->var_51 = 0; + current->num_peeps = 0; + current->next_free_seat = 0; + return current; +} + +/** + * + * rct2: 0x006DD365 + */ +bool sub_6DD365(rct_vehicle *vehicle) +{ + registers regs; + regs.esi = (int)vehicle; + + return RCT2_CALLFUNC_Y(0x006DD365, ®s) & 0x100; +} + +/** + * + * rct2: 0x006DAB4C + */ +int sub_6DAB4C(rct_vehicle *vehicle, int *outStation) +{ + registers regs; + regs.esi = (int)vehicle; + + RCT2_CALLFUNC_Y(0x006DAB4C, ®s); + + if (outStation != NULL) *outStation = regs.ebx; + return regs.eax; +} + +rct_ride_type_vehicle *vehicle_get_vehicle_entry(rct_vehicle *vehicle) +{ + rct_ride_type *rideEntry = GET_RIDE_ENTRY(vehicle->ride_subtype); + return &rideEntry->vehicles[vehicle->vehicle_type]; +} diff --git a/src/ride/vehicle.h b/src/ride/vehicle.h index 866f52cc08..1f8f175f8b 100644 --- a/src/ride/vehicle.h +++ b/src/ride/vehicle.h @@ -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 . *****************************************************************************/ @@ -29,9 +29,58 @@ typedef struct{ uint8 trim_colour; } rct_vehicle_colour; +/** + * Ride type vehicle structure. + * size: 0x65 + */ +typedef struct { + uint16 rotation_frame_mask; // 0x00 , 0x1A + uint8 var_02; // 0x02 , 0x1C + uint8 var_03; // 0x03 , 0x1D + uint32 var_04; // 0x04 , 0x1E + uint16 car_friction; // 0x08 , 0x22 + sint8 tab_height; // 0x0A , 0x24 + uint8 num_seats; // 0x0B , 0x25 + uint16 sprite_flags; // 0x0C , 0x26 + uint8 sprite_width; // 0x0E , 0x28 + uint8 sprite_height_negative; // 0x0F , 0x29 + uint8 sprite_height_positive; // 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 spinning_inertia; // 0x55 , 0x6F + uint8 spinning_friction; // 0x56 , 0x70 + uint8 pad_57[0x3]; + uint8 var_5A; // 0x5A , 0x74 + uint8 powered_acceleration; // 0x5B , 0x75 + uint8 powered_max_speed; // 0x5C , 0x76 + uint8 car_visual; // 0x5D , 0x77 + uint8 pad_5E; + uint8 draw_order; + uint8 special_frames; // 0x60 , 0x7A + sint8* peep_loading_positions; // 0x61 , 0x7B +} rct_ride_type_vehicle; + typedef struct { uint8 sprite_identifier; // 0x00 - uint8 var_01; + uint8 is_child; // 0x01 uint16 next_in_quadrant; // 0x02 uint16 next; // 0x04 uint16 previous; // 0x06 @@ -39,7 +88,7 @@ typedef struct { // 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 @@ -53,56 +102,82 @@ typedef struct { sint16 sprite_bottom; // 0x1C uint8 sprite_direction; // 0x1E uint8 var_1F; - uint8 pad_20[0x08]; + uint8 var_20; + uint8 pad_21[3]; + uint32 var_24; sint32 velocity; // 0x28 - uint8 pad_2C[0x04]; + uint32 var_2C; uint8 ride; // 0x30 uint8 vehicle_type; // 0x31 - uint8 pad_32[0x02]; + rct_vehicle_colour colours; // 0x32 uint16 var_34; - sint16 var_36; - //x related - uint16 var_38; - // y related - uint16 var_3A; - // z related - uint16 var_3C; + union { + sint16 track_direction; // 0x36 (0000 0000 0000 0011) + sint16 track_type; // 0x36 (0000 0011 1111 1100) + }; + uint16 track_x; // 0x38 + uint16 track_y; // 0x3A + uint16 track_z; // 0x3C uint16 next_vehicle_on_train; // 0x3E - uint16 prev_vehicle_on_train; // 0x40 - uint16 pad_42; + + // The previous vehicle on the same train or the last vehicle on the previous or only train. + uint16 prev_vehicle_on_ride; // 0x40 + + // The next vehicle on the same train or the first vehicle on the next or only train + uint16 next_vehicle_on_ride; // 0x42 + uint16 var_44; - uint16 var_46; - uint16 var_48; - uint8 pad_4A; + uint16 friction; // 0x46 + uint16 update_flags; // 0x48 + uint8 var_4A; uint8 current_station; // 0x4B - uint8 pad_4C[0x4]; + uint16 var_4C; + uint16 var_4E; uint8 status; // 0x50 uint8 var_51; uint16 peep[32]; // 0x52 uint8 peep_tshirt_colours[32]; // 0x92 uint8 num_seats; // 0xB2 uint8 num_peeps; // 0xB3 - uint8 next_free_seat; // 0xB4 - uint8 pad_B5[0x06]; + uint8 next_free_seat; // 0xB4 + uint8 var_B5; + uint16 var_B6; + uint16 var_B8; + uint8 var_BA; uint8 sound1_id; // 0xBB uint8 sound1_volume; // 0xBC uint8 sound2_id; // 0xBD uint8 sound2_volume; // 0xBE sint8 var_BF; - uint8 pad_C0[0x02]; + uint8 pad_C0[2]; uint8 speed; // 0xC2 - uint8 pad_C3[0x09]; - uint8 var_CC; + uint8 acceleration; // 0xC3 + uint8 var_C4; + uint8 var_C5; + uint8 pad_C6[2]; + uint32 var_C8; + uint8 scream_sound_id; // 0xCC uint8 var_CD; union { uint8 var_CE; uint8 num_laps; // 0xCE }; - uint8 pad_CF[0x06]; + uint8 pad_CF[0x03]; + sint8 var_D2; + uint8 var_D3; + uint8 var_D4; uint8 var_D5; uint8 ride_subtype; // 0xD6 + uint8 colours_extended; // 0xD7 + uint8 var_D8; + uint8 var_D9; } rct_vehicle; +typedef struct { + rct_vehicle *head; + rct_vehicle *tail; +} train_ref; + enum { VEHICLE_STATUS_MOVING_TO_END_OF_STATION, VEHICLE_STATUS_WAITING_FOR_PASSENGERS, @@ -137,6 +212,59 @@ enum { VEHICLE_STATUS_STOPPED_BY_BLOCK_BRAKES }; +enum{ + VEHICLE_UPDATE_FLAG_0 = (1 << 0), + VEHICLE_UPDATE_FLAG_1 = (1 << 1), + VEHICLE_UPDATE_FLAG_WAIT_ON_ADJACENT = (1 << 2), + VEHICLE_UPDATE_FLAG_3 = (1 << 3), + VEHICLE_UPDATE_FLAG_TRAIN_READY_DEPART = (1 << 4), + VEHICLE_UPDATE_FLAG_TESTING = (1 << 5), + VEHICLE_UPDATE_FLAG_6 = (1 << 6), + VEHICLE_UPDATE_FLAG_7 = (1 << 7), + VEHICLE_UPDATE_FLAG_BROKEN_CAR = (1 << 8), + VEHICLE_UPDATE_FLAG_BROKEN_TRAIN = (1 << 9), + VEHICLE_UPDATE_FLAG_10 = (1 << 10), + VEHICLE_UPDATE_FLAG_11 = (1 << 11), + VEHICLE_UPDATE_FLAG_12 = (1 << 12), + VEHICLE_UPDATE_FLAG_13 = (1 << 13), + VEHICLE_UPDATE_FLAG_14 = (1 << 14), + VEHICLE_UPDATE_FLAG_15 = (1 << 15) +}; + +enum { + VEHICLE_SPRITE_FLAG_FLAT = (1 << 0), + VEHICLE_SPRITE_FLAG_GENTLE_SLOPES = (1 << 1), + VEHICLE_SPRITE_FLAG_STEEP_SLOPES = (1 << 2), + VEHICLE_SPRITE_FLAG_VERTICAL_SLOPES = (1 << 3), + VEHICLE_SPRITE_FLAG_DIAGONAL_SLOPES = (1 << 4), + VEHICLE_SPRITE_FLAG_FLAT_BANKED = (1 << 5), + VEHICLE_SPRITE_FLAG_INLINE_TWISTS = (1 << 6), + VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_BANKED_TRANSITIONS = (1 << 7), + VEHICLE_SPRITE_FLAG_DIAGONAL_GENTLE_SLOPE_BANKED_TRANSITIONS = (1 << 8), + VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TRANSITIONS = (1 << 9), + VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TURNS = (1 << 10), + VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_WHILE_BANKED_TRANSITIONS = (1 << 11), + VEHICLE_SPRITE_FLAG_CORKSCREWS = (1 << 12), + VEHICLE_SPRITE_FLAG_RESTRAINT_ANIMATION = (1 << 13), + VEHICLE_SPRITE_FLAG_14 = (1 << 14), + VEHICLE_SPRITE_FLAG_15 = (1 << 15), +}; + +enum { + VEHICLE_VISUAL_DEFAULT, + VEHICLE_VISUAL_FLAT_RIDE_OR_CAR_RIDE, + VEHICLE_VISUAL_LAUNCHED_FREEFALL, + VEHICLE_VISUAL_OBSERVATION_TOWER, + VEHICLE_VISUAL_RIVER_RAPIDS, + VEHICLE_VISUAL_MINI_GOLF_PLAYER, + VEHICLE_VISUAL_MINI_GOLF_BALL, + VEHICLE_VISUAL_REVERSER, + VEHICLE_VISUAL_SPLASH_BOATS_OR_WATER_COASTER, + VEHICLE_VISUAL_ROTO_DROP, + VEHICLE_VISUAL_VIRGINIA_REEL = 15, + VEHICLE_VISUAL_SUBMARINE +}; + #define VEHICLE_SEAT_PAIR_FLAG 0x80 #define VEHICLE_SEAT_NUM_MASK 0x7F @@ -148,6 +276,11 @@ 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); +void sub_6DEF56(rct_vehicle *cableLift); +rct_vehicle *cable_lift_segment_create(int rideIndex, int x, int y, int z, int direction, uint16 var_44, uint32 var_24, bool head); +bool sub_6DD365(rct_vehicle *vehicle); +int sub_6DAB4C(rct_vehicle *vehicle, int *outStation); +rct_ride_type_vehicle *vehicle_get_vehicle_entry(rct_vehicle *vehicle); /** Helper macro until rides are stored in this module. */ #define GET_VEHICLE(sprite_index) &(g_sprite_list[sprite_index].vehicle) diff --git a/src/scenario.c b/src/scenario.c index 01fa21a94c..8a6cd24f97 100644 --- a/src/scenario.c +++ b/src/scenario.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,6 +21,7 @@ #include "addresses.h" #include "config.h" #include "game.h" +#include "world/climate.h" #include "interface/viewport.h" #include "localisation/date.h" #include "localisation/localisation.h" @@ -30,6 +31,7 @@ #include "management/research.h" #include "management/news_item.h" #include "object.h" +#include "openrct2.h" #include "peep/staff.h" #include "platform/platform.h" #include "ride/ride.h" @@ -44,9 +46,10 @@ #include "world/water.h" static char _scenarioPath[MAX_PATH]; -static const char *_scenarioFileName; +static const char *_scenarioFileName = ""; -char gScenarioSaveName[MAX_PATH]; +char gScenarioSavePath[MAX_PATH]; +int gFirstTimeSave = 1; static int scenario_create_ducks(); static void scenario_objective_check(); @@ -57,33 +60,55 @@ static void scenario_objective_check(); */ int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *info) { - FILE *file; + SDL_RWops* rw; log_verbose("loading scenario details, %s", path); - file = fopen(path, "rb"); - if (file != NULL) { + rw = SDL_RWFromFile(path, "rb"); + if (rw != NULL) { // Read first chunk - sawyercoding_read_chunk(file, (uint8*)header); + sawyercoding_read_chunk(rw, (uint8*)header); if (header->type == S6_TYPE_SCENARIO) { // Read second chunk - sawyercoding_read_chunk(file, (uint8*)info); - fclose(file); + sawyercoding_read_chunk(rw, (uint8*)info); + SDL_RWclose(rw); RCT2_GLOBAL(0x009AA00C, uint8) = 0; - // Checks for a scenario string object (possibly for localisation) - if ((info->entry.flags & 0xFF) != 255) { - if (object_get_scenario_text(&info->entry)) { - 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(); + // Get filename + utf8 filename[MAX_PATH]; + const char *temp_filename = path_get_filename(path); + int len = strnlen(temp_filename, MAX_PATH); + safe_strncpy(filename, temp_filename, MAX_PATH); + if (len == MAX_PATH) + { + filename[MAX_PATH - 1] = '\0'; + log_warning("truncated string %s", filename); + } + path_remove_extension(filename); + + rct_string_id localisedStringIds[3]; + if (language_get_localised_scenario_strings(filename, localisedStringIds)) { + if (localisedStringIds[0] != (rct_string_id)STR_NONE) { + safe_strncpy(info->name, language_get_string(localisedStringIds[0]), 64); + } + if (localisedStringIds[2] != (rct_string_id)STR_NONE) { + safe_strncpy(info->details, language_get_string(localisedStringIds[2]), 256); + } + } else { + // Checks for a scenario string object (possibly for localisation) + if ((info->entry.flags & 0xFF) != 255) { + if (object_get_scenario_text(&info->entry)) { + 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(); + } } } return 1; } - fclose(file); + SDL_RWclose(rw); } log_error("invalid scenario, %s", path); @@ -93,7 +118,7 @@ int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *in } /** - * + * * rct2: 0x00676053 * scenario (ebx) */ @@ -101,15 +126,15 @@ int scenario_load(const char *path) { log_verbose("loading scenario, %s", path); - FILE *file; + SDL_RWops* rw; int i, j; rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4; rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; - file = fopen(path, "rb"); - if (file != NULL) { - if (!sawyercoding_validate_checksum(file)) { - fclose(file); + rw = SDL_RWFromFile(path, "rb"); + if (rw != NULL) { + if (!sawyercoding_validate_checksum(rw) && !gConfigGeneral.allow_loading_with_incorrect_checksum) { + SDL_RWclose(rw); RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255; RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA; @@ -118,57 +143,57 @@ int scenario_load(const char *path) } // Read first chunk - sawyercoding_read_chunk(file, (uint8*)s6Header); + sawyercoding_read_chunk(rw, (uint8*)s6Header); if (s6Header->type == S6_TYPE_SCENARIO) { // Read second chunk - sawyercoding_read_chunk(file, (uint8*)s6Info); + sawyercoding_read_chunk(rw, (uint8*)s6Info); // Read packed objects if (s6Header->num_packed_objects > 0) { j = 0; for (i = 0; i < s6Header->num_packed_objects; i++) - j += object_load_packed(file); + j += object_load_packed(rw); if (j > 0) object_list_load(); } - uint8 load_success = object_read_and_load_entries(file); + uint8 load_success = object_read_and_load_entries(rw); // Read flags (16 bytes). Loads: // RCT2_ADDRESS_CURRENT_MONTH_YEAR // RCT2_ADDRESS_CURRENT_MONTH_TICKS // RCT2_ADDRESS_SCENARIO_TICKS - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR); // Read map elements memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, MAX_MAP_ELEMENTS * sizeof(rct_map_element)); - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS); // Read game data, including sprites - sawyercoding_read_chunk(file, (uint8*)0x010E63B8); + sawyercoding_read_chunk(rw, (uint8*)0x010E63B8); // Read number of guests in park and something else - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_GUESTS_IN_PARK); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_GUESTS_IN_PARK); // Read ? - sawyercoding_read_chunk(file, (uint8*)0x01357BC8); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_LAST_GUESTS_IN_PARK); // Read park rating - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_PARK_RATING); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_PARK_RATING); // Read ? - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES); // Read ? - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_EXPENDITURE); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_EXPENDITURE); // Read ? - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_PARK_VALUE); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_PARK_VALUE); // Read more game data, including research items and rides - sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_COMPLETED_COMPANY_VALUE); + sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_COMPLETED_COMPANY_VALUE); - fclose(file); + SDL_RWclose(rw); if (!load_success){ log_error("failed to load all entries."); set_load_objects_fail_reason(); @@ -178,10 +203,14 @@ int scenario_load(const char *path) reset_loaded_objects(); map_update_tile_pointers(); reset_0x69EBE4(); + openrct2_reset_object_tween_locations(); + game_convert_strings_to_utf8(); + game_fix_save_vars(); // OpenRCT2 fix broken save games + return 1; } - fclose(file); + SDL_RWclose(rw); } log_error("failed to find scenario file."); @@ -191,7 +220,7 @@ int scenario_load(const char *path) } /** - * + * * rct2: 0x00678282 * scenario (ebx) */ @@ -205,23 +234,32 @@ int scenario_load_and_play(const rct_scenario_basic *scenario) int scenario_load_and_play_from_path(const char *path) { - rct_window *mainWindow; - rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; - - // Create the scenario pseduo-random seeds using the current time - uint32 srand0, srand1; - srand0 = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, uint32) ^ platform_get_ticks(); - srand1 = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_1, uint32) ^ platform_get_ticks(); - window_close_construction_windows(); if (!scenario_load(path)) return 0; - strcpy(_scenarioPath, path); + int len = strnlen(path, MAX_PATH) + 1; + safe_strncpy(_scenarioPath, path, len); + if (len - 1 == MAX_PATH) + { + _scenarioPath[MAX_PATH - 1] = '\0'; + log_warning("truncated string %s", _scenarioPath); + } _scenarioFileName = path_get_filename(_scenarioPath); + gFirstTimeSave = 1; + log_verbose("starting scenario, %s", path); + scenario_begin(); + + return 1; +} + +void scenario_begin() +{ + rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; + rct_window *mainWindow; RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_PLAYING; viewport_init_all(); @@ -232,9 +270,9 @@ int scenario_load_and_play_from_path(const char *path) mainWindow->saved_view_x = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, sint16); mainWindow->saved_view_y = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, sint16); - uint8 _cl = (RCT2_GLOBAL(0x0138869E, sint16) & 0xFF) - mainWindow->viewport->zoom; - mainWindow->viewport->zoom = RCT2_GLOBAL(0x0138869E, sint16) & 0xFF; - *((char*)(&RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, sint32))) = RCT2_GLOBAL(0x0138869E, sint16) >> 8; + uint8 _cl = (RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, sint16) & 0xFF) - mainWindow->viewport->zoom; + mainWindow->viewport->zoom = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, sint16) & 0xFF; + *((char*)(&RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, sint32))) = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, sint16) >> 8; if (_cl != 0) { if (_cl < 0) { _cl = -_cl; @@ -253,10 +291,10 @@ int scenario_load_and_play_from_path(const char *path) window_new_ride_init_vars(); // Set the scenario pseduo-random seeds - RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, sint32) = srand0; - RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_1, sint32) = srand1; + RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, sint32) ^= platform_get_ticks(); + RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_1, sint32) ^= platform_get_ticks(); - RCT2_GLOBAL(0x009DEB7C, sint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_UPDATE_TICKS, sint16) = 0; RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, sint32) &= 0xFFFFF7FF; if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, sint32) & PARK_FLAGS_NO_MONEY_SCENARIO) RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, sint32) |= PARK_FLAGS_NO_MONEY; @@ -269,37 +307,63 @@ int scenario_load_and_play_from_path(const char *path) RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, sint16) = calculate_park_rating(); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_VALUE, money32) = calculate_park_value(); 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)); + RCT2_GLOBAL(0x013587D0, money32) = RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32) - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32) = ENCRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, sint32)); - sub_69E869(); // (loan related) + finance_update_loan_hash(); - strcpy((char*)RCT2_ADDRESS_SCENARIO_DETAILS, s6Info->details); - strcpy((char*)RCT2_ADDRESS_SCENARIO_NAME, s6Info->name); + safe_strncpy((char*)RCT2_ADDRESS_SCENARIO_DETAILS, s6Info->details, 256); + safe_strncpy((char*)RCT2_ADDRESS_SCENARIO_NAME, s6Info->name, 64); - rct_stex_entry* stex = g_stexEntries[0]; - if ((int)stex != -1) { - char *buffer = (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER; + { + // Get filename + utf8 filename[MAX_PATH]; + safe_strncpy(filename, _scenarioFileName, sizeof(filename)); + path_remove_extension(filename); - // Set localised park name - format_string(buffer, stex->park_name, 0); - park_set_name(buffer); + rct_string_id localisedStringIds[3]; + if (language_get_localised_scenario_strings(filename, localisedStringIds)) { + if (localisedStringIds[0] != (rct_string_id)STR_NONE) { + safe_strncpy((char*)RCT2_ADDRESS_SCENARIO_NAME, language_get_string(localisedStringIds[0]), 32); + } + if (localisedStringIds[1] != (rct_string_id)STR_NONE) { + park_set_name(language_get_string(localisedStringIds[1])); + } + if (localisedStringIds[2] != (rct_string_id)STR_NONE) { + safe_strncpy((char*)RCT2_ADDRESS_SCENARIO_DETAILS, language_get_string(localisedStringIds[2]), 256); + } + } else { + rct_stex_entry* stex = g_stexEntries[0]; + if ((int)stex != -1) { + char *buffer = (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER; - // 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 localised park name + format_string(buffer, stex->park_name, 0); + park_set_name(buffer); - // 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 localised scenario name + format_string(buffer, stex->scenario_name, 0); + safe_strncpy((char*)RCT2_ADDRESS_SCENARIO_NAME, buffer, 31); + ((char*)RCT2_ADDRESS_SCENARIO_NAME)[31] = '\0'; + + // Set localised scenario details + format_string(buffer, stex->details, 0); + safe_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); + char parkName[128]; + format_string(parkName, RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id), (void*)RCT2_ADDRESS_PARK_NAME_ARGS); + + platform_get_user_directory(gScenarioSavePath, "save"); + strncat(gScenarioSavePath, parkName, sizeof(gScenarioSavePath) - strlen(gScenarioSavePath) - 1); + strncat(gScenarioSavePath, ".sv6", sizeof(gScenarioSavePath) - strlen(gScenarioSavePath) - 1); + strcpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, (char*)RCT2_ADDRESS_SAVED_GAMES_PATH); - strcpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2 + strlen((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2), gScenarioSaveName); + strcpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2 + strlen((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2), gScenarioSavePath); strcat((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, ".SV6"); memset((void*)0x001357848, 0, 56); @@ -311,7 +375,7 @@ int scenario_load_and_play_from_path(const char *path) RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_ADMISSIONS, uint32) = 0; RCT2_GLOBAL(RCT2_ADDRESS_INCOME_FROM_ADMISSIONS, uint32) = 0; RCT2_GLOBAL(0x013587D8, uint16) = 63; - sub_69E869(); // (loan related, called above already) + finance_update_loan_hash(); park_reset_history(); finance_reset_history(); award_reset(); @@ -335,16 +399,15 @@ int scenario_load_and_play_from_path(const char *path) load_palette(); gfx_invalidate_screen(); - RCT2_GLOBAL(0x009DEA66, uint16) = 0; - RCT2_GLOBAL(0x009DEA5C, uint16) = 62000; // (doesn't appear to ever be read) - return 1; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, uint16) = 0; + gGameSpeed = 1; } void scenario_end() { rct_window* w; window_close_by_class(WC_DROPDOWN); - + for (w = g_window_list; w < RCT2_GLOBAL(RCT2_ADDRESS_NEW_WINDOW_PTR, rct_window*); w++){ if (!(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))) window_close(w); @@ -377,7 +440,7 @@ void scenario_success() int i; rct_scenario_basic* scenario; uint32 current_val = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_COMPANY_VALUE, uint32); - + RCT2_GLOBAL(RCT2_ADDRESS_COMPLETED_COMPANY_VALUE, uint32) = current_val; peep_applause(); @@ -411,21 +474,21 @@ void scenario_success_submit_name(const char *name) int i; rct_scenario_basic* scenario; uint32 scenarioWinCompanyValue; - + for (i = 0; i < gScenarioListCount; i++) { scenario = &gScenarioList[i]; 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); + safe_strncpy(scenario->completed_by, name, 64); + safe_strncpy((char*)0x013587D8, name, 32); scenario_scores_save(); } break; } } - + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_SCENARIO_COMPLETE_NAME_INPUT; } @@ -435,16 +498,16 @@ void scenario_success_submit_name(const char *name) **/ void scenario_entrance_fee_too_high_check() { - uint16 x, y; + uint16 x = 0, y = 0; uint16 totalRideValue = RCT2_GLOBAL(RCT2_TOTAL_RIDE_VALUE, uint16); uint16 park_entrance_fee = RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, uint16); int max_fee = totalRideValue + (totalRideValue / 2); uint32 game_flags = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32), packed_xy; - if ((game_flags & PARK_FLAGS_PARK_OPEN) && park_entrance_fee > max_fee) { - for (int i = 0; RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[i] != SPRITE_LOCATION_NULL; ++i) { - x = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[i] + 16; - y = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, uint16)[i] + 16; + if ((game_flags & PARK_FLAGS_PARK_OPEN) && !(game_flags & PARK_FLAGS_NO_MONEY) && park_entrance_fee > max_fee) { + for (int i = 0; RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[i] != SPRITE_LOCATION_NULL; i++) { + x = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[i] + 16; + y = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, sint16)[i] + 16; } packed_xy = (y << 16) | x; @@ -452,34 +515,38 @@ void scenario_entrance_fee_too_high_check() } } -static void scenario_autosave_check() +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); + // Timestamp in milliseconds + static uint32 last_save = 0; + bool shouldSave = 0; + // Milliseconds since last save + uint32_t time_since_save = SDL_GetTicks() - last_save; + switch (gConfigGeneral.autosave_frequency) { - case AUTOSAVE_EVERY_WEEK: - shouldSave = (next_month_tick % 0x4000 == 0); + case AUTOSAVE_EVERY_MINUTE: + shouldSave = time_since_save >= 1 * 60 * 1000; break; - case AUTOSAVE_EVERY_2_WEEKS: - shouldSave = (next_month_tick % 0x8000 == 0); + case AUTOSAVE_EVERY_5MINUTES: + shouldSave = time_since_save >= 5 * 60 * 1000; break; - case AUTOSAVE_EVERY_MONTH: - shouldSave = (next_month_tick >= 0x10000); + case AUTOSAVE_EVERY_15MINUTES: + shouldSave = time_since_save >= 15 * 60 * 1000; break; - case AUTOSAVE_EVERY_4_MONTHS: - if (next_month_tick >= 0x10000) - shouldSave = (((month + 1) & 3) == 0); + case AUTOSAVE_EVERY_30MINUTES: + shouldSave = time_since_save >= 30 * 60 * 1000; break; - case AUTOSAVE_EVERY_YEAR: - if (next_month_tick >= 0x10000) - shouldSave = (((month + 1) & 7) == 0); + case AUTOSAVE_EVERY_HOUR: + shouldSave = time_since_save >= 60 * 60 * 1000; break; } - if (shouldSave) + if (shouldSave) { + last_save = SDL_GetTicks(); game_autosave(); + } } static void scenario_day_update() @@ -541,36 +608,57 @@ static void scenario_month_update() award_update_all(); } +static void scenario_update_daynight_cycle() +{ + gDayNightCycle = 0; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) != SCREEN_FLAGS_PLAYING) return; + if (!gConfigGeneral.day_night_cycle) return; + + float monthFraction = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16) / (float)0x10000; + if (monthFraction < (1 / 8.0f)) { + gDayNightCycle = 0.0f; + } else if (monthFraction < (3 / 8.0f)) { + gDayNightCycle = (monthFraction - (1 / 8.0f)) / (2 / 8.0f); + } else if (monthFraction < (5 / 8.0f)) { + gDayNightCycle = 1.0f; + } else if (monthFraction < (7 / 8.0f)) { + gDayNightCycle = 1.0f - ((monthFraction - (5 / 8.0f)) / (2 / 8.0f)); + } else { + gDayNightCycle = 0.0f; + } +} + /* * Scenario and finance related update iteration. * rct2: 0x006C44B1 **/ void scenario_update() { - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & ~SCREEN_FLAGS_PLAYING) - return; + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & ~SCREEN_FLAGS_PLAYING)) { + 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]; - 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]; + if ((currentDaysInMonth * nextMonthTick) >> 16 != (currentDaysInMonth * currentMonthTick) >> 16) { + scenario_day_update(); + } + if (nextMonthTick % 0x4000 == 0) { + scenario_week_update(); + } + if (nextMonthTick % 0x8000 == 0) { + scenario_fortnight_update(); + } - 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(); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16) = (uint16)nextMonthTick; + if (nextMonthTick >= 0x10000) { + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16)++; + scenario_month_update(); + } } - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16) = (uint16)nextMonthTick; - if (nextMonthTick >= 0x10000) { - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16)++; - scenario_month_update(); - } + scenario_update_daynight_cycle(); } /** @@ -634,11 +722,30 @@ static int scenario_create_ducks() */ unsigned int scenario_rand() { +#if DEBUG_DESYNC + if (!gInUpdateCode) { + log_warning("scenario_rand called from outside game update"); + assert(false); + } +#endif + int eax = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, uint32); RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_0, uint32) += ror32(RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_1, uint32) ^ 0x1234567F, 7); return RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_SRAND_1, uint32) = ror32(eax, 3); } +unsigned int scenario_rand_max(unsigned int max) +{ + if (max < 2) return 0; + if ((max & (max - 1)) == 0) + return scenario_rand() & (max - 1); + unsigned int rand, cap = ~((unsigned int)0) - (~((unsigned int)0) % max) - 1; + do { + rand = scenario_rand(); + } while (rand > cap); + return rand % max; +} + /** * Prepare rides, for the finish five rollercoasters objective. * rct2: 0x006788F7 @@ -685,8 +792,8 @@ int scenario_prepare_for_save() 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)); - + safe_strncpy(s6Info->name, buffer, sizeof(s6Info->name)); + memcpy(&s6Info->entry, &object_entry_groups[OBJECT_TYPE_SCENARIO_TEXT].entries[0], sizeof(rct_object_entry)); } @@ -703,6 +810,9 @@ int scenario_prepare_for_save() if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) == OBJECTIVE_GUESTS_AND_RATING) RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_PARK_OPEN; + // Fix #2385: saved scenarios did not initialise temperatures to selected climate + climate_reset(RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, uint8)); + return 1; } @@ -716,7 +826,7 @@ int scenario_get_num_packed_objects_to_write() rct_object_entry_extended *entry = (rct_object_entry_extended*)0x00F3F03C; for (i = 0; i < 721; i++, entry++) { - if (RCT2_ADDRESS(0x009ACFA4, uint32)[i] == 0xFFFFFFFF || (entry->flags & 0xF0)) + if (GET_RIDE_ENTRY(i) == (void *)0xFFFFFFFF || (entry->flags & 0xF0)) continue; count++; @@ -729,15 +839,15 @@ int scenario_get_num_packed_objects_to_write() * * rct2: 0x006AA26E */ -int scenario_write_packed_objects(FILE *file) +int scenario_write_packed_objects(SDL_RWops* rw) { int i; rct_object_entry_extended *entry = (rct_object_entry_extended*)0x00F3F03C; for (i = 0; i < 721; i++, entry++) { - if (RCT2_ADDRESS(0x009ACFA4, uint32)[i] == 0xFFFFFFFF || (entry->flags & 0xF0)) + if (GET_RIDE_ENTRY(i) == (void *)0xFFFFFFFF || (entry->flags & 0xF0)) continue; - if (!write_object_file(file, (rct_object_entry*)entry)) + if (!write_object_file(rw, (rct_object_entry*)entry)) return 0; } @@ -750,7 +860,7 @@ int scenario_write_packed_objects(FILE *file) */ int scenario_write_available_objects(FILE *file) { - char *buffer, *dstBuffer; + uint8 *buffer, *dstBuffer; int i, encodedLength; sawyercoding_chunk_header chunkHeader; @@ -759,19 +869,26 @@ int scenario_write_available_objects(FILE *file) // Initialise buffers buffer = malloc(bufferLength); - dstBuffer = malloc(bufferLength + sizeof(sawyercoding_chunk_header)); - if (buffer == NULL || dstBuffer == NULL) + if (buffer == NULL) { + log_error("out of memory"); return 0; + } + dstBuffer = malloc(bufferLength + sizeof(sawyercoding_chunk_header)); + if (dstBuffer == NULL) { + free(buffer); + log_error("out of memory"); + return 0; + } // Write entries rct_object_entry_extended *srcEntry = (rct_object_entry_extended*)0x00F3F03C; rct_object_entry *dstEntry = (rct_object_entry*)buffer; for (i = 0; i < 721; i++) { - if (RCT2_ADDRESS(0x009ACFA4, uint32)[i] == 0xFFFFFFFF) + if (GET_RIDE_ENTRY(i) == (void *)0xFFFFFFFF) memset(dstEntry, 0xFF, sizeof(rct_object_entry)); else *dstEntry = *((rct_object_entry*)srcEntry); - + srcEntry++; dstEntry++; } @@ -802,7 +919,7 @@ static void sub_674BCF() 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); + safe_strncpy(dst, src, 128); } else { *dst = 0; } @@ -812,7 +929,7 @@ static void sub_674BCF() /** * 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) +static void scenario_fix_ghosts(rct_s6_data *s6) { // Remove all ghost elements size_t mapElementTotalSize = MAX_MAP_ELEMENTS * sizeof(rct_map_element); @@ -862,21 +979,16 @@ static scenario_fix_ghosts(rct_s6_data *s6) * rct2: 0x006754F5 * @param flags bit 0: pack objects, 1: save as scenario */ -int scenario_save(char *path, int flags) +int scenario_save(SDL_RWops* rw, int flags) { 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); + log_verbose("saving scenario"); else - log_verbose("saving game, %s", path); + log_verbose("saving game"); if (!(flags & 0x80000000)) @@ -896,7 +1008,7 @@ int scenario_save(char *path, int flags) viewX = viewport->view_width / 2 + viewport->view_x; viewY = viewport->view_height / 2 + viewport->view_y; viewZoom = viewport->zoom; - viewRotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + viewRotation = get_current_rotation(); } else { viewX = 0; viewY = 0; @@ -918,10 +1030,82 @@ int scenario_save(char *path, int flags) 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) { + if (GET_RIDE_ENTRY(i) == (void *)0xFFFFFFFF) { + memset(&s6->objects[i], 0xFF, sizeof(rct_object_entry)); + } else { + s6->objects[i] = *((rct_object_entry*)entry); + } + } + + memcpy(&s6->elapsed_months, (void*)0x00F663A8, 16); + memcpy(s6->map_elements, (void*)0x00F663B8, 0x180000); + memcpy(&s6->dword_010E63B8, (void*)0x010E63B8, 0x2E8570); + + safe_strncpy(s6->scenario_filename, _scenarioFileName, sizeof(s6->scenario_filename)); + + scenario_fix_ghosts(s6); + game_convert_strings_to_rct2(s6); + scenario_save_s6(rw, s6); + + free(s6); + + if (!(flags & 0x80000000)) + reset_loaded_objects(); + + gfx_invalidate_screen(); + if (!(flags & 0x80000000)) + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, uint16) = 0; + return 1; +} + +// Save game state without modifying any of the state for multiplayer +int scenario_save_network(SDL_RWops* rw) +{ + rct_window *w; + rct_viewport *viewport; + int viewX, viewY, viewZoom, viewRotation; + + /*map_reorganise_elements(); + reset_0x69EBE4(); + sprite_clear_all_unused(); + sub_677552(); + sub_674BCF();*/ + + // Set saved view + w = window_get_main(); + if (w != NULL) { + viewport = w->viewport; + + viewX = viewport->view_width / 2 + viewport->view_x; + viewY = viewport->view_height / 2 + viewport->view_y; + viewZoom = viewport->zoom; + viewRotation = get_current_rotation(); + } else { + viewX = 0; + viewY = 0; + viewZoom = 0; + viewRotation = 0; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, uint16) = viewX; + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, uint16) = viewY; + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16) = viewZoom | (viewRotation << 8); + + // Prepare S6 + rct_s6_data *s6 = malloc(sizeof(rct_s6_data)); + s6->header.type = S6_TYPE_SAVEDGAME; + s6->header.num_packed_objects = scenario_get_num_packed_objects_to_write(); + s6->header.version = S6_RCT2_VERSION; + s6->header.magic_number = S6_MAGIC_NUMBER; + + memcpy(&s6->info, (rct_s6_info*)0x0141F570, sizeof(rct_s6_info)); + + for (int i = 0; i < 721; i++) { + rct_object_entry_extended *entry = &(RCT2_ADDRESS(0x00F3F03C, rct_object_entry_extended)[i]); + + if (GET_RIDE_ENTRY(i) == (void *)0xFFFFFFFF) { memset(&s6->objects[i], 0xFF, sizeof(rct_object_entry)); } else { s6->objects[i] = *((rct_object_entry*)entry); @@ -933,37 +1117,28 @@ int scenario_save(char *path, int flags) memcpy(&s6->dword_010E63B8, (void*)0x010E63B8, 0x2E8570); scenario_fix_ghosts(s6); - scenario_save_s6(path, s6); + scenario_save_s6(rw, s6); free(s6); - if (!(flags & 0x80000000)) - reset_loaded_objects(); + // Write other data not in normal save files + SDL_WriteLE32(rw, RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint32)); gfx_invalidate_screen(); - RCT2_GLOBAL(0x009DEA66, uint16) = 0; return 1; } -bool scenario_save_s6(char *path, rct_s6_data *s6) +bool scenario_save_s6(SDL_RWops* rw, rct_s6_data *s6) { - FILE *file; - char *buffer; + uint8 *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 false; - } - buffer = malloc(0x600000); if (buffer == NULL) { log_error("Unable to allocate enough space for a write buffer."); - fclose(file); return false; } @@ -971,21 +1146,20 @@ bool scenario_save_s6(char *path, rct_s6_data *s6) chunkHeader.encoding = CHUNK_ENCODING_ROTATE; chunkHeader.length = sizeof(rct_s6_header); encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->header, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 1: Write scenario info chunk if (s6->header.type == S6_TYPE_SCENARIO) { chunkHeader.encoding = CHUNK_ENCODING_ROTATE; chunkHeader.length = sizeof(rct_s6_info); encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->info, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); } // 2: Write packed objects if (s6->header.num_packed_objects > 0) { - if (!scenario_write_packed_objects(file)) { + if (!scenario_write_packed_objects(rw)) { free(buffer); - fclose(file); return false; } } @@ -994,92 +1168,91 @@ bool scenario_save_s6(char *path, rct_s6_data *s6) 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); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 4: Misc fields (data, rand...) chunk chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 16; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->elapsed_months, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 5: Map elements + sprites and other fields chunk chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 0x180000; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)s6->map_elements, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); if (s6->header.type == S6_TYPE_SCENARIO) { // 6: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 0x27104C; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->dword_010E63B8, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 7: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 4; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->guests_in_park, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 8: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 8; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->last_guests_in_park, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 9: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 2; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->park_rating, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 10: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 1082; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->active_research_types, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 11: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 16; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->current_expenditure, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 12: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 4; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->park_value, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); // 13: chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 0x761E8; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->completed_company_value, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); } else { // 6: Everything else... chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED; chunkHeader.length = 0x2E8570; encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->dword_010E63B8, chunkHeader); - fwrite(buffer, encodedLength, 1, file); + SDL_RWwrite(rw, buffer, encodedLength, 1); } free(buffer); // Determine number of bytes written - fileSize = ftell(file); - fseek(file, 0, SEEK_SET); + fileSize = (long)SDL_RWtell(rw); + SDL_RWseek(rw, 0, RW_SEEK_SET); // Read all written bytes back into a single buffer buffer = malloc(fileSize); - fread(buffer, fileSize, 1, file); + SDL_RWread(rw, buffer, fileSize, 1); checksum = sawyercoding_calculate_checksum(buffer, fileSize); free(buffer); // Append the checksum - fseek(file, fileSize, SEEK_SET); - fwrite(&checksum, sizeof(uint32), 1, file); - fclose(file); + SDL_RWseek(rw, fileSize, RW_SEEK_SET); + SDL_RWwrite(rw, &checksum, sizeof(uint32), 1); return true; } @@ -1169,10 +1342,9 @@ static void scenario_objective_check_guests_and_rating() 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(); + 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() @@ -1306,4 +1478,4 @@ static void scenario_objective_check() scenario_objective_check_monthly_food_income(); break; } -} \ No newline at end of file +} diff --git a/src/scenario.h b/src/scenario.h index b9adcdf8ee..4aed2a22e9 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -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 . *****************************************************************************/ @@ -49,7 +49,7 @@ typedef struct { * size: 0x198 */ typedef struct { - uint8 var_000; + uint8 editor_step; uint8 category; // 0x01 uint8 objective_type; // 0x02 uint8 objective_arg_1; // 0x03 @@ -134,9 +134,10 @@ typedef struct { uint16 sprites_start_litter; uint8 pad_013573C6[2]; uint16 word_013573C8; - uint8 pad_013573CA[4]; - uint16 word_013573CE; - uint16 word_013573D0; + uint16 sprites_count_vehicle; + uint16 sprites_count_peep; + uint16 sprites_count_misc; + uint16 sprites_count_litter; uint8 pad_013573D2[2]; rct_string_id park_name; uint8 pad_013573D6[2]; @@ -174,7 +175,7 @@ typedef struct { uint32 dword_0135789C; uint32 dword_013578A0; uint32 dword_013578A4[201]; - + // SC6[8] uint16 last_guests_in_park; uint8 pad_01357BCA[3]; @@ -282,7 +283,7 @@ typedef struct { uint16 park_entrance_y[4]; uint16 park_entrance_z[4]; uint8 park_entrance_direction[4]; - uint8 scenario_filename[256]; + char scenario_filename[256]; uint8 saved_expansion_pack_names[3256]; rct_banner banners[250]; char custom_strings[0x8000]; @@ -411,7 +412,8 @@ extern int gScenarioListCount; extern int gScenarioListCapacity; extern rct_scenario_basic *gScenarioList; -extern char gScenarioSaveName[MAX_PATH]; +extern char gScenarioSavePath[MAX_PATH]; +extern int gFirstTimeSave; int scenario_scores_save(); void scenario_load_list(); @@ -420,14 +422,18 @@ int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *in int scenario_load(const char *path); int scenario_load_and_play(const rct_scenario_basic *scenario); int scenario_load_and_play_from_path(const char *path); +void scenario_begin(); void scenario_update(); unsigned int scenario_rand(); +unsigned int scenario_rand_max(unsigned int max); int scenario_prepare_for_save(); -int scenario_save(char *path, int flags); -bool scenario_save_s6(char *path, rct_s6_data *s6); +int scenario_save(SDL_RWops* rw, int flags); +int scenario_save_network(SDL_RWops* rw); +bool scenario_save_s6(SDL_RWops* rw, rct_s6_data *s6); void scenario_set_filename(const char *value); void scenario_failure(); void scenario_success(); void scenario_success_submit_name(const char *name); +void scenario_autosave_check(); #endif diff --git a/src/scenario_list.c b/src/scenario_list.c index b924cbf0a5..78940c8935 100644 --- a/src/scenario_list.c +++ b/src/scenario_list.c @@ -8,18 +8,19 @@ * 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 "platform/platform.h" +#include "util/util.h" #include "scenario.h" // Scenario list @@ -43,7 +44,7 @@ rct_scenario_basic *get_scenario_by_filename(const char *filename) } /** - * + * * rct2: 0x006775A8 */ void scenario_load_list() @@ -89,7 +90,7 @@ static void scenario_list_add(const char *path) return; // Ignore scenarios where first header byte is not 255 - if (s6Info.var_000 != 255) + if (s6Info.editor_step != 255) return; // Check if scenario already exists in list, likely if in scores @@ -102,8 +103,8 @@ static void scenario_list_add(const char *path) scenario->objective_arg_1 = s6Info.objective_arg_1; scenario->objective_arg_2 = s6Info.objective_arg_2; scenario->objective_arg_3 = s6Info.objective_arg_3; - strcpy(scenario->name, s6Info.name); - strcpy(scenario->details, s6Info.details); + safe_strncpy(scenario->name, s6Info.name, 64); + safe_strncpy(scenario->details, s6Info.details, 256); } else { // Check if the scenario list buffer has room for another scenario if (gScenarioListCount >= gScenarioListCapacity) { @@ -117,7 +118,7 @@ static void scenario_list_add(const char *path) gScenarioListCount++; // Add this new scenario to the list - strcpy(scenario->path, path); + safe_strncpy(scenario->path, path, 256); scenario->flags = SCENARIO_FLAGS_VISIBLE; if (RCT2_GLOBAL(0x009AA00C, uint8) & 1) scenario->flags |= SCENARIO_FLAGS_SIXFLAGS; @@ -126,8 +127,8 @@ static void scenario_list_add(const char *path) scenario->objective_arg_1 = s6Info.objective_arg_1; scenario->objective_arg_2 = s6Info.objective_arg_2; scenario->objective_arg_3 = s6Info.objective_arg_3; - strcpy(scenario->name, s6Info.name); - strcpy(scenario->details, s6Info.details); + safe_strncpy(scenario->name, s6Info.name, 64); + safe_strncpy(scenario->details, s6Info.details, 256); } } @@ -154,19 +155,19 @@ static int scenario_list_sort_compare(const void *a, const void *b) /** * Gets the path for the scenario scores path. */ -static void scenario_scores_get_path(char *outPath) +static void scenario_scores_get_path(utf8 *outPath) { platform_get_user_directory(outPath, NULL); strcat(outPath, "scores.dat"); } /** - * + * * rct2: 0x006775A8 */ static int scenario_scores_load() { - FILE *file; + SDL_RWops *file; char scoresPath[MAX_PATH]; scenario_scores_get_path(scoresPath); @@ -180,9 +181,9 @@ static int scenario_scores_load() // Try and load the scores file // First check user folder and then fallback to install directory - file = fopen(scoresPath, "rb"); + file = SDL_RWFromFile(scoresPath, "rb"); if (file == NULL) { - file = fopen(get_file_path(PATH_ID_SCORES), "rb"); + file = SDL_RWFromFile(get_file_path(PATH_ID_SCORES), "rb"); if (file == NULL) { log_error("Unable to load scenario scores."); return 0; @@ -191,8 +192,8 @@ static int scenario_scores_load() // Load header rct_scenario_scores_header header; - if (fread(&header, 16, 1, file) != 1) { - fclose(file); + if (SDL_RWread(file, &header, 16, 1) != 1) { + SDL_RWclose(file); log_error("Invalid header in scenario scores file."); return 0; } @@ -202,13 +203,13 @@ static int scenario_scores_load() int scenarioListBufferSize = gScenarioListCount * sizeof(rct_scenario_basic); gScenarioListCapacity = gScenarioListCount; gScenarioList = malloc(scenarioListBufferSize); - if (fread(gScenarioList, scenarioListBufferSize, 1, file) == 1) { - fclose(file); + if (SDL_RWread(file, gScenarioList, scenarioListBufferSize, 1) == 1) { + SDL_RWclose(file); return 1; } // Unable to load scores, free scenario list - fclose(file); + SDL_RWclose(file); gScenarioListCount = 0; gScenarioListCapacity = 0; free(gScenarioList); @@ -217,17 +218,17 @@ static int scenario_scores_load() } /** - * + * * rct2: 0x00677B50 */ int scenario_scores_save() { - FILE *file; - char scoresPath[MAX_PATH]; + SDL_RWops *file; + utf8 scoresPath[MAX_PATH]; scenario_scores_get_path(scoresPath); - file = fopen(scoresPath, "wb"); + file = SDL_RWFromFile(scoresPath, "wb"); if (file == NULL) { log_error("Unable to save scenario scores."); return 0; @@ -236,10 +237,10 @@ int scenario_scores_save() rct_scenario_scores_header header; header.scenario_count = gScenarioListCount; - fwrite(&header, sizeof(header), 1, file); + SDL_RWwrite(file, &header, sizeof(header), 1); if (gScenarioListCount > 0) - fwrite(gScenarioList, gScenarioListCount * sizeof(rct_scenario_basic), 1, file); + SDL_RWwrite(file, gScenarioList, gScenarioListCount * sizeof(rct_scenario_basic), 1); - fclose(file); + SDL_RWclose(file); return 1; -} \ No newline at end of file +} diff --git a/src/sprites.h b/src/sprites.h index b30b07c0a6..3d75810080 100644 --- a/src/sprites.h +++ b/src/sprites.h @@ -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 . *****************************************************************************/ @@ -32,7 +32,7 @@ enum { SPR_HOT_AND_DRY = 3292, SPR_COLD = 3293, - // This is the start of every character there are + // This is the start of every character there are // 224 characters per font (first 32 are control codes hence why it doesn't go to 255) // 4 fonts // = 896 sprites @@ -64,6 +64,10 @@ enum { SPR_TESTING = 5181, SPR_TOGGLE_OPEN_CLOSE = 5182, + SPR_SHOW_GUESTS_THOUGHTS_ABOUT_THIS_RIDE_ATTRACTION = 5184, + SPR_SHOW_GUESTS_QUEUING_FOR_THIS_RIDE_ATTRACTION = 5185, + SPR_SHOW_GUESTS_ON_THIS_RIDE_ATTRACTION = 5186, + SPR_RIDE = 5187, SPR_TRACK_PEEP = 5188, SPR_SCENERY = 5189, @@ -339,7 +343,6 @@ enum { SPR_INTRO_LOGO_11 = SPR_INTRO_LOGO_00 + 4, SPR_INTRO_LOGO_21 = SPR_INTRO_LOGO_00 + 5, - SPR_SIX_FLAGS = 23225, SPR_INTRO_INFOGRAMES_00 = 23226, SPR_INTRO_INFOGRAMES_10 = SPR_INTRO_INFOGRAMES_00 + 1, SPR_INTRO_INFOGRAMES_01 = SPR_INTRO_INFOGRAMES_00 + 2, @@ -380,6 +383,16 @@ enum { 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, + + SPR_G2_TITLE_RESTART = SPR_G2_BEGIN + 29, + SPR_G2_TITLE_STOP = SPR_G2_BEGIN + 30, + SPR_G2_TITLE_PLAY = SPR_G2_BEGIN + 31, + SPR_G2_TITLE_SKIP = SPR_G2_BEGIN + 32, + + SPR_G2_SANDBOX = SPR_G2_BEGIN + 33, + + SPR_G2_TAB_NEWS = SPR_G2_BEGIN + 58, + SPR_G2_LOCKED = SPR_G2_BEGIN + 59, }; #endif diff --git a/src/title.c b/src/title.c index ecf2266cbc..a6b35904f9 100644 --- a/src/title.c +++ b/src/title.c @@ -33,7 +33,9 @@ #include "intro.h" #include "management/news_item.h" #include "management/research.h" +#include "network/network.h" #include "openrct2.h" +#include "peep/staff.h" #include "ride/ride.h" #include "scenario.h" #include "util/util.h" @@ -42,21 +44,19 @@ #include "world/park.h" #include "world/scenery.h" #include "world/sprite.h" +#include "title.h" +#include "interface/title_sequences.h" +#include "windows/error.h" static const int gRandomShowcase = 0; +sint32 gTitleScriptCommand = -1; +uint8 gTitleScriptSave = 0xFF; +sint32 gTitleScriptSkipTo = -1; +sint32 gTitleScriptSkipLoad = -1; +rct_xy16 _titleScriptCurrentCentralPosition = { -1, -1 }; #pragma region Showcase script -enum { - TITLE_SCRIPT_WAIT, - 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 LOADMM() TITLE_SCRIPT_LOADMM #define LOCATION(x, y) TITLE_SCRIPT_LOCATION, x, y @@ -80,8 +80,10 @@ static const uint8 _magicMountainScript[] = { static uint8* _loadedScript; static const uint8* _currentScript; +static uint8 _lastOpcode; static int _scriptNoLoadsSinceRestart; static int _scriptWaitCounter; +static int _scriptCurrentPreset; static void title_init_showcase(); static void title_update_showcase(); @@ -112,7 +114,7 @@ void title_load() reset_sprite_list(); ride_init_all(); window_guest_list_init_vars_a(); - sub_6BD3A4(); + staff_reset_modes(); map_init(150); park_init(); date_reset(); @@ -123,15 +125,18 @@ void title_load() window_staff_list_init_vars(); map_update_tile_pointers(); reset_0x69EBE4(); - stop_ride_music(); - stop_crowd_sound(); - stop_other_sounds(); + audio_stop_ride_music(); + audio_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; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, uint16) = 0; +#ifndef DISABLE_NETWORK + network_close(); +#endif if (gOpenRCT2ShowChangelog) { gOpenRCT2ShowChangelog = false; @@ -153,7 +158,7 @@ static void title_create_windows() window_title_exit_open(); window_title_options_open(); window_title_logo_open(); - window_resize_gui(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16), RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16)); + window_resize_gui(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16), RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16)); } /** @@ -162,35 +167,23 @@ static void title_create_windows() */ static void title_init_showcase() { - _scriptNoLoadsSinceRestart = 1; - - SafeFree(_loadedScript); - - _currentScript = _magicMountainScript; - 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(); + title_refresh_sequence(); } static int title_load_park(const char *path) { rct_window* w; - int successfulLoad; + int successfulLoad = 0; - successfulLoad = _strcmpi(path_get_extension(path), ".sv6") == 0 ? - game_load_sv6(path) : - scenario_load(path); + if (_strcmpi(path_get_extension(path), ".sv6") == 0) { + SDL_RWops* rw = SDL_RWFromFile(path, "rb"); + if (rw != NULL) { + successfulLoad = game_load_sv6(rw); + SDL_RWclose(rw); + } + } else { + successfulLoad = scenario_load(path); + } if (!successfulLoad) return 0; @@ -201,9 +194,9 @@ static int title_load_park(const char *path) 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; + char _cl = (RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, sint16) & 0xFF) - w->viewport->zoom; + w->viewport->zoom = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, sint16) & 0xFF; + *((char*)(&RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, sint32))) = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, sint16) >> 8; if (_cl != 0) { if (_cl < 0) { _cl = -_cl; @@ -223,19 +216,57 @@ static int title_load_park(const char *path) window_new_ride_init_vars(); if (_strcmpi(path_get_extension(path), ".sv6") != 0) sub_684AC3(); - RCT2_CALLPROC_EBPSAFE(0x006DFEE4); + scenery_set_default_placement_configuration(); news_item_init_queue(); gfx_invalidate_screen(); - RCT2_GLOBAL(0x009DEA66, sint16) = 0; - RCT2_GLOBAL(0x009DEA5C, sint16) = 0x0D6D8; + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, sint16) = 0; + gGameSpeed = 1; return 1; } +/** + * Sets the map location to the given tile coordinates. Z is automatic. + * @param x X position in map tiles. + * @param y Y position in map tiles. + */ +static void title_set_location(int x, int y) +{ + int z = map_element_height(x, y); + + // Update viewport + rct_window* 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); + } + + // Save known tile position in case of window resize + _titleScriptCurrentCentralPosition.x = (sint16)x; + _titleScriptCurrentCentralPosition.y = (sint16)y; +} + +/** + * Re-centres the map location to the last scripted tile position. + */ +void title_fix_location() +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) == SCREEN_FLAGS_TITLE_DEMO) { + rct_xy16 position = _titleScriptCurrentCentralPosition; + if (position.x != -1) { + title_set_location(position.x, position.y); + } + } +} + static void title_skip_opcode() { uint8 script_opcode; script_opcode = *_currentScript++; + gTitleScriptCommand++; + _lastOpcode = script_opcode; + switch (script_opcode) { case TITLE_SCRIPT_WAIT: _currentScript++; @@ -263,12 +294,36 @@ static void title_skip_opcode() static void title_do_next_script_opcode() { int i; - short x, y, z; + short x, y; uint8 script_opcode, script_operand; rct_window* w; - - script_opcode = *_currentScript++; + gTitleScriptCommand++; + if (gTitleScriptCommand <= 1 || *(_currentScript - 1) != TITLE_SCRIPT_END) + script_opcode = *_currentScript++; + else + script_opcode = *_currentScript; + if (gTitleScriptSkipTo != -1) { + if (gTitleScriptSkipTo == gTitleScriptCommand) { + gTitleScriptSkipTo = -1; + gTitleScriptSkipLoad = -1; + } + else if (gTitleScriptSkipLoad == gTitleScriptCommand) { + gTitleScriptSkipLoad = -1; + } + else if (gTitleScriptSkipLoad != -1) { + gTitleScriptCommand--; + _currentScript--; + title_skip_opcode(); + return; + } + } + + _lastOpcode = script_opcode; + switch (script_opcode) { + case TITLE_SCRIPT_END: + _scriptWaitCounter = 1; + break; case TITLE_SCRIPT_WAIT: _scriptWaitCounter = (*_currentScript++) * 32; break; @@ -277,26 +332,19 @@ static void title_do_next_script_opcode() log_fatal("OpenRCT2 can not currently cope when unable to load title screen scenario."); exit(-1); } + gTitleScriptSave = 0xFF; 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); - } + title_set_location(x, y); 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); + window_rotate_camera(w, 1); break; case TITLE_SCRIPT_ZOOM: script_operand = (*_currentScript++); @@ -304,8 +352,14 @@ static void title_do_next_script_opcode() if (w != NULL && w->viewport != NULL) window_zoom_set(w, script_operand); break; + case TITLE_SCRIPT_SPEED: + script_operand = (*_currentScript++); + gGameSpeed = max(1, min(4, script_operand)); + break; case TITLE_SCRIPT_RESTART: _scriptNoLoadsSinceRestart = 1; + gTitleScriptCommand = -1; + gTitleScriptSave = 0xFF; _currentScript = _loadedScript; if (gRandomShowcase) { if (_currentScript != NULL) @@ -317,7 +371,8 @@ static void title_do_next_script_opcode() { const uint8 *loadPtr; char *ch, filename[32], path[MAX_PATH]; - + char separator = platform_get_path_separator(); + loadPtr = _currentScript - 1; // Get filename @@ -327,19 +382,38 @@ static void title_do_next_script_opcode() } 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 (gConfigTitleSequences.presets[_scriptCurrentPreset].path[0]) { + safe_strncpy(path, gConfigTitleSequences.presets[_scriptCurrentPreset].path, MAX_PATH); + } + else { + platform_get_user_directory(path, "title sequences"); + strcat(path, gConfigTitleSequences.presets[_scriptCurrentPreset].name); + strncat(path, &separator, 1); + } + + strcat(path, filename); if (title_load_park(path)) { _scriptNoLoadsSinceRestart = 0; + gTitleScriptSave = gConfigTitleSequences.presets[gCurrentPreviewTitleSequence].commands[gTitleScriptCommand].saveIndex; } else { + log_error("Failed to load: \"%s\" for the title sequence.", path); script_opcode = *_currentScript; - while (script_opcode != TITLE_SCRIPT_LOADMM && script_opcode != TITLE_SCRIPT_LOAD && script_opcode != TITLE_SCRIPT_RESTART) { + while (script_opcode != TITLE_SCRIPT_LOADMM && script_opcode != TITLE_SCRIPT_LOAD && script_opcode != TITLE_SCRIPT_RESTART && script_opcode != TITLE_SCRIPT_END) { title_skip_opcode(); script_opcode = *_currentScript; } - if (script_opcode == TITLE_SCRIPT_RESTART && _scriptNoLoadsSinceRestart) { + if ((script_opcode == TITLE_SCRIPT_RESTART || script_opcode == TITLE_SCRIPT_END) && _scriptNoLoadsSinceRestart) { if (_currentScript != _magicMountainScript) { + _scriptNoLoadsSinceRestart = 1; + gTitleScriptCommand = -1; + gTitleScriptSave = 0xFF; _currentScript = _magicMountainScript; + gCurrentPreviewTitleSequence = 0; + gTitleScriptSkipTo = -1; + gTitleScriptSkipLoad = -1; + _scriptCurrentPreset = 0; + //window_invalidate_by_class(WC_TITLE_EDITOR); } else { log_fatal("OpenRCT2 can not currently cope when unable to load title screen scenario."); exit(-1); @@ -349,6 +423,7 @@ static void title_do_next_script_opcode() } break; } + window_invalidate_by_class(WC_TITLE_EDITOR); } /** @@ -357,31 +432,54 @@ static void title_do_next_script_opcode() */ static void title_update_showcase() { - if (_scriptWaitCounter <= 0) { + int i, numUpdates; + // Loop used for scene skip functionality + // Only loop here when the appropriate save hasn't been loaded yet since no game updates are required + do { do { - title_do_next_script_opcode(); - } while (_scriptWaitCounter == 0); - } + if (_scriptWaitCounter <= 0) { + do { + title_do_next_script_opcode(); + } while (_scriptWaitCounter == 0); + } - _scriptWaitCounter--; + if (gTitleScriptSkipTo != -1 && gTitleScriptSkipLoad != -1) + _scriptWaitCounter = 0; + else if (_lastOpcode != TITLE_SCRIPT_END) + _scriptWaitCounter--; + } while (gTitleScriptSkipTo != -1 && gTitleScriptSkipLoad != -1); + + if (gTitleScriptSkipTo != -1 && gTitleScriptSkipLoad == -1) { + if (gGameSpeed > 1) { + numUpdates = 1 << (gGameSpeed - 1); + } else { + numUpdates = 1; + } + for (i = 0; i < numUpdates; i++) { + game_logic_update(); + } + update_palette_effects(); + update_rain_animation(); + } + } while (gTitleScriptSkipTo != -1 && gTitleScriptSkipLoad == -1); } -static void DrawOpenRCT2(int x, int y) +void DrawOpenRCT2(int x, int y) { - char buffer[256]; + utf8 buffer[256]; rct_drawpixelinfo *dpi = RCT2_ADDRESS(RCT2_ADDRESS_SCREEN_DPI, rct_drawpixelinfo); - + // Draw background gfx_fill_rect_inset(dpi, x, y, x + 128, y + 20, 0x80 | 12, 0x8); - // 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); + // Write format codes + utf8 *ch = buffer; + ch = utf8_write_codepoint(ch, FORMAT_MEDIUMFONT); + ch = utf8_write_codepoint(ch, FORMAT_OUTLINE); + ch = utf8_write_codepoint(ch, FORMAT_WHITE); + + // Write name and version information + openrct2_write_full_version_info(ch, sizeof(buffer) - (ch - buffer)); // Draw Text gfx_draw_string(dpi, buffer, 0, x + 5, y + 5); @@ -391,35 +489,34 @@ static void DrawOpenRCT2(int x, int y) void game_handle_input(); void title_update() { + int i, numUpdates; screenshot_check(); title_handle_keyboard_input(); if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0) { title_update_showcase(); - game_logic_update(); - start_title_music(); + + if (gGameSpeed > 1) { + numUpdates = 1 << (gGameSpeed - 1); + } else { + numUpdates = 1; + } + + for (i = 0; i < numUpdates; i++) { + game_logic_update(); + } + audio_start_title_music(); } RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~0x80; 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)++; + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_AGE, uint16)++; // Input game_handle_input(); - - update_palette_effects(); - update_rain_animation(); - - if (RCT2_GLOBAL(0x009AAC73, uint8) != 255) { - RCT2_GLOBAL(0x009AAC73, uint8)++; - if (RCT2_GLOBAL(0x009AAC73, uint8) == 255) - config_save_default(); - } } static uint8 *generate_random_script() @@ -427,24 +524,24 @@ static uint8 *generate_random_script() int i, j; const int views = 16; - srand((unsigned int)time(NULL)); + util_srand((unsigned int)time(NULL)); uint8 *script = malloc(views * 8 + 2); i = 0; script[i++] = TITLE_SCRIPT_LOAD; for (j = 0; j < views; j++) { script[i++] = TITLE_SCRIPT_LOCATION; - script[i++] = 64 + (rand() % 128); - script[i++] = 64 + (rand() % 128); + script[i++] = 64 + (util_rand() % 128); + script[i++] = 64 + (util_rand() % 128); - int rotationCount = rand() % 4; + int rotationCount = util_rand() % 4; if (rotationCount > 0) { script[i++] = TITLE_SCRIPT_ROTATE; script[i++] = rotationCount; } script[i++] = TITLE_SCRIPT_WAIT; - script[i++] = 8 + (rand() % 6); + script[i++] = 8 + (util_rand() % 6); } script[i] = TITLE_SCRIPT_RESTART; @@ -453,60 +550,72 @@ static uint8 *generate_random_script() #pragma region Load script.txt -static void title_script_get_line(FILE *file, char *parts) +void title_script_get_line(SDL_RWops *file, char *parts) { - int i, c, part, cindex, whitespace, comment; + int i, c, part, cindex, whitespace, comment, load; for (i = 0; i < 3; i++) - parts[i * 32] = 0; + parts[i * 128] = 0; part = 0; cindex = 0; whitespace = 1; comment = 0; - for (;;) { - c = fgetc(file); + load = 0; + for (; part < 3;) { + c = 0; + if (SDL_RWread(file, &c, 1, 1) != 1) + c = EOF; + if (c == '\n' || c == '\r' || c == EOF) { - parts[part * 32 + cindex] = 0; + parts[part * 128 + cindex] = 0; return; } else if (c == '#') { - parts[part * 32 + cindex] = 0; + parts[part * 128 + cindex] = 0; comment = 1; - } else if (c == ' ' && !comment) { + } else if (c == ' ' && !comment && !load) { if (!whitespace) { - parts[part * 32 + cindex] = 0; + if (part == 0 && cindex == 4 && _strnicmp(parts, "LOAD", 4) == 0) + load = true; + parts[part * 128 + cindex] = 0; part++; cindex = 0; } } else if (!comment) { whitespace = 0; - if (cindex < 31) { - parts[part * 32 + cindex] = c; + if (cindex < 127) { + parts[part * 128 + cindex] = c; cindex++; } + else { + parts[part * 128 + cindex] = 0; + part++; + cindex = 0; + } } } } static uint8 *title_script_load() { - FILE *file; - char parts[3 * 32], *token, *part1, *part2, *src; + SDL_RWops *file; + char parts[3 * 128], *token, *part1, *part2, *src; + + utf8 path[MAX_PATH]; + utf8 filePath[] = "data/title/script.txt"; - 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"); + file = SDL_RWFromFile(path, "r"); if (file == NULL) { log_error("unable to load title script"); return NULL; } + sint64 fileSize = SDL_RWsize(file); uint8 *binaryScript = (uint8*)malloc(1024 * 8); if (binaryScript == NULL) { - fclose(file); + SDL_RWclose(file); log_error("unable to allocate memory for script"); return NULL; @@ -517,9 +626,9 @@ static uint8 *title_script_load() do { title_script_get_line(file, parts); - token = &parts[0 * 32]; - part1 = &parts[1 * 32]; - part2 = &parts[2 * 32]; + token = &parts[0 * 128]; + part1 = &parts[1 * 128]; + part2 = &parts[2 * 128]; if (token[0] != 0) { if (_stricmp(token, "LOAD") == 0) { @@ -543,11 +652,13 @@ static uint8 *title_script_load() *scriptPtr++ = atoi(part1) & 0xFF; } else { log_error("unknown token, %s", token); + SafeFree(binaryScript); + SDL_RWclose(file); return NULL; } } - } while (!feof(file)); - fclose(file); + } while (SDL_RWtell(file) < fileSize); + SDL_RWclose(file); *scriptPtr++ = TITLE_SCRIPT_RESTART; @@ -562,3 +673,115 @@ static uint8 *title_script_load() } #pragma endregion + +bool title_refresh_sequence() +{ + _scriptCurrentPreset = gCurrentPreviewTitleSequence; + title_sequence *title = &gConfigTitleSequences.presets[_scriptCurrentPreset]; + + bool hasLoad = false, hasInvalidSave = false, hasWait = false, hasRestart = false; + for (int i = 0; i < title->num_commands && !hasInvalidSave; i++) { + if (title->commands[i].command == TITLE_SCRIPT_LOAD) { + if (title->commands[i].saveIndex == 0xFF) + hasInvalidSave = true; + hasLoad = true; + } + else if (title->commands[i].command == TITLE_SCRIPT_LOADMM) { + hasLoad = true; + } + else if (title->commands[i].command == TITLE_SCRIPT_WAIT && title->commands[i].seconds >= 4) { + hasWait = true; + } + else if (title->commands[i].command == TITLE_SCRIPT_RESTART) { + hasRestart = true; + break; + } + else if (title->commands[i].command == TITLE_SCRIPT_END) { + break; + } + } + if (hasLoad && (hasWait || !hasRestart) && !hasInvalidSave) { + char *src; + uint8 *scriptPtr, *binaryScript; + binaryScript = malloc(1024 * 8); + scriptPtr = binaryScript; + + for (int i = 0; i < title->num_commands; i++) { + *scriptPtr++ = title->commands[i].command; + switch (title->commands[i].command) { + case TITLE_SCRIPT_LOAD: + src = title->saves[title->commands[i].saveIndex]; + do { + *scriptPtr++ = *src++; + } while (*(src - 1) != 0); + break; + case TITLE_SCRIPT_LOCATION: + *scriptPtr++ = title->commands[i].x; + *scriptPtr++ = title->commands[i].y; + break; + case TITLE_SCRIPT_ROTATE: + *scriptPtr++ = title->commands[i].rotations; + break; + case TITLE_SCRIPT_ZOOM: + *scriptPtr++ = title->commands[i].zoom; + break; + case TITLE_SCRIPT_SPEED: + *scriptPtr++ = title->commands[i].speed; + break; + case TITLE_SCRIPT_WAIT: + *scriptPtr++ = title->commands[i].seconds; + break; + } + } + + *scriptPtr++ = TITLE_SCRIPT_END; + + int scriptLength = (int)(scriptPtr - binaryScript); + binaryScript = realloc(binaryScript, scriptLength); + + _scriptNoLoadsSinceRestart = 1; + if (_loadedScript != _magicMountainScript) + SafeFree(_loadedScript); + _loadedScript = binaryScript; + _currentScript = binaryScript; + _scriptWaitCounter = 0; + gTitleScriptCommand = -1; + gTitleScriptSave = 0xFF; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) == SCREEN_FLAGS_TITLE_DEMO) { + title_update_showcase(); + gfx_invalidate_screen(); + } + + return true; + } + log_error("Failed to load title sequence, hasLoad: %i, hasWait4seconds: %i, hasRestart: %i, hasInvalidSave: %i", hasLoad, hasWait, hasRestart, hasInvalidSave); + window_error_open(5402, (!hasWait && hasRestart) ? 5439 : STR_NONE); + _scriptNoLoadsSinceRestart = 1; + if (_loadedScript != _magicMountainScript) + SafeFree(_loadedScript); + _scriptCurrentPreset = 0; + _loadedScript = (uint8*)_magicMountainScript; + _currentScript = _magicMountainScript; + _scriptWaitCounter = 0; + gTitleScriptCommand = -1; + gTitleScriptSave = 0xFF; + gCurrentPreviewTitleSequence = 0; + window_invalidate_by_class(WC_OPTIONS); + window_invalidate_by_class(WC_TITLE_EDITOR); + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) == SCREEN_FLAGS_TITLE_DEMO) { + title_update_showcase(); + gfx_invalidate_screen(); + } + + return false; +} + +void title_skip_from_beginning() +{ + _scriptNoLoadsSinceRestart = 1; + gTitleScriptCommand = -1; + gTitleScriptSave = 0xFF; + _currentScript = _loadedScript; +} diff --git a/src/title.h b/src/title.h index 33897b12e7..890a6bdf60 100644 --- a/src/title.h +++ b/src/title.h @@ -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 @@ -17,11 +17,37 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ - + #ifndef _TITLE_H_ #define _TITLE_H_ +#include + +enum { + TITLE_SCRIPT_WAIT, + TITLE_SCRIPT_LOADMM, + TITLE_SCRIPT_LOCATION, + TITLE_SCRIPT_ROTATE, + TITLE_SCRIPT_ZOOM, + TITLE_SCRIPT_RESTART, + TITLE_SCRIPT_LOAD, + TITLE_SCRIPT_END, + TITLE_SCRIPT_SPEED, + TITLE_SCRIPT_LOOP, + TITLE_SCRIPT_ENDLOOP +} TITLE_SCRIPT_COMMANDS; + +extern sint32 gTitleScriptCommand; +extern uint8 gTitleScriptSave; +extern sint32 gTitleScriptSkipTo; +extern sint32 gTitleScriptSkipLoad; + void title_load(); void title_update(); +void title_skip_from_beginning(); +void title_script_get_line(SDL_RWops *file, char *parts); +bool title_refresh_sequence(); +void title_fix_location(); +void DrawOpenRCT2(int x, int y); #endif diff --git a/src/tutorial.c b/src/tutorial.c index 778cf47812..07e6b4c725 100644 --- a/src/tutorial.c +++ b/src/tutorial.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 . *****************************************************************************/ diff --git a/src/tutorial.h b/src/tutorial.h index a9db5b71db..d1b2eced61 100644 --- a/src/tutorial.h +++ b/src/tutorial.h @@ -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 . *****************************************************************************/ diff --git a/src/util/sawyercoding.c b/src/util/sawyercoding.c index f11ddeb7cb..d73bda1fda 100644 --- a/src/util/sawyercoding.c +++ b/src/util/sawyercoding.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 @@ -19,19 +19,21 @@ *****************************************************************************/ #include "../addresses.h" +#include "../platform/platform.h" #include "sawyercoding.h" -static int decode_chunk_rle(uint8* src_buffer, uint8* dst_buffer, int length); -static int decode_chunk_repeat(char *buffer, int length); -static void decode_chunk_rotate(char *buffer, int length); +static size_t decode_chunk_rle(const uint8* src_buffer, uint8* dst_buffer, size_t length); +static size_t decode_chunk_repeat(uint8 *buffer, size_t length); +static void decode_chunk_rotate(uint8 *buffer, size_t length); -static int encode_chunk_rle(char *src_buffer, char *dst_buffer, int length); -static int encode_chunk_repeat(char *src_buffer, char *dst_buffer, int length); -static void encode_chunk_rotate(char *buffer, int length); +static size_t encode_chunk_rle(const uint8 *src_buffer, uint8 *dst_buffer, size_t length); +static size_t encode_chunk_repeat(const uint8 *src_buffer, uint8 *dst_buffer, size_t length); +static void encode_chunk_rotate(uint8 *buffer, size_t length); -uint32 sawyercoding_calculate_checksum(uint8* buffer, uint32 length) +uint32 sawyercoding_calculate_checksum(const uint8* buffer, size_t length) { - uint32 i, checksum = 0; + size_t i; + uint32 checksum = 0; for (i = 0; i < length; i++) checksum += buffer[i]; @@ -39,27 +41,29 @@ uint32 sawyercoding_calculate_checksum(uint8* buffer, uint32 length) } /** - * + * * rct2: 0x00676FD2 */ -int sawyercoding_validate_checksum(FILE *file) +int sawyercoding_validate_checksum(SDL_RWops* rw) { - uint32 i, checksum, fileChecksum, dataSize, bufferSize; + size_t i, dataSize, bufferSize; + uint32 checksum, fileChecksum; uint8 buffer[1024]; // Get data size - fseek(file, 0, SEEK_END); - dataSize = ftell(file); + SDL_RWseek(rw, 0, RW_SEEK_END); + // for whatever the reason, SDL_RWtell return Sint64 instead of size_t. + dataSize = (size_t)SDL_RWtell(rw); if (dataSize < 8) return 0; dataSize -= 4; - + // Calculate checksum - fseek(file, 0, SEEK_SET); + SDL_RWseek(rw, 0, RW_SEEK_SET); checksum = 0; do { bufferSize = min(dataSize, 1024); - if (fread(buffer, bufferSize, 1, file) != 1) + if (SDL_RWread(rw, buffer, bufferSize, 1) != 1) return 0; for (i = 0; i < bufferSize; i++) @@ -68,27 +72,27 @@ int sawyercoding_validate_checksum(FILE *file) } while (dataSize != 0); // Read file checksum - if (fread(&fileChecksum, sizeof(fileChecksum), 1, file) != 1) + if (SDL_RWread(rw, &fileChecksum, sizeof(fileChecksum), 1) != 1) return 0; // Reset file position - fseek(file, 0, SEEK_SET); + SDL_RWseek(rw, 0, RW_SEEK_SET); // Validate return checksum == fileChecksum; } /** - * + * * rct2: 0x0067685F * buffer (esi) */ -int sawyercoding_read_chunk(FILE *file, uint8 *buffer) +size_t sawyercoding_read_chunk(SDL_RWops* rw, uint8 *buffer) { sawyercoding_chunk_header chunkHeader; // Read chunk header - if (fread(&chunkHeader, sizeof(sawyercoding_chunk_header), 1, file) != 1) { + if (SDL_RWread(rw, &chunkHeader, sizeof(sawyercoding_chunk_header), 1) != 1) { log_error("Unable to read chunk header!"); return -1; } @@ -96,7 +100,7 @@ int sawyercoding_read_chunk(FILE *file, uint8 *buffer) uint8* src_buffer = malloc(chunkHeader.length); // Read chunk data - if (fread(src_buffer, chunkHeader.length, 1, file) != 1) { + if (SDL_RWread(rw, src_buffer, chunkHeader.length, 1) != 1) { free(src_buffer); log_error("Unable to read chunk data!"); return -1; @@ -128,9 +132,9 @@ int sawyercoding_read_chunk(FILE *file, uint8 *buffer) /** * * rct2: 0x006762E1 -* +* */ -int sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding_chunk_header chunkHeader){ +size_t sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding_chunk_header chunkHeader){ uint8 *encode_buffer, *encode_buffer2; switch (chunkHeader.encoding){ @@ -177,16 +181,16 @@ int sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding return chunkHeader.length + sizeof(sawyercoding_chunk_header); } -int sawyercoding_decode_sv4(char *src, char *dst, int length) +size_t sawyercoding_decode_sv4(const uint8 *src, uint8 *dst, size_t length) { // (0 to length - 4): RLE chunk // (length - 4 to length): checksum return decode_chunk_rle(src, dst, length - 4); } -int sawyercoding_decode_sc4(char *src, char *dst, int length) +size_t sawyercoding_decode_sc4(const uint8 *src, uint8 *dst, size_t length) { - int decodedLength, i; + size_t decodedLength, i; uint32 *code; // Uncompress @@ -206,9 +210,10 @@ int sawyercoding_decode_sc4(char *src, char *dst, int length) return decodedLength; } -int sawyercoding_encode_sv4(char *src, char *dst, int length) +size_t sawyercoding_encode_sv4(const uint8 *src, uint8 *dst, size_t length) { - int encodedLength, checksum; + size_t encodedLength; + uint32 checksum; // Encode encodedLength = encode_chunk_rle(src, dst, length); @@ -220,16 +225,16 @@ int sawyercoding_encode_sv4(char *src, char *dst, int length) return encodedLength + 4; } -int sawyercoding_decode_td6(char *src, char *dst, int length) +size_t sawyercoding_decode_td6(const uint8 *src, uint8 *dst, size_t 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); +size_t sawyercoding_encode_td6(const uint8* src, uint8* dst, size_t length){ + size_t output_length = encode_chunk_rle(src, dst, length); uint32 checksum = 0; - for (int i = 0; i < output_length; i++){ + for (size_t i = 0; i < output_length; i++){ uint8 new_byte = ((checksum & 0xFF) + dst[i]) & 0xFF; checksum = (checksum & 0xFFFFFF00) + new_byte; checksum = rol32(checksum, 3); @@ -242,11 +247,11 @@ int sawyercoding_encode_td6(char* src, char* dst, int length){ } /* Based off of rct2: 0x006770C1 */ -int sawyercoding_validate_track_checksum(char* src, int length){ +int sawyercoding_validate_track_checksum(const uint8* src, size_t length){ uint32 file_checksum = *((uint32*)&src[length - 4]); uint32 checksum = 0; - for (int i = 0; i < length - 4; i++){ + for (size_t i = 0; i < length - 4; i++){ uint8 new_byte = ((checksum & 0xFF) + src[i]) & 0xFF; checksum = (checksum & 0xFFFFFF00) + new_byte; checksum = rol32(checksum, 3); @@ -257,7 +262,7 @@ int sawyercoding_validate_track_checksum(char* src, int length){ else if (checksum - 0x1A67C == file_checksum) return 1; // .TD4 else if (checksum - 0x1A650 == file_checksum) - return 1; // .TD4 + return 1; // .TD4 else return 0; } @@ -265,12 +270,12 @@ int sawyercoding_validate_track_checksum(char* src, int length){ #pragma region Decoding /** - * + * * rct2: 0x0067693A */ -static int decode_chunk_rle(uint8* src_buffer, uint8* dst_buffer, int length) +static size_t decode_chunk_rle(const uint8* src_buffer, uint8* dst_buffer, size_t length) { - int i, j, count; + size_t i, j, count; uint8 *dst, rleCodeByte; dst = dst_buffer; @@ -287,19 +292,19 @@ static int decode_chunk_rle(uint8* src_buffer, uint8* dst_buffer, int length) *dst++ = src_buffer[++i]; } } - + // Return final size return dst - dst_buffer; } /** - * + * * rct2: 0x006769F1 */ -static int decode_chunk_repeat(char *buffer, int length) +static size_t decode_chunk_repeat(uint8 *buffer, size_t length) { - int i, j, count; - unsigned char *src, *dst, *copyOffset; + size_t i, j, count; + uint8 *src, *dst, *copyOffset; // Backup buffer src = malloc(length); @@ -321,16 +326,17 @@ static int decode_chunk_repeat(char *buffer, int length) free(src); // Return final size - return (char*)dst - buffer; + return dst - buffer; } /** - * + * * rct2: 0x006768F4 */ -static void decode_chunk_rotate(char *buffer, int length) +static void decode_chunk_rotate(uint8 *buffer, size_t length) { - int i, code = 1; + size_t i; + uint8 code = 1; for (i = 0; i < length; i++) { buffer[i] = ror8(buffer[i], code); code = (code + 2) % 8; @@ -345,13 +351,13 @@ static void decode_chunk_rotate(char *buffer, int length) * Ensure dst_buffer is bigger than src_buffer then resize afterwards * returns length of dst_buffer */ -static int encode_chunk_rle(char *src_buffer, char *dst_buffer, int length) +static size_t encode_chunk_rle(const uint8 *src_buffer, uint8 *dst_buffer, size_t length) { - char* src = src_buffer; - char* dst = dst_buffer; - char* end_src = src + length; + const uint8* src = src_buffer; + uint8* dst = dst_buffer; + const uint8* end_src = src + length; uint8 count = 0; - char* src_norm_start = src; + const uint8* src_norm_start = src; while (src < end_src - 1){ @@ -386,11 +392,11 @@ static int encode_chunk_rle(char *src_buffer, char *dst_buffer, int length) return dst - dst_buffer; } -static int encode_chunk_repeat(char *src_buffer, char *dst_buffer, int length) +static size_t encode_chunk_repeat(const uint8 *src_buffer, uint8 *dst_buffer, size_t length) { - int i, j, outLength; - int searchIndex, searchEnd, maxRepeatCount; - int bestRepeatIndex, bestRepeatCount, repeatIndex, repeatCount; + size_t i, j, outLength; + size_t searchIndex, searchEnd, maxRepeatCount; + size_t bestRepeatIndex, bestRepeatCount, repeatIndex, repeatCount; if (length == 0) return 0; @@ -402,7 +408,7 @@ static int encode_chunk_repeat(char *src_buffer, char *dst_buffer, int length) *dst_buffer++ = src_buffer[0]; outLength += 2; - // Itereate through remainder of the source buffer + // Iterate through remainder of the source buffer for (i = 1; i < length; ) { searchIndex = max(0, i - 32); searchEnd = i - 1; @@ -434,7 +440,7 @@ static int encode_chunk_repeat(char *src_buffer, char *dst_buffer, int length) outLength += 2; i++; } else { - *dst_buffer++ = (bestRepeatCount - 1) | ((32 - (i - bestRepeatIndex)) << 3); + *dst_buffer++ = (uint8)((bestRepeatCount - 1) | ((32 - (i - bestRepeatIndex)) << 3)); outLength++; i += bestRepeatCount; } @@ -443,9 +449,10 @@ static int encode_chunk_repeat(char *src_buffer, char *dst_buffer, int length) return outLength; } -static void encode_chunk_rotate(char *buffer, int length) +static void encode_chunk_rotate(uint8 *buffer, size_t length) { - int i, code = 1; + size_t i; + uint8 code = 1; for (i = 0; i < length; i++) { buffer[i] = rol8(buffer[i], code); code = (code + 2) % 8; @@ -454,9 +461,9 @@ static void encode_chunk_rotate(char *buffer, int length) #pragma endregion -int sawyercoding_detect_file_type(char *src, int length) +int sawyercoding_detect_file_type(const uint8 *src, size_t length) { - int i; + size_t i; // Currently can't detect TD4, as the checksum is the same as SC4 (need alternative method) @@ -477,4 +484,4 @@ int sawyercoding_detect_file_type(char *src, int length) } return -1; -} \ No newline at end of file +} diff --git a/src/util/sawyercoding.h b/src/util/sawyercoding.h index a1c702b334..80e3c756ed 100644 --- a/src/util/sawyercoding.h +++ b/src/util/sawyercoding.h @@ -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 @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ - + #ifndef _SAWYERCODING_H_ #define _SAWYERCODING_H_ @@ -47,17 +47,17 @@ enum { 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); -int sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding_chunk_header chunkHeader); -int sawyercoding_decode_sv4(char *src, char *dst, int length); -int sawyercoding_decode_sc4(char *src, char *dst, int length); -int sawyercoding_encode_sv4(char *src, char *dst, int length); -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_validate_checksum(SDL_RWops* rw); +uint32 sawyercoding_calculate_checksum(const uint8* buffer, size_t length); +size_t sawyercoding_read_chunk(SDL_RWops* rw, uint8 *buffer); +size_t sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding_chunk_header chunkHeader); +size_t sawyercoding_decode_sv4(const uint8 *src, uint8 *dst, size_t length); +size_t sawyercoding_decode_sc4(const uint8 *src, uint8 *dst, size_t length); +size_t sawyercoding_encode_sv4(const uint8 *src, uint8 *dst, size_t length); +size_t sawyercoding_decode_td6(const uint8 *src, uint8 *dst, size_t length); +size_t sawyercoding_encode_td6(const uint8 *src, uint8 *dst, size_t length); +int sawyercoding_validate_track_checksum(const uint8* src, size_t length); -int sawyercoding_detect_file_type(char *src, int length); +int sawyercoding_detect_file_type(const uint8 *src, size_t length); #endif diff --git a/src/util/util.c b/src/util/util.c index bf856238fa..890423e0fd 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -8,17 +8,19 @@ * 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 "util.h" +#include +#include "../platform/platform.h" int squaredmetres_to_squaredfeet(int squaredMetres) { @@ -41,7 +43,17 @@ int mph_to_kmph(int mph) return (mph * 1648) / 1024; } -const char *path_get_filename(const char *path) +bool filename_valid_characters(const utf8 *filename) +{ + for (int i = 0; filename[i] != '\0'; i++) { + if (filename[i] == '\\' || filename[i] == '/' || filename[i] == ':' || filename[i] == '?' || + filename[i] == '*' || filename[i] == '<' || filename[i] == '>' || filename[i] == '|') + return false; + } + return true; +} + +const char *path_get_filename(const utf8 *path) { const char *result, *ch; @@ -56,7 +68,7 @@ const char *path_get_filename(const char *path) return result; } -const char *path_get_extension(const char *path) +const char *path_get_extension(const utf8 *path) { const char *extension = NULL; const char *ch = path; @@ -71,7 +83,7 @@ const char *path_get_extension(const char *path) return extension; } -void path_set_extension(char *path, const char *newExtension) +void path_set_extension(utf8 *path, const utf8 *newExtension) { char *extension = NULL; char *ch = path; @@ -90,7 +102,7 @@ void path_set_extension(char *path, const char *newExtension) strcpy(extension, newExtension); } -void path_remove_extension(char *path) +void path_remove_extension(utf8 *path) { char *ch = path + strlen(path); for (--ch; ch >= path; --ch) { @@ -101,38 +113,24 @@ void path_remove_extension(char *path) } } -long fsize(FILE *fp) +bool readentirefile(const utf8 *path, void **outBuffer, int *outLength) { - long originalPosition, size; - - originalPosition = ftell(fp); - fseek(fp, 0, SEEK_END); - size = ftell(fp); - fseek(fp, originalPosition, SEEK_SET); - - return size; -} - -bool readentirefile(const char *path, void **outBuffer, long *outLength) -{ - FILE *fp; - long fpLength; + SDL_RWops *fp; + int fpLength; void *fpBuffer; // Open file - fp = fopen(path, "rb"); + fp = SDL_RWFromFile(path, "rb"); if (fp == NULL) return 0; // Get length - fseek(fp, 0, SEEK_END); - fpLength = ftell(fp); - rewind(fp); + fpLength = (int)SDL_RWsize(fp); // Read whole file into a buffer fpBuffer = malloc(fpLength); - fread(fpBuffer, fpLength, 1, fp); - fclose(fp); + SDL_RWread(fp, fpBuffer, fpLength, 1); + SDL_RWclose(fp); *outBuffer = fpBuffer; *outLength = fpLength; @@ -143,11 +141,27 @@ int bitscanforward(int source) { int i; + #if _MSC_VER >= 1400 // Visual Studio 2005 + uint8 success = _BitScanForward(&i, source); + return success != 0 ? i : -1; + #else for (i = 0; i < 32; i++) - if (source & (1 << i)) + if (source & (1u << i)) return i; return -1; + #endif +} + +int bitcount(int source) +{ + int result = 0; + for (int i = 0; i < 32; i++) { + if (source & (1u << i)) { + result++; + } + } + return result; } bool strequals(const char *a, const char *b, int length, bool caseInsensitive) @@ -167,12 +181,60 @@ int strcicmp(char const *a, char const *b) } } +char *safe_strncpy(char * destination, const char * source, size_t size) +{ + assert(destination != NULL); + assert(source != NULL); + + if (size == 0) + { + return destination; + } + char *result = destination; + bool terminated = false; + for (size_t i = 0; i < size; i++) + { + if (*source != '\0') + { + *destination++ = *source++; + } else { + *destination = *source; + terminated = true; + break; + } + } + if (!terminated) + { + result[size - 1] = '\0'; + log_warning("Truncating string %s to %d bytes.", destination, size); + } + return result; +} + bool utf8_is_bom(const char *str) { - return str[0] == 0xEF && str[1] == 0xBB && str[2] == 0xBF; + return str[0] == (char)0xEF && str[1] == (char)0xBB && str[2] == (char)0xBF; } bool str_is_null_or_empty(const char *str) { return str == NULL || str[0] == 0; +} + +uint32 srand0, srand1, srand2, srand3; + +void util_srand(int source) { + srand0 = source; + srand1 = srand0 ^ (source >> 24); + srand2 = srand1 ^ (source >> 16); + srand3 = srand2 ^ (source >> 8); +} + +uint32 util_rand() { + uint32 temp = srand0 ^ (srand0 << 11); + srand0 = srand1; + srand1 = srand2; + srand2 = srand3; + srand3 = srand3 ^ (srand3 >> 19) ^ temp ^ (temp >> 8); + return srand3; } \ No newline at end of file diff --git a/src/util/util.h b/src/util/util.h index e8d8cca36d..23ea66c2d2 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -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 . *****************************************************************************/ @@ -27,18 +27,24 @@ int squaredmetres_to_squaredfeet(int squaredMetres); int metres_to_feet(int metres); int mph_to_kmph(int mph); -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); +bool filename_valid_characters(const utf8 *filename); + +const char *path_get_filename(const utf8 *path); +const char *path_get_extension(const utf8 *path); +void path_set_extension(utf8 *path, const utf8 *newExtension); +void path_remove_extension(utf8 *path); +bool readentirefile(const utf8 *path, void **outBuffer, int *outLength); int bitscanforward(int source); +int bitcount(int source); bool strequals(const char *a, const char *b, int length, bool caseInsensitive); int strcicmp(char const *a, char const *b); +char *safe_strncpy(char * destination, const char * source, size_t num); bool utf8_is_bom(const char *str); bool str_is_null_or_empty(const char *str); +void util_srand(int source); +uint32 util_rand(); + #endif diff --git a/src/windows/about.c b/src/windows/about.c index 9cc7045cd9..a513d5bf41 100644 --- a/src/windows/about.c +++ b/src/windows/about.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 . *****************************************************************************/ @@ -42,43 +42,42 @@ rct_widget window_about_widgets[] = { { WIDGETS_END }, }; -static void window_about_emptysub() { } -static void window_about_mouseup(); -static void window_about_paint(); +static void window_about_mouseup(rct_window *w, int widgetIndex); +static void window_about_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void* window_about_events[] = { - window_about_emptysub, +static rct_window_event_list window_about_events = { + NULL, window_about_mouseup, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, - window_about_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_about_paint, - window_about_emptysub + NULL }; /** - * + * * rct2: 0x0066D2AC */ void window_about_open() @@ -93,7 +92,7 @@ void window_about_open() window = window_create_centred( 400, 330, - (uint32*)window_about_events, + &window_about_events, WC_ABOUT, 0 ); @@ -107,16 +106,11 @@ void window_about_open() } /** - * + * * rct2: 0x0066D4D5 */ -static void window_about_mouseup() +static void window_about_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -131,16 +125,12 @@ static void window_about_mouseup() } /** - * + * * rct2: 0x0066D321 */ -static void window_about_paint() +static void window_about_paint(rct_window *w, rct_drawpixelinfo *dpi) { int x, y; - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); window_draw_widgets(w, dpi); @@ -150,7 +140,7 @@ static void window_about_paint() // Version RCT2_GLOBAL(0x009C383C, uint8) = 49; gfx_draw_string_centred(dpi, STR_VERSION_X, x, y, 0, (void*)0x009E2D28); - + // Credits RCT2_GLOBAL(0x009C383C, uint8) = 48; y += 10; diff --git a/src/windows/banner.c b/src/windows/banner.c index b33b94fcdb..d084a8de62 100644 --- a/src/windows/banner.c +++ b/src/windows/banner.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 . *****************************************************************************/ @@ -63,44 +63,43 @@ rct_widget window_banner_widgets[] = { { WIDGETS_END }, }; -static void window_banner_emptysub() { } -static void window_banner_mouseup(); +static void window_banner_mouseup(rct_window *w, int widgetIndex); static void window_banner_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_banner_dropdown(); -static void window_banner_textinput(); -static void window_banner_invalidate(); -static void window_banner_paint(); -static void window_banner_unknown_14(); +static void window_banner_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); +static void window_banner_textinput(rct_window *w, int widgetIndex, char *text); +static void window_banner_unknown_14(rct_window *w); +static void window_banner_invalidate(rct_window *w); +static void window_banner_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void* window_banner_events[] = { - window_banner_emptysub, +static rct_window_event_list window_banner_events = { + NULL, window_banner_mouseup, - window_banner_emptysub, - window_banner_mousedown, - window_banner_dropdown, - window_banner_emptysub, - window_banner_emptysub, - window_banner_emptysub, - window_banner_emptysub, - window_banner_emptysub, - window_banner_emptysub, - window_banner_emptysub, - window_banner_emptysub, - window_banner_emptysub, - window_banner_emptysub, - window_banner_emptysub, - window_banner_emptysub, - window_banner_emptysub, - window_banner_emptysub, + NULL, + window_banner_mousedown, + window_banner_dropdown, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_banner_textinput, window_banner_unknown_14, - window_banner_emptysub, - window_banner_emptysub, - window_banner_emptysub, - window_banner_emptysub, + NULL, + NULL, + NULL, + NULL, window_banner_invalidate, - window_banner_paint, - window_banner_emptysub + window_banner_paint, + NULL }; /** @@ -118,7 +117,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, WF_2); + w = window_create_auto_pos(WW, WH, &window_banner_events, WC_BANNER, WF_NO_SCROLLING); w->widgets = window_banner_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | @@ -134,7 +133,7 @@ void window_banner_open(rct_windownumber number) int view_x = gBanners[w->number].x << 5; int view_y = gBanners[w->number].y << 5; - + rct_map_element* map_element = map_get_first_element_at(view_x / 32, view_y / 32); while(1) { if ( @@ -174,13 +173,8 @@ void window_banner_open(rct_windownumber number) } /* rct2: 0x6ba4d6*/ -static void window_banner_mouseup() +static void window_banner_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - rct_banner* banner = &gBanners[w->number]; int x = banner->x << 5; int y = banner->y << 5; @@ -205,13 +199,7 @@ static void window_banner_mouseup() break; case WIDX_BANNER_NO_ENTRY: textinput_cancel(); - banner->flags ^= BANNER_FLAG_NO_ENTRY; - window_invalidate(w); - - map_element->properties.banner.flags = 0xFF; - if (banner->flags & BANNER_FLAG_NO_ENTRY){ - map_element->properties.banner.flags &= ~(1 << map_element->properties.banner.position); - } + game_do_command(1, GAME_COMMAND_FLAG_APPLY, w->number, banner->colour, GAME_COMMAND_SET_BANNER_STYLE, banner->text_colour, banner->flags ^ BANNER_FLAG_NO_ENTRY); break; } } @@ -226,115 +214,64 @@ static void window_banner_mousedown(int widgetIndex, rct_window*w, rct_widget* w window_dropdown_show_colour(w, widget, w->colours[1] | 0x80, banner->colour); break; case WIDX_TEXT_COLOR_DROPDOWN_BUTTON: - + for( int i = 0; i < 13; ++i){ gDropdownItemsFormat[i] = 1142; gDropdownItemsArgs[i] = 2997 + i; } - + //Switch to the dropdown box widget. widget--; window_dropdown_show_text_custom_width( - widget->left + w->x, - widget->top + w->y, + widget->left + w->x, + widget->top + w->y, widget->bottom - widget->top + 1, - w->colours[1], + w->colours[1], DROPDOWN_FLAG_STAY_OPEN, - 13, + 13, widget->right - widget->left - 3); - - gDropdownItemsChecked = 1 << (banner->text_colour - 1); + + dropdown_set_checked(banner->text_colour - 1, true); break; } } /* rct2: 0x6ba517 */ -static void window_banner_dropdown() +static void window_banner_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - short widgetIndex, dropdownIndex; - rct_window* w; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - rct_banner* banner = &gBanners[w->number]; switch(widgetIndex){ case WIDX_MAIN_COLOR: - if ( dropdownIndex == 0xFFFF) return; - banner->colour = (uint8)dropdownIndex; - window_invalidate(w); + if (dropdownIndex == -1) + break; + + game_do_command(1, GAME_COMMAND_FLAG_APPLY, w->number, dropdownIndex, GAME_COMMAND_SET_BANNER_STYLE, banner->text_colour, 0); break; case WIDX_TEXT_COLOR_DROPDOWN_BUTTON: - if ( dropdownIndex == 0xFFFF) return; - banner->text_colour = dropdownIndex + 1; + if (dropdownIndex == -1) + break; - //Can be replaced with a buffer 34 chars wide ( 32 character + 1 colour_format + 1 '\0') - uint8* text_buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, uint8); - - format_string(text_buffer, banner->string_idx, 0); - - if (text_buffer[0] < FORMAT_COLOUR_CODE_START - || text_buffer[0] > FORMAT_COLOUR_CODE_END){ - int end_point = strlen(text_buffer) + 1; - strncpy(text_buffer + 1, text_buffer, 32); - text_buffer[end_point] = '\0'; - } - - text_buffer[0] = banner->text_colour + FORMAT_COLOUR_CODE_START; - - 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 = stringId; - user_string_free(prev_string_id); - window_invalidate(w); - } else { - window_error_open(2984, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id)); - } + game_do_command(1, GAME_COMMAND_FLAG_APPLY, w->number, banner->colour, GAME_COMMAND_SET_BANNER_STYLE, dropdownIndex + 1, 0); break; } } /* rct2: 0x6ba50c */ -static void window_banner_textinput() +static void window_banner_textinput(rct_window *w, int widgetIndex, char *text) { - short widgetIndex; - rct_window *w; - uint8 result; - uint8* text; - - window_text_input_get_registers(w, widgetIndex, result, text); - - - if (widgetIndex == WIDX_BANNER_TEXT && result) { - - rct_banner* banner = &gBanners[w->number]; - - uint8* text_buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, uint8); - - text_buffer[0] = banner->text_colour + FORMAT_COLOUR_CODE_START; - strncpy(text_buffer + 1, text, 32); - - rct_string_id stringId = user_string_allocate(128, text_buffer); - if (stringId) { - rct_string_id prev_string_id = banner->string_idx; - banner->string_idx = stringId; - user_string_free(prev_string_id); - window_invalidate(w); - } else { - window_error_open(2984, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id)); - } + if (widgetIndex == WIDX_BANNER_TEXT && text != NULL) { + game_do_command(1, GAME_COMMAND_FLAG_APPLY, w->number, *((int*)(text + 0)), GAME_COMMAND_SET_BANNER_NAME, *((int*)(text + 8)), *((int*)(text + 4))); + game_do_command(2, GAME_COMMAND_FLAG_APPLY, w->number, *((int*)(text + 12)), GAME_COMMAND_SET_BANNER_NAME, *((int*)(text + 20)), *((int*)(text + 16))); + game_do_command(0, GAME_COMMAND_FLAG_APPLY, w->number, *((int*)(text + 24)), GAME_COMMAND_SET_BANNER_NAME, *((int*)(text + 32)), *((int*)(text + 28))); } } /* rct2: 0x006BA44D */ -static void window_banner_invalidate() +static void window_banner_invalidate(rct_window *w) { - rct_window* w; - - window_get_register(w); colour_scheme_update(w); rct_banner* banner = &gBanners[w->number]; @@ -345,16 +282,16 @@ static void window_banner_invalidate() rct_scenery_entry* sceneryEntry = g_bannerSceneryEntries[banner->type]; if (sceneryEntry->banner.flags & 1) colour_btn->type = WWT_COLORBTN; - + w->pressed_widgets &= ~(1ULL<disabled_widgets &= ~( (1ULL<flags & BANNER_FLAG_NO_ENTRY){ w->pressed_widgets |= (1ULL<disabled_widgets |= + w->disabled_widgets |= (1ULL<viewport; w->viewport = 0; diff --git a/src/windows/changelog.c b/src/windows/changelog.c index 1faa85ba46..fa37953a29 100644 --- a/src/windows/changelog.c +++ b/src/windows/changelog.c @@ -32,41 +32,40 @@ rct_widget window_changelog_widgets[] = { { 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_close(rct_window *w); +static void window_changelog_mouseup(rct_window *w, int widgetIndex); +static void window_changelog_resize(rct_window *w); +static void window_changelog_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_changelog_invalidate(rct_window *w); +static void window_changelog_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_changelog_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void* window_changelog_events[] = { +static rct_window_event_list 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_changelog_invalidate, window_changelog_paint, window_changelog_scrollpaint @@ -98,7 +97,7 @@ rct_window *window_changelog_open() window = window_create_centred( screenWidth * 4 / 5, screenHeight * 4 / 5, - (uint32*)window_changelog_events, + &window_changelog_events, WC_CHANGELOG, WF_RESIZABLE ); @@ -116,18 +115,13 @@ rct_window *window_changelog_open() return window; } -static void window_changelog_close() +static void window_changelog_close(rct_window *w) { window_changelog_dispose_file(); } -static void window_changelog_mouseup() +static void window_changelog_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -135,12 +129,8 @@ static void window_changelog_mouseup() } } -static void window_changelog_resize() +static void window_changelog_resize(rct_window *w) { - 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); @@ -159,24 +149,14 @@ static void window_changelog_resize() } } -static void window_changelog_scrollgetsize() +static void window_changelog_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - rct_window *w; - int width, height; - window_get_register(w); - - width = _changelogLongestLineWidth + 4; - height = _changelogNumLines * 11; - - window_scrollsize_set_registers(width, height); + *width = _changelogLongestLineWidth + 4; + *height = _changelogNumLines * 11; } -static void window_changelog_invalidate() +static void window_changelog_invalidate(rct_window *w) { - 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; @@ -188,23 +168,13 @@ static void window_changelog_invalidate() window_changelog_widgets[WIDX_SCROLL].bottom = w->height - 15; } -static void window_changelog_paint() +static void window_changelog_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); } -static void window_changelog_scrollpaint() +static void window_changelog_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { - 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; @@ -222,9 +192,9 @@ static void window_changelog_scrollpaint() static bool window_changelog_read_file() { window_changelog_dispose_file(); - char path[MAX_PATH]; + utf8 path[MAX_PATH]; sprintf(path, "%s%cchangelog.txt", gExePath, platform_get_path_separator()); - if (!readentirefile(path, &_changelogText, &_changelogTextSize)) { + if (!readentirefile(path, (void**)&_changelogText, (int*)&_changelogTextSize)) { log_error("Unable to read changelog.txt"); return false; } @@ -276,4 +246,4 @@ static void window_changelog_dispose_file() 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 3048369028..e905ac7577 100644 --- a/src/windows/cheats.c +++ b/src/windows/cheats.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 . *****************************************************************************/ @@ -33,13 +33,16 @@ #include "../world/footpath.h" #include "../world/park.h" #include "../world/sprite.h" +#include "../world/scenery.h" #include "../interface/themes.h" #include "../cheats.h" +#include "error.h" -//#define WW 200 -//#define WH 128 #define CHEATS_MONEY_INCREMENT MONEY(5000,00) #define CHEATS_TRAM_INCREMENT 250 + +#define CHEATS_PARK_RATING_SPINNER_PAUSE 20 + enum { WINDOW_CHEATS_PAGE_MONEY, WINDOW_CHEATS_PAGE_GUESTS, @@ -57,130 +60,210 @@ enum WINDOW_CHEATS_WIDGET_IDX { WIDX_TAB_3, WIDX_TAB_4, WIDX_HIGH_MONEY, - WIDX_PARK_ENTRANCE_FEE, WIDX_CLEAR_LOAN, - WIDX_HAPPY_GUESTS = 8, //Same as HIGH_MONEY as it is also the 8th widget but on a different page + WIDX_GUEST_PARAMETERS_GROUP = 8, //Same as HIGH_MONEY as it is also the 8th widget but on a different page + WIDX_GUEST_HAPPINESS_MAX, + WIDX_GUEST_HAPPINESS_MIN, + WIDX_GUEST_ENERGY_MAX, + WIDX_GUEST_ENERGY_MIN, + WIDX_GUEST_HUNGER_MAX, + WIDX_GUEST_HUNGER_MIN, + WIDX_GUEST_THIRST_MAX, + WIDX_GUEST_THIRST_MIN, + WIDX_GUEST_NAUSEA_MAX, + WIDX_GUEST_NAUSEA_MIN, + WIDX_GUEST_NAUSEA_TOLERANCE_MAX, + WIDX_GUEST_NAUSEA_TOLERANCE_MIN, + WIDX_GUEST_BATHROOM_MAX, + WIDX_GUEST_BATHROOM_MIN, + WIDX_GUEST_RIDE_INTENSITY_MORE_THAN_1, + WIDX_GUEST_RIDE_INTENSITY_LESS_THAN_15, + WIDX_GUEST_IGNORE_RIDE_INTENSITY, + WIDX_DISABLE_VANDALISM, + WIDX_GIVE_ALL_GUESTS_GROUP, + WIDX_GIVE_GUESTS_MONEY, + WIDX_GIVE_GUESTS_PARK_MAPS, + WIDX_GIVE_GUESTS_BALLOONS, + WIDX_GIVE_GUESTS_UMBRELLAS, WIDX_TRAM_GUESTS, - WIDX_NAUSEA_GUESTS, + WIDX_REMOVE_ALL_GUESTS, WIDX_EXPLODE_GUESTS, - WIDX_FREEZE_CLIMATE = 8, + WIDX_GENERAL_GROUP = 8, WIDX_OPEN_CLOSE_PARK, - WIDX_ZERO_CLEARANCE, + WIDX_PARK_PARAMETERS, + WIDX_SANDBOX_MODE, + WIDX_UNLOCK_ALL_PRICES, + WIDX_FORCE_PARK_RATING, + WIDX_PARK_RATING_SPINNER, + WIDX_INCREASE_PARK_RATING, + WIDX_DECREASE_PARK_RATING, + WIDX_WIN_SCENARIO, + WIDX_HAVE_FUN, + WIDX_CLIMATE_GROUP, + WIDX_FREEZE_CLIMATE, WIDX_WEATHER_SUN, WIDX_WEATHER_THUNDER, + WIDX_STAFF_GROUP, 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_FAST_STAFF, + WIDX_NORMAL_STAFF, 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 + WIDX_BUILD_IN_PAUSE_MODE, + WIDX_RESET_CRASH_STATUS, + WIDX_10_MINUTE_INSPECTIONS, + WIDX_SHOW_ALL_OPERATING_MODES, + WIDX_SHOW_VEHICLES_FROM_OTHER_TRACK_TYPES +}; + +enum { + GUEST_PARAMETER_HAPPINESS, + GUEST_PARAMETER_ENERGY, + GUEST_PARAMETER_HUNGER, + GUEST_PARAMETER_THIRST, + GUEST_PARAMETER_NAUSEA, + GUEST_PARAMETER_NAUSEA_TOLERANCE, + GUEST_PARAMETER_BATHROOM, + GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY +}; + +enum { + OBJECT_MONEY, + OBJECT_PARK_MAP, + OBJECT_BALLOON, + OBJECT_UMBRELLA }; #pragma region MEASUREMENTS -#define WW 240 -#define WH 240 -#define TAB_HEIGHT 43 -#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 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 WW 249 +#define WH 300 +#define TAB_HEIGHT 43 +#define XSPA 5 // X spacing +#define YSPA 5 // Y spacing +#define XOS 6 + XSPA // X offset from left +#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 GROUP_SPACE 6 + +#define YPL(ROW) ((sint16)(YOS + ((BTNH + YSPA) * ROW))) +#define HPL(ROW) ((sint16)(YPL(ROW) + BTNH)) +#define OHPL(ROW) ((sint16)(YPL(ROW) + OPTH)) +#define XPL(COL) ((sint16)(XOS + ((BTNW + XSPA) * COL))) +#define WPL(COL) ((sint16)(XPL(COL) + BTNW)) +#define OWPL ((sint16)(XPL(0) + OPTW)) + +#define MIN_BTN_LEFT ((sint16)(XPL(1))) +#define MIN_BTN_RIGHT ((sint16)(WPL(1) - (BTNW / 2))) +#define MAX_BTN_LEFT ((sint16)(XPL(1.5))) +#define MAX_BTN_RIGHT ((sint16)(WPL(1))) #define TXTO 3 //text horizontal offset from button left (for button text) #pragma endregion +#define MAIN_CHEATS_WIDGETS \ + { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, STR_NONE }, /* panel / background */ \ + { WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_CHEAT_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_IMGBTN, 1, 0, WW - 1, 43, WH - 1, 0x0FFFFFFFF, STR_NONE }, /* 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 */ + 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, 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 + MAIN_CHEATS_WIDGETS, + { 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(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, 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 + MAIN_CHEATS_WIDGETS, + { WWT_GROUPBOX, 1, XPL(0) - GROUP_SPACE, WPL(1) + GROUP_SPACE, YPL(0), HPL(11.5), STR_CHEAT_SET_GUESTS_PARAMETERS, STR_NONE }, // Guests parameters group frame + { WWT_CLOSEBOX, 1, MAX_BTN_LEFT, MAX_BTN_RIGHT, YPL(1), HPL(1), STR_MAX, STR_NONE }, // happiness max + { WWT_CLOSEBOX, 1, MIN_BTN_LEFT, MIN_BTN_RIGHT, YPL(1), HPL(1), STR_MIN, STR_NONE }, // happiness min + { WWT_CLOSEBOX, 1, MAX_BTN_LEFT, MAX_BTN_RIGHT, YPL(2), HPL(2), STR_MAX, STR_NONE }, // energy max + { WWT_CLOSEBOX, 1, MIN_BTN_LEFT, MIN_BTN_RIGHT, YPL(2), HPL(2), STR_MIN, STR_NONE }, // energy min + { WWT_CLOSEBOX, 1, MAX_BTN_LEFT, MAX_BTN_RIGHT, YPL(3), HPL(3), STR_MAX, STR_NONE }, // hunger max + { WWT_CLOSEBOX, 1, MIN_BTN_LEFT, MIN_BTN_RIGHT, YPL(3), HPL(3), STR_MIN, STR_NONE }, // hunger min + { WWT_CLOSEBOX, 1, MAX_BTN_LEFT, MAX_BTN_RIGHT, YPL(4), HPL(4), STR_MAX, STR_NONE }, // thirst max + { WWT_CLOSEBOX, 1, MIN_BTN_LEFT, MIN_BTN_RIGHT, YPL(4), HPL(4), STR_MIN, STR_NONE }, // thirst min + { WWT_CLOSEBOX, 1, MAX_BTN_LEFT, MAX_BTN_RIGHT, YPL(5), HPL(5), STR_MAX, STR_NONE }, // nausea max + { WWT_CLOSEBOX, 1, MIN_BTN_LEFT, MIN_BTN_RIGHT, YPL(5), HPL(5), STR_MIN, STR_NONE }, // nausea min + { WWT_CLOSEBOX, 1, MAX_BTN_LEFT, MAX_BTN_RIGHT, YPL(6), HPL(6), STR_MAX, STR_NONE }, // nausea tolerance max + { WWT_CLOSEBOX, 1, MIN_BTN_LEFT, MIN_BTN_RIGHT, YPL(6), HPL(6), STR_MIN, STR_NONE }, // nausea tolerance min + { WWT_CLOSEBOX, 1, MAX_BTN_LEFT, MAX_BTN_RIGHT, YPL(7), HPL(7), STR_MAX, STR_NONE }, // bathroom max + { WWT_CLOSEBOX, 1, MIN_BTN_LEFT, MIN_BTN_RIGHT, YPL(7), HPL(7), STR_MIN, STR_NONE }, // bathroom min + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(9), HPL(9), STR_CHEAT_MORE_THAN_1, STR_NONE }, // ride intensity > 1 + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(9), HPL(9), STR_CHEAT_LESS_THAN_15, STR_NONE }, // ride intensity < 15 + { WWT_CHECKBOX, 2, XPL(0), OWPL, YPL(10), OHPL(10), STR_CHEAT_IGNORE_INTENSITY, STR_NONE }, // guests ignore intensity + { WWT_CHECKBOX, 2, XPL(0), OWPL, YPL(11), OHPL(11), STR_CHEAT_DISABLE_VANDALISM, STR_CHEAT_DISABLE_VANDALISM_TIP }, // disable vandalism + { WWT_GROUPBOX, 1, XPL(0) - GROUP_SPACE, WPL(1) + GROUP_SPACE, YPL(13), HPL(15.5), STR_CHEAT_GIVE_ALL_GUESTS, STR_NONE }, // Guests parameters group frame + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(14), HPL(14), STR_CHEAT_CURRENCY_FORMAT, STR_NONE }, // give guests money + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(14), HPL(14), STR_SHOP_ITEM_PLURAL_PARK_MAP, STR_NONE }, // give guests park maps + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(15), HPL(15), STR_SHOP_ITEM_PLURAL_BALLOON, STR_NONE }, // give guests balloons + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(15), HPL(15), STR_SHOP_ITEM_PLURAL_UMBRELLA, STR_NONE }, // give guests umbrellas + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(17), HPL(17), STR_CHEAT_LARGE_TRAM_GUESTS, STR_CHEAT_TIP_LARGE_TRAM_GUESTS }, // large tram + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(17), HPL(17), STR_CHEAT_REMOVE_ALL_GUESTS, STR_CHEAT_TIP_REMOVE_ALL_GUESTS }, // remove all guests + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(18), HPL(18), STR_CHEAT_EXPLODE, STR_CHEAT_TIP_EXPLODE }, // 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, 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) + MAIN_CHEATS_WIDGETS, + { WWT_GROUPBOX, 1, XPL(0) - GROUP_SPACE, WPL(1) + GROUP_SPACE, YPL(0), HPL(5.5), STR_CHEAT_GENERAL_GROUP, STR_NONE }, // General group + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), STR_CHEAT_OPEN_PARK, STR_NONE}, // open / close park + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(1), HPL(1), STR_CHEAT_PARK_PARAMETERS, STR_CHEAT_TIP_PARK_PARAMETERS}, // Park parameters + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(2), HPL(2), STR_CHEAT_SANDBOX_MODE, STR_CHEAT_SANDBOX_MODE_TIP}, // Sandbox mode (edit land ownership in-game) + { WWT_CHECKBOX, 1, XPL(0), OWPL, YPL(3), OHPL(3), STR_CHEAT_UNLOCK_PRICES, STR_NONE}, // Unlock all prices + { WWT_CHECKBOX, 1, XPL(0), WPL(0), YPL(4), HPL(4), STR_FORCE_PARK_RATING, STR_NONE}, // Force park rating + { WWT_SPINNER, 1, XPL(1), WPL(1) - 10, YPL(4) + 2, HPL(4) - 3, STR_NONE, STR_NONE }, // park rating + { WWT_DROPDOWN_BUTTON, 1, WPL(1) - 10, WPL(1), YPL(4) + 3, YPL(4) + 7, STR_NUMERIC_UP, STR_NONE }, // increase rating + { WWT_DROPDOWN_BUTTON, 1, WPL(1) - 10, WPL(1), YPL(4) + 8, YPL(4) + 12, STR_NUMERIC_DOWN, STR_NONE }, // decrease rating + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(5), HPL(5), STR_CHEAT_WIN_SCENARIO, STR_NONE}, // Win scenario + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(5), HPL(5), STR_CHEAT_HAVE_FUN, STR_NONE}, // Have fun! + { WWT_GROUPBOX, 1, XPL(0) - GROUP_SPACE, WPL(1) + GROUP_SPACE, YPL(7), HPL(9.5), STR_CHEAT_CLIMATE_GROUP, STR_NONE }, // Climate group + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(8), HPL(8), STR_CHEAT_FREEZE_CLIMATE, STR_NONE}, // Freeze climate + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(9), HPL(9), STR_CHEAT_FORCE_SUN, STR_NONE}, // Sun + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(9), HPL(9), STR_CHEAT_FORCE_THUNDER, STR_NONE}, // Thunder + { WWT_GROUPBOX, 1, XPL(0) - GROUP_SPACE, WPL(1) + GROUP_SPACE, YPL(11), HPL(15.5), STR_CHEAT_STAFF_GROUP, STR_NONE }, // Staff group + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(12), HPL(12), STR_CHEAT_CLEAR_GRASS, STR_NONE}, // Clear grass + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(12), HPL(12), STR_CHEAT_MOWED_GRASS, STR_NONE}, // Mowed grass + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(13), HPL(13), STR_CHEAT_WATER_PLANTS, STR_NONE}, // Water plants + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(13), HPL(13), STR_CHEAT_FIX_VANDALISM, STR_NONE}, // Fix vandalism + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(14), HPL(14), STR_CHEAT_REMOVE_LITTER, STR_NONE}, // Remove litter + { WWT_CLOSEBOX, 1, MAX_BTN_LEFT, MAX_BTN_RIGHT, YPL(15), HPL(15), STR_FAST, STR_NONE }, // Fast staff + { WWT_CLOSEBOX, 1, MIN_BTN_LEFT, MIN_BTN_RIGHT, YPL(15), HPL(15), STR_NORMAL, STR_NONE }, // Normal staff + + { 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 + MAIN_CHEATS_WIDGETS, + { 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(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(11), OHPL(11) + 8, STR_CHEAT_410_HILL_LIFT, STR_NONE }, // 410 km/h lift hill + { WWT_CHECKBOX, 2, XPL(0), OWPL, YPL(9), OHPL(9), STR_CHEAT_DISABLE_BRAKES_FAILURE, STR_NONE }, // Disable brakes failure + { WWT_CHECKBOX, 2, XPL(0), OWPL, YPL(10), OHPL(10), STR_CHEAT_DISABLE_BREAKDOWNS, STR_NONE }, // Disable all breakdowns + { WWT_CHECKBOX, 2, XPL(0), OWPL, YPL(8), OHPL(8), STR_CHEAT_BUILD_IN_PAUSE_MODE, STR_NONE }, // Build in pause mode + { WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(2), HPL(2), STR_CHEAT_RESET_CRASH_STATUS, STR_NONE }, // Reset crash status + { WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(2), HPL(2), STR_CHEAT_10_MINUTE_INSPECTIONS, STR_CHEAT_10_MINUTE_INSPECTIONS_TIP }, // 10 minute inspections + { WWT_CHECKBOX, 2, XPL(0), OWPL, YPL(7), OHPL(7), STR_CHEAT_SHOW_ALL_OPERATING_MODES, STR_NONE }, // Show all operating modes + { WWT_CHECKBOX, 2, XPL(0), OWPL, YPL(6), OHPL(6), STR_CHEAT_SHOW_VEHICLES_FROM_OTHER_TRACK_TYPES, STR_NONE }, // Show vehicles from other track types { WIDGETS_END }, }; @@ -191,159 +274,166 @@ static rct_widget *window_cheats_page_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(); -static void window_cheats_rides_mouseup(); -static void window_cheats_misc_tool_update(); -static void window_cheats_misc_tool_down(); +static void window_cheats_money_mouseup(rct_window *w, int widgetIndex); +static void window_cheats_guests_mouseup(rct_window *w, int widgetIndex); +static void window_cheats_misc_mouseup(rct_window *w, int widgetIndex); +static void window_cheats_rides_mouseup(rct_window *w, int widgetIndex); static void window_cheats_update(rct_window *w); -static void window_cheats_invalidate(); -static void window_cheats_paint(); +static void window_cheats_invalidate(rct_window *w); +static void window_cheats_paint(rct_window *w, rct_drawpixelinfo *dpi); static void window_cheats_set_page(rct_window *w, int page); -static void* window_cheats_money_events[] = { - window_cheats_emptysub, +static rct_window_event_list window_cheats_money_events = { + NULL, window_cheats_money_mouseup, - window_cheats_emptysub, - window_cheats_emptysub, - window_cheats_emptysub, - window_cheats_emptysub, + NULL, + NULL, + NULL, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_cheats_invalidate, window_cheats_paint, - window_cheats_emptysub + NULL }; -static void* window_cheats_guests_events[] = { - window_cheats_emptysub, +static rct_window_event_list window_cheats_guests_events = { + NULL, window_cheats_guests_mouseup, - window_cheats_emptysub, - window_cheats_emptysub, - window_cheats_emptysub, - window_cheats_emptysub, + NULL, + NULL, + NULL, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_cheats_invalidate, window_cheats_paint, - window_cheats_emptysub + NULL }; -static void* window_cheats_misc_events[] = { - window_cheats_emptysub, +static rct_window_event_list window_cheats_misc_events = { + NULL, window_cheats_misc_mouseup, - window_cheats_emptysub, - window_cheats_emptysub, - window_cheats_emptysub, - window_cheats_emptysub, + NULL, + NULL, + NULL, + NULL, window_cheats_update, - window_cheats_emptysub, - window_cheats_emptysub, - window_cheats_misc_tool_update, - window_cheats_misc_tool_down, - 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_cheats_invalidate, window_cheats_paint, - window_cheats_emptysub + NULL }; -static void* window_cheats_rides_events[] = { - window_cheats_emptysub, +static rct_window_event_list window_cheats_rides_events = { + NULL, window_cheats_rides_mouseup, - window_cheats_emptysub, - window_cheats_emptysub, - window_cheats_emptysub, - window_cheats_emptysub, + NULL, + NULL, + NULL, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_cheats_invalidate, window_cheats_paint, - window_cheats_emptysub + NULL }; -static void* window_cheats_page_events[] = { - window_cheats_money_events, - window_cheats_guests_events, - window_cheats_misc_events, - window_cheats_rides_events, +static rct_window_event_list *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_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 uint64 window_cheats_page_enabled_widgets[] = { + (1ULL << WIDX_CLOSE) | (1ULL << WIDX_TAB_1) | (1ULL << WIDX_TAB_2) | (1ULL << WIDX_TAB_3) | (1ULL << WIDX_TAB_4) | (1ULL << WIDX_HIGH_MONEY) | (1ULL << WIDX_CLEAR_LOAN), + (1ULL << WIDX_CLOSE) | (1ULL << WIDX_TAB_1) | (1ULL << WIDX_TAB_2) | (1ULL << WIDX_TAB_3) | (1ULL << WIDX_TAB_4) | (1ULL << WIDX_GUEST_PARAMETERS_GROUP) | (1ULL << WIDX_GUEST_HAPPINESS_MAX) | (1ULL << WIDX_GUEST_HAPPINESS_MIN) | (1ULL << WIDX_GUEST_ENERGY_MAX) | (1ULL << WIDX_GUEST_ENERGY_MIN) | (1ULL << WIDX_GUEST_HUNGER_MAX) | (1ULL << WIDX_GUEST_HUNGER_MIN) | (1ULL << WIDX_GUEST_THIRST_MAX) | (1ULL << WIDX_GUEST_THIRST_MIN) | (1ULL << WIDX_GUEST_NAUSEA_MAX) | (1ULL << WIDX_GUEST_NAUSEA_MIN) | (1ULL << WIDX_GUEST_NAUSEA_TOLERANCE_MAX) | (1ULL << WIDX_GUEST_NAUSEA_TOLERANCE_MIN) | (1ULL << WIDX_GUEST_BATHROOM_MAX) | (1ULL << WIDX_GUEST_BATHROOM_MIN) | (1ULL << WIDX_GUEST_RIDE_INTENSITY_MORE_THAN_1) | (1ULL << WIDX_GUEST_RIDE_INTENSITY_LESS_THAN_15) | (1ULL << WIDX_GUEST_IGNORE_RIDE_INTENSITY) | (1ULL << WIDX_GIVE_ALL_GUESTS_GROUP) | (1ULL << WIDX_GIVE_GUESTS_MONEY) | (1ULL << WIDX_GIVE_GUESTS_PARK_MAPS) | (1ULL << WIDX_GIVE_GUESTS_BALLOONS) | (1ULL << WIDX_GIVE_GUESTS_UMBRELLAS) | (1ULL << WIDX_TRAM_GUESTS) | (1ULL << WIDX_REMOVE_ALL_GUESTS) | (1ULL << WIDX_EXPLODE_GUESTS) | (1ULL << WIDX_DISABLE_VANDALISM), + (1ULL << WIDX_CLOSE) | (1ULL << WIDX_TAB_1) | (1ULL << WIDX_TAB_2) | (1ULL << WIDX_TAB_3) | (1ULL << WIDX_TAB_4) | (1ULL << WIDX_FREEZE_CLIMATE) | (1ULL << WIDX_OPEN_CLOSE_PARK) | (1ULL << WIDX_WEATHER_SUN) | (1ULL << WIDX_WEATHER_THUNDER) | (1ULL << WIDX_CLEAR_GRASS) | (1ULL << WIDX_MOWED_GRASS) | (1ULL << WIDX_WATER_PLANTS) | (1ULL << WIDX_FIX_VANDALISM) | (1ULL << WIDX_REMOVE_LITTER) | (1ULL << WIDX_WIN_SCENARIO) | (1ULL << WIDX_HAVE_FUN) | (1ULL << WIDX_UNLOCK_ALL_PRICES) | (1ULL << WIDX_SANDBOX_MODE) | (1ULL << WIDX_FAST_STAFF) | (1ULL << WIDX_NORMAL_STAFF) | (1ULL << WIDX_PARK_PARAMETERS) | (1ULL << WIDX_FORCE_PARK_RATING) | (1ULL << WIDX_INCREASE_PARK_RATING) | (1ULL << WIDX_DECREASE_PARK_RATING), + (1ULL << WIDX_CLOSE) | (1ULL << WIDX_TAB_1) | (1ULL << WIDX_TAB_2) | (1ULL << WIDX_TAB_3) | (1ULL << WIDX_TAB_4) | (1ULL << WIDX_RENEW_RIDES) | (1ULL << WIDX_MAKE_DESTRUCTIBLE) | (1ULL << WIDX_FIX_ALL) | (1ULL << WIDX_FAST_LIFT_HILL) | (1ULL << WIDX_DISABLE_BRAKES_FAILURE) | (1ULL << WIDX_DISABLE_ALL_BREAKDOWNS) | (1ULL << WIDX_BUILD_IN_PAUSE_MODE) | (1ULL << WIDX_RESET_CRASH_STATUS) | (1ULL << WIDX_10_MINUTE_INSPECTIONS) | (1ULL << WIDX_SHOW_ALL_OPERATING_MODES) | (1ULL << WIDX_SHOW_VEHICLES_FROM_OTHER_TRACK_TYPES) +}; + +static rct_string_id window_cheats_page_titles[] = { + STR_CHEAT_TITLE_FINANCIAL, + STR_CHEAT_TITLE_GUEST, + STR_CHEAT_TITLE_RIDE, + STR_CHEAT_TITLE_PARK, }; static void window_cheats_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w); +int park_rating_spinner_value; +int park_rating_spinner_pressed_for = 0; + #pragma region Cheat functions static void cheat_set_grass_length(int length) @@ -413,6 +503,23 @@ static void cheat_remove_litter() sprite_remove((rct_sprite*)litter); } + map_element_iterator it; + rct_scenery_entry *sceneryEntry; + + 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; + + sceneryEntry = g_pathBitSceneryEntries[(it.element->properties.path.additions & 0xF) - 1]; + if(sceneryEntry->path_bit.var_06 & (1 << 0)) + it.element->properties.path.addition_status = 0xFF; + + } while (map_element_iterator_next(&it)); + gfx_invalidate_screen(); } @@ -432,7 +539,7 @@ static void cheat_fix_rides() remove_peep_from_ride(mechanic); } - RCT2_CALLPROC_X(0x006B7481, 0, 0, 0, rideIndex, 0, 0, 0); + ride_fix_breakdown(rideIndex, 0); ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST; } } @@ -453,18 +560,6 @@ static void cheat_renew_rides() 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; @@ -473,6 +568,35 @@ static void cheat_make_destructible() { if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE) ride->lifecycle_flags&=~RIDE_LIFECYCLE_INDESTRUCTIBLE; + if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) + ride->lifecycle_flags&=~RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK; + } + window_invalidate_by_class(WC_RIDE); +} + +static void cheat_reset_crash_status() +{ + int i; + rct_ride *ride; + + FOR_ALL_RIDES(i, ride){ + //reset crash status + if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED) + ride->lifecycle_flags&=~RIDE_LIFECYCLE_CRASHED; + //reset crash history + ride->last_crash_type=RIDE_CRASH_TYPE_NONE; + } + window_invalidate_by_class(WC_RIDE); +} + +static void cheat_10_minute_inspections() +{ + int i; + rct_ride *ride; + + FOR_ALL_RIDES(i, ride) { + // Set inspection interval to 10 minutes + ride->inspection_interval = RIDE_INSPECTION_EVERY_10_MINUTES; } window_invalidate_by_class(WC_RIDE); } @@ -513,23 +637,100 @@ static void cheat_generate_guests(int count) window_invalidate_by_class(WC_BOTTOM_TOOLBAR); } -static void cheat_make_guests_happy() +static void cheat_set_guest_parameter(int parameter, int value) { int spriteIndex; rct_peep *peep; - FOR_ALL_GUESTS(spriteIndex, peep) - if (peep->var_2A == 0) - peep->happiness = 255; + FOR_ALL_GUESTS(spriteIndex, peep) { + switch(parameter) { + case GUEST_PARAMETER_HAPPINESS: + peep->happiness = value; + break; + case GUEST_PARAMETER_ENERGY: + peep->energy = value; + break; + case GUEST_PARAMETER_HUNGER: + peep->hunger = value; + break; + case GUEST_PARAMETER_THIRST: + peep->thirst = value; + break; + case GUEST_PARAMETER_NAUSEA: + peep->nausea = value; + break; + case GUEST_PARAMETER_NAUSEA_TOLERANCE: + peep->nausea_tolerance = value; + break; + case GUEST_PARAMETER_BATHROOM: + peep->bathroom = value; + break; + case GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY: + peep->intensity = (15 << 4) | value; + break; + } + peep_update_sprite_type(peep); + } + } -static void cheat_make_guests_nauseous() +static void cheat_give_all_guests(int object) { int spriteIndex; rct_peep *peep; - FOR_ALL_GUESTS(spriteIndex, peep) - peep->flags |= PEEP_FLAGS_NAUSEA; + FOR_ALL_GUESTS(spriteIndex, peep) { + switch(object) + { + case OBJECT_MONEY: + peep->cash_in_pocket = MONEY(1000,00); + break; + case OBJECT_PARK_MAP: + peep->item_standard_flags |= PEEP_ITEM_MAP; + break; + case OBJECT_BALLOON: + peep->item_standard_flags |= PEEP_ITEM_BALLOON; + peep->balloon_colour=scenario_rand_max(31); + peep_update_sprite_type(peep); + break; + case OBJECT_UMBRELLA: + peep->item_standard_flags |= PEEP_ITEM_UMBRELLA; + peep->umbrella_colour=scenario_rand_max(31); + peep_update_sprite_type(peep); + break; + } + } + window_invalidate_by_class(WC_PEEP); +} + +static void cheat_remove_all_guests() +{ + rct_peep *peep; + uint16 spriteIndex, nextSpriteIndex; + + for (spriteIndex = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_PEEP, uint16); spriteIndex != SPRITE_INDEX_NULL; spriteIndex = nextSpriteIndex) { + peep = &(g_sprite_list[spriteIndex].peep); + nextSpriteIndex = peep->next; + if (peep->type == PEEP_TYPE_GUEST) { + peep_remove(peep); + } + } + + int i; + rct_ride *ride; + + FOR_ALL_RIDES(i, ride) + { + ride_clear_for_construction(i); + ride_set_status(i, RIDE_STATUS_CLOSED); + + for(int i=0;i<4;i++) { + ride->queue_length[i] = 0; + ride->last_peep_in_queue[i]=0xFFFF; + } + } + window_invalidate_by_class(WC_RIDE); + gfx_invalidate_screen(); } static void cheat_explode_guests() @@ -538,12 +739,21 @@ static void cheat_explode_guests() rct_peep *peep; FOR_ALL_GUESTS(sprite_index, peep) { - unsigned int rand = scenario_rand(); - if ((rand & 0x07) == 0) { + if (scenario_rand_max(6) == 0) { peep->flags |= PEEP_FLAGS_EXPLODE; } } +} +static void cheat_set_staff_speed(uint8 value) +{ + uint16 spriteIndex; + rct_peep *peep; + + FOR_ALL_STAFF(spriteIndex, peep) { + peep->energy = value; + peep->energy_growth_rate = value; + } } #pragma endregion @@ -557,20 +767,16 @@ void window_cheats_open() if (window != NULL) return; - window = window_create(32, 32, WW, WH, (uint32*)window_cheats_money_events, WC_CHEATS, 0); + window = window_create(32, 32, WW, WH, &window_cheats_money_events, WC_CHEATS, 0); window->widgets = window_cheats_money_widgets; window->enabled_widgets = window_cheats_page_enabled_widgets[0]; window_init_scroll_widgets(window); - window->page = WINDOW_CHEATS_PAGE_MONEY; + window_cheats_set_page(window, WINDOW_CHEATS_PAGE_MONEY); + park_rating_spinner_value = get_forced_park_rating() >= 0 ? get_forced_park_rating() : 999; } -static void window_cheats_money_mouseup() +static void window_cheats_money_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -587,21 +793,11 @@ static void window_cheats_money_mouseup() case WIDX_CLEAR_LOAN: cheat_clear_loan(); break; - case WIDX_PARK_ENTRANCE_FEE: - 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; } } -static void window_cheats_guests_mouseup() +static void window_cheats_guests_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -612,28 +808,90 @@ static void window_cheats_guests_mouseup() case WIDX_TAB_4: window_cheats_set_page(w, widgetIndex - WIDX_TAB_1); break; - case WIDX_HAPPY_GUESTS: - cheat_make_guests_happy(); + case WIDX_GUEST_HAPPINESS_MAX: + cheat_set_guest_parameter(GUEST_PARAMETER_HAPPINESS,255); + break; + case WIDX_GUEST_HAPPINESS_MIN: + cheat_set_guest_parameter(GUEST_PARAMETER_HAPPINESS,0); + break; + case WIDX_GUEST_ENERGY_MAX: + cheat_set_guest_parameter(GUEST_PARAMETER_ENERGY,127); + break; + case WIDX_GUEST_ENERGY_MIN: + cheat_set_guest_parameter(GUEST_PARAMETER_ENERGY,0); + break; + case WIDX_GUEST_HUNGER_MAX: + cheat_set_guest_parameter(GUEST_PARAMETER_HUNGER,0); + break; + case WIDX_GUEST_HUNGER_MIN: + cheat_set_guest_parameter(GUEST_PARAMETER_HUNGER,255); + break; + case WIDX_GUEST_THIRST_MAX: + cheat_set_guest_parameter(GUEST_PARAMETER_THIRST,0); + break; + case WIDX_GUEST_THIRST_MIN: + cheat_set_guest_parameter(GUEST_PARAMETER_THIRST,255); + break; + case WIDX_GUEST_NAUSEA_MAX: + cheat_set_guest_parameter(GUEST_PARAMETER_NAUSEA,255); + break; + case WIDX_GUEST_NAUSEA_MIN: + cheat_set_guest_parameter(GUEST_PARAMETER_NAUSEA,0); + break; + case WIDX_GUEST_NAUSEA_TOLERANCE_MAX: + cheat_set_guest_parameter(GUEST_PARAMETER_NAUSEA_TOLERANCE,PEEP_NAUSEA_TOLERANCE_HIGH); + break; + case WIDX_GUEST_NAUSEA_TOLERANCE_MIN: + cheat_set_guest_parameter(GUEST_PARAMETER_NAUSEA_TOLERANCE,PEEP_NAUSEA_TOLERANCE_NONE); + break; + case WIDX_GUEST_BATHROOM_MAX: + cheat_set_guest_parameter(GUEST_PARAMETER_BATHROOM,255); + break; + case WIDX_GUEST_BATHROOM_MIN: + cheat_set_guest_parameter(GUEST_PARAMETER_BATHROOM,0); + break; + case WIDX_GUEST_RIDE_INTENSITY_MORE_THAN_1: + cheat_set_guest_parameter(GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY,1); + break; + case WIDX_GUEST_RIDE_INTENSITY_LESS_THAN_15: + cheat_set_guest_parameter(GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY,0); break; case WIDX_TRAM_GUESTS: cheat_generate_guests(CHEATS_TRAM_INCREMENT); break; - case WIDX_NAUSEA_GUESTS: - cheat_make_guests_nauseous(); + case WIDX_REMOVE_ALL_GUESTS: + cheat_remove_all_guests(); break; case WIDX_EXPLODE_GUESTS: cheat_explode_guests(); break; + case WIDX_GIVE_GUESTS_MONEY: + cheat_give_all_guests(OBJECT_MONEY); + break; + case WIDX_GIVE_GUESTS_PARK_MAPS: + cheat_give_all_guests(OBJECT_PARK_MAP); + break; + case WIDX_GIVE_GUESTS_BALLOONS: + cheat_give_all_guests(OBJECT_BALLOON); + break; + case WIDX_GIVE_GUESTS_UMBRELLAS: + cheat_give_all_guests(OBJECT_UMBRELLA); + break; + case WIDX_GUEST_IGNORE_RIDE_INTENSITY: + gConfigCheat.ignore_ride_intensity ^= 1; + config_save_default(); + window_invalidate(w); + break; + case WIDX_DISABLE_VANDALISM: + gConfigCheat.disable_vandalism ^= 1; + config_save_default(); + window_invalidate(w); + break; } } -static void window_cheats_misc_mouseup() +static void window_cheats_misc_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -651,11 +909,6 @@ static void window_cheats_misc_mouseup() case WIDX_OPEN_CLOSE_PARK: park_set_open(park_is_open() ? 0 : 1); break; - case WIDX_ZERO_CLEARANCE: - if (tool_set(w, widgetIndex, 7)) { - return; - } - break; case WIDX_WEATHER_SUN: climate_force_weather(WEATHER_SUNNY); break; @@ -680,6 +933,9 @@ static void window_cheats_misc_mouseup() case WIDX_WIN_SCENARIO: scenario_success(); break; + case WIDX_HAVE_FUN: + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8) = OBJECTIVE_HAVE_FUN; + break; case WIDX_UNLOCK_ALL_PRICES: gConfigCheat.unlock_all_prices ^= 1; config_save_default(); @@ -688,23 +944,46 @@ static void window_cheats_misc_mouseup() window_invalidate_by_class(WC_PARK_INFORMATION); break; case WIDX_SANDBOX_MODE: - gSandboxMode = !gSandboxMode; + gCheatsSandboxMode = !gCheatsSandboxMode; 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; + case WIDX_FAST_STAFF: + cheat_set_staff_speed(0xFF); + break; + case WIDX_NORMAL_STAFF: + cheat_set_staff_speed(0x60); + break; + case WIDX_PARK_PARAMETERS: + window_editor_scenario_options_open(); + break; + case WIDX_FORCE_PARK_RATING: + if (get_forced_park_rating() >= 0){ + set_forced_park_rating(-1); + } else { + set_forced_park_rating(park_rating_spinner_value); + } + break; + case WIDX_INCREASE_PARK_RATING: + park_rating_spinner_value = min(999, 10 * (park_rating_spinner_value / 10 + 1)); + widget_invalidate_by_class(WC_CHEATS, WIDX_PARK_RATING_SPINNER); + if (get_forced_park_rating() >= 0) + set_forced_park_rating(park_rating_spinner_value); + break; + case WIDX_DECREASE_PARK_RATING: + park_rating_spinner_value = max(0, 10 * (park_rating_spinner_value / 10 - 1)); + widget_invalidate_by_class(WC_CHEATS, WIDX_PARK_RATING_SPINNER); + if (get_forced_park_rating() >= 0) + set_forced_park_rating(park_rating_spinner_value); + break; } } -static void window_cheats_rides_mouseup() +static void window_cheats_rides_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -718,9 +997,6 @@ static void window_cheats_rides_mouseup() 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; @@ -746,6 +1022,25 @@ static void window_cheats_rides_mouseup() gConfigCheat.build_in_pause_mode ^= 1; config_save_default(); window_invalidate(w); + break; + case WIDX_RESET_CRASH_STATUS: + cheat_reset_crash_status(); + break; + case WIDX_10_MINUTE_INSPECTIONS: + cheat_10_minute_inspections(); + break; + case WIDX_SHOW_ALL_OPERATING_MODES: + gCheatsShowAllOperatingModes = !gCheatsShowAllOperatingModes; + if (gCheatsShowAllOperatingModes) { + window_error_open(STR_WARNING_IN_CAPS, STR_THIS_FEATURE_IS_CURRENTLY_UNSTABLE); + } + break; + case WIDX_SHOW_VEHICLES_FROM_OTHER_TRACK_TYPES: + gCheatsShowVehiclesFromOtherTrackTypes = !gCheatsShowVehiclesFromOtherTrackTypes; + if (gCheatsShowVehiclesFromOtherTrackTypes) { + window_error_open(STR_WARNING_IN_CAPS, STR_THIS_FEATURE_IS_CURRENTLY_UNSTABLE); + } + break; } } @@ -753,14 +1048,31 @@ static void window_cheats_update(rct_window *w) { w->frame_no++; widget_invalidate(w, WIDX_TAB_1 + w->page); + + if (widget_is_pressed(w, WIDX_INCREASE_PARK_RATING) || widget_is_pressed(w, WIDX_DECREASE_PARK_RATING)) + park_rating_spinner_pressed_for++; + else + park_rating_spinner_pressed_for = 0; + if (park_rating_spinner_pressed_for >= CHEATS_PARK_RATING_SPINNER_PAUSE) + if (!(w->frame_no % 3)){ + if (widget_is_pressed(w, WIDX_INCREASE_PARK_RATING)){ + park_rating_spinner_value = min(999, 10 * (park_rating_spinner_value / 10 + 1)); + widget_invalidate_by_class(WC_CHEATS, WIDX_PARK_RATING_SPINNER); + if (get_forced_park_rating() >= 0) + set_forced_park_rating(park_rating_spinner_value); + } else if (widget_is_pressed(w, WIDX_DECREASE_PARK_RATING)){ + park_rating_spinner_value = max(0, 10 * (park_rating_spinner_value / 10 - 1)); + widget_invalidate_by_class(WC_CHEATS, WIDX_PARK_RATING_SPINNER); + if (get_forced_park_rating() >= 0) + set_forced_park_rating(park_rating_spinner_value); + } + } } -static void window_cheats_invalidate() +static void window_cheats_invalidate(rct_window *w) { int i; - rct_window *w; - window_get_register(w); colour_scheme_update(w); rct_widget *widgets = window_cheats_page_widgets[w->page]; @@ -773,13 +1085,18 @@ static void window_cheats_invalidate() 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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, int) = 50000; + break; + case WINDOW_CHEATS_PAGE_GUESTS: + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, int) = 10000; + widget_set_checkbox_value(w, WIDX_GUEST_IGNORE_RIDE_INTENSITY, gConfigCheat.ignore_ride_intensity); + widget_set_checkbox_value(w, WIDX_DISABLE_VANDALISM, gConfigCheat.disable_vandalism); 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); + widget_set_checkbox_value(w, WIDX_FORCE_PARK_RATING, get_forced_park_rating() >= 0); break; case WINDOW_CHEATS_PAGE_RIDES: RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = 255; @@ -787,6 +1104,8 @@ static void window_cheats_invalidate() 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); + widget_set_checkbox_value(w, WIDX_SHOW_ALL_OPERATING_MODES, gCheatsShowAllOperatingModes); + widget_set_checkbox_value(w, WIDX_SHOW_VEHICLES_FROM_OTHER_TRACK_TYPES, gCheatsShowVehiclesFromOtherTrackTypes); break; } @@ -794,28 +1113,34 @@ static void window_cheats_invalidate() for (i = 0; i < 7; i++) w->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i)); w->pressed_widgets |= 1LL << (WIDX_TAB_1 + w->page); + + // Set title + w->widgets[WIDX_TITLE].image = window_cheats_page_titles[w->page]; } -static void window_cheats_paint() +static void window_cheats_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_cheats_draw_tab_images(dpi, w); if (w->page == WINDOW_CHEATS_PAGE_MONEY){ - 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); + RCT2_GLOBAL(0x0013CE952, money32) = CHEATS_MONEY_INCREMENT; + gfx_draw_string_left(dpi, STR_CHEAT_TIP_5K_MONEY, (void*)0x0013CE952, 0, w->x + XPL(0) + TXTO, w->y + YPL(0) + 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_MISC){ + gfx_draw_string_left(dpi, STR_CHEAT_STAFF_SPEED, NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(15) + TXTO); + gfx_draw_string_right(dpi, 5182, &park_rating_spinner_value, w->colours[2], w->x + WPL(1) - 10 - TXTO, w->y + YPL(4) + TXTO); } else if (w->page == WINDOW_CHEATS_PAGE_GUESTS){ - 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); + gfx_draw_string_left(dpi, STR_CHEAT_GUEST_HAPPINESS, NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(1) + TXTO); + gfx_draw_string_left(dpi, STR_CHEAT_GUEST_ENERGY, NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(2) + TXTO); + gfx_draw_string_left(dpi, STR_CHEAT_GUEST_HUNGER, NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(3) + TXTO); + gfx_draw_string_left(dpi, STR_CHEAT_GUEST_THIRST, NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(4) + TXTO); + gfx_draw_string_left(dpi, STR_CHEAT_GUEST_NAUSEA, NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(5) + TXTO); + gfx_draw_string_left(dpi, STR_CHEAT_GUEST_NAUSEA_TOLERANCE, NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(6) + TXTO); + gfx_draw_string_left(dpi, STR_CHEAT_GUEST_BATHROOM, NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(7) + TXTO); + gfx_draw_string_left(dpi, STR_CHEAT_GUEST_PREFERRED_INTENSITY,NULL, 0, w->x + XPL(0) + TXTO, w->y + YPL(8) + TXTO); } } @@ -830,7 +1155,7 @@ static void window_cheats_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w) sprite_idx += (w->frame_no / 2) % 8; gfx_draw_sprite(dpi, sprite_idx, w->x + w->widgets[WIDX_TAB_1].left, w->y + w->widgets[WIDX_TAB_1].top, 0); } - + // Guests tab if (!(w->disabled_widgets & (1 << WIDX_TAB_2))) { sprite_idx = 5568; @@ -858,74 +1183,25 @@ 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]; + int maxY = 0; + rct_widget *widget = &w->widgets[8]; + while (widget->type != WWT_LAST) { + maxY = max(maxY, widget->bottom); + widget++; + } + maxY += 6; + + window_invalidate(w); + w->height = maxY; + w->widgets[WIDX_BACKGROUND].bottom = maxY - 1; + w->widgets[WIDX_PAGE_BACKGROUND].bottom = maxY - 1; window_invalidate(w); } - -static void window_cheats_misc_tool_update() -{ - short widgetIndex; - rct_window* w; - short x, y; - - window_tool_get_registers(w, widgetIndex, x, y); - - if (widgetIndex != WIDX_ZERO_CLEARANCE) return; - - map_invalidate_selection_rect(); - - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); - - 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, 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; -} - -static void window_cheats_misc_tool_down() -{ - short widgetIndex; - rct_window* w; - short x, y; - - window_tool_get_registers(w, widgetIndex, x, y); - - if (widgetIndex != WIDX_ZERO_CLEARANCE) return; - - int dest_x, dest_y; - footpath_get_coordinates_from_pos(x, y + 16, &dest_x, &dest_y, NULL, NULL); - - 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_x = (dest_x & 0xFFE0) >> 5; - int tile_y = (dest_y & 0xFFE0) >> 5; - - 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; - } - } while (!map_element_is_last_for_tile(mapElement++)); -} diff --git a/src/windows/clear_scenery.c b/src/windows/clear_scenery.c index 88b2c670c7..e6ef342c3d 100644 --- a/src/windows/clear_scenery.c +++ b/src/windows/clear_scenery.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 . *****************************************************************************/ @@ -27,6 +27,9 @@ #include "../interface/window.h" #include "../interface/themes.h" +#define MINIMUM_TOOL_SIZE 1 +#define MAXIMUM_TOOL_SIZE 64 + enum WINDOW_CLEAR_SCENERY_WIDGET_IDX { WIDX_BACKGROUND, WIDX_TITLE, @@ -52,51 +55,49 @@ rct_widget window_clear_scenery_widgets[] = { { WIDGETS_END }, }; - static int window_clear_scenery_should_close(); -static void window_clear_scenery_emptysub() { } -static void window_clear_scenery_close(); -static void window_clear_scenery_mouseup(); +static void window_clear_scenery_close(rct_window *w); +static void window_clear_scenery_mouseup(rct_window *w, int widgetIndex); 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_invalidate(rct_window *w); +static void window_clear_scenery_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_clear_scenery_textinput(rct_window *w, int widgetIndex, char *text); static void window_clear_scenery_inputsize(rct_window *w); -static void* window_clear_scenery_events[] = { +static rct_window_event_list window_clear_scenery_events = { window_clear_scenery_close, window_clear_scenery_mouseup, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, + NULL, + NULL, + NULL, + NULL, window_clear_scenery_update, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_clear_scenery_textinput, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, - window_clear_scenery_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, window_clear_scenery_invalidate, window_clear_scenery_paint, - window_clear_scenery_emptysub + NULL }; /** - * + * * rct2: 0x0068E0A7 */ void window_clear_scenery_open() @@ -107,7 +108,7 @@ 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, 94, (uint32*)window_clear_scenery_events, WC_CLEAR_SCENERY, 0); + window = window_create(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 98, 29, 98, 94, &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) | (1 << WIDX_PREVIEW) | (1 << WIDX_SMALL_SCENERY) | (1 << WIDX_LARGE_SCENERY) | (1 << WIDX_FOOTPATH); @@ -125,7 +126,7 @@ void window_clear_scenery_open() * * rct2: 0x006E6B65 */ -static void window_clear_scenery_close() +static void window_clear_scenery_close(rct_window *w) { // If the tool wasn't changed, turn tool off if (!window_clear_scenery_should_close()) @@ -136,39 +137,22 @@ static void window_clear_scenery_close() * * rct2: 0x0068E185 */ -static void window_clear_scenery_mouseup() +static void window_clear_scenery_mouseup(rct_window *w, int widgetIndex) { - 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; + // Decrement land tool size, if it stays within the limit + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = max(MINIMUM_TOOL_SIZE,RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)-1); // Invalidate the window window_invalidate(w); break; case WIDX_INCREMENT: - // Increment land tool size - RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)++; - - // FEATURE: maximum size is always 7 - limit = 7; - // limit = (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2 ? 7 : 5); - - if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) > limit) - RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = limit; + // Increment land tool size, if it stays within the limit + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = min(MAXIMUM_TOOL_SIZE,RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)+1); // Invalidate the window window_invalidate(w); @@ -191,24 +175,18 @@ static void window_clear_scenery_mouseup() } } -static void window_clear_scenery_textinput() +static void window_clear_scenery_textinput(rct_window *w, int widgetIndex, char *text) { - 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) + if (widgetIndex != WIDX_PREVIEW || text == NULL) return; size = strtol(text, &end, 10); if (*end == '\0') { - if (size < 1) size = 1; - if (size > 7) size = 7; + size=max(MINIMUM_TOOL_SIZE,size); + size=min(MAXIMUM_TOOL_SIZE,size); RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = size; window_invalidate(w); } @@ -216,8 +194,8 @@ static void window_clear_scenery_textinput() static void window_clear_scenery_inputsize(rct_window *w) { - ((uint16*)TextInputDescriptionArgs)[0] = 1; - ((uint16*)TextInputDescriptionArgs)[1] = 7; + ((uint16*)TextInputDescriptionArgs)[0] = MINIMUM_TOOL_SIZE; + ((uint16*)TextInputDescriptionArgs)[1] = MAXIMUM_TOOL_SIZE; window_text_input_open(w, WIDX_PREVIEW, 5128, 5129, STR_NONE, STR_NONE, 3); } @@ -236,37 +214,38 @@ static void window_clear_scenery_update(rct_window *w) * * rct2: 0x0068E115 */ -static void window_clear_scenery_invalidate() +static void window_clear_scenery_invalidate(rct_window *w) { - 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) | (gClearSmallScenery ? (1 << WIDX_SMALL_SCENERY) : 0) | - (gClearLargeScenery ? (1 << WIDX_LARGE_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); + // Update the preview image (for tool sizes up to 7) + window_clear_scenery_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; } /** * * rct2: 0x0068E130 */ -static void window_clear_scenery_paint() +static void window_clear_scenery_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; int x, y; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); + // Draw number for tool sizes bigger than 7 + x = w->x + (window_clear_scenery_widgets[WIDX_PREVIEW].left + window_clear_scenery_widgets[WIDX_PREVIEW].right) / 2; + y = w->y + (window_clear_scenery_widgets[WIDX_PREVIEW].top + window_clear_scenery_widgets[WIDX_PREVIEW].bottom) / 2; + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) > 7) { + gfx_draw_string_centred(dpi, STR_LAND_TOOL_SIZE_VALUE, x, y - 2, 0, &RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)); + } + // 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 + 27; diff --git a/src/windows/demolish_ride_prompt.c b/src/windows/demolish_ride_prompt.c index ba62515caf..0f95dd8269 100644 --- a/src/windows/demolish_ride_prompt.c +++ b/src/windows/demolish_ride_prompt.c @@ -42,60 +42,60 @@ enum WINDOW_RIDE_DEMOLISH_WIDGET_IDX { // 0x009AEBA0 static rct_widget window_ride_demolish_widgets[] = { - { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, STR_NONE, STR_NONE }, - { WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_DEMOLISH_RIDE, STR_WINDOW_TITLE_TIP }, - { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, - { WWT_DROPDOWN_BUTTON, 0, 10, 94, WH - 20, WH - 9, STR_DEMOLISH, STR_NONE }, - { WWT_DROPDOWN_BUTTON, 0, WW - 95, WW - 11, WH - 20, WH - 9, STR_SAVE_PROMPT_CANCEL, STR_NONE }, - { WIDGETS_END } + { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, STR_NONE, STR_NONE }, + { WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_DEMOLISH_RIDE, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_DROPDOWN_BUTTON, 0, 10, 94, WH - 20, WH - 9, STR_DEMOLISH, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 0, WW - 95, WW - 11, WH - 20, WH - 9, STR_SAVE_PROMPT_CANCEL, STR_NONE }, + { WIDGETS_END } }; -static void window_ride_demolish_emptysub(){} -static void window_ride_demolish_mouseup(); -static void window_ride_demolish_invalidate(); -static void window_ride_demolish_paint(); +static void window_ride_demolish_mouseup(rct_window *w, int widgetIndex); +static void window_ride_demolish_invalidate(rct_window *w); +static void window_ride_demolish_paint(rct_window *w, rct_drawpixelinfo *dpi); //0x0098E2E4 -static void* window_ride_demolish_events[] = { - window_ride_demolish_emptysub, +static rct_window_event_list window_ride_demolish_events = { + NULL, window_ride_demolish_mouseup, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, - window_ride_demolish_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_ride_demolish_invalidate, window_ride_demolish_paint, - window_ride_demolish_emptysub + NULL }; /** Based off of rct2: 0x006B486A */ -void window_ride_demolish_prompt_open(int rideIndex){ +void window_ride_demolish_prompt_open(int rideIndex) +{ rct_window *w; w = window_bring_to_front_by_number(WC_DEMOLISH_RIDE_PROMPT, rideIndex); if (w != NULL) return; - w = window_create_centred(WW, WH, (uint32*)window_ride_demolish_events, WC_DEMOLISH_RIDE_PROMPT, WF_TRANSPARENT); + w = window_create_centred(WW, WH, &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); @@ -107,28 +107,22 @@ void window_ride_demolish_prompt_open(int rideIndex){ * * rct2: 0x006B4933 */ -static void window_ride_demolish_mouseup(){ - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - - switch (widgetIndex){ +static void window_ride_demolish_mouseup(rct_window *w, int widgetIndex) +{ + switch (widgetIndex) { case WIDX_DEMOLISH: - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = STR_CANT_DEMOLISH_RIDE; - game_do_command(0, 1, 0, w->number, GAME_COMMAND_7, 0, 0); + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_DEMOLISH_RIDE; + game_do_command(0, 1, 0, w->number, GAME_COMMAND_DEMOLISH_RIDE, 0, 0); break; case WIDX_CANCEL: case WIDX_CLOSE: window_close(w); + break; } } -static void window_ride_demolish_invalidate() +static void window_ride_demolish_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); } @@ -136,12 +130,8 @@ static void window_ride_demolish_invalidate() * * rct2: 0x006B48E5 */ -static void window_ride_demolish_paint(){ - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +static void window_ride_demolish_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ window_draw_widgets(w, dpi); rct_ride* ride = GET_RIDE(w->number); diff --git a/src/windows/dropdown.c b/src/windows/dropdown.c index f8581cf490..2b471441e4 100644 --- a/src/windows/dropdown.c +++ b/src/windows/dropdown.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 . *****************************************************************************/ @@ -47,47 +47,70 @@ int _dropdown_num_columns; int _dropdown_num_rows; int _dropdown_item_width; int _dropdown_item_height; -int _dropdown_highlighted_index; int gDropdownNumItems; uint16 gDropdownItemsFormat[64]; sint64 gDropdownItemsArgs[64]; -// Replaces 0x009DED38 -uint32 gDropdownItemsChecked; -uint32 *gDropdownItemsDisabled = RCT2_ADDRESS(0x009DED34, uint32); +uint64 gDropdownItemsChecked; +uint64 gDropdownItemsDisabled; +bool gDropdownIsColour; +int gDropdownLastColourHover; +int gDropdownHighlightedIndex; -static void window_dropdown_emptysub() { } -static void window_dropdown_paint(); +bool dropdown_is_checked(int index) +{ + return gDropdownItemsChecked & (1ULL << index); +} -static void* window_dropdown_events[] = { - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, - window_dropdown_emptysub, +void dropdown_set_checked(int index, bool value) +{ + if (value) { + gDropdownItemsChecked |= 1ULL << index; + } else { + gDropdownItemsChecked &= ~(1ULL << index); + } +} + +void dropdown_set_disabled(int index, bool value) +{ + if (value) { + gDropdownItemsDisabled |= 1ULL << index; + } else { + gDropdownItemsDisabled &= ~(1ULL << index); + } +} + +static void window_dropdown_paint(rct_window *w, rct_drawpixelinfo *dpi); + +static rct_window_event_list window_dropdown_events = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_dropdown_paint, - window_dropdown_emptysub + NULL }; /** @@ -147,17 +170,17 @@ void window_dropdown_show_text_custom_width(int x, int y, int extray, uint8 colo _dropdown_item_height = 10; if (flags & 0x40) _dropdown_item_height = flags & 0x3F; - + // 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); + if (x + width > RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16)) + x = max(0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - width); + if (y + height > RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16)) + y = max(0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - height); window_dropdown_widgets[WIDX_BACKGROUND].bottom = _dropdown_item_height * num_items + 3; window_dropdown_widgets[WIDX_BACKGROUND].right = _dropdown_item_width + 3; @@ -167,7 +190,7 @@ void window_dropdown_show_text_custom_width(int x, int y, int extray, uint8 colo x, y + extray, window_dropdown_widgets[WIDX_BACKGROUND].right + 1, window_dropdown_widgets[WIDX_BACKGROUND].bottom + 1, - (uint32*)window_dropdown_events, + &window_dropdown_events, WC_DROPDOWN, 0x02 ); @@ -177,18 +200,11 @@ void window_dropdown_show_text_custom_width(int x, int y, int extray, uint8 colo w->colours[0] = colour; // Input state - _dropdown_highlighted_index = -1; - RCT2_GLOBAL(0x009DED34, sint32) = 0; + gDropdownHighlightedIndex = -1; + gDropdownItemsDisabled = 0; gDropdownItemsChecked = 0; + gDropdownIsColour = false; RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, sint8) = INPUT_STATE_DROPDOWN_ACTIVE; - - // Copy the following properties until all use of it is decompiled - RCT2_GLOBAL(0x009DEBA0, sint16) = gDropdownNumItems; - RCT2_GLOBAL(0x009DED44, sint32) = _dropdown_num_columns; - RCT2_GLOBAL(0x009DED48, sint32) = _dropdown_num_rows; - RCT2_GLOBAL(0x009DED40, sint32) = _dropdown_item_width; - RCT2_GLOBAL(0x009DED3C, sint32) = _dropdown_item_height; - RCT2_GLOBAL(0x009DEBA2, sint16) = _dropdown_highlighted_index; } /** @@ -233,10 +249,10 @@ void window_dropdown_show_image(int x, int y, int extray, uint8 colour, uint8 fl // Calculate position and size width = _dropdown_item_width * _dropdown_num_columns + 3; 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); + if (x + width > RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16)) + x = max(0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - width); + if (y + height > RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16)) + y = max(0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - height); window_dropdown_widgets[WIDX_BACKGROUND].right = width; window_dropdown_widgets[WIDX_BACKGROUND].bottom = height; @@ -245,7 +261,7 @@ void window_dropdown_show_image(int x, int y, int extray, uint8 colour, uint8 fl x, y + extray, window_dropdown_widgets[WIDX_BACKGROUND].right + 1, window_dropdown_widgets[WIDX_BACKGROUND].bottom + 1, - (uint32*)window_dropdown_events, + &window_dropdown_events, WC_DROPDOWN, WF_STICK_TO_FRONT ); @@ -255,18 +271,14 @@ void window_dropdown_show_image(int x, int y, int extray, uint8 colour, uint8 fl w->colours[0] = colour; // Input state - _dropdown_highlighted_index = -1; - RCT2_GLOBAL(0x009DED34, sint32) = 0; + gDropdownHighlightedIndex = -1; + gDropdownItemsDisabled = 0; gDropdownItemsChecked = 0; RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, sint8) = INPUT_STATE_DROPDOWN_ACTIVE; // Copy the following properties until all use of it is decompiled - RCT2_GLOBAL(0x009DEBA0, sint16) = gDropdownNumItems; - RCT2_GLOBAL(0x009DED44, sint32) = _dropdown_num_columns; - RCT2_GLOBAL(0x009DED48, sint32) = _dropdown_num_rows; - RCT2_GLOBAL(0x009DED40, sint32) = _dropdown_item_width; - RCT2_GLOBAL(0x009DED3C, sint32) = _dropdown_item_height; - RCT2_GLOBAL(0x009DEBA2, sint16) = _dropdown_highlighted_index; + gDropdownHighlightedIndex = gDropdownHighlightedIndex; + gDropdownIsColour = false; } void window_dropdown_close() @@ -274,94 +286,89 @@ void window_dropdown_close() window_close_by_class(WC_DROPDOWN); } -static void window_dropdown_paint() +static void window_dropdown_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); + int cell_x, cell_y, l, t, r, b, item, image, colour; window_draw_widgets(w, dpi); - _dropdown_highlighted_index = RCT2_GLOBAL(0x009DEBA2, sint16); - { - int i, cell_x, cell_y, l, t, r, b, item, image, colour; - for (i = 0; i < gDropdownNumItems; i++) { - cell_x = i % _dropdown_num_columns; - cell_y = i / _dropdown_num_columns; + gDropdownHighlightedIndex = gDropdownHighlightedIndex; + for (int i = 0; i < gDropdownNumItems; i++) { + cell_x = i % _dropdown_num_columns; + cell_y = i / _dropdown_num_columns; - if (gDropdownItemsFormat[i] == DROPDOWN_SEPARATOR) { + if (gDropdownItemsFormat[i] == DROPDOWN_SEPARATOR) { + l = w->x + 2 + (cell_x * _dropdown_item_width); + t = w->y + 2 + (cell_y * _dropdown_item_height); + r = l + _dropdown_item_width - 1; + t += (_dropdown_item_height / 2); + b = t; + + if (w->colours[0] & 0x80) { + gfx_fill_rect(dpi, l, t, r, b, (RCT2_ADDRESS(0x009DEDF4, uint8)[w->colours[0]] | 0x02000000) + 1); + gfx_fill_rect(dpi, l, t + 1, r, b + 1, (RCT2_ADDRESS(0x009DEDF4, uint8)[w->colours[0]] | 0x02000000) + 2); + } else { + gfx_fill_rect(dpi, l, t, r, b, ColourMapA[w->colours[0]].mid_dark); + gfx_fill_rect(dpi, l, t + 1, r, b + 1, ColourMapA[w->colours[0]].lightest); + } + } else { + // + if (i == gDropdownHighlightedIndex) { l = w->x + 2 + (cell_x * _dropdown_item_width); t = w->y + 2 + (cell_y * _dropdown_item_height); r = l + _dropdown_item_width - 1; - t += (_dropdown_item_height / 2); - b = t; + b = t + _dropdown_item_height - 1; + gfx_fill_rect(dpi, l, t, r, b, 0x2000000 | 0x2F); + } - if (w->colours[0] & 0x80) { - gfx_fill_rect(dpi, l, t, r, b, (RCT2_ADDRESS(0x009DEDF4, uint8)[w->colours[0]] | 0x02000000) + 1); - gfx_fill_rect(dpi, l, t + 1, r, b + 1, (RCT2_ADDRESS(0x009DEDF4, uint8)[w->colours[0]] | 0x02000000) + 2); - } else { - gfx_fill_rect(dpi, l, t, r, b, - *((char*)(0x00141FC47 + (w->colours[0] * 8)))); - gfx_fill_rect(dpi, l, t + 1, r, b + 1, - *((char*)(0x00141FC4B + (w->colours[0] * 8)))); - } + item = gDropdownItemsFormat[i]; + if (item == (uint16)-1 || item == (uint16)-2) { + // Image item + image = *((uint32*)&gDropdownItemsArgs[i]); + if (item == (uint16)-2 && gDropdownHighlightedIndex == i) + image++; + + gfx_draw_sprite( + dpi, + image, + w->x + 2 + (cell_x * _dropdown_item_width), + w->y + 2 + (cell_y * _dropdown_item_height), 0 + ); } else { - // - if (i == _dropdown_highlighted_index) { - l = w->x + 2 + (cell_x * _dropdown_item_width); - t = w->y + 2 + (cell_y * _dropdown_item_height); - r = l + _dropdown_item_width - 1; - b = t + _dropdown_item_height - 1; - gfx_fill_rect(dpi, l, t, r, b, 0x2000000 | 0x2F); + // Text item + if (i < 64) { + if (dropdown_is_checked(i)) { + item++; + } } - item = gDropdownItemsFormat[i]; - if (item == (uint16)-1 || item == (uint16)-2) { - // Image item - image = *((uint32*)&gDropdownItemsArgs[i]); - if (item == (uint16)-2 && _dropdown_highlighted_index == i) - image++; + // Calculate colour + colour = w->colours[0] & 0x7F; + if (i == gDropdownHighlightedIndex) + colour = 2; + if (gDropdownItemsDisabled & (1ULL << i)) + if (i < 64) + colour = (w->colours[0] & 0x7F) | 0x40; - gfx_draw_sprite( - dpi, - image, - w->x + 2 + (cell_x * _dropdown_item_width), - w->y + 2 + (cell_y * _dropdown_item_height), 0 - ); - } else { - // Text item - if (i < 32) - if (gDropdownItemsChecked & (1 << i)) - item++; - - // Calculate colour - colour = w->colours[0] & 0x7F; - if (i == _dropdown_highlighted_index) - colour = 2; - if (RCT2_GLOBAL(0x009DED34, uint32) & (1 << i)) - if (i < 32) - colour = (w->colours[0] & 0x7F) | 0x40; - - // Draw item string - gfx_draw_string_left_clipped( - dpi, - item, - (void*)(&gDropdownItemsArgs[i]), colour, - w->x + 2 + (cell_x * _dropdown_item_width), - w->y + 1 + (cell_y * _dropdown_item_height), - w->width - 5 - ); - } + // Draw item string + gfx_draw_string_left_clipped( + dpi, + item, + (void*)(&gDropdownItemsArgs[i]), colour, + w->x + 2 + (cell_x * _dropdown_item_width), + w->y + 1 + (cell_y * _dropdown_item_height), + w->width - 5 + ); } } } } -/* New function based on 6e914e +/* New function based on 6e914e * returns -1 if index is invalid */ -int dropdown_index_from_point(int x, int y, rct_window* w){ +int dropdown_index_from_point(int x, int y, rct_window *w) +{ int top = y - w->y - 2; if (top < 0) return -1; @@ -370,20 +377,14 @@ int dropdown_index_from_point(int x, int y, rct_window* w){ left -= 2; if (left < 0) return -1; - // _dropdown_item_width - int column_no = left / RCT2_GLOBAL(0x009DED40, sint32); - // _dropdown_no_columns - if (column_no >= RCT2_GLOBAL(0x009DED44, sint32)) return -1; - - // _dropdown_item_height - int row_no = top / RCT2_GLOBAL(0x9DED3C, uint8); - // _dropdown_no_rows - if (row_no >= RCT2_GLOBAL(0x009DED48, sint32)) return -1; + int column_no = left / _dropdown_item_width; + if (column_no >= _dropdown_num_columns) return -1; - // _dropdown_no_columns - int dropdown_index = row_no * RCT2_GLOBAL(0x009DED44, sint32) + column_no; - // _dropdown_no_items - if (dropdown_index >= RCT2_GLOBAL(0x009DEBA0, sint16)) return -1; + int row_no = top / _dropdown_item_height; + if (row_no >= _dropdown_num_rows) return -1; + + int dropdown_index = row_no * _dropdown_num_columns + column_no; + if (dropdown_index >= gDropdownNumItems) return -1; return dropdown_index; } @@ -405,7 +406,7 @@ void window_dropdown_show_colour_available(rct_window *w, rct_widget *widget, ui uint32 availableColours) { int i, numItems; - + // Count number of available colours numItems = 0; for (i = 0; i < 32; i++) @@ -416,7 +417,7 @@ void window_dropdown_show_colour_available(rct_window *w, rct_widget *widget, ui for (i = 0; i < 32; i++) { if (availableColours & (1 << i)) { if (selectedColour == i) - RCT2_GLOBAL(0x009DEBA2, sint16) = i; + gDropdownHighlightedIndex = i; gDropdownItemsFormat[i] = 0xFFFE; gDropdownItemsArgs[i] = ((uint64)i << 32) | (0x20000000 | (i << 19) | 5059); @@ -436,4 +437,6 @@ void window_dropdown_show_colour_available(rct_window *w, rct_widget *widget, ui gAppropriateImageDropdownItemsPerRow[numItems] ); + gDropdownIsColour = true; + gDropdownLastColourHover = -1; } diff --git a/src/windows/dropdown.h b/src/windows/dropdown.h index c26f140197..43dcc4cf0d 100644 --- a/src/windows/dropdown.h +++ b/src/windows/dropdown.h @@ -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 . *****************************************************************************/ @@ -35,8 +35,14 @@ extern int gAppropriateImageDropdownItemsPerRow[]; extern int gDropdownNumItems; extern uint16 gDropdownItemsFormat[64]; extern sint64 gDropdownItemsArgs[64]; -extern uint32 gDropdownItemsChecked; -extern uint32 *gDropdownItemsDisabled; +extern uint64 gDropdownItemsChecked; +extern uint64 gDropdownItemsDisabled; +extern bool gDropdownIsColour; +extern int gDropdownLastColourHover; +extern int gDropdownHighlightedIndex; + +void dropdown_set_checked(int index, bool value); +void dropdown_set_disabled(int index, bool value); 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); @@ -46,4 +52,4 @@ int dropdown_index_from_point(int x, int y, rct_window* w); void window_dropdown_show_colour(rct_window *w, rct_widget *widget, uint8 dropdownColour, uint8 selectedColour); void window_dropdown_show_colour_available(rct_window *w, rct_widget *widget, uint8 dropdownColour, uint8 selectedColour, uint32 availableColours); -#endif \ No newline at end of file +#endif diff --git a/src/windows/editor_bottom_toolbar.c b/src/windows/editor_bottom_toolbar.c index 6f235769bf..8e466117f9 100644 --- a/src/windows/editor_bottom_toolbar.c +++ b/src/windows/editor_bottom_toolbar.c @@ -25,15 +25,16 @@ #include "../scenario.h" #include "../sprites.h" #include "../localisation/localisation.h" +#include "../interface/themes.h" #include "../interface/viewport.h" #include "../interface/widget.h" #include "../interface/window.h" #include "../platform/platform.h" #include "../title.h" #include "../util/util.h" +#include "../world/footpath.h" #include "../world/scenery.h" #include "error.h" -#include "../interface/themes.h" enum { WIDX_PREVIOUS_IMAGE, // 1 @@ -50,11 +51,9 @@ static rct_widget window_editor_bottom_toolbar_widgets[] = { { WIDGETS_END }, }; -static void window_editor_bottom_toolbar_emptysub() { } - -static void window_editor_bottom_toolbar_mouseup(); -static void window_editor_bottom_toolbar_invalidate(); -static void window_editor_bottom_toolbar_paint(); +static void window_editor_bottom_toolbar_mouseup(rct_window *w, int widgetIndex); +static void window_editor_bottom_toolbar_invalidate(rct_window *w); +static void window_editor_bottom_toolbar_paint(rct_window *w, rct_drawpixelinfo *dpi); static void window_editor_bottom_toolbar_jump_back_to_object_selection(); static void window_editor_bottom_toolbar_jump_back_to_landscape_editor(); @@ -67,59 +66,61 @@ static void window_editor_bottom_toolbar_jump_forward_to_options_selection(); static void window_editor_bottom_toolbar_jump_forward_to_objective_selection(); static void window_editor_bottom_toolbar_jump_forward_to_save_scenario(); -static void* window_editor_bottom_toolbar_events[] = { - window_editor_bottom_toolbar_emptysub, +static rct_window_event_list window_editor_bottom_toolbar_events = { + NULL, window_editor_bottom_toolbar_mouseup, //0x0066f5ae, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_editor_bottom_toolbar_invalidate, //0x0066f1c9, window_editor_bottom_toolbar_paint, //0x0066f25c, - window_editor_bottom_toolbar_emptysub + NULL }; -static EMPTY_ARGS_VOID_POINTER* previous_button_mouseup_events[] = { - window_editor_bottom_toolbar_emptysub, +static EMPTY_ARGS_VOID_POINTER *previous_button_mouseup_events[] = { + NULL, window_editor_bottom_toolbar_jump_back_to_object_selection, window_editor_bottom_toolbar_jump_back_to_landscape_editor, window_editor_bottom_toolbar_jump_back_to_invention_list_set_up, window_editor_bottom_toolbar_jump_back_to_options_selection, - window_editor_bottom_toolbar_emptysub, + NULL, window_editor_bottom_toolbar_jump_back_to_object_selection, - window_editor_bottom_toolbar_emptysub + NULL }; -static EMPTY_ARGS_VOID_POINTER* next_button_mouseup_events[] = { - window_editor_bottom_toolbar_jump_forward_from_object_selection, +static EMPTY_ARGS_VOID_POINTER *next_button_mouseup_events[] = { + window_editor_bottom_toolbar_jump_forward_from_object_selection, window_editor_bottom_toolbar_jump_forward_to_invention_list_set_up, window_editor_bottom_toolbar_jump_forward_to_options_selection, window_editor_bottom_toolbar_jump_forward_to_objective_selection, window_editor_bottom_toolbar_jump_forward_to_save_scenario, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub, - window_editor_bottom_toolbar_emptysub + NULL, + NULL, + NULL }; +static void sub_6DFED0(); + /** * Creates the main editor top toolbar window. * rct2: 0x0066F052 (part of 0x0066EF38) @@ -128,10 +129,10 @@ void window_editor_bottom_toolbar_open() { rct_window* window; - window = window_create(0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) - 32, - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16), 32, - (uint32*)window_editor_bottom_toolbar_events, - WC_BOTTOM_TOOLBAR, WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_5); + window = window_create(0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - 32, + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16), 32, + &window_editor_bottom_toolbar_events, + WC_BOTTOM_TOOLBAR, WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_NO_BACKGROUND); window->widgets = window_editor_bottom_toolbar_widgets; window->enabled_widgets |= @@ -141,6 +142,7 @@ void window_editor_bottom_toolbar_open() (1 << WIDX_NEXT_IMAGE); window_init_scroll_widgets(window); + sub_6DFED0(); } /** @@ -153,13 +155,23 @@ void window_editor_bottom_toolbar_jump_back_to_object_selection() { gfx_invalidate_screen(); } +/** + * + * rct2: 0x006DFED0 + */ +static void sub_6DFED0() +{ + for (int i = 0; i < 56; i++) + RCT2_ADDRESS(0x01357BD0, sint32)[i] = -1; +} + /** * * rct2: 0x0066F62C */ void window_editor_bottom_toolbar_jump_back_to_landscape_editor() { window_close_all(); - RCT2_CALLPROC_EBPSAFE(0x006DFED0); + sub_6DFED0(); scenery_set_default_placement_configuration(); g_editor_step = EDITOR_STEP_LANDSCAPE_EDITOR; window_map_open(); @@ -203,9 +215,48 @@ void window_editor_bottom_toolbar_jump_back_to_options_selection() { * * rct2: 0x006AB1CE */ -int window_editor_bottom_toolbar_check_object_selection() +bool window_editor_bottom_toolbar_check_object_selection() { - return RCT2_CALLPROC_EBPSAFE(0x006AB1CE) & 0x100; + rct_window *w; + + int missingObjectType = editor_check_object_selection(); + if (missingObjectType < 0) { + window_close_by_class(WC_EDITOR_OBJECT_SELECTION); + return true; + } + + window_error_open(STR_INVALID_SELECTION_OF_OBJECTS, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id)); + w = window_find_by_class(WC_EDITOR_OBJECT_SELECTION); + if (w != NULL) { + // Click tab with missing object + window_event_mouse_up_call(w, 4 + missingObjectType); + } + return false; +} + +/** + * + * rct2: 0x0066F6E3 + */ +static void sub_66F6E3() +{ + RCT2_GLOBAL(0x01357404, uint32) = 0xFFFFFFFF; + RCT2_GLOBAL(0x01357408, uint32) = 0xFFFFFFFF; + RCT2_GLOBAL(0x0135740C, uint32) = 0xFFFFFFFF; + RCT2_GLOBAL(0x01357410, uint32) = 0xFFFFFFFF; + + for (int i = 0; i < 128; i++) { + RCT2_ADDRESS(0x01357444, uint32)[i] = RCT2_ADDRESS(0x0097C468, uint32)[i]; + RCT2_ADDRESS(0x01357644, uint32)[i] = RCT2_ADDRESS(0x0097C5D4, uint32)[i]; + } + + for (int i = 0; i < 8; i++) { + RCT2_ADDRESS(0x01357424, uint32)[i] = 0xFFFFFFFF; + } + + window_new_ride_open(); + RCT2_GLOBAL(0x0141F570, uint8) = 6; + gfx_invalidate_screen(); } /** @@ -214,13 +265,13 @@ int window_editor_bottom_toolbar_check_object_selection() */ void window_editor_bottom_toolbar_jump_forward_from_object_selection() { - if (window_editor_bottom_toolbar_check_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); + sub_66F6E3(); } else { - RCT2_CALLPROC_EBPSAFE(0x006DFED0); + sub_6DFED0(); scenery_set_default_placement_configuration(); RCT2_GLOBAL(0x00141F570, uint8) = 1; window_map_open(); @@ -230,12 +281,10 @@ void window_editor_bottom_toolbar_jump_forward_from_object_selection() /** * -* rct2: 0x0066f758 +* rct2: 0x0066F758 */ void window_editor_bottom_toolbar_jump_forward_to_invention_list_set_up() { - uint32 flags = RCT2_CALLPROC_X(0x0066FEAC, 0, 0, 0, 0, 0, 0, 0); - - if (!(flags & 0x100)) { + if (editor_check_park()) { window_close_all(); window_editor_inventions_list_open(); g_editor_step = EDITOR_STEP_INVENTIONS_LIST_SET_UP; @@ -287,12 +336,12 @@ static int show_save_scenario_dialog(char *resultPath) strcat(filename, ".SC6"); format_string(filterName, STR_RCT2_SCENARIO_FILE, NULL); - pause_sounds(); + audio_pause_sounds(); result = platform_open_common_file_dialog(0, title, filename, "*.SC6", filterName); - unpause_sounds(); + audio_unpause_sounds(); if (result) - strcpy(resultPath, filename); + safe_strncpy(resultPath, filename, MAX_PATH); return result; } @@ -322,8 +371,8 @@ void window_editor_bottom_toolbar_jump_forward_to_save_scenario() return; } - // - s6Info->var_000 = 255; + // + s6Info->editor_step = 255; // Ensure path has .SC6 extension path_set_extension(path, ".SC6"); @@ -331,14 +380,18 @@ 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, gConfigGeneral.save_plugin_data ? 3 : 2); + SDL_RWops* rw = SDL_RWFromFile(path, "wb+"); + if (rw != NULL) { + success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2); + SDL_RWclose(rw); + } RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = parkFlagsBackup; if (success) { title_load(); } else { window_error_open(STR_SCENARIO_SAVE_FAILED, -1); - s6Info->var_000 = 4; + s6Info->editor_step = EDITOR_STEP_OBJECTIVE_SELECTION; } } @@ -346,16 +399,11 @@ void window_editor_bottom_toolbar_jump_forward_to_save_scenario() * * rct2: 0x0066F5AE */ -static void window_editor_bottom_toolbar_mouseup() +static void window_editor_bottom_toolbar_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - 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_18)) { + (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) { @@ -377,14 +425,11 @@ void hide_next_step_button() { * * rct2: 0x0066F1C9 */ -void window_editor_bottom_toolbar_invalidate() { - rct_window* w; - - window_get_register(w); - +void window_editor_bottom_toolbar_invalidate(rct_window *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); + uint16 screenWidth = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); 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; @@ -415,27 +460,23 @@ void window_editor_bottom_toolbar_invalidate() { * * rct2: 0x0066F25C */ -void window_editor_bottom_toolbar_paint() { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +void window_editor_bottom_toolbar_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ bool drawPreviousButton = false; bool drawNextButton = false; if (g_editor_step == EDITOR_STEP_OBJECT_SELECTION) { drawNextButton = true; - } + } else if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) { drawPreviousButton = true; - } + } else if (RCT2_GLOBAL(0x13573C8, uint16) != 0x2710) { drawNextButton = true; } else if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_18) { drawNextButton = true; - } + } else { drawPreviousButton = true; } @@ -461,7 +502,7 @@ void window_editor_bottom_toolbar_paint() { window_draw_widgets(w, dpi); if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER)) { - + if (drawPreviousButton) { gfx_fill_rect_inset(dpi, @@ -525,7 +566,7 @@ void window_editor_bottom_toolbar_paint() { short textX = (window_editor_bottom_toolbar_widgets[WIDX_NEXT_IMAGE].left + window_editor_bottom_toolbar_widgets[WIDX_NEXT_IMAGE].right - 30) / 2 + w->x; short textY = window_editor_bottom_toolbar_widgets[WIDX_NEXT_IMAGE].top + 6 + w->y; - + short stringId = STR_OBJECT_SELECTION_STEP + g_editor_step + 1; if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) stringId = STR_ROLLERCOASTER_DESIGNER_STEP; @@ -535,4 +576,4 @@ void window_editor_bottom_toolbar_paint() { } } -} \ No newline at end of file +} diff --git a/src/windows/editor_inventions_list.c b/src/windows/editor_inventions_list.c index de90fbf90b..a8396b77d1 100644 --- a/src/windows/editor_inventions_list.c +++ b/src/windows/editor_inventions_list.c @@ -28,6 +28,8 @@ #include "../object.h" #include "../world/scenery.h" #include "../interface/themes.h" +#include "../rct1.h" +#include "../util/util.h" #pragma region Widgets @@ -69,86 +71,84 @@ static rct_widget window_editor_inventions_list_drag_widgets[] = { #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_close(rct_window *w); +static void window_editor_inventions_list_mouseup(rct_window *w, int widgetIndex); 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_scrollgetheight(rct_window *w, int scrollIndex, int *width, int *height); +static void window_editor_inventions_list_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_editor_inventions_list_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_editor_inventions_list_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_editor_inventions_list_cursor(rct_window *w, int widgetIndex, int x, int y, int *cursorId); +static void window_editor_inventions_list_invalidate(rct_window *w); +static void window_editor_inventions_list_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_editor_inventions_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void window_editor_inventions_list_drag_cursor(); -static void window_editor_inventions_list_drag_moved(); -static void window_editor_inventions_list_drag_paint(); +static void window_editor_inventions_list_drag_cursor(rct_window *w, int widgetIndex, int x, int y, int *cursorId); +static void window_editor_inventions_list_drag_moved(rct_window* w, int x, int y); +static void window_editor_inventions_list_drag_paint(rct_window *w, rct_drawpixelinfo *dpi); // 0x0098177C -static void* window_editor_inventions_list_events[] = { +static rct_window_event_list 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, + NULL, + NULL, + NULL, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_editor_inventions_list_scrollgetheight, window_editor_inventions_list_scrollmousedown, - window_editor_inventions_list_emptysub, + NULL, window_editor_inventions_list_scrollmouseover, - window_editor_inventions_list_emptysub, - window_editor_inventions_list_emptysub, - window_editor_inventions_list_emptysub, + NULL, + NULL, + NULL, window_editor_inventions_list_tooltip, window_editor_inventions_list_cursor, - window_editor_inventions_list_emptysub, + NULL, 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, +static rct_window_event_list window_editor_inventions_list_drag_events = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_editor_inventions_list_drag_cursor, window_editor_inventions_list_drag_moved, - window_editor_inventions_list_emptysub, + NULL, window_editor_inventions_list_drag_paint, - window_editor_inventions_list_emptysub + NULL }; #pragma endregion @@ -165,7 +165,7 @@ 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 +/* rct2: 0x0068596F * Sets rides that are in use to be always researched */ static void research_rides_setup(){ @@ -198,14 +198,14 @@ static void research_rides_setup(){ rct_ride_type* ride_entry = GET_RIDE_ENTRY(object_index); uint8 master_found = 0; - if (!(ride_entry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE)){ + if (!(ride_entry->flags & RIDE_ENTRY_FLAG_SEPARATE_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) + if (master_ride->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) continue; // If master ride not in use @@ -240,11 +240,11 @@ static void research_rides_setup(){ } } -/* rct2: 0x0068590C +/* 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++){ @@ -285,13 +285,13 @@ static void research_always_researched_setup() * rct2: 0x00685A79 */ static void sub_685A79() -{ - for (rct_research_item* research = gResearchItems; +{ + for (rct_research_item* research = gResearchItems; research->entryIndex != RESEARCHED_ITEMS_END_2; research++){ // Clear the always researched flags. - if (research->entryIndex > RESEARCHED_ITEMS_SEPERATOR){ + if (research->entryIndex > RESEARCHED_ITEMS_SEPARATOR){ research->entryIndex &= 0x00FFFFFF; } } @@ -305,7 +305,7 @@ 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) @@ -318,7 +318,7 @@ static rct_string_id research_item_get_name(uint32 researchItem) if (rideEntry == NULL || rideEntry == (rct_ride_type*)0xFFFFFFFF) return 0; - if (rideEntry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME) + if (rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) return rideEntry->name; return ((researchItem >> 8) & 0xFF) + 2; @@ -334,7 +334,7 @@ static void research_items_shuffle() int i, ri, numNonResearchedItems; // Skip pre-researched items - for (researchItem = gResearchItems; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR; researchItem++) {} + for (researchItem = gResearchItems; researchItem->entryIndex != RESEARCHED_ITEMS_SEPARATOR; researchItem++) {} researchItem++; researchOrderBase = researchItem; @@ -345,7 +345,7 @@ static void research_items_shuffle() // Shuffle list for (i = 0; i < numNonResearchedItems; i++) { - ri = rand() % numNonResearchedItems; + ri = util_rand() % numNonResearchedItems; if (ri == i) continue; @@ -362,19 +362,19 @@ static void research_items_make_all_unresearched() int sorted; do { sorted = 1; - for (researchItem = gResearchItems; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR; researchItem++) { + for (researchItem = gResearchItems; researchItem->entryIndex != RESEARCHED_ITEMS_SEPARATOR; 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 + if (nextResearchItem->entryIndex == RESEARCHED_ITEMS_SEPARATOR || research_item_is_always_researched(nextResearchItem)) { + // Bubble up always researched item or separator researchItemTemp = *researchItem; *researchItem = *nextResearchItem; *nextResearchItem = researchItemTemp; sorted = 0; - if (researchItem->entryIndex == RESEARCHED_ITEMS_SEPERATOR) + if (researchItem->entryIndex == RESEARCHED_ITEMS_SEPARATOR) break; } } @@ -385,12 +385,12 @@ static void research_items_make_all_researched() { rct_research_item *researchItem, researchItemTemp; - // Find seperator - for (researchItem = gResearchItems; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR; researchItem++) { } + // Find separator + for (researchItem = gResearchItems; researchItem->entryIndex != RESEARCHED_ITEMS_SEPARATOR; researchItem++) { } - // Move seperator below all items + // Move separator below all items for (; (researchItem + 1)->entryIndex != RESEARCHED_ITEMS_END; researchItem++) { - // Swap seperator with research item + // Swap separator with research item researchItemTemp = *researchItem; *researchItem = *(researchItem + 1); *(researchItem + 1) = researchItemTemp; @@ -450,11 +450,11 @@ static rct_research_item *window_editor_inventions_list_get_item_from_scroll_y(i if (scrollIndex != 0) { // Skip pre-researched items - for (; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR; researchItem++) { } + for (; researchItem->entryIndex != RESEARCHED_ITEMS_SEPARATOR; researchItem++) { } researchItem++; } - for (; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR && researchItem->entryIndex != RESEARCHED_ITEMS_END; researchItem++) { + for (; researchItem->entryIndex != RESEARCHED_ITEMS_SEPARATOR && researchItem->entryIndex != RESEARCHED_ITEMS_END; researchItem++) { y -= 10; if (y < 0) return researchItem; @@ -475,11 +475,11 @@ static rct_research_item *window_editor_inventions_list_get_item_from_scroll_y_i if (scrollIndex != 0) { // Skip pre-researched items - for (; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR; researchItem++) { } + for (; researchItem->entryIndex != RESEARCHED_ITEMS_SEPARATOR; researchItem++) { } researchItem++; } - for (; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR && researchItem->entryIndex != RESEARCHED_ITEMS_END; researchItem++) { + for (; researchItem->entryIndex != RESEARCHED_ITEMS_SEPARATOR && researchItem->entryIndex != RESEARCHED_ITEMS_END; researchItem++) { y -= 10; if (y < 0) return researchItem; @@ -531,9 +531,9 @@ void window_editor_inventions_list_open() w = window_create_centred( 600, 400, - (uint32*)window_editor_inventions_list_events, + &window_editor_inventions_list_events, WC_EDITOR_INVENTION_LIST, - WF_2 + WF_NO_SCROLLING ); w->widgets = window_editor_inventions_list_widgets; w->enabled_widgets = @@ -553,8 +553,15 @@ void window_editor_inventions_list_open() * * rct2: 0x006853D2 */ -static void window_editor_inventions_list_close() +static void window_editor_inventions_list_close(rct_window *w) { + // When used in-game (as a cheat) + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_EDITOR)) { + gSilentResearch = true; + sub_684AC3(); + gSilentResearch = false; + } + sub_685A79(); } @@ -562,13 +569,8 @@ static void window_editor_inventions_list_close() * * rct2: 0x0068521B */ -static void window_editor_inventions_list_mouseup() +static void window_editor_inventions_list_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -614,45 +616,33 @@ static void window_editor_inventions_list_update(rct_window *w) * * rct2: 0x00685239 */ -static void window_editor_inventions_list_scrollgetheight() +static void window_editor_inventions_list_scrollgetheight(rct_window *w, int scrollIndex, int *width, int *height) { - rct_window *w; - short scrollIndex; rct_research_item *researchItem; - int width, height; - window_scroll_get_registers(w, scrollIndex); - - width = 0; - height = 0; + *height = 0; // Count / skip pre-researched items - for (researchItem = gResearchItems; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR; researchItem++) - height += 10; - + for (researchItem = gResearchItems; researchItem->entryIndex != RESEARCHED_ITEMS_SEPARATOR; researchItem++) + *height += 10; + if (scrollIndex == 1) { researchItem++; // Count non pre-researched items - height = 0; + *height = 0; for (; researchItem->entryIndex != RESEARCHED_ITEMS_END; researchItem++) - height += 10; + *height += 10; } - - window_scrollsize_set_registers(width, height); } /** * * rct2: 0x006852D4 */ -static void window_editor_inventions_list_scrollmousedown() +static void window_editor_inventions_list_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) { - 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) @@ -669,14 +659,10 @@ static void window_editor_inventions_list_scrollmousedown() * * rct2: 0x00685275 */ -static void window_editor_inventions_list_scrollmouseover() +static void window_editor_inventions_list_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) { - 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; @@ -688,31 +674,28 @@ static void window_editor_inventions_list_scrollmouseover() * * rct2: 0x0068526B */ -static void window_editor_inventions_list_tooltip() +static void window_editor_inventions_list_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) { - RCT2_GLOBAL(0x013CE952, uint16) = 3159; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = 3159; } /** * * rct2: 0x00685291 */ -static void window_editor_inventions_list_cursor() +static void window_editor_inventions_list_cursor(rct_window *w, int widgetIndex, int x, int y, int *cursorId) { - rct_window *w; rct_research_item *researchItem; - short widgetIndex, x, y; - int scrollIndex, cursorId; + int scrollIndex; - window_cursor_get_registers(w, widgetIndex, x, y); - - if (widgetIndex == WIDX_PRE_RESEARCHED_SCROLL) { + switch (widgetIndex) { + case WIDX_PRE_RESEARCHED_SCROLL: scrollIndex = 0; - } else if (widgetIndex == WIDX_RESEARCH_ORDER_SCROLL) { + break; + case WIDX_RESEARCH_ORDER_SCROLL: scrollIndex = 1; - } else { - cursorId = -1; - window_cursor_set_registers(cursorId); + break; + default: return; } @@ -721,24 +704,18 @@ static void window_editor_inventions_list_cursor() 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); + *cursorId = CURSOR_HAND_OPEN; } /** * * rct2: 0x00685392 */ -static void window_editor_inventions_list_invalidate() +static void window_editor_inventions_list_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); w->pressed_widgets |= 1 << WIDX_PREVIEW; @@ -752,19 +729,15 @@ static void window_editor_inventions_list_invalidate() * * rct2: 0x00684EE0 */ -static void window_editor_inventions_list_paint() +static void window_editor_inventions_list_paint(rct_window *w, rct_drawpixelinfo *dpi) { - 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; @@ -788,13 +761,13 @@ static void window_editor_inventions_list_paint() w->y + widget->top + 1, w->x + widget->right - 1, w->y + widget->bottom - 1, - RCT2_GLOBAL(0x0141FC44 + (w->colours[1] * 8), uint8) + ColourMapA[w->colours[1]].darkest ); researchItem = _editorInventionsListDraggedItem; if (researchItem == NULL) researchItem = WindowHighlightedItem(w); - // If the research item is null or a list seperator. + // If the research item is null or a list separator. if (researchItem == NULL || researchItem->entryIndex < 0) return; @@ -832,22 +805,17 @@ static void window_editor_inventions_list_paint() * * rct2: 0x006850BD */ -static void window_editor_inventions_list_scrollpaint() +static void window_editor_inventions_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { - 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); + utf8 buffer[256], *ptr; // Draw background - colour = RCT2_GLOBAL(0x0141FC48 + (w->colours[1] * 8), uint8); + colour = ColourMapA[w->colours[1]].mid_light; colour = (colour << 24) | (colour << 16) | (colour << 8) | colour; gfx_clear(dpi, colour); @@ -855,16 +823,16 @@ static void window_editor_inventions_list_scrollpaint() if (scrollIndex == 1) { // Skip pre-researched items - for (; researchItem->entryIndex != RESEARCHED_ITEMS_SEPERATOR; researchItem++) { } + for (; researchItem->entryIndex != RESEARCHED_ITEMS_SEPARATOR; researchItem++) { } researchItem++; researchItemEndMarker = RESEARCHED_ITEMS_END; } else { - researchItemEndMarker = RESEARCHED_ITEMS_SEPERATOR; + researchItemEndMarker = RESEARCHED_ITEMS_SEPARATOR; } // Since this is now a do while need to conteract the +10 itemY = -10; - do{ + do{ itemY += 10; if (itemY + 10 < dpi->y || itemY >= dpi->y + dpi->height) continue; @@ -886,7 +854,7 @@ static void window_editor_inventions_list_scrollpaint() colour = 14; } - if (researchItem->entryIndex == RESEARCHED_ITEMS_SEPERATOR || researchItem->entryIndex == RESEARCHED_ITEMS_END) + if (researchItem->entryIndex == RESEARCHED_ITEMS_SEPARATOR || researchItem->entryIndex == RESEARCHED_ITEMS_END) continue; if (researchItem == _editorInventionsListDraggedItem) @@ -896,8 +864,9 @@ static void window_editor_inventions_list_scrollpaint() stringId = research_item_get_name(researchItem->entryIndex & 0xFFFFFF); ptr = buffer; - if (!disableItemMovement) - *ptr++ = colour & 0xFF; + if (!disableItemMovement) { + ptr = utf8_write_codepoint(ptr, colour & 0xFF); + } format_string(ptr, stringId, NULL); @@ -943,7 +912,7 @@ static void window_editor_inventions_list_drag_open(rct_research_item *researchI RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, uint16) - 7, stringWidth, 14, - (uint32*)window_editor_inventions_list_drag_events, + &window_editor_inventions_list_drag_events, WC_EDITOR_INVENTION_LIST_DRAG, WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_NO_SNAPPING ); @@ -958,14 +927,10 @@ static void window_editor_inventions_list_drag_open(rct_research_item *researchI * * rct2: 0x0068549C */ -static void window_editor_inventions_list_drag_cursor() +static void window_editor_inventions_list_drag_cursor(rct_window *w, int widgetIndex, int x, int y, int *cursorId) { - rct_window *w, *inventionListWindow; + rct_window *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) { @@ -976,21 +941,16 @@ static void window_editor_inventions_list_drag_cursor() } } - cursorId = CURSOR_HAND_CLOSED; - window_cursor_set_registers(cursorId); + *cursorId = CURSOR_HAND_CLOSED; } /** * * rct2: 0x00685412 */ -static void window_editor_inventions_list_drag_moved() +static void window_editor_inventions_list_drag_moved(rct_window* w, int x, int y) { - 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) @@ -1005,15 +965,11 @@ static void window_editor_inventions_list_drag_moved() * * rct2: 0x006853D9 */ -static void window_editor_inventions_list_drag_paint() +static void window_editor_inventions_list_drag_paint(rct_window *w, rct_drawpixelinfo *dpi) { - 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); diff --git a/src/windows/editor_main.c b/src/windows/editor_main.c index a9635b4e47..dcdd7d1830 100644 --- a/src/windows/editor_main.c +++ b/src/windows/editor_main.c @@ -23,39 +23,37 @@ #include "../interface/widget.h" #include "../interface/window.h" -static void window_editor_main_emptysub() { } +static void window_editor_main_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_editor_main_paint(); - -static void* window_editor_main_events[] = { - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, - window_editor_main_emptysub, +static rct_window_event_list window_editor_main_events = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_editor_main_paint,// 0x0066FC97, //window_editor_main_paint, - window_editor_main_emptysub, + NULL, }; static rct_widget window_editor_main_widgets[] = { @@ -72,10 +70,10 @@ void window_editor_main_open() { rct_window* window; - window_editor_main_widgets[0].right = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); - window_editor_main_widgets[0].bottom = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16); + window_editor_main_widgets[0].right = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); + window_editor_main_widgets[0].bottom = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16); window = window_create(0, 0, window_editor_main_widgets[0].right, window_editor_main_widgets[0].bottom, - (uint32*)window_editor_main_events, WC_MAIN_WINDOW, WF_STICK_TO_BACK); + &window_editor_main_events, WC_MAIN_WINDOW, WF_STICK_TO_BACK); window->widgets = window_editor_main_widgets; viewport_create(window, window->x, window->y, window->width, window->height, 0, 0x0FFF, 0x0FFF, 0, 0x1, -1); @@ -96,11 +94,7 @@ void window_editor_main_open() * rct2: 0x0066FC97 * This function immediately jumps to 0x00685BE1 */ -static void window_editor_main_paint() { - rct_window* w; - rct_drawpixelinfo* dpi; - - window_paint_get_registers(w, dpi); - +static void window_editor_main_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ viewport_render(dpi, w->viewport, dpi->x, dpi->y, dpi->x + dpi->width, dpi->y + dpi->height); } \ No newline at end of file diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index 6697ec28cc..ffe8457740 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -1,3 +1,4 @@ + /***************************************************************************** * Copyright (c) 2014 Dániel Tar * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. @@ -21,16 +22,20 @@ #include "../addresses.h" #include "../audio/audio.h" #include "../game.h" +#include "../interface/themes.h" #include "../interface/widget.h" #include "../interface/window.h" #include "../localisation/localisation.h" #include "../management/research.h" #include "../object.h" +#include "../rct1.h" +#include "../ride/ride.h" +#include "../ride/ride_data.h" #include "../ride/track.h" #include "../scenario.h" -#include "error.h" -#include "../interface/themes.h" #include "dropdown.h" +#include "error.h" +#include "../util/util.h" enum { @@ -46,7 +51,7 @@ enum { FILTER_RIDE_WATER = (1 << 9), FILTER_RIDE_STALL = (1 << 10), - + FILTER_ALL = 0x7EF, } FILTER_FLAGS; @@ -95,10 +100,10 @@ enum WINDOW_STAFF_LIST_WIDGET_IDX { WIDX_TAB_9, // 12, 1000 WIDX_TAB_10, // 13, 2000 WIDX_TAB_11, // 14, 4000 - WIDX_DROPDOWN1, // 15, 8000 + WIDX_ADVANCED, // 15, 8000 WIDX_LIST, // 16, 10000 WIDX_PREVIEW, // 17, 20000 - WIDX_DROPDOWN2, // 18, 40000 + WIDX_INSTALL_TRACK, // 18, 40000 WIDX_FILTER_DROPDOWN, // 19, 80000 WIDX_FILTER_STRING_BUTTON, // 20, 100000 WIDX_FILTER_CLEAR_BUTTON, // 21, 200000 @@ -109,40 +114,44 @@ enum WINDOW_STAFF_LIST_WIDGET_IDX { WIDX_FILTER_RIDE_TAB_COASTER, WIDX_FILTER_RIDE_TAB_THRILL, WIDX_FILTER_RIDE_TAB_WATER, - WIDX_FILTER_RIDE_TAB_STALL + WIDX_FILTER_RIDE_TAB_STALL, + WIDX_LIST_SORT_TYPE, + WIDX_LIST_SORT_RIDE, }; 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_CAPTION, 0, 1, 598, 1, 14, STR_OBJECT_SELECTION, 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_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_STRING_DEFINED_TOOLTIP }, + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_STRING_DEFINED_TOOLTIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_STRING_DEFINED_TOOLTIP }, + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_STRING_DEFINED_TOOLTIP }, + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_STRING_DEFINED_TOOLTIP }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_STRING_DEFINED_TOOLTIP }, + { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_STRING_DEFINED_TOOLTIP }, + { WWT_TAB, 1, 220, 250, 17, 43, 0x2000144E, STR_STRING_DEFINED_TOOLTIP }, + { WWT_TAB, 1, 251, 281, 17, 43, 0x2000144E, STR_STRING_DEFINED_TOOLTIP }, + { WWT_TAB, 1, 282, 312, 17, 43, 0x2000144E, STR_STRING_DEFINED_TOOLTIP }, + { WWT_TAB, 1, 313, 343, 17, 43, 0x2000144E, STR_STRING_DEFINED_TOOLTIP }, { 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_DROPDOWN_BUTTON, 0, 470, 591, 23, 34, STR_INSTALL_NEW_TRACK_DESIGN, STR_INSTALL_NEW_TRACK_DESIGN_TIP }, + { WWT_DROPDOWN_BUTTON, 0, 350, 463, 23, 34, STR_OBJECT_FILTER, STR_OBJECT_FILTER_TIP }, { 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 }, + { WWT_DROPDOWN_BUTTON, 1, 218, 287, 46, 57, STR_OBJECT_SEARCH_CLEAR, STR_NONE }, + { WWT_IMGBTN, 1, 3, 287, 73, 76, 0xFFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 47, 73, 0x2000144E, STR_OBJECT_FILTER_ALL_RIDES_TIP }, + { WWT_TAB, 1, 34, 64, 47, 73, 0x2000144E, STR_TRANSPORT_RIDES_TIP }, + { WWT_TAB, 1, 65, 95, 47, 73, 0x2000144E, STR_GENTLE_RIDES_TIP }, + { WWT_TAB, 1, 96, 126, 47, 73, 0x2000144E, STR_ROLLER_COASTERS_TIP }, + { WWT_TAB, 1, 127, 157, 47, 73, 0x2000144E, STR_THRILL_RIDES_TIP }, + { WWT_TAB, 1, 158, 188, 47, 73, 0x2000144E, STR_WATER_RIDES_TIP }, + { WWT_TAB, 1, 189, 219, 47, 73, 0x2000144E, STR_SHOPS_STALLS_TIP }, + { WWT_13, 1, 4, 204, 80, 93, STR_NONE, STR_NONE }, + { WWT_13, 1, 205, 291, 80, 93, STR_NONE, STR_NONE }, { WIDGETS_END } }; @@ -150,68 +159,75 @@ static rct_widget window_editor_object_selection_widgets[] = { #pragma region Events -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_close(rct_window *w); +static void window_editor_object_selection_mouseup(rct_window *w, int widgetIndex); +static void window_editor_object_selection_resize(rct_window *w); 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_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); 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_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_editor_object_selection_scroll_mousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_editor_object_selection_scroll_mouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_editor_object_selection_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_editor_object_selection_invalidate(rct_window *w); +static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_editor_object_selection_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); +static void window_editor_object_selection_textinput(rct_window *w, int widgetIndex, char *text); -static void* window_editor_object_selection_events[] = { +static rct_window_event_list window_editor_object_selection_events = { 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, - (void*)window_editor_object_selection_emptysub, - (void*)window_editor_object_selection_emptysub, - (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*)window_editor_object_selection_invalidate, - (void*)window_editor_object_selection_paint, - (void*)window_editor_object_selection_scrollpaint + window_editor_object_selection_mouseup, + window_editor_object_selection_resize, + window_editor_object_selection_mousedown, + window_editor_object_selection_dropdown, + NULL, + window_editor_object_selection_update, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_editor_object_selection_scrollgetsize, + window_editor_object_selection_scroll_mousedown, + NULL, + window_editor_object_selection_scroll_mouseover, + window_editor_object_selection_textinput, + NULL, + NULL, + window_editor_object_selection_tooltip, + NULL, + NULL, + window_editor_object_selection_invalidate, + window_editor_object_selection_paint, + window_editor_object_selection_scrollpaint }; #pragma endregion +const int window_editor_object_selection_animation_loops[] = { 20, 32, 10, 72, 24, 28, 16 }; +const int window_editor_object_selection_animation_divisor[] = { 4, 8, 2, 4, 4, 4, 2 }; + 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 void window_editor_object_selection_select_required_objects(); +static int window_editor_object_selection_select_object(uint8 bh, 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_string(rct_object_entry *entry, rct_object_filters *filter); 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[] = { +void reset_selected_object_count_and_size(); +void reset_required_object_flags(); +static int sub_6AB211(); + +static rct_object_entry RequiredSelectedObjects[] = { // Objects that are always required { 0x00000087, { "SCGTREES" }, 0 }, // Scenery: Trees { 0x00000087, { "SCGSHRUB" }, 0 }, // Scenery: Shrubs and Ornaments @@ -220,31 +236,33 @@ static rct_object_entry DefaultSelectedObjects[] = { { 0x00000087, { "SCGWALLS" }, 0 }, // Scenery: Walls and Roofs { 0x00000087, { "SCGPATHX" }, 0 }, // Scenery: Signs and Items for Footpaths { 0x00000085, { "TARMAC " }, 0 }, // Footpath: Tarmac +}; +static rct_object_entry DefaultSelectedObjects[] = { // 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 + { 0x00000080, { "TWIST1 " }, 0 }, // Ride: Twist + { 0x00000080, { "PTCT1 " }, 0 }, // Ride: Wooden Roller Coaster (Wooden Roller Coaster Trains) + { 0x00000080, { "ZLDB " }, 0 }, // Ride: Junior Roller Coaster (Ladybird Trains) + { 0x00000080, { "LFB1 " }, 0 }, // Ride: Log Flume + { 0x00000080, { "VCR " }, 0 }, // Ride: Vintage Cars + { 0x00000080, { "MGR1 " }, 0 }, // Ride: Merry-Go-Round + { 0x00000080, { "TLT1 " }, 0 }, // Ride: Restroom + { 0x00000080, { "ATM1 " }, 0 }, // Ride: Cash Machine + { 0x00000080, { "FAID1 " }, 0 }, // Ride: First Aid Room + { 0x00000080, { "INFOK " }, 0 }, // Ride: Information Kiosk + { 0x00000080, { "DRNKS " }, 0 }, // Ride: Drinks Stall + { 0x00000080, { "CNDYF " }, 0 }, // Ride: Cotten Candy Stall + { 0x00000080, { "BURGB " }, 0 }, // Ride: Burger Bar + { 0x00000080, { "BALLN " }, 0 }, // Ride: Balloon Stall + { 0x00000080, { "ARRT1 " }, 0 }, // Ride: Corkscrew Roller Coaster + { 0x00000080, { "RBOAT " }, 0 }, // Ride: Rowing Boats + { 0x00000088, { "PKENT1 " }, 0 }, // Park Entrace: Traditional Park Entrance + { 0x00000089, { "WTRCYAN " }, 0 }, // Water: Natural Water + { 0x00000085, { "TARMACB " }, 0 }, // Footpath: Brown Tarmac Footpath + { 0x00000085, { "PATHSPCE" }, 0 }, // Footpath: Space Style Footpath + { 0x00000085, { "PATHDIRT" }, 0 }, // Footpath: Dirt Footpath + { 0x00000085, { "PATHCRZY" }, 0 }, // Footpath: Crazy Paving Footpath + { 0x00000085, { "PATHASH " }, 0 }, // Footpath: Ash Footpath // The following are for all random map generation features to work out the box { 0x00000087, { "SCGJUNGL" }, 0 }, // Jungle Themeing @@ -252,6 +270,110 @@ static rct_object_entry DefaultSelectedObjects[] = { { 0x00000087, { "SCGWATER" }, 0 } // Water Feature Themeing }; +enum { + RIDE_SORT_TYPE, + RIDE_SORT_RIDE +}; + +typedef struct { + rct_object_entry *entry; + rct_object_filters *filter; + uint8 *flags; +} list_item; + +typedef int (*sortFunc)(const void *, const void *); + +static int _numListItems = 0; +static list_item *_listItems = NULL; +static int _listSortType = RIDE_SORT_TYPE; +static bool _listSortDescending = false; + +static void visible_list_dispose() +{ + SafeFree(_listItems); + _numListItems = 0; +} + +static int visible_list_sort_ride_name(const void *rawA, const void *rawB) +{ + list_item *a = (list_item*)rawA; + list_item *b = (list_item*)rawB; + + const char *nameA = object_get_name(a->entry); + const char *nameB = object_get_name(b->entry); + return strcmp(nameA, nameB); +} + +static int visible_list_sort_ride_type(const void *rawA, const void *rawB) +{ + list_item *a = (list_item*)rawA; + list_item *b = (list_item*)rawB; + + const char *rideTypeA = language_get_string(2 + a->filter->ride.ride_type); + const char *rideTypeB = language_get_string(2 + b->filter->ride.ride_type); + int result = strcmp(rideTypeA, rideTypeB); + if (result != 0) + return result; + + return visible_list_sort_ride_name(rawA, rawB); +} + +static void visible_list_refresh(rct_window *w) +{ + int numObjects = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, sint32); + + visible_list_dispose(); + _listItems = malloc(numObjects * sizeof(list_item)); + _numListItems = 0; + + list_item *currentListItem = &_listItems[0]; + rct_object_entry *entry = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + uint8 *itemFlags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + for (int i = 0; i < numObjects; i++) { + rct_object_filters *filter = get_object_filter(i); + int type = entry->flags & 0x0F; + int source = (entry->flags & 0xF0) >> 4; + if (type == w->selected_tab && !(*itemFlags & OBJECT_SELECTION_FLAG_6) && filter_source(entry) && filter_string(entry, filter) && filter_chunks(entry, filter)) { + currentListItem->entry = entry; + currentListItem->filter = filter; + currentListItem->flags = itemFlags; + currentListItem++; + _numListItems++; + } + + entry = object_get_next(entry); + itemFlags++; + } + + _listItems = realloc(_listItems, _numListItems * sizeof(list_item)); + + sortFunc sortFunc = NULL; + switch (_listSortType) { + case RIDE_SORT_TYPE: + sortFunc = visible_list_sort_ride_type; + break; + case RIDE_SORT_RIDE: + sortFunc = visible_list_sort_ride_name; + break; + default: + log_warning("Wrong sort type %d, leaving list as-is.", _listSortType); + window_invalidate(w); + return; + } + qsort(_listItems, _numListItems, sizeof(list_item), sortFunc); + + if (_listSortDescending) { + for (int i = 0; i < _numListItems / 2; i++) { + int ri = _numListItems - i - 1; + list_item temp = _listItems[i]; + _listItems[i] = _listItems[ri]; + _listItems[ri] = temp; + } + } + + window_invalidate(w); +} + /** * * rct2: 0x006AA64E @@ -264,31 +386,30 @@ void window_editor_object_selection_open() if (window != NULL) return; - RCT2_CALLPROC_EBPSAFE(0x006AB211); - RCT2_CALLPROC_EBPSAFE(0x006AA770); - - // 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(); + if (!sub_6AB211()) + return; + reset_selected_object_count_and_size(); window = window_create_centred( 600, 400, - (uint32*)window_editor_object_selection_events, + &window_editor_object_selection_events, WC_EDITOR_OBJECT_SELECTION, - WF_10 + WF_10 | WF_RESIZABLE ); window->widgets = window_editor_object_selection_widgets; window->enabled_widgets = - (1 << WIDX_DROPDOWN1) | - (1 << WIDX_DROPDOWN2) | + (1 << WIDX_ADVANCED) | + (1 << WIDX_INSTALL_TRACK) | (1 << WIDX_FILTER_DROPDOWN) | (1 << WIDX_FILTER_STRING_BUTTON) | (1 << WIDX_FILTER_CLEAR_BUTTON) | - (1 << WIDX_CLOSE); + (1 << WIDX_CLOSE) | + (1 << WIDX_LIST_SORT_TYPE) | + (1 << WIDX_LIST_SORT_RIDE); - _filter_flags = FILTER_ALL; + _filter_flags = gConfigInterface.object_selection_filter_flags; memset(_filter_string, 0, sizeof(_filter_string)); for (int i = WIDX_TAB_1; i <= WIDX_TAB_11; i++) @@ -299,25 +420,345 @@ void window_editor_object_selection_open() window->selected_tab = 0; window->selected_list_item = -1; window->var_494 = 0xFFFFFFFF; + window->min_width = 600; + window->min_height = 400; + window->max_width = 1200; + window->max_height = 1000; + + visible_list_refresh(window); +} + +/* rct2: 0x006ABCD1 */ +static void setup_track_manager_objects(){ + uint8 ride_list[128] = { 0 }; + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + uint16 num_objects = 0; + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + uint8 object_type = installedObject->flags & 0xF; + if (object_type == OBJECT_TYPE_RIDE){ + *selection_flags |= OBJECT_SELECTION_FLAG_6; + + uint8* pos = (uint8*)installedObject; + // Skip sizeof(rct_object_entry) + pos += 16; + + // Skip filename + while (*pos++); + + // Skip no of images + pos += 4; + + // Skip name + while (*pos++); + + // Skip size of chunk + pos += 4; + + // Skip required objects + pos += *pos * 16 + 1; + + // Skip theme objects + pos += *pos * 16 + 1; + + for (uint8 j = 0; j < 3; j++){ + uint8 ride_type = pos[j]; + if (ride_type == 0xFF) + continue; + + if (!(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride_type * 2] & + RIDE_TYPE_FLAG_HAS_TRACK)) + continue; + + if (pos[3] & (1 << 0)){ + *selection_flags &= ~OBJECT_SELECTION_FLAG_6; + } + else if (ride_list[ride_type] & (1 << 0)){ + continue; + } + else{ + ride_list[ride_type] |= (1 << 0); + *selection_flags &= ~OBJECT_SELECTION_FLAG_6; + } + num_objects++; + break; + } + } + + installedObject = object_get_next(installedObject); + selection_flags++; + } + + RCT2_GLOBAL(0x00F43412, uint16) = num_objects; +} + +/* rct2: 0x006ABC1E */ +static void setup_track_designer_objects(){ + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + uint16 num_objects = 0; + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + uint8 object_type = installedObject->flags & 0xF; + if (object_type == OBJECT_TYPE_RIDE){ + *selection_flags |= OBJECT_SELECTION_FLAG_6; + + uint8* pos = (uint8*)installedObject; + // Skip sizeof(rct_object_entry) + pos += 16; + + // Skip filename + while (*pos++); + + // Skip no of images + pos += 4; + + // Skip name + while (*pos++); + + // Skip size of chunk + pos += 4; + + // Skip required objects + pos += *pos * 16 + 1; + + // Skip theme objects + pos += *pos * 16 + 1; + + for (uint8 j = 0; j < 3; j++){ + uint8 ride_type = pos[j]; + if (ride_type == 0xFF) + continue; + + if (!(RideData4[ride_type].flags & RIDE_TYPE_FLAG4_11)) + continue; + + *selection_flags &= ~OBJECT_SELECTION_FLAG_6; + num_objects++; + break; + } + } + + installedObject = object_get_next(installedObject); + selection_flags++; + } + + RCT2_GLOBAL(0x00F43412, uint16) = num_objects; +} + +/* rct2: 0x006AA82B */ +static void setup_in_use_selection_flags(){ + + for (uint8 object_type = 0; object_type < 11; object_type++){ + for (uint16 i = 0; i < object_entry_group_counts[object_type]; i++){ + RCT2_ADDRESS(0x0098DA38, uint8*)[object_type][i] = 0; + } + } + + for (uint8 object_type = 0; object_type < 11; object_type++){ + for (uint16 i = 0; i < object_entry_group_counts[object_type]; i++){ + if (object_entry_groups[object_type].chunks[i] != (uint8*)0xFFFFFFFF){ + RCT2_ADDRESS(0x0098DA38, uint8*)[object_type][i] |= (1 << 1); + } + } + } + + map_element_iterator iter; + map_element_iterator_begin(&iter); + do { + uint16 type; + uint8 path_additions; + rct_banner* banner; + + switch (map_element_get_type(iter.element)) { + default: + case MAP_ELEMENT_TYPE_SURFACE: + case MAP_ELEMENT_TYPE_TRACK: + break; + case MAP_ELEMENT_TYPE_PATH: + type = iter.element->properties.path.type; + type >>= 4; + assert(type < object_entry_group_counts[OBJECT_TYPE_PATHS]); + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_PATHS][type] |= (1 << 0); + + path_additions = iter.element->properties.path.additions & 0xF; + if (path_additions){ + path_additions--; + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_PATH_BITS][path_additions] |= (1 << 0); + } + break; + case MAP_ELEMENT_TYPE_SCENERY: + type = iter.element->properties.scenery.type; + assert(type < object_entry_group_counts[OBJECT_TYPE_SMALL_SCENERY]); + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_SMALL_SCENERY][type] |= (1 << 0); + break; + case MAP_ELEMENT_TYPE_ENTRANCE: + if (iter.element->properties.entrance.type != ENTRANCE_TYPE_PARK_ENTRANCE) + break; + + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_PARK_ENTRANCE][0] |= (1 << 0); + + type = iter.element->properties.entrance.path_type; + assert(type < object_entry_group_counts[OBJECT_TYPE_PATHS]); + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_PATHS][type] |= (1 << 0); + break; + case MAP_ELEMENT_TYPE_FENCE: + type = iter.element->properties.fence.type; + assert(type < object_entry_group_counts[OBJECT_TYPE_WALLS]); + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_WALLS][type] |= (1 << 0); + break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + type = iter.element->properties.scenerymultiple.type & 0x3FF; + assert(type < object_entry_group_counts[OBJECT_TYPE_LARGE_SCENERY]); + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_LARGE_SCENERY][type] |= (1 << 0); + break; + case MAP_ELEMENT_TYPE_BANNER: + banner = &gBanners[iter.element->properties.banner.index]; + type = banner->type; + assert(type < object_entry_group_counts[OBJECT_TYPE_BANNERS]); + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_BANNERS][type] |= (1 << 0); + break; + } + } while (map_element_iterator_next(&iter)); + + for (uint8 ride_index = 0; ride_index < 0xFF; ride_index++){ + rct_ride* ride = GET_RIDE(ride_index); + if (ride->type == RIDE_TYPE_NULL) + continue; + + uint8 type = ride->subtype; + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_RIDE][type] |= (1 << 0); + } + + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + *selection_flags &= ~OBJECT_SELECTION_FLAG_IN_USE; + + uint8 entry_type, entry_index; + if (find_object_in_entry_group(installedObject, &entry_type, &entry_index)){ + if (RCT2_ADDRESS(0x0098DA38, uint8*)[entry_type][entry_index] & (1 << 0)){ + *selection_flags |= + OBJECT_SELECTION_FLAG_IN_USE | + OBJECT_SELECTION_FLAG_SELECTED; + } + if (RCT2_ADDRESS(0x0098DA38, uint8*)[entry_type][entry_index] & (1 << 1)){ + *selection_flags |= OBJECT_SELECTION_FLAG_SELECTED; + } + } + installedObject = object_get_next(installedObject); + selection_flags++; + } +} + +/* rct2: 0x006AB211 */ +static int sub_6AB211(){ + uint32 total_objects = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); + + RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*) = rct2_malloc(total_objects); + + if (RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*) == NULL){ + log_error("Failed to allocate memory for object flag list."); + return 0; + } + + memset(RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*), 0, total_objects); + for (uint8 object_type = 0; object_type < 11; object_type++){ + RCT2_ADDRESS(0x00F433F7, uint16)[object_type] = 0; + RCT2_ADDRESS(0x00F433E1, uint16)[object_type] = 0; + } + + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + uint8 object_type = installedObject->flags & 0xF; + RCT2_ADDRESS(0x00F433E1, uint16)[object_type]++; + + installedObject = object_get_next(installedObject); + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER){ + setup_track_designer_objects(); + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER){ + setup_track_manager_objects(); + } + + setup_in_use_selection_flags(); + reset_selected_object_count_and_size(); + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER))){ + window_editor_object_selection_select_required_objects(); + + // To prevent it breaking in scenario mode. + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) + window_editor_object_selection_select_default_objects(); + } + + reset_required_object_flags(); + reset_selected_object_count_and_size(); + return 1; +} + +/* rct2: 0x006AB316 */ +static void editor_object_flags_free(){ + if (RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*) == NULL){ + return; + } + rct2_free(RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*)); + RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*) = NULL; +} + +/* rct2: 0x00685791 */ +void remove_selected_objects_from_research(rct_object_entry* installedObject){ + uint8 entry_type, entry_index; + if (!find_object_in_entry_group(installedObject, &entry_type, &entry_index)) + return; + + if (entry_type == OBJECT_TYPE_RIDE){ + rct_ride_type* rideEntry = (rct_ride_type*)object_entry_groups[entry_type].chunks[entry_index]; + research_remove(entry_index | rideEntry->ride_type[0] << 8 | 0x10000); + research_remove(entry_index | rideEntry->ride_type[1] << 8 | 0x10000); + research_remove(entry_index | rideEntry->ride_type[2] << 8 | 0x10000); + } + else if (entry_type == OBJECT_TYPE_SCENERY_SETS){ + research_remove(entry_index); + } +} + +/* rct2: 0x006ABB66 */ +void unload_unselected_objects(){ + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + if (!(*selection_flags & OBJECT_SELECTION_FLAG_SELECTED)){ + remove_selected_objects_from_research(installedObject); + object_unload(installedObject); + } + selection_flags++; + installedObject = object_get_next(installedObject); + } } /** - * + * * rct2: 0x006AB199 */ -static void window_editor_object_selection_close() +static void window_editor_object_selection_close(rct_window *w) { - rct_window* w; - window_get_register(w); - //if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_EDITOR)) // return; - RCT2_CALLPROC_EBPSAFE(0x6ABB66); + unload_unselected_objects(); editor_load_selected_objects(); reset_loaded_objects(); object_free_scenario_text(); - RCT2_CALLPROC_EBPSAFE(0x6AB316); + editor_object_flags_free(); + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_EDITOR) { research_populate_list_random(); research_remove_non_separate_vehicle_types(); @@ -331,19 +772,16 @@ static void window_editor_object_selection_close() gSilentResearch = false; } window_new_ride_init_vars(); + + visible_list_dispose(); } /** - * + * * rct2: 0x006AAFAB */ -static void window_editor_object_selection_mouseup() +static void window_editor_object_selection_mouseup(rct_window *w, int widgetIndex) { - rct_window *w; - short widgetIndex; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_EDITOR) { @@ -370,7 +808,11 @@ static void window_editor_object_selection_mouseup() break; case WIDX_FILTER_RIDE_TAB_ALL: _filter_flags |= 0x7E0; + gConfigInterface.object_selection_filter_flags = _filter_flags; + config_save_default(); + filter_update_counts(); + visible_list_refresh(w); w->selected_list_item = -1; w->var_494 = 0xFFFFFFFF; @@ -386,8 +828,11 @@ static void window_editor_object_selection_mouseup() case WIDX_FILTER_RIDE_TAB_STALL: _filter_flags &= ~0x7E0; _filter_flags |= (1 << (widgetIndex - WIDX_FILTER_RIDE_TAB_TRANSPORT + 5)); + gConfigInterface.object_selection_filter_flags = _filter_flags; + config_save_default(); filter_update_counts(); + visible_list_refresh(w); w->selected_list_item = -1; w->var_494 = 0xFFFFFFFF; @@ -396,12 +841,12 @@ static void window_editor_object_selection_mouseup() window_invalidate(w); break; - case WIDX_DROPDOWN1: + case WIDX_ADVANCED: w->list_information_type ^= 1; window_invalidate(w); break; - case WIDX_DROPDOWN2: + case WIDX_INSTALL_TRACK: if (w->selected_list_item != -1) { w->selected_list_item = -1; object_free_scenario_text(); @@ -416,14 +861,37 @@ static void window_editor_object_selection_mouseup() break; case WIDX_FILTER_CLEAR_BUTTON: memset(_filter_string, 0, sizeof(_filter_string)); - + filter_update_counts(); w->scrolls->v_top = 0; - + visible_list_refresh(w); window_invalidate(w); break; + case WIDX_LIST_SORT_TYPE: + if (_listSortType == RIDE_SORT_TYPE) { + _listSortDescending = !_listSortDescending; + } else { + _listSortType = RIDE_SORT_TYPE; + _listSortDescending = false; + } + visible_list_refresh(w); + break; + case WIDX_LIST_SORT_RIDE: + if (_listSortType == RIDE_SORT_RIDE) { + _listSortDescending = !_listSortDescending; + } else { + _listSortType = RIDE_SORT_RIDE; + _listSortDescending = false; + } + visible_list_refresh(w); + break; } } +static void window_editor_object_selection_resize(rct_window *w) +{ + window_set_resize(w, 600, 400, 1200, 1000); +} + void window_editor_object_selection_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) { int num_items; @@ -438,10 +906,10 @@ void window_editor_object_selection_mousedown(int widgetIndex, rct_window*w, rct gDropdownItemsFormat[1] = 1156; gDropdownItemsFormat[2] = 1156; gDropdownItemsFormat[3] = 1156; - gDropdownItemsArgs[0] = 2741; - gDropdownItemsArgs[1] = 5262; - gDropdownItemsArgs[2] = 5263; - gDropdownItemsArgs[3] = 5264; + gDropdownItemsArgs[0] = STR_ROLLERCOASTER_TYCOON_2_DROPDOWN; + gDropdownItemsArgs[1] = STR_OBJECT_FILTER_WW; + gDropdownItemsArgs[2] = STR_OBJECT_FILTER_TT; + gDropdownItemsArgs[3] = STR_OBJECT_FILTER_CUSTOM; window_dropdown_show_text( w->x + widget->left, @@ -454,66 +922,45 @@ void window_editor_object_selection_mousedown(int widgetIndex, rct_window*w, rct gDropdownItemsChecked = _filter_flags & 0xF; break; - + } } -static void window_editor_object_selection_dropdown() +static void window_editor_object_selection_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - 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); + gConfigInterface.object_selection_filter_flags = _filter_flags; + config_save_default(); filter_update_counts(); w->scrolls->v_top = 0; + visible_list_refresh(w); window_invalidate(w); break; } } /** - * + * * rct2: 0x006AB031 */ -static void window_editor_object_selection_scrollgetsize() +static void window_editor_object_selection_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - 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); + *height = _numListItems * 12; } /** - * + * * rct2: 0x006AB0B6 */ -static void window_editor_object_selection_scroll_mousedown() +static void window_editor_object_selection_scroll_mousedown(rct_window *w, int scrollIndex, int x, int y) { - 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); @@ -521,16 +968,16 @@ static void window_editor_object_selection_scroll_mousedown() 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)) + if (selected_object == -1 || (object_selection_flags & OBJECT_SELECTION_FLAG_6)) return; window_invalidate(w); - sound_play_panned(SOUND_CLICK_1, RCT2_GLOBAL(0x142406C,uint32), 0, 0, 0); + audio_play_sound_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)) + if (!window_editor_object_selection_select_object(0, 1, installed_entry)) return; // Close any other open windows such as options/colour schemes to prevent a crash. @@ -544,16 +991,16 @@ static void window_editor_object_selection_scroll_mousedown() int ebx = 6; // If already selected - if (!(object_selection_flags & 1)) + if (!(object_selection_flags & OBJECT_SELECTION_FLAG_SELECTED)) ebx = 7; RCT2_GLOBAL(0xF43411, uint8) = 0; - if (!window_editor_object_selection_select_object(ebx, installed_entry)) { + if (!window_editor_object_selection_select_object(0, 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)); + window_error_open(error_title, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16)); return; } @@ -564,23 +1011,19 @@ static void window_editor_object_selection_scroll_mousedown() } /** - * + * * rct2: 0x006AB079 */ -static void window_editor_object_selection_scroll_mouseover() +static void window_editor_object_selection_scroll_mouseover(rct_window *w, int scrollIndex, int x, int y) { - 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) + if (objectSelectionFlags & OBJECT_SELECTION_FLAG_6) selectedObject = -1; if (selectedObject == w->selected_list_item) @@ -596,16 +1039,11 @@ static void window_editor_object_selection_scroll_mouseover() } /** - * + * * rct2: 0x006AB058 */ -static void window_editor_object_selection_tooltip() +static void window_editor_object_selection_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) { - rct_window *w; - short widgetIndex; - - window_scroll_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_TAB_1: case WIDX_TAB_2: @@ -628,40 +1066,57 @@ static void window_editor_object_selection_tooltip() } /** - * + * * rct2: 0x006AA9FD */ -static void window_editor_object_selection_invalidate() +static void window_editor_object_selection_invalidate(rct_window *w) { int i, x; - rct_window *w; rct_widget *widget; - window_get_register(w); colour_scheme_update(w); + // Resize widgets + w->widgets[WIDX_BACKGROUND].right = w->width - 1; + w->widgets[WIDX_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; + w->widgets[WIDX_TAB_CONTENT_PANEL].right = w->width - 1; + w->widgets[WIDX_TAB_CONTENT_PANEL].bottom = w->height - 1; + w->widgets[WIDX_ADVANCED].left = w->width - 130; + w->widgets[WIDX_ADVANCED].right = w->width - 9; + w->widgets[WIDX_LIST].right = w->width - 309; + w->widgets[WIDX_LIST].bottom = w->height - 14; + w->widgets[WIDX_PREVIEW].left = w->width - 209; + w->widgets[WIDX_PREVIEW].right = w->width - 96; + w->widgets[WIDX_INSTALL_TRACK].left = w->width - 130; + w->widgets[WIDX_INSTALL_TRACK].right = w->width - 9; + w->widgets[WIDX_FILTER_DROPDOWN].left = w->width - 250; + w->widgets[WIDX_FILTER_DROPDOWN].right = w->width - 137; + // 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); + w->pressed_widgets |= (1 << WIDX_ADVANCED); else - w->pressed_widgets &= ~(1 << WIDX_DROPDOWN1); + w->pressed_widgets &= ~(1 << WIDX_ADVANCED); // 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; + w->widgets[WIDX_INSTALL_TRACK].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; + w->widgets[WIDX_INSTALL_TRACK].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; + w->widgets[WIDX_INSTALL_TRACK].type = WWT_EMPTY; } // Align tabs, hide advanced ones @@ -680,25 +1135,28 @@ static void window_editor_object_selection_invalidate() } 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; + w->widgets[WIDX_ADVANCED].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; + w->widgets[WIDX_ADVANCED].type = WWT_DROPDOWN_BUTTON; x = 300; } - w->widgets[WIDX_LIST].right = 587 - x; - w->widgets[WIDX_PREVIEW].left = 537 - (x >> 1); + w->widgets[WIDX_FILTER_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_LIST].right = w->width - (600 - 587) - x; + w->widgets[WIDX_PREVIEW].left = w->width - (600 - 537) - (x / 2); w->widgets[WIDX_PREVIEW].right = w->widgets[WIDX_PREVIEW].left + 113; + w->widgets[WIDX_FILTER_RIDE_TAB_FRAME].right = w->widgets[WIDX_LIST].right; bool ridePage = (w->selected_tab == WINDOW_OBJECT_SELECTION_PAGE_RIDE_VEHICLES_ATTRACTIONS); - w->widgets[WIDX_LIST].top = (ridePage ? 94 : 60); + w->widgets[WIDX_LIST].top = (ridePage ? 118 : 60); + w->widgets[WIDX_FILTER_STRING_BUTTON].right = w->widgets[WIDX_LIST].right - 77; 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].left = w->widgets[WIDX_LIST].right - 73; + w->widgets[WIDX_FILTER_CLEAR_BUTTON].right = w->widgets[WIDX_LIST].right; w->widgets[WIDX_FILTER_CLEAR_BUTTON].top = (ridePage ? 80 : 46); w->widgets[WIDX_FILTER_CLEAR_BUTTON].bottom = (ridePage ? 91 : 57); @@ -716,36 +1174,43 @@ static void window_editor_object_selection_invalidate() w->pressed_widgets |= (uint64)(1 << (WIDX_FILTER_RIDE_TAB_TRANSPORT + i)); } } - w->widgets[WIDX_FILTER_RIDE_TAB_FRAME].type = WWT_RESIZE; + w->widgets[WIDX_FILTER_RIDE_TAB_FRAME].type = WWT_IMGBTN; for (int i = WIDX_FILTER_RIDE_TAB_ALL; i <= WIDX_FILTER_RIDE_TAB_STALL; i++) w->widgets[i].type = WWT_TAB; - } - else { + + w->widgets[WIDX_LIST_SORT_TYPE].type = WWT_13; + w->widgets[WIDX_LIST_SORT_TYPE].top = w->widgets[WIDX_FILTER_STRING_BUTTON].bottom + 3; + w->widgets[WIDX_LIST_SORT_TYPE].bottom = w->widgets[WIDX_LIST_SORT_TYPE].top + 13; + w->widgets[WIDX_LIST_SORT_RIDE].type = WWT_13; + w->widgets[WIDX_LIST_SORT_RIDE].top = w->widgets[WIDX_LIST_SORT_TYPE].top; + w->widgets[WIDX_LIST_SORT_RIDE].bottom = w->widgets[WIDX_LIST_SORT_TYPE].bottom; + w->widgets[WIDX_LIST_SORT_RIDE].right = w->widgets[WIDX_LIST].right; + w->widgets[WIDX_LIST].top = w->widgets[WIDX_LIST_SORT_TYPE].bottom + 2; + } 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; + + w->widgets[WIDX_LIST_SORT_TYPE].type = WWT_EMPTY; + w->widgets[WIDX_LIST_SORT_RIDE].type = WWT_EMPTY; } } /** - * + * * rct2: 0x006AAB56 */ -static void window_editor_object_selection_paint() +static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinfo *dpi) { 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, @@ -770,18 +1235,28 @@ static void window_editor_object_selection_paint() gfx_draw_sprite(dpi, 5458 + i, x, y, 0); } - const int ride_tabs[] = { 5458, 0x200015A1, 5542, 0x200015AA, 5557 + 5, 5551, 5530, 5327 }; + const int ride_tabs[] = { 5458, 0x200015A1, 5542, 0x200015AA, 5557, 5551, 5530, 5327 }; + const int ThrillRidesTabAnimationSequence[] = { + 5, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0 + }; // 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]; + widget = &w->widgets[WIDX_FILTER_RIDE_TAB_ALL + i]; if (widget->type == WWT_EMPTY) continue; + int spriteIndex = ride_tabs[i]; + int frame = 0; + if (i != 0 && w->pressed_widgets & (1ULL << (WIDX_FILTER_RIDE_TAB_ALL + i))) { + frame = w->frame_no / window_editor_object_selection_animation_divisor[i - 1]; + } + spriteIndex += (i == 4 ? ThrillRidesTabAnimationSequence[frame] : frame); + x = w->x + widget->left; y = w->y + widget->top; - gfx_draw_sprite(dpi, ride_tabs[i] | (w->colours[1] << 19), x, y, 0); + gfx_draw_sprite(dpi, spriteIndex | (w->colours[1] << 19), x, y, 0); } } @@ -794,7 +1269,7 @@ static void window_editor_object_selection_paint() w->y + widget->top + 1, w->x + widget->right - 1, w->y + widget->bottom - 1, - RCT2_ADDRESS(0x0141FC44, uint8)[w->colours[1] * 8] + ColourMapA[w->colours[1]].darkest ); // Draw number of selected items @@ -834,6 +1309,18 @@ static void window_editor_object_selection_paint() w->x + window_editor_object_selection_widgets[WIDX_FILTER_STRING_BUTTON].right );*/ + // Draw sort button text + widget = &w->widgets[WIDX_LIST_SORT_TYPE]; + if (widget->type != WWT_EMPTY) { + stringId = _listSortType == RIDE_SORT_TYPE ? (_listSortDescending ? STR_DOWN : STR_UP) : STR_NONE; + gfx_draw_string_left_clipped(dpi, STR_OBJECTS_SORT_TYPE, &stringId, w->colours[1], w->x + widget->left + 1, w->y + widget->top + 1, widget->right - widget->left); + } + widget = &w->widgets[WIDX_LIST_SORT_RIDE]; + if (widget->type != WWT_EMPTY) { + stringId = _listSortType == RIDE_SORT_RIDE ? (_listSortDescending ? STR_DOWN : STR_UP) : STR_NONE; + gfx_draw_string_left_clipped(dpi, STR_OBJECTS_SORT_RIDE, &stringId, w->colours[1], w->x + widget->left + 1, w->y + widget->top + 1, widget->right - widget->left); + } + if (w->selected_list_item == -1 || stex_entry == NULL) return; @@ -852,13 +1339,13 @@ static void window_editor_object_selection_paint() width = w->width - w->widgets[WIDX_LIST].right - 6; // Skip object dat name - text = (char*)(highlightedEntry + 1); - datName = text; + text = (uint8*)(highlightedEntry + 1); + datName = (char*)text; do { text++; } while (*(text - 1) != 0); text += 4; - name = text; + name = (char*)text; RCT2_GLOBAL(0x009BC677, uint8) = 14; @@ -888,7 +1375,7 @@ static void window_editor_object_selection_paint() 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; @@ -897,14 +1384,14 @@ static void window_editor_object_selection_paint() // 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; + case 8: stringId = STR_ROLLERCOASTER_TYCOON_2_DROPDOWN; break; + case 1: stringId = STR_OBJECT_FILTER_WW; break; + case 2: stringId = STR_OBJECT_FILTER_TT; break; + default: stringId = STR_OBJECT_FILTER_CUSTOM; 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; @@ -929,84 +1416,77 @@ static void window_editor_object_selection_paint() } /** - * + * * rct2: 0x006AADA3 */ -static void window_editor_object_selection_scrollpaint() +static void window_editor_object_selection_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { - 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; + int x, y, i, colour, colour2; - window_scrollpaint_get_registers(w, dpi, scrollIndex); + bool ridePage = (w->selected_tab == WINDOW_OBJECT_SELECTION_PAGE_RIDE_VEHICLES_ATTRACTIONS); - colour = RCT2_ADDRESS(0x0141FC48, uint8)[w->colours[1] * 8]; + colour = ColourMapA[w->colours[1]].mid_light; 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); + for (i = 0; i < _numListItems; i++) { + list_item *listItem = &_listItems[i]; - // 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; - } + if (y + 12 >= dpi->y && y <= dpi->y + dpi->height) { + // Draw checkbox + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) && !(*listItem->flags & 0x20)) + gfx_fill_rect_inset(dpi, 2, y, 11, y + 10, w->colours[1], 0xE0); - // 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); + // Highlight background + colour = 142; + if (listItem->entry == (rct_object_entry*)w->var_494 && !(*listItem->flags & OBJECT_SELECTION_FLAG_6)) { + gfx_fill_rect(dpi, 0, y, w->width, y + 11, 0x2000031); + colour = 14; } - y += 12; - } - entry = object_get_next(entry); - itemFlags++; + // Draw checkmark + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) && (*listItem->flags & OBJECT_SELECTION_FLAG_SELECTED)) { + x = 2; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16) = colour == 14 ? -2 : -1; + colour2 = w->colours[1] & 0x7F; + if (*listItem->flags & (OBJECT_SELECTION_FLAG_IN_USE | OBJECT_SELECTION_FLAG_REQUIRED | OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED)) + colour2 |= 0x40; + + gfx_draw_string(dpi, (char*)CheckBoxMarkString, colour2, x, y); + } + + x = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER ? 0 : 15; + + char *bufferWithColour = (char*)0x0141ED68; + char *buffer = utf8_write_codepoint(bufferWithColour, colour); + if (*listItem->flags & OBJECT_SELECTION_FLAG_6) { + 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; + } + + if (ridePage) { + // Draw ride type + strcpy(buffer, language_get_string(2 + listItem->filter->ride.ride_type)); + gfx_draw_string(dpi, bufferWithColour, colour, x, y); + x = w->widgets[WIDX_LIST_SORT_RIDE].left - w->widgets[WIDX_LIST].left; + } + + // Draw text + strcpy(buffer, object_get_name(listItem->entry)); + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { + while (*buffer != 0 && *buffer != 9) + buffer++; + + *buffer = 0; + } + gfx_draw_string(dpi, bufferWithColour, colour, x, y); + } + y += 12; } } @@ -1020,6 +1500,16 @@ static void window_editor_object_set_page(rct_window *w, int page) w->var_494 = 0xFFFFFFFF; w->scrolls[0].v_top = 0; object_free_scenario_text(); + + if (page == WINDOW_OBJECT_SELECTION_PAGE_RIDE_VEHICLES_ATTRACTIONS) { + _listSortType = RIDE_SORT_TYPE; + _listSortDescending = false; + } else { + _listSortType = RIDE_SORT_RIDE; + _listSortDescending = false; + } + + visible_list_refresh(w); window_invalidate(w); } @@ -1032,27 +1522,361 @@ static void window_editor_object_selection_set_pressed_tab(rct_window *w) } /** - * - * rct2: 0x006AA7E9 - */ +* +* rct2: 0x006AA805 +*/ static void window_editor_object_selection_select_default_objects() { int i; - if (RCT2_GLOBAL(0x00F433F7, uint16) == 0) + if (RCT2_GLOBAL(0x00F433F7, uint16) != 0) return; for (i = 0; i < countof(DefaultSelectedObjects); i++) - window_editor_object_selection_select_object(7, &DefaultSelectedObjects[i]); + window_editor_object_selection_select_object(0, 7, &DefaultSelectedObjects[i]); +} + +/** + * + * rct2: 0x006AA7E9 + */ +static void window_editor_object_selection_select_required_objects() +{ + int i; + + for (i = 0; i < countof(RequiredSelectedObjects); i++) + window_editor_object_selection_select_object(0, 0xF, &RequiredSelectedObjects[i]); +} + +/* rct2: 0x006AA770 */ +void reset_selected_object_count_and_size(){ + for (uint8 object_type = 0; object_type < 11; object_type++){ + RCT2_ADDRESS(0x00F433F7, uint16)[object_type] = 0; + } + + uint32 total_object_size = 0; + + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + uint8 object_type = installedObject->flags & 0xF; + + if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED){ + uint8* pos = (uint8*)installedObject; + // Skip sizeof(rct_object_entry) + pos += 16; + + // Skip filename + while (*pos++); + + // Skip no of images + pos += 4; + + // Skip name + while (*pos++); + + uint32 size_of_chunk = *((uint32*)pos); + RCT2_ADDRESS(0x00F433F7, uint16)[object_type]++; + total_object_size += size_of_chunk; + } + selection_flags++; + installedObject = object_get_next(installedObject); + } + + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_OBJECTS_FILE_SIZE, uint32) = total_object_size; +} + +/* rct2: 0x006AB863 */ +void set_required_object_flags(rct_object_entry* required_object){ + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + if (object_entry_compare(required_object, installedObject)){ + *selection_flags |= OBJECT_SELECTION_FLAG_REQUIRED; + + uint8* pos = (uint8*)installedObject; + // Skip sizeof(rct_object_entry) + pos += 16; + + // Skip filename + while (*pos++); + + // Skip no of images + pos += 4; + + // Skip name + while (*pos++); + + // Skip size of chunk + pos += 4; + + uint8 no_required_objects = *pos++; + + required_object = (rct_object_entry*)pos; + for (; no_required_objects > 0; no_required_objects--){ + set_required_object_flags(required_object); + required_object++; + } + return; + } + + selection_flags++; + installedObject = object_get_next(installedObject); + } +} + +/* rct2: 0x006AB923 */ +void reset_required_object_flags(){ + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + *selection_flags &= ~OBJECT_SELECTION_FLAG_REQUIRED; + selection_flags++; + } + + selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED){ + uint8* pos = (uint8*)installedObject; + // Skip sizeof(rct_object_entry) + pos += 16; + + // Skip filename + while (*pos++); + + // Skip no of images + pos += 4; + + // Skip name + while (*pos++); + + // Skip size of chunk + pos += 4; + + uint8 no_required_objects = *pos++; + + rct_object_entry* required_object = (rct_object_entry*)pos; + for (; no_required_objects > 0; no_required_objects--){ + set_required_object_flags(required_object); + required_object++; + } + + } + + selection_flags++; + installedObject = object_get_next(installedObject); + } +} + +/* + * Master objects are objects that are not + * optional / required dependants of an + * object. + */ +void set_object_selection_error(uint8 is_master_object, rct_string_id error_msg){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = error_msg; + if (!is_master_object){ + reset_selected_object_count_and_size(); + } } /** * * rct2: 0x006AB54F */ -static int window_editor_object_selection_select_object(int flags, rct_object_entry *entry) +static int window_editor_object_selection_select_object(uint8 bh, int flags, rct_object_entry *entry) { - return (RCT2_CALLPROC_X(0x006AB54F, 0, flags, 0, 0, 0, 0, (int)entry) & 0x100) == 0; + uint8* selection_flags; + //if (bh == 0){ + // // Unsure what this does?? + // uint16 total_objects = 0; + // for (uint8 i = 0; i < 11; ++i){ + // total_objects += RCT2_ADDRESS(0x00F433E1, uint16)[i]; + // } + + // selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + // for (; total_objects != 0; total_objects--, selection_flags++){ + // uint8 select_flag = *selection_flags & ~OBJECT_SELECTION_FLAG_2; + // if (select_flag & OBJECT_SELECTION_FLAG_SELECTED){ + // select_flag |= OBJECT_SELECTION_FLAG_2; + // } + // } + //} + + selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + // There was previously a check to make sure the object list had an item + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + uint8 not_found = 1; + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + if (object_entry_compare(entry, installedObject)){ + not_found = 0; + break; + } + + installedObject = object_get_next(installedObject); + selection_flags++; + } + if (not_found){ + set_object_selection_error(bh, 3169); + return 0; + } + + if (!(flags & 1)){ + if (!(*selection_flags & OBJECT_SELECTION_FLAG_SELECTED)) + { + if (bh == 0){ + reset_required_object_flags(); + } + return 1; + } + else if (*selection_flags & OBJECT_SELECTION_FLAG_IN_USE){ + set_object_selection_error(bh, 3173); + return 0; + } + else if (*selection_flags & OBJECT_SELECTION_FLAG_REQUIRED){ + set_object_selection_error(bh, 3174); + return 0; + } + else if (*selection_flags & OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED){ + set_object_selection_error(bh, 3175); + return 0; + } + + uint8* pos = (uint8*)installedObject; + // Skip sizeof(rct_object_entry) + pos += 16; + + // Skip filename + while (*pos++); + + // Skip no of images + pos += 4; + + // Skip name + while (*pos++); + + uint32 size_of_chunk = *((uint32*)pos); + // Skip size of chunk + pos += 4; + + // Skip required objects + pos += *pos * 16 + 1; + + uint8 no_theme_objects = *pos++; + + if (no_theme_objects != 0 && flags&(1 << 2)){ + rct_object_entry* theme_object = (rct_object_entry*)pos; + for (; no_theme_objects > 0; no_theme_objects--){ + window_editor_object_selection_select_object(++bh, flags, theme_object); + theme_object++; + } + } + + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_OBJECTS_FILE_SIZE, uint32) -= size_of_chunk; + uint8 object_type = installedObject->flags & 0xF; + RCT2_ADDRESS(0x00F433F7, uint16)[object_type]--; + *selection_flags &= ~OBJECT_SELECTION_FLAG_SELECTED; + if (bh == 0){ + reset_required_object_flags(); + } + return 1; + } + else{ + if (bh == 0){ + if (flags & (1 << 3)){ + *selection_flags |= OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED; + } + } + if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED){ + if (bh == 0){ + reset_required_object_flags(); + } + return 1; + } + + uint8 object_type = installedObject->flags & 0xF; + uint16 no_objects = object_entry_group_counts[object_type]; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER){ + no_objects = 4; + } + + if (no_objects <= RCT2_ADDRESS(0x00F433F7, uint16)[object_type]){ + set_object_selection_error(bh, 3171); + return 0; + } + + uint8* pos = (uint8*)installedObject; + // Skip sizeof(rct_object_entry) + pos += 16; + + // Skip filename + while (*pos++); + + // Skip no of images + pos += 4; + + // Skip name + while (*pos++); + + uint32 size_of_chunk = *((uint32*)pos); + // Skip size of chunk + pos += 4; + + uint8 num_required_objects = *pos++; + rct_object_entry* required_objects = (rct_object_entry*)pos; + for (; num_required_objects != 0; num_required_objects--){ + if (!window_editor_object_selection_select_object(++bh, flags, required_objects)){ + if (bh != 0){ + reset_selected_object_count_and_size(); + } + return 0; + } + required_objects++; + } + pos = (uint8*)required_objects; + + uint8 num_theme_objects = *pos++; + rct_object_entry* theme_object = (rct_object_entry*)pos; + for (; num_theme_objects != 0; num_theme_objects--){ + if (flags & (1 << 2)){ + if (!window_editor_object_selection_select_object(++bh, flags, theme_object)){ + RCT2_GLOBAL(0x00F43411, uint8) |= 1; + } + } + theme_object++; + } + + if (bh != 0 && !(flags&(1 << 1))){ + uint32* arguments = RCT2_ADDRESS(0x0013CE952, uint32); + object_create_identifier_name((char*)0x009BC95A, installedObject); + *arguments = (uint32)0x009BC95A; + set_object_selection_error(bh, 3172); + return 0; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_OBJECTS_FILE_SIZE, uint32) + size_of_chunk > 0x40000){ + set_object_selection_error(bh, 3170); + return 0; + } + + if (no_objects <= RCT2_ADDRESS(0x00F433F7, uint16)[object_type]){ + set_object_selection_error(bh, 3171); + return 0; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_OBJECTS_FILE_SIZE, uint32) += size_of_chunk; + RCT2_ADDRESS(0x00F433F7, uint16)[object_type]++; + + *selection_flags |= OBJECT_SELECTION_FLAG_SELECTED; + if (bh == 0){ + reset_required_object_flags(); + } + return 1; + } } /** @@ -1065,31 +1889,18 @@ static int window_editor_object_selection_select_object(int flags, rct_object_en */ 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++; - } - } + int listItemIndex = y / 12; + if (listItemIndex < 0 || listItemIndex >= _numListItems) + return -1; - *installed_entry = object_get_next(*installed_entry); - selection_flags++; - } - return -1; + list_item *listItem = &_listItems[listItemIndex]; + *object_selection_flags = *listItem->flags; + *installed_entry = listItem->entry; + return listItemIndex; } /** - * + * * rct2: 0x006D33E2 */ static void window_editor_object_selection_manage_tracks() @@ -1128,7 +1939,7 @@ static void window_editor_object_selection_manage_tracks() } /** - * + * * rct2: 0x006ABBBE */ static void editor_load_selected_objects() @@ -1140,7 +1951,7 @@ static void editor_load_selected_objects() return; for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i != 0; i--, selection_flags++) { - if (*selection_flags & 1) { + if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED) { uint8 entry_index, entry_type; if (!find_object_in_entry_group(installed_entry, &entry_type, &entry_index)){ int chunk_size; @@ -1161,18 +1972,23 @@ static void window_editor_object_selection_update(rct_window *w) window_update_textbox_caret(); widget_invalidate(w, WIDX_FILTER_STRING_BUTTON); } + + for (int i = WIDX_FILTER_RIDE_TAB_TRANSPORT; i <= WIDX_FILTER_RIDE_TAB_STALL; i++) { + if (!(w->pressed_widgets & (1ULL << i))) + continue; + + w->frame_no++; + if (w->frame_no >= window_editor_object_selection_animation_loops[i - WIDX_FILTER_RIDE_TAB_TRANSPORT]) + w->frame_no = 0; + + widget_invalidate(w, i); + break; + } } -static void window_editor_object_selection_textinput() +static void window_editor_object_selection_textinput(rct_window *w, int widgetIndex, char *text) { - uint8 result; - short widgetIndex; - rct_window *w; - char *text; - - window_textinput_get_registers(w, widgetIndex, result, text); - - if (widgetIndex != WIDX_FILTER_STRING_BUTTON || !result) + if (widgetIndex != WIDX_FILTER_STRING_BUTTON || text == NULL) return; if (strcmp(_filter_string, text) == 0) @@ -1183,36 +1999,48 @@ static void window_editor_object_selection_textinput() } else { memset(_filter_string, 0, sizeof(_filter_string)); - strcpy(_filter_string, text); + safe_strncpy(_filter_string, text, sizeof(_filter_string)); } filter_update_counts(); w->scrolls->v_top = 0; + visible_list_refresh(w); window_invalidate(w); } -static bool filter_string(rct_object_entry *entry) +static bool filter_string(rct_object_entry *entry, rct_object_filters *filter) { - if (_filter_string[0] == 0) + // Nothing to search for + if (_filter_string[0] == '\0') return true; + // Object doesn't have a name char *name = object_get_name(entry); - if (name[0] == 0) + 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); + // Get ride type + const char *ride_type = language_get_string(2 + filter->ride.ride_type); - for (int i = 0; i < (int)strlen(name_lower); i++) + // Get object name (ride/vehicle for rides) and type name (rides only) + char name_lower[MAX_PATH]; + char type_lower[MAX_PATH]; + char filter_lower[sizeof(_filter_string)]; + safe_strncpy(name_lower, name, MAX_PATH); + safe_strncpy(type_lower, ride_type, MAX_PATH); + safe_strncpy(filter_lower, _filter_string, sizeof(_filter_string)); + + // Make use of lowercase characters only + for (int i = 0; name_lower[i] != '\0'; i++) name_lower[i] = (char)tolower(name_lower[i]); - for (int i = 0; i < (int)strlen(filter_lower); i++) + for (int i = 0; type_lower[i] != '\0'; i++) + type_lower[i] = (char)tolower(type_lower[i]); + for (int i = 0; filter_lower[i] != '\0'; i++) filter_lower[i] = (char)tolower(filter_lower[i]); - return strstr(name_lower, filter_lower) != NULL; + return strstr(name_lower, filter_lower) != NULL || (((entry->flags & 0x0F) == OBJECT_TYPE_RIDE) && strstr(type_lower, filter_lower) != NULL); } static bool filter_source(rct_object_entry *entry) @@ -1228,11 +2056,16 @@ 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; - + if(!gConfigInterface.select_by_track_type) { + if (_filter_flags & (1 << (filter->ride.category[0] + 5))) + return true; + if (_filter_flags & (1 << (filter->ride.category[1] + 5))) + return true; + } + else { + if (_filter_flags & (1 << (gRideCategories[filter->ride.ride_type] + 5))) + return true; + } return false; } return true; @@ -1250,7 +2083,7 @@ static void filter_update_counts() 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)) { + if (filter_source(installed_entry) && filter_string(installed_entry, filter) && 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 52071d8287..d1cc24b9ea 100644 --- a/src/windows/editor_objective_options.c +++ b/src/windows/editor_objective_options.c @@ -29,8 +29,7 @@ #include "dropdown.h" #include "error.h" #include "../interface/themes.h" - -#define DISABLE_SIX_FLAGS_CHECKBOX +#include "../util/util.h" #pragma region Widgets @@ -63,7 +62,6 @@ enum { WIDX_CATEGORY, WIDX_CATEGORY_DROPDOWN, WIDX_DETAILS, - WIDX_SIX_FLAGS, WIDX_RIDES = 6 }; @@ -90,7 +88,6 @@ static rct_widget window_editor_objective_options_main_widgets[] = { { 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 } }; @@ -114,94 +111,92 @@ static rct_widget *window_editor_objective_options_widgets[] = { #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_mouseup(rct_window *w, int widgetIndex); +static void window_editor_objective_options_main_resize(rct_window *w); 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_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); 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_main_textinput(rct_window *w, int widgetIndex, char *text); +static void window_editor_objective_options_main_invalidate(rct_window *w); +static void window_editor_objective_options_main_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_editor_objective_options_rides_mouseup(); -static void window_editor_objective_options_rides_resize(); +static void window_editor_objective_options_rides_mouseup(rct_window *w, int widgetIndex); +static void window_editor_objective_options_rides_resize(rct_window *w); 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(); +static void window_editor_objective_options_rides_scrollgetheight(rct_window *w, int scrollIndex, int *width, int *height); +static void window_editor_objective_options_rides_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_editor_objective_options_rides_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_editor_objective_options_rides_invalidate(rct_window *w); +static void window_editor_objective_options_rides_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_editor_objective_options_rides_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); // 0x009A9DF4 -static void* window_objective_options_main_events[] = { - window_editor_objective_options_emptysub, +static rct_window_event_list window_objective_options_main_events = { + NULL, 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, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, window_editor_objective_options_main_invalidate, window_editor_objective_options_main_paint, - window_editor_objective_options_emptysub + NULL }; // 0x009A9F58 -static void* window_objective_options_rides_events[] = { - window_editor_objective_options_emptysub, +static rct_window_event_list window_objective_options_rides_events = { + NULL, 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, + NULL, + NULL, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_editor_objective_options_rides_scrollgetheight, window_editor_objective_options_rides_scrollmousedown, - window_editor_objective_options_emptysub, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, 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 +static rct_window_event_list *window_editor_objective_options_page_events[] = { + &window_objective_options_main_events, + &window_objective_options_rides_events }; #pragma endregion @@ -224,8 +219,7 @@ static uint64 window_editor_objective_options_page_enabled_widgets[] = { (1 << WIDX_SCENARIO_NAME) | (1 << WIDX_CATEGORY) | (1 << WIDX_CATEGORY_DROPDOWN) | - (1 << WIDX_DETAILS) | - (1 << WIDX_SIX_FLAGS), + (1 << WIDX_DETAILS), (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | @@ -243,6 +237,8 @@ static uint64 window_editor_objective_options_page_hold_down_widgets[] = { #pragma endregion +static void window_editor_objective_options_update_disabled_widgets(rct_window *w); + /** * * rct2: 0x0067137D @@ -258,7 +254,7 @@ void window_editor_objective_options_open() w = window_create_centred( 450, 228, - (uint32*)window_objective_options_main_events, + &window_objective_options_main_events, WC_EDTIOR_OBJECTIVE_OPTIONS, WF_10 ); @@ -271,7 +267,7 @@ void window_editor_objective_options_open() 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); + window_editor_objective_options_update_disabled_widgets(w); } static void window_editor_objective_options_set_pressed_tab(rct_window *w) @@ -337,7 +333,7 @@ static void window_editor_objective_options_set_page(rct_window *w, int 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_editor_objective_options_update_disabled_widgets(w); window_event_resize_call(w); window_event_invalidate_call(w); window_init_scroll_widgets(w); @@ -393,13 +389,9 @@ static void window_editor_objective_options_set_objective(rct_window *w, int obj * * rct2: 0x006719CA */ -static void window_editor_objective_options_main_mouseup() +static void window_editor_objective_options_main_mouseup(rct_window *w, int widgetIndex) { rct_s6_info *s6Info = (rct_s6_info*)0x00141F570; - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); switch (widgetIndex) { case WIDX_CLOSE: @@ -410,21 +402,17 @@ static void window_editor_objective_options_main_mouseup() window_editor_objective_options_set_page(w, widgetIndex - WIDX_TAB_1); break; case WIDX_PARK_NAME: - RCT2_GLOBAL(0x013CE962, uint32) = RCT2_GLOBAL(0x013573D8, uint32); + RCT2_GLOBAL(0x013CE962, uint32) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME_ARGS, 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); + safe_strncpy((char*)0x009BC677, s6Info->name, 64); + window_text_input_open(w, WIDX_SCENARIO_NAME, STR_SCENARIO_NAME, STR_ENTER_SCENARIO_NAME, 3165, 0, 64); break; case WIDX_DETAILS: - strcpy((char*)0x009BC677, s6Info->details); + safe_strncpy((char*)0x009BC677, s6Info->details, 256); 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; } } @@ -432,12 +420,8 @@ static void window_editor_objective_options_main_mouseup() * * rct2: 0x00672254 */ -static void window_editor_objective_options_main_resize() +static void window_editor_objective_options_main_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 450, 229, 450, 229); } @@ -513,7 +497,7 @@ static void window_editor_objective_options_show_objective_dropdown(rct_window * 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); + dropdown_set_checked(i, true); break; } } @@ -523,7 +507,7 @@ 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++) { @@ -539,7 +523,7 @@ static void window_editor_objective_options_show_climate_dropdown(rct_window *w) 4, dropdownWidget->right - dropdownWidget->left - 3 ); - gDropdownItemsChecked = (1 << RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, uint8)); + dropdown_set_checked(RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, uint8), true); } static void window_editor_objective_options_show_category_dropdown(rct_window *w) @@ -547,7 +531,7 @@ 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++) { @@ -563,7 +547,7 @@ static void window_editor_objective_options_show_category_dropdown(rct_window *w 5, dropdownWidget->right - dropdownWidget->left - 3 ); - gDropdownItemsChecked = (1 << s6Info->category); + dropdown_set_checked(s6Info->category, true); } static void window_editor_objective_options_arg_1_increase(rct_window *w) @@ -607,7 +591,7 @@ static void window_editor_objective_options_arg_1_increase(rct_window *w) 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; + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) += 50; window_invalidate(w); } break; @@ -652,10 +636,10 @@ static void window_editor_objective_options_arg_1_decrease(rct_window *w) } break; default: - if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) <= 500) { + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) <= 250) { window_error_open(3265, STR_NONE); } else { - RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) -= 100; + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16) -= 50; window_invalidate(w); } break; @@ -717,15 +701,11 @@ static void window_editor_objective_options_main_mousedown(int widgetIndex, rct_ * * rct2: 0x00671A54 */ -static void window_editor_objective_options_main_dropdown() +static void window_editor_objective_options_main_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { 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; @@ -790,17 +770,11 @@ static void window_editor_objective_options_main_update(rct_window *w) * * rct2: 0x00671A73 */ -static void window_editor_objective_options_main_textinput() +static void window_editor_objective_options_main_textinput(rct_window *w, int widgetIndex, char *text) { 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) + if (text == NULL) return; switch (widgetIndex) { @@ -812,10 +786,20 @@ static void window_editor_objective_options_main_textinput() break; case WIDX_SCENARIO_NAME: strncpy(s6Info->name, text, 64); + if (strnlen(s6Info->name, 64) == 64) + { + s6Info->name[64 - 1] = '\0'; + log_warning("Truncated S6 name: %s", s6Info->name); + } window_invalidate(w); break; case WIDX_DETAILS: strncpy(s6Info->details, text, 256); + if (strnlen(s6Info->details, 256) == 256) + { + s6Info->details[256 - 1] = '\0'; + log_warning("Truncated S6 name: %s", s6Info->details); + } window_invalidate(w); break; } @@ -825,13 +809,11 @@ static void window_editor_objective_options_main_textinput() * * rct2: 0x0067161C */ -static void window_editor_objective_options_main_invalidate() +static void window_editor_objective_options_main_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; rct_stex_entry *stex; - window_get_register(w); colour_scheme_update(w); stex = g_stexEntries[0]; @@ -846,16 +828,6 @@ static void window_editor_objective_options_main_invalidate() 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 @@ -904,18 +876,14 @@ static void window_editor_objective_options_main_invalidate() * * rct2: 0x0067161C */ -static void window_editor_objective_options_main_paint() +static void window_editor_objective_options_main_paint(rct_window *w, rct_drawpixelinfo *dpi) { 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); @@ -931,7 +899,7 @@ static void window_editor_objective_options_main_paint() // 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); + stringId = STR_OBJECTIVE_DROPDOWN_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) { @@ -1035,7 +1003,7 @@ static void window_editor_objective_options_main_paint() if (stex != NULL) { RCT2_GLOBAL(0x013CE952 + 0, uint16) = stex->scenario_name; } else { - strcpy((char*)0x009BC677, s6Info->name); + safe_strncpy((char*)0x009BC677, s6Info->name, 64); RCT2_GLOBAL(0x013CE952 + 0, uint16) = 3165; } RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(0x0013573D8, uint32); @@ -1054,7 +1022,7 @@ static void window_editor_objective_options_main_paint() if (stex != NULL) { RCT2_GLOBAL(0x013CE952 + 0, uint16) = stex->details; } else { - strcpy((char*)0x009BC677, s6Info->details); + safe_strncpy((char*)0x009BC677, s6Info->details, 256); RCT2_GLOBAL(0x013CE952 + 0, uint16) = 3165; } RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(0x0013573D8, uint32); @@ -1076,13 +1044,9 @@ static void window_editor_objective_options_main_paint() * * rct2: 0x006724A4 */ -static void window_editor_objective_options_rides_mouseup() +static void window_editor_objective_options_rides_mouseup(rct_window *w, int widgetIndex) { rct_s6_info *s6Info = (rct_s6_info*)0x00141F570; - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); switch (widgetIndex) { case WIDX_CLOSE: @@ -1099,12 +1063,8 @@ static void window_editor_objective_options_rides_mouseup() * * rct2: 0x006725A8 */ -static void window_editor_objective_options_rides_resize() +static void window_editor_objective_options_rides_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 380, 224, 380, 224); } @@ -1140,32 +1100,20 @@ static void window_editor_objective_options_rides_update(rct_window *w) * * rct2: 0x006724BF */ -static void window_editor_objective_options_rides_scrollgetheight() +static void window_editor_objective_options_rides_scrollgetheight(rct_window *w, int scrollIndex, int *width, int *height) { - int width, height; - rct_window *w; - - window_get_register(w); - - width = 0; - height = w->no_list_items * 12; - - window_scrollsize_set_registers(width, height); + *height = w->no_list_items * 12; } /** * * rct2: 0x006724FC */ -static void window_editor_objective_options_rides_scrollmousedown() +static void window_editor_objective_options_rides_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) { 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; @@ -1179,14 +1127,10 @@ static void window_editor_objective_options_rides_scrollmousedown() * * rct2: 0x006724CC */ -static void window_editor_objective_options_rides_scrollmouseover() +static void window_editor_objective_options_rides_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) { - 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; @@ -1201,12 +1145,10 @@ static void window_editor_objective_options_rides_scrollmouseover() * * rct2: 0x006722B5 */ -static void window_editor_objective_options_rides_invalidate() +static void window_editor_objective_options_rides_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; - window_get_register(w); colour_scheme_update(w); widgets = window_editor_objective_options_widgets[w->page]; @@ -1227,13 +1169,8 @@ static void window_editor_objective_options_rides_invalidate() * * rct2: 0x00672340 */ -static void window_editor_objective_options_rides_paint() +static void window_editor_objective_options_rides_paint(rct_window *w, rct_drawpixelinfo *dpi) { - 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); @@ -1244,17 +1181,13 @@ static void window_editor_objective_options_rides_paint() * * rct2: 0x0067236F */ -static void window_editor_objective_options_rides_scrollpaint() +static void window_editor_objective_options_rides_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { 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); + colour = ColourMapA[w->colours[1]].mid_light; 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++) { @@ -1278,10 +1211,34 @@ static void window_editor_objective_options_rides_scrollpaint() 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); + gfx_draw_string(dpi, (char*)CheckBoxMarkString, 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 +} + +/** + * + * rct2: 0x00672609 + */ +static void window_editor_objective_options_update_disabled_widgets(rct_window *w) +{ + rct_ride *ride; + int i, numRides; + + // Check if there are any rides (not shops or facilities) + numRides = 0; + FOR_ALL_RIDES(i, ride) { + if (gRideClassifications[ride->type] == RIDE_CLASS_RIDE) { + numRides++; + } + } + + if (numRides == 0) { + w->disabled_widgets &= ~(1 << WIDX_TAB_2); + } else { + w->disabled_widgets |= (1 << WIDX_TAB_2); + } +} diff --git a/src/windows/editor_scenario_options.c b/src/windows/editor_scenario_options.c index 1dea670bd6..4073444ec4 100644 --- a/src/windows/editor_scenario_options.c +++ b/src/windows/editor_scenario_options.c @@ -184,130 +184,128 @@ static rct_widget *window_editor_scenario_options_widgets[] = { #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_mouseup(rct_window *w, int widgetIndex); +static void window_editor_scenario_options_financial_resize(rct_window *w); 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_financial_invalidate(rct_window *w); +static void window_editor_scenario_options_financial_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_editor_scenario_options_guests_mouseup(); -static void window_editor_scenario_options_guests_resize(); +static void window_editor_scenario_options_guests_mouseup(rct_window *w, int widgetIndex); +static void window_editor_scenario_options_guests_resize(rct_window *w); 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_guests_invalidate(rct_window *w); +static void window_editor_scenario_options_guests_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_editor_scenario_options_park_mouseup(); -static void window_editor_scenario_options_park_resize(); +static void window_editor_scenario_options_park_mouseup(rct_window *w, int widgetIndex); +static void window_editor_scenario_options_park_resize(rct_window *w); 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_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); 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(); +static void window_editor_scenario_options_park_invalidate(rct_window *w); +static void window_editor_scenario_options_park_paint(rct_window *w, rct_drawpixelinfo *dpi); // 0x0097EB60 -static void* window_scenario_options_financial_events[] = { - window_editor_scenario_options_emptysub, +static rct_window_event_list window_scenario_options_financial_events = { + NULL, 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, + NULL, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_editor_scenario_options_financial_invalidate, window_editor_scenario_options_financial_paint, - window_editor_scenario_options_emptysub + NULL }; // 0x0097EBD0 -static void* window_scenario_options_guests_events[] = { - window_editor_scenario_options_emptysub, +static rct_window_event_list window_scenario_options_guests_events = { + NULL, 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, + NULL, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_editor_scenario_options_guests_invalidate, window_editor_scenario_options_guests_paint, - window_editor_scenario_options_emptysub + NULL }; // 0x0097EC40 -static void* window_scenario_options_park_events[] = { - window_editor_scenario_options_emptysub, +static rct_window_event_list window_scenario_options_park_events = { + NULL, 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, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_editor_scenario_options_park_invalidate, window_editor_scenario_options_park_paint, - window_editor_scenario_options_emptysub + NULL }; -static void* window_editor_scenario_options_page_events[] = { - window_scenario_options_financial_events, - window_scenario_options_guests_events, - window_scenario_options_park_events +static rct_window_event_list *window_editor_scenario_options_page_events[] = { + &window_scenario_options_financial_events, + &window_scenario_options_guests_events, + &window_scenario_options_park_events }; #pragma endregion @@ -345,7 +343,7 @@ void window_editor_scenario_options_open() 148, window_editor_scenario_options_page_events[0], WC_EDITOR_SCENARIO_OPTIONS, - WF_2 + WF_NO_SCROLLING ); w->widgets = window_editor_scenario_options_widgets[0]; w->enabled_widgets = window_editor_scenario_options_page_enabled_widgets[0]; @@ -434,13 +432,8 @@ static void window_editor_scenario_options_set_page(rct_window *w, int page) * * rct2: 0x0067049D */ -static void window_editor_scenario_options_financial_mouseup() +static void window_editor_scenario_options_financial_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -451,7 +444,18 @@ static void window_editor_scenario_options_financial_mouseup() 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; + if(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) ^= PARK_FLAGS_NO_MONEY_SCENARIO; + } + else { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) ^= PARK_FLAGS_NO_MONEY; + // Invalidate all windows that have anything to do with finance + window_invalidate_by_class(WC_RIDE); + window_invalidate_by_class(WC_PEEP); + window_invalidate_by_class(WC_PARK_INFORMATION); + window_invalidate_by_class(WC_FINANCES); + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); + } window_invalidate(w); break; case WIDX_FORBID_MARKETING: @@ -465,12 +469,8 @@ static void window_editor_scenario_options_financial_mouseup() * * rct2: 0x0067077A */ -static void window_editor_scenario_options_financial_resize() +static void window_editor_scenario_options_financial_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 280, 149, 280, 149); } @@ -482,10 +482,10 @@ static void window_editor_scenario_options_financial_mousedown(int widgetIndex, { switch (widgetIndex) { case WIDX_INITIAL_CASH_INCREASE: - if (RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32) < MONEY(10000,00)) { + if (RCT2_GLOBAL(RCT2_ADDRESS_INITIAL_CASH, money32) < MONEY(1000000,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(); + finance_update_loan_hash(); } else { window_error_open(3248, STR_NONE); } @@ -495,7 +495,7 @@ static void window_editor_scenario_options_financial_mousedown(int widgetIndex, 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(); + finance_update_loan_hash(); } else { window_error_open(3249, STR_NONE); } @@ -505,6 +505,7 @@ static void window_editor_scenario_options_financial_mousedown(int widgetIndex, 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)); + finance_update_loan_hash(); } else { window_error_open(3250, STR_NONE); } @@ -514,6 +515,7 @@ static void window_editor_scenario_options_financial_mousedown(int widgetIndex, 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)); + finance_update_loan_hash(); } else { window_error_open(3251, STR_NONE); } @@ -523,6 +525,7 @@ static void window_editor_scenario_options_financial_mousedown(int widgetIndex, 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)); + finance_update_loan_hash(); } else { window_error_open(3252, STR_NONE); } @@ -532,6 +535,7 @@ static void window_editor_scenario_options_financial_mousedown(int widgetIndex, 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)); + finance_update_loan_hash(); } else { window_error_open(3253, STR_NONE); } @@ -546,7 +550,7 @@ static void window_editor_scenario_options_financial_mousedown(int widgetIndex, window_invalidate(w); break; case WIDX_INTEREST_RATE_DECREASE: - if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_INTEREST_RATE, money32) > 5) { + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_INTEREST_RATE, money32) >= 0) { RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_INTEREST_RATE, money32)--; } else { window_error_open(3255, STR_NONE); @@ -554,6 +558,11 @@ static void window_editor_scenario_options_financial_mousedown(int widgetIndex, window_invalidate(w); break; } + + if(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) == SCREEN_FLAGS_PLAYING) { + window_invalidate_by_class(WC_FINANCES); + window_invalidate_by_class(WC_BOTTOM_TOOLBAR); + } } /** @@ -571,13 +580,11 @@ static void window_editor_scenario_options_financial_update(rct_window *w) * * rct2: 0x006701CF */ -static void window_editor_scenario_options_financial_invalidate() +static void window_editor_scenario_options_financial_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; int i; - window_get_register(w); colour_scheme_update(w); widgets = window_editor_scenario_options_widgets[w->page]; @@ -588,7 +595,8 @@ static void window_editor_scenario_options_financial_invalidate() window_editor_scenario_options_set_pressed_tab(w); - if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY_SCENARIO) { + if (((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY_SCENARIO)) || + (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY))) { w->pressed_widgets |= (1 << WIDX_NO_MONEY); for (i = WIDX_INITIAL_CASH; i <= WIDX_FORBID_MARKETING; i++) w->widgets[i].type = WWT_EMPTY; @@ -624,14 +632,10 @@ static void window_editor_scenario_options_financial_invalidate() * * rct2: 0x00670338 */ -static void window_editor_scenario_options_financial_paint() +static void window_editor_scenario_options_financial_paint(rct_window *w, rct_drawpixelinfo *dpi) { - 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); @@ -684,13 +688,8 @@ static void window_editor_scenario_options_financial_paint() * * rct2: 0x00670A62 */ -static void window_editor_scenario_options_guests_mouseup() +static void window_editor_scenario_options_guests_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -715,12 +714,8 @@ static void window_editor_scenario_options_guests_mouseup() * * rct2: 0x00670C59 */ -static void window_editor_scenario_options_guests_resize() +static void window_editor_scenario_options_guests_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 380, 149, 380, 149); } @@ -732,7 +727,7 @@ static void window_editor_scenario_options_guests_mousedown(int widgetIndex, rct { switch (widgetIndex) { case WIDX_CASH_PER_GUEST_INCREASE: - if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) < MONEY(100, 00)) { + if (RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) < MONEY(1000, 00)) { RCT2_GLOBAL(RCT2_ADDRESS_GUEST_INITIAL_CASH, money16) += MONEY(1, 00); } else { window_error_open(3264, STR_NONE); @@ -813,12 +808,10 @@ static void window_editor_scenario_options_guests_update(rct_window *w) * * rct2: 0x006707DB */ -static void window_editor_scenario_options_guests_invalidate() +static void window_editor_scenario_options_guests_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; - window_get_register(w); colour_scheme_update(w); widgets = window_editor_scenario_options_widgets[w->page]; @@ -829,14 +822,15 @@ static void window_editor_scenario_options_guests_invalidate() window_editor_scenario_options_set_pressed_tab(w); - if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY_SCENARIO) { + if (((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY_SCENARIO)) || + (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY))) { 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; + w->widgets[WIDX_CASH_PER_GUEST_DECREASE].type = WWT_DROPDOWN_BUTTON; } // Guests prefer less intense rides checkbox @@ -861,14 +855,10 @@ static void window_editor_scenario_options_guests_invalidate() * * rct2: 0x006708C4 */ -static void window_editor_scenario_options_guests_paint() +static void window_editor_scenario_options_guests_paint(rct_window *w, rct_drawpixelinfo *dpi) { - 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); @@ -884,7 +874,7 @@ static void window_editor_scenario_options_guests_paint() 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; @@ -927,13 +917,8 @@ static void window_editor_scenario_options_guests_paint() * * rct2: 0x00670FD8 */ -static void window_editor_scenario_options_park_mouseup() +static void window_editor_scenario_options_park_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -970,12 +955,8 @@ static void window_editor_scenario_options_park_mouseup() * * rct2: 0x00671287 */ -static void window_editor_scenario_options_park_resize() +static void window_editor_scenario_options_park_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 400, 183, 400, 183); } @@ -1054,7 +1035,7 @@ static void window_editor_scenario_options_park_mousedown(int widgetIndex, rct_w dropdownWidget->right - dropdownWidget->left - 3 ); - gDropdownItemsChecked = 1 << (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY ? 0 : 1); + dropdown_set_checked((RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY ? 0 : 1), true); break; } } @@ -1063,27 +1044,36 @@ static void window_editor_scenario_options_park_mousedown(int widgetIndex, rct_w * * rct2: 0x00671060 */ -static void window_editor_scenario_options_park_dropdown() +static void window_editor_scenario_options_park_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - 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); + if(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) { + 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); + } + } 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); + } } } + else { + 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; + } + } 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; + } + } + window_invalidate_by_class(WC_PARK_INFORMATION); + window_invalidate_by_class(WC_RIDE); + } + window_invalidate(w); } } @@ -1102,14 +1092,12 @@ static void window_editor_scenario_options_park_update(rct_window *w) * * rct2: 0x00670CBA */ -static void window_editor_scenario_options_park_invalidate() +static void window_editor_scenario_options_park_invalidate(rct_window *w) { - 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]; @@ -1120,7 +1108,8 @@ static void window_editor_scenario_options_park_invalidate() window_editor_scenario_options_set_pressed_tab(w); - if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY_SCENARIO) { + if (((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY_SCENARIO)) || + (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY))) { for (i = WIDX_LAND_COST; i <= WIDX_ENTRY_PRICE_DECREASE; i++) w->widgets[i].type = WWT_EMPTY; } else { @@ -1175,15 +1164,11 @@ static void window_editor_scenario_options_park_invalidate() * * rct2: 0x00670E5B */ -static void window_editor_scenario_options_park_paint() +static void window_editor_scenario_options_park_paint(rct_window *w, rct_drawpixelinfo *dpi) { - 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); @@ -1192,7 +1177,7 @@ static void window_editor_scenario_options_park_paint() 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; @@ -1205,7 +1190,7 @@ static void window_editor_scenario_options_park_paint() 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; @@ -1223,7 +1208,7 @@ static void window_editor_scenario_options_park_paint() 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; diff --git a/src/windows/error.c b/src/windows/error.c index 531c40d00e..bba3cbece5 100644 --- a/src/windows/error.c +++ b/src/windows/error.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 . *****************************************************************************/ @@ -34,46 +34,45 @@ static rct_widget window_error_widgets[] = { { WIDGETS_END } }; -static void window_error_emptysub() { } -static void window_error_unknown5(); -static void window_error_paint(); +static void window_error_unknown5(rct_window *w); +static void window_error_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void* window_error_events[] = { - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_unknown5, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_emptysub, - (uint32*)window_error_paint, - (uint32*)window_error_emptysub +static rct_window_event_list window_error_events = { + NULL, + NULL, + NULL, + NULL, + NULL, + window_error_unknown5, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_error_paint, + NULL }; static char _window_error_text[512]; static uint16 _window_error_num_lines; /** - * + * * rct2: 0x0066792F * * bx: title @@ -81,7 +80,8 @@ static uint16 _window_error_num_lines; */ void window_error_open(rct_string_id title, rct_string_id message) { - char *dst, *args; + utf8 *dst; + char *args; int numLines, fontHeight, x, y, width, height, maxY; rct_window *w; @@ -90,17 +90,17 @@ void window_error_open(rct_string_id title, rct_string_id message) args = (char*)0x0013CE952; // Format the title - *dst++ = FORMAT_BLACK; + dst = utf8_write_codepoint(dst, FORMAT_BLACK); if (title != (rct_string_id)STR_NONE) { format_string(dst, title, args); - dst += get_string_length(dst); + dst = get_string_end(dst); } // Format the message if (message != (rct_string_id)STR_NONE) { - *dst++ = FORMAT_NEWLINE; + dst = utf8_write_codepoint(dst, FORMAT_NEWLINE); format_string(dst, message, args); - dst += get_string_length(dst); + dst = get_string_end(dst); } log_verbose("show error, %s", _window_error_text + 1); @@ -124,50 +124,42 @@ void window_error_open(rct_string_id title, rct_string_id message) window_error_widgets[WIDX_BACKGROUND].bottom = height; x = RCT2_GLOBAL(0x0142406C, sint32) - (width / 2); - x = clamp(0, x, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16)); + x = clamp(0, x, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16)); y = RCT2_GLOBAL(0x01424070, sint32) + 26; y = max(22, y); - maxY = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) - height; + maxY = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - height; if (y > maxY) { y = y - height - 40; y = min(y, maxY); } - - w = window_create(x, y, width, height, (uint32*)window_error_events, WC_ERROR, WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_RESIZABLE); + + w = window_create(x, y, width, height, &window_error_events, WC_ERROR, WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_RESIZABLE); w->widgets = window_error_widgets; w->error.var_480 = 0; if (!(RCT2_GLOBAL(0x009A8C29, uint8) & 1)) - sound_play_panned(SOUND_ERROR, 0, w->x + (w->width / 2), 0, 0); + audio_play_sound_panned(SOUND_ERROR, 0, w->x + (w->width / 2), 0, 0); } /** - * + * * rct2: 0x00667BFE */ -static void window_error_unknown5() +static void window_error_unknown5(rct_window *w) { - rct_window *w; - - window_get_register(w); - w->error.var_480++; if (w->error.var_480 >= 8) window_close(w); } /** - * + * * rct2: 0x00667AA3 */ -static void window_error_paint() +static void window_error_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; int t, l, r, b; - window_paint_get_registers(w, dpi); - l = w->x; t = w->y; r = w->x + w->width - 1; diff --git a/src/windows/error.h b/src/windows/error.h index 3ddb36c1c9..6f30cc74f2 100644 --- a/src/windows/error.h +++ b/src/windows/error.h @@ -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 . *****************************************************************************/ diff --git a/src/windows/finances.c b/src/windows/finances.c index 17fc47d1e9..006b9a76ff 100644 --- a/src/windows/finances.c +++ b/src/windows/finances.c @@ -30,6 +30,7 @@ #include "../management/marketing.h" #include "../management/research.h" #include "../ride/ride.h" +#include "../ride/ride_data.h" #include "../scenario.h" #include "../sprites.h" #include "dropdown.h" @@ -93,7 +94,7 @@ static rct_widget window_finances_summary_widgets[] = { { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_FINANCES_SHOW_PARK_VALUE_TAB_TIP }, { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_FINANCES_SHOW_WEEKLY_PROFIT_TAB_TIP }, { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_FINANCES_SHOW_MARKETING_TAB_TIP }, - { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH_TIP }, { WWT_SPINNER, 1, 64, 153, 229, 240, 1917, STR_NONE }, { WWT_DROPDOWN_BUTTON, 1, 142, 152, 230, 234, STR_NUMERIC_UP, STR_NONE }, { WWT_DROPDOWN_BUTTON, 1, 142, 152, 235, 239, STR_NUMERIC_DOWN, STR_NONE }, @@ -110,7 +111,7 @@ static rct_widget window_finances_cash_widgets[] = { { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_FINANCES_SHOW_PARK_VALUE_TAB_TIP }, { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_FINANCES_SHOW_WEEKLY_PROFIT_TAB_TIP }, { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_FINANCES_SHOW_MARKETING_TAB_TIP }, - { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH_TIP }, { WIDGETS_END }, }; @@ -124,7 +125,7 @@ static rct_widget window_finances_park_value_widgets[] = { { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_FINANCES_SHOW_PARK_VALUE_TAB_TIP }, { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_FINANCES_SHOW_WEEKLY_PROFIT_TAB_TIP }, { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_FINANCES_SHOW_MARKETING_TAB_TIP }, - { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH_TIP }, { WIDGETS_END }, }; @@ -138,7 +139,7 @@ static rct_widget window_finances_profit_widgets[] = { { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_FINANCES_SHOW_PARK_VALUE_TAB_TIP }, { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_FINANCES_SHOW_WEEKLY_PROFIT_TAB_TIP }, { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_FINANCES_SHOW_MARKETING_TAB_TIP }, - { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH_TIP }, { WIDGETS_END }, }; @@ -152,7 +153,7 @@ static rct_widget window_finances_marketing_widgets[] = { { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_FINANCES_SHOW_PARK_VALUE_TAB_TIP }, { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_FINANCES_SHOW_WEEKLY_PROFIT_TAB_TIP }, { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_FINANCES_SHOW_MARKETING_TAB_TIP }, - { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH_TIP }, { WWT_GROUPBOX, 2, 3, 526, 47, 91, STR_MARKETING_CAMPAIGNS_IN_OPERATION, STR_NONE }, { WWT_GROUPBOX, 2, 3, 526, 47, 252, STR_MARKETING_CAMPAIGNS_AVAILABLE, STR_NONE }, { WWT_IMGBTN, 1, 8, 521, 0, 11, 0xFFFFFFFF, STR_START_THIS_MARKETING_CAMPAIGN }, @@ -174,7 +175,7 @@ static rct_widget window_finances_research_widgets[] = { { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_FINANCES_SHOW_PARK_VALUE_TAB_TIP }, { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_FINANCES_SHOW_WEEKLY_PROFIT_TAB_TIP }, { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_FINANCES_SHOW_MARKETING_TAB_TIP }, - { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH_TIP }, { WWT_GROUPBOX, 2, 3, 316, 47, 91, STR_RESEARCH_FUNDING_, STR_NONE }, { WWT_DROPDOWN, 2, 8, 167, 59, 70, 0xFFFFFFFF, STR_SELECT_LEVEL_OF_RESEARCH_AND_DEVELOPMENT }, { WWT_DROPDOWN_BUTTON, 2, 156, 166, 60, 69, 876, STR_SELECT_LEVEL_OF_RESEARCH_AND_DEVELOPMENT }, @@ -202,240 +203,238 @@ static rct_widget *window_finances_page_widgets[] = { #pragma region Events -static void window_finances_emptysub() { } - -static void window_finances_summary_mouseup(); +static void window_finances_summary_mouseup(rct_window *w, int widgetIndex); static void window_finances_summary_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); static void window_finances_summary_update(rct_window *w); -static void window_finances_summary_invalidate(); -static void window_finances_summary_paint(); +static void window_finances_summary_invalidate(rct_window *w); +static void window_finances_summary_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_finances_financial_graph_mouseup(); +static void window_finances_financial_graph_mouseup(rct_window *w, int widgetIndex); static void window_finances_financial_graph_update(rct_window *w); -static void window_finances_financial_graph_invalidate(); -static void window_finances_financial_graph_paint(); +static void window_finances_financial_graph_invalidate(rct_window *w); +static void window_finances_financial_graph_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_finances_park_value_graph_mouseup(); +static void window_finances_park_value_graph_mouseup(rct_window *w, int widgetIndex); static void window_finances_park_value_graph_update(rct_window *w); -static void window_finances_park_value_graph_invalidate(); -static void window_finances_park_value_graph_paint(); +static void window_finances_park_value_graph_invalidate(rct_window *w); +static void window_finances_park_value_graph_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_finances_profit_graph_mouseup(); +static void window_finances_profit_graph_mouseup(rct_window *w, int widgetIndex); static void window_finances_profit_graph_update(rct_window *w); -static void window_finances_profit_graph_invalidate(); -static void window_finances_profit_graph_paint(); +static void window_finances_profit_graph_invalidate(rct_window *w); +static void window_finances_profit_graph_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_finances_marketing_mouseup(); +static void window_finances_marketing_mouseup(rct_window *w, int widgetIndex); static void window_finances_marketing_update(rct_window *w); -static void window_finances_marketing_invalidate(); -static void window_finances_marketing_paint(); +static void window_finances_marketing_invalidate(rct_window *w); +static void window_finances_marketing_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_finances_research_mouseup(); +static void window_finances_research_mouseup(rct_window *w, int widgetIndex); static void window_finances_research_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_finances_research_dropdown(); +static void window_finances_research_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_finances_research_update(rct_window *w); -static void window_finances_research_invalidate(); -static void window_finances_research_paint(); +static void window_finances_research_invalidate(rct_window *w); +static void window_finances_research_paint(rct_window *w, rct_drawpixelinfo *dpi); // 0x00988EB8 -static void* window_finances_summary_events[] = { - window_finances_emptysub, +static rct_window_event_list window_finances_summary_events = { + NULL, window_finances_summary_mouseup, - window_finances_emptysub, + NULL, window_finances_summary_mousedown, - window_finances_emptysub, - window_finances_emptysub, + NULL, + NULL, window_finances_summary_update, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_finances_summary_invalidate, window_finances_summary_paint, - window_finances_emptysub + NULL }; // 0x00988F28 -static void* window_finances_financial_graph_events[] = { - window_finances_emptysub, +static rct_window_event_list window_finances_financial_graph_events = { + NULL, window_finances_financial_graph_mouseup, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, + NULL, + NULL, + NULL, + NULL, window_finances_financial_graph_update, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_finances_financial_graph_invalidate, window_finances_financial_graph_paint, - window_finances_emptysub + NULL }; // 0x00988F98 -static void* window_finances_value_graph_events[] = { - window_finances_emptysub, +static rct_window_event_list window_finances_value_graph_events = { + NULL, window_finances_park_value_graph_mouseup, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, + NULL, + NULL, + NULL, + NULL, window_finances_park_value_graph_update, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_finances_park_value_graph_invalidate, window_finances_park_value_graph_paint, - window_finances_emptysub + NULL }; // 0x00989008 -static void* window_finances_profit_graph_events[] = { - window_finances_emptysub, +static rct_window_event_list window_finances_profit_graph_events = { + NULL, window_finances_profit_graph_mouseup, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, + NULL, + NULL, + NULL, + NULL, window_finances_profit_graph_update, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_finances_profit_graph_invalidate, window_finances_profit_graph_paint, - window_finances_emptysub + NULL }; // 0x00989078 -static void* window_finances_marketing_events[] = { - window_finances_emptysub, +static rct_window_event_list window_finances_marketing_events = { + NULL, window_finances_marketing_mouseup, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, + NULL, + NULL, + NULL, + NULL, window_finances_marketing_update, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_finances_marketing_invalidate, window_finances_marketing_paint, - window_finances_emptysub + NULL }; // 0x009890E8 -static void* window_finances_research_events[] = { - window_finances_emptysub, +static rct_window_event_list window_finances_research_events = { + NULL, window_finances_research_mouseup, - window_finances_emptysub, + NULL, window_finances_research_mousedown, window_finances_research_dropdown, - window_finances_emptysub, + NULL, window_finances_research_update, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, - window_finances_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_finances_research_invalidate, window_finances_research_paint, - window_finances_emptysub + NULL }; -static void* window_finances_page_events[] = { - window_finances_summary_events, - window_finances_financial_graph_events, - window_finances_value_graph_events, - window_finances_profit_graph_events, - window_finances_marketing_events, - window_finances_research_events +static rct_window_event_list *window_finances_page_events[] = { + &window_finances_summary_events, + &window_finances_financial_graph_events, + &window_finances_value_graph_events, + &window_finances_profit_graph_events, + &window_finances_marketing_events, + &window_finances_research_events }; static void window_finances_set_colours(); @@ -583,13 +582,8 @@ void window_finances_research_open() * * rct2: 0x0069CA99 */ -static void window_finances_summary_mouseup() +static void window_finances_summary_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - if (widgetIndex == WIDX_CLOSE) window_close(w); else if (widgetIndex >= WIDX_TAB_1 && widgetIndex <= WIDX_TAB_6) @@ -633,14 +627,11 @@ static void window_finances_summary_update(rct_window *w) } /** - * + * * rct2: 0x0069C732 */ -static void window_finances_summary_invalidate() +static void window_finances_summary_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); if (w->widgets != window_finances_page_widgets[WINDOW_FINANCES_PAGE_SUMMARY]) { @@ -653,17 +644,13 @@ static void window_finances_summary_invalidate() } /** - * + * * rct2: 0x0069C771 */ -static void window_finances_summary_paint() +static void window_finances_summary_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; int i, j, x, y; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_finances_draw_tab_images(dpi, w); @@ -678,7 +665,7 @@ static void window_finances_summary_paint() for (i = 0; i < 14; i++) { // Darken every even row if (i % 2 == 0) - gfx_fill_rect(dpi, x, y, x + 513 - 2, y + 9, RCT2_GLOBAL(0x0141FC4A + (w->colours[1] * 8), uint8) | 0x1000000); + gfx_fill_rect(dpi, x, y, x + 513 - 2, y + 9, ColourMapA[w->colours[1]].lighter | 0x1000000); gfx_draw_string_left(dpi, STR_FINANCES_SUMMARY_RIDE_CONSTRUCTION + i, NULL, 0, x, y - 1); y += 10; @@ -706,7 +693,7 @@ static void window_finances_summary_paint() y - 1 ); y += 14; - + // Month expenditures money32 profit = 0; money32 *expenditures = &RCT2_ADDRESS(RCT2_ADDRESS_EXPENDITURE_TABLE, money32)[i * 14]; @@ -741,7 +728,7 @@ static void window_finances_summary_paint() x += 80; } - + // Horizontal rule below expenditure / income table gfx_fill_rect_inset(dpi, w->x + 8, w->y + 223, w->x + 8 + 513, w->y + 223 + 1, w->colours[1], 0x20); @@ -778,16 +765,11 @@ static void window_finances_summary_paint() #pragma region Financial graph page /** - * + * * rct2: 0x0069CF70 */ -static void window_finances_financial_graph_mouseup() +static void window_finances_financial_graph_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - if (widgetIndex == WIDX_CLOSE) window_close(w); else if (widgetIndex >= WIDX_TAB_1 && widgetIndex <= WIDX_TAB_6) @@ -795,7 +777,7 @@ static void window_finances_financial_graph_mouseup() } /** - * + * * rct2: 0x0069CF8B */ static void window_finances_financial_graph_update(rct_window *w) @@ -807,14 +789,11 @@ static void window_finances_financial_graph_update(rct_window *w) } /** - * + * * rct2: 0x0069CBDB */ -static void window_finances_financial_graph_invalidate() +static void window_finances_financial_graph_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); if (w->widgets != window_finances_page_widgets[WINDOW_FINANCES_PAGE_FINANCIAL_GRAPH]) { @@ -826,17 +805,13 @@ static void window_finances_financial_graph_invalidate() } /** - * + * * rct2: 0x0069CC10 */ -static void window_finances_financial_graph_paint() +static void window_finances_financial_graph_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; int i, x, y, graphLeft, graphTop, graphRight, graphBottom; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_finances_draw_tab_images(dpi, w); @@ -866,9 +841,8 @@ static void window_finances_financial_graph_paint() // Calculate the Y axis scale (log2 of highest [+/-]balance) int yAxisScale = 0; - money32 *balanceHistory = RCT2_ADDRESS(RCT2_ADDRESS_BALANCE_HISTORY, money32); for (i = 0; i < 64; i++) { - money32 balance = balanceHistory[i]; + money32 balance = gCashHistory[i]; if (balance == MONEY32_UNDEFINED) continue; @@ -893,7 +867,7 @@ static void window_finances_financial_graph_paint() // X axis labels and values x = graphLeft + 98; y = graphTop + 17; - graph_draw_money32(dpi, balanceHistory, 64, x, y, yAxisScale, 128); + graph_draw_money32(dpi, gCashHistory, 64, x, y, yAxisScale, 128); } #pragma endregion @@ -901,16 +875,11 @@ static void window_finances_financial_graph_paint() #pragma region Value graph page /** - * + * * rct2: 0x0069D338 */ -static void window_finances_park_value_graph_mouseup() +static void window_finances_park_value_graph_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - if (widgetIndex == WIDX_CLOSE) window_close(w); else if (widgetIndex >= WIDX_TAB_1 && widgetIndex <= WIDX_TAB_6) @@ -918,7 +887,7 @@ static void window_finances_park_value_graph_mouseup() } /** - * + * * rct2: 0x0069D353 */ static void window_finances_park_value_graph_update(rct_window *w) @@ -930,14 +899,11 @@ static void window_finances_park_value_graph_update(rct_window *w) } /** - * + * * rct2: 0x0069CFC0 */ -static void window_finances_park_value_graph_invalidate() +static void window_finances_park_value_graph_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); if (w->widgets != window_finances_page_widgets[WINDOW_FINANCES_PAGE_VALUE_GRAPH]) { @@ -949,17 +915,13 @@ static void window_finances_park_value_graph_invalidate() } /** - * + * * rct2: 0x0069CFF5 */ -static void window_finances_park_value_graph_paint() +static void window_finances_park_value_graph_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; int i, x, y, graphLeft, graphTop, graphRight, graphBottom; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_finances_draw_tab_images(dpi, w); @@ -985,9 +947,8 @@ static void window_finances_park_value_graph_paint() // Calculate the Y axis scale (log2 of highest [+/-]balance) int yAxisScale = 0; - money32 *parkValueHistory = RCT2_ADDRESS(RCT2_ADDRESS_PARK_VALUE_HISTORY, money32); for (i = 0; i < 64; i++) { - money32 balance = parkValueHistory[i]; + money32 balance = gParkValueHistory[i]; if (balance == MONEY32_UNDEFINED) continue; @@ -1012,7 +973,7 @@ static void window_finances_park_value_graph_paint() // X axis labels and values x = graphLeft + 98; y = graphTop + 17; - graph_draw_money32(dpi, parkValueHistory, 64, x, y, yAxisScale, 0); + graph_draw_money32(dpi, gParkValueHistory, 64, x, y, yAxisScale, 0); } #pragma endregion @@ -1020,16 +981,11 @@ static void window_finances_park_value_graph_paint() #pragma region Profit graph page /** - * + * * rct2: 0x0069D715 */ -static void window_finances_profit_graph_mouseup() +static void window_finances_profit_graph_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - if (widgetIndex == WIDX_CLOSE) window_close(w); else if (widgetIndex >= WIDX_TAB_1 && widgetIndex <= WIDX_TAB_6) @@ -1037,7 +993,7 @@ static void window_finances_profit_graph_mouseup() } /** - * + * * rct2: 0x0069D730 */ static void window_finances_profit_graph_update(rct_window *w) @@ -1049,14 +1005,11 @@ static void window_finances_profit_graph_update(rct_window *w) } /** - * + * * rct2: 0x0069D388 */ -static void window_finances_profit_graph_invalidate() +static void window_finances_profit_graph_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); if (w->widgets != window_finances_page_widgets[WINDOW_FINANCES_PAGE_PROFIT_GRAPH]) { @@ -1068,17 +1021,13 @@ static void window_finances_profit_graph_invalidate() } /** - * + * * rct2: 0x0069D3BD */ -static void window_finances_profit_graph_paint() +static void window_finances_profit_graph_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; int i, x, y, graphLeft, graphTop, graphRight, graphBottom; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_finances_draw_tab_images(dpi, w); @@ -1104,9 +1053,8 @@ static void window_finances_profit_graph_paint() // Calculate the Y axis scale (log2 of highest [+/-]balance) int yAxisScale = 0; - money32 *weeklyProfitHistory = RCT2_ADDRESS(RCT2_ADDRESS_WEEKLY_PROFIT_HISTORY, money32); for (i = 0; i < 64; i++) { - money32 balance = weeklyProfitHistory[i]; + money32 balance = gWeeklyProfitHistory[i]; if (balance == MONEY32_UNDEFINED) continue; @@ -1131,7 +1079,7 @@ static void window_finances_profit_graph_paint() // X axis labels and values x = graphLeft + 98; y = graphTop + 17; - graph_draw_money32(dpi, weeklyProfitHistory, 64, x, y, yAxisScale, 128); + graph_draw_money32(dpi, gWeeklyProfitHistory, 64, x, y, yAxisScale, 128); } #pragma endregion @@ -1139,16 +1087,11 @@ static void window_finances_profit_graph_paint() #pragma region Marketing page /** - * + * * rct2: 0x0069D9F9 */ -static void window_finances_marketing_mouseup() +static void window_finances_marketing_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - if (widgetIndex == WIDX_CLOSE) window_close(w); else if (widgetIndex >= WIDX_TAB_1 && widgetIndex <= WIDX_TAB_6) @@ -1159,7 +1102,7 @@ static void window_finances_marketing_mouseup() } /** - * + * * rct2: 0x0069DA2F */ static void window_finances_marketing_update(rct_window *w) @@ -1171,15 +1114,13 @@ static void window_finances_marketing_update(rct_window *w) } /** - * + * * rct2: 0x0069D765 */ -static void window_finances_marketing_invalidate() +static void window_finances_marketing_invalidate(rct_window *w) { - rct_window *w; int i; - window_get_register(w); colour_scheme_update(w); if (w->widgets != window_finances_page_widgets[WINDOW_FINANCES_PAGE_MARKETING]) { @@ -1207,19 +1148,12 @@ static void window_finances_marketing_invalidate() campaginButton->type = 0; - // Do not allow park entry campaigns if park entry is free - if ( - (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) && ( - i == ADVERTISING_CAMPAIGN_PARK_ENTRY_FREE || - i == ADVERTISING_CAMPAIGN_PARK_ENTRY_HALF_PRICE - ) - ) { - continue; - } - if (gMarketingCampaignDaysLeft[i] != 0) continue; + if (!marketing_is_campaign_type_applicable(i)) + continue; + campaginButton->type = WWT_DROPDOWN_BUTTON; campaginButton->top = y; campaginButton->bottom = y + 11; @@ -1228,18 +1162,13 @@ static void window_finances_marketing_invalidate() } /** - * + * * rct2: 0x0069D834 */ -static void window_finances_marketing_paint() +static void window_finances_marketing_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - int i, x, y; + int i, x, y, weeksRemaining; rct_ride *ride; - rct_string_id shopString, weeksRemainingStringId; - - window_paint_get_registers(w, dpi); window_draw_widgets(w, dpi); window_finances_draw_tab_images(dpi, w); @@ -1253,7 +1182,7 @@ static void window_finances_marketing_paint() continue; noCampaignsActive = 0; - RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, 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 @@ -1261,14 +1190,11 @@ static void window_finances_marketing_paint() case ADVERTISING_CAMPAIGN_RIDE_FREE: case ADVERTISING_CAMPAIGN_RIDE: ride = GET_RIDE(gMarketingCampaignRideIndex[i]); - RCT2_GLOBAL(0x013CE952, uint16) = ride->name; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = ride->name; RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; break; case ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE: - shopString = gMarketingCampaignRideIndex[i] + 2016; // STR_BALLOONS+ - if (shopString >= 2048) // STR_AN_UMBRELLA - shopString += 96; // STR_ON_RIDE_PHOTOS+ - RCT2_GLOBAL(0x013CE952, uint16) = shopString; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = ShopItemStringIds[gMarketingCampaignRideIndex[i]].plural; break; } @@ -1276,8 +1202,8 @@ 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) + (gMarketingCampaignDaysLeft[i] % 128); - gfx_draw_string_left(dpi, STR_MARKETING_WEEKS_REMAINING, &weeksRemainingStringId, 0, x + 304, y); + weeksRemaining = (gMarketingCampaignDaysLeft[i] % 128); + gfx_draw_string_left(dpi, weeksRemaining == 1 ? STR_1_WEEK_REMAINING : STR_X_WEEKS_REMAINING, &weeksRemaining, 0, x + 304, y); y += 10; } @@ -1292,19 +1218,7 @@ static void window_finances_marketing_paint() for (i = 0; i < ADVERTISING_CAMPAIGN_COUNT; i++) { rct_widget *campaginButton = &window_finances_marketing_widgets[WIDX_CAMPAIGN_1 + i]; - campaginButton->type = 0; - - // Do not allow park entry campaigns if park entry is free - if ( - (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) && ( - i == ADVERTISING_CAMPAIGN_PARK_ENTRY_FREE || - i == ADVERTISING_CAMPAIGN_PARK_ENTRY_HALF_PRICE - ) - ) { - continue; - } - - if (gMarketingCampaignDaysLeft[i] != 0) + if (campaginButton->type == WWT_EMPTY) continue; money32 pricePerWeek = AdvertisingCampaignPricePerWeek[i]; @@ -1322,17 +1236,13 @@ static void window_finances_marketing_paint() #pragma region Research page /** - * + * * rct2: 0x0069DB3F */ -static void window_finances_research_mouseup() +static void window_finances_research_mouseup(rct_window *w, int widgetIndex) { - rct_window * w; - short widgetIndex; int activeResearchTypes; - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -1360,14 +1270,14 @@ static void window_finances_research_mouseup() } /** - * + * * rct2: 0x0069DB66 */ static void window_finances_research_mousedown(int widgetIndex, rct_window *w, rct_widget* widget) { rct_widget *dropdownWidget; int i; - + if (widgetIndex != WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON) return; @@ -1388,21 +1298,15 @@ static void window_finances_research_mousedown(int widgetIndex, rct_window *w, r ); int currentResearchLevel = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8); - gDropdownItemsChecked = (1 << currentResearchLevel); + dropdown_set_checked(currentResearchLevel, true); } /** - * + * * rct2: 0x0069DB6D */ -static void window_finances_research_dropdown() +static void window_finances_research_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - rct_window *w; - short widgetIndex; - short dropdownIndex; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (widgetIndex != WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON || dropdownIndex == -1) return; @@ -1410,7 +1314,7 @@ static void window_finances_research_dropdown() } /** - * + * * rct2: 0x0069DC23 */ static void window_finances_research_update(rct_window *w) @@ -1422,14 +1326,11 @@ static void window_finances_research_update(rct_window *w) } /** - * + * * rct2: 0x0069DA64 */ -static void window_finances_research_invalidate() +static void window_finances_research_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); if (w->widgets != window_finances_page_widgets[WINDOW_FINANCES_PAGE_RESEARCH]) { @@ -1446,7 +1347,7 @@ static void window_finances_research_invalidate() // Current funding window_finances_research_widgets[WIDX_RESEARCH_FUNDING].image = STR_NO_FUNDING + currentResearchLevel; - + // Checkboxes int activeResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES, uint16); int uncompletedResearchTypes = gResearchUncompletedCategories; @@ -1471,22 +1372,15 @@ static void window_finances_research_invalidate() } /** - * + * * rct2: 0x0069DAF0 */ -static void window_finances_research_paint() +static void window_finances_research_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_finances_draw_tab_images(dpi, w); - int currentResearchLevel = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8); - money32 currentResearchCostPerWeek = research_cost_table[currentResearchLevel]; - gfx_draw_string_left(dpi, STR_RESEARCH_COST_PER_MONTH, ¤tResearchCostPerWeek, 0, w->x + 10, w->y + 77); + window_research_funding_page_paint(w, dpi, WIDX_RESEARCH_FUNDING); } #pragma endregion @@ -1512,7 +1406,7 @@ static void window_finances_set_page(rct_window *w, int page) w->widgets = window_finances_page_widgets[page]; w->disabled_widgets = 0; w->pressed_widgets = 0; - + window_invalidate(w); if (w->page == WINDOW_FINANCES_PAGE_RESEARCH) { w->width = 320; diff --git a/src/windows/footpath.c b/src/windows/footpath.c index c3135efe4a..fb16189460 100644 --- a/src/windows/footpath.c +++ b/src/windows/footpath.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 . *****************************************************************************/ @@ -103,48 +103,47 @@ static rct_widget window_footpath_widgets[] = { { WIDGETS_END }, }; -static void window_footpath_emptysub() { } -static void window_footpath_close(); -static void window_footpath_mouseup(); +static void window_footpath_close(rct_window *w); +static void window_footpath_mouseup(rct_window *w, int widgetIndex); static void window_footpath_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); -static void window_footpath_dropdown(); +static void window_footpath_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_footpath_update(rct_window *w); -static void window_footpath_toolupdate(); -static void window_footpath_tooldown(); -static void window_footpath_tooldrag(); -static void window_footpath_toolup(); -static void window_footpath_invalidate(); -static void window_footpath_paint(); +static void window_footpath_toolupdate(rct_window* w, int widgetIndex, int x, int y); +static void window_footpath_tooldown(rct_window* w, int widgetIndex, int x, int y); +static void window_footpath_tooldrag(rct_window* w, int widgetIndex, int x, int y); +static void window_footpath_toolup(rct_window* w, int widgetIndex, int x, int y); +static void window_footpath_invalidate(rct_window *w); +static void window_footpath_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void* window_footpath_events[] = { +static rct_window_event_list window_footpath_events = { window_footpath_close, window_footpath_mouseup, - window_footpath_emptysub, + NULL, window_footpath_mousedown, window_footpath_dropdown, - window_footpath_emptysub, + NULL, window_footpath_update, - window_footpath_emptysub, - window_footpath_emptysub, + NULL, + NULL, window_footpath_toolupdate, window_footpath_tooldown, window_footpath_tooldrag, window_footpath_toolup, - window_footpath_emptysub, - window_footpath_emptysub, - window_footpath_emptysub, - window_footpath_emptysub, - window_footpath_emptysub, - window_footpath_emptysub, - window_footpath_emptysub, - window_footpath_emptysub, - window_footpath_emptysub, - window_footpath_emptysub, - window_footpath_emptysub, - window_footpath_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_footpath_invalidate, window_footpath_paint, - window_footpath_emptysub + NULL }; money32 _window_footpath_cost; @@ -163,7 +162,7 @@ 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); /** - * + * * rct2: 0x006A7C43 */ void window_footpath_open() @@ -182,7 +181,7 @@ void window_footpath_open() 29, 106, 381, - (uint32*)window_footpath_events, + &window_footpath_events, WC_FOOTPATH, 0 ); @@ -210,7 +209,7 @@ void window_footpath_open() // 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) { + if((pathType->flags & 4) && !gCheatsSandboxMode) { RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, sint16) = 0; } @@ -223,15 +222,11 @@ void window_footpath_open() } /** - * + * * rct2: 0x006A852F */ -static void window_footpath_close() +static void window_footpath_close(rct_window *w) { - rct_window *w; - - window_get_register(w); - footpath_provisional_update(); viewport_set_visibility(0); map_invalidate_map_selection_tiles(); @@ -241,16 +236,11 @@ static void window_footpath_close() } /** - * + * * rct2: 0x006A7E92 */ -static void window_footpath_mouseup() +static void window_footpath_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -295,7 +285,7 @@ static void window_footpath_mouseup() } /** - * + * * rct2: 0x006A7EC5 */ static void window_footpath_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) @@ -332,33 +322,28 @@ static void window_footpath_mousedown(int widgetIndex, rct_window*w, rct_widget* } /** - * + * * rct2: 0x006A7F18 */ -static void window_footpath_dropdown() +static void window_footpath_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { int i, j, pathId; - short dropdownIndex; - short widgetIndex; - rct_window *w; rct_path_type *pathType; - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (widgetIndex == WIDX_FOOTPATH_TYPE) RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_TYPE, uint8) = SELECTED_PATH_TYPE_NORMAL; else if (widgetIndex == WIDX_QUEUELINE_TYPE) RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_TYPE, uint8) = SELECTED_PATH_TYPE_QUEUE; else return; - + // Get path id pathId = dropdownIndex; if (pathId == -1) { pathId = RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, sint16); } else { int flags = 4; - if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || gSandboxMode) + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) flags = 0; j = 0; @@ -387,17 +372,11 @@ static void window_footpath_dropdown() } /** - * + * * rct2: 0x006A8032 */ -static void window_footpath_toolupdate() +static void window_footpath_toolupdate(rct_window* w, int widgetIndex, int x, int y) { - short x, y; - short widgetIndex; - rct_window *w; - - window_tool_get_registers(w, widgetIndex, x, y); - if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) { window_footpath_set_provisional_path_at_point(x, y); } else if (widgetIndex == WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL) { @@ -406,17 +385,11 @@ static void window_footpath_toolupdate() } /** - * + * * rct2: 0x006A8047 */ -static void window_footpath_tooldown() +static void window_footpath_tooldown(rct_window* w, int widgetIndex, int x, int y) { - short x, y; - short widgetIndex; - rct_window *w; - - window_tool_get_registers(w, widgetIndex, x, y); - if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) window_footpath_place_path_at_point(x, y); else if (widgetIndex == WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL) @@ -424,34 +397,22 @@ static void window_footpath_tooldown() } /** - * + * * rct2: 0x006A8067 */ -static void window_footpath_tooldrag() +static void window_footpath_tooldrag(rct_window* w, int widgetIndex, int x, int y) { - short x, y; - short widgetIndex; - rct_window *w; - - window_tool_get_registers(w, widgetIndex, x, y); - if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) { window_footpath_place_path_at_point(x, y); } } /** - * + * * rct2: 0x006A8066 */ -static void window_footpath_toolup() +static void window_footpath_toolup(rct_window* w, int widgetIndex, int x, int y) { - short x, y; - short widgetIndex; - rct_window *w; - - window_tool_get_registers(w, widgetIndex, x, y); - if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) { // The function at 0x006A8380 in rct2 is just the following: RCT2_GLOBAL(RCT2_ADDRESS_PATH_ERROR_OCCURED, uint8) = 0; @@ -459,7 +420,7 @@ static void window_footpath_toolup() } /** - * + * * rct2: 0x006A7760 */ static void window_footpath_update_provisional_path_for_bridge_mode(rct_window *w) @@ -469,6 +430,12 @@ static void window_footpath_update_provisional_path_for_bridge_mode(rct_window * if (RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) != PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL) return; + // Recheck area for construction. Set by ride_construction window + if (RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) & (1 << 2)) { + footpath_provisional_remove(); + RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) &= ~(1 << 2); + } + // 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); @@ -494,7 +461,7 @@ static void window_footpath_update_provisional_path_for_bridge_mode(rct_window * } /** - * + * * rct2: 0x006A84BB */ static void window_footpath_update(rct_window *w) @@ -521,18 +488,16 @@ static void window_footpath_update(rct_window *w) } /** - * + * * rct2: 0x006A7D1C */ -static void window_footpath_invalidate() +static void window_footpath_invalidate(rct_window *w) { int selectedPath; rct_path_type *pathType; - 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); w->pressed_widgets &= ~(1 << WIDX_QUEUELINE_TYPE); @@ -558,7 +523,7 @@ static void window_footpath_invalidate() 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) @@ -566,23 +531,19 @@ static void window_footpath_invalidate() } /** - * + * * rct2: 0x006A7D8B */ -static void window_footpath_paint() +static void window_footpath_paint(rct_window *w, rct_drawpixelinfo *dpi) { int x, y, image, selectedPath; rct_path_type *pathType; - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); window_draw_widgets(w, dpi); 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; + image = (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8) + get_current_rotation()) % 4; if (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_SLOPE, uint8) == 2) image += 4; else if (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_SLOPE, uint8) == 6) @@ -615,7 +576,7 @@ static void window_footpath_paint() } /** - * + * * rct2: 0x006A7F88 */ static void window_footpath_show_footpath_types_dialog(rct_window *w, rct_widget *widget, int showQueues) @@ -626,7 +587,7 @@ static void window_footpath_show_footpath_types_dialog(rct_window *w, rct_widget numPathTypes = 0; flags = 4; // 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)) + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || (gCheatsSandboxMode && !showQueues)) flags = 0; for (i = 0; i < 16; i++) { @@ -663,7 +624,7 @@ static void window_footpath_show_footpath_types_dialog(rct_window *w, rct_widget 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; + RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8) = (direction - get_current_rotation()) & 3; _window_footpath_cost = MONEY32_UNDEFINED; window_footpath_set_enabled_and_pressed_widgets(); } @@ -681,7 +642,7 @@ static void window_footpath_mousedown_slope(int slope) } /** - * + * * rct2: 0x006A81FB */ static void window_footpath_set_provisional_path_at_point(int x, int y) @@ -769,7 +730,7 @@ static void window_footpath_set_selection_start_bridge_at_point(int screenX, int } /** - * + * * rct2: 0x006A82C5 */ static void window_footpath_place_path_at_point(int x, int y) @@ -798,21 +759,21 @@ static void window_footpath_place_path_at_point(int x, int y) selectedType = (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_TYPE, uint8) << 7) + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, uint8); // Try and place path - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_CANT_BUILD_FOOTPATH_HERE; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, 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; } else if (RCT2_GLOBAL(0x00F3EFD9, uint32) != 0) { - // bp = 0x009DEA62 - // dx = 0x009DEA60 - // cx = 0x009DEA5E - sound_play_panned(SOUND_PLACE_ITEM, 0x8001, RCT2_GLOBAL(0x009DEA5E, uint16), RCT2_GLOBAL(0x009DEA60, uint16), RCT2_GLOBAL(0x009DEA62, uint16)); + // bp = RCT2_ADDRESS_COMMAND_MAP_Z + // dx = RCT2_ADDRESS_COMMAND_MAP_Y + // cx = RCT2_ADDRESS_COMMAND_MAP_X + audio_play_sound_at_location(SOUND_PLACE_ITEM, RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16)); } } /** - * + * * rct2: 0x006A840F */ static void window_footpath_start_bridge_at_point(int screenX, int screenY) @@ -845,7 +806,7 @@ static void window_footpath_start_bridge_at_point(int screenX, int screenY) } } } - + tool_cancel(); RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_X, uint16) = x; RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y, uint16) = y; @@ -891,9 +852,8 @@ static void window_footpath_construct() cost = footpath_place(type, x, y, z, slope, GAME_COMMAND_FLAG_APPLY); if (cost != MONEY32_UNDEFINED) { - sound_play_panned( + audio_play_sound_at_location( 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) @@ -923,7 +883,7 @@ static void window_footpath_construct() } /** - * + * * rct2: 0x006A78EF */ static void footpath_remove_map_element(rct_map_element *mapElement) @@ -954,7 +914,7 @@ static void footpath_remove_map_element(rct_map_element *mapElement) } // Remove path - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_CANT_REMOVE_FOOTPATH_FROM_HERE; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_REMOVE_FOOTPATH_FROM_HERE; footpath_remove( RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y, uint16), @@ -974,7 +934,7 @@ static void footpath_remove_map_element(rct_map_element *mapElement) } /** - * + * * rct2: 0x006A7873 */ static rct_map_element *footpath_get_map_element_to_remove() @@ -1003,7 +963,7 @@ static rct_map_element *footpath_get_map_element_to_remove() if (!(mapElement->properties.path.type & 4)) if ((mapElement->properties.path.type & 3) == RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8)) continue; - + return mapElement; } } @@ -1013,7 +973,7 @@ static rct_map_element *footpath_get_map_element_to_remove() } /** - * + * * rct2: 0x006A7863 */ static void window_footpath_remove() @@ -1031,7 +991,7 @@ static void window_footpath_remove() } /** - * + * * rct2: 0x006A855C */ static void window_footpath_set_enabled_and_pressed_widgets() @@ -1057,7 +1017,7 @@ static void window_footpath_set_enabled_and_pressed_widgets() pressedWidgets = w->pressed_widgets & 0xFFFF887F; disabledWidgets = 0; - currentRotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + currentRotation = get_current_rotation(); 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; @@ -1106,7 +1066,7 @@ static void window_footpath_set_enabled_and_pressed_widgets() } /** - * + * * rct2: 0x006A7B20 */ static void footpath_get_next_path_info(int *type, int *x, int *y, int *z, int *slope) diff --git a/src/windows/game_bottom_toolbar.c b/src/windows/game_bottom_toolbar.c index 9789ec2a0c..c63c6e4599 100644 --- a/src/windows/game_bottom_toolbar.c +++ b/src/windows/game_bottom_toolbar.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 . *****************************************************************************/ @@ -69,18 +69,17 @@ rct_widget window_game_bottom_toolbar_widgets[] = { { 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 + { WWT_FLATBTN, 0, 0x020A-WIDTH_MOD, 0x027D, 2, 13, 0xFFFFFFFF, STR_NONE }, // Date { WIDGETS_END }, }; -static void window_game_bottom_toolbar_emptysub() { } -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_mouseup(rct_window *w, int widgetIndex); +static void window_game_bottom_toolbar_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_game_bottom_toolbar_invalidate(rct_window *w); +static void window_game_bottom_toolbar_paint(rct_window *w, rct_drawpixelinfo *dpi); 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_cursor(rct_window *w, int widgetIndex, int x, int y, int *cursorId); +static void window_game_bottom_toolbar_unknown05(rct_window *w); 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); @@ -89,37 +88,39 @@ static void window_game_bottom_toolbar_draw_news_item(rct_drawpixelinfo *dpi, rc 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, +static rct_window_event_list window_game_bottom_toolbar_events = { + NULL, window_game_bottom_toolbar_mouseup, - window_game_bottom_toolbar_emptysub, - window_game_bottom_toolbar_emptysub, - window_game_bottom_toolbar_emptysub, + NULL, + NULL, + NULL, 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, - 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_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_emptysub, - window_game_bottom_toolbar_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_game_bottom_toolbar_tooltip, window_game_bottom_toolbar_cursor, - window_game_bottom_toolbar_emptysub, + NULL, window_game_bottom_toolbar_invalidate, window_game_bottom_toolbar_paint, - window_game_bottom_toolbar_emptysub + NULL }; +static void window_game_bottom_toolbar_invalidate_dirty_widgets(rct_window *w); + /** * Creates the main game bottom toolbar window. * rct2: 0x0066B52F (part of 0x0066B3E8) @@ -129,11 +130,11 @@ void window_game_bottom_toolbar_open() rct_window* window; window = window_create( - 0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) - 32, - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16), 32, - (uint32*)window_game_bottom_toolbar_events, + 0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - 32, + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16), 32, + &window_game_bottom_toolbar_events, WC_BOTTOM_TOOLBAR, - WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_5 + WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_NO_BACKGROUND ); window->widgets = window_game_bottom_toolbar_widgets; window->enabled_widgets |= @@ -157,17 +158,14 @@ void window_game_bottom_toolbar_open() } /** - * + * * rct2: 0x0066C588 */ -static void window_game_bottom_toolbar_mouseup() +static void window_game_bottom_toolbar_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w, *mainWindow; + rct_window *mainWindow; rct_news_item *newsItem; - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_LEFT_OUTSET: case WIDX_MONEY: @@ -184,21 +182,21 @@ static void window_game_bottom_toolbar_mouseup() news_item_close_current(); break; case WIDX_NEWS_SUBJECT: - newsItem = &(RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item)[0]); + newsItem = news_item_get(0); news_item_open_subject(newsItem->type, newsItem->assoc); break; case WIDX_NEWS_LOCATE: - newsItem = &(RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item)[0]); - if (newsItem->type == NEWS_ITEM_NULL) + if (news_item_is_queue_empty()) break; { + newsItem = news_item_get(0); int x, y, z; int subject = newsItem->assoc; news_item_get_subject_location(newsItem->type, subject, &x, &y, &z); - if ((uint16)x == SPRITE_LOCATION_NULL) + if (x == SPRITE_LOCATION_NULL) break; if ((mainWindow = window_get_main()) != NULL) @@ -212,52 +210,41 @@ static void window_game_bottom_toolbar_mouseup() } } -static void window_game_bottom_toolbar_tooltip() +static void window_game_bottom_toolbar_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) { int month, day; - short widgetIndex, result; - rct_window *w; - - window_tooltip_get_registers(w, widgetIndex); switch (widgetIndex) { case WIDX_MONEY: - RCT2_GLOBAL(0x013CE952, int) = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PROFIT, sint32); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, int) = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PROFIT, sint32); RCT2_GLOBAL(0x013CE956, int) = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_VALUE, sint32); - result = 0; break; case WIDX_PARK_RATING: - RCT2_GLOBAL(0x013CE952, short) = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, sint16); - result = 0; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, short) = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, sint16); break; case WIDX_DATE: month = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16) & 7; 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(RCT2_ADDRESS_COMMON_FORMAT_ARGS, short) = STR_DATE_DAY_1 + day; RCT2_GLOBAL(0x013CE954, short) = STR_MONTH_MARCH + month; - result = 0; break; } - - window_tooltip_set_registers(result); } /** - * + * * rct2: 0x0066BBA0 */ -static void window_game_bottom_toolbar_invalidate() +static void window_game_bottom_toolbar_invalidate(rct_window *w) { int x; - rct_window *w; 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); + x = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); w->width = x; x--; window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].right = x; @@ -281,12 +268,12 @@ static void window_game_bottom_toolbar_invalidate() window_game_bottom_toolbar_widgets[WIDX_LEFT_INSET].type = WWT_EMPTY; window_game_bottom_toolbar_widgets[WIDX_RIGHT_INSET].type = WWT_EMPTY; - newsItem = &(RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item)[0]); - if (newsItem->type == 0) { + if (news_item_is_queue_empty()) { window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].type = WWT_EMPTY; window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].type = WWT_EMPTY; window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].type = WWT_EMPTY; } else { + newsItem = news_item_get(0); window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].type = WWT_25; window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].type = WWT_FLATBTN; window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].type = WWT_FLATBTN; @@ -327,27 +314,22 @@ static void window_game_bottom_toolbar_invalidate() } /** - * + * * rct2: 0x0066BB79 */ void window_game_bottom_toolbar_invalidate_news_item() { window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].type = - RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item)[0].type == NEWS_ITEM_NULL ? WWT_EMPTY : WWT_IMGBTN; + news_item_is_queue_empty() ? WWT_EMPTY : WWT_IMGBTN; widget_invalidate_by_class(WC_BOTTOM_TOOLBAR, WIDX_MIDDLE_OUTSET); } /** - * + * * rct2: 0x0066BC87 */ -static void window_game_bottom_toolbar_paint() +static void window_game_bottom_toolbar_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - // Draw panel grey backgrounds gfx_fill_rect( dpi, @@ -371,7 +353,7 @@ static void window_game_bottom_toolbar_paint() window_game_bottom_toolbar_draw_left_panel(dpi, w); window_game_bottom_toolbar_draw_right_panel(dpi, w); - if (RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item)[0].type != 0) + if (!news_item_is_queue_empty()) window_game_bottom_toolbar_draw_news_item(dpi, w); else if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8)) window_game_bottom_toolbar_draw_tutorial_text(dpi, w); @@ -397,10 +379,10 @@ static void window_game_bottom_toolbar_draw_left_panel(rct_drawpixelinfo *dpi, r // Draw money if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) { - RCT2_GLOBAL(0x013CE952, int) = DECRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32)); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, int) = DECRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32)); gfx_draw_string_centred( dpi, - (RCT2_GLOBAL(0x013CE952, int) < 0 ? 1391 : 1390), + (RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, int) < 0 ? 1391 : 1390), x, y - 3, (RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWCLASS, rct_windowclass) == 2 && RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WIDGETINDEX, sint32) == WIDX_MONEY ? 2 : w->colours[0] & 0x7F), (void*)0x013CE952 @@ -411,7 +393,7 @@ static void window_game_bottom_toolbar_draw_left_panel(rct_drawpixelinfo *dpi, r // Draw guests gfx_draw_string_centred( dpi, - STR_NUM_GUESTS + RCT2_GLOBAL(0x013573FE, uint8), + STR_NUM_GUESTS + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_CHANGE_MODIFIER, uint8), x, y, (RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WINDOWCLASS, rct_windowclass) == 2 && RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_OVER_WIDGETINDEX, sint32) == WIDX_GUESTS ? 2 : w->colours[0] & 0x7F), (void*)RCT2_ADDRESS_GUESTS_IN_PARK @@ -429,7 +411,7 @@ static void window_game_bottom_toolbar_draw_left_panel(rct_drawpixelinfo *dpi, r } /** - * + * * rct2: 0x0066C76C */ static void window_game_bottom_toolbar_draw_park_rating(rct_drawpixelinfo *dpi, rct_window *w, int colour, int x, int y, uint8 factor) @@ -438,7 +420,7 @@ static void window_game_bottom_toolbar_draw_park_rating(rct_drawpixelinfo *dpi, 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 (!(colour & 0x80000000) || RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0 || (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 8)) { if (bar_width > 2) gfx_fill_rect_inset(dpi, x + 2, y + 2, x + bar_width - 1, y + 8, colour & 0x7FFFFFFF, 0); } @@ -470,19 +452,14 @@ static void window_game_bottom_toolbar_draw_right_panel(rct_drawpixelinfo *dpi, 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; - 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; - } - + + rct_string_id stringId = DateFormatStringFormatIds[gConfigGeneral.date_format]; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, short) = STR_DATE_DAY_1 + day; + RCT2_GLOBAL(0x013CE954, short) = month; RCT2_GLOBAL(0x013CE956, short) = year; gfx_draw_string_centred( dpi, - (gConfigGeneral.date_format ? 5160 : 2737), + stringId, 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), @@ -499,7 +476,7 @@ static void window_game_bottom_toolbar_draw_right_panel(rct_drawpixelinfo *dpi, temperature = climate_celsius_to_fahrenheit(temperature); format = STR_FAHRENHEIT_VALUE; } - RCT2_GLOBAL(0x013CE952, short) = temperature; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, short) = temperature; gfx_draw_string_left(dpi, format, (void*)0x013CE952, 0, x, y + 6); x += 30; @@ -516,39 +493,37 @@ static void window_game_bottom_toolbar_draw_right_panel(rct_drawpixelinfo *dpi, } /** - * + * * rct2: 0x0066BFA5 */ static void window_game_bottom_toolbar_draw_news_item(rct_drawpixelinfo *dpi, rct_window *w) { - int x, y; + int x, y, width; + rct_string_id stringId; rct_news_item *newsItem; + rct_widget *middleOutsetWidget; - newsItem = &(RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item)[0]); + middleOutsetWidget = &window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET]; + newsItem = news_item_get(0); // Current news item gfx_fill_rect_inset( dpi, - w->x + window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].left + 1, - w->y + window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].top + 1, - w->x + window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].right - 1, - w->y + window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].bottom - 1, + w->x + middleOutsetWidget->left + 1, + w->y + middleOutsetWidget->top + 1, + w->x + middleOutsetWidget->right - 1, + w->y + middleOutsetWidget->bottom - 1, w->colours[2], 48 ); // Text - memcpy((void*)0x009B5F2C, &newsItem->colour, 256); - RCT2_CALLPROC_X( - 0x006C1F57, - 14, - 1926, - (window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].left + window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].right) / 2 + w->x, - w->y + window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].top + 11, - 0, - (int)dpi, - (newsItem->ticks << 16) | (window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].right - window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].left - 62) - ); + stringId = 5485; + utf8 *newsItemText = newsItem->text; + x = w->x + (middleOutsetWidget->left + middleOutsetWidget->right) / 2; + y = w->y + middleOutsetWidget->top + 11; + width = middleOutsetWidget->right - middleOutsetWidget->left - 62; + gfx_draw_string_centred_wrapped_partial(dpi, x, y, width, 14, stringId, &newsItemText, newsItem->ticks); x = w->x + window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].left; y = w->y + window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].top; @@ -635,20 +610,16 @@ static void window_game_bottom_toolbar_draw_tutorial_text(rct_drawpixelinfo *dpi static void window_game_bottom_toolbar_update(rct_window* w){ w->frame_no++; - if (w->frame_no >= 24)w->frame_no = 0; + 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); + window_game_bottom_toolbar_invalidate_dirty_widgets(w); } /* 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){ +static void window_game_bottom_toolbar_cursor(rct_window *w, int widgetIndex, int x, int y, int *cursorId) +{ + switch (widgetIndex) { case WIDX_MONEY: case WIDX_GUESTS: case WIDX_PARK_RATING: @@ -659,11 +630,14 @@ static void window_game_bottom_toolbar_cursor(){ } /* rct2: 0x0066C6F2 */ -static void window_game_bottom_toolbar_unknown05(){ - rct_window* w; - - window_get_register(w); +static void window_game_bottom_toolbar_unknown05(rct_window *w) +{ + window_game_bottom_toolbar_invalidate_dirty_widgets(w); +} +/* rct2: 0x0066C6F2 */ +static void window_game_bottom_toolbar_invalidate_dirty_widgets(rct_window *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); diff --git a/src/windows/guest.c b/src/windows/guest.c index d5b9467b55..2a9eb29bdd 100644 --- a/src/windows/guest.c +++ b/src/windows/guest.c @@ -21,23 +21,26 @@ #include "../addresses.h" #include "../config.h" #include "../game.h" -#include "../world/map.h" +#include "../input.h" #include "../management/marketing.h" +#include "../network/network.h" #include "../peep/peep.h" #include "../peep/staff.h" #include "../ride/ride.h" +#include "../ride/ride_data.h" #include "../scenario.h" #include "../localisation/localisation.h" -#include "../world/sprite.h" #include "../sprites.h" +#include "../interface/themes.h" #include "../interface/viewport.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../util/util.h" #include "../world/footpath.h" -#include "../input.h" +#include "../world/map.h" +#include "../world/sprite.h" #include "dropdown.h" #include "error.h" -#include "../interface/themes.h" enum WINDOW_GUEST_PAGE { WINDOW_GUEST_OVERVIEW, @@ -62,18 +65,16 @@ enum WINDOW_GUEST_WIDGET_IDX { WIDX_MARQUEE = 10, WIDX_VIEWPORT, - WIDX_ACTION_LBL, + WIDX_ACTION_LBL, WIDX_PICKUP, WIDX_RENAME, WIDX_LOCATE, WIDX_TRACK, - + WIDX_RIDE_SCROLL = 10 }; -void window_guest_emptysub(){}; - -rct_widget window_guest_overview_widgets[] = { +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 @@ -179,245 +180,245 @@ void window_guest_set_page(rct_window* w, int page); void window_guest_disable_widgets(rct_window* w); void window_guest_viewport_init(rct_window* w); -void window_guest_overview_close(); -void window_guest_overview_resize(); -void window_guest_overview_mouse_up(); -void window_guest_overview_paint(); -void window_guest_overview_invalidate(); -void window_guest_overview_viewport_init_wrapper(); +void window_guest_overview_close(rct_window *w); +void window_guest_overview_resize(rct_window *w); +void window_guest_overview_mouse_up(rct_window *w, int widgetIndex); +void window_guest_overview_paint(rct_window *w, rct_drawpixelinfo *dpi); +void window_guest_overview_invalidate(rct_window *w); +void window_guest_overview_unknown_14(rct_window *w); void window_guest_overview_update(rct_window* w); -void window_guest_overview_text_input(); -void window_guest_overview_tool_update(); -void window_guest_overview_tool_down(); -void window_guest_overview_tool_abort(); +void window_guest_overview_text_input(rct_window *w, int widgetIndex, char *text); +void window_guest_overview_tool_update(rct_window* w, int widgetIndex, int x, int y); +void window_guest_overview_tool_down(rct_window* w, int widgetIndex, int x, int y); +void window_guest_overview_tool_abort(rct_window *w, int widgetIndex); -static void* window_guest_overview_events[] = { +void window_guest_mouse_up(rct_window *w, int widgetIndex); +void window_guest_unknown_05(rct_window *w); + +void window_guest_stats_resize(rct_window *w); +void window_guest_stats_update(rct_window *w); +void window_guest_stats_invalidate(rct_window *w); +void window_guest_stats_paint(rct_window *w, rct_drawpixelinfo *dpi); + +void window_guest_rides_resize(rct_window *w); +void window_guest_rides_update(rct_window *w); +void window_guest_rides_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +void window_guest_rides_scroll_get_size(rct_window *w, int scrollIndex, int *width, int *height); +void window_guest_rides_scroll_mouse_down(rct_window *w, int scrollIndex, int x, int y); +void window_guest_rides_scroll_mouse_over(rct_window *w, int scrollIndex, int x, int y); +void window_guest_rides_invalidate(rct_window *w); +void window_guest_rides_paint(rct_window *w, rct_drawpixelinfo *dpi); +void window_guest_rides_scroll_paint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); + +void window_guest_finance_resize(rct_window *w); +void window_guest_finance_update(rct_window *w); +void window_guest_finance_invalidate(rct_window *w); +void window_guest_finance_paint(rct_window *w, rct_drawpixelinfo *dpi); + +void window_guest_thoughts_resize(rct_window *w); +void window_guest_thoughts_update(rct_window *w); +void window_guest_thoughts_invalidate(rct_window *w); +void window_guest_thoughts_paint(rct_window *w, rct_drawpixelinfo *dpi); + +void window_guest_inventory_resize(rct_window *w); +void window_guest_inventory_update(rct_window *w); +void window_guest_inventory_invalidate(rct_window *w); +void window_guest_inventory_paint(rct_window *w, rct_drawpixelinfo *dpi); + +static rct_window_event_list window_guest_overview_events = { window_guest_overview_close, window_guest_overview_mouse_up, window_guest_overview_resize, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, + NULL, + NULL, + NULL, window_guest_overview_update, - window_guest_emptysub, - window_guest_emptysub, - window_guest_overview_tool_update,//tool_update - window_guest_overview_tool_down,//tool_down - window_guest_emptysub, - window_guest_emptysub, - window_guest_overview_tool_abort,//tool_abort - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_overview_text_input,//text_input - window_guest_overview_viewport_init_wrapper, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_overview_invalidate, //Invalidate - window_guest_overview_paint, //Paint - window_guest_emptysub + NULL, + NULL, + window_guest_overview_tool_update, + window_guest_overview_tool_down, + NULL, + NULL, + window_guest_overview_tool_abort, + NULL, + NULL, + NULL, + NULL, + NULL, + window_guest_overview_text_input, + window_guest_overview_unknown_14, + NULL, + NULL, + NULL, + NULL, + window_guest_overview_invalidate, + window_guest_overview_paint, + NULL }; -void window_guest_mouse_up(); -void window_guest_unknown_05(); - -void window_guest_stats_resize(); -void window_guest_stats_update(); -void window_guest_stats_invalidate(); -void window_guest_stats_paint(); - -static void* window_guest_stats_events[] = { - window_guest_emptysub, - window_guest_mouse_up, //mouse_up - window_guest_stats_resize, //resize - window_guest_emptysub, - window_guest_emptysub, +static rct_window_event_list window_guest_stats_events = { + NULL, + window_guest_mouse_up, + window_guest_stats_resize, + NULL, + NULL, window_guest_unknown_05, window_guest_stats_update, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_stats_invalidate, //invalidate - window_guest_stats_paint, //paint - window_guest_emptysub + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_guest_stats_invalidate, + window_guest_stats_paint, + NULL }; -void window_guest_rides_resize(); -void window_guest_rides_update(); -void window_guest_rides_tooltip(); -void window_guest_rides_scroll_get_size(); -void window_guest_rides_scroll_mouse_down(); -void window_guest_rides_scroll_mouse_over(); -void window_guest_rides_invalidate(); -void window_guest_rides_paint(); -void window_guest_rides_scroll_paint(); - -static void* window_guest_rides_events[] = { - window_guest_emptysub, - window_guest_mouse_up, //mouse_up - window_guest_rides_resize, //resize - window_guest_emptysub, - window_guest_emptysub, +static rct_window_event_list window_guest_rides_events = { + NULL, + window_guest_mouse_up, + window_guest_rides_resize, + NULL, + NULL, window_guest_unknown_05, window_guest_rides_update, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_rides_scroll_get_size, //scroll_get_size - window_guest_rides_scroll_mouse_down, //scroll_mouse_down - window_guest_emptysub, - window_guest_rides_scroll_mouse_over, //scroll_mouse_over - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_rides_tooltip, //tooltip - window_guest_emptysub, - window_guest_emptysub, - window_guest_rides_invalidate, //invalidate - window_guest_rides_paint, //paint - window_guest_rides_scroll_paint //scroll_paint + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_guest_rides_scroll_get_size, + window_guest_rides_scroll_mouse_down, + NULL, + window_guest_rides_scroll_mouse_over, + NULL, + NULL, + NULL, + window_guest_rides_tooltip, + NULL, + NULL, + window_guest_rides_invalidate, + window_guest_rides_paint, + window_guest_rides_scroll_paint }; -void window_guest_finance_resize(); -void window_guest_finance_update(); -void window_guest_finance_invalidate(); -void window_guest_finance_paint(); - -static void* window_guest_finance_events[] = { - window_guest_emptysub, - window_guest_mouse_up, //mouse_up - window_guest_finance_resize, //resize - window_guest_emptysub, - window_guest_emptysub, +static rct_window_event_list window_guest_finance_events = { + NULL, + window_guest_mouse_up, + window_guest_finance_resize, + NULL, + NULL, window_guest_unknown_05, window_guest_finance_update, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_finance_invalidate, //invalidate - window_guest_finance_paint, //paint - window_guest_emptysub + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_guest_finance_invalidate, + window_guest_finance_paint, + NULL }; -void window_guest_thoughts_resize(); -void window_guest_thoughts_update(); -void window_guest_thoughts_invalidate(); -void window_guest_thoughts_paint(); - -static void* window_guest_thoughts_events[] = { - window_guest_emptysub, - window_guest_mouse_up, //mouse_up - window_guest_thoughts_resize, //resize - window_guest_emptysub, - window_guest_emptysub, +static rct_window_event_list window_guest_thoughts_events = { + NULL, + window_guest_mouse_up, + window_guest_thoughts_resize, + NULL, + NULL, window_guest_unknown_05, window_guest_thoughts_update, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_thoughts_invalidate, //invalidate - window_guest_thoughts_paint, //paint - window_guest_emptysub + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_guest_thoughts_invalidate, + window_guest_thoughts_paint, + NULL }; -void window_guest_inventory_resize(); -void window_guest_inventory_update(); -void window_guest_inventory_invalidate(); -void window_guest_inventory_paint(); - -static void* window_guest_inventory_events[] = { - window_guest_emptysub, - window_guest_mouse_up, //mouse_up - window_guest_inventory_resize, //resize - window_guest_emptysub, - window_guest_emptysub, +static rct_window_event_list window_guest_inventory_events = { + NULL, + window_guest_mouse_up, + window_guest_inventory_resize, + NULL, + NULL, window_guest_unknown_05, window_guest_inventory_update, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_emptysub, - window_guest_inventory_invalidate, //invalidate - window_guest_inventory_paint, //paint - window_guest_emptysub + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_guest_inventory_invalidate, + window_guest_inventory_paint, + NULL }; //0x981D24 -void* window_guest_page_events[] = { - window_guest_overview_events, - window_guest_stats_events, - window_guest_rides_events, - window_guest_finance_events, - window_guest_thoughts_events, - window_guest_inventory_events +static rct_window_event_list *window_guest_page_events[] = { + &window_guest_overview_events, + &window_guest_stats_events, + &window_guest_rides_events, + &window_guest_finance_events, + &window_guest_thoughts_events, + &window_guest_inventory_events }; void window_guest_set_colours(); @@ -483,7 +484,7 @@ uint32 window_guest_page_enabled_widgets[] = { * */ void window_guest_open(rct_peep* peep){ - + if (peep->type == PEEP_TYPE_STAFF){ window_staff_open(peep); return; @@ -493,7 +494,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, WF_RESIZABLE); + window = window_create_auto_pos(192, 157, &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; @@ -513,22 +514,22 @@ void window_guest_open(rct_peep* peep){ window->viewport_focus_coordinates.y = -1; } - + window->page = 0; window_invalidate(window); - + window->widgets = window_guest_page_widgets[WINDOW_GUEST_OVERVIEW]; window->enabled_widgets = window_guest_page_enabled_widgets[WINDOW_GUEST_OVERVIEW]; window->hold_down_widgets = 0; window->event_handlers = window_guest_page_events[WINDOW_GUEST_OVERVIEW]; window->pressed_widgets = 0; - + window_guest_disable_widgets(window); window_init_scroll_widgets(window); window_guest_viewport_init(window); } -/* rct2: 0x006987A6 +/* rct2: 0x006987A6 * Disables the finance tab when no money. * Disables peep pickup when in certain no pickup states. */ @@ -552,33 +553,26 @@ void window_guest_disable_widgets(rct_window* w){ } /* rct2: 0x00696A75 */ -void window_guest_overview_close(){ - rct_window* w; - - window_get_register(w); - +void window_guest_overview_close(rct_window *w) +{ 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)) + if (w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS,rct_windowclass) && + w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER,rct_windownumber)) tool_cancel(); } } /* rct2: 0x00696FBE */ -void window_guest_overview_resize(){ - rct_window* w; - - window_get_register(w); - +void window_guest_overview_resize(rct_window *w){ window_guest_disable_widgets(w); window_event_invalidate_call(w); - + widget_invalidate(w, WIDX_MARQUEE); - + window_set_resize(w, 192, 159, 500, 450); - + rct_viewport* view = w->viewport; - + if (view){ if ((w->width - 30) == view->width){ if ((w->height - 72) == view->height){ @@ -596,10 +590,8 @@ void window_guest_overview_resize(){ } /* rct2: 0x00696A06 */ -void window_guest_overview_mouse_up(){ - short widgetIndex; - rct_window* w; - window_widget_get_registers(w, widgetIndex); +void window_guest_overview_mouse_up(rct_window *w, int widgetIndex) +{ rct_peep* peep = GET_PEEP(w->number); switch(widgetIndex){ @@ -621,11 +613,11 @@ void window_guest_overview_mouse_up(){ if (tool_set(w, widgetIndex, 7)) { return; } - + w->var_48C = peep->x; remove_peep_from_ride(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); sprite_move(0x8000, peep->y, peep->z, (rct_sprite*)peep); peep_decrement_num_riders(peep); @@ -652,26 +644,26 @@ void window_guest_set_page(rct_window* w, int page){ if(w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) && w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass)) tool_cancel(); - + } int listen = 0; if ( page == WINDOW_GUEST_OVERVIEW && w->page==WINDOW_GUEST_OVERVIEW && w->viewport){ if(!(w->viewport->flags & VIEWPORT_FLAG_SOUND_ON)) listen = 1; } - - + + w->page = page; w->frame_no = 0; w->no_list_items = 0; w->selected_list_item = -1; - + rct_viewport* viewport = w->viewport; w->viewport = 0; if (viewport){ viewport->width = 0; } - + w->enabled_widgets = window_guest_page_enabled_widgets[page]; w->hold_down_widgets = 0; w->event_handlers = window_guest_page_events[page]; @@ -683,14 +675,12 @@ void window_guest_set_page(rct_window* w, int page){ window_event_invalidate_call(w); window_init_scroll_widgets(w); window_invalidate(w); - + if (listen && w->viewport) w->viewport->flags |= VIEWPORT_FLAG_SOUND_ON; } -void window_guest_overview_viewport_init_wrapper(){ - rct_window* w; - window_get_register(w); - +void window_guest_overview_unknown_14(rct_window *w) +{ window_guest_viewport_init(w); } @@ -701,10 +691,10 @@ void window_guest_viewport_init(rct_window* w){ union{ sprite_focus sprite; coordinate_focus coordinate; - } focus; //The focus will be either a sprite or a coordinate. + } focus = { 0 }; //The focus will be either a sprite or a coordinate. focus.sprite.sprite_id = w->number; - + rct_peep* peep = GET_PEEP(w->number); if (peep->state == PEEP_STATE_PICKED){ @@ -712,8 +702,8 @@ void window_guest_viewport_init(rct_window* w){ } else{ uint8 final_check = 1; - if (peep->state == PEEP_STATE_ON_RIDE - || peep->state == PEEP_STATE_ENTERING_RIDE + if (peep->state == PEEP_STATE_ON_RIDE + || peep->state == PEEP_STATE_ENTERING_RIDE || (peep->state == PEEP_STATE_LEAVING_RIDE && peep->x == SPRITE_LOCATION_NULL)){ rct_ride* ride = &(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride)[peep->current_ride]); @@ -744,14 +734,14 @@ void window_guest_viewport_init(rct_window* w){ focus.sprite.type |= VIEWPORT_FOCUS_TYPE_SPRITE | VIEWPORT_FOCUS_TYPE_COORDINATE; focus.sprite.pad_486 &= 0xFFFF; } - focus.coordinate.rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + focus.coordinate.rotation = get_current_rotation(); } uint16 viewport_flags; if (w->viewport){ //Check all combos, for now skipping y and rot - if (focus.coordinate.x == w->viewport_focus_coordinates.x && + if (focus.coordinate.x == w->viewport_focus_coordinates.x && focus.coordinate.y == w->viewport_focus_coordinates.y && focus.coordinate.z == w->viewport_focus_coordinates.z && focus.coordinate.rotation == w->viewport_focus_coordinates.rotation) @@ -786,7 +776,7 @@ void window_guest_viewport_init(rct_window* w){ int height = view_widget->bottom - view_widget->top - 1; viewport_create(w, x, y, width, height, 0, focus.coordinate.x, focus.coordinate.y, focus.coordinate.z, focus.sprite.type & VIEWPORT_FOCUS_TYPE_MASK, focus.sprite.sprite_id); - w->flags |= WF_2; + w->flags |= WF_NO_SCROLLING; window_invalidate(w); } } @@ -797,58 +787,58 @@ void window_guest_viewport_init(rct_window* w){ } /** - * rct2: 0x6983dd + * rct2: 0x6983dd * used by window_staff as well */ void window_guest_overview_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ if (w->disabled_widgets & (1<widgets[WIDX_TAB_1]; int width = widget->right - widget->left - 1; int height = widget->bottom - widget->top - 1; int x = widget->left + 1 + w->x; int y = widget->top + 1 + w->y; if (w->page == WINDOW_GUEST_OVERVIEW) height++; - + rct_drawpixelinfo* clip_dpi = clip_drawpixelinfo(dpi, x, width, y, height ); if (!clip_dpi) return; - + x = 14; y = 20; - + rct_peep* peep = GET_PEEP(w->number); - + if (peep->type == PEEP_TYPE_STAFF && peep->staff_type == STAFF_TYPE_ENTERTAINER) y++; - + int ebx = *(RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2]) + 1; - + int eax = 0; - + if (w->page == WINDOW_GUEST_OVERVIEW){ eax = w->var_494>>16; eax &= 0xFFFC; } ebx += eax; - + int sprite_id = ebx | (peep->tshirt_colour << 19) | (peep->trousers_colour << 24) | 0xA0000000; gfx_draw_sprite( clip_dpi, sprite_id, x, y, 0); - + // If holding a balloon if (ebx >= 0x2A1D && ebx < 0x2A3D){ ebx += 32; ebx |= (peep->balloon_colour << 19) | 0x20000000; gfx_draw_sprite( clip_dpi, ebx, x, y, 0); } - + // If holding umbrella if (ebx >= 0x2BBD && ebx < 0x2BDD){ ebx += 32; ebx |= (peep->umbrella_colour << 19) | 0x20000000; gfx_draw_sprite(clip_dpi, ebx, x, y, 0); } - + // If wearing hat if (ebx >= 0x29DD && ebx < 0x29FD){ ebx += 32; @@ -899,9 +889,9 @@ void window_guest_rides_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ int image_id = SPR_TAB_RIDE_0; if ( w->page == WINDOW_GUEST_RIDES ){ - image_id += (w->frame_no / 4) & 0xF; + image_id += (w->frame_no / 4) & 0xF; } - + gfx_draw_sprite(dpi, image_id, x, y, 0); } @@ -916,9 +906,9 @@ void window_guest_finance_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ int image_id = SPR_TAB_FINANCES_SUMMARY_0; if ( w->page == WINDOW_GUEST_FINANCE ){ - image_id += (w->frame_no / 2) & 0x7; + image_id += (w->frame_no / 2) & 0x7; } - + gfx_draw_sprite(dpi, image_id, x, y, 0); } @@ -933,9 +923,9 @@ void window_guest_thoughts_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ int image_id = 5269; if ( w->page == WINDOW_GUEST_THOUGHTS ){ - image_id += (w->frame_no / 2) & 0x7; + image_id += (w->frame_no / 2) & 0x7; } - + gfx_draw_sprite(dpi, image_id, x, y, 0); } @@ -948,17 +938,13 @@ void window_guest_inventory_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ int y = widget->top + w->y; int image_id = 5326; - + gfx_draw_sprite(dpi, image_id, x, y, 0); } /* rct2: 0x696887 */ -void window_guest_overview_paint(){ - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +void window_guest_overview_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ window_draw_widgets(w, dpi); window_guest_overview_tab_paint(w, dpi); window_guest_stats_tab_paint(w, dpi); @@ -1001,6 +987,7 @@ void window_guest_overview_paint(){ for (; i < PEEP_MAX_THOUGHTS; ++i){ if (peep->thoughts[i].type == PEEP_THOUGHT_TYPE_NONE){ w->list_information_type = 0; + rct2_free(dpi_marquee); return; } if (peep->thoughts[i].var_2 == 1){ // If a fresh thought @@ -1009,6 +996,7 @@ void window_guest_overview_paint(){ } if (i == PEEP_MAX_THOUGHTS){ w->list_information_type = 0; + rct2_free(dpi_marquee); return; } @@ -1025,36 +1013,35 @@ void window_guest_overview_paint(){ } /* rct2: 0x696749*/ -void window_guest_overview_invalidate(){ - rct_window* w; - window_get_register(w); +void window_guest_overview_invalidate(rct_window *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); } - + w->pressed_widgets &= ~(WIDX_TAB_1 | WIDX_TAB_2 |WIDX_TAB_3 |WIDX_TAB_4 |WIDX_TAB_5 |WIDX_TAB_6); w->pressed_widgets |= 1ULL << (w->page + WIDX_TAB_1); - + rct_peep* peep = GET_PEEP(w->number); RCT2_GLOBAL(0x13CE952,uint16) = peep->name_string_idx; RCT2_GLOBAL(0x13CE954,uint32) = peep->id; - + w->pressed_widgets &= ~(1<flags & 0x8){ w->pressed_widgets |= (1<width - 1; window_guest_overview_widgets[WIDX_BACKGROUND].bottom = w->height - 1; - + window_guest_overview_widgets[WIDX_PAGE_BACKGROUND].right =w->width - 1; window_guest_overview_widgets[WIDX_PAGE_BACKGROUND].bottom = w->height - 1; - + window_guest_overview_widgets[WIDX_TITLE].right = w->width - 2; - + window_guest_overview_widgets[WIDX_CLOSE].left = w->width - 13; window_guest_overview_widgets[WIDX_CLOSE].right = w->width - 3; @@ -1064,7 +1051,7 @@ void window_guest_overview_invalidate(){ window_guest_overview_widgets[WIDX_ACTION_LBL].top = w->height - 12; window_guest_overview_widgets[WIDX_ACTION_LBL].bottom = w->height - 3; window_guest_overview_widgets[WIDX_ACTION_LBL].right = w->width - 24; - + window_guest_overview_widgets[WIDX_MARQUEE].right = w->width - 24; window_guest_overview_widgets[WIDX_PICKUP].right = w->width - 2; @@ -1076,7 +1063,7 @@ void window_guest_overview_invalidate(){ window_guest_overview_widgets[WIDX_RENAME].left = w->width - 25; window_guest_overview_widgets[WIDX_LOCATE].left = w->width - 25; window_guest_overview_widgets[WIDX_TRACK].left = w->width - 25; - + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_6); } @@ -1090,7 +1077,7 @@ void window_guest_overview_update(rct_window* w){ widget_invalidate(w, WIDX_TAB_1); widget_invalidate(w, WIDX_TAB_2); - + w->list_information_type += 2; if ((w->var_494 & 0xFFFF) == 0xFFFF) @@ -1098,47 +1085,41 @@ void window_guest_overview_update(rct_window* w){ else w->var_494++; - // Create the "I have the strangest feeling I am being watched thought" - if ((w->var_494 & 0xFFFF) >= 3840){ - if (!(w->var_494 & 0x3FF)){ - int rand = scenario_rand() & 0xFFFF; - if (rand <= 0x2AAA){ - rct_peep* peep = GET_PEEP(w->number); - peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_WATCHED, 0xFF); + // Disable peep watching thought for multiplayer as its client specific + if (network_get_mode() == NETWORK_MODE_NONE) { + // Create the "I have the strangest feeling I am being watched thought" + if ((w->var_494 & 0xFFFF) >= 3840) { + if (!(w->var_494 & 0x3FF)) { + int random = util_rand() & 0xFFFF; + if (random <= 0x2AAA) { + rct_peep* peep = GET_PEEP(w->number); + peep_insert_new_thought(peep, PEEP_THOUGHT_TYPE_WATCHED, 0xFF); + } } } } } /* rct2:0x696A6A */ -void window_guest_overview_text_input(){ - short widgetIndex; - rct_window *w; - char _cl; - uint32* text; +void window_guest_overview_text_input(rct_window *w, int widgetIndex, char *text) +{ + if (widgetIndex != WIDX_RENAME) + return; - window_text_input_get_registers(w, widgetIndex, _cl, text); + if (text == NULL) + return; - if (widgetIndex != WIDX_RENAME)return; - - if (!_cl) return; - - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = 0x5AE; - - game_do_command(1, 1, w->number, *text, 22, *(text + 2), *(text + 1)); - game_do_command(2, 1, 0, *(text + 3), 22, *(text + 5), *(text + 4)); - game_do_command(0, 1, 0, *(text + 6), 22, *(text + 8), *(text + 7)); + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_NAME_GUEST; + game_do_command(1, GAME_COMMAND_FLAG_APPLY, w->number, *((int*)(text + 0)), GAME_COMMAND_SET_PEEP_NAME, *((int*)(text + 8)), *((int*)(text + 4))); + game_do_command(2, GAME_COMMAND_FLAG_APPLY, w->number, *((int*)(text + 12)), GAME_COMMAND_SET_PEEP_NAME, *((int*)(text + 20)), *((int*)(text + 16))); + game_do_command(0, GAME_COMMAND_FLAG_APPLY, w->number, *((int*)(text + 24)), GAME_COMMAND_SET_PEEP_NAME, *((int*)(text + 32)), *((int*)(text + 28))); } /* rct2: 0x696A5F */ -void window_guest_overview_tool_update(){ - short widgetIndex; - rct_window* w; - short x, y; - - window_tool_get_registers(w, widgetIndex, x, y); - - if (widgetIndex != WIDX_PICKUP) return; +void window_guest_overview_tool_update(rct_window* w, int widgetIndex, int x, int y) +{ + if (widgetIndex != WIDX_PICKUP) + return; map_invalidate_selection_rect(); @@ -1169,7 +1150,7 @@ void window_guest_overview_tool_update(){ RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_Y, uint16) = y; w->var_492++; if (w->var_492 >= 48)w->var_492 = 0; - + rct_peep* peep; peep = GET_PEEP(w->number); int ebx = (RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2])[22]; @@ -1183,14 +1164,10 @@ void window_guest_overview_tool_update(){ } /* rct2: 0x696A54 */ -void window_guest_overview_tool_down(){ - short widgetIndex; - rct_window* w; - short x, y; - - window_tool_get_registers(w, widgetIndex, x, y); - - if (widgetIndex != WIDX_PICKUP) return; +void window_guest_overview_tool_down(rct_window* w, int widgetIndex, int x, int y) +{ + if (widgetIndex != WIDX_PICKUP) + return; int dest_x, dest_y; rct_map_element *mapElement; @@ -1198,7 +1175,7 @@ void window_guest_overview_tool_down(){ if (dest_x == (sint16)0x8000)return; - // Set the coordinate of destination to be exactly + // Set the coordinate of destination to be exactly // in the middle of a tile. dest_x += 16; dest_y += 16; @@ -1212,12 +1189,8 @@ void window_guest_overview_tool_down(){ window_error_open(0x785,-1); return; } - - int _edx; - _edx = (dest_z / 8) | (((dest_z / 8) + 1) << 8); - int flags = RCT2_CALLPROC_X(0x68B93A, tile_x, 0xF, tile_y, _edx, (int)w, 0, 0); - - if (flags & 0x100){ + + if (!map_can_construct_at(tile_x, tile_y, dest_z / 8, (dest_z / 8) + 1, 15)){ if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) != 0x3A5 ){ if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) != 0x49B){ window_error_open(0x785, -1); @@ -1228,7 +1201,7 @@ void window_guest_overview_tool_down(){ rct_peep* peep = GET_PEEP(w->number); sprite_move(dest_x, dest_y, dest_z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); peep_decrement_num_riders(peep); peep->state = 0; peep_window_state_update(peep); @@ -1246,19 +1219,17 @@ void window_guest_overview_tool_down(){ } /* rct2: 0x696A49 */ -void window_guest_overview_tool_abort(){ - short widgetIndex; - rct_window* w; - short x, y; - - window_tool_get_registers(w, widgetIndex, x, y); - if (widgetIndex != WIDX_PICKUP) return; +void window_guest_overview_tool_abort(rct_window *w, int widgetIndex) +{ + if (widgetIndex != WIDX_PICKUP) + return; rct_peep* peep = GET_PEEP(w->number); - if (peep->state != PEEP_STATE_PICKED) return; + if (peep->state != PEEP_STATE_PICKED) + return; sprite_move( w->var_48C, peep->y, peep->z + 8, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); if (peep->x != (sint16)0x8000){ peep_decrement_num_riders(peep); @@ -1277,11 +1248,8 @@ void window_guest_overview_tool_abort(){ /* rct2:0x69744F, 0x697795, 0x697BDD, 0x697E18, 0x698279 * This is a combination of 5 functions that were identical */ -void window_guest_mouse_up(){ - short widgetIndex; - rct_window* w; - window_widget_get_registers(w, widgetIndex); - +void window_guest_mouse_up(rct_window *w, int widgetIndex) +{ switch (widgetIndex){ case WIDX_CLOSE: window_close(w); @@ -1298,39 +1266,32 @@ void window_guest_mouse_up(){ } /* rct2: 0x697488 */ -void window_guest_stats_resize(){ - rct_window* w; - window_get_register(w); - +void window_guest_stats_resize(rct_window *w) +{ window_set_resize(w, 192, 162, 192, 162); } -/* rct2: 0x6974ED, 0x00697959, 0x00697C7B, 0x00697ED2, 0x00698333 +/* rct2: 0x6974ED, 0x00697959, 0x00697C7B, 0x00697ED2, 0x00698333 * This is a combination of 5 functions that were identical */ -void window_guest_unknown_05(){ - rct_window* w; - window_get_register(w); - +void window_guest_unknown_05(rct_window *w) +{ widget_invalidate(w, WIDX_TAB_1); } /* rct2: 0x69746A */ -void window_guest_stats_update(){ - rct_window* w; - window_get_register(w); - +void window_guest_stats_update(rct_window *w) +{ w->frame_no++; rct_peep* peep = GET_PEEP(w->number); - peep->var_45 &= ~(1<<1); + peep->window_invalidate_flags &= ~PEEP_INVALIDATE_PEEP_STATS; window_invalidate(w); } /* rct2: 0x69707D */ -void window_guest_stats_invalidate(){ - rct_window* w; - window_get_register(w); +void window_guest_stats_invalidate(rct_window *w) +{ colour_scheme_update(w); if (w->widgets != window_guest_page_widgets[w->page]) { @@ -1361,7 +1322,7 @@ void window_guest_stats_invalidate(){ /** * * rct2: 0x0066ECC1 -* +* * 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){ @@ -1384,12 +1345,8 @@ void window_guest_stats_bars_paint(int value, int x, int y, rct_window *w, rct_d } /* rct2: 0x0069711D */ -void window_guest_stats_paint(){ - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +void window_guest_stats_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ window_draw_widgets(w, dpi); window_guest_overview_tab_paint(w, dpi); window_guest_stats_tab_paint(w, dpi); @@ -1540,18 +1497,14 @@ void window_guest_stats_paint(){ } /* rct2: 0x006978F4 */ -void window_guest_rides_resize(){ - rct_window* w; - window_get_register(w); - +void window_guest_rides_resize(rct_window *w) +{ window_set_resize(w, 192, 128, 500, 400); } /* rct2: 0x6977B0 */ -void window_guest_rides_update(){ - rct_window* w; - window_get_register(w); - +void window_guest_rides_update(rct_window *w) +{ w->frame_no++; widget_invalidate(w, WIDX_TAB_2); @@ -1566,7 +1519,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 & 0x7; + uint8 ride_id_bit = ride_id % 8; 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); @@ -1584,28 +1537,23 @@ void window_guest_rides_update(){ } /* rct2: 0x697844 */ -void window_guest_rides_tooltip(){ - RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST; +void window_guest_rides_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) +{ + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = STR_LIST; } /* rct2: 0x69784E */ -void window_guest_rides_scroll_get_size() +void window_guest_rides_scroll_get_size(rct_window *w, int scrollIndex, int *width, int *height) { - rct_window *w; - int width, height; - - window_get_register(w); - - width = 0; - height = w->no_list_items * 10; + *height = w->no_list_items * 10; if (w->selected_list_item != -1){ w->selected_list_item = -1; window_invalidate(w); } - int visable_height = height - - window_guest_rides_widgets[WIDX_RIDE_SCROLL].bottom + int visable_height = *height + - window_guest_rides_widgets[WIDX_RIDE_SCROLL].bottom + window_guest_rides_widgets[WIDX_RIDE_SCROLL].top + 21; @@ -1615,17 +1563,12 @@ void window_guest_rides_scroll_get_size() w->scrolls[0].v_top = visable_height; window_invalidate(w); } - - window_scrollsize_set_registers(width, height); } /* rct2: 0x006978CC */ -void window_guest_rides_scroll_mouse_down(){ +void window_guest_rides_scroll_mouse_down(rct_window *w, int scrollIndex, int x, int y) +{ int index; - short x, y, scrollIndex; - rct_window *w; - - window_scrollmouse_get_registers(w, scrollIndex, x, y); index = y / 10; if (index >= w->no_list_items) return; @@ -1634,12 +1577,9 @@ void window_guest_rides_scroll_mouse_down(){ } /* rct2: 0x0069789C */ -void window_guest_rides_scroll_mouse_over(){ +void window_guest_rides_scroll_mouse_over(rct_window *w, int scrollIndex, int x, int y) +{ int index; - short x, y, scrollIndex; - rct_window *w; - - window_scrollmouse_get_registers(w, scrollIndex, x, y); index = y / 10; if (index >= w->no_list_items)return; @@ -1651,9 +1591,8 @@ void window_guest_rides_scroll_mouse_over(){ } /* rct2: 0x0069757A */ -void window_guest_rides_invalidate(){ - rct_window* w; - window_get_register(w); +void window_guest_rides_invalidate(rct_window *w) +{ colour_scheme_update(w); if (window_guest_page_widgets[w->page] != w->widgets){ @@ -1685,12 +1624,8 @@ void window_guest_rides_invalidate(){ } /* rct2: 0x00697637 */ -void window_guest_rides_paint(){ - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +void window_guest_rides_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ window_draw_widgets(w, dpi); window_guest_overview_tab_paint(w, dpi); window_guest_stats_tab_paint(w, dpi); @@ -1710,7 +1645,7 @@ void window_guest_rides_paint(){ y = w->y + window_guest_rides_widgets[WIDX_PAGE_BACKGROUND].bottom - 12; - int ride_string_id = 3094; + int ride_string_id = 3094; int ride_string_arguments = 0; if (peep->favourite_ride != 0xFF){ rct_ride* ride = GET_RIDE(peep->favourite_ride); @@ -1724,12 +1659,8 @@ void window_guest_rides_paint(){ } /* rct2: 0x006976FC */ -void window_guest_rides_scroll_paint(){ - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +void window_guest_rides_scroll_paint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) +{ // ax int left = dpi->x; // bx @@ -1739,7 +1670,7 @@ void window_guest_rides_scroll_paint(){ // dx int bottom = dpi->y + dpi->height - 1; - int colour = RCT2_ADDRESS(0x141FC48, uint8)[w->colours[1] * 8]; + int colour = ColourMapA[w->colours[1]].mid_light; gfx_fill_rect(dpi, left, top, right, bottom, colour); for (int list_index = 0; list_index < w->no_list_items; list_index++){ @@ -1756,18 +1687,14 @@ void window_guest_rides_scroll_paint(){ } /* rct2: 0x00697C16 */ -void window_guest_finance_resize(){ - rct_window* w; - window_get_register(w); - +void window_guest_finance_resize(rct_window *w) +{ window_set_resize(w, 210, 134, 210, 134); } /* rct2: 0x00697BF8 */ -void window_guest_finance_update(){ - rct_window* w; - window_get_register(w); - +void window_guest_finance_update(rct_window *w) +{ w->frame_no++; widget_invalidate(w, WIDX_TAB_2); @@ -1775,9 +1702,8 @@ void window_guest_finance_update(){ } /* rct2: 0x00697968 */ -void window_guest_finance_invalidate(){ - rct_window* w; - window_get_register(w); +void window_guest_finance_invalidate(rct_window *w) +{ colour_scheme_update(w); if (window_guest_page_widgets[w->page] != w->widgets){ @@ -1807,12 +1733,8 @@ void window_guest_finance_invalidate(){ } /* rct2: 0x00697A08 */ -void window_guest_finance_paint(){ - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +void window_guest_finance_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ window_draw_widgets(w, dpi); window_guest_overview_tab_paint(w, dpi); window_guest_stats_tab_paint(w, dpi); @@ -1890,13 +1812,11 @@ void window_guest_finance_paint(){ } /* rct2: 0x00697E33 */ -void window_guest_thoughts_resize(){ - rct_window* w; - window_get_register(w); - +void window_guest_thoughts_resize(rct_window *w) +{ rct_peep* peep = GET_PEEP(w->number); - if (peep->var_45 & 1){ - peep->var_45 &=~(1 << 0); + if (peep->window_invalidate_flags & PEEP_INVALIDATE_PEEP_THOUGHTS){ + peep->window_invalidate_flags &= ~PEEP_INVALIDATE_PEEP_THOUGHTS; window_invalidate(w); } @@ -1904,10 +1824,8 @@ void window_guest_thoughts_resize(){ } /* rct2: 0x00697EB4 */ -void window_guest_thoughts_update(){ - rct_window* w; - window_get_register(w); - +void window_guest_thoughts_update(rct_window *w) +{ w->frame_no++; widget_invalidate(w, WIDX_TAB_2); @@ -1915,9 +1833,8 @@ void window_guest_thoughts_update(){ } /* rct2: 0x00697C8A */ -void window_guest_thoughts_invalidate(){ - rct_window* w; - window_get_register(w); +void window_guest_thoughts_invalidate(rct_window *w) +{ colour_scheme_update(w); if (window_guest_page_widgets[w->page] != w->widgets){ @@ -1947,12 +1864,8 @@ void window_guest_thoughts_invalidate(){ } /* rct2: 0x00697D2A */ -void window_guest_thoughts_paint(){ - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +void window_guest_thoughts_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ window_draw_widgets(w, dpi); window_guest_overview_tab_paint(w, dpi); window_guest_stats_tab_paint(w, dpi); @@ -1980,7 +1893,7 @@ void window_guest_thoughts_paint(){ RCT2_GLOBAL(0x13CE952, uint32) = argument1; RCT2_GLOBAL(0x13CE956, uint32) = argument2; - int width = window_guest_thoughts_widgets[WIDX_PAGE_BACKGROUND].right + int width = window_guest_thoughts_widgets[WIDX_PAGE_BACKGROUND].right - window_guest_thoughts_widgets[WIDX_PAGE_BACKGROUND].left - 8; @@ -1993,13 +1906,11 @@ void window_guest_thoughts_paint(){ /* rct2: 0x00698294 */ -void window_guest_inventory_resize(){ - rct_window* w; - window_get_register(w); - +void window_guest_inventory_resize(rct_window *w) +{ rct_peep* peep = GET_PEEP(w->number); - if (peep->var_45 & (1<<3)){ - peep->var_45 &= ~(1 << 3); + if (peep->window_invalidate_flags & PEEP_INVALIDATE_PEEP_INVENTORY){ + peep->window_invalidate_flags &= ~PEEP_INVALIDATE_PEEP_INVENTORY; window_invalidate(w); } @@ -2007,10 +1918,8 @@ void window_guest_inventory_resize(){ } /* rct2: 0x00698315 */ -void window_guest_inventory_update(){ - rct_window* w; - window_get_register(w); - +void window_guest_inventory_update(rct_window *w) +{ w->frame_no++; widget_invalidate(w, WIDX_TAB_2); @@ -2018,9 +1927,8 @@ void window_guest_inventory_update(){ } /* rct2: 0x00697EE1 */ -void window_guest_inventory_invalidate(){ - rct_window* w; - window_get_register(w); +void window_guest_inventory_invalidate(rct_window *w) +{ colour_scheme_update(w); if (window_guest_page_widgets[w->page] != w->widgets){ @@ -2049,13 +1957,82 @@ void window_guest_inventory_invalidate(){ window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_6); } +static rct_string_id window_guest_inventory_format_item(rct_peep *peep, int item, uint8 *args) +{ + rct_ride *ride; + + // Default arguments + RCT2_GLOBAL(args + 0, uint32) = ShopItemImage[item]; + RCT2_GLOBAL(args + 4, uint16) = ShopItemStringIds[item].display; + RCT2_GLOBAL(args + 6, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, uint16); + RCT2_GLOBAL(args + 8, uint32) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME_ARGS, uint32); + + // Special overrides + switch (item) { + case SHOP_ITEM_BALLOON: + RCT2_GLOBAL(args + 0, uint32) |= 0x20000000 | peep->balloon_colour << 19; + break; + case SHOP_ITEM_PHOTO: + ride = GET_RIDE(peep->photo1_ride_ref); + RCT2_GLOBAL(args + 6, uint16) = ride->name; + RCT2_GLOBAL(args + 8, uint32) = ride->name_arguments; + break; + case SHOP_ITEM_UMBRELLA: + RCT2_GLOBAL(args + 0, uint32) |= 0x20000000 | peep->umbrella_colour << 19; + break; + case SHOP_ITEM_VOUCHER: + switch (peep->voucher_type) { + case VOUCHER_TYPE_PARK_ENTRY_FREE: + RCT2_GLOBAL(args + 6, uint16) = 2418; + RCT2_GLOBAL(args + 8, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, uint16); + RCT2_GLOBAL(args + 10, uint32) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME_ARGS, uint32); + break; + case VOUCHER_TYPE_RIDE_FREE: + ride = GET_RIDE(peep->voucher_arguments); + RCT2_GLOBAL(args + 6, uint16) = 2419; + RCT2_GLOBAL(args + 8, uint16) = ride->name; + RCT2_GLOBAL(args + 10, uint32) = ride->name_arguments; + break; + case VOUCHER_TYPE_PARK_ENTRY_HALF_PRICE: + RCT2_GLOBAL(args + 6, uint16) = 2420; + RCT2_GLOBAL(args + 8, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, uint16); + RCT2_GLOBAL(args + 10, uint32) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME_ARGS, uint32); + break; + case VOUCHER_TYPE_FOOD_OR_DRINK_FREE: + RCT2_GLOBAL(args + 6, uint16) = 2421; + RCT2_GLOBAL(args + 8, uint16) = ShopItemStringIds[peep->voucher_arguments].singular; + break; + } + break; + case SHOP_ITEM_HAT: + RCT2_GLOBAL(args + 0, uint32) |= 0x20000000 | peep->hat_colour << 19; + break; + case SHOP_ITEM_TSHIRT: + RCT2_GLOBAL(args + 0, uint32) |= 0x20000000 | peep->tshirt_colour << 19; + break; + case SHOP_ITEM_PHOTO2: + ride = GET_RIDE(peep->photo2_ride_ref); + RCT2_GLOBAL(args + 6, uint16) = ride->name; + RCT2_GLOBAL(args + 8, uint32) = ride->name_arguments; + break; + case SHOP_ITEM_PHOTO3: + ride = GET_RIDE(peep->photo3_ride_ref); + RCT2_GLOBAL(args + 6, uint16) = ride->name; + RCT2_GLOBAL(args + 8, uint32) = ride->name_arguments; + break; + case SHOP_ITEM_PHOTO4: + ride = GET_RIDE(peep->photo4_ride_ref); + RCT2_GLOBAL(args + 6, uint16) = ride->name; + RCT2_GLOBAL(args + 8, uint32) = ride->name_arguments; + break; + } + + return STR_GUEST_ITEM_FORMAT; +} + /* rct2: 0x00697F81 */ -void window_guest_inventory_paint(){ - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +void window_guest_inventory_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ window_draw_widgets(w, dpi); window_guest_overview_tab_paint(w, dpi); window_guest_stats_tab_paint(w, dpi); @@ -2064,120 +2041,30 @@ void window_guest_inventory_paint(){ window_guest_thoughts_tab_paint(w, dpi); window_guest_inventory_tab_paint(w, dpi); - rct_peep* peep = GET_PEEP(w->number); + rct_peep *peep = GET_PEEP(w->number); - //cx - int x = w->x + window_guest_inventory_widgets[WIDX_PAGE_BACKGROUND].left + 4; - //dx - int y = w->y + window_guest_inventory_widgets[WIDX_PAGE_BACKGROUND].top + 2; + rct_widget *pageBackgroundWidget = &window_guest_inventory_widgets[WIDX_PAGE_BACKGROUND]; + int x = w->x + pageBackgroundWidget->left + 4; + int y = w->y + pageBackgroundWidget->top + 2; + int itemNameWidth = pageBackgroundWidget->right - pageBackgroundWidget->left - 8; - int max_y = w->y + w->height - 22; - int no_items = 0; - - gfx_draw_string_left(dpi, 1810, (void*)0, 0, x, y); + int maxY = w->y + w->height - 22; + int numItems = 0; + gfx_draw_string_left(dpi, STR_CARRYING, NULL, 0, x, y); y += 10; - for (int i = 0; y < max_y && i < 28; ++i){ - int item_flag = 1 << i; - if (!(peep->item_standard_flags & item_flag))continue; - no_items++; + for (int item = 0; item < SHOP_ITEM_COUNT; item++) { + if (y >= maxY) break; + if (!peep_has_item(peep, item)) continue; - RCT2_GLOBAL(0x13CE952, uint32) = 5061 + i; - - switch (item_flag){ - case PEEP_ITEM_TSHIRT: - RCT2_GLOBAL(0x13CE952, uint32) |= 0x20000000 | peep->tshirt_colour << 19; - break; - case PEEP_ITEM_HAT: - RCT2_GLOBAL(0x13CE952, uint32) |= 0x20000000 | peep->hat_colour << 19; - break; - case PEEP_ITEM_BALLOON: - RCT2_GLOBAL(0x13CE952, uint32) |= 0x20000000 | peep->balloon_colour << 19; - break; - case PEEP_ITEM_UMBRELLA: - RCT2_GLOBAL(0x13CE952, uint32) |= 0x20000000 | peep->umbrella_colour << 19; - break; - } - - int string_format = 2072 + i; - if (string_format >= 2104) string_format += 84; //??? i is never 32 - - RCT2_GLOBAL(0x13CE956, uint16) = string_format; - RCT2_GLOBAL(0x13CE958, uint16) = RCT2_GLOBAL(0x13573D4, uint16); - RCT2_GLOBAL(0x13CE95A, uint32) = RCT2_GLOBAL(0x13573D8, uint32); - rct_ride* ride; - - switch (item_flag){ - case PEEP_ITEM_PHOTO: - ride = GET_RIDE(peep->photo1_ride_ref); - RCT2_GLOBAL(0x13CE958, uint16) = ride->name; - RCT2_GLOBAL(0x13CE95A, uint32) = ride->name_arguments; - break; - case PEEP_ITEM_VOUCHER: - RCT2_GLOBAL(0x13CE958, uint16) = peep->voucher_type + 2418; - RCT2_GLOBAL(0x13CE95A, uint16) = RCT2_GLOBAL(0x13573D4, uint16); - RCT2_GLOBAL(0x13CE95C, uint32) = RCT2_GLOBAL(0x13573D8, uint32); - - if (peep->voucher_type == VOUCHER_TYPE_PARK_ENTRY_FREE || peep->voucher_type == VOUCHER_TYPE_PARK_ENTRY_HALF_PRICE)break; - - int voucher_id = peep->voucher_arguments + 1988; - if (voucher_id >= 2020) voucher_id += 102; - - RCT2_GLOBAL(0x13CE95A, uint16) = voucher_id; - - if (peep->voucher_type == VOUCHER_TYPE_FOOD_OR_DRINK_FREE)break; - ride = GET_RIDE(peep->voucher_arguments); - RCT2_GLOBAL(0x13CE95A, uint16) = ride->name; - RCT2_GLOBAL(0x13CE95C, uint32) = ride->name_arguments; - break; - } - - int width = window_guest_inventory_widgets[WIDX_PAGE_BACKGROUND].right - - window_guest_inventory_widgets[WIDX_PAGE_BACKGROUND].left - - 8; - - y += gfx_draw_string_left_wrapped(dpi, (void*)0x13CE952, x, y, width, 1875, 0); + void *args = (void*)0x013CE952; + rct_string_id stringId = window_guest_inventory_format_item(peep, item, (uint8*)args); + y += gfx_draw_string_left_wrapped(dpi, args, x, y, itemNameWidth, stringId, 0); + numItems++; } - for (int i = 0; y < max_y && i < 22; ++i){ - int item_flag = 1 << i; - - if (!(peep->item_extra_flags & item_flag))continue; - no_items++; - - RCT2_GLOBAL(0x13CE952, uint32) = 5089 + i; - RCT2_GLOBAL(0x13CE956, uint16) = 2188 + i; - RCT2_GLOBAL(0x13CE958, uint16) = RCT2_GLOBAL(0x13573D4, uint16); - RCT2_GLOBAL(0x13CE95A, uint32) = RCT2_GLOBAL(0x13573D8, uint32); - - if (i < 3){ - int ride_id = 0; - switch (item_flag){ - case PEEP_ITEM_PHOTO2: - ride_id = peep->photo2_ride_ref; - break; - case PEEP_ITEM_PHOTO3: - ride_id = peep->photo3_ride_ref; - break; - case PEEP_ITEM_PHOTO4: - ride_id = peep->photo4_ride_ref; - break; - } - - rct_ride* ride = GET_RIDE(ride_id); - RCT2_GLOBAL(0x13CE958, uint16) = ride->name; - RCT2_GLOBAL(0x13CE95A, uint32) = ride->name_arguments; - } - - int width = window_guest_inventory_widgets[WIDX_PAGE_BACKGROUND].right - - window_guest_inventory_widgets[WIDX_PAGE_BACKGROUND].left - - 8; - - y += gfx_draw_string_left_wrapped(dpi, (void*)0x13CE952, x, y, width, 1875, 0); - } - - if (!no_items){ - gfx_draw_string_left(dpi, 2293, (void*)0, 0, x, y); + if (numItems == 0) { + gfx_draw_string_left(dpi, STR_NOTHING, (void*)0, 0, x, y); } } diff --git a/src/windows/guest_list.c b/src/windows/guest_list.c index 47fff45313..04edb7f2ce 100644 --- a/src/windows/guest_list.c +++ b/src/windows/guest_list.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 . *****************************************************************************/ @@ -46,6 +46,7 @@ enum WINDOW_GUEST_LIST_WIDGET_IDX { WIDX_INFO_TYPE_DROPDOWN, WIDX_INFO_TYPE_DROPDOWN_BUTTON, WIDX_MAP, + WIDX_TRACKING, WIDX_TAB_1, WIDX_TAB_2, WIDX_GUEST_LIST @@ -63,55 +64,55 @@ static rct_widget window_guest_list_widgets[] = { { WWT_RESIZE, 1, 0, 349, 43, 329, 0x0FFFFFFFF, STR_NONE }, // tab content panel { WWT_DROPDOWN, 1, 5, 84, 59, 70, STR_PAGE_1, STR_NONE }, // page dropdown { WWT_DROPDOWN_BUTTON, 1, 73, 83, 60, 69, 876, STR_NONE }, // page dropdown button - { WWT_DROPDOWN, 1, 126, 301, 59, 70, 0x0FFFFFFFF, STR_INFORMATION_TYPE_TIP }, // information type dropdown - { WWT_DROPDOWN_BUTTON, 1, 290, 300, 60, 69, 876, STR_INFORMATION_TYPE_TIP }, // information type dropdown button - { WWT_FLATBTN, 1, 321, 344, 46, 69, 5192, STR_SHOW_GUESTS_ON_MAP_TIP }, // map + { WWT_DROPDOWN, 1, 120, 295, 59, 70, 0x0FFFFFFFF, STR_INFORMATION_TYPE_TIP }, // information type dropdown + { WWT_DROPDOWN_BUTTON, 1, 284, 294, 60, 69, 876, STR_INFORMATION_TYPE_TIP }, // information type dropdown button + { WWT_FLATBTN, 1, 297, 320, 46, 69, 5192, STR_SHOW_GUESTS_ON_MAP_TIP }, // map + { WWT_FLATBTN, 1, 321, 344, 46, 69, SPR_TRACK_PEEP, STR_TRACKED_GUESTS_ONLY_TIP }, // tracking { WWT_TAB, 1, 3, 33, 17, 43, 0x02000144E, STR_INDIVIDUAL_GUESTS_TIP }, // tab 1 { WWT_TAB, 1, 34, 64, 17, 43, 0x02000144E, STR_SUMMARISED_GUESTS_TIP }, // tab 2 { WWT_SCROLL, 1, 3, 346, 72, 326, 3, STR_NONE }, // guest list { WIDGETS_END }, }; -static void window_guest_list_emptysub() { } -static void window_guest_list_mouseup(); -static void window_guest_list_resize(); +static void window_guest_list_mouseup(rct_window *w, int widgetIndex); +static void window_guest_list_resize(rct_window *w); static void window_guest_list_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_guest_list_dropdown(); +static void window_guest_list_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_guest_list_update(rct_window *w); -static void window_guest_list_scrollgetsize(); -static void window_guest_list_scrollmousedown(); -static void window_guest_list_scrollmouseover(); -static void window_guest_list_tooltip(); -static void window_guest_list_invalidate(); -static void window_guest_list_paint(); -static void window_guest_list_scrollpaint(); +static void window_guest_list_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_guest_list_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_guest_list_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_guest_list_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_guest_list_invalidate(rct_window *w); +static void window_guest_list_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_guest_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void* window_guest_list_events[] = { - window_guest_list_emptysub, +static rct_window_event_list window_guest_list_events = { + NULL, window_guest_list_mouseup, window_guest_list_resize, window_guest_list_mousedown, window_guest_list_dropdown, - window_guest_list_emptysub, + NULL, window_guest_list_update, - window_guest_list_emptysub, - window_guest_list_emptysub, - window_guest_list_emptysub, - window_guest_list_emptysub, - window_guest_list_emptysub, - window_guest_list_emptysub, - window_guest_list_emptysub, - window_guest_list_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_guest_list_scrollgetsize, window_guest_list_scrollmousedown, - window_guest_list_emptysub, + NULL, window_guest_list_scrollmouseover, - window_guest_list_emptysub, - window_guest_list_emptysub, - window_guest_list_emptysub, + NULL, + NULL, + NULL, window_guest_list_tooltip, - window_guest_list_emptysub, - window_guest_list_emptysub, + NULL, + NULL, window_guest_list_invalidate, window_guest_list_paint, window_guest_list_scrollpaint @@ -124,6 +125,7 @@ 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 bool _window_guest_list_tracking_only; static uint16 _window_guest_list_groups_num_guests[240]; static uint32 _window_guest_list_groups_argument_1[240]; @@ -136,7 +138,7 @@ static void window_guest_list_find_groups(); static void get_arguments_from_peep(rct_peep *peep, uint32 *argument_1, uint32* argument_2); /** - * + * * rct2: 0x006992E3 */ void window_guest_list_open() @@ -148,7 +150,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, WF_10 | WF_RESIZABLE); + window = window_create_auto_pos(350, 330, &window_guest_list_events, WC_GUEST_LIST, WF_10 | WF_RESIZABLE); window->widgets = window_guest_list_widgets; window->enabled_widgets = (1 << WIDX_CLOSE) | @@ -157,6 +159,7 @@ void window_guest_list_open() (1 << WIDX_INFO_TYPE_DROPDOWN) | (1 << WIDX_INFO_TYPE_DROPDOWN_BUTTON) | (1 << WIDX_MAP) | + (1 << WIDX_TRACKING) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2); @@ -167,6 +170,7 @@ void window_guest_list_open() _window_guest_list_selected_filter = -1; _window_guest_list_selected_page = 0; _window_guest_list_num_pages = 1; + _window_guest_list_tracking_only = false; window_guest_list_widgets[WIDX_PAGE_DROPDOWN].type = WWT_EMPTY; window_guest_list_widgets[WIDX_PAGE_DROPDOWN_BUTTON].type = WWT_EMPTY; window->var_492 = 0; @@ -194,11 +198,12 @@ void window_guest_list_open_with_filter(int type, int index) _window_guest_list_selected_page = 0; _window_guest_list_num_pages = 1; + _window_guest_list_tracking_only = false; RCT2_GLOBAL(0x009AC7E0, uint8) = 0; RCT2_GLOBAL(0x009AC7F0, uint8) = 0; - rct_ride *ride; + rct_ride *ride = NULL; if (type != 3) { // common for cases 0, 1, 2 ride = GET_RIDE(index & 0x000000FF); eax = ride->name; @@ -262,16 +267,11 @@ void window_guest_list_open_with_filter(int type, int index) } /** - * + * * rct2: 0x00699AAF */ -static void window_guest_list_mouseup() +static void window_guest_list_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -279,19 +279,24 @@ static void window_guest_list_mouseup() case WIDX_MAP: window_map_open(); break; + case WIDX_TRACKING: + _window_guest_list_tracking_only = !_window_guest_list_tracking_only; + if (_window_guest_list_tracking_only) + w->pressed_widgets |= (1 << WIDX_TRACKING); + else + w->pressed_widgets &= ~(1 << WIDX_TRACKING); + window_invalidate(w); + w->scrolls[0].v_top = 0; + break; } } /** - * + * * rct2: 0x00699EA3 */ -static void window_guest_list_resize() +static void window_guest_list_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - w->min_width = 350; w->min_height = 330; if (w->width < w->min_width) { @@ -305,7 +310,7 @@ static void window_guest_list_resize() } /** - * + * * rct2: 0x00699AC4 */ static void window_guest_list_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) @@ -320,6 +325,9 @@ static void window_guest_list_mousedown(int widgetIndex, rct_window*w, rct_widge _window_guest_list_selected_tab = widgetIndex - WIDX_TAB_1; _window_guest_list_selected_page = 0; _window_guest_list_num_pages = 1; + window_guest_list_widgets[WIDX_TRACKING].type = WWT_EMPTY; + if (_window_guest_list_selected_tab == PAGE_INDIVIDUAL) + window_guest_list_widgets[WIDX_TRACKING].type = WWT_FLATBTN; window_guest_list_widgets[WIDX_PAGE_DROPDOWN].type = WWT_EMPTY; window_guest_list_widgets[WIDX_PAGE_DROPDOWN_BUTTON].type = WWT_EMPTY; w->list_information_type = 0; @@ -344,7 +352,7 @@ static void window_guest_list_mousedown(int widgetIndex, rct_window*w, rct_widge gDropdownItemsFormat[i] = 1142; gDropdownItemsArgs[i] = STR_PAGE_1 + i; } - gDropdownItemsChecked = (1 << _window_guest_list_selected_view); + dropdown_set_checked(_window_guest_list_selected_view, true); break; case WIDX_INFO_TYPE_DROPDOWN_BUTTON: widget = &w->widgets[widgetIndex - 1]; @@ -364,22 +372,17 @@ static void window_guest_list_mousedown(int widgetIndex, rct_window*w, rct_widge widget->right - widget->left - 3 ); - gDropdownItemsChecked = (1 << _window_guest_list_selected_view); + dropdown_set_checked(_window_guest_list_selected_view, true); break; } } /** - * + * * rct2: 0x00699AE1 */ -static void window_guest_list_dropdown() +static void window_guest_list_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - short dropdownIndex, widgetIndex; - rct_window *w; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - switch (widgetIndex) { case WIDX_PAGE_DROPDOWN_BUTTON: if (dropdownIndex == -1) @@ -397,7 +400,7 @@ static void window_guest_list_dropdown() } /** - * + * * rct2: 0x00699E54 */ static void window_guest_list_update(rct_window *w) @@ -411,32 +414,32 @@ static void window_guest_list_update(rct_window *w) } /** - * + * * rct2: 0x00699C55 */ -static void window_guest_list_scrollgetsize() +static void window_guest_list_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - int i, y, numGuests, spriteIndex, width, height; - rct_window *w; + int i, y, numGuests, spriteIndex; rct_peep *peep; - window_get_register(w); - switch (_window_guest_list_selected_tab) { case PAGE_INDIVIDUAL: // Count the number of guests numGuests = 0; FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->var_2A != 0) + if (peep->outside_of_park != 0) continue; if (_window_guest_list_selected_filter != -1) if (window_guest_list_is_peep_in_filter(peep)) continue; + if (_window_guest_list_tracking_only && !(peep->flags & PEEP_FLAGS_TRACKING)) + continue; numGuests++; } w->var_492 = numGuests; y = numGuests * 10; + RCT2_GLOBAL(0x00F1EE09, uint32) = numGuests; break; case PAGE_SUMMARISED: // Find the groups @@ -444,9 +447,11 @@ static void window_guest_list_scrollgetsize() w->var_492 = _window_guest_list_num_groups; y = _window_guest_list_num_groups * 21; break; + default: + log_error("Improper tab selected: %d, bailing out.", _window_guest_list_selected_tab); + return; } - RCT2_GLOBAL(0x00F1EE09, uint32) = numGuests; i = _window_guest_list_selected_page; for (i = _window_guest_list_selected_page - 1; i >= 0; i--) y -= 0x7BF2; @@ -467,40 +472,36 @@ static void window_guest_list_scrollgetsize() window_invalidate(w); } - width = 447; - height = y; - - window_scrollsize_set_registers(width, height); + *width = 447; + *height = y; } /** - * + * * rct2: 0x00699D7D */ -static void window_guest_list_scrollmousedown() +static void window_guest_list_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) { int i, spriteIndex; - short x, y, scrollIndex; - rct_window *w; rct_peep *peep; - window_scrollmouse_get_registers(w, scrollIndex, x, y); - switch (_window_guest_list_selected_tab) { case PAGE_INDIVIDUAL: i = y / 10; i += _window_guest_list_selected_page * 3173; FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->var_2A != 0) + if (peep->outside_of_park != 0) continue; if (_window_guest_list_selected_filter != -1) if (window_guest_list_is_peep_in_filter(peep)) continue; + if (_window_guest_list_tracking_only && !(peep->flags & PEEP_FLAGS_TRACKING)) + continue; if (i == 0) { // Open guest window window_guest_open(peep); - + break; } else { i--; @@ -514,6 +515,7 @@ static void window_guest_list_scrollmousedown() RCT2_GLOBAL(0x00F1EDFA, uint32) = _window_guest_list_groups_argument_2[i]; _window_guest_list_selected_filter = _window_guest_list_selected_view; _window_guest_list_selected_tab = PAGE_INDIVIDUAL; + window_guest_list_widgets[WIDX_TRACKING].type = WWT_FLATBTN; window_invalidate(w); w->scrolls[0].v_top = 0; } @@ -522,16 +524,12 @@ static void window_guest_list_scrollmousedown() } /** - * + * * rct2: 0x00699D3B */ -static void window_guest_list_scrollmouseover() +static void window_guest_list_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) { int i; - short x, y, scrollIndex; - rct_window *w; - - 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; @@ -542,23 +540,20 @@ static void window_guest_list_scrollmouseover() } /** - * + * * rct2: 0x00699E4A */ -static void window_guest_list_tooltip() +static void window_guest_list_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) { - RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = STR_LIST; } /** - * + * * rct2: 0x00699511 */ -static void window_guest_list_invalidate() +static void window_guest_list_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); w->pressed_widgets &= ~(1 << WIDX_TAB_1); @@ -584,16 +579,12 @@ static void window_guest_list_invalidate() } /** - * + * * rct2: 0x006995CC */ -static void window_guest_list_paint() +static void window_guest_list_paint(rct_window *w, rct_drawpixelinfo *dpi) { int i, x, y, format; - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); // Widgets window_draw_widgets(w, dpi); @@ -638,28 +629,24 @@ static void window_guest_list_paint() if (_window_guest_list_selected_tab == PAGE_INDIVIDUAL) { x = w->x + 4; y = w->y + window_guest_list_widgets[WIDX_GUEST_LIST].bottom + 2; - RCT2_GLOBAL(0x013CE952, sint16) = w->var_492; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, sint16) = w->var_492; gfx_draw_string_left(dpi, (w->var_492 == 1 ? 1755 : 1754), (void*)0x013CE952, 0, x, y); } } /** - * + * * rct2: 0x00699701 */ -static void window_guest_list_scrollpaint() +static void window_guest_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { int spriteIndex, format, numGuests, i, j, y; - rct_window *w; - rct_drawpixelinfo *dpi; rct_peep *peep; rct_peep_thought *thought; uint32 argument_1, argument_2; - window_paint_get_registers(w, dpi); - // Background fill - 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_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, ColourMapA[w->colours[1]].mid_light); switch (_window_guest_list_selected_tab) { case PAGE_INDIVIDUAL: @@ -669,7 +656,7 @@ static void window_guest_list_scrollpaint() // For each guest FOR_ALL_GUESTS(spriteIndex, peep) { peep->var_0C &= ~0x200; - if (peep->var_2A != 0) + if (peep->outside_of_park != 0) continue; if (_window_guest_list_selected_filter != -1) { if (window_guest_list_is_peep_in_filter(peep)) @@ -677,8 +664,10 @@ static void window_guest_list_scrollpaint() RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) |= (1 << 0); peep->var_0C |= 0x200; } + if (_window_guest_list_tracking_only && !(peep->flags & PEEP_FLAGS_TRACKING)) + continue; - // + // if (y + 11 >= -0x7FFF && y + 11 > dpi->y && y < 0x7FFF) { // Check if y is beyond the scroll control if (y > dpi->y + dpi->height) @@ -692,7 +681,7 @@ static void window_guest_list_scrollpaint() } // Guest name - RCT2_GLOBAL(0x013CE952, uint16) = peep->name_string_idx; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = peep->name_string_idx; RCT2_GLOBAL(0x013CE954, uint32) = peep->id; gfx_draw_string_left_clipped(dpi, format, (void*)0x013CE952, 0, 0, y - 1, 113); @@ -704,12 +693,12 @@ static void window_guest_list_scrollpaint() // Tracking icon if (peep->flags & PEEP_FLAGS_TRACKING) gfx_draw_sprite(dpi, 5129, 112, y, 0); - + // Action - + get_arguments_from_action(peep, &argument_1, &argument_2); - RCT2_GLOBAL(0x013CE952, uint32) = argument_1; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) = argument_1; RCT2_GLOBAL(0x013CE952 + 4, uint32) = argument_2; gfx_draw_string_left_clipped(dpi, format, (void*)0x013CE952, 0, 133, y - 1, 314); break; @@ -723,10 +712,10 @@ static void window_guest_list_scrollpaint() continue; if (thought->var_2 > 5) break; - + get_arguments_from_thought(peep->thoughts[j], &argument_1, &argument_2); - RCT2_GLOBAL(0x013CE952, uint32) = argument_1; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) = argument_1; RCT2_GLOBAL(0x013CE952 + 4, uint32) = argument_2; gfx_draw_string_left_clipped(dpi, format, (void*)0x013CE952, 0, 118, y - 1, 329); break; @@ -764,7 +753,7 @@ static void window_guest_list_scrollpaint() gfx_draw_sprite(dpi, _window_guest_list_groups_guest_faces[i * 56 + j] + 5486, j * 8, y + 9, 0); // Draw action - RCT2_GLOBAL(0x013CE952, uint32) = _window_guest_list_groups_argument_1[i]; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) = _window_guest_list_groups_argument_1[i]; RCT2_GLOBAL(0x013CE952 + 4, uint32) = _window_guest_list_groups_argument_2[i]; RCT2_GLOBAL(0x013CE952 + 10, uint32) = numGuests; gfx_draw_string_left_clipped(dpi, format, (void*)0x013CE952, 0, 0, y - 1, 414); @@ -803,7 +792,7 @@ static int window_guest_list_is_peep_in_filter(rct_peep* peep) return 1; } -/** +/** * rct2:0x0069B7EA * Calculates a hash value (arguments) for comparing peep actions/thoughts * peep (esi) @@ -831,7 +820,7 @@ static void get_arguments_from_peep(rct_peep *peep, uint32 *argument_1, uint32* } /** - * + * * rct2: 0x0069B5AE */ static void window_guest_list_find_groups() @@ -851,12 +840,12 @@ static void window_guest_list_find_groups() // Set all guests to unassigned FOR_ALL_GUESTS(spriteIndex, peep) - if (peep->var_2A == 0) + if (peep->outside_of_park == 0) peep->var_0C |= (1 << 8); // For each guest / group FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->var_2A != 0 || !(peep->var_0C & (1 << 8))) + if (peep->outside_of_park != 0 || !(peep->var_0C & (1 << 8))) continue; // New group, cap at 240 though @@ -868,18 +857,18 @@ static void window_guest_list_find_groups() _window_guest_list_num_groups++; _window_guest_list_groups_num_guests[groupIndex] = 1; peep->var_0C &= ~(1 << 8); - + get_arguments_from_peep( peep, &_window_guest_list_groups_argument_1[groupIndex], &_window_guest_list_groups_argument_2[groupIndex]); RCT2_GLOBAL(0x00F1EDF6, uint32) = _window_guest_list_groups_argument_1[groupIndex]; RCT2_GLOBAL(0x00F1EDFA, uint32) = _window_guest_list_groups_argument_2[groupIndex]; - + RCT2_ADDRESS(0x00F1AF26, uint8)[groupIndex] = groupIndex; faceIndex = groupIndex * 56; _window_guest_list_groups_guest_faces[faceIndex++] = get_peep_face_sprite_small(peep) - 5486; // Find more peeps that belong to same group FOR_ALL_GUESTS(spriteIndex2, peep2) { - if (peep2->var_2A != 0 || !(peep2->var_0C & (1 << 8))) + if (peep2->outside_of_park != 0 || !(peep2->var_0C & (1 << 8))) continue; uint32 argument1, argument2; diff --git a/src/windows/install_track.c b/src/windows/install_track.c index c98aca69d0..1b631782ae 100644 --- a/src/windows/install_track.c +++ b/src/windows/install_track.c @@ -53,42 +53,41 @@ static rct_widget window_install_track_widgets[] = { { 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_close(rct_window *w); +static void window_install_track_mouseup(rct_window *w, int widgetIndex); +static void window_install_track_invalidate(rct_window *w); +static void window_install_track_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_install_track_text_input(rct_window *w, int widgetIndex, char *text); -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 +static rct_window_event_list window_install_track_events = { + window_install_track_close, + window_install_track_mouseup, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_install_track_text_input, + NULL, + NULL, + NULL, + NULL, + NULL, + window_install_track_invalidate, + window_install_track_paint, + NULL }; ride_list_item _window_install_track_item; @@ -127,7 +126,7 @@ void window_install_track_open(const char* path) 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 = window_create(x, y, 402, 400, &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); @@ -135,15 +134,16 @@ void window_install_track_open(const char* path) w->track_list.var_484 = 0; window_push_others_right(w); - memset(track_path, 0, MAX_PATH - 1); - strcpy(track_path, path); + strncpy(track_path, path, MAX_PATH); + track_path[MAX_PATH - 1] = '\0'; 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); + strncpy(track_dest_name, track_name_pointer, MAX_PATH); + track_dest_name[MAX_PATH - 1] = '\0'; window_invalidate(w); } @@ -154,12 +154,12 @@ void window_install_track_open(const char* path) */ static void window_install_track_select(rct_window *w, int index) { - uint8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); + utf8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, utf8); rct_track_design *trackDesign; w->track_list.var_480 = index; - sound_play_panned(SOUND_CLICK_1, w->x + (w->width / 2), 0, 0, 0); + audio_play_sound_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); @@ -173,7 +173,7 @@ static void window_install_track_select(rct_window *w, int index) index--; trackDesignItem = trackDesignList + (index * 128); - RCT2_GLOBAL(0x00F4403C, uint8*) = trackDesignItem; + RCT2_GLOBAL(0x00F4403C, utf8*) = trackDesignItem; window_track_list_format_name( (char*)0x009BC313, @@ -210,7 +210,7 @@ static void window_install_track_select(rct_window *w, int index) * * rct2: 0x006D41DC */ -static void window_install_track_close() +static void window_install_track_close(rct_window *w) { free(RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, void*)); } @@ -219,12 +219,9 @@ static void window_install_track_close() * * rct2: 0x006D407A */ -static void window_install_track_mouseup() +static void window_install_track_mouseup(rct_window *w, int widgetIndex) { - rct_window *w; - short widgetIndex, result; - - window_widget_get_registers(w, widgetIndex); + int result; switch (widgetIndex) { case WIDX_CLOSE: @@ -264,10 +261,8 @@ static void window_install_track_mouseup() * * rct2: 0x006D3B06 */ -static void window_install_track_invalidate() +static void window_install_track_invalidate(rct_window *w) { - rct_window *w; - window_get_register(w); colour_scheme_update(w); w->pressed_widgets |= 1 << WIDX_TRACK_PREVIEW; @@ -276,7 +271,7 @@ static void window_install_track_invalidate() else w->pressed_widgets &= ~(1 << WIDX_TOGGLE_SCENERY); - if (w->track_list.var_482 != 0xFFFF) { + if (w->track_list.var_482 != 0xFFFF) { w->disabled_widgets &= ~(1 << WIDX_TRACK_PREVIEW); } else { @@ -288,10 +283,8 @@ static void window_install_track_invalidate() * * rct2: 0x006D3B1F */ -static void window_install_track_paint() +static void window_install_track_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_widget *widget; rct_track_design *trackDesign = NULL; uint8 *image, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); @@ -300,8 +293,6 @@ static void window_install_track_paint() 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) @@ -311,7 +302,7 @@ static void window_install_track_paint() 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); + colour = ColourMapA[w->colours[0]].darkest; gfx_fill_rect(dpi, x, y, x + 369, y + 216, colour); //call 6d3993 (load track) @@ -336,7 +327,7 @@ static void window_install_track_paint() y = w->y + widget->bottom - 12; RCT2_GLOBAL(0x00F44153, uint8) = 0; - + // Warnings if (track_td6->track_flags & 1) { RCT2_GLOBAL(0x00F44153, uint8) = 1; @@ -356,11 +347,6 @@ static void window_install_track_paint() 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); @@ -467,21 +453,14 @@ static void window_install_track_paint() * * 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) - { +static void window_install_track_text_input(rct_window *w, int widgetIndex, char *text) +{ + if (text == NULL) { window_close(w); return; } - if (widgetIndex == WIDX_INSTALL){ - + if (widgetIndex == WIDX_INSTALL) { char* extension_pointer = track_dest_name; while (*extension_pointer++ != '.'); --extension_pointer; @@ -489,4 +468,4 @@ static void window_install_track_text_input(){ 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 5c5c308f81..f97044bcea 100644 --- a/src/windows/land.c +++ b/src/windows/land.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 . *****************************************************************************/ @@ -28,76 +28,80 @@ #include "dropdown.h" #include "../interface/themes.h" +#define MINIMUM_TOOL_SIZE 1 +#define MAXIMUM_TOOL_SIZE 64 + enum WINDOW_LAND_WIDGET_IDX { WIDX_BACKGROUND, WIDX_TITLE, WIDX_CLOSE, + WIDX_MOUNTAINMODE, + WIDX_PAINTMODE, WIDX_PREVIEW, WIDX_DECREMENT, 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, 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 + { WWT_FRAME, 0, 0, 97, 0, 159, -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_FLATBTN, 1, 19, 42, 19, 42, 5147, STR_ENABLE_MOUNTAIN_TOOL_TIP }, // mountain mode + { WWT_FLATBTN, 1, 55, 78, 19, 42, 5173, 5127 }, // paint mode + + { WWT_IMGBTN, 0, 27, 70, 48, 79, 5503, STR_NONE }, // preview box + { WWT_TRNBTN, 1, 28, 43, 49, 64, 0x20000000 | SPR_LAND_TOOL_DECREASE, STR_ADJUST_SMALLER_LAND_TIP }, // decrement size + { WWT_TRNBTN, 1, 54, 69, 63, 78, 0x20000000 | SPR_LAND_TOOL_INCREASE, STR_ADJUST_LARGER_LAND_TIP }, // increment size + + { WWT_FLATBTN, 1, 2, 48, 106, 141, 0xFFFFFFFF, STR_CHANGE_BASE_LAND_TIP }, // floor texture + { WWT_FLATBTN, 1, 49, 95, 106, 141, 0xFFFFFFFF, STR_CHANGE_VERTICAL_LAND_TIP }, // wall texture { WIDGETS_END }, }; -static void window_land_emptysub() { } -static void window_land_close(); -static void window_land_mouseup(); +static void window_land_close(rct_window *w); +static void window_land_mouseup(rct_window *w, int widgetIndex); static void window_land_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_land_dropdown(); +static void window_land_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); 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_invalidate(rct_window *w); +static void window_land_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_land_textinput(rct_window *w, int widgetIndex, char *text); static void window_land_inputsize(rct_window *w); - -static void* window_land_events[] = { +static rct_window_event_list window_land_events = { window_land_close, window_land_mouseup, - window_land_emptysub, + NULL, window_land_mousedown, window_land_dropdown, - window_land_emptysub, + NULL, window_land_update, - window_land_emptysub, - window_land_emptysub, - window_land_emptysub, - window_land_emptysub, - window_land_emptysub, - window_land_emptysub, - window_land_emptysub, - window_land_emptysub, - window_land_emptysub, - window_land_emptysub, - window_land_emptysub, - window_land_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_land_textinput, - window_land_emptysub, - window_land_emptysub, - window_land_emptysub, - window_land_emptysub, - window_land_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, window_land_invalidate, window_land_paint, - window_land_emptysub + NULL }; -static int window_land_should_close(); - 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, @@ -129,7 +133,7 @@ void window_land_open() if (window_find_by_class(WC_LAND) != NULL) return; - window = window_create(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - 98, 29, 98, 126, (uint32*)window_land_events, WC_LAND, 0); + window = window_create(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 98, 29, 98, 160, &window_land_events, WC_LAND, 0); window->widgets = window_land_widgets; window->enabled_widgets = (1 << WIDX_CLOSE) | @@ -137,6 +141,7 @@ void window_land_open() (1 << WIDX_INCREMENT) | (1 << WIDX_FLOOR) | (1 << WIDX_WALL) | + (1 << WIDX_MOUNTAINMODE) | (1 << WIDX_PAINTMODE) | (1 << WIDX_PREVIEW); window_init_scroll_widgets(window); @@ -144,7 +149,8 @@ void window_land_open() RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) = 255; RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) = 255; - LandPaintMode = false; + gLandMountainMode = false; + gLandPaintMode = false; _selectedFloorTexture = 0; _selectedWallTexture = 0; RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, money32) = MONEY32_UNDEFINED; @@ -155,10 +161,10 @@ void window_land_open() * * rct2: 0x006640A5 */ -static void window_land_close() +static void window_land_close(rct_window *w) { // If the tool wasn't changed, turn tool off - if (!window_land_should_close()) + if (land_tool_is_active()) tool_cancel(); } @@ -166,48 +172,34 @@ static void window_land_close() * * rct2: 0x00664064 */ -static void window_land_mouseup() +static void window_land_mouseup(rct_window *w, int widgetIndex) { - int limit; - short widgetIndex; - rct_window *w; - - 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)--; - - // FEATURE: minimum size is always 0 - limit = 0; - // limit = (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2 ? 0 : 1); - - if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) < limit) - RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = limit; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = max(MINIMUM_TOOL_SIZE, RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)-1); // Invalidate the window window_invalidate(w); break; case WIDX_INCREMENT: // Increment land tool size - RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)++; - - // FEATURE: maximum size is 64 - limit = 64; - // limit = (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2 ? 7 : 5); - - if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) > limit) - RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = limit; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = min(MAXIMUM_TOOL_SIZE, RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)+1); // Invalidate the window window_invalidate(w); break; + case WIDX_MOUNTAINMODE: + gLandMountainMode ^= 1; + gLandPaintMode = 0; + window_invalidate(w); + break; case WIDX_PAINTMODE: - LandPaintMode ^= 1; + gLandMountainMode = 0; + gLandPaintMode ^= 1; window_invalidate(w); break; case WIDX_PREVIEW: @@ -230,7 +222,7 @@ static void window_land_mousedown(int widgetIndex, rct_window*w, rct_widget* wid gDropdownItemsFormat[i] = -1; gDropdownItemsArgs[i] = SPR_FLOOR_TEXTURE_GRASS + window_land_floor_texture_order[i]; if (window_land_floor_texture_order[i] == _selectedFloorTexture) - RCT2_GLOBAL(0x009DEBA2, sint16) = i; + gDropdownHighlightedIndex = i; } window_dropdown_show_image( w->x + widget->left, w->y + widget->top, @@ -247,7 +239,7 @@ static void window_land_mousedown(int widgetIndex, rct_window*w, rct_widget* wid gDropdownItemsFormat[i] = -1; gDropdownItemsArgs[i] = SPR_WALL_TEXTURE_ROCK + window_land_wall_texture_order[i]; if (window_land_wall_texture_order[i] == _selectedWallTexture) - RCT2_GLOBAL(0x009DEBA2, sint16) = i; + gDropdownHighlightedIndex = i; } window_dropdown_show_image( w->x + widget->left, w->y + widget->top, @@ -269,18 +261,14 @@ static void window_land_mousedown(int widgetIndex, rct_window*w, rct_widget* wid * * rct2: 0x00664090 */ -static void window_land_dropdown() +static void window_land_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { int type; - short dropdownIndex, widgetIndex; - rct_window *w; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); switch (widgetIndex) { case WIDX_FLOOR: if (dropdownIndex == -1) - dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); + dropdownIndex = gDropdownHighlightedIndex; type = (dropdownIndex == -1) ? _selectedFloorTexture : @@ -296,7 +284,7 @@ static void window_land_dropdown() break; case WIDX_WALL: if (dropdownIndex == -1) - dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); + dropdownIndex = gDropdownHighlightedIndex; type = (dropdownIndex == -1) ? _selectedWallTexture : @@ -313,33 +301,28 @@ static void window_land_dropdown() } } -static void window_land_textinput() +static void window_land_textinput(rct_window *w, int widgetIndex, char *text) { - 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) + if (widgetIndex != WIDX_PREVIEW || text == NULL) return; size = strtol(text, &end, 10); if (*end == '\0') { - if (size < 0) size = 0; - if (size > 64) size = 64; + size = max(MINIMUM_TOOL_SIZE,size); + size = min(MAXIMUM_TOOL_SIZE,size); 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; + ((uint16*)TextInputDescriptionArgs)[0] = MINIMUM_TOOL_SIZE; + ((uint16*)TextInputDescriptionArgs)[1] = MAXIMUM_TOOL_SIZE; window_text_input_open(w, WIDX_PREVIEW, 5128, 5129, STR_NONE, STR_NONE, 3); } @@ -349,8 +332,7 @@ static void window_land_inputsize(rct_window *w) */ static void window_land_update(rct_window *w) { - // Close window if another tool is open - if (window_land_should_close()) + if (!land_tool_is_active()) window_close(w); } @@ -358,11 +340,8 @@ static void window_land_update(rct_window *w) * * rct2: 0x00663F20 */ -static void window_land_invalidate() +static void window_land_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); w->pressed_widgets = (1 << WIDX_PREVIEW); @@ -370,11 +349,14 @@ static void window_land_invalidate() 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) + if (gLandMountainMode) + w->pressed_widgets |= (1 << WIDX_MOUNTAINMODE); + if (gLandPaintMode) 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; + // Update the preview image (for tool sizes up to 7) window_land_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; @@ -384,31 +366,27 @@ static void window_land_invalidate() * * rct2: 0x00663F7C */ -static void window_land_paint() +static void window_land_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; int x, y, numTiles; money32 price; - - window_paint_get_registers(w, dpi); + rct_widget *previewWidget = &window_land_widgets[WIDX_PREVIEW]; window_draw_widgets(w, dpi); - x = w->x + (window_land_widgets[WIDX_PREVIEW].left + window_land_widgets[WIDX_PREVIEW].right) / 2; - y = w->y + (window_land_widgets[WIDX_PREVIEW].top + window_land_widgets[WIDX_PREVIEW].bottom) / 2; - - // FEATURE larger land tool size support + // Draw number for tool sizes bigger than 7 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); + x = w->x + (previewWidget->left + previewWidget->right) / 2; + y = w->y + (previewWidget->top + previewWidget->bottom) / 2; + gfx_draw_string_centred(dpi, STR_LAND_TOOL_SIZE_VALUE, x, y - 2, 0, &RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)); + } else if (gLandMountainMode) { + x = w->x + previewWidget->left; + y = w->y + previewWidget->top; + gfx_draw_sprite(dpi, SPR_LAND_TOOL_SIZE_0, x, y, 0); } - 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; + x = w->x + (previewWidget->left + previewWidget->right) / 2; + y = w->y + previewWidget->bottom + 5; // Draw raise cost amount if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, uint32) != MONEY32_UNDEFINED && RCT2_GLOBAL(RCT2_ADDRESS_LAND_RAISE_COST, uint32) != 0) @@ -429,22 +407,7 @@ static void window_land_paint() price += numTiles * 100; if (price != 0 && !(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) { - RCT2_GLOBAL(0x013CE952, sint32) = price; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, sint32) = price; gfx_draw_string_centred(dpi, 986, x, y, 0, (void*)0x013CE952); } } - -/** - * - * rct2: 0x0066D104 - */ -static int window_land_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_TOP_TOOLBAR) - return 1; - if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, sint16) != 7) - return 1; - return 0; -} diff --git a/src/windows/land_rights.c b/src/windows/land_rights.c index 9a81fc3cbb..b59432fee9 100644 --- a/src/windows/land_rights.c +++ b/src/windows/land_rights.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 . *****************************************************************************/ @@ -29,7 +29,8 @@ #include "../game.h" #include "../interface/themes.h" -const int MAX_LAND_RIGHTS_SIZE = 64; +#define MINIMUM_TOOL_SIZE 1 +#define MAXIMUM_TOOL_SIZE 64 enum WINDOW_WATER_WIDGET_IDX { WIDX_BACKGROUND, @@ -56,44 +57,43 @@ static rct_widget window_land_rights_widgets[] = { 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_close(rct_window *w); +static void window_land_rights_mouseup(rct_window *w, int widgetIndex); +static void window_land_rights_update(rct_window *w); +static void window_land_rights_invalidate(rct_window *w); +static void window_land_rights_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_land_rights_textinput(rct_window *w, int widgetIndex, char *text); static void window_land_rights_inputsize(rct_window *w); -static void* window_land_rights_events[] = { +static rct_window_event_list 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, + NULL, + NULL, + NULL, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_land_rights_textinput, - window_land_rights_emptysub, - window_land_rights_emptysub, - window_land_rights_emptysub, - window_land_rights_emptysub, - window_land_rights_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, window_land_rights_invalidate, window_land_rights_paint, - window_land_rights_emptysub + NULL }; void window_land_rights_open() @@ -104,7 +104,7 @@ void window_land_rights_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 = window_create(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 98, 29, 98, 94, &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); @@ -120,47 +120,29 @@ void window_land_rights_open() show_land_rights(); } -static void window_land_rights_close() +static void window_land_rights_close(rct_window *w) { - //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() +static void window_land_rights_mouseup(rct_window *w, int widgetIndex) { - 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; + // Decrement land rights tool size + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = max(MINIMUM_TOOL_SIZE, RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)-1); // 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; + // Decrement land rights tool size + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = min(MAXIMUM_TOOL_SIZE, RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)+1); // Invalidate the window window_invalidate(w); @@ -187,24 +169,18 @@ static void window_land_rights_mouseup() } } -static void window_land_rights_textinput() +static void window_land_rights_textinput(rct_window *w, int widgetIndex, char *text) { - 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) + if (widgetIndex != WIDX_PREVIEW || text == NULL) 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; + size = max(MINIMUM_TOOL_SIZE,size); + size = min(MAXIMUM_TOOL_SIZE,size); RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = size; window_invalidate(w); } @@ -212,8 +188,8 @@ static void window_land_rights_textinput() static void window_land_rights_inputsize(rct_window *w) { - ((uint16*)TextInputDescriptionArgs)[0] = 1; - ((uint16*)TextInputDescriptionArgs)[1] = MAX_LAND_RIGHTS_SIZE; + ((uint16*)TextInputDescriptionArgs)[0] = MINIMUM_TOOL_SIZE; + ((uint16*)TextInputDescriptionArgs)[1] = MAXIMUM_TOOL_SIZE; window_text_input_open(w, WIDX_PREVIEW, 5128, 5129, STR_NONE, STR_NONE, 3); } @@ -224,11 +200,8 @@ static void window_land_rights_update(rct_window *w) window_close(w); } -static void window_land_rights_invalidate() +static void window_land_rights_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); // Set the preview image button to be pressed down @@ -241,25 +214,17 @@ static void window_land_rights_invalidate() 0xFFFFFFFF; } -static void window_land_rights_paint() +static void window_land_rights_paint(rct_window *w, rct_drawpixelinfo *dpi) { - 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 + // Draw number for tool sizes bigger than 7 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); + gfx_draw_string_centred(dpi, STR_LAND_TOOL_SIZE_VALUE, x, y - 2, 0, &RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)); } y = w->y + window_land_rights_widgets[WIDX_PREVIEW].bottom + 5; diff --git a/src/windows/loadsave.c b/src/windows/loadsave.c index 63228e7153..d9d9b5a3f4 100644 --- a/src/windows/loadsave.c +++ b/src/windows/loadsave.c @@ -18,6 +18,7 @@ * along with this program. If not, see . *****************************************************************************/ +#include #include "../addresses.h" #include "../config.h" #include "../game.h" @@ -25,10 +26,12 @@ #include "../interface/widget.h" #include "../interface/window.h" #include "../localisation/localisation.h" +#include "../network/network.h" #include "../scenario.h" #include "../title.h" #include "../windows/error.h" #include "../interface/themes.h" +#include "../interface/title_sequences.h" #include "../util/util.h" #pragma region Widgets @@ -40,17 +43,25 @@ enum { WIDX_BACKGROUND, WIDX_TITLE, WIDX_CLOSE, + WIDX_UP, + WIDX_NEW, + WIDX_SORT_NAME, + WIDX_SORT_DATE, 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 + { 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 }, //Window close button + { WWT_CLOSEBOX, 0, 4, 104, 36, 47, 2718, STR_NONE}, // Up + { WWT_CLOSEBOX, 0, 105, 205, 36, 47, 2719, STR_NONE}, // New + { WWT_CLOSEBOX, 0, 4, (WW - 5) / 2, 50, 61, STR_NONE, STR_NONE }, // Name + { WWT_CLOSEBOX, 0, (WW - 5) / 2 + 1, WW - 5 - 1, 50, 61, STR_NONE, STR_NONE }, // Date + { WWT_SCROLL, 0, 4, WW - 5, 61, WH - 40, 2, STR_NONE }, // File list + { WWT_CLOSEBOX, 0, 4, 200, WH - 36, WH - 18, 2707, STR_NONE }, // Use native browser { WIDGETS_END } }; @@ -58,45 +69,44 @@ static rct_widget window_loadsave_widgets[] = { #pragma region Events -void window_loadsave_emptysub() { } -static void window_loadsave_close(); -static void window_loadsave_mouseup(); +static void window_loadsave_close(rct_window *w); +static void window_loadsave_mouseup(rct_window *w, int widgetIndex); 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_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_loadsave_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_loadsave_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_loadsave_textinput(rct_window *w, int widgetIndex, char *text); +static void window_loadsave_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_loadsave_invalidate(rct_window *w); +static void window_loadsave_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_loadsave_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void* window_loadsave_events[] = { +static rct_window_event_list 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_loadsave_scrollgetsize, window_loadsave_scrollmousedown, - window_loadsave_emptysub, + NULL, window_loadsave_scrollmouseover, window_loadsave_textinput, - window_loadsave_emptysub, - window_loadsave_emptysub, + NULL, + NULL, window_loadsave_tooltip, - window_loadsave_emptysub, - window_loadsave_emptysub, + NULL, + NULL, window_loadsave_invalidate, window_loadsave_paint, window_loadsave_scrollpaint @@ -104,46 +114,67 @@ static void* window_loadsave_events[] = { #pragma endregion +enum { + TYPE_DIRECTORY, + TYPE_FILE, +}; + typedef struct { char name[256]; char path[MAX_PATH]; + time_t date_modified; + uint8 type; } loadsave_list_item; +modal_callback gLoadSaveCallback; + int _listItemsCount = 0; loadsave_list_item *_listItems = NULL; char _directory[MAX_PATH]; +char _shortenedDirectory[MAX_PATH]; +static char _parentDirectory[MAX_PATH]; char _extension[32]; -char *_defaultName = NULL; +char _defaultName[MAX_PATH]; int _loadsaveType; int _type; -static void window_loadsave_populate_list(int includeNewItem, bool browsable, const char *directory, const char *extension); +static void window_loadsave_populate_list(rct_window *w, int includeNewItem, const char *directory, const char *extension); static void window_loadsave_select(rct_window *w, const char *path); +static void window_loadsave_sort_list(int index, int endIndex); static int has_extension(char *path, char *extension); +static void shorten_path(char* path, char* buffer, int available_width); + static rct_window *window_overwrite_prompt_open(const char *name, const char *path); rct_window *window_loadsave_open(int type, char *defaultName) { + gLoadSaveCallback = NULL; + gLoadSaveTitleSequenceSave = false; char path[MAX_PATH], *ch; int includeNewItem; rct_window* w; _type = type; - _defaultName = defaultName; + _defaultName[0] = 0; + + if (!str_is_null_or_empty(defaultName)) { + safe_strncpy(_defaultName, path_get_filename(defaultName), sizeof(_defaultName)); + path_remove_extension(_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 = window_create_centred(WW, WH, &window_loadsave_events, WC_LOADSAVE, WF_STICK_TO_FRONT); w->widgets = window_loadsave_widgets; - w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_BROWSE); + w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_UP) | (1 << WIDX_NEW) | (1 << WIDX_SORT_NAME) | (1 << WIDX_SORT_DATE) | (1 << WIDX_BROWSE); w->colours[0] = 7; w->colours[1] = 7; w->colours[2] = 7; } _loadsaveType = type; - switch (type) { + switch (type & 0x0F) { case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME): w->widgets[WIDX_TITLE].image = STR_LOAD_GAME; break; @@ -167,8 +198,8 @@ rct_window *window_loadsave_open(int type, char *defaultName) w->no_list_items = 0; w->selected_list_item = -1; - includeNewItem = (type & 1) == LOADSAVETYPE_SAVE; - switch (type & 6) { + includeNewItem = (type & 0x01) == LOADSAVETYPE_SAVE; + switch (type & 0x0E) { case LOADSAVETYPE_GAME: platform_get_user_directory(path, "save"); if (!platform_ensure_directory_exists(path)) { @@ -177,7 +208,7 @@ rct_window *window_loadsave_open(int type, char *defaultName) return NULL; } - window_loadsave_populate_list(includeNewItem, TRUE, path, ".sv6"); + window_loadsave_populate_list(w, includeNewItem, path, ".sv6"); break; case LOADSAVETYPE_LANDSCAPE: platform_get_user_directory(path, "landscape"); @@ -187,7 +218,7 @@ rct_window *window_loadsave_open(int type, char *defaultName) return NULL; } - window_loadsave_populate_list(includeNewItem, TRUE, path, ".sc6"); + window_loadsave_populate_list(w, includeNewItem, path, ".sc6"); break; case LOADSAVETYPE_SCENARIO: /* @@ -201,12 +232,12 @@ rct_window *window_loadsave_open(int type, char *defaultName) } */ - strcpy(path, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char)); + safe_strncpy(path, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), MAX_PATH); ch = strchr(path, '*'); if (ch != NULL) *ch = 0; - window_loadsave_populate_list(includeNewItem, TRUE, path, ".sc6"); + window_loadsave_populate_list(w, includeNewItem, path, ".sc6"); break; case LOADSAVETYPE_TRACK: /* @@ -220,12 +251,12 @@ rct_window *window_loadsave_open(int type, char *defaultName) } */ - strcpy(path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char)); + safe_strncpy(path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), MAX_PATH); ch = strchr(path, '*'); if (ch != NULL) *ch = 0; - window_loadsave_populate_list(includeNewItem, TRUE, path, ".td?"); + window_loadsave_populate_list(w, includeNewItem, path, ".td?"); break; } w->no_list_items = _listItemsCount; @@ -233,7 +264,7 @@ rct_window *window_loadsave_open(int type, char *defaultName) return w; } -static void window_loadsave_close() +static void window_loadsave_close(rct_window *w) { if (_listItems != NULL) { free(_listItems); @@ -243,26 +274,43 @@ static void window_loadsave_close() window_close_by_class(WC_LOADSAVE_OVERWRITE_PROMPT); } -static void window_loadsave_mouseup() +static void window_loadsave_mouseup(rct_window *w, int widgetIndex) { - 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_UP: + { + char directory[MAX_PATH]; + int includeNewItem = (_type & 1) == LOADSAVETYPE_SAVE; + + safe_strncpy(directory, _parentDirectory, sizeof(directory)); + window_loadsave_populate_list(w, includeNewItem, directory, _extension); + window_init_scroll_widgets(w); + w->no_list_items = _listItemsCount; + break; + } + case WIDX_NEW: + { + rct_string_id templateStringId = 3165; + char *templateString; + + templateString = (char *)language_get_string(templateStringId); + strcpy(templateString, _defaultName); + window_text_input_open(w, WIDX_NEW, STR_NONE, 2710, templateStringId, 0, 64); + break; + } case WIDX_BROWSE: - strcpy(filename, _directory); + safe_strncpy(filename, _directory, MAX_PATH); if (_type & LOADSAVETYPE_SAVE) strcat(filename, (char*)RCT2_ADDRESS_SCENARIO_NAME); memset(filter, '\0', MAX_PATH); - strncpy(filter, "*", MAX_PATH); + safe_strncpy(filter, "*", MAX_PATH); strncat(filter, _extension, MAX_PATH); switch (_type) { @@ -293,6 +341,26 @@ static void window_loadsave_mouseup() window_loadsave_select(w, filename); } break; + case WIDX_SORT_NAME: + if (gConfigGeneral.load_save_sort == SORT_NAME_ASCENDING){ + gConfigGeneral.load_save_sort = SORT_NAME_DESCENDING; + } else { + gConfigGeneral.load_save_sort = SORT_NAME_ASCENDING; + } + config_save_default(); + window_loadsave_sort_list(0, _listItemsCount - 1); + window_invalidate(w); + break; + case WIDX_SORT_DATE: + if (gConfigGeneral.load_save_sort == SORT_DATE_DESCENDING){ + gConfigGeneral.load_save_sort = SORT_DATE_ASCENDING; + } else { + gConfigGeneral.load_save_sort = SORT_DATE_DESCENDING; + } + config_save_default(); + window_loadsave_sort_list(0, _listItemsCount - 1); + window_invalidate(w); + break; } } @@ -307,104 +375,82 @@ static int has_extension(char *path, char *extension) return 1; } -static void window_loadsave_update(rct_window *w) +static void window_loadsave_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - + *height = w->no_list_items * 10; } -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() +static void window_loadsave_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) { 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; + if (_listItems[selectedItem].type == TYPE_DIRECTORY){ + // The selected item is a folder + int includeNewItem; - // Load or overwrite - if (_listItems[selectedItem].path[0] == 0) { - rct_string_id templateStringId = 3165; - char *templateString; + w->no_list_items = 0; + w->selected_list_item = -1; + includeNewItem = (_type & 1) == LOADSAVETYPE_SAVE; - templateString = (char*)language_get_string(templateStringId); - strcpy(templateString, _defaultName); + char directory[MAX_PATH]; + safe_strncpy(directory, _listItems[selectedItem].path, sizeof(directory)); - window_text_input_open(w, WIDX_SCROLL, STR_NONE, 2710, templateStringId, 0, 64); + window_loadsave_populate_list(w, includeNewItem, directory, _extension); + window_init_scroll_widgets(w); + + w->no_list_items = _listItemsCount; } 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); - } + // TYPE_FILE + // Load or overwrite + if ((_loadsaveType & 0x01) == 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() +static void window_loadsave_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) { 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() +static void window_loadsave_textinput(rct_window *w, int widgetIndex, char *text) { - rct_window *w; - short widgetIndex; - uint8 result; - char *text, path[MAX_PATH]; + char path[MAX_PATH]; int i, overwrite; - window_textinput_get_registers(w, widgetIndex, result, text); - - if (!result || text[0] == 0) + if (text == NULL || text[0] == 0) return; - strncpy(path, _directory, sizeof(path)); - strncat(path, text, sizeof(path)); - strncat(path, _extension, sizeof(path)); + if (gLoadSaveTitleSequenceSave) { + if (filename_valid_characters(text)) { + if (!title_sequence_save_exists(gCurrentTitleSequence, text)) { + title_sequence_add_save(gCurrentTitleSequence, path, text); + } + else { + window_error_open(5404, STR_NONE); + } + } + else { + window_error_open(5243, STR_NONE); + } + return; + } + + safe_strncpy(path, _directory, sizeof(path)); + strncat(path, text, sizeof(path) - strnlen(path, MAX_PATH) - 1); + strncat(path, _extension, sizeof(path) - strnlen(path, MAX_PATH) - 1); overwrite = 0; for (i = 0; i < _listItemsCount; i++) { @@ -420,54 +466,99 @@ static void window_loadsave_textinput() window_loadsave_select(w, path); } -static void window_loadsave_tooltip() +static void window_loadsave_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) { - RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = STR_LIST; } -static void window_loadsave_invalidate() +static void window_loadsave_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); } -static void window_loadsave_paint() +static void window_loadsave_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); - char buffer[256]; + if (_shortenedDirectory[0] == '\0') + shorten_path(_directory, _shortenedDirectory, w->width - 8); + + utf8 buffer[256]; + // Format text - sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_BLACK, _directory); + utf8 *ch = buffer; + ch = utf8_write_codepoint(ch, FORMAT_MEDIUMFONT); + ch = utf8_write_codepoint(ch, FORMAT_BLACK); + safe_strncpy(ch, _shortenedDirectory, sizeof(buffer) - (ch - buffer)); + // Draw shadow gfx_draw_string(dpi, buffer, 0, w->x + 4, w->y + 20); - + rct_string_id id = STR_NONE; + // Name button text + if (gConfigGeneral.load_save_sort == SORT_NAME_ASCENDING) + id = STR_UP; + else if (gConfigGeneral.load_save_sort == SORT_NAME_DESCENDING) + id = STR_DOWN; + gfx_draw_string_centred_clipped(dpi, STR_NAME, &id, 1, w->x + 4 + (w->width - 8) / 4, w->y + 50, (w->width - 8) / 2); + // Date button text + if (gConfigGeneral.load_save_sort == SORT_DATE_ASCENDING) + id = STR_UP; + else if (gConfigGeneral.load_save_sort == SORT_DATE_DESCENDING) + id = STR_DOWN; + else + id = STR_NONE; + gfx_draw_string_centred_clipped(dpi, STR_DATE, &id, 1, w->x + 4 + (w->width - 8) * 3 / 4, w->y + 50, (w->width - 8) / 2); } -static void window_loadsave_scrollpaint() +static void shorten_path(char* path, char* buffer, int available_width){ + int length = strlen(path); + + // Return full string if it fits + if (gfx_get_string_width(path) <= available_width){ + strcpy(buffer, path); + return; + } + + // Count path separators + int path_separators = 0; + for (int x = 0; x < length; x++) + if (path[x] == platform_get_path_separator()) + path_separators++; + + // TODO: Replace with unicode ellipsis when supported + strcpy(buffer, "..."); + + // Abreviate beginning with xth separator + + int begin = -1; + for (int x = 0; x < path_separators; x++){ + do { + begin++; + } while (path[begin] != platform_get_path_separator()); + + strcpy(buffer + 3, path + begin); + if (gfx_get_string_width(buffer) <= available_width) + return; + } + + strcpy(buffer, path); + return; +} + +static void window_loadsave_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { 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, ColourMapA[w->colours[1]].mid_light); - 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; @@ -482,12 +573,35 @@ static void window_loadsave_scrollpaint() } } +static int compare_string_case_insensitive(char const *a, char const *b) +{ + for (;; a++, b++) { + int d = tolower(*a) - tolower(*b); + if (d != 0 || !*a) + return d; + } +} + 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); + if (itemA->type != itemB->type) + return itemA->type - itemB->type; + + switch (gConfigGeneral.load_save_sort){ + case SORT_NAME_ASCENDING: + return compare_string_case_insensitive(itemA->name, itemB->name); + case SORT_NAME_DESCENDING: + return -compare_string_case_insensitive(itemA->name, itemB->name); + case SORT_DATE_DESCENDING: + return (int) -difftime(itemA->date_modified, itemB->date_modified); + case SORT_DATE_ASCENDING: + return (int) difftime(itemA->date_modified, itemB->date_modified); + default: + return compare_string_case_insensitive(itemA->name, itemB->name); + } } static void window_loadsave_sort_list(int index, int endIndex) @@ -499,176 +613,259 @@ static void window_loadsave_sort_list(int index, int endIndex) 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) +static void window_loadsave_populate_list(rct_window *w, int includeNewItem, const char *directory, const char *extension) { - int i, listItemCapacity, fileEnumHandle; - file_info fileInfo; + int i; + int sortStartIndex = 0; + int listItemCapacity = 8; loadsave_list_item *listItem; - const char *src; - char *dst, filter[MAX_PATH], subDir[MAX_PATH]; + char filter[MAX_PATH]; + + safe_strncpy(_directory, directory, sizeof(_directory)); + if (_extension != extension) { + safe_strncpy(_extension, extension, sizeof(_extension)); + _extension[sizeof(_extension) - 1] = '\0'; + } + _shortenedDirectory[0] = '\0'; - strncpy(_directory, directory, sizeof(_directory)); - strncpy(_extension, extension, sizeof(_extension)); - - strncpy(filter, directory, sizeof(filter)); - strncat(filter, "*", sizeof(filter)); - strncat(filter, extension, sizeof(filter)); + safe_strncpy(filter, directory, sizeof(filter)); + strncat(filter, "*", sizeof(filter) - strnlen(filter, MAX_PATH) - 1); + strncat(filter, extension, sizeof(filter) - strnlen(filter, MAX_PATH) - 1); if (_listItems != NULL) free(_listItems); - - listItemCapacity = 8; _listItems = (loadsave_list_item*)malloc(listItemCapacity * sizeof(loadsave_list_item)); _listItemsCount = 0; + + window_loadsave_widgets[WIDX_NEW].type = includeNewItem?WWT_CLOSEBOX:WWT_EMPTY; // Hide/Show "new" button + if(directory[0]=='\0' && platform_get_drives()!=0) // List Windows drives + { + w->disabled_widgets |= (1<= 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 (platform_get_drives() & (1 << (x))){ + listItem = &_listItems[_listItemsCount]; + memset(listItem->path, '\0', MAX_PATH); + listItem->path[0] = 'A' + x; + listItem->path[1] = ':'; + listItem->path[2] = platform_get_path_separator(); + strcpy(listItem->name, listItem->path); + listItem->type = TYPE_DIRECTORY; + _listItemsCount++; } } - if (!topLevel){ + } + else + { + //Get parent directory + int directoryLength = strlen(directory); + char separator = platform_get_path_separator(); + for(i = directoryLength-2; i>=0; i--) + { + if(directory[i]==separator) + break; + } + safe_strncpy(_parentDirectory, directory, sizeof(_parentDirectory)); + _parentDirectory[i+1] = '\0'; + if(_parentDirectory[0]=='\0' && platform_get_drives()==0) + w->disabled_widgets |= (1<disabled_widgets &= ~(1<disabled_widgets &= ~(1<name, language_get_string(2718), sizeof(listItem->name)); memset(listItem->path, '\0', MAX_PATH); - strncpy(listItem->path, directory, lastSlash + 1); + safe_strncpy(listItem->path, directory, MAX_PATH); + strncat(listItem->path, subDir, MAX_PATH); + safe_strncpy(listItem->name, subDir, sizeof(listItem->name)); + listItem->type = TYPE_DIRECTORY; _listItemsCount++; } - } + platform_enumerate_files_end(fileEnumHandle); + window_loadsave_sort_list(sortStartIndex, _listItemsCount - 1); - if (includeNewItem) { - listItem = &_listItems[_listItemsCount]; - strncpy(listItem->name, language_get_string(2719), sizeof(listItem->name)); - listItem->path[0] = 0; - _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)); + } - 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]; + safe_strncpy(listItem->path, directory, sizeof(listItem->path)); + strncat(listItem->path, fileInfo.path, sizeof(listItem->path)); + listItem->type = TYPE_FILE; + listItem->date_modified = platform_file_get_modified_time(listItem->path); + + src = fileInfo.path; + dst = listItem->name; + last_dot_in_filename = strrchr(fileInfo.path, '.'); + assert(last_dot_in_filename != NULL); + i = 0; + while (src < last_dot_in_filename && i < sizeof(listItem->name) - 1) { + *dst++ = *src++; + i++; + } + *dst = '\0'; + + _listItemsCount++; } - - 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); } - 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++; +static void window_loadsave_invoke_callback(int result) +{ + if (gLoadSaveCallback != NULL) { + gLoadSaveCallback(result); } - 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) { + SDL_RWops* rw; + switch (_loadsaveType & 0x0F) { case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME) : - if (game_load_save(path)) { - window_close(w); - gfx_invalidate_screen(); - rct2_endupdate(); + if (gLoadSaveTitleSequenceSave) { + utf8 newName[MAX_PATH]; + char *extension = (char*)path_get_extension(path_get_filename(path)); + safe_strncpy(newName, path_get_filename(path), MAX_PATH); + if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) + strcat(newName, ".sv6"); + if (title_sequence_save_exists(gCurrentTitleSequence, newName)) { + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&_listItems[w->selected_list_item].name; + window_text_input_open(w, WIDX_SCROLL, 5435, 5404, 1170, (uint32)_listItems[w->selected_list_item].name, TITLE_SEQUENCE_MAX_SAVE_LENGTH - 1); } 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)) { + title_sequence_add_save(gCurrentTitleSequence, path, newName); window_close(w); + } + window_loadsave_invoke_callback(MODAL_RESULT_OK); + } + else if (game_load_save(path)) { + if (_loadsaveType & LOADSAVETYPE_NETWORK) { + network_begin_server(gConfigNetwork.default_port); + } - 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; + safe_strncpy(gScenarioSavePath, path, MAX_PATH); + gFirstTimeSave = 0; - if (success) { - window_close(w); - title_load(); - } - else { - window_error_open(STR_SAVE_SCENARIO, STR_SCENARIO_SAVE_FAILED); - s6Info->var_000 = 4; - } + window_close(w); + gfx_invalidate_screen(); + window_loadsave_invoke_callback(MODAL_RESULT_OK); + rct2_endupdate(); + } + else { + // 1050, not the best message... + window_error_open(STR_LOAD_GAME, 1050); + window_loadsave_invoke_callback(MODAL_RESULT_FAIL); } break; - case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) : - window_install_track_open(path); - window_close_by_class(WC_LOADSAVE); - break; + case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) : + rw = SDL_RWFromFile(path, "wb+"); + if (rw != NULL) { + int success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 1 : 0); + SDL_RWclose(rw); + if (success) { + + safe_strncpy(gScenarioSavePath, path, MAX_PATH); + gFirstTimeSave = 0; + + window_close_by_class(WC_LOADSAVE); + game_do_command(0, 1047, 0, -1, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0); + gfx_invalidate_screen(); + + window_loadsave_invoke_callback(MODAL_RESULT_OK); + } else { + window_error_open(STR_SAVE_GAME, 1047); + window_loadsave_invoke_callback(MODAL_RESULT_FAIL); + } + } else { + window_error_open(STR_SAVE_GAME, 1047); + window_loadsave_invoke_callback(MODAL_RESULT_FAIL); } + break; + case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) : + editor_load_landscape(path); + if (1) { + gfx_invalidate_screen(); + window_loadsave_invoke_callback(MODAL_RESULT_OK); + rct2_endupdate(); + } + else { + // 1050, not the best message... + window_error_open(STR_LOAD_LANDSCAPE, 1050); + window_loadsave_invoke_callback(MODAL_RESULT_FAIL); + } + break; + case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) : + rw = SDL_RWFromFile(path, "wb+"); + if (rw != NULL) { + scenario_set_filename(path); + int success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2); + SDL_RWclose(rw); + if (success) { + window_close_by_class(WC_LOADSAVE); + gfx_invalidate_screen(); + window_loadsave_invoke_callback(MODAL_RESULT_OK); + } else { + window_error_open(STR_SAVE_LANDSCAPE, 1049); + window_loadsave_invoke_callback(MODAL_RESULT_FAIL); + } + } else { + window_error_open(STR_SAVE_LANDSCAPE, 1049); + window_loadsave_invoke_callback(MODAL_RESULT_FAIL); + } + 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->editor_step = 255; + rw = SDL_RWFromFile(path, "wb+"); + int success = 0; + if (rw != NULL) { + scenario_set_filename(path); + success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2); + SDL_RWclose(rw); + } + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = parkFlagsBackup; + + if (success) { + window_close_by_class(WC_LOADSAVE); + window_loadsave_invoke_callback(MODAL_RESULT_OK); + title_load(); + } else { + window_error_open(STR_SAVE_SCENARIO, STR_SCENARIO_SAVE_FAILED); + s6Info->editor_step = EDITOR_STEP_OBJECTIVE_SELECTION; + window_loadsave_invoke_callback(MODAL_RESULT_FAIL); + } + break; + } + case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) : + window_install_track_open(path); + window_close_by_class(WC_LOADSAVE); + window_loadsave_invoke_callback(MODAL_RESULT_OK); + break; + } } #pragma region Overwrite prompt @@ -693,40 +890,39 @@ static rct_widget window_overwrite_prompt_widgets[] = { { 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_mouseup(rct_window *w, int widgetIndex); +static void window_overwrite_prompt_invalidate(rct_window *w); +static void window_overwrite_prompt_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void* window_overwrite_prompt_events[] = { - window_overwrite_prompt_emptysub, +static rct_window_event_list window_overwrite_prompt_events = { + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_overwrite_prompt_invalidate, window_overwrite_prompt_paint, - window_overwrite_prompt_emptysub + NULL }; static char _window_overwrite_prompt_name[256]; @@ -738,54 +934,46 @@ static rct_window *window_overwrite_prompt_open(const char *name, const char *pa 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 = window_create_centred(OVERWRITE_WW, OVERWRITE_WH, &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)); + safe_strncpy(_window_overwrite_prompt_name, name, sizeof(_window_overwrite_prompt_name)); + safe_strncpy(_window_overwrite_prompt_path, path, sizeof(_window_overwrite_prompt_path)); return w; } -static void window_overwrite_prompt_mouseup() +static void window_overwrite_prompt_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w, *loadsaveWindow; + rct_window *loadsaveWindow; - window_widget_get_registers(w, widgetIndex); - - switch (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); + // As the window_loadsave_select function can change the order of the + // windows we can't use window_close(w). + window_close_by_class(WC_LOADSAVE_OVERWRITE_PROMPT); break; case WIDX_OVERWRITE_CANCEL: case WIDX_OVERWRITE_CLOSE: window_close(w); + break; } } -static void window_overwrite_prompt_invalidate() +static void window_overwrite_prompt_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); } -static void window_overwrite_prompt_paint() +static void window_overwrite_prompt_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); rct_string_id templateStringId = 3165; diff --git a/src/windows/main.c b/src/windows/main.c index f56303b4c6..e1bdf08aa8 100644 --- a/src/windows/main.c +++ b/src/windows/main.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 . *****************************************************************************/ @@ -28,38 +28,37 @@ rct_widget window_main_widgets[] = { { WIDGETS_END }, }; -void window_main_empty(){} -void window_main_paint(); +void window_main_paint(rct_window *w, rct_drawpixelinfo *dpi); -void* window_main_events[] = { - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, - window_main_empty, +static rct_window_event_list window_main_events = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_main_paint, - window_main_empty + NULL }; /** @@ -70,12 +69,12 @@ void window_main_open() { rct_window* window; - window_main_widgets[0].right = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16); - window_main_widgets[0].bottom = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16); + window_main_widgets[0].right = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16); + window_main_widgets[0].bottom = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16); window = window_create( 0, 0, window_main_widgets[0].right, window_main_widgets[0].bottom, - (uint32*)window_main_events, + &window_main_events, WC_MAIN_WINDOW, WF_STICK_TO_BACK ); @@ -93,16 +92,11 @@ void window_main_open() /** * - * rct2: 0x66CCAE + * rct2: 0x66CCAE * This function immediately jumps to 0x00685BE1 this is the second function * decompiled. */ -void window_main_paint() +void window_main_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window* w; - rct_drawpixelinfo* dpi; - - window_paint_get_registers(w, dpi); - viewport_render(dpi, w->viewport, dpi->x, dpi->y, dpi->x + dpi->width, dpi->y + dpi->height); } diff --git a/src/windows/map.c b/src/windows/map.c index 4e8e2f9149..b932d36c1b 100644 --- a/src/windows/map.c +++ b/src/windows/map.c @@ -8,27 +8,43 @@ * 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 "../cheats.h" +#include "../game.h" #include "../localisation/localisation.h" #include "../input.h" +#include "../interface/themes.h" #include "../interface/widget.h" #include "../interface/viewport.h" #include "../interface/window.h" #include "../sprites.h" +#include "../world/footpath.h" #include "../world/scenery.h" -#include "../interface/themes.h" -#include "../cheats.h" +#include "error.h" +#define MINIMUM_TOOL_SIZE 1 +#define MAXIMUM_TOOL_SIZE 64 + +#define MINIMUM_MAP_SIZE_TECHNICAL 15 +#define MAXIMUM_MAP_SIZE_TECHNICAL 256 +#define MINIMUM_MAP_SIZE_PRACTICAL MINIMUM_MAP_SIZE_TECHNICAL-2 +#define MAXIMUM_MAP_SIZE_PRACTICAL MAXIMUM_MAP_SIZE_TECHNICAL-2 + +enum { + PAGE_PEEPS, + PAGE_RIDES +}; enum WINDOW_MAP_WIDGET_IDX { WIDX_BACKGROUND, @@ -55,96 +71,118 @@ enum WINDOW_MAP_WIDGET_IDX { }; static rct_widget window_map_widgets[] = { - { WWT_FRAME, 0, 0, 244, 0, 258, STR_NONE, STR_NONE }, - { WWT_CAPTION, 0, 1, 243, 1, 14, STR_MAP, STR_WINDOW_TITLE_TIP }, - { WWT_CLOSEBOX, 0, 232, 242, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, - { WWT_RESIZE, 1, 0, 244, 43, 257, STR_NONE, STR_NONE }, - { WWT_COLORBTN, 1, 3, 33, 17, 43, 0x02000144E, STR_SHOW_PEOPLE_ON_MAP_TIP }, - { WWT_COLORBTN, 1, 34, 64, 17, 43, 0x02000144E, STR_SHOW_RIDES_STALLS_ON_MAP_TIP }, - { WWT_SCROLL, 1, 3, 241, 46, 225, 0x3, STR_NONE }, - { WWT_SPINNER, 1, 104, 198, 229, 240, 0xC8C, STR_NONE }, - { WWT_DROPDOWN_BUTTON, 1, 187, 197, 230, 234, STR_NUMERIC_UP, STR_NONE }, - { WWT_DROPDOWN_BUTTON, 1, 187, 197, 235, 239, STR_NUMERIC_DOWN, STR_NONE }, - { WWT_FLATBTN, 1, 4, 27, 1, 24, SPR_BUY_LAND_RIGHTS, STR_SELECT_PARK_OWNED_LAND_TIP }, - { WWT_FLATBTN, 1, 4, 27, 1, 24, SPR_PARK_ENTRANCE, STR_BUILD_PARK_ENTRANCE_TIP }, - { WWT_FLATBTN, 1, 28, 51, 1, 24, STR_NONE, STR_SET_STARTING_POSITIONS_TIP }, - { WWT_IMGBTN, 1, 4, 47, 17, 48, SPR_LAND_TOOL_SIZE_0, STR_NONE }, - { WWT_TRNBTN, 1, 5, 20, 18, 33, 0x02000157B, STR_ADJUST_SMALLER_LAND_TIP }, - { WWT_TRNBTN, 1, 31, 46, 32, 47, 0x02000157D, STR_ADJUST_LARGER_LAND_TIP }, - { WWT_CHECKBOX, 1, 58, 241, 197, 208, STR_LAND_OWNED, STR_SET_LAND_TO_BE_OWNED_TIP }, - { WWT_CHECKBOX, 1, 58, 241, 197, 208, STR_CONSTRUCTION_RIGHTS_OWNED, STR_SET_CONSTRUCTION_RIGHTS_TO_BE_OWNED_TIP }, - { WWT_CHECKBOX, 1, 58, 241, 197, 208, STR_LAND_SALE, STR_SET_LAND_TO_BE_AVAILABLE_TIP }, - { WWT_CHECKBOX, 1, 58, 231, 197, 208, STR_CONSTRUCTION_RIGHTS_SALE, STR_SET_CONSTRUCTION_RIGHTS_TO_BE_AVAILABLE_TIP }, - { WWT_FLATBTN, 1, 218, 241, 45, 68, SPR_ROTATE_ARROW, STR_ROTATE_OBJECTS_90 }, + { WWT_FRAME, 0, 0, 244, 0, 258, STR_NONE, STR_NONE }, + { WWT_CAPTION, 0, 1, 243, 1, 14, STR_MAP, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 232, 242, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 244, 43, 257, STR_NONE, STR_NONE }, + { WWT_COLORBTN, 1, 3, 33, 17, 43, 0x02000144E, STR_SHOW_PEOPLE_ON_MAP_TIP }, + { WWT_COLORBTN, 1, 34, 64, 17, 43, 0x02000144E, STR_SHOW_RIDES_STALLS_ON_MAP_TIP }, + { WWT_SCROLL, 1, 3, 241, 46, 225, 0x3, STR_NONE }, + { WWT_SPINNER, 1, 104, 198, 229, 240, 0xC8C, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 230, 234, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 235, 239, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_FLATBTN, 1, 4, 27, 1, 24, SPR_BUY_LAND_RIGHTS, STR_SELECT_PARK_OWNED_LAND_TIP }, + { WWT_FLATBTN, 1, 4, 27, 1, 24, SPR_PARK_ENTRANCE, STR_BUILD_PARK_ENTRANCE_TIP }, + { WWT_FLATBTN, 1, 28, 51, 1, 24, STR_NONE, STR_SET_STARTING_POSITIONS_TIP }, + { WWT_IMGBTN, 1, 4, 47, 17, 48, SPR_LAND_TOOL_SIZE_0, STR_NONE }, + { WWT_TRNBTN, 1, 5, 20, 18, 33, 0x02000157B, STR_ADJUST_SMALLER_LAND_TIP }, + { WWT_TRNBTN, 1, 31, 46, 32, 47, 0x02000157D, STR_ADJUST_LARGER_LAND_TIP }, + { WWT_CHECKBOX, 1, 58, 241, 197, 208, STR_LAND_OWNED, STR_SET_LAND_TO_BE_OWNED_TIP }, + { WWT_CHECKBOX, 1, 58, 241, 197, 208, STR_CONSTRUCTION_RIGHTS_OWNED, STR_SET_CONSTRUCTION_RIGHTS_TO_BE_OWNED_TIP }, + { WWT_CHECKBOX, 1, 58, 241, 197, 208, STR_LAND_SALE, STR_SET_LAND_TO_BE_AVAILABLE_TIP }, + { WWT_CHECKBOX, 1, 58, 231, 197, 208, STR_CONSTRUCTION_RIGHTS_SALE, STR_SET_CONSTRUCTION_RIGHTS_TO_BE_AVAILABLE_TIP }, + { WWT_FLATBTN, 1, 218, 241, 45, 68, SPR_ROTATE_ARROW, STR_ROTATE_OBJECTS_90 }, { 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 }; +// rct2: 0x00981BBC +const rct_xy16 MiniMapOffsets[] = { + { 256 - 8, 0 }, + { 512 - 8, 256 }, + { 256 - 8, 512 }, + { 0 - 8, 256 } +}; -static void window_map_emptysub() { } -static void window_map_close(); -static void window_map_resize(); -static void window_map_mouseup(); +static void window_map_close(rct_window *w); +static void window_map_resize(rct_window *w); +static void window_map_mouseup(rct_window *w, int widgetIndex); static void window_map_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); static void window_map_update(rct_window *w); -static void window_map_scrollgetsize(); -static void window_map_scrollmousedown(); -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_toolupdate(rct_window* w, int widgetIndex, int x, int y); +static void window_map_tooldown(rct_window* w, int widgetIndex, int x, int y); +static void window_map_tooldrag(rct_window* w, int widgetIndex, int x, int y); +static void window_map_toolabort(rct_window *w, int widgetIndex); +static void window_map_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_map_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_map_textinput(rct_window *w, int widgetIndex, char *text); +static void window_map_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_map_invalidate(rct_window *w); +static void window_map_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_map_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void window_map_set_bounds(rct_window* w); - -static void window_map_init_map(); -static void window_map_center_on_view_point(); - -static void* window_map_events[] = { +static rct_window_event_list window_map_events = { window_map_close, window_map_mouseup, window_map_resize, window_map_mousedown, - window_map_emptysub, - window_map_emptysub, + NULL, + NULL, window_map_update, - window_map_emptysub, - window_map_emptysub, - (void*)0x0068D093, - (void*)0x0068D074, - (void*)0x0068D088, - window_map_emptysub, - (void*)0x0068D055, - window_map_emptysub, + NULL, + NULL, + window_map_toolupdate, + window_map_tooldown, + window_map_tooldrag, + NULL, + window_map_toolabort, + NULL, window_map_scrollgetsize, window_map_scrollmousedown, window_map_scrollmousedown, - window_map_emptysub, + NULL, window_map_textinput, - window_map_emptysub, - window_map_emptysub, + NULL, + NULL, window_map_tooltip, - window_map_emptysub, - window_map_emptysub, + NULL, + NULL, window_map_invalidate, window_map_paint, window_map_scrollpaint }; + +static void window_map_init_map(); +static void window_map_center_on_view_point(); +static void window_map_show_default_scenario_editor_buttons(rct_window *w); +static void window_map_draw_tab_images(rct_window *w, rct_drawpixelinfo *dpi); +static void window_map_paint_peep_overlay(rct_drawpixelinfo *dpi); +static void window_map_paint_train_overlay(rct_drawpixelinfo *dpi); +static void window_map_paint_hud_rectangle(rct_drawpixelinfo *dpi); +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_set_land_rights_tool_update(int x, int y); +static void window_map_place_park_entrance_tool_update(int x, int y); +static void window_map_set_peep_spawn_tool_update(int x, int y); +static void window_map_place_park_entrance_tool_down(int x, int y); +static void window_map_set_peep_spawn_tool_down(int x, int y); +static void map_window_increase_map_size(); +static void map_window_decrease_map_size(); +static void map_window_set_pixels(rct_window *w); + +static void map_window_screen_to_map(int screenX, int screenY, int *mapX, int *mapY); + /** * * rct2: 0x0068C88A */ void window_map_open() { - rct_window* w; - uint32* map_image_data; + rct_window *w; + uint32 *map_image_data; // Check if window is already open w = window_bring_to_front_by_class(WC_MAP); @@ -154,12 +192,12 @@ void window_map_open() return; } - map_image_data = rct2_malloc(256 * 256 * sizeof(uint32)); + map_image_data = malloc(256 * 256 * sizeof(uint32)); if (map_image_data == NULL) 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, WF_10); + w = window_create_auto_pos(245, 259, &window_map_events, WC_MAP, WF_10); w->widgets = window_map_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | @@ -179,168 +217,122 @@ void window_map_open() (1 << WIDX_BUILD_PARK_ENTRANCE) | (1 << WIDX_ROTATE_90) | (1 << WIDX_PEOPLE_STARTING_POSITION); + w->hold_down_widgets = (1 << WIDX_MAP_SIZE_SPINNER_UP) | (1 << WIDX_MAP_SIZE_SPINNER_DOWN); + window_init_scroll_widgets(w); - w->map.rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint16); + w->map.rotation = get_current_rotation(); window_map_init_map(); RCT2_GLOBAL(0x00F64F05, uint8) = 0; window_map_center_on_view_point(); + + // Reset land tool size + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; } /** * * rct2: 0x0068D0F1 */ -static void window_map_close() +static void window_map_close(rct_window *w) { - rct_window *w; - - window_get_register(w); - - rct2_free(RCT2_GLOBAL(RCT2_ADDRESS_MAP_IMAGE_DATA, uint32*)); + 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_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() + * + * rct2: 0x0068CFC1 + */ +static void window_map_mouseup(rct_window *w, int widgetIndex) { - 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; -} - -/** -* -* rct2: 0x0068CFC1 -*/ -static void window_map_mouseup() -{ - 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) - { + switch (widgetIndex) { case WIDX_CLOSE: - window_close(var_w); + window_close(w); break; - case WIDX_SET_LAND_RIGHTS: - window_invalidate(var_w); - if (tool_set(var_w, var_idx, 2)) // jb nullsub_52 + window_invalidate(w); + if (tool_set(w, widgetIndex, 2)) break; - - RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; RCT2_GLOBAL(0xF1AD61, sint8) = 2; + // Prevent mountain tool tool size. + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = max(MINIMUM_TOOL_SIZE, RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)); show_gridlines(); show_land_rights(); show_construction_rights(); break; - case WIDX_LAND_OWNED_CHECKBOX: RCT2_GLOBAL(0xF1AD61, sint8) ^= 2; if (RCT2_GLOBAL(0xF1AD61, sint8) & 2) RCT2_GLOBAL(0xF1AD61, sint8) &= 0xF2; - window_invalidate(var_w); + window_invalidate(w); break; - case WIDX_LAND_SALE_CHECKBOX: RCT2_GLOBAL(0xF1AD61, sint8) ^= 8; if (RCT2_GLOBAL(0xF1AD61, sint8) & 8) RCT2_GLOBAL(0xF1AD61, sint8) &= 0xF8; - window_invalidate(var_w); + window_invalidate(w); break; - case WIDX_CONSTRUCTION_RIGHTS_OWNED_CHECKBOX: RCT2_GLOBAL(0xF1AD61, sint8) ^= 1; if (RCT2_GLOBAL(0xF1AD61, sint8) & 1) RCT2_GLOBAL(0xF1AD61, sint8) &= 0xF1; - window_invalidate(var_w); + window_invalidate(w); break; - case WIDX_CONSTRUCTION_RIGHTS_SALE_CHECKBOX: RCT2_GLOBAL(0xF1AD61, sint8) ^= 4; if (RCT2_GLOBAL(0xF1AD61, sint8) & 4) RCT2_GLOBAL(0xF1AD61, sint8) &= 0xF4; - window_invalidate(var_w); + window_invalidate(w); break; - case WIDX_LAND_TOOL_SMALLER: - --RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16); - land_tool_limit=1; + // Decrement land ownership tool size + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = max(MINIMUM_TOOL_SIZE, 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); + window_invalidate(w); break; - case WIDX_LAND_TOOL_LARGER: - ++RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16); - land_tool_limit=64; + // Increment land ownership tool size + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = min(MAXIMUM_TOOL_SIZE, 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); + window_invalidate(w); break; - case WIDX_BUILD_PARK_ENTRANCE: - window_invalidate(var_w); - if (tool_set(var_w, var_idx, 2)) // jb nullsub_52 + window_invalidate(w); + if (tool_set(w, widgetIndex, 2)) break; RCT2_GLOBAL(0x9E32D2, sint8) = 0; - - if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, sint32) & INPUT_FLAG_6)) // Remove? - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, sint32) |= INPUT_FLAG_6; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; show_gridlines(); show_land_rights(); show_construction_rights(); break; - case WIDX_ROTATE_90: - ++window_scenery_rotation; - window_scenery_rotation &= 3; + window_scenery_rotation = (window_scenery_rotation + 1) & 3; break; - case WIDX_PEOPLE_STARTING_POSITION: - if (tool_set(var_w, var_idx, 2)) // jb nullsub_52 + if (tool_set(w, widgetIndex, 2)) break; RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 0; - if (RCT2_GLOBAL(RCT2_ADDRESS_PEEP_SPAWNS, sint16) != -1 && RCT2_GLOBAL(0x13573F8, sint16) != -1) RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; @@ -349,190 +341,349 @@ static void window_map_mouseup() show_construction_rights(); break; case WIDX_LAND_TOOL: - window_map_inputsize_land(var_w); + window_map_inputsize_land(w); break; case WIDX_MAP_SIZE_SPINNER: - window_map_inputsize_map(var_w); + window_map_inputsize_map(w); break; - default: - if (var_idx >= WIDX_PEOPLE_TAB && var_idx <= WIDX_RIDES_TAB) - { - var_idx -= WIDX_PEOPLE_TAB; - if (var_idx == var_w->selected_tab) + if (widgetIndex >= WIDX_PEOPLE_TAB && widgetIndex <= WIDX_RIDES_TAB) { + widgetIndex -= WIDX_PEOPLE_TAB; + if (widgetIndex == w->selected_tab) break; - var_w->selected_tab = var_idx; - var_w->list_information_type = 0; + w->selected_tab = widgetIndex; + w->list_information_type = 0; } break; - } - - return; } /** * -* rct2: 0x0068D040 +* rct2: 0x0068D7DC */ -static void window_map_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) +static void window_map_resize(rct_window *w) { - // 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 == 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; + w->flags |= WF_RESIZABLE; + w->min_width = 245; + w->max_width = 800; + w->min_height = 259; + w->max_height = 560; +} + +/** + * + * rct2: 0x0068D040 + */ +static void window_map_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + switch (widgetIndex) { + case WIDX_MAP_SIZE_SPINNER_UP: + map_window_increase_map_size(); + break; + case WIDX_MAP_SIZE_SPINNER_DOWN: + map_window_decrease_map_size(); + break; } } -static void window_map_textinput() +/** + * + * rct2: 0x0068D7FB + */ +static void window_map_update(rct_window *w) +{ + if (get_current_rotation() != w->map.rotation) { + w->map.rotation = get_current_rotation(); + window_map_init_map(); + window_map_center_on_view_point(); + } + + for (int i = 0; i < 16; i++) + map_window_set_pixels(w); + + window_invalidate(w); + + // Update tab animations + w->list_information_type++; + switch (w->selected_tab) { + case PAGE_PEEPS: + if (w->list_information_type >= 32) { + w->list_information_type = 0; + } + break; + case PAGE_RIDES: + if (w->list_information_type >= 64) { + w->list_information_type = 0; + } + break; + } +} + +/** + * + * rct2: 0x0068D093 + */ +static void window_map_toolupdate(rct_window* w, int widgetIndex, int x, int y) +{ + switch (widgetIndex) { + case WIDX_SET_LAND_RIGHTS: + window_map_set_land_rights_tool_update(x, y); + break; + case WIDX_BUILD_PARK_ENTRANCE: + window_map_place_park_entrance_tool_update(x, y); + break; + case WIDX_PEOPLE_STARTING_POSITION: + window_map_set_peep_spawn_tool_update(x, y); + break; + } +} + +/** + * + * rct2: 0x0068D074 + */ +static void window_map_tooldown(rct_window* w, int widgetIndex, int x, int y) +{ + switch (widgetIndex) { + case WIDX_BUILD_PARK_ENTRANCE: + window_map_place_park_entrance_tool_down(x, y); + break; + case WIDX_PEOPLE_STARTING_POSITION: + window_map_set_peep_spawn_tool_down(x, y); + break; + } +} + +/** + * + * rct2: 0x0068D088 + */ +static void window_map_tooldrag(rct_window* w, int widgetIndex, int x, int y) +{ + switch (widgetIndex) { + case WIDX_SET_LAND_RIGHTS: + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & (1 << 0)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 0; + game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16), + GAME_COMMAND_FLAG_APPLY, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16), + RCT2_GLOBAL(0x00F1AD61, uint8), + GAME_COMMAND_SET_LAND_OWNERSHIP, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) + ); + } + break; + } +} + +/** + * + * rct2: 0x0068D055 + */ +static void window_map_toolabort(rct_window *w, int widgetIndex) +{ + switch (widgetIndex) { + case WIDX_SET_LAND_RIGHTS: + window_invalidate(w); + hide_gridlines(); + hide_land_rights(); + hide_construction_rights(); + break; + case WIDX_BUILD_PARK_ENTRANCE: + park_remove_ghost_entrance(); + window_invalidate(w); + hide_gridlines(); + hide_land_rights(); + hide_construction_rights(); + break; + case WIDX_PEOPLE_STARTING_POSITION: + window_invalidate(w); + hide_gridlines(); + hide_land_rights(); + hide_construction_rights(); + break; + } +} + +/** + * + * rct2: 0x0068D7CC + */ +static void window_map_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) +{ + window_map_invalidate(w); + + *width = 512; + *height = 512; +} + +/** + * + * rct2: 0x0068D726 + */ +static void window_map_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) +{ + int mapX, mapY, mapZ; + rct_window *mainWindow; + + map_window_screen_to_map(x, y, &mapX, &mapY); + mapX = clamp(0, mapX, 8191); + mapY = clamp(0, mapY, 8191); + mapZ = map_element_height(x, y); + + mainWindow = window_get_main(); + if (mainWindow != NULL) { + window_scroll_to_location(mainWindow, mapX, mapY, mapZ); + } + + if (land_tool_is_active()) { + // Set land terrain + int landToolSize = max(1, RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, uint16)); + int size = (landToolSize * 32) - 32; + int radius = (landToolSize * 16) - 16; + mapX = (mapX - radius) & 0xFFE0; + mapY = (mapY - radius) & 0xFFE0; + + map_invalidate_selection_rect(); + 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) = mapX; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16) = mapY; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16) = mapX + size; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) = mapY + size; + map_invalidate_selection_rect(); + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_CHANGE_LAND_TYPE; + game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), + GAME_COMMAND_FLAG_APPLY, + 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) + ); + } else if (widget_is_active_tool(w, WIDX_SET_LAND_RIGHTS)) { + // Set land rights + int landToolSize = max(1, RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, uint16)); + int size = (landToolSize * 32) - 32; + int radius = (landToolSize * 16) - 16; + mapX = (mapX - radius) & 0xFFE0; + mapY = (mapY - radius) & 0xFFE0; + + map_invalidate_selection_rect(); + 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) = mapX; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16) = mapY; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16) = mapX + size; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) = mapY + size; + map_invalidate_selection_rect(); + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 0; + game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16), + GAME_COMMAND_FLAG_APPLY, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16), + RCT2_GLOBAL(0x00F1AD61, uint8), + GAME_COMMAND_SET_LAND_OWNERSHIP, + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16), + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) + ); + } +} + +static void window_map_textinput(rct_window *w, int widgetIndex, char *text) { - uint8 result; - short widgetIndex; - rct_window *w; - char *text; int size; char* end; - window_textinput_get_registers(w, widgetIndex, result, text); + if (text == NULL) + return; - 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); - } + switch (widgetIndex) { + case WIDX_LAND_TOOL: + size = strtol(text, &end, 10); + if (*end == '\0') { + size = clamp(MINIMUM_TOOL_SIZE, size, MAXIMUM_TOOL_SIZE); + 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); + break; + case WIDX_MAP_SIZE_SPINNER: + size = strtol(text, &end, 10); + if (*end == '\0') { + // The practical size is 2 lower than the technical size + size += 2; + size=clamp(MINIMUM_MAP_SIZE_TECHNICAL, size, MAXIMUM_MAP_SIZE_TECHNICAL); + + int currentSize = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16); + while (size < currentSize) { + map_window_decrease_map_size(); + currentSize--; } + while (size > currentSize) { + map_window_increase_map_size(); + currentSize++; + } + window_invalidate(w); } + break; } } -static void window_map_inputsize_land(rct_window *w) +/* + * + * rct2: 0x0068D140 + */ +static void window_map_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) { - ((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); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, short) = 3157; } /** -* -* rct2: 0x0068D7FB -*/ -static void window_map_update(rct_window *w) + * + * rct2: 0x0068CA8F + */ +static void window_map_invalidate(rct_window *w) { - RCT2_CALLPROC_X(0x0068D7FB, 0, 0, 0, 0, (int)w, 0, 0); -} - -/** -* -* rct2: 0x0068D7CC -*/ -static void window_map_scrollgetsize() -{ - int width, height; - - window_map_invalidate(); - - width = 512; - height = 512; - window_scrollsize_set_registers(width, height); -} - -/** -* -* rct2: 0x0068D726 -*/ -static void window_map_scrollmousedown() -{ - 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); -} - -/** -* -* rct2: 0x0068CD35 (part of 0x0068CA8F) -*/ -static void window_map_show_default_scenario_editor_buttons(rct_window *mapWindow) { - mapWindow->widgets[WIDX_BUILD_PARK_ENTRANCE].type = WWT_FLATBTN; - mapWindow->widgets[WIDX_PEOPLE_STARTING_POSITION].type = WWT_FLATBTN; - mapWindow->widgets[WIDX_MAP_SIZE_SPINNER].type = WWT_SPINNER; - mapWindow->widgets[WIDX_MAP_SIZE_SPINNER_UP].type = WWT_DROPDOWN_BUTTON; - mapWindow->widgets[WIDX_MAP_SIZE_SPINNER_DOWN].type = WWT_DROPDOWN_BUTTON; - RCT2_GLOBAL(0x013CE952 + 2, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16); -} - -/** -* -* rct2: 0x0068CA8F -*/ -static void window_map_invalidate() -{ - rct_window *w; - uint32 pressed_widgets; + uint64 pressedWidgets; int i, height; - window_get_register(w); colour_scheme_update(w); - // set the pressed widgets - pressed_widgets = (uint32)w->pressed_widgets; - pressed_widgets &= 0xFFFFFF8F; // both tabs and the map - pressed_widgets |= (1 << (w->selected_tab + 4)); // people tab or rides tab - pressed_widgets |= (1 << WIDX_LAND_TOOL); // land tool - pressed_widgets &= 0xFFF0FFFF; // the land option checkboxes + // Set the pressed widgets + pressedWidgets = w->pressed_widgets; + pressedWidgets &= (1ULL << WIDX_PEOPLE_TAB); + pressedWidgets &= (1ULL << WIDX_RIDES_TAB); + pressedWidgets &= (1ULL << WIDX_MAP); + pressedWidgets &= (1ULL << WIDX_LAND_OWNED_CHECKBOX); + pressedWidgets &= (1ULL << WIDX_CONSTRUCTION_RIGHTS_OWNED_CHECKBOX); + pressedWidgets &= (1ULL << WIDX_LAND_SALE_CHECKBOX); + pressedWidgets &= (1ULL << WIDX_CONSTRUCTION_RIGHTS_SALE_CHECKBOX); - if (RCT2_GLOBAL(0x0F1AD61, uint8) & 8) - pressed_widgets |= (1 << WIDX_LAND_SALE_CHECKBOX); + pressedWidgets |= (1ULL << (WIDX_PEOPLE_TAB + w->selected_tab)); + pressedWidgets |= (1ULL << WIDX_LAND_TOOL); - if (RCT2_GLOBAL(0x0F1AD61, uint8) & 4) - pressed_widgets |= (1 << WIDX_CONSTRUCTION_RIGHTS_SALE_CHECKBOX); + if (RCT2_GLOBAL(0x00F1AD61, uint8) & (1 << 3)) + pressedWidgets |= (1 << WIDX_LAND_SALE_CHECKBOX); - if (RCT2_GLOBAL(0x0F1AD61, uint8) & 2) - pressed_widgets |= (1 << WIDX_LAND_OWNED_CHECKBOX); + if (RCT2_GLOBAL(0x00F1AD61, uint8) & (1 << 2)) + pressedWidgets |= (1 << WIDX_CONSTRUCTION_RIGHTS_SALE_CHECKBOX); - if (RCT2_GLOBAL(0x0F1AD61, uint8) & 1) - pressed_widgets |= (1 << WIDX_CONSTRUCTION_RIGHTS_OWNED_CHECKBOX); + if (RCT2_GLOBAL(0x00F1AD61, uint8) & (1 << 1)) + pressedWidgets |= (1 << WIDX_LAND_OWNED_CHECKBOX); - w->pressed_widgets = pressed_widgets; + if (RCT2_GLOBAL(0x00F1AD61, uint8) & (1 << 0)) + pressedWidgets |= (1 << WIDX_CONSTRUCTION_RIGHTS_OWNED_CHECKBOX); - // resizing changes some widget coordinates + w->pressed_widgets = pressedWidgets; + + // Resize widgets to window size w->widgets[WIDX_BACKGROUND].right = w->width - 1; w->widgets[WIDX_BACKGROUND].bottom = w->height - 1; w->widgets[WIDX_RESIZE].right = w->width - 1; @@ -542,10 +693,9 @@ 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) || - gSandboxMode) + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) w->widgets[WIDX_MAP].bottom = w->height - 1 - 72; - else if (w->selected_tab == 1) + else if (w->selected_tab == PAGE_RIDES) w->widgets[WIDX_MAP].bottom = w->height - 1 - 44; else w->widgets[WIDX_MAP].bottom = w->height - 1 - 14; @@ -573,7 +723,7 @@ static void window_map_invalidate() w->widgets[WIDX_LAND_TOOL_LARGER].top = w->height - 27; w->widgets[WIDX_LAND_TOOL_LARGER].bottom = w->height - 27 + 15; - // land tool mode (4 checkboxes) + // Land tool mode (4 checkboxes) height = w->height - 55; for (i = 0; i < 4; i++) { w->widgets[WIDX_LAND_OWNED_CHECKBOX + i].top = height; @@ -582,29 +732,29 @@ static void window_map_invalidate() height += 2; } - // disable all scenario editor related widgets + // Disable all scenario editor related widgets for (i = WIDX_MAP_SIZE_SPINNER; i <= WIDX_ROTATE_90; i++) { w->widgets[i].type = WWT_EMPTY; } - - - if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || - gSandboxMode) { + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) { // scenario editor: build park entrance selected, show rotate button - if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && + 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_BUILD_PARK_ENTRANCE) { + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint8) == WIDX_BUILD_PARK_ENTRANCE + ) { w->widgets[WIDX_ROTATE_90].type = WWT_FLATBTN; } - // always show set land rights button + // Always show set land rights button w->widgets[WIDX_SET_LAND_RIGHTS].type = WWT_FLATBTN; - // if any tool is active - if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && - RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == WC_MAP) { - + // If any tool is active + if ( + (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == WC_MAP + ) { // if not in set land rights mode: show the default scenario editor buttons if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint8) != WIDX_SET_LAND_RIGHTS) { window_map_show_default_scenario_editor_buttons(w); @@ -612,83 +762,56 @@ static void window_map_invalidate() w->widgets[WIDX_LAND_TOOL].type = WWT_IMGBTN; w->widgets[WIDX_LAND_TOOL_SMALLER].type = WWT_TRNBTN; 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 = RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, uint16) <= 7 ? SPR_LAND_TOOL_SIZE_0 + - RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, uint16) : 0xFFFFFFFF; + + 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 { + // if no tool is active: show the default scenario editor buttons window_map_show_default_scenario_editor_buttons(w); } } } /** -* -* rct2: 0x0068CDA9 -*/ -static void window_map_paint() + * + * rct2: 0x0068CDA9 + */ +static void window_map_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - int image_id; int i, x, y; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); + window_map_draw_tab_images(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); + // Draw land tool size + if (widget_is_active_tool(w, WIDX_SET_LAND_RIGHTS) && RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) > 7) { + gfx_draw_string_centred(dpi, STR_LAND_TOOL_SIZE_VALUE, x, y - 2, 0, &RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)); } 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) - image_id += w->list_information_type / 4; - - gfx_draw_sprite(dpi, image_id, - w->x + w->widgets[WIDX_PEOPLE_TAB].left, - w->y + w->widgets[WIDX_PEOPLE_TAB].top, 0); - - // ride/stall tab image (animated) - image_id = SPR_TAB_RIDE_0; - if (w->selected_tab == 1) - image_id += w->list_information_type / 4; - - gfx_draw_sprite(dpi, image_id, - w->x + w->widgets[WIDX_RIDES_TAB].left, - w->y + w->widgets[WIDX_RIDES_TAB].top, 0); - - // people starting position (scenario editor only) + // People starting position (scenario editor only) if (w->widgets[WIDX_PEOPLE_STARTING_POSITION].type != 0) { - gfx_draw_sprite(dpi, 0x0B6E0190A, - w->x + w->widgets[WIDX_PEOPLE_STARTING_POSITION].left + 12, - w->y + w->widgets[WIDX_PEOPLE_STARTING_POSITION].top + 18, 0); + x = w->x + w->widgets[WIDX_PEOPLE_STARTING_POSITION].left + 12; + y = w->y + w->widgets[WIDX_PEOPLE_STARTING_POSITION].top + 18; + gfx_draw_sprite(dpi, 0x0B6E0190A, x, y, 0); } - if (!((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) - || gSandboxMode)) { - // render the map legend - if (w->selected_tab != 0) { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) { + // Render the map legend + if (w->selected_tab == PAGE_RIDES) { x = w->x + 4; y = w->y + w->widgets[WIDX_MAP].bottom + 2; for (i = 0; i < 8; i++) { - gfx_fill_rect(dpi, x, y + 2, x + 6, y + 8, RCT2_GLOBAL(0x00981BCC+ 2 * i, uint8)); + gfx_fill_rect(dpi, x, y + 2, x + 6, y + 8, RCT2_GLOBAL(0x00981BCC + (i * 2), uint8)); gfx_draw_string_left(dpi, STR_MAP_RIDE + i, w, 0, x + 10, y); y += 10; if (i == 3) { @@ -697,35 +820,162 @@ 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)) - return; - + } else if (!widget_is_active_tool(w, WIDX_SET_LAND_RIGHTS)) { gfx_draw_string_left(dpi, STR_MAP_SIZE, 0, 0, w->x + 4, w->y + w->widgets[WIDX_MAP_SIZE_SPINNER].top + 1); } } -/* -* -* rct2: 0x0068D140 -*/ -static void window_map_tooltip() +/** + * + * rct2: 0x0068CF23 + */ +static void window_map_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { - RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, short) = 0xC55; + rct_g1_element *g1_element, pushed_g1_element; + + gfx_clear(dpi, 0x0A0A0A0A); + + g1_element = &g1Elements[0]; + pushed_g1_element = *g1_element; + + g1_element->offset = RCT2_GLOBAL(RCT2_ADDRESS_MAP_IMAGE_DATA, uint8*); + g1_element->width = 0x200; + g1_element->height = 0x200; + g1_element->x_offset = 0xFFF8; + g1_element->y_offset = 0xFFF8; + g1_element->flags = 0; + + gfx_draw_sprite(dpi, 0, 0, 0, 0); + + *g1_element = pushed_g1_element; + + if (w->selected_tab == PAGE_PEEPS) + window_map_paint_peep_overlay(dpi); + else + window_map_paint_train_overlay(dpi); + + window_map_paint_hud_rectangle(dpi); } /** -* -* part of window_map_paint_peep_overlay and window_map_paint_train_overlay -*/ + * + * rct2: 0x0068CA6C + */ +static void window_map_init_map() +{ + memset(RCT2_GLOBAL(RCT2_ADDRESS_MAP_IMAGE_DATA, void*), 0x0A0A0A0A, 256 * 256 * sizeof(uint32)); + RCT2_GLOBAL(0x00F1AD6C, uint32) = 0; +} + +/** + * + * rct2: 0x0068C990 + */ +static void window_map_center_on_view_point() +{ + rct_window *w = window_get_main(); + rct_window *w_map; + sint16 ax, bx, cx, dx; + sint16 bp, di; + + if (w == NULL || w->viewport == NULL) + return; + + w_map = window_find_by_class(WC_MAP); + if (w_map == NULL) + return; + + rct_xy16 offset = MiniMapOffsets[get_current_rotation()]; + + // 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 += offset.x; + dx += offset.y; + + // 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; + di = bx; + + ax >>= 1; + bx >>= 1; + cx = max(cx - ax, 0); + dx = max(dx - bx, 0); + + bp = w_map->scrolls[0].h_right - bp; + di = w_map->scrolls[0].v_bottom - di; + + if (bp < 0 && (bp - cx) < 0) + cx = 0; + + if (di < 0 && (di - dx) < 0) + dx = 0; + + w_map->scrolls[0].h_left = cx; + w_map->scrolls[0].v_top = dx; + widget_scroll_update_thumbs(w_map, WIDX_MAP); +} + +/** + * + * rct2: 0x0068CD35 (part of 0x0068CA8F) + */ +static void window_map_show_default_scenario_editor_buttons(rct_window *w) { + w->widgets[WIDX_BUILD_PARK_ENTRANCE].type = WWT_FLATBTN; + w->widgets[WIDX_PEOPLE_STARTING_POSITION].type = WWT_FLATBTN; + w->widgets[WIDX_MAP_SIZE_SPINNER].type = WWT_SPINNER; + w->widgets[WIDX_MAP_SIZE_SPINNER_UP].type = WWT_DROPDOWN_BUTTON; + w->widgets[WIDX_MAP_SIZE_SPINNER_DOWN].type = WWT_DROPDOWN_BUTTON; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) - 2; +} + +static void window_map_inputsize_land(rct_window *w) +{ + ((uint16*)TextInputDescriptionArgs)[0] = MINIMUM_TOOL_SIZE; + ((uint16*)TextInputDescriptionArgs)[1] = MAXIMUM_TOOL_SIZE; + 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] = MINIMUM_MAP_SIZE_PRACTICAL; + ((uint16*)TextInputDescriptionArgs)[1] = MAXIMUM_MAP_SIZE_PRACTICAL; + window_text_input_open(w, WIDX_MAP_SIZE_SPINNER, 5130, 5131, STR_NONE, STR_NONE, 4); +} + +static void window_map_draw_tab_images(rct_window *w, rct_drawpixelinfo *dpi) +{ + uint32 image; + + // Guest tab image (animated) + image = SPR_TAB_GUESTS_0; + if (w->selected_tab == PAGE_PEEPS) + image += w->list_information_type / 4; + + gfx_draw_sprite(dpi, image, w->x + w->widgets[WIDX_PEOPLE_TAB].left, w->y + w->widgets[WIDX_PEOPLE_TAB].top, 0); + + // Ride/stall tab image (animated) + image = SPR_TAB_RIDE_0; + if (w->selected_tab == PAGE_RIDES) + image += w->list_information_type / 4; + + gfx_draw_sprite(dpi, image, w->x + w->widgets[WIDX_RIDES_TAB].left, w->y + w->widgets[WIDX_RIDES_TAB].top, 0); +} + +/** + * + * 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)) { + switch (get_current_rotation()) { case 3: temp = x; x = y; @@ -753,9 +1003,9 @@ static void window_map_transform_to_map_coords(sint16 *left, sint16 *top) } /** -* -* rct2: 0x0068DADA -*/ + * + * rct2: 0x0068DADA + */ static void window_map_paint_peep_overlay(rct_drawpixelinfo *dpi) { rct_peep *peep; @@ -800,9 +1050,9 @@ static void window_map_paint_peep_overlay(rct_drawpixelinfo *dpi) } /** -* -* rct2: 0x0068DBC1 -*/ + * + * rct2: 0x0068DBC1 + */ static void window_map_paint_train_overlay(rct_drawpixelinfo *dpi) { rct_vehicle *train, *vehicle; @@ -832,28 +1082,26 @@ static void window_map_paint_train_overlay(rct_drawpixelinfo *dpi) } /** -* 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 -*/ + * 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; + rct_xy16 offset = MiniMapOffsets[get_current_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); @@ -873,100 +1121,562 @@ static void window_map_paint_hud_rectangle(rct_drawpixelinfo *dpi) } /** -* -* rct2: 0x0068CF23 -*/ -static void window_map_scrollpaint() + * + * rct2: 0x0068D24E + */ +static void window_map_set_land_rights_tool_update(int x, int y) { - rct_window *w; - rct_drawpixelinfo *dpi; - rct_g1_element *g1_element, pushed_g1_element; + sint16 mapX, mapY; + rct_viewport *viewport; - window_paint_get_registers(w, dpi); + map_invalidate_selection_rect(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); + screen_get_map_xy(x, y, &mapX, &mapY, &viewport); + if (mapX == (sint16)0x8000) + return; - gfx_clear(dpi, 0x0A0A0A0A); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; - g1_element = &g1Elements[0]; - pushed_g1_element = *g1_element; + int landToolSize = RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, uint16); + if (landToolSize == 0) + landToolSize = 1; - g1_element->offset = RCT2_GLOBAL(RCT2_ADDRESS_MAP_IMAGE_DATA, uint8*); - g1_element->width = 0x200; - g1_element->height = 0x200; - g1_element->x_offset = 0xFFF8; - g1_element->y_offset = 0xFFF8; - g1_element->flags = 0; - - gfx_draw_sprite(dpi, 0, 0, 0, 0); - - *g1_element = pushed_g1_element; - - if (w->selected_tab == 0) - window_map_paint_peep_overlay(dpi); - else - window_map_paint_train_overlay(dpi); - - window_map_paint_hud_rectangle(dpi); + int size = (landToolSize * 32) - 32; + int radius = (landToolSize * 16) - 16; + mapX = (mapX - radius) & 0xFFE0; + mapY = (mapY - radius) & 0xFFE0; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16) = mapX; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16) = mapY; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16) = mapX + size; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) = mapY + size; + map_invalidate_selection_rect(); } /** -* -* rct2: 0x0068CA6C -*/ -static void window_map_init_map() + * + * rct2: 0x00666EEF + */ +void sub_666EEF(int x, int y, sint16 *mapX, sint16 *mapY, sint16 *mapZ, int *direction) { - memset(RCT2_GLOBAL(RCT2_ADDRESS_MAP_IMAGE_DATA, void*), 0x0A0A0A0A, 256 * 256 * sizeof(uint32)); - RCT2_GLOBAL(0x00F1AD6C, uint32) = 0; + rct_map_element *mapElement; + + sub_68A15E(x, y, mapX, mapY, direction, &mapElement); + if (*mapX == (sint16)0x8000) + return; + + mapElement = map_get_surface_element_at(*mapX >> 5, *mapY >> 5); + *mapZ = mapElement->properties.surface.slope & 0x1F; + if (*mapZ == 0) { + *mapZ = mapElement->base_height / 2; + if ((mapElement->properties.surface.slope & 0x0F) != 0) { + (*mapZ)++; + if (mapElement->properties.surface.slope & 0x10) { + (*mapZ)++; + } + } + } + *direction = (window_scenery_rotation - get_current_rotation()) & 3; } /** -* -* rct2: 0x0068C990 -*/ -static void window_map_center_on_view_point() + * + * rct2: 0x00666FD0 + */ +static void window_map_place_park_entrance_tool_update(int x, int y) { - rct_window *w = window_get_main(); - rct_window *w_map; - sint16 ax, bx, cx, dx; - sint16 bp, di; + sint16 mapX, mapY, mapZ; + int direction, sideDirection; - if (w == NULL || w->viewport == NULL) + map_invalidate_selection_rect(); + map_invalidate_map_selection_tiles(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 1); + sub_666EEF(x, y, &mapX, &mapY, &mapZ, &direction); + if (mapX == (sint16)-1) { + park_remove_ghost_entrance(); + return; + } + + sideDirection = (direction + 1) & 3; + gMapSelectionTiles[0].x = mapX; + gMapSelectionTiles[0].y = mapY; + gMapSelectionTiles[1].x = mapX + TileDirectionDelta[sideDirection].x; + gMapSelectionTiles[1].y = mapY + TileDirectionDelta[sideDirection].y; + gMapSelectionTiles[2].x = mapX - TileDirectionDelta[sideDirection].x; + gMapSelectionTiles[2].y = mapY - TileDirectionDelta[sideDirection].y; + gMapSelectionTiles[3].x = -1; + gMapSelectionTiles[3].y = -1; + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 1); + map_invalidate_map_selection_tiles(); + if ( + (RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_GHOST_EXISTS, uint8) & (1 << 0)) && + mapX == RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_GHOST_X, uint16) && + mapY == RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_GHOST_Y, uint16) && + direction == RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_GHOST_DIRECTION, uint8) + ) { + return; + } + + park_remove_ghost_entrance(); + RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_GHOST_PRICE, uint32) = park_place_ghost_entrance(mapX, mapY, mapZ, direction); +} + +/** + * + * rct2: 0x0068D4E9 + */ +static void window_map_set_peep_spawn_tool_update(int x, int y) +{ + int mapX, mapY, mapZ, direction; + rct_map_element *mapElement; + + map_invalidate_selection_rect(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 2); + footpath_bridge_get_info_from_pos(x, y, &mapX, &mapY, &direction, &mapElement); + if ((mapX & 0xFFFF) == 0x8000) return; - w_map = window_find_by_class(WC_MAP); - if (w_map == NULL) + mapZ = mapElement->base_height * 8; + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_SURFACE) { + if ((mapElement->properties.surface.slope & 0x0F) != 0) + mapZ += 16; + if (mapElement->properties.surface.slope & 0x10) + mapZ += 16; + } + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 2); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16) = mapX; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16) = mapY; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16) = mapX; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) = mapY; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_DIRECTION, uint8) = direction ^ 2; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_X, uint16) = mapX; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_Y, uint16) = mapY; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_Z, uint16) = mapZ; + map_invalidate_selection_rect(); +} + +/** + * + * rct2: 0x006670A4 + */ +static void window_map_place_park_entrance_tool_down(int x, int y) +{ + sint16 mapX, mapY, mapZ; + int direction; + money32 price; + + park_remove_ghost_entrance(); + sub_666EEF(x, y, &mapX, &mapY, &mapZ, &direction); + if (mapX == (sint16)0x8000) return; - uint8 rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_BUILD_PARK_ENTRANCE_HERE; + price = game_do_command( + mapX, + GAME_COMMAND_FLAG_APPLY | (direction << 8), + mapY, + mapZ, + GAME_COMMAND_PLACE_PARK_ENTRANCE, + 0, + 0 + ); + if (price == MONEY32_UNDEFINED) + return; - // calculate center view point of viewport and transform it to minimap coordinates + audio_play_sound_at_location( + SOUND_PLACE_ITEM, + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16), + RCT2_GLOBAL(0x009DEA64, uint16), + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, uint16) + ); +} - cx = ((w->viewport->view_width >> 1) + w->viewport->view_x) >> 5; - dx = ((w->viewport->view_height >> 1) + w->viewport->view_y) >> 4; - cx += _minimap_offsets_x[rotation]; - dx += _minimap_offsets_y[rotation]; - - // calculate width and height of minimap +/** + * + * rct2: 0x0068D573 + */ +static void window_map_set_peep_spawn_tool_down(int x, int y) +{ + rct_map_element *mapElement, *surfaceMapElement; + int mapX, mapY, mapZ, direction; - 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; - di = bx; + footpath_get_coordinates_from_pos(x, y, &mapX, &mapY, &direction, &mapElement); + if (mapX == 0x8000) + return; - ax >>= 1; - bx >>= 1; - cx = max(cx - ax, 0); - dx = max(dx - bx, 0); + surfaceMapElement = map_get_surface_element_at(mapX >> 5, mapY >> 5); + if (surfaceMapElement->properties.surface.ownership & 0xF0) { + return; + } - bp = w_map->scrolls[0].h_right - bp; - di = w_map->scrolls[0].v_bottom - di; + mapX = mapX + 16 + (word_981D6C[direction].x * 15); + mapY = mapY + 16 + (word_981D6C[direction].y * 15); + mapZ = mapElement->base_height / 2; - if (bp < 0 && (bp - cx) < 0) - cx = 0; + int peepSpawnIndex = 0; + if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, uint16) != 1 && gPeepSpawns[0].x != 0xFFFF) + peepSpawnIndex = 1; - if (di < 0 && (di - dx) < 0) + gPeepSpawns[peepSpawnIndex].x = mapX; + gPeepSpawns[peepSpawnIndex].y = mapY; + gPeepSpawns[peepSpawnIndex].z = mapZ; + gPeepSpawns[peepSpawnIndex].direction = direction; + gfx_invalidate_screen(); + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, uint16) = peepSpawnIndex; +} + +/** + * + * rct2: 0x0068D641 + */ +static void map_window_increase_map_size() +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) >= 256) { + window_error_open(STR_CANT_INCREASE_MAP_SIZE_ANY_FURTHER, STR_NONE); + return; + } + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16)++; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) = (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) - 1) * 32; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_MINUS_2, uint16) = (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) * 32) + 254; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16) = ((RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) - 1) * 32) - 1; + map_extend_boundary_surface(); + window_map_init_map(); + window_map_center_on_view_point(); + gfx_invalidate_screen(); +} + +/** + * + * rct2: 0x0068D6B4 + */ +static void map_window_decrease_map_size() +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) < 16) { + window_error_open(STR_CANT_DECREASE_MAP_SIZE_ANY_FURTHER, STR_NONE); + return; + } + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16)--; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) = (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) - 1) * 32; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_MINUS_2, uint16) = (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) * 32) + 254; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16) = ((RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) - 1) * 32) - 1; + map_remove_out_of_range_elements(); + window_map_init_map(); + window_map_center_on_view_point(); + gfx_invalidate_screen(); +} + +static const uint16 WaterColour = 0xC3C3; +static const uint16 TerrainColour[] = { + 0x4949, // TERRAIN_GRASS + 0x2828, // TERRAIN_SAND + 0x6C6C, // TERRAIN_DIRT + 0x0C0C, // TERRAIN_ROCK + 0x3E3E, // TERRAIN_MARTIAN + 0x0A10, // TERRAIN_CHECKERBOARD + 0x496C, // TERRAIN_GRASS_CLUMPS + 0x8D8D, // TERRAIN_ICE + 0xAC0A, // TERRAIN_GRID_RED + 0x360A, // TERRAIN_GRID_YELLOW + 0xA20A, // TERRAIN_GRID_BLUE + 0x660A, // TERRAIN_GRID_GREEN + 0x6F6F, // TERRAIN_SAND_DARK + 0xDEDE, // TERRAIN_SAND_LIGHT +}; + +static const uint16 ElementTypeMaskColour[] = { + 0xFFFF, // MAP_ELEMENT_TYPE_SURFACE + 0x0000, // MAP_ELEMENT_TYPE_PATH + 0x00FF, // MAP_ELEMENT_TYPE_TRACK + 0xFF00, // MAP_ELEMENT_TYPE_SCENERY + 0x0000, // MAP_ELEMENT_TYPE_ENTRANCE + 0xFFFF, // MAP_ELEMENT_TYPE_FENCE + 0x0000, // MAP_ELEMENT_TYPE_SCENERY_MULTIPLE + 0xFFFF // MAP_ELEMENT_TYPE_BANNER +}; + +static const uint16 ElementTypeAddColour[] = { + 0x0000, // MAP_ELEMENT_TYPE_SURFACE + 0x1111, // MAP_ELEMENT_TYPE_PATH + 0xB700, // MAP_ELEMENT_TYPE_TRACK + 0x0063, // MAP_ELEMENT_TYPE_SCENERY + 0xBABA, // MAP_ELEMENT_TYPE_ENTRANCE + 0x0000, // MAP_ELEMENT_TYPE_FENCE + 0x6363, // MAP_ELEMENT_TYPE_SCENERY_MULTIPLE + 0x0000 // MAP_ELEMENT_TYPE_BANNER +}; + +enum { + COLOUR_KEY_RIDE, + COLOUR_KEY_FOOD, + COLOUR_KEY_DRINK, + COLOUR_KEY_SOUVENIR, + COLOUR_KEY_KIOSK, + COLOUR_KEY_FIRST_AID, + COLOUR_KEY_CASH_MACHINE, + COLOUR_KEY_TOILETS +}; + +static const uint8 RideColourKey[] = { + COLOUR_KEY_RIDE, // RIDE_TYPE_SPIRAL_ROLLER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_STAND_UP_ROLLER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_SUSPENDED_SWINGING_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_INVERTED_ROLLER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_JUNIOR_ROLLER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_MINIATURE_RAILWAY + COLOUR_KEY_RIDE, // RIDE_TYPE_MONORAIL + COLOUR_KEY_RIDE, // RIDE_TYPE_MINI_SUSPENDED_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_BOAT_RIDE + COLOUR_KEY_RIDE, // RIDE_TYPE_WOODEN_WILD_MOUSE + COLOUR_KEY_RIDE, // RIDE_TYPE_STEEPLECHASE + COLOUR_KEY_RIDE, // RIDE_TYPE_CAR_RIDE + COLOUR_KEY_RIDE, // RIDE_TYPE_LAUNCHED_FREEFALL + COLOUR_KEY_RIDE, // RIDE_TYPE_BOBSLEIGH_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_OBSERVATION_TOWER + COLOUR_KEY_RIDE, // RIDE_TYPE_LOOPING_ROLLER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_DINGHY_SLIDE + COLOUR_KEY_RIDE, // RIDE_TYPE_MINE_TRAIN_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_CHAIRLIFT + COLOUR_KEY_RIDE, // RIDE_TYPE_CORKSCREW_ROLLER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_MAZE = 20 + COLOUR_KEY_RIDE, // RIDE_TYPE_SPIRAL_SLIDE + COLOUR_KEY_RIDE, // RIDE_TYPE_GO_KARTS + COLOUR_KEY_RIDE, // RIDE_TYPE_LOG_FLUME + COLOUR_KEY_RIDE, // RIDE_TYPE_RIVER_RAPIDS + COLOUR_KEY_RIDE, // RIDE_TYPE_DODGEMS + COLOUR_KEY_RIDE, // RIDE_TYPE_PIRATE_SHIP + COLOUR_KEY_RIDE, // RIDE_TYPE_SWINGING_INVERTER_SHIP + COLOUR_KEY_FOOD, // RIDE_TYPE_FOOD_STALL + COLOUR_KEY_FOOD, // RIDE_TYPE_1D + COLOUR_KEY_DRINK, // RIDE_TYPE_DRINK_STALL + COLOUR_KEY_DRINK, // RIDE_TYPE_1F + COLOUR_KEY_SOUVENIR, // RIDE_TYPE_SHOP + COLOUR_KEY_RIDE, // RIDE_TYPE_MERRY_GO_ROUND + COLOUR_KEY_SOUVENIR, // RIDE_TYPE_22 + COLOUR_KEY_KIOSK, // RIDE_TYPE_INFORMATION_KIOSK + COLOUR_KEY_TOILETS, // RIDE_TYPE_TOILETS + COLOUR_KEY_RIDE, // RIDE_TYPE_FERRIS_WHEEL + COLOUR_KEY_RIDE, // RIDE_TYPE_MOTION_SIMULATOR + COLOUR_KEY_RIDE, // RIDE_TYPE_3D_CINEMA + COLOUR_KEY_RIDE, // RIDE_TYPE_TOP_SPIN + COLOUR_KEY_RIDE, // RIDE_TYPE_SPACE_RINGS + COLOUR_KEY_RIDE, // RIDE_TYPE_REVERSE_FREEFALL_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_LIFT + COLOUR_KEY_RIDE, // RIDE_TYPE_VERTICAL_DROP_ROLLER_COASTER + COLOUR_KEY_CASH_MACHINE, // RIDE_TYPE_CASH_MACHINE + COLOUR_KEY_RIDE, // RIDE_TYPE_TWIST + COLOUR_KEY_RIDE, // RIDE_TYPE_HAUNTED_HOUSE + COLOUR_KEY_FIRST_AID, // RIDE_TYPE_FIRST_AID + COLOUR_KEY_RIDE, // RIDE_TYPE_CIRCUS_SHOW + COLOUR_KEY_RIDE, // RIDE_TYPE_GHOST_TRAIN + COLOUR_KEY_RIDE, // RIDE_TYPE_TWISTER_ROLLER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_WOODEN_ROLLER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_SIDE_FRICTION_ROLLER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_WILD_MOUSE + COLOUR_KEY_RIDE, // RIDE_TYPE_MULTI_DIMENSION_ROLLER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_38 + COLOUR_KEY_RIDE, // RIDE_TYPE_FLYING_ROLLER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_3A + COLOUR_KEY_RIDE, // RIDE_TYPE_VIRGINIA_REEL + COLOUR_KEY_RIDE, // RIDE_TYPE_SPLASH_BOATS + COLOUR_KEY_RIDE, // RIDE_TYPE_MINI_HELICOPTERS + COLOUR_KEY_RIDE, // RIDE_TYPE_LAY_DOWN_ROLLER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_SUSPENDED_MONORAIL + COLOUR_KEY_RIDE, // RIDE_TYPE_40 + COLOUR_KEY_RIDE, // RIDE_TYPE_REVERSER_ROLLER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_HEARTLINE_TWISTER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_MINI_GOLF + COLOUR_KEY_RIDE, // RIDE_TYPE_GIGA_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_ROTO_DROP + COLOUR_KEY_RIDE, // RIDE_TYPE_FLYING_SAUCERS + COLOUR_KEY_RIDE, // RIDE_TYPE_CROOKED_HOUSE + COLOUR_KEY_RIDE, // RIDE_TYPE_MONORAIL_CYCLES + COLOUR_KEY_RIDE, // RIDE_TYPE_COMPACT_INVERTED_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_WATER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_INVERTED_HAIRPIN_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_MAGIC_CARPET + COLOUR_KEY_RIDE, // RIDE_TYPE_SUBMARINE_RIDE + COLOUR_KEY_RIDE, // RIDE_TYPE_RIVER_RAFTS + COLOUR_KEY_RIDE, // RIDE_TYPE_50 + COLOUR_KEY_RIDE, // RIDE_TYPE_ENTERPRISE + COLOUR_KEY_RIDE, // RIDE_TYPE_52 + COLOUR_KEY_RIDE, // RIDE_TYPE_53 + COLOUR_KEY_RIDE, // RIDE_TYPE_54 + COLOUR_KEY_RIDE, // RIDE_TYPE_55 + COLOUR_KEY_RIDE, // RIDE_TYPE_INVERTED_IMPULSE_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_MINI_ROLLER_COASTER + COLOUR_KEY_RIDE, // RIDE_TYPE_MINE_RIDE + COLOUR_KEY_RIDE, // RIDE_TYPE_59 + COLOUR_KEY_RIDE, // RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER + COLOUR_KEY_RIDE, // + COLOUR_KEY_RIDE, // + COLOUR_KEY_RIDE, // +}; + +static const uint16 RideKeyColours[] = { + 0x3D3D, // COLOUR_KEY_RIDE + 0x2A2A, // COLOUR_KEY_FOOD + 0x1414, // COLOUR_KEY_DRINK + 0x0D1D, // COLOUR_KEY_SOUVENIR + 0x8888, // COLOUR_KEY_KIOSK + 0x6666, // COLOUR_KEY_FIRST_AID + 0x3737, // COLOUR_KEY_CASH_MACHINE + 0xA1A1, // COLOUR_KEY_TOILETS +}; + +static uint16 map_window_get_pixel_colour_peep(int x, int y) +{ + rct_map_element *mapElement; + uint16 colour; + + mapElement = map_get_surface_element_at(x >> 5, y >> 5); + colour = TerrainColour[map_element_get_terrain(mapElement)]; + if (mapElement->properties.surface.terrain & 0x1F) + colour = WaterColour; + + if (!(mapElement->properties.surface.ownership & OWNERSHIP_OWNED)) + colour = 10 | (colour & 0xFF00); + + while (!map_element_is_last_for_tile(mapElement++)) { + int mapElementType = map_element_get_type(mapElement); + colour &= ElementTypeMaskColour[mapElementType >> 2]; + colour |= ElementTypeAddColour[mapElementType >> 2]; + } + + return colour; +} + +static uint16 map_window_get_pixel_colour_ride(int x, int y) +{ + rct_map_element *mapElement; + rct_ride *ride; + uint32 colour; + + colour = 0x0D0D0000; + mapElement = map_get_surface_element_at(x >> 5, y >> 5); + do { + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_SURFACE: + if (mapElement->properties.surface.terrain & 0x1F) { + colour &= 0xFFFF; + colour |= 0xC2C20000; + } + if (!(mapElement->properties.surface.ownership & OWNERSHIP_OWNED)) { + colour &= 0xFF00FFFF; + colour |= 0x000A0000; + } + break; + case MAP_ELEMENT_TYPE_PATH: + colour = 0x0E0E; + break; + case MAP_ELEMENT_TYPE_ENTRANCE: + if (mapElement->properties.entrance.type == ENTRANCE_TYPE_PARK_ENTRANCE) + break; + // fall-through + case MAP_ELEMENT_TYPE_TRACK: + ride = GET_RIDE(mapElement->properties.track.ride_index); + colour = RideKeyColours[RideColourKey[ride->type]]; + break; + } + } while (!map_element_is_last_for_tile(mapElement++)); + + if ((colour & 0xFFFF) == 0) + colour >>= 16; + + return colour & 0xFFFF; +} + +static void map_window_set_pixels(rct_window *w) +{ + uint16 colour = 0, *destination; + int x, y, dx, dy; + + destination = (uint16*)((RCT2_GLOBAL(0x00F1AD6C, uint32) * 511) + RCT2_GLOBAL(RCT2_ADDRESS_MAP_IMAGE_DATA, uint32) + 255); + switch (get_current_rotation()) { + case 0: + x = RCT2_GLOBAL(0x00F1AD6C, uint32) * 32; + y = 0; dx = 0; + dy = 32; + break; + case 1: + x = 8192 - 32; + y = RCT2_GLOBAL(0x00F1AD6C, uint32) * 32; + dx = -32; + dy = 0; + break; + case 2: + x = (255 - RCT2_GLOBAL(0x00F1AD6C, uint32)) * 32; + y = 8192 - 32; + dx = 0; + dy = -32; + break; + case 3: + x = 0; + y = (255 - RCT2_GLOBAL(0x00F1AD6C, uint32)) * 32; + dx = 32; + dy = 0; + break; + } - w_map->scrolls[0].h_left = cx; - w_map->scrolls[0].v_top = dx; - widget_scroll_update_thumbs(w_map, WIDX_MAP); + for (int i = 0; i < 256; i++) { + if ( + x > 0 && + y > 0 && + x < RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) && + y < RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) + ) { + switch (w->selected_tab) { + case PAGE_PEEPS: + colour = map_window_get_pixel_colour_peep(x, y); + break; + case PAGE_RIDES: + colour = map_window_get_pixel_colour_ride(x, y); + break; + } + *destination = colour; + } + x += dx; + y += dy; + destination = (uint16*)((int)destination + 513); + } + RCT2_GLOBAL(0x00F1AD6C, uint32)++; + if (RCT2_GLOBAL(0x00F1AD6C, uint32) >= 256) + RCT2_GLOBAL(0x00F1AD6C, uint32) = 0; +} + +static void map_window_screen_to_map(int screenX, int screenY, int *mapX, int *mapY) +{ + int x, y; + + screenX = ((screenX + 8) - 256) / 2; + screenY = ((screenY + 8) ) / 2; + x = (screenY - screenX) * 32; + y = (screenX + screenY) * 32; + switch (get_current_rotation()) { + case 0: + *mapX = x; + *mapY = y; + break; + case 1: + *mapX = 8191 - y; + *mapY = x; + break; + case 2: + *mapX = 8191 - x; + *mapY = 8191 - y; + break; + case 3: + *mapX = y; + *mapY = 8191 - x; + break; + } } diff --git a/src/windows/map_tooltip.c b/src/windows/map_tooltip.c index 3832471df4..8499a0b7d2 100644 --- a/src/windows/map_tooltip.c +++ b/src/windows/map_tooltip.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 . *****************************************************************************/ @@ -29,42 +29,41 @@ static rct_widget window_map_tooltip_widgets[] = { { WIDGETS_END } }; -static void window_map_tooltip_emptysub() { } static void window_map_tooltip_update(rct_window *w); -static void window_map_tooltip_paint(); +static void window_map_tooltip_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void* window_map_tooltip_events[] = { - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, +static rct_window_event_list window_map_tooltip_events = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_map_tooltip_update, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, - window_map_tooltip_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_map_tooltip_paint, - window_map_tooltip_emptysub + NULL }; -#define MAP_TOOLTIP_ARGS +#define MAP_TOOLTIP_ARGS static int _lastCursorX; static int _lastCursorY; @@ -106,7 +105,7 @@ void window_map_tooltip_update_visibility() } /** - * + * * rct2: 0x006A7C43 */ static void window_map_tooltip_open() @@ -122,7 +121,7 @@ static void window_map_tooltip_open() w = window_find_by_class(WC_MAP_TOOLTIP); if (w == NULL) { w = window_create( - x, y, width, height, (uint32*)window_map_tooltip_events, WC_MAP_TOOLTIP, WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_5 + x, y, width, height, &window_map_tooltip_events, WC_MAP_TOOLTIP, WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_NO_BACKGROUND ); w->widgets = window_map_tooltip_widgets; } else { @@ -135,7 +134,7 @@ static void window_map_tooltip_open() } /** - * + * * rct2: 0x006EE8CE */ static void window_map_tooltip_update(rct_window *w) @@ -144,18 +143,13 @@ static void window_map_tooltip_update(rct_window *w) } /** - * + * * rct2: 0x006EE894 */ -static void window_map_tooltip_paint() +static void window_map_tooltip_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS, rct_string_id) == (rct_string_id)STR_NONE) return; - gfx_draw_string_centred_wrapped(dpi, (void*)0x009A9808, w->x + (w->width / 2), w->y + (w->height / 2), w->width, 1162, 0); + gfx_draw_string_centred_wrapped(dpi, (void*)RCT2_ADDRESS_MAP_TOOLTIP_ARGS, w->x + (w->width / 2), w->y + (w->height / 2), w->width, 1162, 0); } \ No newline at end of file diff --git a/src/windows/mapgen.c b/src/windows/mapgen.c index 01c48c457c..03cb6a5e18 100644 --- a/src/windows/mapgen.c +++ b/src/windows/mapgen.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 . *****************************************************************************/ @@ -25,6 +25,7 @@ #include "../interface/viewport.h" #include "../interface/window.h" #include "../sprites.h" +#include "../util/util.h" #include "../world/mapgen.h" #include "../world/scenery.h" #include "dropdown.h" @@ -168,7 +169,7 @@ static rct_widget window_mapgen_simplex_widgets[] = { { 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 }, }; @@ -186,124 +187,124 @@ static rct_widget *window_mapgen_page_widgets[] = { #pragma region Events -static void window_mapgen_emptysub() { } - -static void window_mapgen_base_mouseup(); +static void window_mapgen_base_mouseup(rct_window *w, int widgetIndex); 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_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); 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_textinput(rct_window *w, int widgetIndex, char *text); +static void window_mapgen_base_invalidate(rct_window *w); +static void window_mapgen_base_paint(rct_window *w, rct_drawpixelinfo *dpi); + +static void window_mapgen_random_mouseup(rct_window *w, int widgetIndex); 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_random_invalidate(rct_window *w); +static void window_mapgen_random_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void* window_mapgen_base_events[] = { - window_mapgen_emptysub, +static void window_mapgen_simplex_mouseup(rct_window *w, int widgetIndex); +static void window_mapgen_simplex_mousedown(int widgetIndex, rct_window *w, rct_widget* widget); +static void window_mapgen_simplex_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); +static void window_mapgen_simplex_update(rct_window *w); +static void window_mapgen_simplex_invalidate(rct_window *w); +static void window_mapgen_simplex_paint(rct_window *w, rct_drawpixelinfo *dpi); + +static rct_window_event_list window_mapgen_base_events = { + NULL, window_mapgen_base_mouseup, - window_mapgen_emptysub, + NULL, window_mapgen_base_mousedown, window_mapgen_base_dropdown, - window_mapgen_emptysub, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_mapgen_textinput, - window_mapgen_emptysub, - window_mapgen_emptysub, - window_mapgen_emptysub, - window_mapgen_emptysub, - window_mapgen_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, window_mapgen_base_invalidate, window_mapgen_base_paint, - window_mapgen_emptysub + NULL }; -static void* window_mapgen_random_events[] = { - window_mapgen_emptysub, +static rct_window_event_list window_mapgen_random_events = { + NULL, window_mapgen_random_mouseup, - window_mapgen_emptysub, + NULL, window_mapgen_random_mousedown, - window_mapgen_emptysub, - window_mapgen_emptysub, + NULL, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_mapgen_random_invalidate, window_mapgen_random_paint, - window_mapgen_emptysub + NULL }; -static void* window_mapgen_simplex_events[] = { - window_mapgen_emptysub, +static rct_window_event_list window_mapgen_simplex_events = { + NULL, window_mapgen_simplex_mouseup, - window_mapgen_emptysub, + NULL, window_mapgen_simplex_mousedown, window_mapgen_simplex_dropdown, - window_mapgen_emptysub, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_mapgen_textinput, + NULL, + NULL, + NULL, + NULL, + NULL, window_mapgen_simplex_invalidate, window_mapgen_simplex_paint, - window_mapgen_emptysub + NULL }; -static void* window_mapgen_page_events[] = { - window_mapgen_base_events, - window_mapgen_random_events, - window_mapgen_simplex_events +static rct_window_event_list *window_mapgen_page_events[] = { + &window_mapgen_base_events, + &window_mapgen_random_events, + &window_mapgen_simplex_events }; #pragma endregion @@ -392,8 +393,10 @@ static uint32 window_mapgen_page_hold_down_widgets[] = { const int window_mapgen_tab_animation_loops[] = { 16, 16 }; -#define MAPSIZE_MIN 16 -#define MAPSIZE_MAX 256 +#define MINIMUM_MAP_SIZE_TECHNICAL 15 +#define MAXIMUM_MAP_SIZE_TECHNICAL 256 +#define MINIMUM_MAP_SIZE_PRACTICAL MINIMUM_MAP_SIZE_TECHNICAL-2 +#define MAXIMUM_MAP_SIZE_PRACTICAL MAXIMUM_MAP_SIZE_TECHNICAL-2 #define BASESIZE_MIN 0 #define BASESIZE_MAX 60 #define WATERLEVEL_MIN 0 @@ -461,14 +464,10 @@ rct_window *window_mapgen_open() #pragma region Base page -static void window_mapgen_base_mouseup() +static void window_mapgen_base_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; mapgen_settings mapgenSettings; - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -489,9 +488,10 @@ static void window_mapgen_base_mouseup() 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); + ((uint16*)TextInputDescriptionArgs)[0] = MINIMUM_MAP_SIZE_PRACTICAL; + ((uint16*)TextInputDescriptionArgs)[1] = MAXIMUM_MAP_SIZE_PRACTICAL; + // Practical map size is 2 lower than the technical map size + window_text_input_open(w, WIDX_MAP_SIZE, 5130, 5131, 5182, _mapSize - 2, 4); break; case WIDX_BASE_HEIGHT: ((uint16*)TextInputDescriptionArgs)[0] = (BASESIZE_MIN - 12) / 2; @@ -512,11 +512,11 @@ static void window_mapgen_base_mousedown(int widgetIndex, rct_window *w, rct_wid switch (widgetIndex) { case WIDX_MAP_SIZE_UP: - _mapSize = min(_mapSize + 1, MAPSIZE_MAX); + _mapSize = min(_mapSize + 1, MAXIMUM_MAP_SIZE_TECHNICAL); window_invalidate(w); break; case WIDX_MAP_SIZE_DOWN: - _mapSize = max(_mapSize - 1, MAPSIZE_MIN); + _mapSize = max(_mapSize - 1, MINIMUM_MAP_SIZE_TECHNICAL); window_invalidate(w); break; case WIDX_BASE_HEIGHT_UP: @@ -540,7 +540,7 @@ static void window_mapgen_base_mousedown(int widgetIndex, rct_window *w, rct_wid 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; + gDropdownHighlightedIndex = i; } window_dropdown_show_image( w->x + widget->left, w->y + widget->top, @@ -557,7 +557,7 @@ static void window_mapgen_base_mousedown(int widgetIndex, rct_window *w, rct_wid 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; + gDropdownHighlightedIndex = i; } window_dropdown_show_image( w->x + widget->left, w->y + widget->top, @@ -572,18 +572,14 @@ static void window_mapgen_base_mousedown(int widgetIndex, rct_window *w, rct_wid } } -static void window_mapgen_base_dropdown() +static void window_mapgen_base_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { 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); + dropdownIndex = gDropdownHighlightedIndex; type = (dropdownIndex == -1) ? _floorTexture : @@ -599,7 +595,7 @@ static void window_mapgen_base_dropdown() break; case WIDX_WALL_TEXTURE: if (dropdownIndex == -1) - dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); + dropdownIndex = gDropdownHighlightedIndex; type = (dropdownIndex == -1) ? _wallTexture : @@ -624,20 +620,13 @@ static void window_mapgen_base_update(rct_window *w) widget_invalidate(w, WIDX_TAB_1); } -static void window_mapgen_textinput() +static void window_mapgen_textinput(rct_window *w, int widgetIndex, char *text) { - uint8 result; - short widgetIndex; - rct_window *w; - char *text; int value; char* end; - window_textinput_get_registers(w, widgetIndex, result, text); - - if (!result) { + if (text == NULL) return; - } value = strtol(text, &end, 10); @@ -647,7 +636,10 @@ static void window_mapgen_textinput() switch (widgetIndex) { case WIDX_MAP_SIZE: - _mapSize = clamp(MAPSIZE_MIN, value, MAPSIZE_MAX); + case WIDX_SIMPLEX_MAP_SIZE: + // The practical size is 2 lower than the technical size + value += 2; + _mapSize = clamp(MINIMUM_MAP_SIZE_TECHNICAL, value, MAXIMUM_MAP_SIZE_TECHNICAL); break; case WIDX_BASE_HEIGHT: _baseHeight = clamp(BASESIZE_MIN, (value * 2) + 12, BASESIZE_MAX); @@ -661,11 +653,8 @@ static void window_mapgen_textinput() } -static void window_mapgen_base_invalidate() +static void window_mapgen_base_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); if (w->widgets != window_mapgen_page_widgets[WINDOW_MAPGEN_PAGE_BASE]) { @@ -680,13 +669,9 @@ static void window_mapgen_base_invalidate() window_mapgen_anchor_border_widgets(w); } -static void window_mapgen_base_paint() +static void window_mapgen_base_paint(rct_window *w, rct_drawpixelinfo *dpi) { 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); @@ -696,7 +681,8 @@ static void window_mapgen_base_paint() 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 }; + // The practical map size is 2 lower than the technical map size + uint16 mapSizeArgs[2] = { _mapSize - 2, _mapSize -2 }; 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; @@ -710,14 +696,10 @@ static void window_mapgen_base_paint() #pragma region Random page -static void window_mapgen_random_mouseup() +static void window_mapgen_random_mouseup(rct_window *w, int widgetIndex) { - rct_window * w; - short widgetIndex; mapgen_settings mapgenSettings; - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -735,8 +717,8 @@ static void window_mapgen_random_mouseup() mapgenSettings.wall = _randomTerrrain ? -1 : _wallTexture; mapgenSettings.trees = _placeTrees; - mapgenSettings.simplex_low = rand() % 4; - mapgenSettings.simplex_high = 12 + (rand() % (32 - 12)); + mapgenSettings.simplex_low = util_rand() % 4; + mapgenSettings.simplex_high = 12 + (util_rand() % (32 - 12)); mapgenSettings.simplex_base_freq = 1.75f; mapgenSettings.simplex_octaves = 6; @@ -765,11 +747,8 @@ static void window_mapgen_random_update(rct_window *w) widget_invalidate(w, WIDX_TAB_2); } -static void window_mapgen_random_invalidate() +static void window_mapgen_random_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); if (w->widgets != window_mapgen_page_widgets[WINDOW_MAPGEN_PAGE_RANDOM]) { @@ -787,13 +766,8 @@ static void window_mapgen_random_invalidate() window_mapgen_anchor_border_widgets(w); } -static void window_mapgen_random_paint() +static void window_mapgen_random_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_mapgen_draw_tab_images(dpi, w); } @@ -802,14 +776,10 @@ static void window_mapgen_random_paint() #pragma region Simplex page -static void window_mapgen_simplex_mouseup() +static void window_mapgen_simplex_mouseup(rct_window *w, int widgetIndex) { - rct_window * w; - short widgetIndex; mapgen_settings mapgenSettings; - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -819,6 +789,12 @@ static void window_mapgen_simplex_mouseup() case WIDX_TAB_3: window_mapgen_set_page(w, widgetIndex - WIDX_TAB_1); break; + case WIDX_SIMPLEX_MAP_SIZE: + ((uint16*)TextInputDescriptionArgs)[0] = MINIMUM_MAP_SIZE_PRACTICAL; + ((uint16*)TextInputDescriptionArgs)[1] = MAXIMUM_MAP_SIZE_PRACTICAL; + // Practical map size is 2 lower than the technical map size + window_text_input_open(w, WIDX_SIMPLEX_MAP_SIZE, 5130, 5131, 5182, _mapSize - 2, 4); + break; case WIDX_GENERATE: mapgenSettings.mapSize = _mapSize; @@ -877,11 +853,11 @@ static void window_mapgen_simplex_mousedown(int widgetIndex, rct_window *w, rct_ window_invalidate(w); break; case WIDX_SIMPLEX_MAP_SIZE_UP: - _mapSize = min(_mapSize + 1, 256); + _mapSize = min(_mapSize + 1, MAXIMUM_MAP_SIZE_TECHNICAL); window_invalidate(w); break; case WIDX_SIMPLEX_MAP_SIZE_DOWN: - _mapSize = max(_mapSize - 1, 16); + _mapSize = max(_mapSize - 1, MINIMUM_MAP_SIZE_TECHNICAL); window_invalidate(w); break; case WIDX_SIMPLEX_WATER_LEVEL_UP: @@ -897,7 +873,7 @@ static void window_mapgen_simplex_mousedown(int widgetIndex, rct_window *w, rct_ 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; + gDropdownHighlightedIndex = i; } window_dropdown_show_image( w->x + widget->left, w->y + widget->top, @@ -914,7 +890,7 @@ static void window_mapgen_simplex_mousedown(int widgetIndex, rct_window *w, rct_ 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; + gDropdownHighlightedIndex = i; } window_dropdown_show_image( w->x + widget->left, w->y + widget->top, @@ -929,18 +905,14 @@ static void window_mapgen_simplex_mousedown(int widgetIndex, rct_window *w, rct_ } } -static void window_mapgen_simplex_dropdown() +static void window_mapgen_simplex_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { 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); + dropdownIndex = gDropdownHighlightedIndex; type = (dropdownIndex == -1) ? _floorTexture : @@ -957,7 +929,7 @@ static void window_mapgen_simplex_dropdown() break; case WIDX_SIMPLEX_WALL_TEXTURE: if (dropdownIndex == -1) - dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); + dropdownIndex = gDropdownHighlightedIndex; type = (dropdownIndex == -1) ? _wallTexture : @@ -983,11 +955,8 @@ static void window_mapgen_simplex_update(rct_window *w) widget_invalidate(w, WIDX_TAB_3); } -static void window_mapgen_simplex_invalidate() +static void window_mapgen_simplex_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); if (w->widgets != window_mapgen_page_widgets[WINDOW_MAPGEN_PAGE_SIMPLEX]) { @@ -1002,13 +971,9 @@ static void window_mapgen_simplex_invalidate() window_mapgen_anchor_border_widgets(w); } -static void window_mapgen_simplex_paint() +static void window_mapgen_simplex_paint(rct_window *w, rct_drawpixelinfo *dpi) { 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); @@ -1025,9 +990,10 @@ static void window_mapgen_simplex_paint() 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 }; + // The practical map size is 2 lower than the technical map size + uint16 mapSizeArgs[2] = { _mapSize - 2, _mapSize - 2 }; 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); } diff --git a/src/windows/maze_construction.c b/src/windows/maze_construction.c new file mode 100644 index 0000000000..a3c992b76d --- /dev/null +++ b/src/windows/maze_construction.c @@ -0,0 +1,513 @@ +/***************************************************************************** + * 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 "../drawing/drawing.h" +#include "../game.h" +#include "../input.h" +#include "../interface/themes.h" +#include "../interface/viewport.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../ride/track.h" +#include "dropdown.h" + +#pragma region Widgets + +enum { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_MAZE_MODE_GROUPBOX, + WIDX_MAZE_BUILD_MODE = 6, + WIDX_MAZE_MOVE_MODE, + WIDX_MAZE_FILL_MODE, + WIDX_MAZE_DIRECTION_GROUPBOX = 23, + WIDX_MAZE_DIRECTION_NW, + WIDX_MAZE_DIRECTION_NE, + WIDX_MAZE_DIRECTION_SW, + WIDX_MAZE_DIRECTION_SE, + WIDX_MAZE_ENTRANCE = 29, + WIDX_MAZE_EXIT, +}; + +static rct_widget window_maze_construction_widgets[] = { + { WWT_FRAME, 0, 0, 165, 0, 199, 0xFFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 164, 1, 14, 896, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 153, 163, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_GROUPBOX, 0, 3, 162, 17, 71, STR_RIDE_CONSTRUCTION_MODE, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_FLATBTN, 1, 35, 66, 29, 60, 0x15C8, STR_RIDE_CONSTRUCTION_BUILD_MODE }, + { WWT_FLATBTN, 1, 67, 98, 29, 60, 0x15C9, STR_RIDE_CONSTRUCTION_MOVE_MODE }, + { WWT_FLATBTN, 1, 99, 130, 29, 60, 0x15CA, STR_RIDE_CONSTRUCTION_FILL_IN_MODE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_GROUPBOX, 0, 3, 162, 80, 166, STR_RIDE_CONSTRUCTION_BUILD, STR_NONE }, + { WWT_FLATBTN, 1, 83, 127, 96, 124, 0x1603, STR_RIDE_CONSTRUCTION_BUILD_MAZE_IN_THIS_DIRECTION_TIP }, + { WWT_FLATBTN, 1, 83, 127, 125, 153, 0x1604, STR_RIDE_CONSTRUCTION_BUILD_MAZE_IN_THIS_DIRECTION_TIP }, + { WWT_FLATBTN, 1, 38, 82, 125, 153, 0x1605, STR_RIDE_CONSTRUCTION_BUILD_MAZE_IN_THIS_DIRECTION_TIP }, + { WWT_FLATBTN, 1, 38, 82, 96, 124, 0x1606, STR_RIDE_CONSTRUCTION_BUILD_MAZE_IN_THIS_DIRECTION_TIP }, + { WWT_GROUPBOX, 0, 3, 162, 168, 195, 0xFFFFFFFF, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 9, 78, 178, 189, STR_RIDE_CONSTRUCTION_ENTRANCE, STR_RIDE_CONSTRUCTION_ENTRANCE_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 87, 156, 178, 189, STR_RIDE_CONSTRUCTION_EXIT, STR_RIDE_CONSTRUCTION_EXIT_TIP }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WWT_EMPTY, 0, 0, 0, 0, 0, 0xFFFFFFFF, STR_NONE }, + { WIDGETS_END } +}; + +#pragma endregion + +#pragma region Events + +static void window_maze_construction_close(rct_window *w); +static void window_maze_construction_mouseup(rct_window *w, int widgetIndex); +static void window_maze_construction_resize(rct_window *w); +static void window_maze_construction_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_maze_construction_update(rct_window *w); +static void window_maze_construction_toolupdate(rct_window* w, int widgetIndex, int x, int y); +static void window_maze_construction_tooldown(rct_window* w, int widgetIndex, int x, int y); +static void window_maze_construction_invalidate(rct_window *w); +static void window_maze_construction_paint(rct_window *w, rct_drawpixelinfo *dpi); + +// 0x993F6C +static rct_window_event_list window_maze_construction_events = { + window_maze_construction_close, + window_maze_construction_mouseup, + window_maze_construction_resize, + window_maze_construction_mousedown, + NULL, + NULL, + window_maze_construction_update, + NULL, + NULL, + window_maze_construction_toolupdate, + window_maze_construction_tooldown, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_maze_construction_invalidate, + window_maze_construction_paint, + NULL +}; + +#pragma endregion + +static void window_maze_construction_construct(int direction); + +/** + * + * rct2: 0x006CB481 + */ +rct_window *window_maze_construction_open() +{ + rct_window *w = window_create(0, 29, 166, 200, &window_maze_construction_events, WC_RIDE_CONSTRUCTION, WF_NO_AUTO_CLOSE); + w->widgets = window_maze_construction_widgets; + w->enabled_widgets = 0x6F0001C4; + + window_init_scroll_widgets(w); + colour_scheme_update(w); + + w->number = _currentRideIndex; + + window_push_others_right(w); + show_gridlines(); + return w; +} + +/** + * + * rct2: 0x006CD811 + */ +static void window_maze_construction_close(rct_window *w) +{ + sub_6C9627(); + viewport_set_visibility(0); + + 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 rideIndex = _currentRideIndex; + rct_ride* ride = GET_RIDE(rideIndex); + if (ride->overall_view == 0xFFFF) { + int savedPausedState = RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8); + RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) = 0; + game_do_command(0, 9, 0, rideIndex, GAME_COMMAND_DEMOLISH_RIDE, 0, 0); + RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) = savedPausedState; + } else { + window_ride_main_open(rideIndex); + } +} + +static void window_maze_construction_entrance_mouseup(rct_window *w, int widgetIndex){ + if (tool_set(w, widgetIndex, 12)) + return; + + RCT2_GLOBAL(0x00F44191, uint8) = widgetIndex == WIDX_MAZE_ENTRANCE ? 0 : 1; + RCT2_GLOBAL(0x00F44192, uint8) = (uint8)w->number; + RCT2_GLOBAL(0x00F44193, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + + sub_6C9627(); + + // ??? + uint8 old_state = _rideConstructionState; + _rideConstructionState = 5; + if (old_state != 5) + _rideConstructionState = old_state; + window_maze_construction_update_pressed_widgets(); +} + +/** + * + * rct2: 0x006CD461 + */ +static void window_maze_construction_mouseup(rct_window *w, int widgetIndex) +{ + switch (widgetIndex){ + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_MAZE_ENTRANCE: + case WIDX_MAZE_EXIT: + window_maze_construction_entrance_mouseup(w, widgetIndex); + break; + case WIDX_MAZE_DIRECTION_NW: + case WIDX_MAZE_DIRECTION_NE: + case WIDX_MAZE_DIRECTION_SE: + case WIDX_MAZE_DIRECTION_SW: + window_maze_construction_construct( + ((widgetIndex - WIDX_MAZE_DIRECTION_NW) - get_current_rotation()) & 3 + ); + break; + } +} + +/** + * + * rct2: 0x006CD623 + */ +static void window_maze_construction_resize(rct_window *w) +{ + uint64 disabledWidgets = 0; + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_PLACE) { + disabledWidgets |= ( + (1ULL << WIDX_MAZE_BUILD_MODE) | + (1ULL << WIDX_MAZE_MOVE_MODE) | + (1ULL << WIDX_MAZE_FILL_MODE) | + (1ULL << WIDX_MAZE_DIRECTION_NW) | + (1ULL << WIDX_MAZE_DIRECTION_NE) | + (1ULL << WIDX_MAZE_DIRECTION_SW) | + (1ULL << WIDX_MAZE_DIRECTION_SE) + ); + } + + // Set and invalidate the changed widgets + uint64 currentDisabledWidgets = w->disabled_widgets; + if (currentDisabledWidgets == disabledWidgets) + return; + + for (int i = 0; i < 64; i++) { + if ((disabledWidgets & (1ULL << i)) != (currentDisabledWidgets & (1ULL << i))) { + widget_invalidate(w, i); + } + } + w->disabled_widgets = disabledWidgets; +} + +/** + * + * rct2: 0x006CD48C + */ +static void window_maze_construction_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + switch (widgetIndex) { + case WIDX_MAZE_BUILD_MODE: + _rideConstructionState = RIDE_CONSTRUCTION_STATE_MAZE_BUILD; + window_maze_construction_update_pressed_widgets(); + break; + case WIDX_MAZE_MOVE_MODE: + _rideConstructionState = RIDE_CONSTRUCTION_STATE_MAZE_MOVE; + window_maze_construction_update_pressed_widgets(); + break; + case WIDX_MAZE_FILL_MODE: + _rideConstructionState = RIDE_CONSTRUCTION_STATE_MAZE_FILL; + window_maze_construction_update_pressed_widgets(); + break; + } +} + +/** + * + * rct2: 0x006CD767 + */ +static void window_maze_construction_update(rct_window *w) +{ + switch (_rideConstructionState) { + case RIDE_CONSTRUCTION_STATE_PLACE: + if (!widget_is_active_tool(w, WIDX_MAZE_DIRECTION_GROUPBOX)) { + window_close(w); + return; + } + break; + case RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT: + if (!widget_is_active_tool(w, WIDX_MAZE_ENTRANCE) && !widget_is_active_tool(w, WIDX_MAZE_EXIT)) { + _rideConstructionState = RCT2_GLOBAL(0x00F440CC, uint8); + window_maze_construction_update_pressed_widgets(); + } + break; + } + + switch (_rideConstructionState) { + case RIDE_CONSTRUCTION_STATE_FRONT: + case RIDE_CONSTRUCTION_STATE_BACK: + case RIDE_CONSTRUCTION_STATE_SELECTED: + if ( + (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint8) & INPUT_FLAG_TOOL_ACTIVE) && + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) == WC_RIDE_CONSTRUCTION + ) { + tool_cancel(); + } + break; + } + sub_6C94D8(); +} + +/** + * + * rct2: 0x006CD63E + */ +static void window_maze_construction_toolupdate(rct_window* w, int widgetIndex, int x, int y) +{ + switch (widgetIndex){ + case WIDX_MAZE_DIRECTION_GROUPBOX: + ride_construction_toolupdate_construct(x, y); + break; + case WIDX_MAZE_ENTRANCE: + case WIDX_MAZE_EXIT: + ride_construction_toolupdate_entrance_exit(x, y); + break; + } +} + +/** + * + * rct2: 0x006C825F + */ +static void window_maze_construction_entrance_tooldown(int x, int y, rct_window* w){ + sub_6C9627(); + + map_invalidate_selection_rect(); + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~((1 << 0) | (1 << 2)); + + int direction = 0; + ride_get_entrance_or_exit_position_from_screen_position(x, y, &x, &y, &direction); + + if (RCT2_GLOBAL(0x00F44194, uint8) == 0xFF) + return; + + uint8 rideIndex = RCT2_GLOBAL(0x00F44192, uint8); + uint8 is_exit = RCT2_GLOBAL(0x00F44191, uint8); + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = is_exit ? 1144 : 1145; + + money32 cost = game_do_command( + x, + GAME_COMMAND_FLAG_APPLY | ((direction ^ 2) << 8), + y, + rideIndex | (is_exit << 8), + GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, + RCT2_GLOBAL(0x00F44193, uint8), + 0); + + if (cost == MONEY32_UNDEFINED) + return; + + audio_play_sound_at_location( + SOUND_PLACE_ITEM, + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16)); + + rct_ride* ride = GET_RIDE(rideIndex); + if (ride_are_all_possible_entrances_and_exits_built(ride)){ + tool_cancel(); + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_15)) + window_close(w); + } + else{ + RCT2_GLOBAL(0x00F44191, uint8) = is_exit ^ 1; + window_invalidate_by_class(WC_RIDE_CONSTRUCTION); + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint8) = is_exit ? WIDX_MAZE_ENTRANCE : WIDX_MAZE_EXIT; + } +} + +/** + * + * rct2: 0x006CD65D + */ +static void window_maze_construction_tooldown(rct_window* w, int widgetIndex, int x, int y) +{ + switch (widgetIndex){ + case WIDX_MAZE_DIRECTION_GROUPBOX: + ride_construction_tooldown_construct(x, y); + break; + case WIDX_MAZE_ENTRANCE: + case WIDX_MAZE_EXIT: + window_maze_construction_entrance_tooldown(x, y, w); + break; + } +} + +/** + * + * rct2: 0x006CD435 + */ +static void window_maze_construction_invalidate(rct_window *w) +{ + rct_ride *ride = GET_RIDE(_currentRideIndex); + + // Set window title arguments + RCT2_GLOBAL(0x013CE956, rct_string_id) = ride->name; + RCT2_GLOBAL(0x013CE958, uint32) = ride->name_arguments; +} + +/** + * + * rct2: 0x006CD45B + */ +static void window_maze_construction_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ + window_draw_widgets(w, dpi); +} + +/** + * + * rct2: 0x006CD887 + */ +void window_maze_construction_update_pressed_widgets() +{ + rct_window *w; + + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w == NULL) + return; + + uint64 pressedWidgets = w->pressed_widgets; + pressedWidgets &= ~(1ULL << WIDX_MAZE_BUILD_MODE); + pressedWidgets &= ~(1ULL << WIDX_MAZE_MOVE_MODE); + pressedWidgets &= ~(1ULL << WIDX_MAZE_FILL_MODE); + + switch (_rideConstructionState) { + case RIDE_CONSTRUCTION_STATE_MAZE_BUILD: + pressedWidgets |= (1ULL << WIDX_MAZE_BUILD_MODE); + break; + case RIDE_CONSTRUCTION_STATE_MAZE_MOVE: + pressedWidgets |= (1ULL << WIDX_MAZE_MOVE_MODE); + break; + case RIDE_CONSTRUCTION_STATE_MAZE_FILL: + pressedWidgets |= (1ULL << WIDX_MAZE_FILL_MODE); + break; + } + + w->pressed_widgets = pressedWidgets; + window_invalidate(w); +} + +/** + * + * rct2: 0x006CD4AB + */ +static void window_maze_construction_construct(int direction) +{ + int x, y, z, flags, mode; + + sub_6C9627(); + + x = _currentTrackBeginX + (TileDirectionDelta[direction].x / 2); + y = _currentTrackBeginY + (TileDirectionDelta[direction].y / 2); + z = _currentTrackBeginZ; + switch (_rideConstructionState) { + case RIDE_CONSTRUCTION_STATE_MAZE_BUILD: + mode = 0; + flags = 1; + break; + case RIDE_CONSTRUCTION_STATE_MAZE_MOVE: + mode = 1; + flags = 1 | 8; + break; + default: + case RIDE_CONSTRUCTION_STATE_MAZE_FILL: + mode = 2; + flags = 1 | 8; + break; + } + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; + money32 cost = game_do_command( + x, + flags | (direction << 8), + y, + _currentRideIndex | (mode << 8), + GAME_COMMAND_SET_MAZE_TRACK, + z, + 0 + ); + if (cost == MONEY32_UNDEFINED) { + return; + } + + _currentTrackBeginX = x; + _currentTrackBeginY = y; + if (_rideConstructionState != 7) { + audio_play_sound_at_location(SOUND_PLACE_ITEM, x, y, z); + } +} diff --git a/src/windows/music_credits.c b/src/windows/music_credits.c index 1c628bde81..8908fc8520 100644 --- a/src/windows/music_credits.c +++ b/src/windows/music_credits.c @@ -38,39 +38,38 @@ rct_widget window_music_credits_widgets[] = { { WIDGETS_END }, }; -static void window_music_credits_emptysub() { } -static void window_music_credits_mouseup(); -static void window_music_credits_scrollgetsize(); -static void window_music_credits_paint(); -static void window_music_credits_scrollpaint(); +static void window_music_credits_mouseup(rct_window *w, int widgetIndex); +static void window_music_credits_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_music_credits_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_music_credits_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void* window_music_credits_events[] = { - window_music_credits_emptysub, +static rct_window_event_list window_music_credits_events = { + NULL, window_music_credits_mouseup, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_music_credits_scrollgetsize, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, - window_music_credits_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_music_credits_paint, window_music_credits_scrollpaint }; @@ -91,7 +90,7 @@ void window_music_credits_open() window = window_create_centred( 510, 314, - (uint32*)window_music_credits_events, + &window_music_credits_events, WC_MUSIC_CREDITS, 0 ); @@ -103,20 +102,15 @@ void window_music_credits_open() window->colours[0] = 7; window->colours[1] = 7; window->colours[2] = 7; - + } /** * * rct2: 0x0066DB2C */ -static void window_music_credits_mouseup() +static void window_music_credits_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -128,26 +122,17 @@ static void window_music_credits_mouseup() * * rct2: 0x0066DB37 */ -static void window_music_credits_scrollgetsize() +static void window_music_credits_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - int width, height; - - width = 0; - height = 560; - window_scrollsize_set_registers(width, height); + *height = 560; } /** * * rct2: 0x0066D7B9 */ -static void window_music_credits_paint() +static void window_music_credits_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); } @@ -155,12 +140,8 @@ static void window_music_credits_paint() * * rct2: 0x0066D7BF */ -static void window_music_credits_scrollpaint() +static void window_music_credits_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { - rct_window *w; - rct_drawpixelinfo *dpi; - window_paint_get_registers(w, dpi); - int x = 245; int y = 2; @@ -191,5 +172,5 @@ static void window_music_credits_scrollpaint() y += 10; string += 1; } - + } \ No newline at end of file diff --git a/src/windows/network_status.c b/src/windows/network_status.c new file mode 100644 index 0000000000..1aadcf2d51 --- /dev/null +++ b/src/windows/network_status.c @@ -0,0 +1,181 @@ +/***************************************************************************** + * 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 "../interface/themes.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../util/util.h" +#include "../network/network.h" + +char _password[33]; + +enum WINDOW_NETWORK_STATUS_WIDGET_IDX { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_PASSWORD +}; + +static rct_widget window_network_status_widgets[] = { + { WWT_FRAME, 0, 0, 340, 0, 90, 0x0FFFFFFFF, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, 338, 1, 14, STR_NONE, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, 327, 337, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button + { WIDGETS_END }, +}; + +static char window_network_status_text[1024]; + +static void window_network_status_mouseup(rct_window *w, int widgetIndex); +static void window_network_status_update(rct_window *w); +static void window_network_status_textinput(rct_window *w, int widgetIndex, char *text); +static void window_network_status_invalidate(rct_window *w); +static void window_network_status_paint(rct_window *w, rct_drawpixelinfo *dpi); + +static rct_window_event_list window_network_status_events = { + NULL, + window_network_status_mouseup, + NULL, + NULL, + NULL, + NULL, + window_network_status_update, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_network_status_textinput, + NULL, + NULL, + NULL, + NULL, + NULL, + window_network_status_invalidate, + window_network_status_paint, + NULL +}; + +void window_network_status_open(const char* text) +{ + rct_window* window; + + safe_strncpy(window_network_status_text, text, sizeof(window_network_status_text)); + + // Check if window is already open + window = window_bring_to_front_by_class(WC_NETWORK_STATUS); + if (window != NULL) + return; + + window = window_create_centred(320, 90, &window_network_status_events, WC_NETWORK_STATUS, WF_10 | WF_TRANSPARENT); + + window->widgets = window_network_status_widgets; + window->enabled_widgets = 1 << WIDX_CLOSE; + window_init_scroll_widgets(window); + window->no_list_items = 0; + window->selected_list_item = -1; + window->frame_no = 0; + window->min_width = 320; + window->min_height = 90; + window->max_width = window->min_width; + window->max_height = window->min_height; + + window->page = 0; + window->list_information_type = 0; + window->colours[0] = 7; + window->colours[1] = 7; + window->colours[2] = 7; +} + +void window_network_status_close() +{ + window_close_by_class(WC_NETWORK_STATUS); +} + +void window_network_status_open_password() +{ + rct_window* window; + window = window_bring_to_front_by_class(WC_NETWORK_STATUS); + if (window == NULL) + return; + + window_text_input_raw_open(window, WIDX_PASSWORD, STR_PASSWORD_REQUIRED, STR_PASSWORD_REQUIRED_DESC, _password, 32); +} + +static void window_network_status_mouseup(rct_window *w, int widgetIndex) +{ + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + } +} + +static void window_network_status_update(rct_window *w) +{ + widget_invalidate(w, WIDX_BACKGROUND); +} + +static void window_network_status_textinput(rct_window *w, int widgetIndex, char *text) +{ + strcpy(_password, ""); + switch (widgetIndex) { + case WIDX_PASSWORD: + if (text != NULL) + safe_strncpy(_password, text, sizeof(_password)); + break; + } + if (text == NULL) { + network_shutdown_client(); + } else { + network_send_password(_password); + } +} + +static void window_network_status_invalidate(rct_window *w) +{ + window_network_status_widgets[WIDX_BACKGROUND].right = w->width - 1; + window_network_status_widgets[WIDX_BACKGROUND].bottom = w->height - 1; + window_network_status_widgets[WIDX_TITLE].right = w->width - 2; + window_network_status_widgets[WIDX_CLOSE].left = w->width - 2 - 0x0B; + window_network_status_widgets[WIDX_CLOSE].right = w->width - 2 - 0x0B + 0x0A; +} + +static void window_network_status_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ + window_draw_widgets(w, dpi); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + char buffer[sizeof(window_network_status_text) + 10]; + char* lineCh = buffer; + lineCh = utf8_write_codepoint(lineCh, FORMAT_BLACK); + strcpy(lineCh, window_network_status_text); + gfx_clip_string(buffer, 230); + int x = w->x + (w->width / 2); + int y = w->y + (w->height / 2); + x -= gfx_get_string_width(buffer) / 2; + gfx_draw_string(dpi, buffer, 0, x, y); +} diff --git a/src/windows/new_campaign.c b/src/windows/new_campaign.c index f64a894d51..611a8cb1f2 100644 --- a/src/windows/new_campaign.c +++ b/src/windows/new_campaign.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 . *****************************************************************************/ @@ -26,6 +26,7 @@ #include "../interface/window.h" #include "../management/marketing.h" #include "../ride/ride.h" +#include "../ride/ride_data.h" #include "dropdown.h" #include "../interface/themes.h" @@ -61,42 +62,41 @@ static rct_widget window_new_campaign_widgets[] = { }; -static void window_new_campaign_emptysub() { } -static void window_new_campaign_mouseup(); +static void window_new_campaign_mouseup(rct_window *w, int widgetIndex); static void window_new_campaign_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_new_campaign_dropdown(); -static void window_new_campaign_invalidate(); -static void window_new_campaign_paint(); +static void window_new_campaign_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); +static void window_new_campaign_invalidate(rct_window *w); +static void window_new_campaign_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void* window_new_campaign_events[] = { - window_new_campaign_emptysub, +static rct_window_event_list window_new_campaign_events = { + NULL, window_new_campaign_mouseup, - window_new_campaign_emptysub, + NULL, window_new_campaign_mousedown, window_new_campaign_dropdown, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, - window_new_campaign_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_new_campaign_invalidate, window_new_campaign_paint, - window_new_campaign_emptysub + NULL }; uint8 window_new_campaign_rides[MAX_RIDES]; @@ -126,7 +126,7 @@ int ride_name_compare(const void *a, const void *b) } /** - * + * * rct2: 0x0069E16F */ void window_new_campaign_open(sint16 campaignType) @@ -134,7 +134,7 @@ void window_new_campaign_open(sint16 campaignType) rct_window *w; rct_ride *ride; int i, numApplicableRides; - + w = window_bring_to_front_by_class(WC_NEW_CAMPAIGN); if (w != NULL) { if (w->campaign.campaign_type == campaignType) @@ -143,7 +143,7 @@ void window_new_campaign_open(sint16 campaignType) window_close(w); } - w = window_create_auto_pos(350, 107, (uint32*)window_new_campaign_events, WC_NEW_CAMPAIGN, 0); + w = window_create_auto_pos(350, 107, &window_new_campaign_events, WC_NEW_CAMPAIGN, 0); w->widgets = window_new_campaign_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | @@ -172,7 +172,7 @@ void window_new_campaign_open(sint16 campaignType) numApplicableRides = 0; window_new_campaign_rides[0] = 255; FOR_ALL_RIDES(i, ride) { - 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)) + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP | RIDE_TYPE_FLAG_SELLS_FOOD | RIDE_TYPE_FLAG_SELLS_DRINKS | RIDE_TYPE_FLAG_IS_BATHROOM)) window_new_campaign_rides[numApplicableRides++] = i; } @@ -189,7 +189,7 @@ void window_new_campaign_open(sint16 campaignType) } /** - * + * * rct2: 0x0069E320 */ static void window_new_campaign_get_shop_items() @@ -208,7 +208,7 @@ static void window_new_campaign_get_shop_items() // Remove certain items? items &= 0x0011FF78036BA3E0; - // + // numItems = 0; for (i = 0; i < 64; i++) if (items & (1LL << i)) @@ -217,16 +217,11 @@ static void window_new_campaign_get_shop_items() } /** - * + * * rct2: 0x0069E50B */ -static void window_new_campaign_mouseup() +static void window_new_campaign_mouseup(rct_window *w, int widgetIndex) { - rct_window *w; - short widgetIndex; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -239,7 +234,7 @@ static void window_new_campaign_mouseup() } /** - * + * * rct2: 0x0069E51C */ static void window_new_campaign_mousedown(int widgetIndex, rct_window *w, rct_widget* widget) @@ -258,12 +253,8 @@ static void window_new_campaign_mousedown(int widgetIndex, rct_window *w, rct_wi if (window_new_campaign_shop_items[i] == 255) break; - rct_string_id itemStringId = window_new_campaign_shop_items[i] + 2016; - if (itemStringId >= 2048) - itemStringId += 96; - gDropdownItemsFormat[i] = 1142; - gDropdownItemsArgs[i] = itemStringId; + gDropdownItemsArgs[i] = ShopItemStringIds[window_new_campaign_shop_items[i]].plural; numItems++; } @@ -300,8 +291,9 @@ static void window_new_campaign_mousedown(int widgetIndex, rct_window *w, rct_wi ); } break; + // In RCT2, the maximum was 6 weeks case WIDX_WEEKS_INCREASE_BUTTON: - w->campaign.no_weeks = min(w->campaign.no_weeks + 1, 6); + w->campaign.no_weeks = min(w->campaign.no_weeks + 1, 12); window_invalidate(w); break; case WIDX_WEEKS_DECREASE_BUTTON: @@ -312,24 +304,16 @@ static void window_new_campaign_mousedown(int widgetIndex, rct_window *w, rct_wi } /** - * + * * rct2: 0x0069E537 */ -static void window_new_campaign_dropdown() +static void window_new_campaign_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - rct_window *w; - short widgetIndex, dropdownIndex; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (widgetIndex != WIDX_RIDE_DROPDOWN_BUTTON) return; if (w->campaign.campaign_type == ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE) { - rct_string_id itemStringId = (uint16)gDropdownItemsArgs[dropdownIndex] - 2016; - if (itemStringId >= 32) - itemStringId -= 96; - w->campaign.ride_id = itemStringId; + w->campaign.ride_id = window_new_campaign_shop_items[dropdownIndex]; } else { w->campaign.ride_id = window_new_campaign_rides[dropdownIndex]; } @@ -338,14 +322,11 @@ static void window_new_campaign_dropdown() } /** - * + * * rct2: 0x0069E397 */ -static void window_new_campaign_invalidate() +static void window_new_campaign_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); window_new_campaign_widgets[WIDX_RIDE_LABEL].type = WWT_EMPTY; @@ -362,7 +343,7 @@ static void window_new_campaign_invalidate() if (w->campaign.ride_id != SELECTED_RIDE_UNDEFINED) { rct_ride *ride = GET_RIDE(w->campaign.ride_id); window_new_campaign_widgets[WIDX_RIDE_DROPDOWN].image = ride->name; - RCT2_GLOBAL(0x013CE952, uint32) = ride->name_arguments; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) = ride->name_arguments; } break; case ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE: @@ -371,16 +352,13 @@ static void window_new_campaign_invalidate() window_new_campaign_widgets[WIDX_RIDE_DROPDOWN_BUTTON].type = WWT_DROPDOWN_BUTTON; window_new_campaign_widgets[WIDX_RIDE_LABEL].image = STR_MARKETING_ITEM; if (w->campaign.ride_id != SELECTED_RIDE_UNDEFINED) { - rct_string_id itemStringId = w->campaign.ride_id + 2016; - if (itemStringId >= 2048) - itemStringId += 96; - window_new_campaign_widgets[WIDX_RIDE_DROPDOWN].image = itemStringId; + window_new_campaign_widgets[WIDX_RIDE_DROPDOWN].image = ShopItemStringIds[w->campaign.ride_id].plural; } break; } - // Set current number of weeks spinner - window_new_campaign_widgets[WIDX_WEEKS_SPINNER].image = (STR_MARKETING_1_WEEK - 1) + w->campaign.no_weeks; + // Set current number of weeks spinner (moved to paint due to required parameter) + window_new_campaign_widgets[WIDX_WEEKS_SPINNER].image = STR_NONE; // Enable / disable start button based on ride dropdown w->disabled_widgets &= ~(1 << WIDX_START_BUTTON); @@ -389,19 +367,26 @@ static void window_new_campaign_invalidate() } /** - * + * * rct2: 0x0069E493 */ -static void window_new_campaign_paint() +static void window_new_campaign_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; int x, y; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); + // Number of weeks + rct_widget *spinnerWidget = &window_new_campaign_widgets[WIDX_WEEKS_SPINNER]; + gfx_draw_string_left( + dpi, + w->campaign.no_weeks == 1 ? STR_MARKETING_1_WEEK : STR_X_WEEKS, + &w->campaign.no_weeks, + w->colours[0], + w->x + spinnerWidget->left + 1, + w->y + spinnerWidget->top + ); + x = w->x + 14; y = w->y + 60; diff --git a/src/windows/new_ride.c b/src/windows/new_ride.c index 99518a8d95..fc9d702cc6 100644 --- a/src/windows/new_ride.c +++ b/src/windows/new_ride.c @@ -24,6 +24,8 @@ #include "../game.h" #include "../management/news_item.h" #include "../management/research.h" +#include "../object.h" +#include "../rct1.h" #include "../ride/ride.h" #include "../localisation/localisation.h" #include "../world/scenery.h" @@ -164,6 +166,7 @@ enum { WIDX_TAB_6, WIDX_TAB_7, WIDX_RIDE_LIST, + WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP, WIDX_LAST_DEVELOPMENT_GROUP, WIDX_LAST_DEVELOPMENT_BUTTON, @@ -186,7 +189,7 @@ static rct_widget window_new_ride_widgets[] = { { WWT_GROUPBOX, 2, 3, 292, 47, 116, STR_CURRENTLY_IN_DEVELOPMENT, STR_NONE }, { WWT_GROUPBOX, 2, 3, 292, 124, 188, STR_LAST_DEVELOPMENT, STR_NONE }, { WWT_FLATBTN, 2, 265, 288, 161, 184, 0xFFFFFFFF, STR_RESEARCH_SHOW_DETAILS_TIP }, - { WWT_FLATBTN, 2, 265, 288, 68, 91, 5190, STR_FINANCES_RESEARCH }, + { WWT_FLATBTN, 2, 265, 288, 68, 91, 5190, STR_FINANCES_RESEARCH_TIP }, { WIDGETS_END }, }; @@ -194,46 +197,44 @@ static rct_widget window_new_ride_widgets[] = { #pragma region Events -static void window_new_ride_emptysub() { } - -static void window_new_ride_mouseup(); +static void window_new_ride_mouseup(rct_window *w, int widgetIndex); static void window_new_ride_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); static void window_new_ride_update(rct_window *w); -static void window_new_ride_scrollgetsize(); -static void window_new_ride_scrollmousedown(); -static void window_new_ride_scrollmouseover(); -static void window_new_ride_tooltip(); -static void window_new_ride_invalidate(); -static void window_new_ride_paint(); -static void window_new_ride_scrollpaint(); +static void window_new_ride_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_new_ride_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_new_ride_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_new_ride_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_new_ride_invalidate(rct_window *w); +static void window_new_ride_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_new_ride_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); // 0x0098E354 -static void* window_new_ride_events[] = { - window_new_ride_emptysub, +static rct_window_event_list window_new_ride_events = { + NULL, window_new_ride_mouseup, - window_new_ride_emptysub, + NULL, window_new_ride_mousedown, - window_new_ride_emptysub, - window_new_ride_emptysub, + NULL, + NULL, window_new_ride_update, - window_new_ride_emptysub, - window_new_ride_emptysub, - window_new_ride_emptysub, - window_new_ride_emptysub, - window_new_ride_emptysub, - window_new_ride_emptysub, - window_new_ride_emptysub, - window_new_ride_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_new_ride_scrollgetsize, window_new_ride_scrollmousedown, - window_new_ride_emptysub, + NULL, window_new_ride_scrollmouseover, - window_new_ride_emptysub, - window_new_ride_emptysub, - window_new_ride_emptysub, + NULL, + NULL, + NULL, window_new_ride_tooltip, - window_new_ride_emptysub, - window_new_ride_emptysub, + NULL, + NULL, window_new_ride_invalidate, window_new_ride_paint, window_new_ride_scrollpaint @@ -278,8 +279,9 @@ void window_new_ride_init_vars() { } /** + * rct2: 0x006B6F3E * - * rct2: 0x006B6F3E + * Note: When the user has selection by track type enabled, the categories are determined by the track type, not those in the rct_ride_type. */ static void window_new_ride_populate_list() { @@ -295,6 +297,14 @@ static void window_new_ride_populate_list() if (rideType == RIDE_TYPE_NULL) continue; + if(gConfigInterface.select_by_track_type) { + if(gRideCategories[rideType]!=currentCategory) + continue; + } + + char preferredVehicleName[9]; + strcpy(preferredVehicleName," "); + quadIndex = rideType >> 5; bitIndex = rideType & 0x1F; if (RCT2_ADDRESS(0x01357404, uint32)[quadIndex] & (1 << bitIndex)) { @@ -304,9 +314,13 @@ static void window_new_ride_populate_list() // For each ride entry for this ride type while (*rideEntryIndexPtr != 255) { uint8 rideEntryIndex = *rideEntryIndexPtr++; + char rideEntryName[9]; + memcpy(rideEntryName,object_entry_groups[OBJECT_TYPE_RIDE].entries[rideEntryIndex].name,8); + rideEntryName[8]=0; quadIndex = rideEntryIndex >> 5; bitIndex = rideEntryIndex & 0x1F; + // Skip if vehicle type is not invented yet if (!(RCT2_ADDRESS(0x01357424, uint32)[quadIndex] & (1 << bitIndex))) continue; @@ -314,10 +328,27 @@ static void window_new_ride_populate_list() rct_ride_type *rideEntry = rideEntries[rideEntryIndex]; // Check if ride is in this category - if (currentCategory != rideEntry->category[0] && currentCategory != rideEntry->category[1]) + if (!gConfigInterface.select_by_track_type && (currentCategory != rideEntry->category[0] && currentCategory != rideEntry->category[1])) continue; - if (rideEntry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE) { + // Skip if the vehicle isn't the preferred vehicle for this generic track type + if(gConfigInterface.select_by_track_type && (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) || rideTypeShouldLoseSeparateFlag(rideEntry))) { + if(strcmp(preferredVehicleName," \0")==0) { + strcpy(preferredVehicleName,rideEntryName); + preferredVehicleName[8]=0; + } + else { + if(vehicleIsHigherInHierarchy(rideType,preferredVehicleName,rideEntryName)) { + strcpy(preferredVehicleName,rideEntryName); + preferredVehicleName[8]=0; + } + else { + continue; + } + } + } + + if ((rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) && !rideTypeShouldLoseSeparateFlag(rideEntry)) { dh &= ~4; nextListItem->type = rideType; nextListItem->entry_index = rideEntryIndex; @@ -349,9 +380,10 @@ static void window_new_ride_populate_list() */ static void window_new_ride_scroll_to_focused_ride(rct_window *w) { - int scrollWidth, scrollHeight; + int scrollWidth = 0; + int scrollHeight = 0; 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]; int focusRideType = RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_RIDE_LIST_HIGHLIGHTED_ITEM, uint16)[_window_new_ride_current_tab]; @@ -390,7 +422,7 @@ rct_window *window_new_ride_open() 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, WF_10); + w = window_create_auto_pos(601, 370, &window_new_ride_events, WC_CONSTRUCT_RIDE, WF_10); w->widgets = window_new_ride_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | @@ -411,13 +443,13 @@ rct_window *window_new_ride_open() w->new_ride.highlighted_ride_id = -1; _lastTrackDesignCountRideType.type = 255; _lastTrackDesignCountRideType.entry_index = 255; - + window_new_ride_populate_list(); - + w->new_ride.highlighted_ride_id = RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_RIDE_LIST_HIGHLIGHTED_ITEM, sint16)[_window_new_ride_current_tab]; if (w->new_ride.highlighted_ride_id == -1) w->new_ride.highlighted_ride_id = RCT2_GLOBAL(0x00F43523, sint16); - + w->width = 1; window_new_ride_refresh_widget_sizing(w); window_new_ride_scroll_to_focused_ride(w); @@ -428,7 +460,7 @@ rct_window *window_new_ride_open() 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; @@ -448,12 +480,16 @@ void window_new_ride_focus(ride_list_item rideItem) return; rideType = GET_RIDE_ENTRY(rideItem.entry_index); - window_new_ride_set_page(w, rideType->category[0]); + + if(!gConfigInterface.select_by_track_type) + window_new_ride_set_page(w, rideType->category[0]); + else + window_new_ride_set_page(w, gRideCategories[rideType->ride_type[0]]); ride_list_item *listItem = (ride_list_item*)0x00F43523; while (listItem->type != RIDE_TYPE_NULL) { if (listItem->type == rideItem.type && listItem->entry_index == rideItem.entry_index) { - RCT2_GLOBAL(0x00F43825, uint8) = rideItem.type; + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_RIDE_LIST_HIGHLIGHTED_ITEM, uint8) = rideItem.type; RCT2_GLOBAL(0x00F43826, uint8) = rideItem.entry_index; w->new_ride.highlighted_ride_id = (rideItem.entry_index << 8) | rideItem.type; window_new_ride_scroll_to_focused_ride(w); @@ -576,13 +612,8 @@ static void window_new_ride_draw_tab_images(rct_drawpixelinfo *dpi, rct_window * * * rct2: 0x006B6B38 */ -static void window_new_ride_mouseup() +static void window_new_ride_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -626,34 +657,26 @@ static void window_new_ride_update(rct_window *w) * * rct2: 0x006B6BC9 */ -static void window_new_ride_scrollgetsize() +static void window_new_ride_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { ride_list_item *listItem = (ride_list_item*)0x00F43523; - int width, height; int count = 0; while (listItem->type != 255 || listItem->entry_index != 255) { count++; listItem++; } - width = 0; - height = ((count + 4) / 5) * 116; - - window_scrollsize_set_registers(width, height); + *height = ((count + 4) / 5) * 116; } /** * * rct2: 0x006B6C89 */ -static void window_new_ride_scrollmousedown() +static void window_new_ride_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) { - short x, y, scrollIndex; - rct_window *w; ride_list_item item; - window_scrollmouse_get_registers(w, scrollIndex, x, y); - // 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;*/ @@ -665,7 +688,7 @@ static void window_new_ride_scrollmousedown() RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_RIDE_LIST_HIGHLIGHTED_ITEM, ride_list_item)[_window_new_ride_current_tab] = item; w->new_ride.selected_ride_id = *((sint16*)&item); - sound_play_panned(SOUND_CLICK_1, w->x + (w->width / 2), 0, 0, 0); + audio_play_sound_panned(SOUND_CLICK_1, w->x + (w->width / 2), 0, 0, 0); w->new_ride.selected_ride_countdown = 8; window_invalidate(w); } @@ -674,14 +697,10 @@ static void window_new_ride_scrollmousedown() * * rct2: 0x006B6C51 */ -static void window_new_ride_scrollmouseover() +static void window_new_ride_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) { - short x, y, scrollIndex; - rct_window *w; ride_list_item item; - window_scrollmouse_get_registers(w, scrollIndex, x, y); - if (w->new_ride.selected_ride_id != -1) return; @@ -699,20 +718,17 @@ static void window_new_ride_scrollmouseover() * * rct2: 0x006B6BBF */ -static void window_new_ride_tooltip() +static void window_new_ride_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) { - RCT2_GLOBAL(0x013CE952, uint16) = 3159; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = 3159; } /** * * rct2: 0x006B6819 */ -static void window_new_ride_invalidate() +static void window_new_ride_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); window_new_ride_set_pressed_tab(w); @@ -736,98 +752,17 @@ static void window_new_ride_invalidate() * * rct2: 0x006B689B */ -static void window_new_ride_paint() +static void window_new_ride_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_new_ride_draw_tab_images(dpi, w); if (_window_new_ride_current_tab != WINDOW_NEW_RIDE_PAGE_RESEARCH) { ride_list_item item = *((ride_list_item*)&w->new_ride.highlighted_ride_id); - if (item.type == 255 && item.entry_index == 255) - return; - - window_new_ride_paint_ride_information(w, dpi, item, w->x + 3, w->y + w->height - 52, w->width - 6); - return; - } - - int x = w->x + 10; - int y = w->y + window_new_ride_widgets[WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP].top + 12; - rct_string_id stringId; - - 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; - - // 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; - } - } - 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; - - uint32 typeId = RCT2_GLOBAL(RCT2_ADDRESS_LAST_RESEARCHED_ITEM_SUBJECT, uint32); - int lastDevelopmentFormat; - if (typeId != 0xFFFFFFFF) { - 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; - - lastDevelopmentFormat = STR_RESEARCH_RIDE_LABEL; - } else { - stringId = g_scenerySetEntries[typeId]->name; - lastDevelopmentFormat = STR_RESEARCH_SCENERY_LABEL; - } - gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 266, lastDevelopmentFormat, 0); + if (item.type != 255 || item.entry_index != 255) + window_new_ride_paint_ride_information(w, dpi, item, w->x + 3, w->y + w->height - 52, w->width - 6); + } else { + window_research_development_page_paint(w, dpi, WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP); } } @@ -835,18 +770,14 @@ static void window_new_ride_paint() * * rct2: 0x006B6ABF */ -static void window_new_ride_scrollpaint() +static void window_new_ride_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_ride_type **rideEntries = (rct_ride_type**)0x009ACFA4; - window_paint_get_registers(w, dpi); - if (_window_new_ride_current_tab == WINDOW_NEW_RIDE_PAGE_RESEARCH) return; - gfx_clear(dpi, RCT2_GLOBAL(0x0141FC48 + (w->colours[1] * 8), uint8) * 0x1010101); + gfx_clear(dpi, ColourMapA[w->colours[1]].mid_light * 0x1010101); int x = 1; int y = 1; @@ -859,8 +790,8 @@ static void window_new_ride_scrollpaint() flags |= 0x20; if (w->new_ride.highlighted_ride_id == *((sint16*)listItem) || flags != 0) gfx_fill_rect_inset(dpi, x, y, x + 115, y + 115, w->colours[1], 0x80 | flags); - - // Draw ride image + + // Draw ride image with feathered border rideEntry = rideEntries[listItem->entry_index]; int image_id = rideEntry->images_offset; if (listItem->type != rideEntry->ride_type[0]) { @@ -868,7 +799,7 @@ static void window_new_ride_scrollpaint() if (listItem->type != rideEntry->ride_type[1]) image_id++; } - RCT2_CALLPROC_X(0x00681DE2, 0, 29013, x + 2, y + 2, 0xA0, (int)dpi, image_id); + gfx_draw_sprite_raw_masked(dpi, x + 2, y + 2, 29013, image_id); // Next position x += 116; @@ -937,7 +868,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->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME)) { + if (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) || rideTypeShouldLoseSeparateFlag(rideEntry)) { rideName = item.type + 2; rideDescription = item.type + 512; } @@ -973,14 +904,14 @@ 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 (ride_type_has_flag(item.type, RIDE_TYPE_FLAG_SELLS_FOOD)) { + if (ride_type_has_flag(item.type, RIDE_TYPE_FLAG_FLAT_RIDE)) { price *= RCT2_ADDRESS(0x0099DE34, uint32)[unk2]; } else { price *= RCT2_ADDRESS(0x0099DA34, uint32)[unk2]; } price = (price >> 17) * 10 * RCT2_GLOBAL(0x0097D21D + (item.type * 8), uint8); - // + // rct_string_id stringId = 1691; if (!ride_type_has_flag(item.type, RIDE_TYPE_FLAG_15)) stringId++; @@ -1000,6 +931,7 @@ static void window_new_ride_select(rct_window *w) return; window_close(w); + window_close_construction_windows(); if (ride_type_has_flag(item.type, RIDE_TYPE_FLAG_HAS_TRACK)) { track_load_list(item); diff --git a/src/windows/news.c b/src/windows/news.c index 512bff4d0e..0df430e2de 100644 --- a/src/windows/news.c +++ b/src/windows/news.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 . *****************************************************************************/ @@ -44,49 +44,48 @@ static rct_widget window_news_widgets[] = { { WIDGETS_END }, }; -static void window_news_emptysub() { } -static void window_news_mouseup(); +static void window_news_mouseup(rct_window *w, int widgetIndex); 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(); +static void window_news_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_news_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_news_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_news_invalidate(rct_window *w); +static void window_news_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_news_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void* window_news_events[] = { - window_news_emptysub, +static rct_window_event_list window_news_events = { + NULL, window_news_mouseup, - window_news_emptysub, - window_news_emptysub, - window_news_emptysub, - window_news_emptysub, + NULL, + NULL, + NULL, + NULL, window_news_update, - window_news_emptysub, - window_news_emptysub, - window_news_emptysub, - window_news_emptysub, - window_news_emptysub, - window_news_emptysub, - window_news_emptysub, - window_news_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_news_scrollgetsize, window_news_scrollmousedown, - window_news_emptysub, - window_news_emptysub, - window_news_emptysub, - window_news_emptysub, - window_news_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, window_news_tooltip, - window_news_emptysub, - window_news_emptysub, + NULL, + NULL, window_news_invalidate, window_news_paint, window_news_scrollpaint }; /** - * + * * rct2: 0x0066E464 */ void window_news_open() @@ -99,7 +98,7 @@ void window_news_open() window = window_create_auto_pos( 400, 300, - (uint32*)window_news_events, + &window_news_events, WC_RECENT_NEWS, 0 ); @@ -110,9 +109,10 @@ void window_news_open() } // sub_66E4BA: - int width, height; rct_widget *widget; + int width = 0; + int height = 0; window_get_scroll_size(window, 0, &width, &height); widget = &window_news_widgets[WIDX_SCROLL]; window->scrolls[0].v_top = max(0, height - (widget->bottom - widget->top - 1)); @@ -121,28 +121,25 @@ void window_news_open() } /** - * + * * rct2: 0x0066D4D5 */ -static void window_news_mouseup() +static void window_news_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - - if (widgetIndex == WIDX_CLOSE) + switch (widgetIndex) { + case WIDX_CLOSE: window_close(w); + break; + } } /** - * + * * rct2: 0x0066EAB8 */ static void window_news_update(rct_window *w) { int i, j, x, y, z; - rct_news_item *newsItems; if (w->news.var_480 == -1) return; @@ -150,24 +147,24 @@ static void window_news_update(rct_window *w) return; window_invalidate(w); - sound_play_panned(SOUND_CLICK_2, w->x + (w->width / 2), 0, 0, 0); + audio_play_sound_panned(SOUND_CLICK_2, w->x + (w->width / 2), 0, 0, 0); - newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); j = w->news.var_480; w->news.var_480 = -1; for (i = 11; i < 61; i++) { - if (newsItems[i].type == NEWS_ITEM_NULL) + if (news_item_is_empty(i)) return; if (j == 0) { - if (newsItems[i].flags & 1) + rct_news_item * const newsItem = news_item_get(i); + if (newsItem->flags & 1) return; if (w->news.var_482 == 1) { - news_item_open_subject(newsItems[i].type, newsItems[i].assoc); + news_item_open_subject(newsItem->type, newsItem->assoc); return; } else if (w->news.var_482 > 1) { - news_item_get_subject_location(newsItems[i].type, newsItems[i].assoc, &x, &y, &z); + news_item_get_subject_location(newsItem->type, newsItem->assoc, &x, &y, &z); if (x != SPRITE_LOCATION_NULL) if ((w = window_get_main()) != NULL) window_scroll_to_location(w, x, y, z); @@ -179,47 +176,38 @@ static void window_news_update(rct_window *w) } /** - * + * * rct2: 0x0066EA3C */ -static void window_news_scrollgetsize() +static void window_news_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - int i, width, height; - rct_news_item *newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); + int i; - width = 0; - height = 0; + *height = 0; for (i = 11; i < 61; i++) { - if (newsItems[i].type == NEWS_ITEM_NULL) + if (news_item_is_empty(i)) break; - height += 42; + *height += 42; } - - window_scrollsize_set_registers(width, height); } /** - * + * * rct2: 0x0066EA5C */ -static void window_news_scrollmousedown() +static void window_news_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) { int i, buttonIndex; - short x, y, scrollIndex; - rct_window *w; - rct_news_item *newsItems; - - window_scrollmouse_get_registers(w, scrollIndex, x, y); buttonIndex = 0; - newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); for (i = 11; i < 61; i++) { - if (newsItems[i].type == NEWS_ITEM_NULL) + if (news_item_is_empty(i)) break; if (y < 42) { - if (newsItems[i].flags & 1) { + rct_news_item * const newsItem = news_item_get(i); + if (newsItem->flags & 1) { buttonIndex = 0; break; } else if (y < 14) { @@ -232,12 +220,12 @@ static void window_news_scrollmousedown() buttonIndex = 0; break; } else if (x < 351) { - if (RCT2_ADDRESS(0x0097BE7C, uint8)[newsItems[i].type] & 2) { + if (RCT2_ADDRESS(0x0097BE7C, uint8)[newsItem->type] & 2) { buttonIndex = 1; break; } } else if (x < 376) { - if (RCT2_ADDRESS(0x0097BE7C, uint8)[newsItems[i].type] & 1) { + if (RCT2_ADDRESS(0x0097BE7C, uint8)[newsItem->type] & 1) { buttonIndex = 2; break; } @@ -251,59 +239,45 @@ static void window_news_scrollmousedown() w->news.var_482 = buttonIndex; w->news.var_484 = 4; window_invalidate(w); - sound_play_panned(SOUND_CLICK_1, w->x + (w->width / 2), 0, 0, 0); + audio_play_sound_panned(SOUND_CLICK_1, w->x + (w->width / 2), 0, 0, 0); } } /** - * + * * rct2: 0x0066EAAE */ -static void window_news_tooltip() +static void window_news_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) { - RCT2_GLOBAL(0x013CE952, uint16) = 3159; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = 3159; } /** - * + * * rct2: 0x0066E4E8 */ -static void window_news_paint() +static void window_news_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); } -static void window_news_invalidate() +static void window_news_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); } /** - * + * * rct2: 0x0066E4EE */ -static void window_news_scrollpaint() +static void window_news_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { int i, x, y, yy, press; - rct_window *w; - rct_drawpixelinfo *dpi; - rct_news_item *newsItems, *newsItem, *newsItem2; - - window_paint_get_registers(w, dpi); y = 0; - newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item); for (i = 11; i < 61; i++) { - newsItem = &newsItems[i]; - if (newsItem->type == NEWS_ITEM_NULL) + rct_news_item * const newsItem = news_item_get(i); + if (news_item_is_empty(i)) break; if (y >= dpi->y + dpi->height) break; @@ -316,16 +290,17 @@ static void window_news_scrollpaint() gfx_fill_rect_inset(dpi, -1, y, 383, y + 41, w->colours[1], 0x24); // Date text - RCT2_GLOBAL(0x013CE952, uint16) = STR_DATE_DAY_1 + newsItem->day - 1; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = STR_DATE_DAY_1 + newsItem->day - 1; RCT2_GLOBAL(0x013CE952 + 2, uint16) = STR_MONTH_MARCH + (newsItem->month_year % 8); gfx_draw_string_left(dpi, 2235, (void*)0x013CE952, 2, 4, y); // Item text - char sz[400];// = (char*)0x09B5F2C; - char* args[1]; - args[0] = (char*)&sz; - sprintf(sz, "%c%c%s", newsItem->colour, FORMAT_SMALLFONT, newsItem->text); - gfx_draw_string_left_wrapped(dpi, args, 2, y + 10, 325, 1170, 14); + utf8 buffer[400]; + utf8 *ch = buffer; + ch = utf8_write_codepoint(ch, FORMAT_SMALLFONT); + memcpy(ch, newsItem->text, 256); + ch = buffer; + gfx_draw_string_left_wrapped(dpi, &ch, 2, y + 10, 325, 1170, 14); // Subject button if ((RCT2_ADDRESS(0x0097BE7C, uint8)[newsItem->type] & 2) && !(newsItem->flags & 1)) { @@ -334,8 +309,9 @@ static void window_news_scrollpaint() press = 0; if (w->news.var_480 != -1) { - newsItem2 = &newsItems[11 + w->news.var_480]; - if (newsItem == newsItem2 && w->news.var_482 == 1) + const uint8 idx = 11 + w->news.var_480; + news_item_is_valid_idx(idx); + if (i == idx && w->news.var_482 == 1) press = 0x20; } gfx_fill_rect_inset(dpi, x, yy, x + 23, yy + 23, w->colours[2], press); @@ -370,7 +346,7 @@ static void window_news_scrollpaint() gfx_draw_sprite(cliped_dpi, image_id, clip_x, clip_y, 0); rct2_free(cliped_dpi); - break; + break; } case NEWS_ITEM_MONEY: gfx_draw_sprite(dpi, SPR_FINANCE, x, yy, 0); @@ -397,8 +373,9 @@ static void window_news_scrollpaint() press = 0; if (w->news.var_480 != -1) { - newsItem2 = &newsItems[11 + w->news.var_480]; - if (newsItem == newsItem2 && w->news.var_482 == 2) + const uint8 idx = 11 + w->news.var_480; + news_item_is_valid_idx(idx); + if (i == idx && w->news.var_482 == 2) press = 0x20; } gfx_fill_rect_inset(dpi, x, yy, x + 23, yy + 23, w->colours[2], press); @@ -407,4 +384,4 @@ static void window_news_scrollpaint() y += 42; } -} \ No newline at end of file +} diff --git a/src/windows/options.c b/src/windows/options.c index fb46b70615..14f072530a 100644 --- a/src/windows/options.c +++ b/src/windows/options.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 . *****************************************************************************/ @@ -26,27 +26,31 @@ * 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" #include "../config.h" #include "../drawing/drawing.h" +#include "../interface/themes.h" +#include "../interface/title_sequences.h" #include "../interface/viewport.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../localisation/currency.h" +#include "../localisation/date.h" #include "../localisation/localisation.h" #include "../platform/platform.h" #include "../sprites.h" +#include "../title.h" #include "dropdown.h" #include "error.h" -#include "../interface/themes.h" +#include "../util/util.h" enum WINDOW_OPTIONS_PAGE { WINDOW_OPTIONS_PAGE_DISPLAY, WINDOW_OPTIONS_PAGE_CULTURE, WINDOW_OPTIONS_PAGE_AUDIO, - WINDOW_OPTIONS_PAGE_CONTROLS, + WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE, WINDOW_OPTIONS_PAGE_MISC, WINDOW_OPTIONS_PAGE_TWITCH, WINDOW_OPTIONS_PAGE_COUNT @@ -69,19 +73,26 @@ enum WINDOW_OPTIONS_WIDGET_IDX { WIDX_PAGE_START, // Display - WIDX_RESOLUTION = WIDX_PAGE_START, + WIDX_HARDWARE_GROUP = WIDX_PAGE_START, + WIDX_RESOLUTION, WIDX_RESOLUTION_DROPDOWN, WIDX_FULLSCREEN, WIDX_FULLSCREEN_DROPDOWN, + WIDX_HARDWARE_DISPLAY_CHECKBOX, + WIDX_UNCAP_FPS_CHECKBOX, + WIDX_MINIMIZE_FOCUS_LOSS, + WIDX_STEAM_OVERLAY_PAUSE, + WIDX_SCALE, + WIDX_SCALE_UP, + WIDX_SCALE_DOWN, + WIDX_RENDERING_GROUP, 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_DAY_NIGHT_CHECKBOX, + WIDX_UPPER_CASE_BANNERS_CHECKBOX, + // Culture / Units WIDX_LANGUAGE = WIDX_PAGE_START, WIDX_LANGUAGE_DROPDOWN, @@ -101,29 +112,42 @@ enum WINDOW_OPTIONS_WIDGET_IDX { WIDX_SOUND_DROPDOWN, WIDX_SOUND_CHECKBOX, WIDX_MUSIC_CHECKBOX, + WIDX_AUDIO_FOCUS_CHECKBOX, WIDX_TITLE_MUSIC, WIDX_TITLE_MUSIC_DROPDOWN, WIDX_MASTER_VOLUME, WIDX_MUSIC_VOLUME, - // Controls - WIDX_SCREEN_EDGE_SCROLLING = WIDX_PAGE_START, + // Controls and interface + WIDX_CONTROLS_GROUP = WIDX_PAGE_START, + WIDX_SCREEN_EDGE_SCROLLING, + WIDX_INVERT_DRAG, WIDX_HOTKEY_DROPDOWN, + WIDX_THEMES_GROUP, + WIDX_THEMES, + WIDX_THEMES_DROPDOWN, + WIDX_THEMES_BUTTON, + WIDX_TOOLBAR_BUTTONS_GROUP, WIDX_TOOLBAR_SHOW_FINANCES, WIDX_TOOLBAR_SHOW_RESEARCH, WIDX_TOOLBAR_SHOW_CHEATS, + WIDX_TOOLBAR_SHOW_NEWS, + WIDX_SELECT_BY_TRACK_TYPE, // 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_HANDYMEN_MOW_DEFAULT, WIDX_DEBUGGING_TOOLS, WIDX_TITLE_SEQUENCE, WIDX_TITLE_SEQUENCE_DROPDOWN, + WIDX_TITLE_SEQUENCE_BUTTON, + WIDX_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM, + WIDX_STAY_CONNECTED_AFTER_DESYNC, // Twitch WIDX_CHANNEL_BUTTON = WIDX_PAGE_START, @@ -134,96 +158,120 @@ enum WINDOW_OPTIONS_WIDGET_IDX { WIDX_NEWS_CHECKBOX }; -#define WW 310 -#define WH 183 +#define WW 310 +#define WH 280 #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 } + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_OPTIONS_DISPLAY_TIP }, \ + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_OPTIONS_CULTURE_TIP }, \ + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_OPTIONS_AUDIO_TIP }, \ + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_OPTIONS_CONTROLS_AND_INTERFACE_TIP }, \ + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_OPTIONS_MISCELLANEOUS_TIP }, \ + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_OPTIONS_TWITCH_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 + { WWT_GROUPBOX, 1, 5, 304, 53, 175, STR_HARDWARE_GROUP, STR_NONE }, // Hardware group + { WWT_DROPDOWN, 1, 155, 299, 68, 79, STR_RESOLUTION_X_BY_Y, STR_NONE }, // resolution + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 69, 78, STR_DROPDOWN_GLYPH, STR_NONE }, + { WWT_DROPDOWN, 1, 155, 299, 83, 94, 871, STR_NONE }, // fullscreen + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 84, 93, STR_DROPDOWN_GLYPH, STR_NONE }, + { WWT_CHECKBOX, 1, 10, 290, 99, 110, STR_HARDWARE_DISPLAY, STR_NONE }, // hardware display + { WWT_CHECKBOX, 1, 10, 290, 114, 125, STR_UNCAP_FPS, STR_NONE }, // uncap fps + { WWT_CHECKBOX, 1, 10, 290, 129, 140, STR_MININISE_FULL_SCREEN_ON_FOCUS_LOSS, STR_NONE }, // minimise fullscreen focus loss + { WWT_CHECKBOX, 1, 10, 290, 144, 155, STR_STEAM_OVERLAY_PAUSE, STR_NONE }, // minimise fullscreen focus loss + { WWT_SPINNER, 1, 155, 299, 159, 170, STR_NONE, STR_NONE }, // scale spinner + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 160, 164, STR_NUMERIC_UP, STR_NONE }, // scale spinner up + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 165, 169, STR_NUMERIC_DOWN, STR_NONE }, // scale spinner down + + { WWT_GROUPBOX, 1, 5, 304, 179, 270, STR_RENDERING_GROUP, STR_NONE }, // Rendering group + { WWT_CHECKBOX, 1, 10, 290, 194, 205, STR_TILE_SMOOTHING, STR_TILE_SMOOTHING_TIP }, // landscape smoothing + { WWT_CHECKBOX, 1, 10, 290, 209, 220, STR_GRIDLINES, STR_GRIDLINES_TIP }, // gridlines + { WWT_DROPDOWN, 1, 155, 299, 224, 234, STR_NONE, STR_NONE }, // construction marker + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 225, 233, STR_DROPDOWN_GLYPH, STR_NONE }, + { WWT_CHECKBOX, 1, 10, 290, 239, 250, STR_CYCLE_DAY_NIGHT, STR_NONE }, // cycle day-night + { WWT_CHECKBOX, 1, 10, 290, 254, 265, STR_UPPER_CASE_BANNERS, STR_NONE }, // upper case banners { WIDGETS_END }, }; 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 }, + { WWT_DROPDOWN, 1, 155, 299, 53, 64, STR_NONE, STR_NONE }, // language + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 54, 63, STR_DROPDOWN_GLYPH, STR_NONE }, + { WWT_DROPDOWN, 1, 155, 299, 68, 79, 871, STR_NONE }, // currency + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 69, 78, STR_DROPDOWN_GLYPH, STR_NONE }, // + { WWT_DROPDOWN, 1, 155, 299, 83, 94, 872, STR_NONE }, // distance + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 84, 93, STR_DROPDOWN_GLYPH, STR_NONE }, + { WWT_DROPDOWN, 1, 155, 299, 98, 110, 875, STR_NONE }, // temperature + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 99, 108, STR_DROPDOWN_GLYPH, STR_NONE }, + { WWT_DROPDOWN, 1, 155, 299, 113, 124, 868, STR_NONE }, // height labels + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 114, 123, STR_DROPDOWN_GLYPH, STR_NONE }, + { WWT_DROPDOWN, 1, 155, 299, 128, 139, STR_NONE, STR_NONE }, // date format + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 129, 138, STR_DROPDOWN_GLYPH, 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 + { WWT_DROPDOWN, 1, 10, 299, 53, 64, 865, STR_NONE }, // audio device + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 54, 63, STR_DROPDOWN_GLYPH, 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_CHECKBOX, 1, 10, 229, 98, 110, STR_AUDIO_FOCUS, STR_NONE }, // enable / disable audio disabled on focus lost + { WWT_DROPDOWN, 1, 155, 299, 112, 124, STR_NONE, STR_NONE }, // title music + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 113, 123, STR_DROPDOWN_GLYPH, 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[] = { +static rct_widget window_options_controls_and_interface_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 }, + { WWT_GROUPBOX, 1, 5, 304, 53, 114, STR_CONTROLS_GROUP, STR_NONE }, // Controls group + { WWT_CHECKBOX, 2, 10, 299, 68, 79, STR_SCREEN_EDGE_SCROLLING, STR_SCREEN_EDGE_SCROLLING_TIP }, // Edge scrolling + { WWT_CHECKBOX, 2, 10, 299, 83, 94, STR_INVERT_RIGHT_MOUSE_DRAG, STR_NONE }, // Invert right mouse dragging + { WWT_DROPDOWN_BUTTON, 1, 26, 185, 98, 109, STR_HOTKEY, STR_HOTKEY_TIP }, // Set hotkeys buttons + + { WWT_GROUPBOX, 1, 5, 304, 118, 164, STR_THEMES_GROUP, STR_NONE }, // Toolbar buttons group + { WWT_DROPDOWN, 1, 155, 299, 132, 143, STR_NONE, STR_NONE }, // Themes + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 133, 142, STR_DROPDOWN_GLYPH, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 10, 145, 148, 159, STR_EDIT_THEMES_BUTTON, STR_NONE }, // Themes button + + { WWT_GROUPBOX, 1, 5, 304, 168, 230, STR_TOOLBAR_BUTTONS_GROUP, STR_NONE }, // Toolbar buttons group + { WWT_CHECKBOX, 2, 10, 145, 199, 210, STR_FINANCES_BUTTON_ON_TOOLBAR, STR_NONE }, // Finances + { WWT_CHECKBOX, 2, 10, 145, 214, 225, STR_RESEARCH_BUTTON_ON_TOOLBAR, STR_NONE }, // Research + { WWT_CHECKBOX, 2, 155, 299, 199, 210, STR_CHEATS_BUTTON_ON_TOOLBAR, STR_NONE }, // Cheats + { WWT_CHECKBOX, 2, 155, 299, 214, 225, STR_SHOW_RECENT_MESSAGES_ON_TOOLBAR, STR_NONE }, // Recent messages + + { WWT_CHECKBOX, 2, 10, 299, 239, 250, STR_SELECT_BY_TRACK_TYPE, STR_SELECT_BY_TRACK_TYPE_TIP }, // Select by track type { 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 }, + { 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, STR_DROPDOWN_GLYPH, STR_NONE }, + { WWT_CHECKBOX, 2, 10, 299, 114, 125, STR_TEST_UNFINISHED_TRACKS, STR_TEST_UNFINISHED_TRACKS_TIP }, // test unfinished tracks + { WWT_CHECKBOX, 2, 10, 299, 129, 140, STR_AUTO_STAFF_PLACEMENT, STR_NONE }, // auto staff placement + { WWT_CHECKBOX, 2, 10, 299, 144, 155, STR_HANDYMEN_MOW_BY_DEFAULT, STR_NONE }, // handymen mow by default + { WWT_CHECKBOX, 2, 10, 299, 159, 170, STR_ENABLE_DEBUGGING_TOOLS, STR_NONE }, // enable debugging tools + { WWT_DROPDOWN, 1, 155, 299, 173, 184, STR_NONE, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 174, 183, STR_DROPDOWN_GLYPH, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 26, 185, 189, 200, STR_EDIT_TITLE_SEQUENCES_BUTTON, STR_NONE }, // Title sequences button + { WWT_CHECKBOX, 2, 10, 299, 204, 215, STR_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM, STR_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM_TIP }, // Allow loading with incorrect checksum + { WWT_CHECKBOX, 2, 10, 299, 219, 230, STR_STAY_CONNECTED_AFTER_DESYNC, STR_NONE }, // Do not disconnect after the client desynchronises with the server { 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_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 @@ -236,7 +284,7 @@ rct_widget *window_options_page_widgets[] = { window_options_display_widgets, window_options_culture_widgets, window_options_audio_widgets, - window_options_controls_widgets, + window_options_controls_and_interface_widgets, window_options_misc_widgets, window_options_twitch_widgets }; @@ -255,46 +303,44 @@ static void window_options_update_height_markers(); #pragma region Events -static void window_options_emptysub() { } - -static void window_options_mouseup(); +static void window_options_mouseup(rct_window *w, int widgetIndex); static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_options_dropdown(); +static void window_options_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_options_update(rct_window *w); -static void window_options_invalidate(); -static void window_options_paint(); -static void window_options_scrollgetsize(); -static void window_options_text_input(); +static void window_options_invalidate(rct_window *w); +static void window_options_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_options_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_options_text_input(rct_window *w, int widgetIndex, char *text); -static void* window_options_events[] = { - window_options_emptysub, +static rct_window_event_list window_options_events = { + NULL, window_options_mouseup, - window_options_emptysub, + NULL, window_options_mousedown, window_options_dropdown, - window_options_emptysub, + NULL, window_options_update, - window_options_emptysub, - window_options_emptysub, - window_options_emptysub, - window_options_emptysub, - window_options_emptysub, - window_options_emptysub, - window_options_emptysub, - window_options_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_options_scrollgetsize, - window_options_emptysub, - window_options_emptysub, - window_options_emptysub, + NULL, + NULL, + NULL, window_options_text_input, - window_options_emptysub, - window_options_emptysub, - window_options_emptysub, - window_options_emptysub, - window_options_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, window_options_invalidate, window_options_paint, - window_options_emptysub + NULL }; #pragma endregion @@ -319,11 +365,16 @@ static uint32 window_options_page_enabled_widgets[] = { (1 << WIDX_TILE_SMOOTHING_CHECKBOX) | (1 << WIDX_GRIDLINES_CHECKBOX) | (1 << WIDX_HARDWARE_DISPLAY_CHECKBOX) | + (1 << WIDX_UNCAP_FPS_CHECKBOX) | + (1 << WIDX_MINIMIZE_FOCUS_LOSS) | + (1 << WIDX_STEAM_OVERLAY_PAUSE) | + (1 << WIDX_SCALE) | + (1 << WIDX_SCALE_UP) | + (1 << WIDX_SCALE_DOWN) | (1 << WIDX_CONSTRUCTION_MARKER) | (1 << WIDX_CONSTRUCTION_MARKER_DROPDOWN) | - (1 << WIDX_THEMES) | - (1 << WIDX_THEMES_DROPDOWN) | - (1 << WIDX_THEMES_BUTTON), + (1 << WIDX_DAY_NIGHT_CHECKBOX) | + (1 << WIDX_UPPER_CASE_BANNERS_CHECKBOX), MAIN_OPTIONS_ENABLED_WIDGETS | (1 << WIDX_LANGUAGE) | @@ -344,27 +395,37 @@ static uint32 window_options_page_enabled_widgets[] = { (1 << WIDX_SOUND_DROPDOWN) | (1 << WIDX_SOUND_CHECKBOX) | (1 << WIDX_MUSIC_CHECKBOX) | + (1 << WIDX_AUDIO_FOCUS_CHECKBOX) | (1 << WIDX_TITLE_MUSIC) | (1 << WIDX_TITLE_MUSIC_DROPDOWN), MAIN_OPTIONS_ENABLED_WIDGETS | (1 << WIDX_SCREEN_EDGE_SCROLLING) | + (1 << WIDX_INVERT_DRAG) | (1 << WIDX_HOTKEY_DROPDOWN) | (1 << WIDX_TOOLBAR_SHOW_FINANCES) | (1 << WIDX_TOOLBAR_SHOW_RESEARCH) | - (1 << WIDX_TOOLBAR_SHOW_CHEATS), + (1 << WIDX_TOOLBAR_SHOW_CHEATS) | + (1 << WIDX_TOOLBAR_SHOW_NEWS) | + (1 << WIDX_THEMES) | + (1 << WIDX_THEMES_DROPDOWN) | + (1 << WIDX_THEMES_BUTTON) | + (1 << WIDX_SELECT_BY_TRACK_TYPE), 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_HANDYMEN_MOW_DEFAULT) | (1 << WIDX_DEBUGGING_TOOLS) | (1 << WIDX_TITLE_SEQUENCE) | - (1 << WIDX_TITLE_SEQUENCE_DROPDOWN), + (1 << WIDX_TITLE_SEQUENCE_DROPDOWN) | + (1 << WIDX_TITLE_SEQUENCE_BUTTON) | + (1 << WIDX_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM) | + (1 << WIDX_STAY_CONNECTED_AFTER_DESYNC), MAIN_OPTIONS_ENABLED_WIDGETS | (1 << WIDX_CHANNEL_BUTTON) | @@ -390,7 +451,7 @@ void window_options_open() if (w != NULL) return; - w = window_create_centred(WW, WH, (uint32*)window_options_events, WC_OPTIONS, WF_RESIZABLE); + w = window_create_centred(WW, WH, &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; @@ -406,13 +467,8 @@ void window_options_open() * * rct2: 0x006BAFCA */ -static void window_options_mouseup() +static void window_options_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -448,12 +504,43 @@ static void window_options_mouseup() break; case WIDX_HARDWARE_DISPLAY_CHECKBOX: gConfigGeneral.hardware_display ^= 1; +#ifdef _WIN32 + // Windows is apparently able to switch to hardware rendering on the fly although + // using the same window in an unaccelerated and accelerated context is unsupported by SDL2 + gHardwareDisplay = gConfigGeneral.hardware_display; + platform_refresh_video(); +#else + // Linux requires a restart. This could be improved in the future by recreating the window, + // https://github.com/OpenRCT2/OpenRCT2/issues/2015 + window_error_open(STR_RESTART_REQUIRED, STR_NONE); +#endif + config_save_default(); + window_invalidate(w); + break; + case WIDX_UNCAP_FPS_CHECKBOX: + gConfigGeneral.uncap_fps ^= 1; + config_save_default(); + window_invalidate(w); + break; + case WIDX_MINIMIZE_FOCUS_LOSS: + gConfigGeneral.minimize_fullscreen_focus_loss ^= 1; platform_refresh_video(); config_save_default(); window_invalidate(w); break; - case WIDX_THEMES_BUTTON: - window_themes_open(); + case WIDX_STEAM_OVERLAY_PAUSE: + gConfigGeneral.steam_overlay_pause ^= 1; + config_save_default(); + window_invalidate(w); + break; + case WIDX_DAY_NIGHT_CHECKBOX: + gConfigGeneral.day_night_cycle ^= 1; + config_save_default(); + window_invalidate(w); + break; + case WIDX_UPPER_CASE_BANNERS_CHECKBOX: + gConfigGeneral.upper_case_banners ^= 1; + config_save_default(); window_invalidate(w); break; } @@ -465,23 +552,27 @@ static void window_options_mouseup() case WINDOW_OPTIONS_PAGE_AUDIO: switch (widgetIndex) { case WIDX_SOUND_CHECKBOX: - toggle_all_sounds(); + audio_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; + gConfigSound.ride_music = !gConfigSound.ride_music; + if (!gConfigSound.ride_music) { + audio_stop_ride_music(); + } + config_save_default(); + window_invalidate(w); + break; + case WIDX_AUDIO_FOCUS_CHECKBOX: + gConfigSound.audio_focus = !gConfigSound.audio_focus; config_save_default(); window_invalidate(w); break; } break; - case WINDOW_OPTIONS_PAGE_CONTROLS: + case WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE: switch (widgetIndex) { case WIDX_HOTKEY_DROPDOWN: window_shortcut_keys_open(); @@ -509,17 +600,33 @@ static void window_options_mouseup() window_invalidate(w); window_invalidate_by_class(WC_TOP_TOOLBAR); break; + case WIDX_TOOLBAR_SHOW_NEWS: + gConfigInterface.toolbar_show_news ^= 1; + config_save_default(); + window_invalidate(w); + window_invalidate_by_class(WC_TOP_TOOLBAR); + break; + case WIDX_INVERT_DRAG: + gConfigGeneral.invert_viewport_drag ^= 1; + config_save_default(); + window_invalidate(w); + break; + case WIDX_THEMES_BUTTON: + window_themes_open(); + window_invalidate(w); + break; + case WIDX_SELECT_BY_TRACK_TYPE: + gConfigInterface.select_by_track_type ^= 1; + config_save_default(); + window_invalidate(w); + window_invalidate_by_class(WC_RIDE); + window_invalidate_by_class(WC_CONSTRUCT_RIDE); + 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(); @@ -532,8 +639,9 @@ static void window_options_mouseup() 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); + peep_update_names( + !(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_SHOW_REAL_GUEST_NAMES) + ); break; case WIDX_SAVE_PLUGIN_DATA_CHECKBOX: gConfigGeneral.save_plugin_data ^= 1; @@ -545,6 +653,23 @@ static void window_options_mouseup() config_save_default(); window_invalidate(w); break; + case WIDX_HANDYMEN_MOW_DEFAULT: + gConfigGeneral.handymen_mow_default = !gConfigGeneral.handymen_mow_default; + config_save_default(); + window_invalidate(w); + break; + case WIDX_TITLE_SEQUENCE_BUTTON: + window_title_editor_open(0); + break; + case WIDX_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM: + gConfigGeneral.allow_loading_with_incorrect_checksum = !gConfigGeneral.allow_loading_with_incorrect_checksum; + config_save_default(); + window_invalidate(w); + break; + case WIDX_STAY_CONNECTED_AFTER_DESYNC: + gConfigNetwork.stay_connected = !gConfigNetwork.stay_connected; + config_save_default(); + window_invalidate(w); } break; @@ -590,7 +715,7 @@ static void window_options_mouseup() static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) { int num_items, i; - + widget = &w->widgets[widgetIndex - 1]; switch (w->page) { @@ -617,8 +742,9 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* window_options_show_dropdown(w, widget, gNumResolutions); - if (selectedResolution != -1 && selectedResolution < 32) - gDropdownItemsChecked = 1 << selectedResolution; + if (selectedResolution != -1 && selectedResolution < 32) { + dropdown_set_checked(selectedResolution, true); + } } break; @@ -632,7 +758,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* window_options_show_dropdown(w, widget, 3); - gDropdownItemsChecked = 1 << gConfigGeneral.fullscreen_mode; + dropdown_set_checked(gConfigGeneral.fullscreen_mode, true); break; case WIDX_CONSTRUCTION_MARKER_DROPDOWN: gDropdownItemsFormat[0] = 1142; @@ -642,35 +768,20 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* window_options_show_dropdown(w, widget, 2); - gDropdownItemsChecked = 1 << gConfigGeneral.construction_marker_colour; + dropdown_set_checked(gConfigGeneral.construction_marker_colour, true); break; - case WIDX_THEMES_DROPDOWN: - num_items = gConfigThemes.num_presets; - - 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); + case WIDX_SCALE_UP: + gConfigGeneral.window_scale += 0.25f; + config_save_default(); + gfx_invalidate_screen(); + platform_trigger_resize(); + break; + case WIDX_SCALE_DOWN: + gConfigGeneral.window_scale -= 0.25f; + gConfigGeneral.window_scale = max(0.5f, gConfigGeneral.window_scale); + config_save_default(); + gfx_invalidate_screen(); + platform_trigger_resize(); break; } break; @@ -685,19 +796,19 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* window_options_show_dropdown(w, widget, 2); - gDropdownItemsChecked = gConfigGeneral.show_height_as_units ? 1 : 2; + dropdown_set_checked(gConfigGeneral.show_height_as_units ? 0 : 1, true); break; case WIDX_CURRENCY_DROPDOWN: - num_items = 10; + num_items = CURRENCY_END; for (i = 0; i < num_items; i++) { gDropdownItemsFormat[i] = 1142; - gDropdownItemsArgs[i] = STR_POUNDS + i; + gDropdownItemsArgs[i] = CurrencyDescriptors[i].stringId; } window_options_show_dropdown(w, widget, num_items); - gDropdownItemsChecked = 1 << gConfigGeneral.currency_format; + dropdown_set_checked(gConfigGeneral.currency_format, true); break; case WIDX_DISTANCE_DROPDOWN: gDropdownItemsFormat[0] = 1142; @@ -707,7 +818,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* window_options_show_dropdown(w, widget, 2); - gDropdownItemsChecked = 1 << gConfigGeneral.measurement_format; + dropdown_set_checked(gConfigGeneral.measurement_format, true); break; case WIDX_TEMPERATURE_DROPDOWN: gDropdownItemsFormat[0] = 1142; @@ -717,23 +828,23 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* window_options_show_dropdown(w, widget, 2); - gDropdownItemsChecked = 1 << gConfigGeneral.temperature_format; + dropdown_set_checked(gConfigGeneral.temperature_format, true); break; case WIDX_LANGUAGE_DROPDOWN: for (i = 1; i < LANGUAGE_COUNT; i++) { gDropdownItemsFormat[i - 1] = 2777; - gDropdownItemsArgs[i - 1] = (sint64)language_names[i]; + gDropdownItemsArgs[i - 1] = (sint32)LanguagesDescriptors[i].native_name; } window_options_show_dropdown(w, widget, LANGUAGE_COUNT - 1); - gDropdownItemsChecked = 1 << (gCurrentLanguage - 1); + dropdown_set_checked(gCurrentLanguage - 1, true); break; case WIDX_DATE_FORMAT_DROPDOWN: - for (i = 0; i < 2; i++) { + for (i = 0; i < 4; i++) { gDropdownItemsFormat[i] = 1142; - gDropdownItemsArgs[i] = 5162 + i; + gDropdownItemsArgs[i] = DateFormatStringIds[i]; } - window_options_show_dropdown(w, widget, 2); - gDropdownItemsChecked = 1 << (gConfigGeneral.date_format); + window_options_show_dropdown(w, widget, 4); + dropdown_set_checked(gConfigGeneral.date_format, true); break; } break; @@ -741,7 +852,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* case WINDOW_OPTIONS_PAGE_AUDIO: switch (widgetIndex) { case WIDX_SOUND_DROPDOWN: - audio_get_devices(); + audio_populate_devices(); // populate the list with the sound devices for (i = 0; i < gAudioDeviceCount; i++) { @@ -751,7 +862,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* window_options_show_dropdown(w, widget, gAudioDeviceCount); - gDropdownItemsChecked |= (1 << RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32)); + dropdown_set_checked(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32), true); break; case WIDX_TITLE_MUSIC_DROPDOWN: num_items = 4; @@ -766,34 +877,75 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* window_options_show_dropdown(w, widget, num_items); - gDropdownItemsChecked = 1 << gConfigSound.title_music; + dropdown_set_checked(gConfigSound.title_music, true); break; } break; - case WINDOW_OPTIONS_PAGE_CONTROLS: + case WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE: + switch (widgetIndex) { + case WIDX_THEMES_DROPDOWN: + num_items = gConfigThemes.num_presets; + + gDropdownItemsFormat[0] = 2777; + gDropdownItemsArgs[0] = (uint32)&gConfigThemes.presets[1].name; + gDropdownItemsFormat[1] = 2777; + gDropdownItemsArgs[1] = (uint32)&gConfigThemes.presets[0].name; + + for (i = 2; i < num_items; i++) { + gDropdownItemsFormat[i] = 2777; + gDropdownItemsArgs[i] = (uint32)&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) { + dropdown_set_checked(gCurrentTheme ^ 1, true); + } else { + dropdown_set_checked(gCurrentTheme, true); + } + break; + } break; case WINDOW_OPTIONS_PAGE_MISC: switch (widgetIndex) { case WIDX_AUTOSAVE_DROPDOWN: - for (i = AUTOSAVE_EVERY_WEEK; i <= AUTOSAVE_NEVER; i++) { + for (i = AUTOSAVE_EVERY_MINUTE; i <= AUTOSAVE_NEVER; i++) { gDropdownItemsFormat[i] = 1142; - gDropdownItemsArgs[i] = 2701 + i; + gDropdownItemsArgs[i] = STR_SAVE_EVERY_MINUTE + i; } + window_options_show_dropdown(w, widget, AUTOSAVE_NEVER + 1); - gDropdownItemsChecked = 1 << gConfigGeneral.autosave_frequency; + dropdown_set_checked(gConfigGeneral.autosave_frequency, true); 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; + num_items = gConfigTitleSequences.num_presets; + + for (i = 0; i < num_items; i++) { + gDropdownItemsFormat[i] = 2777; + gDropdownItemsArgs[i] = (uint32)&gConfigTitleSequences.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 + ); + + dropdown_set_checked(gCurrentPreviewTitleSequence, true); break; } break; @@ -807,14 +959,8 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* * * rct2: 0x006BB076 */ -static void window_options_dropdown() +static void window_options_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - short dropdownIndex; - short widgetIndex; - rct_window *w; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (dropdownIndex == -1) return; @@ -852,14 +998,6 @@ static void window_options_dropdown() 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; @@ -895,11 +1033,27 @@ static void window_options_dropdown() } break; case WIDX_LANGUAGE_DROPDOWN: - if (dropdownIndex != gCurrentLanguage - 1) { - language_open(dropdownIndex + 1); - gConfigGeneral.language = dropdownIndex + 1; - config_save_default(); - gfx_invalidate_screen(); + { + int fallbackLanguage = gCurrentLanguage; + if (dropdownIndex != gCurrentLanguage - 1) { + if (!language_open(dropdownIndex + 1)) + { + // Failed to open language file, try to recover by falling + // back to previously used language + if (language_open(fallbackLanguage)) + { + // It worked, so we can say it with error message in-game + window_error_open(STR_LANGUAGE_LOAD_FAILED, STR_NONE); + } + // report error to console regardless + log_error("Failed to open language file."); + dropdownIndex = fallbackLanguage - 1; + } else { + gConfigGeneral.language = dropdownIndex + 1; + config_save_default(); + gfx_invalidate_screen(); + } + } } break; case WIDX_DATE_FORMAT_DROPDOWN: @@ -915,25 +1069,20 @@ static void window_options_dropdown() case WINDOW_OPTIONS_PAGE_AUDIO: switch (widgetIndex) { case WIDX_SOUND_DROPDOWN: - audio_init2(dropdownIndex); + audio_init_ride_sounds(dropdownIndex); if (dropdownIndex < gAudioDeviceCount) { -#ifdef USE_MIXER if (dropdownIndex == 0) { Mixer_Init(NULL); + gConfigSound.device = NULL; } else { - Mixer_Init(gAudioDevices[dropdownIndex].name); + char* devicename = gAudioDevices[dropdownIndex].name; + Mixer_Init(devicename); + SafeFree(gConfigSound.device); + gConfigSound.device = strndup(devicename, AUDIO_DEVICE_NAME_SIZE); } -#endif + config_save_default(); } - /*#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: @@ -946,14 +1095,24 @@ static void window_options_dropdown() window_invalidate(w); } - stop_title_music(); + audio_stop_title_music(); if (dropdownIndex != 0) - start_title_music(); + audio_start_title_music(); break; } break; - case WINDOW_OPTIONS_PAGE_CONTROLS: + case WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE: + switch (widgetIndex) { + 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_MISC: @@ -966,9 +1125,9 @@ static void window_options_dropdown() } 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; + if (dropdownIndex != gCurrentPreviewTitleSequence) { + title_sequence_change_preset(dropdownIndex); + title_refresh_sequence(); config_save_default(); window_invalidate(w); } @@ -982,16 +1141,14 @@ static void window_options_dropdown() } /** -* +* * rct2: 0x006BAD48 */ -static void window_options_invalidate() +static void window_options_invalidate(rct_window *w) { - rct_window *w; rct_widget* widget; sint32 currentSoundDevice; - window_get_register(w); colour_scheme_update(w); if (window_options_page_widgets[w->page] != w->widgets) { @@ -1020,8 +1177,13 @@ static void window_options_invalidate() 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); + widget_set_checkbox_value(w, WIDX_UNCAP_FPS_CHECKBOX, gConfigGeneral.uncap_fps); + widget_set_checkbox_value(w, WIDX_MINIMIZE_FOCUS_LOSS, gConfigGeneral.minimize_fullscreen_focus_loss); + widget_set_checkbox_value(w, WIDX_STEAM_OVERLAY_PAUSE, gConfigGeneral.steam_overlay_pause); + widget_set_checkbox_value(w, WIDX_DAY_NIGHT_CHECKBOX, gConfigGeneral.day_night_cycle); + widget_set_checkbox_value(w, WIDX_UPPER_CASE_BANNERS_CHECKBOX, gConfigGeneral.upper_case_banners); - // construction marker: celsius/fahrenheit + // construction marker: white/translucent window_options_display_widgets[WIDX_CONSTRUCTION_MARKER].image = STR_WHITE + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CONSTRUCTION_MARKER, uint8); window_options_display_widgets[WIDX_RESOLUTION].type = WWT_DROPDOWN; @@ -1033,14 +1195,16 @@ static void window_options_invalidate() 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; + window_options_display_widgets[WIDX_UNCAP_FPS_CHECKBOX].type = WWT_CHECKBOX; + window_options_display_widgets[WIDX_MINIMIZE_FOCUS_LOSS].type = WWT_CHECKBOX; + window_options_display_widgets[WIDX_STEAM_OVERLAY_PAUSE].type = WWT_CHECKBOX; + window_options_display_widgets[WIDX_DAY_NIGHT_CHECKBOX].type = WWT_CHECKBOX; + window_options_display_widgets[WIDX_UPPER_CASE_BANNERS_CHECKBOX].type = WWT_CHECKBOX; break; case WINDOW_OPTIONS_PAGE_CULTURE: // currency: pounds, dollars, etc. (10 total) - RCT2_GLOBAL(0x013CE952 + 12, uint16) = STR_POUNDS + gConfigGeneral.currency_format; + RCT2_GLOBAL(0x013CE952 + 12, uint16) = CurrencyDescriptors[gConfigGeneral.currency_format].stringId; // distance: metric/imperial RCT2_GLOBAL(0x013CE952 + 14, uint16) = STR_IMPERIAL + gConfigGeneral.measurement_format; @@ -1070,18 +1234,23 @@ static void window_options_invalidate() // sound devices if (currentSoundDevice == -1 || gAudioDeviceCount == 0) { - RCT2_GLOBAL(0x013CE952, uint16) = STR_SOUND_NONE; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = STR_SOUND_NONE; } else { - RCT2_GLOBAL(0x013CE952, uint16) = 1170; + if (currentSoundDevice == 0) + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = 5510; + else + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = 1170; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = (uint32)gAudioDevices[currentSoundDevice].name; } // music: on/off - RCT2_GLOBAL(0x013CE952 + 8, uint16) = STR_OFF + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8); + RCT2_GLOBAL(0x013CE952 + 8, uint16) = STR_OFF + gConfigSound.ride_music; 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)); + widget_set_checkbox_value(w, WIDX_MUSIC_CHECKBOX, gConfigSound.ride_music); + widget_set_checkbox_value(w, WIDX_AUDIO_FOCUS_CHECKBOX, gConfigSound.audio_focus); 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]; @@ -1097,28 +1266,37 @@ static void window_options_invalidate() 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_AUDIO_FOCUS_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_CONTROLS: + case WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE: widget_set_checkbox_value(w, WIDX_SCREEN_EDGE_SCROLLING, gConfigGeneral.edge_scrolling); + widget_set_checkbox_value(w, WIDX_INVERT_DRAG, gConfigGeneral.invert_viewport_drag); 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); + widget_set_checkbox_value(w, WIDX_TOOLBAR_SHOW_NEWS, gConfigInterface.toolbar_show_news); + widget_set_checkbox_value(w, WIDX_SELECT_BY_TRACK_TYPE, gConfigInterface.select_by_track_type); - 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; + window_options_controls_and_interface_widgets[WIDX_THEMES].type = WWT_DROPDOWN; + window_options_controls_and_interface_widgets[WIDX_THEMES_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_controls_and_interface_widgets[WIDX_THEMES_BUTTON].type = WWT_DROPDOWN_BUTTON; + window_options_controls_and_interface_widgets[WIDX_SCREEN_EDGE_SCROLLING].type = WWT_CHECKBOX; + window_options_controls_and_interface_widgets[WIDX_HOTKEY_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_options_controls_and_interface_widgets[WIDX_TOOLBAR_SHOW_FINANCES].type = WWT_CHECKBOX; + window_options_controls_and_interface_widgets[WIDX_TOOLBAR_SHOW_RESEARCH].type = WWT_CHECKBOX; + window_options_controls_and_interface_widgets[WIDX_TOOLBAR_SHOW_CHEATS].type = WWT_CHECKBOX; + window_options_controls_and_interface_widgets[WIDX_TOOLBAR_SHOW_NEWS].type = WWT_CHECKBOX; + window_options_controls_and_interface_widgets[WIDX_SELECT_BY_TRACK_TYPE].type = WWT_CHECKBOX; break; case WINDOW_OPTIONS_PAGE_MISC: // unknown park flag can disable real name checkbox - if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & 0x8000) + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_LOCK_REAL_NAMES_OPTION) w->disabled_widgets |= (1ULL << WIDX_REAL_NAME_CHECKBOX); // save plugin data checkbox: visible or not @@ -1127,23 +1305,28 @@ static void window_options_invalidate() else window_options_misc_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_HANDYMEN_MOW_DEFAULT, gConfigGeneral.handymen_mow_default); widget_set_checkbox_value(w, WIDX_DEBUGGING_TOOLS, gConfigGeneral.debugging_tools); + widget_set_checkbox_value(w, WIDX_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM, gConfigGeneral.allow_loading_with_incorrect_checksum); + widget_set_checkbox_value(w, WIDX_STAY_CONNECTED_AFTER_DESYNC, gConfigNetwork.stay_connected); 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_HANDYMEN_MOW_DEFAULT].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; + window_options_misc_widgets[WIDX_TITLE_SEQUENCE_BUTTON].type = WWT_DROPDOWN_BUTTON; + window_options_misc_widgets[WIDX_ALLOW_LOADING_WITH_INCORRECT_CHECKSUM].type = WWT_CHECKBOX; + window_options_misc_widgets[WIDX_STAY_CONNECTED_AFTER_DESYNC].type = WWT_CHECKBOX; break; case WINDOW_OPTIONS_PAGE_TWITCH: @@ -1192,13 +1375,8 @@ static void window_options_update(rct_window *w) * * rct2: 0x006BAEB4 */ -static void window_options_paint() +static void window_options_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_options_draw_tab_images(dpi, w); @@ -1207,24 +1385,18 @@ static void window_options_paint() 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); + gfx_draw_string_left(dpi, STR_UI_SCALING_DESC, w, w->colours[1], w->x + 10, w->y + window_options_display_widgets[WIDX_SCALE].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 - ); + int scale = (int)(gConfigGeneral.window_scale * 100); + gfx_draw_string_left(dpi, 3311, &scale, w->colours[1], w->x + w->widgets[WIDX_SCALE].left + 1, w->y + w->widgets[WIDX_SCALE].top + 1); break; case WINDOW_OPTIONS_PAGE_CULTURE: gfx_draw_string_left(dpi, 2776, w, w->colours[1], w->x + 10, w->y + window_options_culture_widgets[WIDX_LANGUAGE].top + 1); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; gfx_draw_string( dpi, - (char*)language_names[gCurrentLanguage], + (char*)LanguagesDescriptors[gCurrentLanguage].native_name, w->colours[1], w->x + window_options_culture_widgets[WIDX_LANGUAGE].left + 1, w->y + window_options_culture_widgets[WIDX_LANGUAGE].top @@ -1234,15 +1406,15 @@ static void window_options_paint() 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, STR_DATE_FORMAT, 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, + DateFormatStringIds[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, 2738, w, w->colours[1], w->x + 10, w->y + window_options_audio_widgets[WIDX_TITLE_MUSIC].top + 1); @@ -1255,25 +1427,41 @@ static void window_options_paint() w->y + window_options_audio_widgets[WIDX_TITLE_MUSIC].top ); break; + case WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE: + gfx_draw_string_left(dpi, STR_SHOW_TOOLBAR_BUTTONS_FOR, w, w->colours[1], w->x + 10, w->y + window_options_controls_and_interface_widgets[WIDX_TOOLBAR_BUTTONS_GROUP].top + 15); + 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_controls_and_interface_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_controls_and_interface_widgets[WIDX_THEMES].left + 1, + w->y + window_options_controls_and_interface_widgets[WIDX_THEMES].top, + window_options_controls_and_interface_widgets[WIDX_THEMES_DROPDOWN].left - window_options_controls_and_interface_widgets[WIDX_THEMES].left - 4 + ); + 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, + STR_SAVE_EVERY_MINUTE + 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 ); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&gConfigTitleSequences.presets[gCurrentPreviewTitleSequence].name; 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( + gfx_draw_string_left_clipped( dpi, - STR_TITLE_SEQUENCE_RCT1 + gConfigGeneral.title_sequence, - NULL, + 1170, + (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, w->colours[1], w->x + window_options_misc_widgets[WIDX_TITLE_SEQUENCE].left + 1, - w->y + window_options_misc_widgets[WIDX_TITLE_SEQUENCE].top + w->y + window_options_misc_widgets[WIDX_TITLE_SEQUENCE].top, + window_options_misc_widgets[WIDX_TITLE_SEQUENCE_DROPDOWN].left - window_options_misc_widgets[WIDX_TITLE_SEQUENCE].left - 4 ); break; } @@ -1293,7 +1481,7 @@ static void window_options_show_dropdown(rct_window *w, rct_widget *widget, int ); } -static void window_options_update_height_markers() +static void window_options_update_height_markers() { RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_HEIGHT_MARKERS, uint16) = gConfigGeneral.show_height_as_units ? 0 : (gConfigGeneral.measurement_format + 1) * 256; @@ -1301,33 +1489,19 @@ static void window_options_update_height_markers() gfx_invalidate_screen(); } -static void window_options_scrollgetsize() +static void window_options_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - 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); + *width = 1000; } } -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) - { +static void window_options_text_input(rct_window *w, int widgetIndex, char *text) +{ + if (text == NULL) return; - } - if (widgetIndex == WIDX_CHANNEL_BUTTON){ + if (widgetIndex == WIDX_CHANNEL_BUTTON) { if (gConfigTwitch.channel != NULL) free(gConfigTwitch.channel); gConfigTwitch.channel = _strdup(text); @@ -1379,7 +1553,7 @@ 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_CONTROLS, 5201); + window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_CONTROLS_AND_INTERFACE, 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); } diff --git a/src/windows/park.c b/src/windows/park.c index 1fe32e1dcb..91be02ae90 100644 --- a/src/windows/park.c +++ b/src/windows/park.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 . *****************************************************************************/ @@ -122,7 +122,7 @@ static rct_widget window_park_guests_widgets[] = { static rct_widget window_park_price_widgets[] = { MAIN_PARK_WIDGETS, - { WWT_24, 1, 7, 146, 50, 61, STR_ADMISSION_PRICE, STR_NONE }, // + { 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 { WWT_DROPDOWN_BUTTON, 1, 211, 221, 56, 60, STR_NUMERIC_DOWN, STR_NONE }, // decrease price @@ -159,286 +159,284 @@ static rct_widget *window_park_page_widgets[] = { #pragma region Events -static void window_park_emptysub() { } - -static void window_park_entrance_close(); -static void window_park_entrance_mouseup(); -static void window_park_entrance_resize(); +static void window_park_entrance_close(rct_window *w); +static void window_park_entrance_mouseup(rct_window *w, int widgetIndex); +static void window_park_entrance_resize(rct_window *w); static void window_park_entrance_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_park_entrance_dropdown(); +static void window_park_entrance_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_park_entrance_update(rct_window *w); -static void window_park_entrance_toolupdate(); -static void window_park_entrance_tooldown(); -static void window_park_entrance_tooldrag(); -static void window_park_entrance_toolabort(); -static void window_park_entrance_textinput(); -static void window_park_entrance_invalidate(); -static void window_park_entrance_paint(); +static void window_park_entrance_toolupdate(rct_window* w, int widgetIndex, int x, int y); +static void window_park_entrance_tooldown(rct_window* w, int widgetIndex, int x, int y); +static void window_park_entrance_tooldrag(rct_window* w, int widgetIndex, int x, int y); +static void window_park_entrance_toolabort(rct_window *w, int widgetIndex); +static void window_park_entrance_textinput(rct_window *w, int widgetIndex, char *text); +static void window_park_entrance_invalidate(rct_window *w); +static void window_park_entrance_paint(rct_window *w, rct_drawpixelinfo *dpi); void toggle_land_rights_window(rct_window *parkWindow, int widgetIndex); -static void window_park_rating_mouseup(); -static void window_park_rating_resize(); +static void window_park_rating_mouseup(rct_window *w, int widgetIndex); +static void window_park_rating_resize(rct_window *w); static void window_park_rating_update(rct_window *w); -static void window_park_rating_invalidate(); -static void window_park_rating_paint(); +static void window_park_rating_invalidate(rct_window *w); +static void window_park_rating_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_park_guests_mouseup(); -static void window_park_guests_resize(); +static void window_park_guests_mouseup(rct_window *w, int widgetIndex); +static void window_park_guests_resize(rct_window *w); static void window_park_guests_update(rct_window *w); -static void window_park_guests_invalidate(); -static void window_park_guests_paint(); +static void window_park_guests_invalidate(rct_window *w); +static void window_park_guests_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_park_price_mouseup(); -static void window_park_price_resize(); +static void window_park_price_mouseup(rct_window *w, int widgetIndex); +static void window_park_price_resize(rct_window *w); static void window_park_price_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); static void window_park_price_update(rct_window *w); -static void window_park_price_invalidate(); -static void window_park_price_paint(); +static void window_park_price_invalidate(rct_window *w); +static void window_park_price_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_park_stats_mouseup(); -static void window_park_stats_resize(); +static void window_park_stats_mouseup(rct_window *w, int widgetIndex); +static void window_park_stats_resize(rct_window *w); static void window_park_stats_update(rct_window *w); -static void window_park_stats_invalidate(); -static void window_park_stats_paint(); +static void window_park_stats_invalidate(rct_window *w); +static void window_park_stats_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_park_objective_mouseup(); -static void window_park_objective_resize(); +static void window_park_objective_mouseup(rct_window *w, int widgetIndex); +static void window_park_objective_resize(rct_window *w); static void window_park_objective_update(rct_window *w); -static void window_park_objective_textinput(); -static void window_park_objective_invalidate(); -static void window_park_objective_paint(); +static void window_park_objective_textinput(rct_window *w, int widgetIndex, char *text); +static void window_park_objective_invalidate(rct_window *w); +static void window_park_objective_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_park_awards_mouseup(); -static void window_park_awards_resize(); +static void window_park_awards_mouseup(rct_window *w, int widgetIndex); +static void window_park_awards_resize(rct_window *w); static void window_park_awards_update(rct_window *w); -static void window_park_awards_invalidate(); -static void window_park_awards_paint(); +static void window_park_awards_invalidate(rct_window *w); +static void window_park_awards_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void* window_park_entrance_events[] = { +static rct_window_event_list window_park_entrance_events = { window_park_entrance_close, window_park_entrance_mouseup, window_park_entrance_resize, window_park_entrance_mousedown, window_park_entrance_dropdown, - window_park_emptysub, + NULL, window_park_entrance_update, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, window_park_entrance_toolupdate, window_park_entrance_tooldown, window_park_entrance_tooldrag, - window_park_emptysub, + NULL, window_park_entrance_toolabort, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, window_park_entrance_textinput, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, window_park_entrance_invalidate, window_park_entrance_paint, - window_park_emptysub + NULL }; -static void* window_park_rating_events[] = { - window_park_emptysub, +static rct_window_event_list window_park_rating_events = { + NULL, window_park_rating_mouseup, window_park_rating_resize, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, + NULL, window_park_rating_update, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_park_rating_invalidate, window_park_rating_paint, - window_park_emptysub + NULL }; -static void* window_park_guests_events[] = { - window_park_emptysub, +static rct_window_event_list window_park_guests_events = { + NULL, window_park_guests_mouseup, window_park_guests_resize, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, + NULL, window_park_guests_update, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_park_guests_invalidate, window_park_guests_paint, - window_park_emptysub + NULL }; -static void* window_park_price_events[] = { - window_park_emptysub, +static rct_window_event_list window_park_price_events = { + NULL, window_park_price_mouseup, window_park_price_resize, window_park_price_mousedown, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, window_park_price_update, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_park_price_invalidate, window_park_price_paint, - window_park_emptysub + NULL }; -static void* window_park_stats_events[] = { - window_park_emptysub, +static rct_window_event_list window_park_stats_events = { + NULL, window_park_stats_mouseup, window_park_stats_resize, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, + NULL, window_park_stats_update, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_park_stats_invalidate, window_park_stats_paint, - window_park_emptysub + NULL }; -static void* window_park_objective_events[] = { - window_park_emptysub, +static rct_window_event_list window_park_objective_events = { + NULL, window_park_objective_mouseup, window_park_objective_resize, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, + NULL, window_park_objective_update, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_park_objective_textinput, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, window_park_objective_invalidate, window_park_objective_paint, - window_park_emptysub + NULL }; -static void* window_park_awards_events[] = { - window_park_emptysub, +static rct_window_event_list window_park_awards_events = { + NULL, window_park_awards_mouseup, window_park_awards_resize, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, + NULL, window_park_awards_update, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, - window_park_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_park_awards_invalidate, window_park_awards_paint, - window_park_emptysub + NULL }; -static void* window_park_page_events[] = { - window_park_entrance_events, - window_park_rating_events, - window_park_guests_events, - window_park_price_events, - window_park_stats_events, - window_park_objective_events, - window_park_awards_events +static rct_window_event_list *window_park_page_events[] = { + &window_park_entrance_events, + &window_park_rating_events, + &window_park_guests_events, + &window_park_price_events, + &window_park_stats_events, + &window_park_objective_events, + &window_park_awards_events }; #pragma endregion @@ -488,7 +486,7 @@ static uint32 window_park_page_enabled_widgets[] = { (1 << WIDX_TAB_5) | (1 << WIDX_TAB_6) | (1 << WIDX_TAB_7) | - (1 << WIDX_INCREASE_PRICE) | + (1 << WIDX_INCREASE_PRICE) | (1 << WIDX_DECREASE_PRICE), (1 << WIDX_CLOSE) | @@ -543,14 +541,14 @@ static void window_park_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w); static void window_park_set_disabled_tabs(rct_window *w); /** - * + * * rct2: 0x00667F11 */ rct_window *window_park_open() { rct_window* w; - w = window_create_auto_pos(230, 174 + 9, (uint32*)window_park_entrance_events, WC_PARK_INFORMATION, WF_10); + w = window_create_auto_pos(230, 174 + 9, &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; @@ -577,14 +575,14 @@ static void window_park_set_disabled_tabs(rct_window *w) static void window_park_prepare_window_title_text() { - RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, 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 /** - * + * * rct2: 0x00667C48 */ void window_park_entrance_open() @@ -602,22 +600,18 @@ void window_park_entrance_open() window_invalidate(window); window->widgets = window_park_entrance_widgets; window->enabled_widgets = window_park_page_enabled_widgets[WINDOW_PARK_PAGE_ENTRANCE]; - window->event_handlers = (uint32*)window_park_entrance_events; + window->event_handlers = &window_park_entrance_events; window->pressed_widgets = 0; window_init_scroll_widgets(window); window_park_init_viewport(window); } /** - * + * * rct2: 0x0066860C */ -static void window_park_entrance_close() +static void window_park_entrance_close(rct_window *w) { - rct_window *w; - - window_get_register(w); - 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(); @@ -627,13 +621,8 @@ static void window_park_entrance_close() * * rct2: 0x0066817C */ -static void window_park_entrance_mouseup() +static void window_park_entrance_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -656,7 +645,7 @@ static void window_park_entrance_mouseup() window_scroll_to_viewport(w); break; case WIDX_RENAME: - RCT2_GLOBAL(0x013CE962, uint32) = RCT2_GLOBAL(0x013573D8, uint32); + RCT2_GLOBAL(0x013CE962, uint32) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME_ARGS, uint32); 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: @@ -672,12 +661,8 @@ static void window_park_entrance_mouseup() * * rct2: 0x00668637 */ -static void window_park_entrance_resize() +static void window_park_entrance_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - w->flags |= WF_RESIZABLE; window_set_resize(w, 230, 174 + 9, 230 * 3, (274 + 9) * 3); window_park_init_viewport(w); @@ -704,29 +689,24 @@ static void window_park_entrance_mousedown(int widgetIndex, rct_window*w, rct_wi ); if (park_is_open()) { - RCT2_GLOBAL(0x009DEBA2, sint16) = 0; - gDropdownItemsChecked |= (1 << 1); + gDropdownHighlightedIndex = 0; + dropdown_set_checked(1, true); } else { - RCT2_GLOBAL(0x009DEBA2, sint16) = 1; - gDropdownItemsChecked |= (1 << 0); + gDropdownHighlightedIndex = 1; + dropdown_set_checked(0, true); } } } /** - * + * * rct2: 0x006682B8 */ -static void window_park_entrance_dropdown() +static void window_park_entrance_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - short widgetIndex, dropdownIndex; - rct_window* w; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (widgetIndex == WIDX_OPEN_OR_CLOSE) { if (dropdownIndex == -1) - dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); + dropdownIndex = gDropdownHighlightedIndex; if (dropdownIndex != 0) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 1724; @@ -739,7 +719,7 @@ static void window_park_entrance_dropdown() } /** - * + * * rct2: 0x006686B5 */ static void window_park_entrance_update(rct_window *w) @@ -754,7 +734,7 @@ void window_park_entrance_tool_update_land_rights(sint16 x, sint16 y){ RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); rct_xy16 mapTile = { 0 }; - sub_688972(x, y, &mapTile.x, &mapTile.y, NULL); + screen_get_map_xy(x, y, &mapTile.x, &mapTile.y, NULL); if (mapTile.x == (sint16)0x8000){ if (RCT2_GLOBAL(0x00F1AD62, money32) != MONEY32_UNDEFINED){ @@ -827,16 +807,11 @@ void window_park_entrance_tool_update_land_rights(sint16 x, sint16 y){ } /** - * + * * rct2: 0x006681D1 */ -static void window_park_entrance_toolupdate() +static void window_park_entrance_toolupdate(rct_window* w, int widgetIndex, int x, int y) { - short x, y, widgetIndex; - rct_window *w; - - window_tool_get_registers(w, widgetIndex, x, y); - switch (widgetIndex){ case WIDX_BUY_LAND_RIGHTS: window_park_entrance_tool_update_land_rights(x, y); @@ -845,16 +820,11 @@ static void window_park_entrance_toolupdate() } /** - * + * * rct2: 0x006681E6 */ -static void window_park_entrance_tooldown() +static void window_park_entrance_tooldown(rct_window* w, int widgetIndex, int x, int y) { - short x, y, widgetIndex; - rct_window *w; - - window_tool_get_registers(w, widgetIndex, x, y); - switch (widgetIndex){ case WIDX_BUY_LAND_RIGHTS: if (LandRightsMode) { @@ -890,18 +860,13 @@ static void window_park_entrance_tooldown() } /** - * + * * rct2: 0x006681FB */ -static void window_park_entrance_tooldrag() +static void window_park_entrance_tooldrag(rct_window* w, int widgetIndex, int x, int y) { - short x, y, widgetIndex; - rct_window *w; - - window_tool_get_registers(w, widgetIndex, x, y); - rct_window* w2 = window_find_by_number(0xB, 0); - + if (!w2) { switch (widgetIndex){ case WIDX_BUY_LAND_RIGHTS: @@ -939,23 +904,18 @@ static void window_park_entrance_tooldrag() } /** - * + * * rct2: 0x0066822A */ -static void window_park_entrance_toolabort() +static void window_park_entrance_toolabort(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - if (widgetIndex == WIDX_BUY_LAND_RIGHTS) { hide_gridlines(); if (LandRightsMode) hide_land_rights(); else hide_construction_rights(); - } + } //else if (widgetIndex == WIDX_BUY_CONSTRUCTION_RIGHTS) { // hide_gridlines(); // hide_construction_rights(); @@ -963,32 +923,23 @@ static void window_park_entrance_toolabort() } /** - * + * * rct2: 0x0066848B */ -static void window_park_entrance_textinput() +static void window_park_entrance_textinput(rct_window *w, int widgetIndex, char *text) { - uint8 result; - short widgetIndex; - rct_window *w; - char *text; - - window_textinput_get_registers(w, widgetIndex, result, text); - - if (widgetIndex == WIDX_RENAME && result) + if (widgetIndex == WIDX_RENAME && text != NULL) park_set_name(text); } /** - * + * * rct2: 0x00667FDC */ -static void window_park_entrance_invalidate() +static void window_park_entrance_invalidate(rct_window *w) { int i, height; - rct_window *w; - window_get_register(w); colour_scheme_update(w); w->widgets = window_park_page_widgets[w->page]; @@ -997,7 +948,7 @@ static void window_park_entrance_invalidate() window_park_set_pressed_tab(w); // Set open / close park button state - RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_PARK_NAME, rct_string_id); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, 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); @@ -1010,7 +961,7 @@ static void window_park_entrance_invalidate() 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; @@ -1026,7 +977,7 @@ 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; - + 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) { @@ -1063,17 +1014,13 @@ static void window_park_entrance_invalidate() } /** - * + * * rct2: 0x006680D0 */ -static void window_park_entrance_paint() +static void window_park_entrance_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_widget *labelWidget; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_park_draw_tab_images(dpi, w); @@ -1085,7 +1032,7 @@ static void window_park_entrance_paint() } // Draw park closed / open label - RCT2_GLOBAL(0x013CE952, uint16) = park_is_open() ? STR_PARK_OPEN : STR_PARK_CLOSED; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = park_is_open() ? STR_PARK_OPEN : STR_PARK_CLOSED; labelWidget = &window_park_entrance_widgets[WIDX_STATUS]; gfx_draw_string_centred_clipped( @@ -1100,12 +1047,13 @@ static void window_park_entrance_paint() } /** - * + * * rct2: 0x00669B55 */ static void window_park_init_viewport(rct_window *w) { int i, x, y, z, r, xy, zr, viewportFlags; + x = y = z = r = xy = zr = 0; rct_viewport *viewport; rct_widget *viewportWidget; @@ -1113,11 +1061,11 @@ static void window_park_init_viewport(rct_window *w) return; for (i = 0; i < 4; i++) { - if (RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[i] != SPRITE_LOCATION_NULL) { - x = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, uint16)[i] + 16; - y = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, uint16)[i] + 16; - z = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Z, uint16)[i] + 32; - r = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + if (RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[i] != SPRITE_LOCATION_NULL) { + x = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[i] + 16; + y = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, sint16)[i] + 16; + z = RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Z, sint16)[i] + 32; + r = get_current_rotation(); xy = 0x40000000 | (y << 16) | x; zr = (z << 16) | (r << 8); @@ -1176,7 +1124,8 @@ static void window_park_init_viewport(rct_window *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) { + if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == WC_PARK_INFORMATION && + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == WIDX_BUY_LAND_RIGHTS) { tool_cancel(); } else { @@ -1217,7 +1166,7 @@ void window_park_rating_open() window->widgets = window_park_rating_widgets; window->enabled_widgets = window_park_page_enabled_widgets[WINDOW_PARK_PAGE_RATING]; window->hold_down_widgets = window_park_page_hold_down_widgets[WINDOW_PARK_PAGE_RATING]; - window->event_handlers = (uint32*)window_park_rating_events; + window->event_handlers = &window_park_rating_events; window_init_scroll_widgets(window); } @@ -1225,13 +1174,8 @@ void window_park_rating_open() * * rct2: 0x00668A06 */ -static void window_park_rating_mouseup() +static void window_park_rating_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - if (widgetIndex == WIDX_CLOSE) window_close(w); else if (widgetIndex >= WIDX_TAB_1 && widgetIndex <= WIDX_TAB_7) @@ -1242,12 +1186,8 @@ static void window_park_rating_mouseup() * * rct2: 0x00668A36 */ -static void window_park_rating_resize() +static void window_park_rating_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 230, 182, 230, 182); } @@ -1265,12 +1205,10 @@ static void window_park_rating_update(rct_window *w) * * rct2: 0x006686CB */ -static void window_park_rating_invalidate() +static void window_park_rating_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; - window_get_register(w); colour_scheme_update(w); widgets = window_park_page_widgets[w->page]; @@ -1290,15 +1228,10 @@ static void window_park_rating_invalidate() * * rct2: 0x0066875D */ -static void window_park_rating_paint() +static void window_park_rating_paint(rct_window *w, rct_drawpixelinfo *dpi) { int x, y; - rct_window *w; - rct_drawpixelinfo *dpi; rct_widget *widget; - uint8 *history; - - window_paint_get_registers(w, dpi); window_draw_widgets(w, dpi); window_park_draw_tab_images(dpi, w); @@ -1317,8 +1250,7 @@ static void window_park_rating_paint() x += widget->left + 22; y += widget->top + 26; - history = RCT2_ADDRESS(RCT2_ADDRESS_PARK_RATING_HISTORY, uint8); - graph_draw_uint8(dpi, history, 32, x, y); + graph_draw_uint8(dpi, gParkRatingHistory, 32, x, y); } #pragma endregion @@ -1350,7 +1282,7 @@ void window_park_guests_open() window->widgets = window_park_guests_widgets; window->enabled_widgets = window_park_page_enabled_widgets[WINDOW_PARK_PAGE_GUESTS]; window->hold_down_widgets = window_park_page_hold_down_widgets[WINDOW_PARK_PAGE_GUESTS]; - window->event_handlers = (uint32*)window_park_guests_events; + window->event_handlers = &window_park_guests_events; window_init_scroll_widgets(window); } @@ -1358,13 +1290,8 @@ void window_park_guests_open() * * rct2: 0x00668DEB */ -static void window_park_guests_mouseup() +static void window_park_guests_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - if (widgetIndex == WIDX_CLOSE) window_close(w); else if (widgetIndex >= WIDX_TAB_1 && widgetIndex <= WIDX_TAB_7) @@ -1375,12 +1302,8 @@ static void window_park_guests_mouseup() * * rct2: 0x00668E33 */ -static void window_park_guests_resize() +static void window_park_guests_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 230, 182, 230, 182); } @@ -1399,12 +1322,10 @@ static void window_park_guests_update(rct_window *w) * * rct2: 0x00668AB0 */ -static void window_park_guests_invalidate() +static void window_park_guests_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; - window_get_register(w); colour_scheme_update(w); widgets = window_park_page_widgets[w->page]; @@ -1424,15 +1345,10 @@ static void window_park_guests_invalidate() * * rct2: 0x00668B42 */ -static void window_park_guests_paint() +static void window_park_guests_paint(rct_window *w, rct_drawpixelinfo *dpi) { int x, y; - rct_window *w; - rct_drawpixelinfo *dpi; rct_widget *widget; - uint8 *history; - - window_paint_get_registers(w, dpi); window_draw_widgets(w, dpi); window_park_draw_tab_images(dpi, w); @@ -1451,8 +1367,7 @@ static void window_park_guests_paint() x += widget->left + 22; y += widget->top + 26; - history = RCT2_ADDRESS(RCT2_ADDRESS_GUESTS_IN_PARK_HISTORY, uint8); - graph_draw_uint8(dpi, history, 32, x, y); + graph_draw_uint8(dpi, gGuestsInParkHistory, 32, x, y); } #pragma endregion @@ -1463,13 +1378,8 @@ static void window_park_guests_paint() * * rct2: 0x00669011 */ -static void window_park_price_mouseup() +static void window_park_price_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - if (widgetIndex == WIDX_CLOSE) window_close(w); else if (widgetIndex >= WIDX_TAB_1 && widgetIndex <= WIDX_TAB_7) @@ -1480,12 +1390,8 @@ static void window_park_price_mouseup() * * rct2: 0x0066908C */ -static void window_park_price_resize() +static void window_park_price_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 230, 124, 230, 124); } @@ -1535,12 +1441,10 @@ static void window_park_price_update(rct_window *w) * * rct2: 0x00668EAD */ -static void window_park_price_invalidate() +static void window_park_price_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; - window_get_register(w); colour_scheme_update(w); widgets = window_park_page_widgets[w->page]; @@ -1575,14 +1479,10 @@ static void window_park_price_invalidate() * * rct2: 0x00668F99 */ -static void window_park_price_paint() +static void window_park_price_paint(rct_window *w, rct_drawpixelinfo *dpi) { int x, y; - rct_window *w; - rct_drawpixelinfo *dpi; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_park_draw_tab_images(dpi, w); @@ -1602,13 +1502,8 @@ static void window_park_price_paint() * * rct2: 0x0066928C */ -static void window_park_stats_mouseup() +static void window_park_stats_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - if (widgetIndex == WIDX_CLOSE) window_close(w); else if (widgetIndex >= WIDX_TAB_1 && widgetIndex <= WIDX_TAB_7) @@ -1619,12 +1514,8 @@ static void window_park_stats_mouseup() * * rct2: 0x00669338 */ -static void window_park_stats_resize() +static void window_park_stats_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 230, 109, 230, 109); } @@ -1658,12 +1549,10 @@ static void window_park_stats_update(rct_window *w) * * rct2: 0x00669106 */ -static void window_park_stats_invalidate() +static void window_park_stats_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; - window_get_register(w); colour_scheme_update(w); widgets = window_park_page_widgets[w->page]; @@ -1683,14 +1572,10 @@ static void window_park_stats_invalidate() * * rct2: 0x00669198 */ -static void window_park_stats_paint() +static void window_park_stats_paint(rct_window *w, rct_drawpixelinfo *dpi) { int x, y, parkSize, stringIndex; - rct_window *w; - rct_drawpixelinfo *dpi; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_park_draw_tab_images(dpi, w); @@ -1704,20 +1589,20 @@ static void window_park_stats_paint() stringIndex = STR_PARK_SIZE_IMPERIAL_LABEL; parkSize = squaredmetres_to_squaredfeet(parkSize); } - RCT2_GLOBAL(0x013CE952, uint32) = parkSize; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) = parkSize; gfx_draw_string_left(dpi, stringIndex, (void*)0x013CE952, 0, x, y); y += 10; // Draw number of rides / attractions if (w->list_information_type != (uint16)-1) { - RCT2_GLOBAL(0x013CE952, uint32) = w->list_information_type; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) = w->list_information_type; gfx_draw_string_left(dpi, STR_NUMBER_OF_RIDES_LABEL, (void*)0x013CE952, 0, x, y); } y += 10; // Draw number of staff if (w->var_48C != -1) { - RCT2_GLOBAL(0x013CE952, uint32) = w->var_48C; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) = w->var_48C; gfx_draw_string_left(dpi, STR_STAFF_LABEL, (void*)0x013CE952, 0, x, y); } y += 10; @@ -1731,7 +1616,7 @@ static void window_park_stats_paint() #pragma region Objective page /** - * + * * rct2: 0x00667E57 */ void window_park_objective_open() @@ -1755,24 +1640,19 @@ void window_park_objective_open() window->widgets = window_park_objective_widgets; window->enabled_widgets = window_park_page_enabled_widgets[WINDOW_PARK_PAGE_OBJECTIVE]; window->hold_down_widgets = window_park_page_hold_down_widgets[WINDOW_PARK_PAGE_OBJECTIVE]; - window->event_handlers = (uint32*)window_park_objective_events; + window->event_handlers = &window_park_objective_events; window_init_scroll_widgets(window); - window->x = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) / 2 - 115; - window->y = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) / 2 - 87; + window->x = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2 - 115; + window->y = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) / 2 - 87; window_invalidate(window); } /** - * + * * rct2: 0x006695AA */ -static void window_park_objective_mouseup() +static void window_park_objective_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -1804,17 +1684,13 @@ static void window_park_objective_mouseup() * * rct2: 0x00669681 */ -static void window_park_objective_resize() +static void window_park_objective_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 230, 224, 230, 224); } /** - * + * * rct2: 0x0066966C */ static void window_park_objective_update(rct_window *w) @@ -1824,39 +1700,29 @@ static void window_park_objective_update(rct_window *w) } /** - * + * * rct2: 0x006695CC */ -static void window_park_objective_textinput() +static void window_park_objective_textinput(rct_window *w, int widgetIndex, char *text) { - uint8 result; - short widgetIndex; - rct_window *w; - char *text; - - window_textinput_get_registers(w, widgetIndex, result, text); - - if (widgetIndex == WIDX_ENTER_NAME && result && text[0] != 0) { + if (widgetIndex == WIDX_ENTER_NAME && text != NULL && text[0] != 0) { scenario_success_submit_name(text); window_invalidate(w); } } /** - * + * * rct2: 0x006693B2 */ -static void window_park_objective_invalidate() +static void window_park_objective_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); window_park_set_pressed_tab(w); window_park_prepare_window_title_text(); - // + // if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_SCENARIO_COMPLETE_NAME_INPUT) window_park_objective_widgets[WIDX_ENTER_NAME].type = WWT_DROPDOWN_BUTTON; else @@ -1867,25 +1733,21 @@ static void window_park_objective_invalidate() } /** - * + * * rct2: 0x0066945C */ -static void window_park_objective_paint() +static void window_park_objective_paint(rct_window *w, rct_drawpixelinfo *dpi) { int x, y; - rct_window *w; - rct_drawpixelinfo *dpi; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_park_draw_tab_images(dpi, w); // Scenario description x = w->x + window_park_objective_widgets[WIDX_PAGE_BACKGROUND].left + 4; y = w->y + window_park_objective_widgets[WIDX_PAGE_BACKGROUND].top + 7; - strcpy((char*)0x009BC677, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIO_DETAILS, char)); - RCT2_GLOBAL(0x013CE952, short) = 3165; + safe_strncpy((char*)0x009BC677, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIO_DETAILS, char), 256); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, short) = 3165; y += gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x, y, 222, 1191, 0); y += 5; @@ -1894,13 +1756,13 @@ static void window_park_objective_paint() y += 10; // Objective - RCT2_GLOBAL(0x013CE952, short) = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, short) = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_NUM_GUESTS, uint16); RCT2_GLOBAL(0x013CE954, short) = date_get_total_months(MONTH_OCTOBER, RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_YEAR, uint8)); RCT2_GLOBAL(0x013CE956, int) = RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_CURRENCY, sint32); y += gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x, y, 221, 2385 + RCT2_GLOBAL(RCT2_ADDRESS_OBJECTIVE_TYPE, uint8), 0); y += 5; - + // Objective outcome if (RCT2_GLOBAL(RCT2_ADDRESS_COMPLETED_COMPANY_VALUE, money32) != MONEY32_UNDEFINED) { if (RCT2_GLOBAL(RCT2_ADDRESS_COMPLETED_COMPANY_VALUE, money32) == 0x80000001) { @@ -1908,7 +1770,7 @@ static void window_park_objective_paint() gfx_draw_string_left_wrapped(dpi, NULL, x, y, 222, 2789, 0); } else { // Objective completed - RCT2_GLOBAL(0x013CE952, int) = RCT2_GLOBAL(RCT2_ADDRESS_COMPLETED_COMPANY_VALUE, money32); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, int) = RCT2_GLOBAL(RCT2_ADDRESS_COMPLETED_COMPANY_VALUE, money32); gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x, y, 222, 2788, 0); } } @@ -1943,7 +1805,7 @@ void window_park_awards_open() window->widgets = window_park_awards_widgets; window->enabled_widgets = window_park_page_enabled_widgets[WINDOW_PARK_PAGE_AWARDS]; window->hold_down_widgets = window_park_page_hold_down_widgets[WINDOW_PARK_PAGE_AWARDS]; - window->event_handlers = (uint32*)window_park_awards_events; + window->event_handlers = &window_park_awards_events; window_init_scroll_widgets(window); } @@ -1951,13 +1813,8 @@ void window_park_awards_open() * * rct2: 0x00669851 */ -static void window_park_awards_mouseup() +static void window_park_awards_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - if (widgetIndex == WIDX_CLOSE) window_close(w); else if (widgetIndex >= WIDX_TAB_1 && widgetIndex <= WIDX_TAB_7) @@ -1968,12 +1825,8 @@ static void window_park_awards_mouseup() * * rct2: 0x00669882 */ -static void window_park_awards_resize() +static void window_park_awards_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 230, 182, 230, 182); } @@ -1991,12 +1844,10 @@ static void window_park_awards_update(rct_window *w) * * rct2: 0x006696FB */ -static void window_park_awards_invalidate() +static void window_park_awards_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; - window_get_register(w); colour_scheme_update(w); widgets = window_park_page_widgets[w->page]; @@ -2016,15 +1867,11 @@ static void window_park_awards_invalidate() * * rct2: 0x0066978D */ -static void window_park_awards_paint() +static void window_park_awards_paint(rct_window *w, rct_drawpixelinfo *dpi) { int i, count, x, y; - rct_window *w; - rct_drawpixelinfo *dpi; rct_award *award; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_park_draw_tab_images(dpi, w); @@ -2134,7 +1981,7 @@ static void window_park_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w) if (w->page == WINDOW_PARK_PAGE_GUESTS) sprite_idx += (w->frame_no / 8) % 8; gfx_draw_sprite(dpi, sprite_idx, w->x + w->widgets[WIDX_TAB_3].left, w->y + w->widgets[WIDX_TAB_3].top, 0); - + sprite_idx = *RCT2_GLOBAL(0x00982708, sint32*) + 1; if (w->page == WINDOW_PARK_PAGE_GUESTS) sprite_idx += w->var_492 & 0xFFFFFFFC; diff --git a/src/windows/player_list.c b/src/windows/player_list.c new file mode 100644 index 0000000000..f482781f10 --- /dev/null +++ b/src/windows/player_list.c @@ -0,0 +1,322 @@ +/***************************************************************************** + * 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 "../interface/themes.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../network/network.h" +#include "../sprites.h" +#include "../windows/dropdown.h" +#include "../util/util.h" + +enum WINDOW_PLAYER_LIST_WIDGET_IDX { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_CONTENT_PANEL, + WIDX_TAB1, + WIDX_LIST, +}; + +static rct_widget window_player_list_widgets[] = { + { WWT_FRAME, 0, 0, 339, 0, 239, 0x0FFFFFFFF, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, 338, 1, 14, STR_PLAYER_LIST, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, 327, 337, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_RESIZE, 1, 0, 339, 43, 239, 0x0FFFFFFFF, STR_NONE }, // content panel + { WWT_TAB, 1, 3, 33, 17, 43, 0x02000144E, STR_NONE }, // tab + { WWT_SCROLL, 1, 3, 336, 60, 236, 2, STR_NONE }, // list + { WIDGETS_END }, +}; + +static void window_player_list_mouseup(rct_window *w, int widgetIndex); +static void window_player_list_resize(rct_window *w); +static void window_player_list_mousedown(int widgetIndex, rct_window* w, rct_widget* widget); +static void window_player_list_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); +static void window_player_list_update(rct_window *w); +static void window_player_list_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_player_list_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_player_list_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_player_list_invalidate(rct_window *w); +static void window_player_list_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_player_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); + +static rct_window_event_list window_player_list_events = { + NULL, + window_player_list_mouseup, + window_player_list_resize, + window_player_list_mousedown, + window_player_list_dropdown, + NULL, + window_player_list_update, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_player_list_scrollgetsize, + window_player_list_scrollmousedown, + NULL, + window_player_list_scrollmouseover, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_player_list_invalidate, + window_player_list_paint, + window_player_list_scrollpaint +}; + +enum { + DDIDX_KICK +}; + +static void window_player_list_refresh_list(rct_window *w); + +static int _dropdownPlayerId; + +void window_player_list_open() +{ + rct_window* window; + + // Check if window is already open + window = window_bring_to_front_by_class(WC_PLAYER_LIST); + if (window != NULL) + return; + + window = window_create_auto_pos(320, 144, &window_player_list_events, WC_PLAYER_LIST, WF_10 | WF_RESIZABLE); + + window->widgets = window_player_list_widgets; + window->enabled_widgets = 1 << WIDX_CLOSE; + window_init_scroll_widgets(window); + window->no_list_items = 0; + window->selected_list_item = -1; + window->frame_no = 0; + window->min_width = 320; + window->min_height = 124; + window->max_width = 500; + window->max_height = 450; + + window->page = 0; + window->list_information_type = 0; + window->colours[0] = 7; + window->colours[1] = 7; + window->colours[2] = 7; +} + +static void window_player_list_mouseup(rct_window *w, int widgetIndex) +{ + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + } +} + +static void window_player_list_resize(rct_window *w) +{ + 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; + } + + window_player_list_refresh_list(w); +} + +static void window_player_list_mousedown(int widgetIndex, rct_window* w, rct_widget* widget) +{ + switch (widgetIndex) { + case WIDX_TAB1: + if (w->page != widgetIndex - WIDX_TAB1) { + w->page = widgetIndex - WIDX_TAB1; + w->no_list_items = 0; + w->frame_no = 0; + w->selected_list_item = -1; + window_invalidate(w); + } + break; + } +} + +static void window_player_list_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) +{ + switch (dropdownIndex) { + case DDIDX_KICK: + network_kick_player(_dropdownPlayerId); + break; + } +} + +static void window_player_list_update(rct_window *w) +{ + widget_invalidate(w, WIDX_TAB1 + w->page); +} + +static void window_player_list_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) +{ + int i; + + if (w->selected_list_item != -1) { + w->selected_list_item = -1; + window_invalidate(w); + } + + *height = network_get_num_players() * 10; + i = *height - window_player_list_widgets[WIDX_LIST].bottom + window_player_list_widgets[WIDX_LIST].top + 21; + if (i < 0) + i = 0; + if (i < w->scrolls[0].v_top) { + w->scrolls[0].v_top = i; + window_invalidate(w); + } +} + +static void window_player_list_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) +{ + if (network_get_mode() != NETWORK_MODE_SERVER) { + return; + } + + int index; + + index = y / 10; + if (index >= w->no_list_items) + return; + + w->selected_list_item = index; + window_invalidate(w); + + rct_widget *listWidget = &w->widgets[WIDX_LIST]; + int ddx = w->x + listWidget->left + x; + int ddy = w->y + listWidget->top + y; + + if (index == 0) { + return; + } + _dropdownPlayerId = network_get_player_id(index); + if (_dropdownPlayerId == network_get_current_player_id()) { + return; + } + + gDropdownItemsFormat[0] = STR_KICK_PLAYER; + window_dropdown_show_text(ddx, ddy, 0, 7, 0, 1); +} + +static void window_player_list_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) +{ + int index; + + index = y / 10; + if (index >= w->no_list_items) + return; + + w->selected_list_item = index; + window_invalidate(w); +} + +static void window_player_list_invalidate(rct_window *w) +{ + for (int i = 0; i < 1; i++) + w->pressed_widgets &= ~(1 << (WIDX_TAB1 + i)); + w->pressed_widgets |= 1LL << (WIDX_TAB1 + w->page); + window_player_list_widgets[WIDX_BACKGROUND].right = w->width - 1; + window_player_list_widgets[WIDX_BACKGROUND].bottom = w->height - 1; + window_player_list_widgets[WIDX_CONTENT_PANEL].right = w->width - 1; + window_player_list_widgets[WIDX_CONTENT_PANEL].bottom = w->height - 1; + window_player_list_widgets[WIDX_TITLE].right = w->width - 2; + window_player_list_widgets[WIDX_CLOSE].left = w->width - 2 - 0x0B; + window_player_list_widgets[WIDX_CLOSE].right = w->width - 2 - 0x0B + 0x0A; + window_player_list_widgets[WIDX_LIST].right = w->width - 4; + window_player_list_widgets[WIDX_LIST].bottom = w->height - 0x0F; +} + +static void window_player_list_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ + window_draw_widgets(w, dpi); + gfx_draw_string_left(dpi, STR_PLAYER, w, w->colours[2], w->x + 6, 58 - 12 + w->y + 1); + gfx_draw_string_left(dpi, STR_PING, w, w->colours[2], w->x + 246, 58 - 12 + w->y + 1); + + gfx_draw_sprite(dpi, SPR_TAB_GUESTS_0, w->x + w->widgets[WIDX_TAB1].left, w->y + w->widgets[WIDX_TAB1].top, 0); +} + +static void window_player_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) +{ + int y; + + gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, ColourMapA[w->colours[1]].mid_light); + + y = 0; + for (int i = 0; i < network_get_num_players(); i++) { + if (y > dpi->y + dpi->height) { + break; + } + + if (y + 11 >= dpi->y) { + char buffer[300]; + char* lineCh = buffer; + int colour = 0; + if (i == w->selected_list_item) { + gfx_fill_rect(dpi, 0, y, 800, y + 9, 0x02000031); + safe_strncpy(&buffer[0], network_get_player_name(i), sizeof(buffer)); + colour = w->colours[2]; + } else { + if (network_get_player_flags(i) & NETWORK_PLAYER_FLAG_ISSERVER) { + lineCh = utf8_write_codepoint(lineCh, FORMAT_BABYBLUE); + } else { + lineCh = utf8_write_codepoint(lineCh, FORMAT_BLACK); + } + safe_strncpy(lineCh, network_get_player_name(i), sizeof(buffer) - (lineCh - buffer)); + } + gfx_clip_string(buffer, 230); + gfx_draw_string(dpi, buffer, colour, 0, y - 1); + lineCh = buffer; + int ping = network_get_player_ping(i); + if (ping <= 100) { + lineCh = utf8_write_codepoint(lineCh, FORMAT_GREEN); + } else + if (ping <= 250) { + lineCh = utf8_write_codepoint(lineCh, FORMAT_YELLOW); + } else { + lineCh = utf8_write_codepoint(lineCh, FORMAT_RED); + } + sprintf(lineCh, "%d ms", ping); + gfx_draw_string(dpi, buffer, colour, 240, y - 1); + } + y += 10; + } +} + +static void window_player_list_refresh_list(rct_window *w) +{ + w->no_list_items = network_get_num_players(); + w->list_item_positions[0] = 0; + + w->selected_list_item = -1; + window_invalidate(w); +} diff --git a/src/windows/publisher_credits.c b/src/windows/publisher_credits.c index 270a2d790c..08eed0e41f 100644 --- a/src/windows/publisher_credits.c +++ b/src/windows/publisher_credits.c @@ -38,39 +38,38 @@ rct_widget window_publisher_credits_widgets[] = { { WIDGETS_END }, }; -static void window_publisher_credits_emptysub() { } -static void window_publisher_credits_mouseup(); -static void window_publisher_credits_scrollgetsize(); -static void window_publisher_credits_paint(); -static void window_publisher_credits_scrollpaint(); +static void window_publisher_credits_mouseup(rct_window *w, int widgetIndex); +static void window_publisher_credits_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_publisher_credits_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_publisher_credits_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void* window_publisher_credits_events[] = { - window_publisher_credits_emptysub, +static rct_window_event_list window_publisher_credits_events = { + NULL, window_publisher_credits_mouseup, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_publisher_credits_scrollgetsize, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, - window_publisher_credits_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_publisher_credits_paint, window_publisher_credits_scrollpaint }; @@ -91,7 +90,7 @@ void window_publisher_credits_open() window = window_create_centred( 420, 384, - (uint32*)window_publisher_credits_events, + &window_publisher_credits_events, WC_PUBLISHER_CREDITS, 0 ); @@ -110,13 +109,8 @@ void window_publisher_credits_open() * * rct2: 0x0066D7A8 */ -static void window_publisher_credits_mouseup() +static void window_publisher_credits_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -128,26 +122,17 @@ static void window_publisher_credits_mouseup() * * rct2: 0x0066D7B3 */ -static void window_publisher_credits_scrollgetsize() +static void window_publisher_credits_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - int width, height; - - width = 0; - height = 820; - window_scrollsize_set_registers(width, height); + *height = 820; } /** * * rct2: 0x0066D5CB */ -static void window_publisher_credits_paint() +static void window_publisher_credits_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); } @@ -180,12 +165,8 @@ int credits_order[] = { * * rct2: 0x0066D5D1 */ -static void window_publisher_credits_scrollpaint() +static void window_publisher_credits_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { - rct_window *w; - rct_drawpixelinfo *dpi; - window_paint_get_registers(w, dpi); - int x = 200; int y = 2; diff --git a/src/windows/research.c b/src/windows/research.c index 32c5792a6f..0c03911c09 100644 --- a/src/windows/research.c +++ b/src/windows/research.c @@ -31,6 +31,7 @@ #include "../world/scenery.h" #include "dropdown.h" #include "../interface/themes.h" +#include "../rct1.h" enum { WINDOW_RESEARCH_PAGE_DEVELOPMENT, @@ -71,7 +72,7 @@ static rct_widget window_research_development_widgets[] = { { 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_RESEARCH_AND_DEVELOPMENT_TIP }, - { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH }, + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH_TIP }, { WWT_GROUPBOX, 2, 3, 292, 47, 116, STR_CURRENTLY_IN_DEVELOPMENT, STR_NONE }, { WWT_GROUPBOX, 2, 3, 292, 124, 188, STR_LAST_DEVELOPMENT, STR_NONE }, { WWT_FLATBTN, 2, 265, 288, 161, 184, 0xFFFFFFFF, STR_RESEARCH_SHOW_DETAILS_TIP }, @@ -84,7 +85,7 @@ static rct_widget window_research_funding_widgets[] = { { WWT_CLOSEBOX, 0, 307, 317, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, { WWT_RESIZE, 1, 0, 319, 43, 206, 0xFFFFFFFF, STR_NONE }, { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_RESEARCH_AND_DEVELOPMENT_TIP }, - { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH }, + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH_TIP }, { WWT_GROUPBOX, 2, 3, 316, 47, 91, STR_RESEARCH_FUNDING_, STR_NONE }, { WWT_DROPDOWN, 2, 8, 167, 59, 70, 0xFFFFFFFF, STR_SELECT_LEVEL_OF_RESEARCH_AND_DEVELOPMENT }, { WWT_DROPDOWN_BUTTON, 2, 156, 166, 60, 69, 876, STR_SELECT_LEVEL_OF_RESEARCH_AND_DEVELOPMENT }, @@ -108,87 +109,85 @@ static rct_widget *window_research_page_widgets[] = { #pragma region Events -static void window_research_emptysub() { } - -static void window_research_development_mouseup(); +static void window_research_development_mouseup(rct_window *w, int widgetIndex); static void window_research_development_update(rct_window *w); -static void window_research_development_invalidate(); -static void window_research_development_paint(); +static void window_research_development_invalidate(rct_window *w); +static void window_research_development_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_research_funding_mouseup(); +static void window_research_funding_mouseup(rct_window *w, int widgetIndex); static void window_research_funding_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_research_funding_dropdown(); +static void window_research_funding_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_research_funding_update(rct_window *w); -static void window_research_funding_invalidate(); -static void window_research_funding_paint(); +static void window_research_funding_invalidate(rct_window *w); +static void window_research_funding_paint(rct_window *w, rct_drawpixelinfo *dpi); -// -static void* window_research_development_events[] = { - window_research_emptysub, +// +static rct_window_event_list window_research_development_events = { + NULL, window_research_development_mouseup, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, + NULL, + NULL, + NULL, + NULL, window_research_development_update, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_research_development_invalidate, window_research_development_paint, - window_research_emptysub + NULL }; // 0x009890E8 -static void* window_research_funding_events[] = { - window_research_emptysub, +static rct_window_event_list window_research_funding_events = { + NULL, window_research_funding_mouseup, - window_research_emptysub, + NULL, window_research_funding_mousedown, window_research_funding_dropdown, - window_research_emptysub, + NULL, window_research_funding_update, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, - window_research_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_research_funding_invalidate, window_research_funding_paint, - window_research_emptysub + NULL }; -static void* window_research_page_events[] = { - window_research_development_events, - window_research_funding_events +static rct_window_event_list *window_research_page_events[] = { + &window_research_development_events, + &window_research_funding_events }; #pragma endregion @@ -260,13 +259,8 @@ void window_research_open() * * rct2: 0x006B6B38 */ -static void window_research_development_mouseup() +static void window_research_development_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -294,14 +288,11 @@ static void window_research_development_update(rct_window *w) } /** - * + * * rct2: 0x006B6819 */ -static void window_research_development_invalidate() +static void window_research_development_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); if (w->widgets != window_research_page_widgets[WINDOW_RESEARCH_PAGE_DEVELOPMENT]) { @@ -320,50 +311,50 @@ static void window_research_development_invalidate() } /** - * + * * rct2: 0x006B689B */ -static void window_research_development_paint() +static void window_research_development_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - int x, y; - rct_string_id stringId; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_research_draw_tab_images(dpi, w); - x = w->x + 10; - y = w->y + window_research_development_widgets[WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP].top + 12; + window_research_development_page_paint(w, dpi, WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP); +} - if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) == RESEARCH_STAGE_FINISHED_ALL){ +void window_research_development_page_paint(rct_window *w, rct_drawpixelinfo *dpi, int baseWidgetIndex) +{ + baseWidgetIndex = baseWidgetIndex - WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP; + + int x = w->x + 10; + int y = w->y + w->widgets[WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP + baseWidgetIndex].top + 12; + rct_string_id stringId; + + 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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = STR_UNKNOWN; gfx_draw_string_left(dpi, STR_RESEARCH_EXPECTED_LABEL, (void*)0x013CE952, 0, x, y); - } - else{ + } else { // Research type stringId = STR_RESEARCH_UNKNOWN; - if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != 0) { + if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != RESEARCH_STAGE_INITIAL_RESEARCH) { stringId = STR_TRANSPORT_RIDE + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_CATEGORY, uint8); - if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != 1) { + if (RCT2_GLOBAL(RCT2_ADDRESS_RESEARH_PROGRESS_STAGE, uint8) != RESEARCH_STAGE_DESIGNING) { 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 ? + stringId = (rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) ? rideEntry->name : ((typeId >> 8) & 0xFF) + 2; - } - else { + } else { stringId = g_scenerySetEntries[typeId]->name; } } @@ -377,27 +368,28 @@ static void window_research_development_paint() y += 15; // Expected - RCT2_GLOBAL(0x013CE952, uint16) = STR_UNKNOWN; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, 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(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = 2289; 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); } + // Last development x = w->x + 10; - y = w->y + window_research_development_widgets[WIDX_LAST_DEVELOPMENT_GROUP].top + 12; + y = w->y + w->widgets[WIDX_LAST_DEVELOPMENT_GROUP + baseWidgetIndex].top + 12; uint32 typeId = RCT2_GLOBAL(RCT2_ADDRESS_LAST_RESEARCHED_ITEM_SUBJECT, uint32); int lastDevelopmentFormat; if (typeId != 0xFFFFFFFF) { 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 ? + stringId = (rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) ? rideEntry->name : ((typeId >> 8) & 0xFF) + 2; @@ -415,17 +407,13 @@ static void window_research_development_paint() #pragma region Funding page /** - * + * * rct2: 0x0069DB3F */ -static void window_research_funding_mouseup() +static void window_research_funding_mouseup(rct_window *w, int widgetIndex) { - rct_window * w; - short widgetIndex; int activeResearchTypes; - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -449,14 +437,14 @@ static void window_research_funding_mouseup() } /** - * + * * rct2: 0x0069DB66 */ static void window_research_funding_mousedown(int widgetIndex, rct_window *w, rct_widget* widget) { rct_widget *dropdownWidget; int i; - + if (widgetIndex != WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON) return; @@ -477,21 +465,15 @@ static void window_research_funding_mousedown(int widgetIndex, rct_window *w, rc ); int currentResearchLevel = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8); - gDropdownItemsChecked = (1 << currentResearchLevel); + dropdown_set_checked(currentResearchLevel, true); } /** - * + * * rct2: 0x0069DB6D */ -static void window_research_funding_dropdown() +static void window_research_funding_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - rct_window *w; - short widgetIndex; - short dropdownIndex; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (widgetIndex != WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON || dropdownIndex == -1) return; @@ -500,7 +482,7 @@ static void window_research_funding_dropdown() } /** - * + * * rct2: 0x0069DC23 */ static void window_research_funding_update(rct_window *w) @@ -512,14 +494,11 @@ static void window_research_funding_update(rct_window *w) } /** - * + * * rct2: 0x0069DA64 */ -static void window_research_funding_invalidate() +static void window_research_funding_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); if (w->widgets != window_research_page_widgets[WINDOW_RESEARCH_PAGE_FUNDING]) { @@ -529,7 +508,7 @@ static void window_research_funding_invalidate() window_research_set_pressed_tab(w); - if ((RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) || + 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; @@ -543,7 +522,7 @@ static void window_research_funding_invalidate() int currentResearchLevel = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8); window_research_funding_widgets[WIDX_RESEARCH_FUNDING].image = STR_NO_FUNDING + currentResearchLevel; } - + // Checkboxes int activeResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES, uint16); int uncompletedResearchTypes = gResearchUncompletedCategories; @@ -568,24 +547,25 @@ static void window_research_funding_invalidate() } /** - * + * * rct2: 0x0069DAF0 */ -static void window_research_funding_paint() +static void window_research_funding_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_research_draw_tab_images(dpi, w); - if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) { - int currentResearchLevel = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8); - money32 currentResearchCostPerWeek = research_cost_table[currentResearchLevel]; - gfx_draw_string_left(dpi, STR_RESEARCH_COST_PER_MONTH, ¤tResearchCostPerWeek, 0, w->x + 10, w->y + 77); - } + window_research_funding_page_paint(w, dpi, WIDX_RESEARCH_FUNDING); +} + +void window_research_funding_page_paint(rct_window *w, rct_drawpixelinfo *dpi, int baseWidgetIndex) +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) + return; + + int currentResearchLevel = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8); + money32 currentResearchCostPerWeek = research_cost_table[currentResearchLevel]; + gfx_draw_string_left(dpi, STR_RESEARCH_COST_PER_MONTH, ¤tResearchCostPerWeek, 0, w->x + 10, w->y + 77); } #pragma endregion @@ -611,7 +591,7 @@ static void window_research_set_page(rct_window *w, int page) w->widgets = window_research_page_widgets[page]; w->disabled_widgets = 0; w->pressed_widgets = 0; - + window_invalidate(w); if (w->page == WINDOW_RESEARCH_PAGE_DEVELOPMENT) { w->width = 300; @@ -657,4 +637,4 @@ static void window_research_draw_tab_images(rct_drawpixelinfo *dpi, rct_window * window_research_draw_tab_image(dpi, w, WINDOW_RESEARCH_PAGE_FUNDING, SPR_TAB_FINANCES_SUMMARY_0); } -#pragma endregion \ No newline at end of file +#pragma endregion diff --git a/src/windows/ride.c b/src/windows/ride.c index c84958848f..b222be3b2a 100644 --- a/src/windows/ride.c +++ b/src/windows/ride.c @@ -8,18 +8,19 @@ * 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 "../cheats.h" #include "../config.h" #include "../game.h" #include "../input.h" @@ -37,6 +38,7 @@ #include "../world/map.h" #include "../world/sprite.h" #include "dropdown.h" +#include "../rct1.h" #define var_496(w) RCT2_GLOBAL((int)w + 0x496, uint16) @@ -471,9 +473,9 @@ static rct_widget window_ride_customer_widgets[] = { { WWT_TAB, 1, 251, 281, 17, 43, 0x2000144E, STR_INCOME_AND_COSTS_TIP }, { WWT_TAB, 1, 282, 312, 17, 43, 0x2000144E, STR_CUSTOMER_INFORMATION_TIP }, - { WWT_FLATBTN, 1, 289, 312, 54, 77, 5184, STR_SHOW_GUESTS_THOUGHTS_ABOUT_THIS_RIDE_ATTRACTION_TIP }, - { WWT_FLATBTN, 1, 289, 312, 78, 101, 5186, STR_SHOW_GUESTS_ON_THIS_RIDE_ATTRACTION_TIP }, - { WWT_FLATBTN, 1, 289, 312, 102, 125, 5185, STR_SHOW_GUESTS_QUEUING_FOR_THIS_RIDE_ATTRACTION_TIP }, + { WWT_FLATBTN, 1, 289, 312, 54, 77, SPR_SHOW_GUESTS_THOUGHTS_ABOUT_THIS_RIDE_ATTRACTION, STR_SHOW_GUESTS_THOUGHTS_ABOUT_THIS_RIDE_ATTRACTION_TIP }, + { WWT_FLATBTN, 1, 289, 312, 78, 101, SPR_SHOW_GUESTS_ON_THIS_RIDE_ATTRACTION, STR_SHOW_GUESTS_ON_THIS_RIDE_ATTRACTION_TIP }, + { WWT_FLATBTN, 1, 289, 312, 102, 125, SPR_SHOW_GUESTS_QUEUING_FOR_THIS_RIDE_ATTRACTION, STR_SHOW_GUESTS_QUEUING_FOR_THIS_RIDE_ATTRACTION_TIP }, { WIDGETS_END }, }; @@ -520,432 +522,431 @@ const uint64 window_ride_page_hold_down_widgets[] = { #pragma region Events -static void window_ride_emptysub() { } static void window_ride_init_viewport(rct_window *w); -static void window_ride_main_mouseup(); -static void window_ride_main_resize(); +static void window_ride_main_mouseup(rct_window *w, int widgetIndex); +static void window_ride_main_resize(rct_window *w); static void window_ride_main_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); -static void window_ride_main_dropdown(); +static void window_ride_main_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_ride_main_update(rct_window *w); -static void window_ride_main_textinput(); -static void window_ride_main_unknown_14(); -static void window_ride_main_invalidate(); -static void window_ride_main_paint(); +static void window_ride_main_textinput(rct_window *w, int widgetIndex, char *text); +static void window_ride_main_unknown_14(rct_window *w); +static void window_ride_main_invalidate(rct_window *w); +static void window_ride_main_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_ride_vehicle_mouseup(); -static void window_ride_vehicle_resize(); +static void window_ride_vehicle_mouseup(rct_window *w, int widgetIndex); +static void window_ride_vehicle_resize(rct_window *w); static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); -static void window_ride_vehicle_dropdown(); +static void window_ride_vehicle_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_ride_vehicle_update(rct_window *w); -static void window_ride_vehicle_invalidate(); -static void window_ride_vehicle_paint(); -static void window_ride_vehicle_scrollpaint(); +static void window_ride_vehicle_invalidate(rct_window *w); +static void window_ride_vehicle_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_ride_vehicle_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void window_ride_operating_mouseup(); -static void window_ride_operating_resize(); +static void window_ride_operating_mouseup(rct_window *w, int widgetIndex); +static void window_ride_operating_resize(rct_window *w); static void window_ride_operating_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); -static void window_ride_operating_dropdown(); +static void window_ride_operating_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_ride_operating_update(rct_window *w); -static void window_ride_operating_invalidate(); -static void window_ride_operating_paint(); +static void window_ride_operating_invalidate(rct_window *w); +static void window_ride_operating_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_ride_maintenance_mouseup(); -static void window_ride_maintenance_resize(); +static void window_ride_maintenance_mouseup(rct_window *w, int widgetIndex); +static void window_ride_maintenance_resize(rct_window *w); static void window_ride_maintenance_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); -static void window_ride_maintenance_dropdown(); +static void window_ride_maintenance_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_ride_maintenance_update(rct_window *w); -static void window_ride_maintenance_invalidate(); -static void window_ride_maintenance_paint(); +static void window_ride_maintenance_invalidate(rct_window *w); +static void window_ride_maintenance_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_ride_colour_close(); -static void window_ride_colour_mouseup(); -static void window_ride_colour_resize(); +static void window_ride_colour_close(rct_window *w); +static void window_ride_colour_mouseup(rct_window *w, int widgetIndex); +static void window_ride_colour_resize(rct_window *w); static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); -static void window_ride_colour_dropdown(); +static void window_ride_colour_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_ride_colour_update(rct_window *w); -static void window_ride_colour_tooldown(); -static void window_ride_colour_tooldrag(); -static void window_ride_colour_invalidate(); -static void window_ride_colour_paint(); -static void window_ride_colour_scrollpaint(); +static void window_ride_colour_tooldown(rct_window *w, int widgetIndex, int x, int y); +static void window_ride_colour_tooldrag(rct_window *w, int widgetIndex, int x, int y); +static void window_ride_colour_invalidate(rct_window *w); +static void window_ride_colour_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_ride_colour_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void window_ride_music_mouseup(); -static void window_ride_music_resize(); +static void window_ride_music_mouseup(rct_window *w, int widgetIndex); +static void window_ride_music_resize(rct_window *w); static void window_ride_music_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); -static void window_ride_music_dropdown(); +static void window_ride_music_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_ride_music_update(rct_window *w); -static void window_ride_music_invalidate(); -static void window_ride_music_paint(); +static void window_ride_music_invalidate(rct_window *w); +static void window_ride_music_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_ride_measurements_close(); -static void window_ride_measurements_mouseup(); -static void window_ride_measurements_resize(); +static void window_ride_measurements_close(rct_window *w); +static void window_ride_measurements_mouseup(rct_window *w, int widgetIndex); +static void window_ride_measurements_resize(rct_window *w); static void window_ride_measurements_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); -static void window_ride_measurements_dropdown(); +static void window_ride_measurements_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_ride_measurements_update(rct_window *w); -static void window_ride_measurements_tooldown(); -static void window_ride_measurements_toolabort(); -static void window_ride_measurements_invalidate(); -static void window_ride_measurements_paint(); +static void window_ride_measurements_tooldown(rct_window *w, int widgetIndex, int x, int y); +static void window_ride_measurements_toolabort(rct_window *w, int widgetIndex); +static void window_ride_measurements_invalidate(rct_window *w); +static void window_ride_measurements_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_ride_graphs_mouseup(); -static void window_ride_graphs_resize(); +static void window_ride_graphs_mouseup(rct_window *w, int widgetIndex); +static void window_ride_graphs_resize(rct_window *w); static void window_ride_graphs_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); static void window_ride_graphs_update(rct_window *w); -static void window_ride_graphs_scrollgetheight(); -static void window_ride_graphs_15(); -static void window_ride_graphs_tooltip(); -static void window_ride_graphs_invalidate(); -static void window_ride_graphs_paint(); -static void window_ride_graphs_scrollpaint(); +static void window_ride_graphs_scrollgetheight(rct_window *w, int scrollIndex, int *width, int *height); +static void window_ride_graphs_15(rct_window *w, int scrollIndex, int scrollAreaType); +static void window_ride_graphs_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_ride_graphs_invalidate(rct_window *w); +static void window_ride_graphs_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_ride_graphs_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void window_ride_income_mouseup(); -static void window_ride_income_resize(); +static void window_ride_income_mouseup(rct_window *w, int widgetIndex); +static void window_ride_income_resize(rct_window *w); static void window_ride_income_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); static void window_ride_income_update(rct_window *w); -static void window_ride_income_invalidate(); -static void window_ride_income_paint(); +static void window_ride_income_invalidate(rct_window *w); +static void window_ride_income_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_ride_customer_mouseup(); -static void window_ride_customer_resize(); +static void window_ride_customer_mouseup(rct_window *w, int widgetIndex); +static void window_ride_customer_resize(rct_window *w); 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_customer_invalidate(rct_window *w); +static void window_ride_customer_paint(rct_window *w, rct_drawpixelinfo *dpi); static void window_ride_set_colours(); // 0x0098DFD4 -static void* window_ride_main_events[] = { - window_ride_emptysub, +static rct_window_event_list window_ride_main_events = { + NULL, window_ride_main_mouseup, window_ride_main_resize, window_ride_main_mousedown, window_ride_main_dropdown, - window_ride_emptysub, + NULL, window_ride_main_update, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_ride_main_textinput, window_ride_main_unknown_14, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, + NULL, + NULL, window_ride_main_invalidate, window_ride_main_paint, - window_ride_emptysub + NULL }; // 0x0098E204 -static void* window_ride_vehicle_events[] = { - window_ride_emptysub, +static rct_window_event_list window_ride_vehicle_events = { + NULL, window_ride_vehicle_mouseup, window_ride_vehicle_resize, window_ride_vehicle_mousedown, window_ride_vehicle_dropdown, - window_ride_emptysub, + NULL, window_ride_vehicle_update, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_ride_vehicle_invalidate, window_ride_vehicle_paint, window_ride_vehicle_scrollpaint }; // 0x0098E0B4 -static void* window_ride_operating_events[] = { - window_ride_emptysub, +static rct_window_event_list window_ride_operating_events = { + NULL, window_ride_operating_mouseup, window_ride_operating_resize, window_ride_operating_mousedown, window_ride_operating_dropdown, - window_ride_emptysub, + NULL, window_ride_operating_update, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_ride_operating_invalidate, window_ride_operating_paint, - window_ride_emptysub + NULL }; // 0x0098E124 -static void* window_ride_maintenance_events[] = { - window_ride_emptysub, +static rct_window_event_list window_ride_maintenance_events = { + NULL, window_ride_maintenance_mouseup, window_ride_maintenance_resize, window_ride_maintenance_mousedown, window_ride_maintenance_dropdown, - window_ride_emptysub, + NULL, window_ride_maintenance_update, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_ride_maintenance_invalidate, window_ride_maintenance_paint, - window_ride_emptysub + NULL }; // 0x0098E044 -static void* window_ride_colour_events[] = { +static rct_window_event_list window_ride_colour_events = { window_ride_colour_close, window_ride_colour_mouseup, window_ride_colour_resize, window_ride_colour_mousedown, window_ride_colour_dropdown, - window_ride_emptysub, + NULL, window_ride_colour_update, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, + NULL, window_ride_colour_tooldown, window_ride_colour_tooldrag, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_ride_colour_invalidate, window_ride_colour_paint, window_ride_colour_scrollpaint }; // 0x0098E194 -static void* window_ride_music_events[] = { - window_ride_emptysub, +static rct_window_event_list window_ride_music_events = { + NULL, window_ride_music_mouseup, window_ride_music_resize, window_ride_music_mousedown, window_ride_music_dropdown, - window_ride_emptysub, + NULL, window_ride_music_update, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_ride_music_invalidate, window_ride_music_paint, - window_ride_emptysub + NULL }; // 0x0098DE14 -static void* window_ride_measurements_events[] = { +static rct_window_event_list window_ride_measurements_events = { window_ride_measurements_close, window_ride_measurements_mouseup, window_ride_measurements_resize, window_ride_measurements_mousedown, window_ride_measurements_dropdown, - window_ride_emptysub, + NULL, window_ride_measurements_update, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, + NULL, window_ride_measurements_tooldown, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, window_ride_measurements_toolabort, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_ride_measurements_invalidate, window_ride_measurements_paint, - window_ride_emptysub + NULL }; // 0x0098DF64 -static void* window_ride_graphs_events[] = { - window_ride_emptysub, +static rct_window_event_list window_ride_graphs_events = { + NULL, window_ride_graphs_mouseup, window_ride_graphs_resize, window_ride_graphs_mousedown, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, window_ride_graphs_update, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_ride_graphs_scrollgetheight, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, window_ride_graphs_15, window_ride_graphs_tooltip, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, window_ride_graphs_invalidate, window_ride_graphs_paint, window_ride_graphs_scrollpaint }; // 0x0098DEF4 -static void* window_ride_income_events[] = { - window_ride_emptysub, +static rct_window_event_list window_ride_income_events = { + NULL, window_ride_income_mouseup, window_ride_income_resize, window_ride_income_mousedown, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, window_ride_income_update, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_ride_income_invalidate, window_ride_income_paint, - window_ride_emptysub + NULL }; // 0x0098DE84 -static void* window_ride_customer_events[] = { - window_ride_emptysub, +static rct_window_event_list window_ride_customer_events = { + NULL, window_ride_customer_mouseup, window_ride_customer_resize, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, + NULL, window_ride_customer_update, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, - window_ride_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_ride_customer_invalidate, window_ride_customer_paint, - window_ride_emptysub + NULL }; -static uint32* window_ride_page_events[] = { - (uint32*)window_ride_main_events, - (uint32*)window_ride_vehicle_events, - (uint32*)window_ride_operating_events, - (uint32*)window_ride_maintenance_events, - (uint32*)window_ride_colour_events, - (uint32*)window_ride_music_events, - (uint32*)window_ride_measurements_events, - (uint32*)window_ride_graphs_events, - (uint32*)window_ride_income_events, - (uint32*)window_ride_customer_events +static rct_window_event_list *window_ride_page_events[] = { + &window_ride_main_events, + &window_ride_vehicle_events, + &window_ride_operating_events, + &window_ride_maintenance_events, + &window_ride_colour_events, + &window_ride_music_events, + &window_ride_measurements_events, + &window_ride_graphs_events, + &window_ride_income_events, + &window_ride_customer_events }; #pragma endregion @@ -968,7 +969,7 @@ static void window_ride_draw_tab_image(rct_drawpixelinfo *dpi, rct_window *w, in } /** - * + * * rct2: 0x006B2E88 */ static void window_ride_draw_tab_main(rct_drawpixelinfo *dpi, rct_window *w) @@ -1002,7 +1003,7 @@ static void window_ride_draw_tab_main(rct_drawpixelinfo *dpi, rct_window *w) } /** - * + * * rct2: 0x006B2B68 */ static void window_ride_draw_tab_vehicle(rct_drawpixelinfo *dpi, rct_window *w) @@ -1035,7 +1036,9 @@ static void window_ride_draw_tab_vehicle(rct_drawpixelinfo *dpi, rct_window *w) y = (widget->bottom - widget->top) - 12; ride = GET_RIDE(w->number); - RCT2_CALLPROC_X(0x006DE4CD, (ride->num_cars_per_train << 8) | ride->subtype, 0, 0, 0, 0, 0, 0); + + uint8 trainLayout[16]; + ride_entry_get_train_layout(ride->subtype, ride->num_cars_per_train, trainLayout); rideEntry = ride_get_entry(ride); if (rideEntry->flags & RIDE_ENTRY_FLAG_0) { @@ -1048,8 +1051,8 @@ static void window_ride_draw_tab_vehicle(rct_drawpixelinfo *dpi, rct_window *w) dpi->y *= 2; } - rct_ride_type_vehicle* rideVehicleEntry = &rideEntry->vehicles[RCT2_ADDRESS(0x00F64E38, uint8)[rideEntry->tab_vehicle]]; - height += rideVehicleEntry->var_0A; + rct_ride_type_vehicle* rideVehicleEntry = &rideEntry->vehicles[trainLayout[rideEntry->tab_vehicle]]; + height += rideVehicleEntry->tab_height; vehicleColour = ride_get_vehicle_colour(ride, 0); @@ -1057,7 +1060,7 @@ static void window_ride_draw_tab_vehicle(rct_drawpixelinfo *dpi, rct_window *w) if (w->page == WINDOW_RIDE_PAGE_VEHICLE) spriteIndex += w->frame_no; spriteIndex /= (rideVehicleEntry->var_12 & 0x800) ? 4 : 2; - spriteIndex &= rideVehicleEntry->var_00; + spriteIndex &= rideVehicleEntry->rotation_frame_mask; spriteIndex *= rideVehicleEntry->var_16; spriteIndex += rideVehicleEntry->base_image_id; spriteIndex |= (vehicleColour.additional_1 << 24) | (vehicleColour.main << 19); @@ -1069,7 +1072,7 @@ static void window_ride_draw_tab_vehicle(rct_drawpixelinfo *dpi, rct_window *w) } /** - * + * * rct2: 0x006B2F42 */ static void window_ride_draw_tab_customer(rct_drawpixelinfo *dpi, rct_window *w) @@ -1086,13 +1089,13 @@ static void window_ride_draw_tab_customer(rct_drawpixelinfo *dpi, rct_window *w) spriteIndex += RCT2_GLOBAL(RCT2_GLOBAL(0x00982708, uint32), uint32); spriteIndex += 1; spriteIndex |= 0xA9E00000; - + gfx_draw_sprite(dpi, spriteIndex, w->x + (widget->left + widget->right) / 2, w->y + widget->bottom - 6, 0); } } /** - * + * * rct2: 0x006B2B35 */ static void window_ride_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w) @@ -1129,15 +1132,19 @@ void window_ride_disable_tabs(rct_window *w) 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) + if ( + !(RCT2_GLOBAL(0x97CF40 + ride_type * 8, uint32) & 0x4000007) && + !(RideData4[ride->type].flags & RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT) + ) { 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) + if (!(RideData4[ride->type].flags & RIDE_TYPE_FLAG4_ALLOW_MUSIC)) { disabled_tabs |= (1 << WIDX_TAB_6); // 0x200 + } if (ride_type == RIDE_TYPE_CASH_MACHINE || ride_type == RIDE_TYPE_FIRST_AID || @@ -1156,7 +1163,7 @@ void window_ride_disable_tabs(rct_window *w) } /** - * + * * rct2: 0x006AEAB4 */ rct_window *window_ride_open(int rideIndex) @@ -1199,7 +1206,7 @@ rct_window *window_ride_open(int rideIndex) } /** - * + * * rct2: 0x006ACC28 */ rct_window *window_ride_main_open(int rideIndex) @@ -1238,7 +1245,7 @@ rct_window *window_ride_main_open(int rideIndex) } /** - * + * * rct2: 0x006ACCCE */ rct_window *window_ride_open_station(int rideIndex, int stationIndex) @@ -1307,7 +1314,7 @@ rct_window *window_ride_open_track(rct_map_element *mapElement) } /** - * + * * rct2: 0x006ACAC2 */ rct_window *window_ride_open_vehicle(rct_vehicle *vehicle) @@ -1328,7 +1335,7 @@ rct_window *window_ride_open_vehicle(rct_vehicle *vehicle) for (i = 0; i < 32; i++) { if (ride->vehicles[i] == headVehicleSpriteIndex) break; - + view++; } @@ -1416,9 +1423,8 @@ static void window_ride_set_page(rct_window *w, int 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 (page == WINDOW_RIDE_PAGE_VEHICLE) { + ride_update_max_vehicles(w->number); } if (w->viewport != NULL) { @@ -1465,7 +1471,7 @@ static void window_ride_anchor_border_widgets(rct_window *w) #pragma region Main /** - * + * * rct2: 0x006AF994 */ static void window_ride_init_viewport(rct_window *w) @@ -1482,8 +1488,8 @@ static void window_ride_init_viewport(rct_window *w) focus.sprite.sprite_id = -1; focus.coordinate.zoom = 0; - focus.coordinate.rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); - + focus.coordinate.rotation = get_current_rotation(); + if (eax >= 0 && eax < ride->num_vehicles && ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK){ focus.sprite.sprite_id = ride->vehicles[eax]; @@ -1505,7 +1511,7 @@ static void window_ride_init_viewport(rct_window *w) } while (count >= 0); eax = ride->station_starts[stationIndex]; - + focus.coordinate.x = (eax & 0xFF) << 5; focus.coordinate.y = (eax & 0xFF00) >> 3; focus.coordinate.z = ride->station_heights[stationIndex] << 3; @@ -1564,19 +1570,19 @@ static void window_ride_init_viewport(rct_window *w) int width = view_widget->right - view_widget->left - 1; int height = view_widget->bottom - view_widget->top - 1; viewport_create( - w, - x, - y, - width, - height, + w, + x, + y, + width, + height, focus.coordinate.zoom, - focus.coordinate.x, - focus.coordinate.y & VIEWPORT_FOCUS_Y_MASK, - focus.coordinate.z, - focus.sprite.type & VIEWPORT_FOCUS_TYPE_MASK, + focus.coordinate.x, + focus.coordinate.y & VIEWPORT_FOCUS_Y_MASK, + focus.coordinate.z, + focus.sprite.type & VIEWPORT_FOCUS_TYPE_MASK, focus.sprite.sprite_id); - w->flags |= WF_2; + w->flags |= WF_NO_SCROLLING; window_invalidate(w); } if (w->viewport){ @@ -1586,17 +1592,20 @@ static void window_ride_init_viewport(rct_window *w) } /** - * + * * rct2: 0x006B4971 */ void window_ride_construct(rct_window *w) { + // Window may be closed by close by class so + // make backup before calling. + uint8 rideIndex = w->number; window_close_by_class(WC_RIDE_CONSTRUCTION); - ride_construct(w->number); + ride_construct(rideIndex); } /** - * + * * rct2: 0x006AF315 */ static void window_ride_rename(rct_window *w) @@ -1609,18 +1618,14 @@ static void window_ride_rename(rct_window *w) } /** - * + * * rct2: 0x006AF17E */ -static void window_ride_main_mouseup() +static void window_ride_main_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; rct_ride *ride; int status; - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -1658,15 +1663,15 @@ static void window_ride_main_mouseup() switch (widgetIndex - WIDX_CLOSE_LIGHT) { case 0: status = RIDE_STATUS_CLOSED; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1004; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_CLOSE; break; case 1: status = RIDE_STATUS_TESTING; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1003; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_TEST; break; case 2: status = RIDE_STATUS_OPEN; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1002; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_OPEN; break; } @@ -1678,17 +1683,14 @@ static void window_ride_main_mouseup() } /** - * + * * rct2: 0x006AF4A2 */ -static void window_ride_main_resize() +static void window_ride_main_resize(rct_window *w) { - rct_window *w; rct_viewport *viewport; int width, height; - window_get_register(w); - w->flags |= WF_RESIZABLE; int minHeight = 180; if (theme_get_preset()->features.rct1_ride_lights) @@ -1711,7 +1713,7 @@ static void window_ride_main_resize() } /** - * + * * rct2: 0x006AF825 */ static void window_ride_show_view_dropdown(rct_window *w, rct_widget *widget) @@ -1764,17 +1766,17 @@ static void window_ride_show_view_dropdown(rct_window *w, rct_widget *widget) if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)) { j = 2; for (i = 0; i < ride->num_vehicles; i++) { - RCT2_GLOBAL(0x009DED34, uint32) |= j; + gDropdownItemsDisabled |= j; j <<= 1; } } // Set checked item - gDropdownItemsChecked |= (1 << w->ride.view); + dropdown_set_checked(w->ride.view, true); } /** - * + * * rct2: 0x006AF64C */ static void window_ride_show_open_dropdown(rct_window *w, rct_widget *widget) @@ -1798,7 +1800,7 @@ static void window_ride_show_open_dropdown(rct_window *w, rct_widget *widget) gDropdownItemsFormat[numItems] = 1142; gDropdownItemsArgs[numItems] = STR_OPEN_RIDE; numItems++; - + window_dropdown_show_text( w->x + widget->left, w->y + widget->top, @@ -1845,12 +1847,12 @@ static void window_ride_show_open_dropdown(rct_window *w, rct_widget *widget) highlightedIndex--; } - gDropdownItemsChecked |= (1 << checkedIndex); - RCT2_GLOBAL(0x009DEBA2, sint16) = highlightedIndex; + dropdown_set_checked(checkedIndex, true); + gDropdownHighlightedIndex = highlightedIndex; } /** - * + * * rct2: 0x006AF1BD */ static void window_ride_main_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) @@ -1866,17 +1868,13 @@ static void window_ride_main_mousedown(int widgetIndex, rct_window *w, rct_widge } /** - * + * * rct2: 0x006AF300 */ -static void window_ride_main_dropdown() +static void window_ride_main_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { rct_ride *ride; - rct_window *w; int status; - short widgetIndex, dropdownIndex; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); switch (widgetIndex) { case WIDX_VIEW_DROPDOWN: @@ -1897,7 +1895,7 @@ static void window_ride_main_dropdown() break; case WIDX_OPEN: if (dropdownIndex == -1) - dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); + dropdownIndex = gDropdownHighlightedIndex; ride = GET_RIDE(w->number); if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_NO_TEST_MODE) && dropdownIndex != 0) @@ -1906,15 +1904,15 @@ static void window_ride_main_dropdown() switch (dropdownIndex) { case 0: status = RIDE_STATUS_CLOSED; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1004; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_CLOSE; break; case 1: status = RIDE_STATUS_TESTING; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1003; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_TEST; break; case 2: status = RIDE_STATUS_OPEN; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1002; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_OPEN; break; } @@ -1926,7 +1924,7 @@ static void window_ride_main_dropdown() } /** - * + * * rct2: 0x006AF40F */ static void window_ride_main_update(rct_window *w) @@ -1970,48 +1968,35 @@ static void window_ride_main_update(rct_window *w) } /** - * + * * rct2: 0x006AF2F9 */ -static void window_ride_main_textinput() +static void window_ride_main_textinput(rct_window *w, int widgetIndex, char *text) { - uint8 result; - short widgetIndex; - rct_window *w; - char *text; - - window_textinput_get_registers(w, widgetIndex, result, text); - - if (widgetIndex != WIDX_RENAME || !result) + if (widgetIndex != WIDX_RENAME || text == NULL) return; ride_set_name(w->number, text); } /** - * + * * rct2: 0x006AF55A */ -static void window_ride_main_unknown_14() +static void window_ride_main_unknown_14(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_ride_init_viewport(w); } /** - * + * * rct2: 0x006AECF6 */ -static void window_ride_main_invalidate() +static void window_ride_main_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; int i, height; - window_get_register(w); colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; @@ -2026,8 +2011,6 @@ 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_SIX_FLAGS) - w->disabled_widgets |= (1 << 19); RCT2_GLOBAL(0x013CE952 + 0, uint16) = ride->name; RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; @@ -2056,7 +2039,7 @@ static void window_ride_main_invalidate() 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; @@ -2091,7 +2074,7 @@ static void window_ride_main_invalidate() } /** - * + * * rct2: 0x006AF10A */ static rct_string_id window_ride_get_status_overall_view(rct_window *w, void *arguments) @@ -2110,7 +2093,7 @@ static rct_string_id window_ride_get_status_overall_view(rct_window *w, void *ar } /** - * + * * rct2: 0x006AEFEF */ static rct_string_id window_ride_get_status_vehicle(rct_window *w, void *arguments) @@ -2130,8 +2113,8 @@ static rct_string_id window_ride_get_status_vehicle(rct_window *w, void *argumen vehicle = &(g_sprite_list[vehicleSpriteIndex].vehicle); if (vehicle->status != VEHICLE_STATUS_CRASHING && vehicle->status != VEHICLE_STATUS_CRASHED) { - int ax = vehicle->var_36 / 4; - if (ax == 216 || ax == 123 || ax == 9 || ax == 63 || ax == 147 || ax == 155) { + int trackType = vehicle->track_type >> 2; + if (trackType == 216 || trackType == 123 || trackType == 9 || trackType == 63 || trackType == 147 || trackType == 155) { if ((RCT2_ADDRESS(0x01357644, uint32)[ride->type] & 0x40) && vehicle->velocity == 0) { RCT2_GLOBAL((int)arguments + 0, uint16) = STR_STOPPED_BY_BLOCK_BRAKES; return 1191; @@ -2147,7 +2130,7 @@ static rct_string_id window_ride_get_status_vehicle(rct_window *w, void *argumen if (ride->type == RIDE_TYPE_MINI_GOLF) return 0; - if ((RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint16) & 0x100) && stringId <= 1104) + if ((RideData4[ride->type].flags & RIDE_TYPE_FLAG4_SINGLE_SESSION) && stringId <= 1104) stringId += 23; RCT2_GLOBAL((int)arguments + 4, uint16) = RideNameConvention[ride->type].station_name; @@ -2160,7 +2143,7 @@ static rct_string_id window_ride_get_status_vehicle(rct_window *w, void *argumen } /** - * + * * rct2: 0x006AEF65 */ static rct_string_id window_ride_get_status_station(rct_window *w, void *arguments) @@ -2208,7 +2191,7 @@ static rct_string_id window_ride_get_status_station(rct_window *w, void *argumen } /** - * + * * rct2: 0x006AEE73 */ static rct_string_id window_ride_get_status(rct_window *w, void *arguments) @@ -2225,19 +2208,15 @@ static rct_string_id window_ride_get_status(rct_window *w, void *arguments) } /** - * + * * rct2: 0x006AEE73 */ -static void window_ride_main_paint() +static void window_ride_main_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_ride *ride; rct_widget *widget; rct_string_id stringId; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_ride_draw_tab_images(dpi, w); @@ -2260,7 +2239,7 @@ static void window_ride_main_paint() RCT2_GLOBAL(0x013CE952 + 2, uint16) = w->ride.view; } } - RCT2_GLOBAL(0x013CE952, uint16) = stringId; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = stringId; widget = &window_ride_main_widgets[WIDX_VIEW]; gfx_draw_string_centred( @@ -2290,17 +2269,13 @@ static void window_ride_main_paint() #pragma region Vehicle /** - * + * * rct2: 0x006B272D */ -static void window_ride_vehicle_mouseup() +static void window_ride_vehicle_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; rct_ride *ride; - window_widget_get_registers(w, widgetIndex); - ride = GET_RIDE(w->number); switch (widgetIndex) { @@ -2323,20 +2298,16 @@ static void window_ride_vehicle_mouseup() } /** - * + * * rct2: 0x006B2ABB */ -static void window_ride_vehicle_resize() +static void window_ride_vehicle_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 316, 208, 316, 208); } /** - * + * * rct2: 0x006B2748 */ static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) @@ -2345,38 +2316,60 @@ static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_wi rct_ride *ride; rct_ride_type *rideEntry, *currentRideEntry; rct_string_id stringId; - int i, minCars, maxCars, cars, numItems, quadIndex, bitIndex, rideEntryIndex, selectedIndex; - uint8 *rideEntryIndexPtr, *currentRideEntryIndex; + int i, minCars, maxCars, cars, numItems, quadIndex, bitIndex, rideEntryIndex, selectedIndex, rideTypeIterator, rideTypeIteratorMax; + uint8 *rideEntryIndexPtr; + bool selectionShouldBeExpanded; ride = GET_RIDE(w->number); rideEntry = ride_get_entry(ride); + if(gCheatsShowVehiclesFromOtherTrackTypes && !(ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE) || ride->type==RIDE_TYPE_MAZE || ride->type==RIDE_TYPE_MINI_GOLF)) { + selectionShouldBeExpanded=true; + rideTypeIterator=0; + rideTypeIteratorMax=90; + } + else { + selectionShouldBeExpanded=false; + rideTypeIterator=ride->type; + rideTypeIteratorMax=ride->type; + } + switch (widgetIndex) { case WIDX_VEHICLE_TYPE_DROPDOWN: - rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(ride->type); - currentRideEntryIndex; - selectedIndex = -1; numItems = 0; - for (currentRideEntryIndex = rideEntryIndexPtr; *currentRideEntryIndex != 0xFF; currentRideEntryIndex++) { - rideEntryIndex = *currentRideEntryIndex; - currentRideEntry = GET_RIDE_ENTRY(rideEntryIndex); - // 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) + + // Dropdowns with more items start acting weird, so cap it to 63. + for (; rideTypeIterator<=rideTypeIteratorMax && numItems<=63; rideTypeIterator++) { + + if(selectionShouldBeExpanded && ride_type_has_flag(rideTypeIterator, RIDE_TYPE_FLAG_FLAT_RIDE)) + continue; + if(selectionShouldBeExpanded && (rideTypeIterator==RIDE_TYPE_MAZE || rideTypeIterator==RIDE_TYPE_MINI_GOLF)) continue; - quadIndex = rideEntryIndex >> 5; - bitIndex = rideEntryIndex & 0x1F; - if (!(RCT2_ADDRESS(0x01357424, uint32)[quadIndex] & (1 << bitIndex))) - continue; + rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(rideTypeIterator); - if (ride->subtype == rideEntryIndex) - selectedIndex = numItems; + for (uint8 *currentRideEntryIndex = rideEntryIndexPtr; *currentRideEntryIndex != 0xFF; currentRideEntryIndex++) { + rideEntryIndex = *currentRideEntryIndex; + currentRideEntry = GET_RIDE_ENTRY(rideEntryIndex); + // Skip if vehicle has the same track type, but not same subtype, unless subtype switching is enabled + if ((currentRideEntry->flags & (RIDE_ENTRY_FLAG_SEPARATE_RIDE | RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME)) && !(gConfigInterface.select_by_track_type || selectionShouldBeExpanded)) + continue; - gDropdownItemsFormat[numItems] = 1142; - gDropdownItemsArgs[numItems] = (rideEntryIndex << 16) | currentRideEntry->name; + quadIndex = rideEntryIndex >> 5; + bitIndex = rideEntryIndex & 0x1F; + // Skip if vehicle type is not invented yet + if (!(RCT2_ADDRESS(0x01357424, uint32)[quadIndex] & (1 << bitIndex))) + continue; - numItems++; + if (ride->subtype == rideEntryIndex) + selectedIndex = numItems; + + gDropdownItemsFormat[numItems] = 1142; + gDropdownItemsArgs[numItems] = (rideEntryIndex << 16) | currentRideEntry->name; + + numItems++; + } } window_dropdown_show_text_custom_width( @@ -2389,7 +2382,7 @@ static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_wi widget->right - dropdownWidget->left ); - gDropdownItemsChecked = (1 << selectedIndex); + dropdown_set_checked(selectedIndex, true); break; case WIDX_VEHICLE_TRAINS_DROPDOWN: window_dropdown_show_text_custom_width( @@ -2398,7 +2391,7 @@ static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_wi dropdownWidget->bottom - dropdownWidget->top + 1, w->colours[1], DROPDOWN_FLAG_STAY_OPEN, - ride->var_0CC, + ride->max_trains, widget->right - dropdownWidget->left ); @@ -2408,11 +2401,11 @@ static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_wi gDropdownItemsArgs[i] = ((i + 1) << 16) | (i == 0 ? stringId : stringId + 1); } - gDropdownItemsChecked = (1 << (ride->num_vehicles - 1)); + dropdown_set_checked(ride->num_vehicles - 1, true); break; case WIDX_VEHICLE_CARS_PER_TRAIN_DROPDOWN: - minCars = (ride->var_0CD >> 4); - maxCars = (ride->var_0CD & 0x0F); + minCars = (ride->min_max_cars_per_train >> 4); + maxCars = (ride->min_max_cars_per_train & 0x0F); window_dropdown_show_text_custom_width( w->x + dropdownWidget->left, @@ -2434,24 +2427,20 @@ static void window_ride_vehicle_mousedown(int widgetIndex, rct_window *w, rct_wi gDropdownItemsArgs[i] |= (cars - rideEntry->zero_cars) << 16; } - gDropdownItemsChecked = (1 << (ride->num_cars_per_train - minCars)); + dropdown_set_checked(ride->num_cars_per_train - minCars, true); break; } } /** - * + * * rct2: 0x006B2767 */ -static void window_ride_vehicle_dropdown() +static void window_ride_vehicle_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - rct_window *w; - short widgetIndex, dropdownIndex; rct_ride *ride; rct_ride_type *rideEntry; - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (dropdownIndex == -1) return; @@ -2461,23 +2450,19 @@ static void window_ride_vehicle_dropdown() switch (widgetIndex) { case WIDX_VEHICLE_TYPE_DROPDOWN: dropdownIndex = (gDropdownItemsArgs[dropdownIndex] >> 16) & 0xFFFF; - - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1018; - game_do_command(0, (2 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_9, 0, 0); + ride_set_ride_entry(w->number, dropdownIndex); break; case WIDX_VEHICLE_TRAINS_DROPDOWN: - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1020; - game_do_command(0, (0 << 8) | 1, 0, ((dropdownIndex + 1) << 8) | w->number, GAME_COMMAND_9, 0, 0); + ride_set_num_vehicles(w->number, dropdownIndex + 1); 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->min_cars_in_train + dropdownIndex) << 8) | w->number, GAME_COMMAND_9, 0, 0); + ride_set_num_cars_per_vehicle(w->number, rideEntry->min_cars_in_train + dropdownIndex); break; } } /** - * + * * rct2: 0x006B2AA1 */ static void window_ride_vehicle_update(rct_window *w) @@ -2488,19 +2473,17 @@ static void window_ride_vehicle_update(rct_window *w) } /** - * + * * rct2: 0x006B222C */ -static void window_ride_vehicle_invalidate() +static void window_ride_vehicle_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; rct_ride *ride; rct_ride_type *rideEntry; rct_string_id stringId; int carsPerTrain; - - window_get_register(w); + colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; @@ -2523,7 +2506,7 @@ static void window_ride_vehicle_invalidate() // Vehicle type window_ride_vehicle_widgets[WIDX_VEHICLE_TYPE].image = rideEntry->name; // 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) { + if ((var_496(w) <= 1 || (rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE)) && !(gConfigInterface.select_by_track_type || gCheatsShowVehiclesFromOtherTrackTypes)) { 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); @@ -2564,21 +2547,17 @@ static void window_ride_vehicle_invalidate() } /** - * + * * rct2: 0x006B23DC */ -static void window_ride_vehicle_paint() +static void window_ride_vehicle_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_ride *ride; rct_ride_type *rideEntry; rct_string_id stringId; int x, y; sint16 factor; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_ride_draw_tab_images(dpi, w); @@ -2597,7 +2576,7 @@ static void window_ride_vehicle_paint() gfx_draw_string_left(dpi, 3142, &stringId, 0, x, y); y += 15; - if (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE) && var_496(w) > 1) { + if ((!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) || rideTypeShouldLoseSeparateFlag(rideEntry)) && var_496(w) > 1) { // Excitement Factor factor = rideEntry->excitement_multipler; if (factor > 0) { @@ -2631,13 +2610,11 @@ typedef struct { rct_vehichle_paintinfo _sprites_to_draw[144]; /** - * + * * rct2: 0x006B2502 */ -static void window_ride_vehicle_scrollpaint() +static void window_ride_vehicle_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_ride *ride; rct_ride_type *rideEntry; rct_widget *widget; @@ -2645,22 +2622,21 @@ static void window_ride_vehicle_scrollpaint() rct_vehichle_paintinfo *nextSpriteToDraw, *current, tmp; vehicle_colour vehicleColour; - window_paint_get_registers(w, dpi); - ride = GET_RIDE(w->number); rideEntry = ride_get_entry(ride); // Background gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width, dpi->y + dpi->height, 12); - RCT2_CALLPROC_X(0x006DE4CD, (ride->num_cars_per_train << 8) | ride->subtype, 0, 0, 0, 0, 0, 0); + uint8 trainLayout[16]; + ride_entry_get_train_layout(ride->subtype, ride->num_cars_per_train, trainLayout); widget = &window_ride_vehicle_widgets[WIDX_VEHICLE_TRAINS_PREVIEW]; startX = max(2, ((widget->right - widget->left) - ((ride->num_vehicles - 1) * 36)) / 2 - 25); startY = widget->bottom - widget->top - 4; - rct_ride_type_vehicle* rideVehicleEntry = &rideEntry->vehicles[RCT2_ADDRESS(0x00F64E38, uint8)[0]]; - startY += rideVehicleEntry->var_0A; + rct_ride_type_vehicle* rideVehicleEntry = &rideEntry->vehicles[trainLayout[0]]; + startY += rideVehicleEntry->tab_height; // For each train for (i = 0; i < ride->num_vehicles; i++) { @@ -2670,7 +2646,7 @@ static void window_ride_vehicle_scrollpaint() // For each car in train for (j = 0; j < ride->num_cars_per_train; j++) { - rct_ride_type_vehicle* rideVehicleEntry = &rideEntry->vehicles[RCT2_ADDRESS(0x00F64E38, uint8)[j]]; + rct_ride_type_vehicle* rideVehicleEntry = &rideEntry->vehicles[trainLayout[j]]; x += rideVehicleEntry->var_04 / 17432; y -= (rideVehicleEntry->var_04 / 2) / 17432; @@ -2692,7 +2668,7 @@ static void window_ride_vehicle_scrollpaint() if (rideVehicleEntry->var_12 & 0x800) spriteIndex /= 2; - spriteIndex &= rideVehicleEntry->var_00; + spriteIndex &= rideVehicleEntry->rotation_frame_mask; spriteIndex *= rideVehicleEntry->var_16; spriteIndex += rideVehicleEntry->base_image_id; spriteIndex |= (vehicleColour.additional_1 << 24) | (vehicleColour.main << 19); @@ -2760,7 +2736,7 @@ static void window_ride_mode_tweak_set(rct_window *w, uint8 value) } /** - * + * * rct2: 0x006B11D5 */ static void window_ride_mode_tweak_increase(rct_window *w) @@ -2781,7 +2757,7 @@ static void window_ride_mode_tweak_increase(rct_window *w) } /** - * + * * rct2: 0x006B120A */ static void window_ride_mode_tweak_decrease(rct_window *w) @@ -2795,7 +2771,7 @@ static void window_ride_mode_tweak_decrease(rct_window *w) } /** - * + * * rct2: 0x006B1631 */ static void window_ride_mode_dropdown(rct_window *w, rct_widget *widget) @@ -2811,24 +2787,21 @@ static void window_ride_mode_dropdown(rct_window *w, rct_widget *widget) rideEntry = ride_get_entry(ride); // Seek to available modes for this ride - availableModes = RideAvailableModes; - for (i = 0; i < ride->type; i++) { - while (*(availableModes++) != 255) { } - } + availableModes = ride_seek_available_modes(ride); // Count number of available modes mode = availableModes; - numAvailableModes = -1; + numAvailableModes = -1; do { numAvailableModes++; } while (*(mode++) != 255); - // ? - if (rideEntry->flags & RIDE_ENTRY_FLAG_15) + // Hide the last operating mode if the vehicle is not intended for it. + if (rideEntry->flags & RIDE_ENTRY_DISABLE_LAST_OPERATING_MODE && !gCheatsShowAllOperatingModes) numAvailableModes--; - // ? - if (rideEntry->flags & RIDE_ENTRY_FLAG_17) { + // If the vehicle is not intended for them, hide those two modes (these are usually (or perhaps always) both continuous circuit modes). + if ((rideEntry->flags & RIDE_ENTRY_DISABLE_FIRST_TWO_OPERATING_MODES) && !gCheatsShowAllOperatingModes) { availableModes += 2; numAvailableModes -= 2; } @@ -2849,13 +2822,15 @@ static void window_ride_mode_dropdown(rct_window *w, rct_widget *widget) ); // Set checked item - for (i = 0; i < numAvailableModes; i++) - if (ride->mode == availableModes[i]) - gDropdownItemsChecked = 1 << i; + for (i = 0; i < numAvailableModes; i++) { + if (ride->mode == availableModes[i]) { + dropdown_set_checked(i, true); + } + } } /** - * + * * rct2: 0x006B15C0 */ static void window_ride_load_dropdown(rct_window *w, rct_widget *widget) @@ -2880,21 +2855,17 @@ static void window_ride_load_dropdown(rct_window *w, rct_widget *widget) widget->right - dropdownWidget->left ); - gDropdownItemsChecked = (1 << (ride->depart_flags & RIDE_DEPART_WAIT_FOR_LOAD_MASK)); + dropdown_set_checked(ride->depart_flags & RIDE_DEPART_WAIT_FOR_LOAD_MASK, true); } /** - * + * * rct2: 0x006B10A7 */ -static void window_ride_operating_mouseup() +static void window_ride_operating_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; rct_ride *ride; - window_widget_get_registers(w, widgetIndex); - ride = GET_RIDE(w->number); switch (widgetIndex) { @@ -2932,20 +2903,16 @@ static void window_ride_operating_mouseup() } /** - * + * * rct2: 0x006B1715 */ -static void window_ride_operating_resize() +static void window_ride_operating_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 316, 186, 316, 186); } /** - * + * * rct2: 0x006B10F4 */ static void window_ride_operating_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) @@ -3000,18 +2967,13 @@ static void window_ride_operating_mousedown(int widgetIndex, rct_window *w, rct_ } /** - * + * * rct2: 0x006B1165 */ -static void window_ride_operating_dropdown() +static void window_ride_operating_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - rct_window *w; - short widgetIndex, dropdownIndex; rct_ride *ride; const uint8 *availableModes; - int i; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); if (dropdownIndex == -1) return; @@ -3021,10 +2983,8 @@ static void window_ride_operating_dropdown() switch (widgetIndex) { case WIDX_MODE_DROPDOWN: // Seek to available modes for this ride - availableModes = RideAvailableModes; - for (i = 0; i < ride->type; i++) { - while (*(availableModes++) != 255) { } - } + availableModes = ride_seek_available_modes(ride); + set_operating_setting(w->number, 0, availableModes[dropdownIndex]); break; case WIDX_LOAD_DROPDOWN: @@ -3034,7 +2994,7 @@ static void window_ride_operating_dropdown() } /** - * + * * rct2: 0x006B178E */ static void window_ride_operating_update(rct_window *w) @@ -3053,18 +3013,16 @@ static void window_ride_operating_update(rct_window *w) } /** - * + * * rct2: 0x006B0B30 */ -static void window_ride_operating_invalidate() +static void window_ride_operating_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; rct_ride *ride; rct_ride_type *rideEntry; rct_string_id format, caption, tooltip; - window_get_register(w); colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; @@ -3085,7 +3043,7 @@ static void window_ride_operating_invalidate() w->pressed_widgets &= ~0x44700000; // Lift hill speed - if ((rideEntry->enabledTrackPieces & RCT2_ADDRESS(0x01357444, uint32)[ride->type]) & 8) { + if ((rideEntry->enabledTrackPiecesA & 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; @@ -3111,7 +3069,7 @@ static void window_ride_operating_invalidate() window_ride_operating_widgets[WIDX_OPERATE_NUMBER_OF_CIRCUITS_INCREASE].type = WWT_EMPTY; window_ride_operating_widgets[WIDX_OPERATE_NUMBER_OF_CIRCUITS_DECREASE].type = WWT_EMPTY; } - + // Leave if another vehicle arrives at station if ( ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_LEAVE_WHEN_ANOTHER_VEHICLE_ARRIVES_AT_STATION) && @@ -3263,18 +3221,14 @@ static void window_ride_operating_invalidate() } /** - * + * * rct2: 0x006B1001 */ -static void window_ride_operating_paint() +static void window_ride_operating_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_ride *ride; uint16 blockSections; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_ride_draw_tab_images(dpi, w); @@ -3303,7 +3257,7 @@ static void window_ride_operating_paint() #pragma region Maintenance /** - * + * * rct2: 0x006B1AE4 */ static void window_ride_locate_mechanic(rct_window *w) @@ -3327,7 +3281,7 @@ static void window_ride_locate_mechanic(rct_window *w) } /** - * + * * rct2: 0x006B7D08 */ static void window_ride_maintenance_draw_bar(rct_window *w, rct_drawpixelinfo *dpi, int x, int y, int value, int unk) @@ -3346,16 +3300,11 @@ static void window_ride_maintenance_draw_bar(rct_window *w, rct_drawpixelinfo *d } /** - * + * * rct2: 0x006B1AAD */ -static void window_ride_maintenance_mouseup() +static void window_ride_maintenance_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -3379,20 +3328,16 @@ static void window_ride_maintenance_mouseup() } /** - * + * * rct2: 0x006B1D70 */ -static void window_ride_maintenance_resize() +static void window_ride_maintenance_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 316, 135, 316, 135); } /** - * + * * rct2: 0x006B1ACE */ static void window_ride_maintenance_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) @@ -3402,7 +3347,7 @@ static void window_ride_maintenance_mousedown(int widgetIndex, rct_window *w, rc rct_widget *dropdownWidget; int i, j, num_items; uint8 breakdownReason; - + dropdownWidget = widget; ride = GET_RIDE(w->number); @@ -3425,7 +3370,7 @@ static void window_ride_maintenance_mousedown(int widgetIndex, rct_window *w, rc widget->right - dropdownWidget->left ); - gDropdownItemsChecked = (1 << ride->inspection_interval); + dropdown_set_checked(ride->inspection_interval, true); break; case WIDX_FORCE_BREAKDOWN: @@ -3435,7 +3380,7 @@ static void window_ride_maintenance_mousedown(int widgetIndex, rct_window *w, rc break; } gDropdownItemsFormat[0] = 1142; - gDropdownItemsArgs[0] = 5290; + gDropdownItemsArgs[0] = STR_DEBUG_FIX_RIDE; 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)) { @@ -3448,7 +3393,7 @@ static void window_ride_maintenance_mousedown(int widgetIndex, rct_window *w, rc } } if (num_items == 1) { - window_error_open(5289, STR_NONE); + window_error_open(STR_DEBUG_NO_BREAKDOWNS_AVAILABLE, STR_NONE); } else { window_dropdown_show_text( @@ -3459,7 +3404,7 @@ static void window_ride_maintenance_mousedown(int widgetIndex, rct_window *w, rc 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)) { @@ -3470,7 +3415,7 @@ static void window_ride_maintenance_mousedown(int widgetIndex, rct_window *w, rc continue; } if (i == breakdownReason) { - gDropdownItemsChecked = (1 << num_items); + dropdown_set_checked(num_items, true); break; } gDropdownItemsFormat[num_items] = 1142; @@ -3481,32 +3426,28 @@ static void window_ride_maintenance_mousedown(int widgetIndex, rct_window *w, rc } if ((ride->lifecycle_flags & RIDE_LIFECYCLE_BREAKDOWN_PENDING) == 0) { - *gDropdownItemsDisabled = (1 << 0); + gDropdownItemsDisabled = (1 << 0); } } break; } - + } /** - * + * * rct2: 0x006B1AD9 */ -static void window_ride_maintenance_dropdown() +static void window_ride_maintenance_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - 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 (dropdownIndex == -1) return; - + ride = GET_RIDE(w->number); ride_type = gRideTypeList[ride->subtype]; @@ -3519,16 +3460,31 @@ static void window_ride_maintenance_dropdown() case WIDX_FORCE_BREAKDOWN: if (dropdownIndex == 0) { switch (ride->breakdown_reason_pending) { + case BREAKDOWN_SAFETY_CUT_OUT: + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)) + break; + for (int i = 0; i < ride->num_vehicles; ++i) { + uint16 spriteId = ride->vehicles[i]; + do { + vehicle = GET_VEHICLE(spriteId); + vehicle->update_flags &= ~( + VEHICLE_UPDATE_FLAG_BROKEN_CAR | + VEHICLE_UPDATE_FLAG_7 | + VEHICLE_UPDATE_FLAG_BROKEN_TRAIN + ); + } while ((spriteId = vehicle->next_vehicle_on_train) != 0xFFFF); + } + break; 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; + vehicle->update_flags &= ~VEHICLE_UPDATE_FLAG_BROKEN_CAR; break; case BREAKDOWN_VEHICLE_MALFUNCTION: vehicle = &(g_sprite_list[ride->vehicles[ride->broken_vehicle]].vehicle); - vehicle->var_48 &= ~0x200; + vehicle->update_flags &= ~VEHICLE_UPDATE_FLAG_BROKEN_TRAIN; break; } ride->lifecycle_flags &= ~(RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN); @@ -3566,7 +3522,7 @@ static void window_ride_maintenance_dropdown() } /** - * + * * rct2: 0x006B1D37 */ static void window_ride_maintenance_update(rct_window *w) @@ -3585,15 +3541,13 @@ static void window_ride_maintenance_update(rct_window *w) } /** - * + * * rct2: 0x006B17C8 */ -static void window_ride_maintenance_invalidate() +static void window_ride_maintenance_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; - window_get_register(w); colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; @@ -3623,13 +3577,11 @@ static void window_ride_maintenance_invalidate() } /** - * + * * rct2: 0x006B1877 */ -static void window_ride_maintenance_paint() +static void window_ride_maintenance_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_ride *ride; rct_widget *widget; rct_peep *mechanicSprite; @@ -3637,8 +3589,6 @@ static void window_ride_maintenance_paint() uint16 reliability, downTime, lastInspection; rct_string_id stringId, breakdownMessage; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_ride_draw_tab_images(dpi, w); @@ -3673,9 +3623,15 @@ static void window_ride_maintenance_paint() // Last inspection lastInspection = ride->last_inspection; - stringId = lastInspection <= 240 ? - STR_TIME_SINCE_LAST_INSPECTION_MINUTES : - STR_TIME_SINCE_LAST_INSPECTION_MORE_THAN_4_HOURS; + + // Use singular form for 1 minute of time or less + if (lastInspection <= 1) + stringId = STR_TIME_SINCE_LAST_INSPECTION_MINUTE; + else if (lastInspection <= 240) + stringId = STR_TIME_SINCE_LAST_INSPECTION_MINUTES; + else + stringId = STR_TIME_SINCE_LAST_INSPECTION_MORE_THAN_4_HOURS; + gfx_draw_string_left(dpi, stringId, &lastInspection, 0, x, y); y += 12; @@ -3718,7 +3674,7 @@ static void window_ride_maintenance_paint() RCT2_GLOBAL(0x013CE952 + 2, uint32) = mechanicSprite->id; gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x + 4, y, 280, stringId, 0); } - } + } } } } @@ -3739,7 +3695,8 @@ const uint8 window_ride_entrance_style_list[] = { RIDE_ENTRANCE_STYLE_ABSTRACT, RIDE_ENTRANCE_STYLE_SNOW_ICE, RIDE_ENTRANCE_STYLE_PAGODA, - RIDE_ENTRANCE_STYLE_SPACE + RIDE_ENTRANCE_STYLE_SPACE, + RIDE_ENTRANCE_STYLE_NONE }; static uint32 window_ride_get_colour_button_image(int colour) @@ -3749,11 +3706,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); + uint16 colourUse = RideEntranceDefinitions[ride->entrance_style].colour_use_flags; switch (trackColour) { - 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 0: return ((colourUse & 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 ((colourUse & 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; } @@ -3763,24 +3720,14 @@ static void window_ride_set_track_colour_scheme(rct_window *w, int x, int y) { rct_map_element *mapElement; uint8 newColourScheme; + int interactionType, z, direction; 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; - 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;*/ if (interactionType != VIEWPORT_INTERACTION_ITEM_RIDE) return; @@ -3789,28 +3736,17 @@ static void window_ride_set_track_colour_scheme(rct_window *w, int x, int y) if ((mapElement->properties.track.colour & 3) == newColourScheme) return; - RCT2_CALLPROC_X( - 0x006C683D, - x, - ((mapElement->type & 3) << 8) | mapElement->properties.track.type, - y, - mapElement->base_height << 3, - newColourScheme, - 0, - 4 - ); + z = mapElement->base_height * 8; + direction = mapElement->type & MAP_ELEMENT_DIRECTION_MASK; + sub_6C683D(&x, &y, &z, direction, mapElement->properties.track.type, newColourScheme, NULL, 4); } /** - * + * * rct2: 0x006B04FA */ -static void window_ride_colour_close() +static void window_ride_colour_close(rct_window *w) { - rct_window *w; - - window_get_register(w); - if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) return; @@ -3824,16 +3760,11 @@ static void window_ride_colour_close() } /** - * + * * rct2: 0x006B02A1 */ -static void window_ride_colour_mouseup() +static void window_ride_colour_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -3857,20 +3788,16 @@ static void window_ride_colour_mouseup() } /** - * + * * rct2: 0x006B0AB6 */ -static void window_ride_colour_resize() +static void window_ride_colour_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 316, 207, 316, 207); } /** - * + * * rct2: 0x006B02C6 */ static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) @@ -3905,7 +3832,7 @@ static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_wid widget->right - dropdownWidget->left ); - gDropdownItemsChecked = 1 << colourSchemeIndex; + dropdown_set_checked(colourSchemeIndex, true); break; case WIDX_TRACK_MAIN_COLOUR: window_dropdown_show_colour(w, widget, w->colours[1], ride->track_colour_main[colourSchemeIndex]); @@ -3932,17 +3859,19 @@ static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_wid widget->right - dropdownWidget->left ); - gDropdownItemsChecked = 1 << ride->track_colour_supports[colourSchemeIndex]; + dropdown_set_checked(ride->track_colour_supports[colourSchemeIndex], true); break; - case WIDX_ENTRANCE_STYLE_DROPDOWN: + case WIDX_ENTRANCE_STYLE_DROPDOWN: + gDropdownItemsChecked = 0; for (i = 0; i < countof(window_ride_entrance_style_list); i++) { gDropdownItemsFormat[i] = 1142; - gDropdownItemsArgs[i] = STR_PLAIN_ENTRANCE + window_ride_entrance_style_list[i]; + gDropdownItemsArgs[i] = RideEntranceDefinitions[window_ride_entrance_style_list[i]].string_id; - if (ride->entrance_style == window_ride_entrance_style_list[i]) - gDropdownItemsChecked = 1 << i; + if (ride->entrance_style == window_ride_entrance_style_list[i]) { + dropdown_set_checked(i, true); + } } - int checked = gDropdownItemsChecked; + uint64 checked = gDropdownItemsChecked; window_dropdown_show_text_custom_width( w->x + dropdownWidget->left, @@ -3956,7 +3885,7 @@ static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_wid gDropdownItemsChecked = checked; break; - case WIDX_VEHICLE_COLOUR_SCHEME_DROPDOWN: + case WIDX_VEHICLE_COLOUR_SCHEME_DROPDOWN: for (i = 0; i < 3; i++) { gDropdownItemsFormat[i] = 1142; gDropdownItemsArgs[i] = (RideNameConvention[ride->type].vehicle_name << 16) | (STR_ALL_VEHICLES_IN_SAME_COLOURS + i); @@ -3972,7 +3901,7 @@ static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_wid widget->right - dropdownWidget->left ); - gDropdownItemsChecked = 1 << (ride->colour_scheme_type & 3); + dropdown_set_checked(ride->colour_scheme_type & 3, true); break; case WIDX_VEHICLE_COLOUR_INDEX_DROPDOWN: numItems = ride->num_vehicles; @@ -3995,7 +3924,7 @@ static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_wid widget->right - dropdownWidget->left ); - gDropdownItemsChecked = 1 << w->var_48C; + dropdown_set_checked(w->var_48C, true); break; case WIDX_VEHICLE_MAIN_COLOUR: vehicleColour = ride_get_vehicle_colour(ride, w->var_48C); @@ -4013,16 +3942,11 @@ static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_wid } /** - * + * * rct2: 0x006B0331 */ -static void window_ride_colour_dropdown() +static void window_ride_colour_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - rct_window *w; - short widgetIndex, dropdownIndex; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (dropdownIndex == -1) return; @@ -4067,7 +3991,7 @@ static void window_ride_colour_dropdown() } /** - * + * * rct2: 0x006B0A8F */ static void window_ride_colour_update(rct_window *w) @@ -4079,42 +4003,31 @@ static void window_ride_colour_update(rct_window *w) } /** - * + * * rct2: 0x006B04EC */ -static void window_ride_colour_tooldown() +static void window_ride_colour_tooldown(rct_window *w, int widgetIndex, int x, int y) { - rct_window *w; - short widgetIndex, x, y; - - window_tool_get_registers(w, widgetIndex, x, y); - if (widgetIndex == WIDX_PAINT_INDIVIDUAL_AREA) window_ride_set_track_colour_scheme(w, x, y); } /** - * + * * rct2: 0x006B04F3 */ -static void window_ride_colour_tooldrag() +static void window_ride_colour_tooldrag(rct_window *w, int widgetIndex, int x, int y) { - rct_window *w; - short widgetIndex, x, y; - - window_tool_get_registers(w, widgetIndex, x, y); - if (widgetIndex == WIDX_PAINT_INDIVIDUAL_AREA) window_ride_set_track_colour_scheme(w, x, y); } /** - * + * * rct2: 0x006AFB36 */ -static void window_ride_colour_invalidate() +static void window_ride_colour_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; rct_ride_type *rideEntry; rct_ride *ride; @@ -4122,7 +4035,6 @@ static void window_ride_colour_invalidate() vehicle_colour vehicleColour; int vehicleColourSchemeType; - window_get_register(w); colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; @@ -4163,7 +4075,7 @@ static void window_ride_colour_invalidate() window_ride_colour_widgets[WIDX_TRACK_COLOUR_SCHEME_DROPDOWN].type = WWT_EMPTY; window_ride_colour_widgets[WIDX_PAINT_INDIVIDUAL_AREA].type = WWT_EMPTY; } - + // Track main colour if (window_ride_has_track_colour(ride, 0)) { window_ride_colour_widgets[WIDX_TRACK_MAIN_COLOUR].type = WWT_COLORBTN; @@ -4179,7 +4091,7 @@ static void window_ride_colour_invalidate() } else { window_ride_colour_widgets[WIDX_TRACK_ADDITIONAL_COLOUR].type = WWT_EMPTY; } - + // Track supports colour if (window_ride_has_track_colour(ride, 2) && ride->type != RIDE_TYPE_MAZE) { window_ride_colour_widgets[WIDX_TRACK_SUPPORT_COLOUR].type = WWT_COLORBTN; @@ -4195,12 +4107,12 @@ static void window_ride_colour_invalidate() window_ride_colour_widgets[WIDX_TRACK_PREVIEW].type = WWT_EMPTY; // Entrance style - if (RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint16) & 0x20) { + if (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_HAS_ENTRANCE_EXIT) { window_ride_colour_widgets[WIDX_ENTRANCE_PREVIEW].type = WWT_SPINNER; window_ride_colour_widgets[WIDX_ENTRANCE_STYLE].type = WWT_DROPDOWN; window_ride_colour_widgets[WIDX_ENTRANCE_STYLE_DROPDOWN].type = WWT_DROPDOWN_BUTTON; - window_ride_colour_widgets[WIDX_ENTRANCE_STYLE].image = STR_PLAIN_ENTRANCE + ride->entrance_style; + window_ride_colour_widgets[WIDX_ENTRANCE_STYLE].image = RideEntranceDefinitions[ride->entrance_style].string_id; } else { window_ride_colour_widgets[WIDX_ENTRANCE_PREVIEW].type = WWT_EMPTY; window_ride_colour_widgets[WIDX_ENTRANCE_STYLE].type = WWT_EMPTY; @@ -4218,23 +4130,25 @@ static void window_ride_colour_invalidate() window_ride_colour_widgets[WIDX_VEHICLE_PREVIEW].type = WWT_SCROLL; window_ride_colour_widgets[WIDX_VEHICLE_MAIN_COLOUR].type = WWT_COLORBTN; window_ride_colour_widgets[WIDX_VEHICLE_MAIN_COLOUR].image = window_ride_get_colour_button_image(vehicleColour.main); - - RCT2_CALLPROC_X(0x006DE4CD, (ride->num_cars_per_train << 8) | ride->subtype, 0, 0, 0, 0, 0, 0); - uint8 *unk; - uint32 unk_eax = 0; - for (unk = (uint8*)0x00F64E38; *unk != 0xFF; unk++) { - unk_eax |= rideEntry->vehicles[*unk].var_14; - unk_eax = ror32(unk_eax, 16); - unk_eax |= rideEntry->vehicles[*unk].var_12; - unk_eax = ror32(unk_eax, 16); + uint8 trainLayout[16]; + ride_entry_get_train_layout(ride->subtype, ride->num_cars_per_train, trainLayout); + + uint32 colourFlags = 0; + for (int i = 0; i < ride->num_cars_per_train; i++) { + uint8 vehicleTypeIndex = trainLayout[i]; + + colourFlags |= rideEntry->vehicles[vehicleTypeIndex].var_14; + colourFlags = ror32(colourFlags, 16); + colourFlags |= rideEntry->vehicles[vehicleTypeIndex].var_12; + colourFlags = ror32(colourFlags, 16); } // Additional colours - if (unk_eax & 1) { + if (colourFlags & 1) { window_ride_colour_widgets[WIDX_VEHICLE_ADDITIONAL_COLOUR_1].type = WWT_COLORBTN; window_ride_colour_widgets[WIDX_VEHICLE_ADDITIONAL_COLOUR_1].image = window_ride_get_colour_button_image(vehicleColour.additional_1); - if (unk_eax & 0x2000000) { + if (colourFlags & 0x2000000) { window_ride_colour_widgets[WIDX_VEHICLE_ADDITIONAL_COLOUR_2].type = WWT_COLORBTN; window_ride_colour_widgets[WIDX_VEHICLE_ADDITIONAL_COLOUR_2].image = window_ride_get_colour_button_image(vehicleColour.additional_2); } else { @@ -4284,21 +4198,18 @@ static void window_ride_colour_invalidate() } /** - * + * * rct2: 0x006AFF3E */ -static void window_ride_colour_paint() +static void window_ride_colour_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi, *clippedDpi; + rct_drawpixelinfo *clippedDpi; rct_widget *widget; rct_ride *ride; rct_ride_type *rideEntry; int x, y, spriteIndex, terniaryColour; track_colour trackColour; - window_paint_get_registers(w, dpi); - ride = GET_RIDE(w->number); rideEntry = ride_get_entry(ride); @@ -4309,10 +4220,10 @@ static void window_ride_colour_paint() widget = &window_ride_colour_widgets[WIDX_TRACK_PREVIEW]; if (widget->type != WWT_EMPTY) gfx_fill_rect(dpi, w->x + widget->left + 1, w->y + widget->top + 1, w->x + widget->right - 1, w->y + widget->bottom - 1, 12); - + trackColour = ride_get_track_colour(ride, *((uint16*)&w->var_494)); - // + // if (rideEntry->shop_item == 0xFF) { x = w->x + widget->left; y = w->y + widget->top; @@ -4355,23 +4266,28 @@ static void window_ride_colour_paint() if (clippedDpi != NULL) { gfx_clear(clippedDpi, 0x0C0C0C0C); - terniaryColour = 0; - if (RCT2_GLOBAL(0x00993E1C + (ride->entrance_style * 8), uint32) & 0x40000000) - terniaryColour = 0x40000000 | ((trackColour.main + 112) << 19); + if (ride->entrance_style != RIDE_ENTRANCE_STYLE_NONE) { + const rct_ride_entrance_definition *entranceStyle = &RideEntranceDefinitions[ride->entrance_style]; - spriteIndex = (trackColour.additional << 24) | (trackColour.main << 19); - spriteIndex |= 0xA0000000; - spriteIndex += RideEntranceDefinitions[ride->entrance_style].spriteIndex; + terniaryColour = 0; + if (entranceStyle->flags & 0x40000000) { + terniaryColour = 0x40000000 | ((trackColour.main + 112) << 19); + } - // Back - gfx_draw_sprite(clippedDpi, spriteIndex, 34, 20, terniaryColour); + spriteIndex = (trackColour.additional << 24) | (trackColour.main << 19); + spriteIndex |= 0xA0000000; + spriteIndex += RideEntranceDefinitions[ride->entrance_style].sprite_index; - // Front - gfx_draw_sprite(clippedDpi, spriteIndex + 4, 34, 20, terniaryColour); + // Back + gfx_draw_sprite(clippedDpi, spriteIndex, 34, 20, terniaryColour); - // ? - if (terniaryColour != 0) - gfx_draw_sprite(clippedDpi, ((spriteIndex + 20) & 0x7FFFF) + terniaryColour, 34, 20, terniaryColour); + // Front + gfx_draw_sprite(clippedDpi, spriteIndex + 4, 34, 20, terniaryColour); + + // ? + if (terniaryColour != 0) + gfx_draw_sprite(clippedDpi, ((spriteIndex + 20) & 0x7FFFF) + terniaryColour, 34, 20, terniaryColour); + } rct2_free(clippedDpi); } @@ -4379,21 +4295,17 @@ static void window_ride_colour_paint() } /** - * + * * rct2: 0x006B0192 */ -static void window_ride_colour_scrollpaint() +static void window_ride_colour_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_ride *ride; rct_ride_type *rideEntry; rct_widget *vehiclePreviewWidget; - int colour, x, y, spriteIndex; + int trainCarIndex, x, y, spriteIndex; vehicle_colour vehicleColour; - window_paint_get_registers(w, dpi); - ride = GET_RIDE(w->number); rideEntry = ride_get_entry(ride); vehiclePreviewWidget = &window_ride_colour_widgets[WIDX_VEHICLE_PREVIEW]; @@ -4405,19 +4317,21 @@ static void window_ride_colour_scrollpaint() // ? x = (vehiclePreviewWidget->right - vehiclePreviewWidget->left) / 2; y = vehiclePreviewWidget->bottom - vehiclePreviewWidget->top - 15; - RCT2_CALLPROC_X(0x006DE4CD, (ride->num_cars_per_train << 8) | ride->subtype, (int)ride, x, y, (int)w, (int)dpi, 0); + + uint8 trainLayout[16]; + ride_entry_get_train_layout(ride->subtype, ride->num_cars_per_train, trainLayout); // ? - colour = (ride->colour_scheme_type & 3) == RIDE_COLOUR_SCHEME_DIFFERENT_PER_CAR ? + trainCarIndex = (ride->colour_scheme_type & 3) == RIDE_COLOUR_SCHEME_DIFFERENT_PER_CAR ? w->var_48C : rideEntry->tab_vehicle; - rct_ride_type_vehicle* rideVehicleEntry = &rideEntry->vehicles[RCT2_ADDRESS(0x00F64E38, uint8)[colour]]; + rct_ride_type_vehicle* rideVehicleEntry = &rideEntry->vehicles[trainLayout[trainCarIndex]]; - y += rideVehicleEntry->var_0A; + y += rideVehicleEntry->tab_height; // Draw the coloured spinning vehicle spriteIndex = rideVehicleEntry->var_12 & 0x800 ? w->frame_no / 4 : w->frame_no / 2; - spriteIndex &= rideVehicleEntry->var_00; + spriteIndex &= rideVehicleEntry->rotation_frame_mask; spriteIndex *= rideVehicleEntry->var_16; spriteIndex += rideVehicleEntry->base_image_id; spriteIndex |= (vehicleColour.additional_1 << 24) | (vehicleColour.main << 19); @@ -4464,7 +4378,7 @@ const uint8 MusicStyleOrder[] = { static uint8 window_ride_current_music_style_order[42]; /** - * + * * rct2: 0x006B215D */ static void window_ride_toggle_music(rct_window *w) @@ -4478,16 +4392,11 @@ static void window_ride_toggle_music(rct_window *w) } /** - * + * * rct2: 0x006B1ED7 */ -static void window_ride_music_mouseup() +static void window_ride_music_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -4511,21 +4420,17 @@ static void window_ride_music_mouseup() } /** - * + * * rct2: 0x006AF4A2 */ -static void window_ride_music_resize() +static void window_ride_music_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - w->flags |= WF_RESIZABLE; window_set_resize(w, 316, 81, 316, 81); } /** - * + * * rct2: 0x006B1EFC */ static void window_ride_music_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) @@ -4541,14 +4446,14 @@ static void window_ride_music_mousedown(int widgetIndex, rct_window *w, rct_widg int numItems = 0; if (ride->type == RIDE_TYPE_MERRY_GO_ROUND) { - window_ride_current_music_style_order[numItems++] = MUSIC_STYLE_FAIRGROUND_ORGAN; + window_ride_current_music_style_order[numItems++] = MUSIC_STYLE_FAIRGROUND_ORGAN; } else { for (i = 0; i < countof(MusicStyleOrder); i++) window_ride_current_music_style_order[numItems++] = MusicStyleOrder[i]; - if (ride_music_info_list[36]->length != 0) + if (gRideMusicInfoList[36]->length != 0) window_ride_current_music_style_order[numItems++] = MUSIC_STYLE_CUSTOM_MUSIC_1; - if (ride_music_info_list[37]->length != 0) + if (gRideMusicInfoList[37]->length != 0) window_ride_current_music_style_order[numItems++] = MUSIC_STYLE_CUSTOM_MUSIC_2; } @@ -4568,23 +4473,20 @@ static void window_ride_music_mousedown(int widgetIndex, rct_window *w, rct_widg ); for (i = 0; i < numItems; i++) { - if (window_ride_current_music_style_order[i] == ride->music) - gDropdownItemsChecked = (1 << i); + if (window_ride_current_music_style_order[i] == ride->music) { + dropdown_set_checked(i, true); + } } } /** - * + * * rct2: 0x006B1F03 */ -static void window_ride_music_dropdown() +static void window_ride_music_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - rct_window *w; rct_ride *ride; uint8 musicStyle; - short widgetIndex, dropdownIndex; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); if (widgetIndex != WIDX_MUSIC_DROPDOWN || dropdownIndex == -1) return; @@ -4596,7 +4498,7 @@ static void window_ride_music_dropdown() } /** - * + * * rct2: 0x006B2198 */ static void window_ride_music_update(rct_window *w) @@ -4607,16 +4509,14 @@ static void window_ride_music_update(rct_window *w) } /** - * + * * rct2: 0x006B1DEA */ -static void window_ride_music_invalidate() +static void window_ride_music_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; int isMusicActivated; - window_get_register(w); colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; @@ -4651,16 +4551,11 @@ static void window_ride_music_invalidate() } /** - * + * * rct2: 0x006B1ECC */ -static void window_ride_music_paint() +static void window_ride_music_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_ride_draw_tab_images(dpi, w); } @@ -4673,7 +4568,7 @@ static void window_ride_music_paint() static void cancel_scenery_selection(){ RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) &= ~(1 << 2); RCT2_GLOBAL(0x9DEA6F, uint8) &= ~(1 << 0); - unpause_sounds(); + audio_unpause_sounds(); rct_window* main_w = window_get_main(); @@ -4698,11 +4593,11 @@ static void setup_scenery_selection(rct_window* w){ RCT2_GLOBAL(0x00F64DE8, uint8) = (uint8)w->number; RCT2_GLOBAL(0x009DA193, uint8) = 0xFF; - RCT2_GLOBAL(0x00F63674, sint32) = -1; + gTrackSavedMapElements[0] = (rct_map_element*)-1; RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) |= (1 << 2); RCT2_GLOBAL(0x009DEA6F, uint8) |= 1; - pause_sounds(); + audio_pause_sounds(); rct_window* w_main = window_get_main(); @@ -4714,7 +4609,7 @@ static void setup_scenery_selection(rct_window* w){ } /** - * + * * rct2: 0x006D3026 */ static void window_ride_measurements_design_reset() @@ -4723,7 +4618,7 @@ static void window_ride_measurements_design_reset() } /** - * + * * rct2: 0x006D303D */ static void window_ride_measurements_design_select_nearby_scenery() @@ -4732,7 +4627,7 @@ static void window_ride_measurements_design_select_nearby_scenery() } /** - * + * * rct2: 0x006AD4DA */ static void window_ride_measurements_design_cancel() @@ -4742,7 +4637,7 @@ static void window_ride_measurements_design_cancel() } /** - * + * * rct2: 0x006AD4CD */ static void window_ride_measurements_design_save(rct_window *w) @@ -4753,25 +4648,20 @@ static void window_ride_measurements_design_save(rct_window *w) } /** - * + * * rct2: 0x006AD4DA */ -static void window_ride_measurements_close() +static void window_ride_measurements_close(rct_window *w) { window_ride_measurements_design_cancel(); } /** - * + * * rct2: 0x006AD478 */ -static void window_ride_measurements_mouseup() +static void window_ride_measurements_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -4804,20 +4694,16 @@ static void window_ride_measurements_mouseup() } /** - * + * * rct2: 0x006AD564 */ -static void window_ride_measurements_resize() +static void window_ride_measurements_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 316, 202, 316, 202); } /** - * + * * rct2: 0x006AD4AB */ static void window_ride_measurements_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) @@ -4838,27 +4724,22 @@ static void window_ride_measurements_mousedown(int widgetIndex, rct_window *w, r 0, 2 ); - RCT2_GLOBAL(0x009DEBA2, sint16) = 0; + gDropdownHighlightedIndex = 0; if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) - RCT2_GLOBAL(0x009DED34, uint32) |= 2; + gDropdownItemsDisabled |= 2; } /** - * + * * rct2: 0x006AD4B2 */ -static void window_ride_measurements_dropdown() +static void window_ride_measurements_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - rct_window *w; - short widgetIndex, dropdownIndex; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (widgetIndex != WIDX_SAVE_TRACK_DESIGN) return; if (dropdownIndex == -1) - dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16); + dropdownIndex = gDropdownHighlightedIndex; if (dropdownIndex == 0) save_track_design((uint8)w->number); @@ -4867,7 +4748,7 @@ static void window_ride_measurements_dropdown() } /** - * + * * rct2: 0x006AD5DD */ static void window_ride_measurements_update(rct_window *w) @@ -4878,38 +4759,43 @@ static void window_ride_measurements_update(rct_window *w) } /** - * - * rct2: 0x006AD4EB + * + * rct2: 0x006D2AE7 */ -static void window_ride_measurements_tooldown() +static void window_ride_measurements_tooldown(rct_window *w, int widgetIndex, int x, int y) { - rct_window *w; - short x, y, widgetIndex; + rct_map_element *mapElement; + sint16 mapX, mapY; + int interactionType; - window_tool_get_registers(w, widgetIndex, x, y); - - RCT2_CALLPROC_X(0x006D2AE7, x, y, 0, widgetIndex, (int)w, 0, 0); + get_map_coordinates_from_pos(x, y, 0xFCCF, &mapX, &mapY, &interactionType, &mapElement, NULL); + switch (interactionType) { + case VIEWPORT_INTERACTION_ITEM_SCENERY: + case VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY: + case VIEWPORT_INTERACTION_ITEM_WALL: + case VIEWPORT_INTERACTION_ITEM_FOOTPATH: + track_save_toggle_map_element(interactionType, mapX, mapY, mapElement); + break; + } } /** - * + * * rct2: 0x006AD4DA */ -static void window_ride_measurements_toolabort(rct_window *w) +static void window_ride_measurements_toolabort(rct_window *w, int widgetIndex) { window_ride_measurements_design_cancel(); } /** - * + * * rct2: 0x006ACDBC */ -static void window_ride_measurements_invalidate() +static void window_ride_measurements_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; - window_get_register(w); colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; @@ -4936,15 +4822,14 @@ 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_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) { - if (ride->excitement != -1) { - w->disabled_widgets &= ~(1 << WIDX_SAVE_TRACK_DESIGN); - window_ride_measurements_widgets[WIDX_SAVE_TRACK_DESIGN].tooltip = STR_SAVE_TRACK_DESIGN; - } + + 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) { + if (ride->excitement != -1) { + w->disabled_widgets &= ~(1 << WIDX_SAVE_TRACK_DESIGN); + window_ride_measurements_widgets[WIDX_SAVE_TRACK_DESIGN].tooltip = STR_SAVE_TRACK_DESIGN; } } } @@ -4955,13 +4840,11 @@ static void window_ride_measurements_invalidate() } /** - * + * * rct2: 0x006ACF07 */ -static void window_ride_measurements_paint() +static void window_ride_measurements_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_widget *widget; rct_ride *ride; rct_string_id stringId; @@ -4969,8 +4852,6 @@ static void window_ride_measurements_paint() sint16 holes, maxSpeed, averageSpeed, drops, highestDropHeight, inversions, time; sint32 maxPositiveVerticalGs, maxNegativeVerticalGs, maxLateralGs, totalAirTime, length; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_ride_draw_tab_images(dpi, w); @@ -4986,9 +4867,6 @@ static void window_ride_measurements_paint() gfx_fill_rect_inset(dpi, x, y, w->x + 312, y + 1, w->colours[1], 0x20); } else { ride = GET_RIDE(w->number); - - 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; y = w->y + window_ride_measurements_widgets[WIDX_PAGE_BACKGROUND].top + 4; @@ -5156,7 +5034,7 @@ enum { }; /** - * + * * rct2: 0x006AE8A6 */ static void window_ride_set_graph(rct_window *w, int type) @@ -5171,16 +5049,11 @@ static void window_ride_set_graph(rct_window *w, int type) } /** - * + * * rct2: 0x006AE85D */ -static void window_ride_graphs_mouseup() +static void window_ride_graphs_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -5201,20 +5074,16 @@ static void window_ride_graphs_mouseup() } /** - * + * * rct2: 0x006AE8DA */ -static void window_ride_graphs_resize() +static void window_ride_graphs_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 316, 180, 500, 450); } /** - * + * * rct2: 0x006AE878 */ static void window_ride_graphs_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) @@ -5236,7 +5105,7 @@ static void window_ride_graphs_mousedown(int widgetIndex, rct_window *w, rct_wid } /** - * + * * rct2: 0x006AE95D */ static void window_ride_graphs_update(rct_window *w) @@ -5265,87 +5134,68 @@ static void window_ride_graphs_update(rct_window *w) } /** - * + * * rct2: 0x006AEA75 */ -static void window_ride_graphs_scrollgetheight() +static void window_ride_graphs_scrollgetheight(rct_window *w, int scrollIndex, int *width, int *height) { - rct_window *w; rct_ride_measurement *measurement; - int width, height; - - window_get_register(w); window_event_invalidate_call(w); // Set minimum size - width = window_ride_graphs_widgets[WIDX_GRAPH].right - window_ride_graphs_widgets[WIDX_GRAPH].left - 2; - height = 0; + *width = window_ride_graphs_widgets[WIDX_GRAPH].right - window_ride_graphs_widgets[WIDX_GRAPH].left - 2; // Get measurement size measurement = ride_get_measurement(w->number, NULL); if (measurement != NULL) - width = max(width, measurement->num_items); - - window_scrollsize_set_registers(width, height); + *width = max(*width, measurement->num_items); } /** - * + * * rct2: 0x006AE953 */ -static void window_ride_graphs_15() +static void window_ride_graphs_15(rct_window *w, int scrollIndex, int scrollAreaType) { - rct_window *w; - - window_get_register(w); - w->list_information_type |= 0x8000; } /** - * + * * rct2: 0x006AEA05 */ -static void window_ride_graphs_tooltip() +static void window_ride_graphs_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) { - rct_window *w; - short widgetIndex, result; rct_ride *ride; rct_ride_measurement *measurement; - rct_string_id stringId; + rct_string_id message; - window_tooltip_get_registers(w, widgetIndex); - - result = -1; if (widgetIndex == WIDX_GRAPH) { - RCT2_GLOBAL(0x013CE952, uint16) = 3158; - measurement = ride_get_measurement(w->number, &stringId); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = 3158; + measurement = ride_get_measurement(w->number, &message); if (measurement != NULL && (measurement->flags & RIDE_MEASUREMENT_FLAG_RUNNING)) { RCT2_GLOBAL(0x013CE952 + 4, uint16) = measurement->vehicle_index + 1; ride = GET_RIDE(w->number); RCT2_GLOBAL(0x013CE952 + 2, uint16) = RideNameConvention[ride->type].vehicle_name + 6; - result = 0; } else { - result = stringId; + *stringId = message; } + } else { + *stringId = STR_NONE; } - - window_tooltip_set_registers(result); } /** - * + * * rct2: 0x006AE372 */ -static void window_ride_graphs_invalidate() +static void window_ride_graphs_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; rct_ride *ride; int x, y; - window_get_register(w); colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; @@ -5367,7 +5217,7 @@ static void window_ride_graphs_invalidate() w->pressed_widgets &= ~(1 << WIDX_GRAPH_VERTICAL); w->pressed_widgets &= ~(1 << WIDX_GRAPH_LATERAL); w->pressed_widgets |= (1LL << (WIDX_GRAPH_VELOCITY + (w->list_information_type & 0xFF))); - + // Hide graph buttons that are not applicable if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_G_FORCES)) { window_ride_graphs_widgets[WIDX_GRAPH_VERTICAL].type = WWT_DROPDOWN_BUTTON; @@ -5399,35 +5249,26 @@ static void window_ride_graphs_invalidate() } /** - * + * * rct2: 0x006AE4BC */ -static void window_ride_graphs_paint() +static void window_ride_graphs_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_ride_draw_tab_images(dpi, w); } /** - * + * * rct2: 0x006AE4C7 */ -static void window_ride_graphs_scrollpaint() +static void window_ride_graphs_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_ride_measurement *measurement; rct_widget *widget; int x, y, width, time, listType, colour, top, bottom, tmp; rct_string_id stringId; - window_paint_get_registers(w, dpi); - gfx_clear(dpi, RCT2_GLOBAL(0x0141FC9D, uint8) * 0x01010101); widget = &window_ride_graphs_widgets[WIDX_GRAPH]; @@ -5518,6 +5359,9 @@ static void window_ride_graphs_scrollpaint() top = measurement->lateral[x] + 52; bottom = measurement->lateral[x + 1] + 52; break; + default: + log_error("Wrong graph type %d", listType); + top = bottom = 0; } top = widget->bottom - widget->top - top - 13; @@ -5536,7 +5380,7 @@ static void window_ride_graphs_scrollpaint() #pragma region Income /** - * + * * rct2: 0x006ADEFD */ static void window_ride_income_toggle_primary_price(rct_window *w) @@ -5548,7 +5392,7 @@ static void window_ride_income_toggle_primary_price(rct_window *w) ride = GET_RIDE(w->number); ride_type = gRideTypeList[ride->subtype]; - + if (ride->type == RIDE_TYPE_TOILETS) { shop_item = 0x1F; } @@ -5583,7 +5427,7 @@ static void window_ride_income_toggle_primary_price(rct_window *w) } /** - * + * * rct2: 0x006AE06E */ static void window_ride_income_toggle_secondary_price(rct_window *w) @@ -5595,7 +5439,7 @@ static void window_ride_income_toggle_secondary_price(rct_window *w) 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); @@ -5626,7 +5470,7 @@ static void window_ride_income_toggle_secondary_price(rct_window *w) } /** - * + * * rct2: 0x006AE1E4 */ static void window_ride_income_increase_primary_price(rct_window *w) @@ -5636,7 +5480,7 @@ static void window_ride_income_increase_primary_price(rct_window *w) 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) @@ -5651,7 +5495,7 @@ static void window_ride_income_increase_primary_price(rct_window *w) } /** - * + * * rct2: 0x006AE237 */ static void window_ride_income_decrease_primary_price(rct_window *w) @@ -5676,7 +5520,7 @@ static void window_ride_income_decrease_primary_price(rct_window *w) } /** - * + * * rct2: 0x006AE269 */ static void window_ride_income_increase_secondary_price(rct_window *w) @@ -5686,13 +5530,7 @@ static void window_ride_income_increase_secondary_price(rct_window *w) 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++; @@ -5701,7 +5539,7 @@ static void window_ride_income_increase_secondary_price(rct_window *w) } /** - * + * * rct2: 0x006AE28D */ static void window_ride_income_decrease_secondary_price(rct_window *w) @@ -5711,13 +5549,7 @@ static void window_ride_income_decrease_secondary_price(rct_window *w) 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--; @@ -5726,16 +5558,11 @@ static void window_ride_income_decrease_secondary_price(rct_window *w) } /** - * + * * rct2: 0x006ADEA9 */ -static void window_ride_income_mouseup() +static void window_ride_income_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -5762,20 +5589,16 @@ static void window_ride_income_mouseup() } /** - * + * * rct2: 0x006AE2F8 */ -static void window_ride_income_resize() +static void window_ride_income_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - window_set_resize(w, 316, 177, 316, 177); } /** - * + * * rct2: 0x006ADED4 */ static void window_ride_income_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) @@ -5797,7 +5620,7 @@ static void window_ride_income_mousedown(int widgetIndex, rct_window *w, rct_wid } /** - * + * * rct2: 0x006AE2BF */ static void window_ride_income_update(rct_window *w) @@ -5816,18 +5639,16 @@ static void window_ride_income_update(rct_window *w) } /** - * + * * rct2: 0x006ADAA3 */ -static void window_ride_income_invalidate() +static void window_ride_income_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; rct_ride_type *rideEntry; rct_string_id stringId; int primaryItem, secondaryItem; - window_get_register(w); colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; @@ -5858,7 +5679,7 @@ static void window_ride_income_invalidate() window_ride_income_widgets[WIDX_PRIMARY_PRICE_LABEL].image = STR_RIDE_INCOME_ADMISSION_PRICE; window_ride_income_widgets[WIDX_SECONDARY_PRICE_LABEL].image = STR_ON_RIDE_PHOTO_PRICE; window_ride_income_widgets[WIDX_PRIMARY_PRICE_SAME_THROUGHOUT_PARK].type = WWT_EMPTY; - + window_ride_income_widgets[WIDX_PRIMARY_PRICE].image = 1429; RCT2_GLOBAL(0x013CE952 + 6, money32) = ride->price; if (ride->price == 0) @@ -5935,21 +5756,17 @@ static void window_ride_income_invalidate() } /** - * + * * rct2: 0x006ADCE5 */ -static void window_ride_income_paint() +static void window_ride_income_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_ride *ride; rct_ride_type *rideEntry; rct_string_id stringId; money32 profit, costPerHour; int x, y, primaryItem, secondaryItem; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_ride_draw_tab_images(dpi, w); @@ -6006,7 +5823,7 @@ static void window_ride_income_paint() // Running cost per hour costPerHour = ride->upkeep_cost * 16; - stringId = ride->upkeep_cost == 0xFFFF ? STR_RUNNING_COST_UNKNOWN : STR_RUNNING_COST_PER_HOUR; + stringId = ride->upkeep_cost == (money16)0xFFFF ? STR_RUNNING_COST_UNKNOWN : STR_RUNNING_COST_PER_HOUR; gfx_draw_string_left(dpi, stringId, &costPerHour, 0, x, y); y += 10; @@ -6026,16 +5843,11 @@ static void window_ride_income_paint() #pragma region Customer /** - * + * * rct2: 0x006AD986 */ -static void window_ride_customer_mouseup() +static void window_ride_customer_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -6065,21 +5877,17 @@ static void window_ride_customer_mouseup() } /** - * + * * rct2: 0x006ADA29 */ -static void window_ride_customer_resize() +static void window_ride_customer_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - w->flags |= WF_RESIZABLE; window_set_resize(w, 316, 139, 316, 139); } /** - * + * * rct2: 0x006AD9DD */ static void window_ride_customer_update(rct_window *w) @@ -6101,15 +5909,13 @@ static void window_ride_customer_update(rct_window *w) } /** - * + * * rct2: 0x006AD5F8 */ -static void window_ride_customer_invalidate() +static void window_ride_customer_invalidate(rct_window *w) { - rct_window *w; rct_widget *widgets; - window_get_register(w); colour_scheme_update(w); widgets = window_ride_page_widgets[w->page]; @@ -6138,13 +5944,11 @@ static void window_ride_customer_invalidate() } /** - * + * * rct2: 0x006AD6CD */ -static void window_ride_customer_paint() +static void window_ride_customer_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_ride *ride; int x, y; uint8 shopItem; @@ -6152,8 +5956,6 @@ static void window_ride_customer_paint() sint32 customersPerHour; rct_string_id stringId; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_ride_draw_tab_images(dpi, w); @@ -6199,26 +6001,18 @@ static void window_ride_customer_paint() // Primary shop items sold shopItem = ride_get_entry(ride)->shop_item; if (shopItem != 0xFF) { - stringId = 2016 + shopItem; - if (stringId >= 2048) - stringId += 96; - - RCT2_GLOBAL(0x013CE952 + 0, uint16) = stringId; + RCT2_GLOBAL(0x013CE952 + 0, uint16) = ShopItemStringIds[shopItem].plural; 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; } - + // Secondary shop items sold / on-ride photos sold shopItem = ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO ? RCT2_GLOBAL(0x0097D7CB + (ride->type * 4), uint8) : ride_get_entry(ride)->shop_item_secondary; if (shopItem != 0xFF) { - stringId = 2016 + shopItem; - if (stringId >= 2048) - stringId += 96; - - RCT2_GLOBAL(0x013CE952 + 0, uint16) = stringId; + RCT2_GLOBAL(0x013CE952 + 0, uint16) = ShopItemStringIds[shopItem].plural; 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; diff --git a/src/windows/ride_construction.c b/src/windows/ride_construction.c index 7cb6c54658..1ece93b7c2 100644 --- a/src/windows/ride_construction.c +++ b/src/windows/ride_construction.c @@ -19,138 +19,501 @@ *****************************************************************************/ #include "../addresses.h" -#include "../interface/window.h" -#include "../interface/viewport.h" -#include "../game.h" -#include "../ride/track.h" +#include "../audio/audio.h" +#include "../cheats.h" #include "../drawing/drawing.h" +#include "../game.h" +#include "../input.h" #include "../interface/themes.h" +#include "../interface/viewport.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../network/network.h" +#include "../ride/ride_data.h" +#include "../ride/track.h" +#include "dropdown.h" /* move to ride.c */ -void sub_6b2fa9(rct_windownumber number){ +void sub_6B2FA9(rct_windownumber number) +{ rct_window* w; w = window_find_by_number(WC_RIDE, number); - if (w){ - if (w->page == 1){ - window_close(w); - } - } + if (w != NULL && w->page == 1) + window_close(w); } +#pragma region Widgets + enum { WIDX_BACKGROUND, WIDX_TITLE, WIDX_CLOSE, - WIDX_PAGE_BACKGROUND, - - WIDX_DEMOLISH = 24 + WIDX_DIRECTION_GROUPBOX, + WIDX_SLOPE_GROUPBOX, + WIDX_BANKING_GROUPBOX, + WIDX_LEFT_CURVE_VERY_SMALL, + WIDX_LEFT_CURVE_SMALL, + WIDX_LEFT_CURVE, + WIDX_STRAIGHT, + WIDX_RIGHT_CURVE, + WIDX_RIGHT_CURVE_SMALL, + WIDX_RIGHT_CURVE_VERY_SMALL, + WIDX_SPECIAL_TRACK_DROPDOWN, + WIDX_SLOPE_DOWN_STEEP, + WIDX_SLOPE_DOWN, + WIDX_LEVEL, + WIDX_SLOPE_UP, + WIDX_SLOPE_UP_STEEP, + WIDX_CHAIN_LIFT, + WIDX_BANK_LEFT, + WIDX_BANK_STRAIGHT, + WIDX_BANK_RIGHT, + WIDX_CONSTRUCT, + WIDX_DEMOLISH, + WIDX_LEFT_CURVE_LARGE, + WIDX_PREVIOUS_SECTION, + WIDX_NEXT_SECTION, + WIDX_ENTRANCE_EXIT_GROUPBOX, + WIDX_ENTRANCE, + WIDX_EXIT, + WIDX_RIGHT_CURVE_LARGE, + WIDX_ROTATE, + WIDX_U_TRACK, + WIDX_O_TRACK, + WIDX_SEAT_ROTATION_GROUPBOX, + WIDX_SEAT_ROTATION_ANGLE_SPINNER, + WIDX_SEAT_ROTATION_ANGLE_SPINNER_UP, + WIDX_SEAT_ROTATION_ANGLE_SPINNER_DOWN, }; -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[] = { - window_construction_maze_close, - (void*)0x6CD461, - (void*)0x6CD623, - (void*)0x6CD48C, - window_construction_emptysub, - window_construction_emptysub, - (void*)0x6CD767, - window_construction_emptysub, - window_construction_emptysub, - (void*)0x6CD63E, - (void*)0x6CD65D, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_maze_invalidate, - window_construction_maze_paint, - window_construction_emptysub +static rct_widget window_ride_construction_widgets[] = { + { WWT_FRAME, 0, 0, 165, 0, 393, 0xFFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 164, 1, 14, 896, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 153, 163, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_GROUPBOX, 0, 3, 162, 17, 73, STR_RIDE_CONSTRUCTION_DIRECTION, STR_NONE }, + { WWT_GROUPBOX, 0, 3, 162, 76, 116, STR_RIDE_CONSTRUCTION_SLOPE, STR_NONE }, + { WWT_GROUPBOX, 0, 3, 162, 120, 160, STR_RIDE_CONSTRUCTION_ROLL_BANKING, STR_NONE }, + { WWT_FLATBTN, 1, 6, 27, 29, 52, 0x1414, STR_RIDE_CONSTRUCTION_LEFT_CURVE_VERY_SMALL_TIP }, + { WWT_FLATBTN, 1, 6, 27, 29, 52, 0x1414, STR_RIDE_CONSTRUCTION_LEFT_CURVE_SMALL_TIP }, + { WWT_FLATBTN, 1, 28, 49, 29, 52, 0x1412, STR_RIDE_CONSTRUCTION_LEFT_CURVE_TIP }, + { WWT_FLATBTN, 1, 72, 93, 29, 52, 0x1411, STR_RIDE_CONSTRUCTION_STRAIGHT_TIP }, + { WWT_FLATBTN, 1, 116, 137, 29, 52, 0x1413, STR_RIDE_CONSTRUCTION_RIGHT_CURVE_TIP }, + { WWT_FLATBTN, 1, 138, 159, 29, 52, 0x1415, STR_RIDE_CONSTRUCTION_RIGHT_CURVE_SMALL_TIP }, + { WWT_FLATBTN, 1, 138, 159, 29, 52, 0x1415, STR_RIDE_CONSTRUCTION_RIGHT_CURVE_VERY_SMALL_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 17, 148, 55, 68, 1384, STR_RIDE_CONSTRUCTION_OTHER_TRACK_CONFIGURATIONS_TIP }, + { WWT_FLATBTN, 1, 23, 46, 88, 111, 0x1418, STR_RIDE_CONSTRUCTION_STEEP_SLOPE_DOWN_TIP }, + { WWT_FLATBTN, 1, 47, 70, 88, 111, 0x1419, STR_RIDE_CONSTRUCTION_SLOPE_DOWN_TIP }, + { WWT_FLATBTN, 1, 71, 94, 88, 111, 0x141A, STR_RIDE_CONSTRUCTION_LEVEL_TIP }, + { WWT_FLATBTN, 1, 95, 118, 88, 111, 0x141B, STR_RIDE_CONSTRUCTION_SLOPE_UP_TIP }, + { WWT_FLATBTN, 1, 119, 142, 88, 111, 0x141C, STR_RIDE_CONSTRUCTION_STEEP_SLOPE_UP_TIP }, + { WWT_FLATBTN, 1, 134, 157, 88, 111, 0x142B, STR_RIDE_CONSTRUCTION_CHAIN_LIFT_TIP }, + { WWT_FLATBTN, 1, 47, 70, 132, 155, 0x1421, STR_RIDE_CONSTRUCTION_ROLL_FOR_LEFT_CURVE_TIP }, + { WWT_FLATBTN, 1, 71, 94, 132, 155, 0x1422, STR_RIDE_CONSTRUCTION_NO_ROLL_TIP }, + { WWT_FLATBTN, 1, 95, 118, 132, 155, 0x1423, STR_RIDE_CONSTRUCTION_ROLL_FOR_RIGHT_CURVE_TIP }, + { WWT_IMGBTN, 1, 3, 162, 164, 333, 0xFFFFFFFF, STR_RIDE_CONSTRUCTION_CONSTRUCT_SELECTED_SECTION_TIP }, + { WWT_FLATBTN, 1, 60, 105, 338, 361, 0x142A, STR_RIDE_CONSTRUCTION_REMOVE_HIGHLIGHTED_SECTION_TIP }, + { WWT_FLATBTN, 1, 50, 71, 29, 52, 0x1416, STR_RIDE_CONSTRUCTION_LEFT_CURVE_LARGE_TIP }, + { WWT_FLATBTN, 1, 20, 43, 338, 361, 0x1428, STR_RIDE_CONSTRUCTION_MOVE_TO_PREVIOUS_SECTION_TIP }, + { WWT_FLATBTN, 1, 122, 145, 338, 361, 0x1429, STR_RIDE_CONSTRUCTION_MOVE_TO_NEXT_SECTION_TIP }, + { WWT_GROUPBOX, 0, 3, 162, 362, 389, 0xFFFFFFFF, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 9, 78, 372, 383, STR_RIDE_CONSTRUCTION_ENTRANCE, STR_RIDE_CONSTRUCTION_ENTRANCE_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 87, 156, 372, 383, STR_RIDE_CONSTRUCTION_EXIT, STR_RIDE_CONSTRUCTION_EXIT_TIP }, + { WWT_FLATBTN, 1, 94, 115, 29, 52, 0x1417, STR_RIDE_CONSTRUCTION_RIGHT_CURVE_LARGE_TIP }, + { WWT_FLATBTN, 1, 72, 95, 338, 361, 0x1431, STR_ROTATE_90_TIP }, + { WWT_FLATBTN, 1, 19, 42, 132, 155, 0x1424, STR_RIDE_CONSTRUCTION_U_SHAPED_OPEN_TRACK_TIP }, + { WWT_FLATBTN, 1, 123, 146, 132, 155, 0x1425, STR_RIDE_CONSTRUCTION_O_SHAPED_ENCLOSED_TRACK_TIP }, + { WWT_GROUPBOX, 0, 96, 162, 120, 160, STR_RIDE_CONSTRUCTION_SEAT_ROT, STR_NONE }, + { WWT_SPINNER, 1, 101, 158, 138, 149, 0, STR_RIDE_CONSTRUCTION_SELECT_SEAT_ROTATION_ANGLE_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 147, 157, 139, 143, STR_NUMERIC_UP, STR_RIDE_CONSTRUCTION_SELECT_SEAT_ROTATION_ANGLE_TIP }, + { WWT_DROPDOWN_BUTTON, 1, 147, 157, 144, 148, STR_NUMERIC_DOWN, STR_RIDE_CONSTRUCTION_SELECT_SEAT_ROTATION_ANGLE_TIP }, + { WIDGETS_END } }; +#pragma endregion + +#pragma region Events + +static void window_ride_construction_close(rct_window *w); +static void window_ride_construction_mouseup(rct_window *w, int widgetIndex); +static void window_ride_construction_resize(rct_window *w); +static void window_ride_construction_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_ride_construction_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); +static void window_ride_construction_update(rct_window *w); +static void window_ride_construction_toolupdate(rct_window* w, int widgetIndex, int x, int y); +static void window_ride_construction_tooldown(rct_window* w, int widgetIndex, int x, int y); +static void window_ride_construction_invalidate(rct_window *w); +static void window_ride_construction_paint(rct_window *w, rct_drawpixelinfo *dpi); + //0x993EEC -static void* window_construction_events[] = { - window_construction_close, - window_construction_mouseup, - (void*)0x6C7934, - (void*)0x6C6E6A, - (void*)0x6C78CD, - window_construction_emptysub, - (void*)0x6C8374, - window_construction_emptysub, - window_construction_emptysub, - (void*)0x6C8229, - (void*)0x6C8248, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - window_construction_emptysub, - (void*)0x6C6AD5, - window_construction_paint,//(void*)0x6C6B86, - window_construction_emptysub +static rct_window_event_list window_ride_construction_events = { + window_ride_construction_close, + window_ride_construction_mouseup, + window_ride_construction_resize, + window_ride_construction_mousedown, + window_ride_construction_dropdown, + NULL, + window_ride_construction_update, + NULL, + NULL, + window_ride_construction_toolupdate, + window_ride_construction_tooldown, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_ride_construction_invalidate, + window_ride_construction_paint, + NULL }; +#pragma endregion + +#pragma region RideConfigurationStringIds + +// rct2: 0x00999492 +rct_string_id RideConfigurationStringIds[] = { + 0, // 0 + STR_STATION_PLATFORM, // 1 + 0, // 2 + 0, // 3 + 0, // 4 + 0, // 5 + 0, // 6 + 0, // 7 + 0, // 8 + 0, // 9 + 0, // 10 + 0, // 11 + 0, // 12 + 0, // 13 + 0, // 14 + 0, // 15 + 0, // 16 + 0, // 17 + 0, // 18 + 0, // 19 + 0, // 20 + 0, // 21 + 0, // 22 + 0, // 23 + 0, // 24 + 0, // 25 + 0, // 26 + 0, // 27 + 0, // 28 + 0, // 29 + 0, // 30 + 0, // 31 + 0, // 32 + 0, // 33 + 0, // 34 + 0, // 35 + 0, // 36 + 0, // 37 + STR_S_BEND_LEFT, // 38 + STR_S_BEND_RIGHT, // 39 + STR_VERTICAL_LOOP_LEFT, // 40 + STR_VERTICAL_LOOP_RIGHT, // 41 + 0, // 42 + 0, // 43 + 0, // 44 + 0, // 45 + 0, // 46 + 0, // 47 + 0, // 48 + 0, // 49 + 0, // 50 + 0, // 51 + STR_IN_LINE_TWIST_LEFT, // 52 + STR_IN_LINE_TWIST_RIGHT, // 53 + STR_IN_LINE_TWIST_LEFT, // 54 + STR_IN_LINE_TWIST_RIGHT, // 55 + STR_HALF_LOOP, // 56 + STR_HALF_LOOP, // 57 + STR_HALF_CORKSCREW_LEFT, // 58 + STR_HALF_CORKSCREW_RIGHT, // 59 + STR_HALF_CORKSCREW_LEFT, // 60 + STR_HALF_CORKSCREW_RIGHT, // 61 + 0, // 62 + 0, // 63 + 0, // 64 + 0, // 65 + STR_ENTRY_EXIT_PLATFORM, // 66 + STR_VERTICAL_TOWER, // 67 + 0, // 68 + 0, // 69 + 0, // 70 + 0, // 71 + 0, // 72 + 0, // 73 + 0, // 74 + 0, // 75 + 0, // 76 + 0, // 77 + 0, // 78 + 0, // 79 + 0, // 80 + 0, // 81 + 0, // 82 + STR_S_BEND_LEFT, // 83 + STR_S_BEND_RIGHT, // 84 + 0, // 85 + 0, // 86 + STR_HELIX_UP_SMALL, // 87 + STR_HELIX_UP_SMALL, // 88 + STR_HELIX_DOWN_SMALL, // 89 + STR_HELIX_DOWN_SMALL, // 90 + STR_HELIX_UP_LARGE, // 91 + STR_HELIX_UP_LARGE, // 92 + STR_HELIX_DOWN_LARGE, // 93 + STR_HELIX_DOWN_LARGE, // 94 + 0, // 95 + 0, // 96 + 0, // 97 + 0, // 98 + STR_BRAKES, // 99 + STR_SPINNING_CONTROL_TOGGLE_TRACK, // 100 + 0, // 101 + STR_HELIX_UP_LARGE, // 102 + STR_HELIX_UP_LARGE, // 103 + STR_HELIX_DOWN_LARGE, // 104 + STR_HELIX_DOWN_LARGE, // 105 + STR_HELIX_UP_LEFT, // 106 + STR_HELIX_UP_RIGHT, // 107 + STR_HELIX_DOWN_LEFT, // 108 + STR_HELIX_DOWN_RIGHT, // 109 + STR_BASE_SIZE_2_X_2, // 110 + STR_BASE_SIZE_4_X_4, // 111 + STR_WATERFALLS, // 112 + STR_RAPIDS, // 113 + STR_ON_RIDE_PHOTO_SECTION, // 114 + STR_BASE_SIZE_2_X_4, // 115 + STR_BASE_SIZE_5_X_1, // 116 + STR_WATER_SPLASH, // 117 + 0, // 118 + 0, // 119 + STR_WHIRLPOOL, // 120 + 0, // 121 + 0, // 122 + STR_CABLE_LIFT_HILL, // 123 + STR_SLOPE_UP_TO_VERTICAL, // 124 + STR_VERTICAL_TRACK, // 125 + 0, // 126 + 0, // 127 + 0, // 128 + 0, // 129 + 0, // 130 + 0, // 131 + STR_HOLDING_BRAKE_FOR_DROP, // 132 + 0, // 133 + 0, // 134 + 0, // 135 + 0, // 136 + 0, // 137 + 0, // 138 + 0, // 139 + 0, // 140 + 0, // 141 + 0, // 142 + 0, // 143 + 0, // 144 + 0, // 145 + 0, // 146 + 0, // 147 + 0, // 148 + 0, // 149 + 0, // 150 + 0, // 151 + 0, // 152 + 0, // 153 + 0, // 154 + 0, // 155 + 0, // 156 + 0, // 157 + 0, // 158 + 0, // 159 + 0, // 160 + 0, // 161 + 0, // 162 + 0, // 163 + 0, // 164 + 0, // 165 + 0, // 166 + 0, // 167 + 0, // 168 + 0, // 169 + 0, // 170 + 0, // 171 + STR_REVERSER_TURNTABLE, // 172 + STR_SPINNING_TUNNEL, // 173 + STR_BARREL_ROLL_LEFT, // 174 + STR_BARREL_ROLL_RIGHT, // 175 + STR_BARREL_ROLL_LEFT, // 176 + STR_BARREL_ROLL_RIGHT, // 177 + 0, // 178 + 0, // 179 + 0, // 180 + 0, // 181 + STR_LAUNCHED_LIFT_HILL, // 182 + STR_LARGE_HALF_LOOP_LEFT, // 183 + STR_LARGE_HALF_LOOP_RIGHT, // 184 + STR_LARGE_HALF_LOOP_LEFT, // 185 + STR_LARGE_HALF_LOOP_RIGHT, // 186 + STR_IN_LINE_TWIST_LEFT, // 187 + STR_IN_LINE_TWIST_RIGHT, // 188 + STR_IN_LINE_TWIST_LEFT, // 189 + STR_IN_LINE_TWIST_RIGHT, // 190 + STR_HALF_LOOP, // 191 + STR_HALF_LOOP, // 192 + STR_HALF_CORKSCREW_LEFT, // 193 + STR_HALF_CORKSCREW_RIGHT, // 194 + STR_HALF_CORKSCREW_LEFT, // 195 + STR_HALF_CORKSCREW_RIGHT, // 196 + STR_UPPER_TRANSFER, // 197 + STR_LOWER_TRANSFER, // 198 + STR_HEARTLINE_ROLL_LEFT, // 199 + STR_HEARTLINE_ROLL_RIGHT, // 200 + STR_GOLF_HOLE_A, // 201 + STR_GOLF_HOLE_B, // 202 + STR_GOLF_HOLE_C, // 203 + STR_GOLF_HOLE_D, // 204 + STR_GOLF_HOLE_E, // 205 + STR_QUARTER_LOOP, // 206 + STR_QUARTER_LOOP, // 207 + STR_QUARTER_LOOP, // 208 + STR_CURVED_LIFT_HILL_LEFT, // 209 + STR_CURVED_LIFT_HILL_RIGHT, // 210 + STR_REVERSER_LEFT, // 211 + STR_REVERSER_RIGHT, // 212 + STR_TOP_SECTION, // 213 + STR_VERTICAL_TRACK, // 214 + STR_SLOPE_TO_LEVEL, // 215 + STR_BLOCK_BRAKES, // 216 + 0, // 217 + 0, // 218 + 0, // 219 + 0, // 220 + 0, // 221 + 0, // 222 + 0, // 223 + 0, // 224 + 0, // 225 + 0, // 226 + 0, // 227 + 0, // 228 + 0, // 229 + 0, // 230 + 0, // 231 + 0, // 232 + 0, // 233 + 0, // 234 + 0, // 235 + 0, // 236 + 0, // 237 + 0, // 238 + 0, // 239 + 0, // 240 + 0, // 241 + 0, // 242 + 0, // 243 + 0, // 244 + 0, // 245 + 0, // 246 + 0, // 247 + 0, // 248 + 0, // 249 + 0, // 250 + 0, // 251 + 0, // 252 + STR_QUARTER_LOOP, // 253 + STR_QUARTER_LOOP, // 254 + STR_QUARTER_LOOP // 255 +}; + +#pragma endregion + +#define _trackPlaceCtrlState RCT2_GLOBAL(0x00F44159, uint8) +static int _trackPlaceCtrlZ; +#define _trackPlaceShiftState RCT2_GLOBAL(0x00F4415C, uint8) +static int _trackPlaceShiftStartScreenX; +static int _trackPlaceShiftStartScreenY; +static int _trackPlaceShiftZ; +#define _trackPlaceZ RCT2_GLOBAL(0x00F44163, sint16) + +static void window_ride_construction_next_section(rct_window *w); +static void window_ride_construction_previous_section(rct_window *w); +static void window_ride_construction_construct(rct_window *w); +static void window_ride_construction_mouseup_demolish(rct_window* w); +static void window_ride_construction_rotate(rct_window *w); +static void window_ride_construction_entrance_click(rct_window *w); +static void window_ride_construction_exit_click(rct_window *w); + +static void window_ride_construction_draw_track_piece( + rct_window *w, rct_drawpixelinfo *dpi, + int rideIndex, int trackType, int trackRotation, int unknown, + int width, int height +); +static void window_ride_construction_update_enabled_track_pieces(); +static bool sub_6CA2DF(int *trackType, int *trackDirection, int *rideIndex, int *edxRS16, int *x, int *y, int *z, int *properties); +static void sub_6CBCE2( + int rideIndex, int trackType, int trackDirection, int edx, + int originX, int originY, int originZ +); +static void window_ride_construction_update_map_selection(); +static void window_ride_construction_update_possible_ride_configurations(); +static void window_ride_construction_update_widgets(rct_window *w); +static void window_ride_construction_select_map_tiles(rct_ride *ride, int trackType, int trackDirection, int x, int y); +money32 sub_6CA162(int rideIndex, int trackType, int trackDirection, int edxRS16, int x, int y, int z); +static void window_ride_construction_show_special_track_dropdown(rct_window *w, rct_widget *widget); +static void ride_selected_track_set_seat_rotation(int seatRotation); +static void loc_6C7502(int al); +static void ride_construction_set_brakes_speed(int brakesSpeed); +static void ride_construction_tooldown_entrance_exit(int screenX, int screenY); + +uint8 *_currentPossibleRideConfigurations = (uint8*)0x00F4407C; + +static bool is_track_enabled(int trackFlagIndex) +{ + return _enabledRidePieces & (1ULL << trackFlagIndex); +} + +static int ride_get_alternative_type(rct_ride *ride) +{ + return _currentTrackCovered & 2 ? + RCT2_ADDRESS(0x0097D4F5, uint8)[ride->type * 8] : + ride->type;; +} + /** * * rct2: 0x006CB481 */ -rct_window *window_construction_open() +rct_window *window_ride_construction_open() { - int ride_id = RCT2_GLOBAL(0xF440A7, uint8); - sub_6b2fa9(ride_id); + int rideIndex = _currentRideIndex; + sub_6B2FA9(rideIndex); rct_window *w; - rct_ride* ride = GET_RIDE(ride_id); - if (ride->type == RIDE_TYPE_MAZE){ - w = window_create(0, 29, 166, 200, (uint32*)window_construction_maze_events, WC_RIDE_CONSTRUCTION, WF_9); + rct_ride* ride = GET_RIDE(rideIndex); - w->widgets = (rct_widget*)0x9D7D04; - w->enabled_widgets = 0x6F0001C4; + if (ride->type == RIDE_TYPE_MAZE) + return window_maze_construction_open(); - window_init_scroll_widgets(w); + w = window_create(0, 29, 166, 394, &window_ride_construction_events, WC_RIDE_CONSTRUCTION, WF_NO_AUTO_CLOSE); - colour_scheme_update(w); - - w->number = ride_id; - - window_push_others_right(w); - show_gridlines(); - return w; - } - - w = window_create(0, 29, 166, 394, (uint32*)window_construction_events, WC_RIDE_CONSTRUCTION, WF_9); - - w->widgets = (rct_widget*)0x9D7A90; + w->widgets = window_ride_construction_widgets; w->enabled_widgets = 0x67EFFFFFC4; window_init_scroll_widgets(w); @@ -159,54 +522,52 @@ rct_window *window_construction_open() w->colours[1] = 24; w->colours[2] = 24; - w->number = ride_id; + w->number = rideIndex; window_push_others_right(w); show_gridlines(); - RCT2_GLOBAL(0xF44070, uint32) = MONEY32_UNDEFINED; - RCT2_GLOBAL(0xF440CD, uint8) = 8; - RCT2_GLOBAL(0xF440CE, uint8) = 18; - RCT2_GLOBAL(0xF440CF, uint8) = 4; + _currentTrackPrice = MONEY32_UNDEFINED; + RCT2_GLOBAL(0x00F440CD, uint8) = 8; + RCT2_GLOBAL(0x00F440CE, uint8) = 18; + RCT2_GLOBAL(0x00F440CF, uint8) = 4; - if (ride->type == RIDE_TYPE_REVERSE_FREEFALL_COASTER){ - RCT2_GLOBAL(0xF440CE, uint8) = 30; - } + if (ride->type == RIDE_TYPE_REVERSE_FREEFALL_COASTER) + RCT2_GLOBAL(0x00F440CE, uint8) = 30; - if (ride->type == RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER){ - RCT2_GLOBAL(0xF440CE, uint8) = 30; - } + if (ride->type == RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER) + RCT2_GLOBAL(0x00F440CE, uint8) = 30; - RCT2_GLOBAL(0xF440A0, uint16) = RCT2_ADDRESS(0x0097CC68, uint8)[ride->type * 2] | 0x100; - RCT2_GLOBAL(0x00F440B2, uint8) = 0; + _currentTrackCurve = RCT2_ADDRESS(0x0097CC68, uint8)[ride->type * 2] | 0x100; + _currentTrackSlopeEnd = 0; RCT2_GLOBAL(0x00F440B3, uint8) = 0; - RCT2_GLOBAL(0x00F440B4, uint8) = 0; - RCT2_GLOBAL(0x00F440B5, uint8) = 0; + _currentTrackLiftHill = 0; + _currentTrackCovered = 0; - if (RCT2_ADDRESS(0x0097D4F2, uint16)[ride->type * 4] & 0x8000) - RCT2_GLOBAL(0x00F440B5, uint8) |= 2; + if (RideData4[ride->type].flags & RIDE_TYPE_FLAG4_15) + _currentTrackCovered |= 2; RCT2_GLOBAL(0x00F440B6, uint8) = 0; RCT2_GLOBAL(0x00F440B7, 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; + _rideConstructionState = RIDE_CONSTRUCTION_STATE_PLACE; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; RCT2_GLOBAL(0x00F44159, uint8) = 0; RCT2_GLOBAL(0x00F4415C, uint8) = 0; colour_scheme_update(w); return w; } -/* rct2: 0x006C845D */ -void window_construction_close() +/** + * + * rct2: 0x006C845D + */ +static void window_ride_construction_close(rct_window *w) { - rct_window *w; rct_xy_element mapElement; - window_get_register(w); - sub_6C9627(); viewport_set_visibility(0); @@ -214,246 +575,3128 @@ void window_construction_close() 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(); + // selection tool should be cancelled. Don't do a tool cancel if + // another window has already taken control of tool. + if (w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) && + w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber)) + tool_cancel(); hide_gridlines(); - uint8 rideIndex = RCT2_GLOBAL(0x00F440A7, uint8); - if (!sub_6CAF80(rideIndex, &mapElement)) { + uint8 rideIndex = _currentRideIndex; + if (sub_6CAF80(rideIndex, &mapElement) || network_get_mode() == NETWORK_MODE_CLIENT) { + window_ride_main_open(rideIndex); + } else { int eax = RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8); RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) = 0; - game_do_command(0, 9, 0, rideIndex, GAME_COMMAND_7, 0, 0); + game_do_command(0, 9, 0, rideIndex, GAME_COMMAND_DEMOLISH_RIDE, 0, 0); RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) = eax; - return; } - - window_ride_main_open(rideIndex); } - -void window_construction_maze_close(){ - rct_window *w; - - window_get_register(w); - - sub_6C9627(); - viewport_set_visibility(0); - - 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(RCT2_ADDRESS_GAME_PAUSED, uint8); - - RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) = 0; - game_do_command(0, 9, 0, ride_id, GAME_COMMAND_7, 0, 0); - - 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); - +/** + * + * rct2: 0x006C6E14 + */ +static void window_ride_construction_mouseup(rct_window *w, int widgetIndex) +{ + window_ride_construction_update_enabled_track_pieces(); switch (widgetIndex){ case WIDX_CLOSE: window_close(w); break; - case 27: - RCT2_CALLPROC_X(0x6C9296, 0, 0, 0, widgetIndex, (int)w, 0, 0); + case WIDX_NEXT_SECTION: + ride_select_next_section(); break; - case 26: - RCT2_CALLPROC_X(0x6C93B8, 0, 0, 0, widgetIndex, (int)w, 0, 0); + case WIDX_PREVIOUS_SECTION: + ride_select_previous_section(); break; - case 23: - RCT2_CALLPROC_X(0x6C9F72, 0, 0, 0, widgetIndex, (int)w, 0, 0); + case WIDX_CONSTRUCT: + window_ride_construction_construct(w); + // Force any footpath construction to recheck the area. + RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) |= (1 << 2); break; case WIDX_DEMOLISH: - window_construction_mouseup_demolish(w); + window_ride_construction_mouseup_demolish(w); break; - case 32: - RCT2_CALLPROC_X(0x6C78AA, 0, 0, 0, widgetIndex, (int)w, 0, 0); + case WIDX_ROTATE: + window_ride_construction_rotate(w); break; - case 29: - RCT2_CALLPROC_X(0x6C7802, 0, 0, 0, widgetIndex, (int)w, 0, 0); + case WIDX_ENTRANCE: + window_ride_construction_entrance_click(w); break; - case 30: - RCT2_CALLPROC_X(0x6C7866, 0, 0, 0, widgetIndex, (int)w, 0, 0); + case WIDX_EXIT: + window_ride_construction_exit_click(w); 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: 0x006C7934 + */ +static void window_ride_construction_resize(rct_window *w) +{ + window_ride_construction_update_enabled_track_pieces(); + w->enabled_widgets &= ~(1 << WIDX_CONSTRUCT); + if (_rideConstructionState != RIDE_CONSTRUCTION_STATE_PLACE) { + w->enabled_widgets |= (1 << WIDX_CONSTRUCT); + } - RCT2_GLOBAL(0xF44070, uint32) = MONEY32_UNDEFINED; + rct_ride *ride = GET_RIDE(_currentRideIndex); + int rideType = ride_get_alternative_type(ride); + + uint64 disabledWidgets = 0; + + if (_currentTrackCurve >= 256) { + disabledWidgets |= + (1ULL << WIDX_SLOPE_GROUPBOX) | + (1ULL << WIDX_BANKING_GROUPBOX) | + (1ULL << WIDX_SLOPE_DOWN_STEEP) | + (1ULL << WIDX_SLOPE_DOWN) | + (1ULL << WIDX_LEVEL) | + (1ULL << WIDX_SLOPE_UP) | + (1ULL << WIDX_SLOPE_UP_STEEP) | + (1ULL << WIDX_CHAIN_LIFT) | + (1ULL << WIDX_BANK_LEFT) | + (1ULL << WIDX_BANK_STRAIGHT) | + (1ULL << WIDX_BANK_RIGHT); + } + + // Disable large curves if the start or end of the track is sloped. + if (_previousTrackSlopeEnd != TRACK_SLOPE_NONE || _currentTrackSlopeEnd != TRACK_SLOPE_NONE) { + disabledWidgets |= + (1ULL << WIDX_LEFT_CURVE_LARGE) | + (1ULL << WIDX_RIGHT_CURVE_LARGE); + } + if (is_track_enabled(TRACK_SLOPE_CURVE) && is_track_enabled(TRACK_CURVE_VERY_SMALL)) { + // Disable small curves if the start or end of the track is sloped. + if (_previousTrackSlopeEnd != TRACK_SLOPE_NONE || _currentTrackSlopeEnd != TRACK_SLOPE_NONE) { + disabledWidgets |= + (1ULL << WIDX_LEFT_CURVE_VERY_SMALL) | + (1ULL << WIDX_LEFT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE_VERY_SMALL); + } + } + if (!is_track_enabled(TRACK_SLOPE_CURVE)) { + if (is_track_enabled(TRACK_CURVE_VERTICAL)) { + // Disable all curves only on vertical track + if (_previousTrackSlopeEnd != TRACK_SLOPE_UP_90 || _currentTrackSlopeEnd != TRACK_SLOPE_UP_90) { + if (_previousTrackSlopeEnd != TRACK_SLOPE_DOWN_90 || _currentTrackSlopeEnd != TRACK_SLOPE_DOWN_90) { + disabledWidgets |= + (1ULL << WIDX_LEFT_CURVE_VERY_SMALL) | + (1ULL << WIDX_LEFT_CURVE_SMALL) | + (1ULL << WIDX_LEFT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE_SMALL) | + (1ULL << WIDX_RIGHT_CURVE_VERY_SMALL); + } + } + } else { + // Disable all curves on sloped track + if (_previousTrackSlopeEnd != TRACK_SLOPE_NONE || _currentTrackSlopeEnd != TRACK_SLOPE_NONE) { + disabledWidgets |= + (1ULL << WIDX_LEFT_CURVE_VERY_SMALL) | + (1ULL << WIDX_LEFT_CURVE_SMALL) | + (1ULL << WIDX_LEFT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE_SMALL) | + (1ULL << WIDX_RIGHT_CURVE_VERY_SMALL); + } + } + } + if (!is_track_enabled(TRACK_FLAT_ROLL_BANKING)) { + // Disable banking + disabledWidgets |= + (1ULL << WIDX_BANKING_GROUPBOX) | + (1ULL << WIDX_BANK_LEFT) | + (1ULL << WIDX_BANK_STRAIGHT) | + (1ULL << WIDX_BANK_RIGHT); + } + if (!is_track_enabled(TRACK_SLOPE) && !is_track_enabled(TRACK_SLOPE_STEEP)) { + if (rideType != RIDE_TYPE_REVERSE_FREEFALL_COASTER && rideType != RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER) { + // Disable all slopes + disabledWidgets |= + (1ULL << WIDX_SLOPE_GROUPBOX) | + (1ULL << WIDX_SLOPE_DOWN_STEEP) | + (1ULL << WIDX_SLOPE_DOWN) | + (1ULL << WIDX_LEVEL) | + (1ULL << WIDX_SLOPE_UP) | + (1ULL << WIDX_SLOPE_UP_STEEP); + } + } + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_0) { + disabledWidgets |= + (1ULL << WIDX_CONSTRUCT) | + (1ULL << WIDX_DEMOLISH) | + (1ULL << WIDX_PREVIOUS_SECTION) | + (1ULL << WIDX_NEXT_SECTION); + } + switch (_currentTrackCurve) { + case TRACK_CURVE_LEFT_VERY_SMALL: + case TRACK_CURVE_LEFT_SMALL: + case TRACK_CURVE_LEFT: + case TRACK_CURVE_LEFT_LARGE: + disabledWidgets |= (1ULL << WIDX_BANK_RIGHT); + if (_previousTrackBankEnd == TRACK_BANK_NONE) { + disabledWidgets |= (1ULL << WIDX_BANK_LEFT); + } else { + disabledWidgets |= (1ULL << WIDX_BANK_STRAIGHT); + } + break; + case TRACK_CURVE_RIGHT_LARGE: + case TRACK_CURVE_RIGHT: + case TRACK_CURVE_RIGHT_SMALL: + case TRACK_CURVE_RIGHT_VERY_SMALL: + disabledWidgets |= (1ULL << WIDX_BANK_LEFT); + if (_previousTrackBankEnd == TRACK_BANK_NONE) { + disabledWidgets |= (1ULL << WIDX_BANK_RIGHT); + } else { + disabledWidgets |= (1ULL << WIDX_BANK_STRAIGHT); + } + break; + } + if (!is_track_enabled(TRACK_SLOPE_ROLL_BANKING)) { + if (_currentTrackBankEnd != TRACK_BANK_NONE) { + disabledWidgets |= + (1ULL << WIDX_SLOPE_DOWN) | + (1ULL << WIDX_SLOPE_UP); + } + } + if (_previousTrackSlopeEnd == _currentTrackSlopeEnd) { + switch (_currentTrackSlopeEnd) { + case TRACK_SLOPE_UP_60: + case TRACK_SLOPE_DOWN_60: + disabledWidgets |= + (1ULL << WIDX_LEFT_CURVE_VERY_SMALL) | + (1ULL << WIDX_LEFT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE_VERY_SMALL); + if (!is_track_enabled(TRACK_SLOPE_CURVE_STEEP)) { + disabledWidgets |= + (1ULL << WIDX_LEFT_CURVE_SMALL) | + (1ULL << WIDX_RIGHT_CURVE_SMALL); + } + break; + case TRACK_SLOPE_UP_90: + case TRACK_SLOPE_DOWN_90: + disabledWidgets |= + (1ULL << WIDX_LEFT_CURVE_VERY_SMALL) | + (1ULL << WIDX_LEFT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE_VERY_SMALL); + if (!is_track_enabled(TRACK_CURVE_VERTICAL)) { + disabledWidgets |= + (1ULL << WIDX_LEFT_CURVE_SMALL) | + (1ULL << WIDX_RIGHT_CURVE_SMALL); + } + break; + } + } else { + // Disable all curves + disabledWidgets |= + (1ULL << WIDX_LEFT_CURVE_VERY_SMALL) | + (1ULL << WIDX_LEFT_CURVE_SMALL) | + (1ULL << WIDX_LEFT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE_SMALL) | + (1ULL << WIDX_RIGHT_CURVE_VERY_SMALL); + } + + switch (_previousTrackSlopeEnd) { + case TRACK_SLOPE_NONE: + if (_currentTrackCurve != TRACK_CURVE_NONE) { + disabledWidgets |= + (1ULL << WIDX_SLOPE_DOWN_STEEP) | + (1ULL << WIDX_SLOPE_UP_STEEP); + } + break; + case TRACK_SLOPE_DOWN_25: + disabledWidgets |= + (1ULL << WIDX_SLOPE_UP) | + (1ULL << WIDX_SLOPE_UP_STEEP); + break; + case TRACK_SLOPE_DOWN_60: + disabledWidgets |= + (1ULL << WIDX_SLOPE_UP) | + (1ULL << WIDX_SLOPE_UP_STEEP); + if (!is_track_enabled(TRACK_SLOPE_LONG) && !is_track_enabled(TRACK_SLOPE_STEEP_LONG)) { + disabledWidgets |= (1ULL << WIDX_LEVEL); + } + break; + case TRACK_SLOPE_UP_25: + disabledWidgets |= + (1ULL << WIDX_SLOPE_DOWN_STEEP) | + (1ULL << WIDX_SLOPE_DOWN); + break; + case TRACK_SLOPE_UP_60: + disabledWidgets |= + (1ULL << WIDX_SLOPE_DOWN_STEEP) | + (1ULL << WIDX_SLOPE_DOWN); + if (!is_track_enabled(TRACK_SLOPE_LONG) && !is_track_enabled(TRACK_SLOPE_STEEP_LONG)) { + disabledWidgets |= (1ULL << WIDX_LEVEL); + } + break; + case TRACK_SLOPE_DOWN_90: + case TRACK_SLOPE_UP_90: + disabledWidgets |= + (1ULL << WIDX_SLOPE_DOWN) | + (1ULL << WIDX_LEVEL) | + (1ULL << WIDX_SLOPE_UP); + break; + } + if (_previousTrackSlopeEnd == TRACK_SLOPE_NONE) { + if (!is_track_enabled(TRACK_SLOPE_LONG) && !is_track_enabled(TRACK_SLOPE_STEEP_LONG)) { + disabledWidgets |= + (1ULL << WIDX_SLOPE_DOWN_STEEP) | + (1ULL << WIDX_SLOPE_UP_STEEP); + } + } + if (is_track_enabled(TRACK_SLOPE_VERTICAL)) { + if (_previousTrackSlopeEnd == TRACK_SLOPE_UP_60 && _currentTrackPieceDirection < 4) { + disabledWidgets &= ~(1ULL << WIDX_SLOPE_DOWN_STEEP); + } + if (_previousTrackSlopeEnd == TRACK_SLOPE_UP_90) { + disabledWidgets &= ~(1ULL << WIDX_SLOPE_DOWN_STEEP); + } + if (_previousTrackSlopeEnd == TRACK_SLOPE_DOWN_60 && _currentTrackPieceDirection < 4) { + disabledWidgets &= ~(1ULL << WIDX_SLOPE_UP_STEEP); + } + } + if (_previousTrackBankEnd == TRACK_BANK_LEFT) { + disabledWidgets |= + (1ULL << WIDX_RIGHT_CURVE_SMALL) | + (1ULL << WIDX_RIGHT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE_LARGE) | + (1ULL << WIDX_BANK_RIGHT); + } + if (_previousTrackBankEnd == TRACK_BANK_RIGHT) { + disabledWidgets |= + (1ULL << WIDX_LEFT_CURVE_SMALL) | + (1ULL << WIDX_LEFT_CURVE) | + (1ULL << WIDX_LEFT_CURVE_LARGE) | + (1ULL << WIDX_BANK_LEFT); + } + if (_currentTrackBankEnd != _previousTrackBankEnd) { + disabledWidgets |= + (1ULL << WIDX_RIGHT_CURVE_SMALL) | + (1ULL << WIDX_RIGHT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE_LARGE) | + (1ULL << WIDX_LEFT_CURVE_SMALL) | + (1ULL << WIDX_LEFT_CURVE) | + (1ULL << WIDX_LEFT_CURVE_LARGE); + } + if (_currentTrackSlopeEnd != TRACK_SLOPE_NONE) { + if (is_track_enabled(TRACK_SLOPE_ROLL_BANKING)) { + if (_previousTrackSlopeEnd == TRACK_SLOPE_NONE) { + if (_currentTrackSlopeEnd != TRACK_SLOPE_UP_25 && _currentTrackSlopeEnd != TRACK_SLOPE_DOWN_25) { + disabledWidgets |= + (1ULL << WIDX_BANK_LEFT) | + (1ULL << WIDX_BANK_RIGHT); + } + } else { + if (_currentTrackSlopeEnd != _previousTrackSlopeEnd) { + disabledWidgets |= + (1ULL << WIDX_BANK_LEFT) | + (1ULL << WIDX_BANK_RIGHT); + } else { + if (_currentTrackSlopeEnd != TRACK_SLOPE_UP_25 && _currentTrackSlopeEnd != TRACK_SLOPE_DOWN_25) { + disabledWidgets |= + (1ULL << WIDX_BANK_LEFT) | + (1ULL << WIDX_BANK_RIGHT); + } + } + } + } else { + disabledWidgets |= + (1ULL << WIDX_BANK_LEFT) | + (1ULL << WIDX_BANK_RIGHT); + } + } + if (_currentTrackBankEnd != TRACK_BANK_NONE || _previousTrackBankEnd != TRACK_BANK_NONE) { + disabledWidgets |= + (1ULL << WIDX_SLOPE_DOWN_STEEP) | + (1ULL << WIDX_SLOPE_UP_STEEP) | + (1ULL << WIDX_CHAIN_LIFT); + } + if (_currentTrackCurve != TRACK_CURVE_NONE) { + if (!is_track_enabled(TRACK_LIFT_HILL_CURVE)) { + disabledWidgets |= (1ULL << WIDX_CHAIN_LIFT); + } + if (_currentTrackSlopeEnd == TRACK_SLOPE_NONE) { + disabledWidgets |= (1ULL << WIDX_CHAIN_LIFT); + } + if (_currentTrackSlopeEnd == TRACK_SLOPE_UP_60) { + disabledWidgets |= (1ULL << WIDX_CHAIN_LIFT); + } + if (_currentTrackSlopeEnd == TRACK_SLOPE_DOWN_60) { + disabledWidgets |= (1ULL << WIDX_CHAIN_LIFT); + } + } + if (_currentTrackSlopeEnd == TRACK_SLOPE_UP_90 || _previousTrackSlopeEnd == TRACK_SLOPE_UP_90) { + disabledWidgets |= (1ULL << WIDX_CHAIN_LIFT); + } + if (_previousTrackBankEnd == TRACK_BANK_UPSIDE_DOWN) { + disabledWidgets |= + (1ULL << WIDX_LEFT_CURVE_SMALL) | + (1ULL << WIDX_LEFT_CURVE) | + (1ULL << WIDX_LEFT_CURVE_LARGE) | + (1ULL << WIDX_STRAIGHT) | + (1ULL << WIDX_RIGHT_CURVE_SMALL) | + (1ULL << WIDX_RIGHT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE_LARGE); + } + if (_currentTrackCurve != TRACK_CURVE_NONE) { + if (_currentTrackSlopeEnd == TRACK_SLOPE_NONE) { + disabledWidgets |= + (1ULL << WIDX_SLOPE_DOWN) | + (1ULL << WIDX_SLOPE_UP); + } + if (_currentTrackSlopeEnd == _previousTrackSlopeEnd) { + if (_currentTrackSlopeEnd == TRACK_SLOPE_UP_25) { + disabledWidgets |= (1ULL << WIDX_SLOPE_UP_STEEP); + if (_currentTrackCurve == TRACK_CURVE_LEFT_SMALL || _currentTrackCurve == TRACK_CURVE_RIGHT_SMALL || _rideConstructionState != RIDE_CONSTRUCTION_STATE_BACK || !is_track_enabled(TRACK_SLOPE_CURVE_BANKED)) { + disabledWidgets |= (1ULL << WIDX_LEVEL); + } + } + if (_currentTrackSlopeEnd == TRACK_SLOPE_DOWN_25) { + disabledWidgets |= (1ULL << WIDX_SLOPE_DOWN_STEEP); + if (_currentTrackCurve == TRACK_CURVE_LEFT_SMALL || _currentTrackCurve == TRACK_CURVE_RIGHT_SMALL || _rideConstructionState != RIDE_CONSTRUCTION_STATE_FRONT || !is_track_enabled(TRACK_SLOPE_CURVE_BANKED)) { + disabledWidgets |= (1ULL << WIDX_LEVEL); + } + } + } else if (is_track_enabled(TRACK_SLOPE_CURVE_BANKED)) { + disabledWidgets |= + (1ULL << WIDX_SLOPE_DOWN_STEEP) | + (1ULL << WIDX_SLOPE_UP_STEEP); + if (_currentTrackBankEnd == TRACK_BANK_LEFT) { + disabledWidgets |= + (1ULL << WIDX_BANK_STRAIGHT) | + (1ULL << WIDX_BANK_RIGHT); + disabledWidgets &= ~(1ULL << WIDX_BANK_LEFT); + } + if (_currentTrackBankEnd == TRACK_BANK_RIGHT) { + disabledWidgets |= + (1ULL << WIDX_BANK_LEFT) | + (1ULL << WIDX_BANK_STRAIGHT); + disabledWidgets &= ~(1ULL << WIDX_BANK_RIGHT); + } + if (_currentTrackBankEnd == TRACK_BANK_NONE) { + disabledWidgets |= + (1ULL << WIDX_BANK_LEFT) | + (1ULL << WIDX_BANK_RIGHT); + disabledWidgets &= ~(1ULL << WIDX_BANK_STRAIGHT); + } + if (_currentTrackSlopeEnd == TRACK_SLOPE_NONE) { + disabledWidgets |= + (1ULL << WIDX_SLOPE_DOWN) | + (1ULL << WIDX_SLOPE_UP); + disabledWidgets &= ~(1ULL << WIDX_LEVEL); + } + if (_currentTrackSlopeEnd == TRACK_SLOPE_UP_25) { + disabledWidgets |= + (1ULL << WIDX_SLOPE_DOWN) | + (1ULL << WIDX_LEVEL); + disabledWidgets &= ~(1ULL << WIDX_SLOPE_UP); + } + if (_currentTrackSlopeEnd == TRACK_SLOPE_DOWN_25) { + disabledWidgets |= + (1ULL << WIDX_LEVEL) | + (1ULL << WIDX_SLOPE_UP); + disabledWidgets &= ~(1ULL << WIDX_SLOPE_DOWN); + } + if (_currentTrackCurve == TRACK_CURVE_LEFT_SMALL) { + disabledWidgets &= ~(1ULL << WIDX_LEFT_CURVE_SMALL); + } + if (_currentTrackCurve == TRACK_CURVE_RIGHT_SMALL) { + disabledWidgets &= ~(1ULL << WIDX_RIGHT_CURVE_SMALL); + } + } + } + if (_currentTrackCurve != TRACK_CURVE_NONE && _currentTrackSlopeEnd == TRACK_SLOPE_UP_60) { + disabledWidgets |= (1ULL << WIDX_SLOPE_UP); + } + if (_currentTrackCurve != TRACK_CURVE_NONE && _currentTrackSlopeEnd == TRACK_SLOPE_DOWN_60) { + disabledWidgets |= (1ULL << WIDX_SLOPE_DOWN); + } + if (_currentTrackLiftHill & 1) { + if (_currentTrackSlopeEnd != TRACK_SLOPE_NONE && !is_track_enabled(TRACK_LIFT_HILL_CURVE)) { + disabledWidgets |= + (1ULL << WIDX_LEFT_CURVE_SMALL) | + (1ULL << WIDX_LEFT_CURVE) | + (1ULL << WIDX_LEFT_CURVE_LARGE) | + (1ULL << WIDX_RIGHT_CURVE_SMALL) | + (1ULL << WIDX_RIGHT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE_LARGE); + } + if (!is_track_enabled(TRACK_LIFT_HILL_STEEP)) { + if (w->widgets[WIDX_SLOPE_UP_STEEP].tooltip == STR_RIDE_CONSTRUCTION_STEEP_SLOPE_UP_TIP) { + disabledWidgets |= (1ULL << WIDX_SLOPE_UP_STEEP); + } + } + } + if (_previousTrackSlopeEnd == TRACK_SLOPE_UP_60 && _currentTrackCurve != TRACK_CURVE_NONE) { + disabledWidgets |= + (1ULL << WIDX_SLOPE_DOWN_STEEP) | + (1ULL << WIDX_LEVEL); + } + if (_previousTrackSlopeEnd == TRACK_SLOPE_DOWN_60 && _currentTrackCurve != TRACK_CURVE_NONE) { + disabledWidgets |= + (1ULL << WIDX_LEVEL) | + (1ULL << WIDX_SLOPE_UP_STEEP); + } + if (_currentTrackSlopeEnd == TRACK_SLOPE_UP_90 || _previousTrackSlopeEnd == TRACK_SLOPE_UP_90) { + if (_currentTrackCurve != TRACK_CURVE_NONE) { + disabledWidgets |= (1ULL << WIDX_SLOPE_UP_STEEP); + } + disabledWidgets |= + (1ULL << WIDX_LEFT_CURVE_LARGE) | + (1ULL << WIDX_RIGHT_CURVE_LARGE); + if (rideType == RIDE_TYPE_REVERSE_FREEFALL_COASTER || rideType == RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER) { + disabledWidgets |= + (1ULL << WIDX_STRAIGHT) | + (1ULL << WIDX_RIGHT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE_SMALL) | + (1ULL << WIDX_LEFT_CURVE_SMALL) | + (1ULL << WIDX_LEFT_CURVE); + } + } else if (_currentTrackSlopeEnd == TRACK_SLOPE_DOWN_90 || _previousTrackSlopeEnd == TRACK_SLOPE_DOWN_90) { + if (_currentTrackCurve != TRACK_CURVE_NONE) { + disabledWidgets |= (1ULL << WIDX_SLOPE_DOWN_STEEP); + } + disabledWidgets |= + (1ULL << WIDX_LEFT_CURVE_LARGE) | + (1ULL << WIDX_RIGHT_CURVE_LARGE); + if (rideType == RIDE_TYPE_REVERSE_FREEFALL_COASTER || rideType == RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER) { + disabledWidgets |= + (1ULL << WIDX_STRAIGHT) | + (1ULL << WIDX_RIGHT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE_SMALL) | + (1ULL << WIDX_LEFT_CURVE_SMALL) | + (1ULL << WIDX_LEFT_CURVE); + } + } + if (is_track_enabled(TRACK_HELIX_LARGE_UNBANKED)) { + if (_currentTrackSlopeEnd == TRACK_SLOPE_NONE && _currentTrackBankEnd == TRACK_SLOPE_NONE) { + if (_currentTrackCurve == TRACK_CURVE_LEFT || _currentTrackCurve == TRACK_CURVE_RIGHT) { + if (_currentTrackSlopeEnd == _previousTrackSlopeEnd) { + disabledWidgets &= ~(1ULL << WIDX_SLOPE_DOWN_STEEP); + disabledWidgets &= ~(1ULL << WIDX_SLOPE_UP_STEEP); + } + } + } + } else if ( + ( + is_track_enabled(TRACK_HELIX_SMALL) || + ( + is_track_enabled(TRACK_HELIX_LARGE) && + _currentTrackCurve != TRACK_CURVE_LEFT_SMALL && + _currentTrackCurve != TRACK_CURVE_RIGHT_SMALL + ) + ) && + ( + _currentTrackCurve == TRACK_CURVE_LEFT || + _currentTrackCurve == TRACK_CURVE_RIGHT || + _currentTrackCurve == TRACK_CURVE_LEFT_SMALL || + _currentTrackCurve == TRACK_CURVE_RIGHT_SMALL + ) && + (_currentTrackSlopeEnd == TRACK_SLOPE_NONE && _currentTrackBankEnd != TRACK_BANK_NONE) + ) { + if (_previousTrackSlopeEnd == _currentTrackSlopeEnd) { + // Enable helix + disabledWidgets &= ~(1ULL << WIDX_SLOPE_DOWN_STEEP); + disabledWidgets &= ~(1ULL << WIDX_SLOPE_UP_STEEP); + } + } + if (is_track_enabled(TRACK_SLOPE_CURVE_BANKED)) { + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_FRONT) { + if (_currentTrackCurve == TRACK_CURVE_LEFT_SMALL || _currentTrackCurve == TRACK_CURVE_RIGHT_SMALL) { + if (_currentTrackSlopeEnd == TRACK_SLOPE_NONE && _previousTrackBankEnd != TRACK_BANK_NONE) { + disabledWidgets &= ~(1ULL << WIDX_SLOPE_UP); + } + } + } else if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_BACK) { + if (_currentTrackCurve == TRACK_CURVE_LEFT_SMALL || _currentTrackCurve == TRACK_CURVE_RIGHT_SMALL) { + if (_currentTrackSlopeEnd == TRACK_SLOPE_NONE && _previousTrackBankEnd != TRACK_BANK_NONE) { + disabledWidgets &= ~(1ULL << WIDX_SLOPE_DOWN); + } + } + } + } + if (_currentTrackPieceDirection >= 4) { + disabledWidgets |= + (1ULL << WIDX_LEFT_CURVE_VERY_SMALL) | + (1ULL << WIDX_LEFT_CURVE_SMALL) | + (1ULL << WIDX_LEFT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE_SMALL) | + (1ULL << WIDX_RIGHT_CURVE_VERY_SMALL); + } + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_FRONT) { + disabledWidgets |= (1ULL << WIDX_NEXT_SECTION); + if (sub_6CA2DF(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) { + disabledWidgets |= (1ULL << WIDX_CONSTRUCT); + } + } else if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_BACK) { + disabledWidgets |= (1ULL << WIDX_PREVIOUS_SECTION); + if (sub_6CA2DF(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) { + disabledWidgets |= (1ULL << WIDX_CONSTRUCT); + } + } + if (ride_type_has_flag(rideType, RIDE_TYPE_FLAG_TRACK_ELEMENTS_HAVE_TWO_VARIETIES)) { + disabledWidgets &= ~(1ULL << WIDX_BANKING_GROUPBOX); + } + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT || _rideConstructionState == RIDE_CONSTRUCTION_STATE_SELECTED) { + disabledWidgets |= + (1ULL << WIDX_DIRECTION_GROUPBOX) | + (1ULL << WIDX_SLOPE_GROUPBOX) | + (1ULL << WIDX_BANKING_GROUPBOX) | + (1ULL << WIDX_LEFT_CURVE_VERY_SMALL) | + (1ULL << WIDX_LEFT_CURVE_SMALL) | + (1ULL << WIDX_LEFT_CURVE) | + (1ULL << WIDX_STRAIGHT) | + (1ULL << WIDX_RIGHT_CURVE) | + (1ULL << WIDX_RIGHT_CURVE_SMALL) | + (1ULL << WIDX_RIGHT_CURVE_VERY_SMALL) | + (1ULL << WIDX_SPECIAL_TRACK_DROPDOWN) | + (1ULL << WIDX_SLOPE_DOWN_STEEP) | + (1ULL << WIDX_SLOPE_DOWN) | + (1ULL << WIDX_LEVEL) | + (1ULL << WIDX_SLOPE_UP) | + (1ULL << WIDX_SLOPE_UP_STEEP) | + (1ULL << WIDX_CHAIN_LIFT) | + (1ULL << WIDX_BANK_LEFT) | + (1ULL << WIDX_BANK_STRAIGHT) | + (1ULL << WIDX_BANK_RIGHT) | + (1ULL << WIDX_LEFT_CURVE_LARGE) | + (1ULL << WIDX_RIGHT_CURVE_LARGE); + } + if (RCT2_GLOBAL(0x00F440D3, uint8) != 0) { + disabledWidgets &= ~(1ULL << WIDX_BANKING_GROUPBOX); + disabledWidgets &= ~(1ULL << WIDX_BANK_LEFT); + disabledWidgets &= ~(1ULL << WIDX_BANK_STRAIGHT); + disabledWidgets &= ~(1ULL << WIDX_BANK_RIGHT); + } + + // Set and invalidate the changed widgets + uint64 currentDisabledWidgets = w->disabled_widgets; + if (currentDisabledWidgets == disabledWidgets) + return; + + for (int i = 0; i < 64; i++) { + if ((disabledWidgets & (1ULL << i)) != (currentDisabledWidgets & (1ULL << i))) { + widget_invalidate(w, i); + } + } + w->disabled_widgets = disabledWidgets; +} + +/** + * + * rct2: 0x006C6E6A + */ +static void window_ride_construction_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + rct_ride *ride = GET_RIDE(_currentRideIndex); + int rideType; + + window_ride_construction_update_enabled_track_pieces(); + switch (widgetIndex) { + case WIDX_LEFT_CURVE: + sub_6C9627(); + _currentTrackCurve = 1; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + case WIDX_RIGHT_CURVE: + sub_6C9627(); + _currentTrackCurve = 2; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + case WIDX_LEFT_CURVE_SMALL: + sub_6C9627(); + _currentTrackCurve = 3; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + case WIDX_RIGHT_CURVE_SMALL: + sub_6C9627(); + _currentTrackCurve = 4; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + case WIDX_LEFT_CURVE_VERY_SMALL: + sub_6C9627(); + _currentTrackCurve = 5; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + case WIDX_RIGHT_CURVE_VERY_SMALL: + sub_6C9627(); + _currentTrackCurve = 6; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + case WIDX_LEFT_CURVE_LARGE: + sub_6C9627(); + _currentTrackCurve = 7; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + case WIDX_RIGHT_CURVE_LARGE: + sub_6C9627(); + _currentTrackCurve = 8; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + case WIDX_STRAIGHT: + sub_6C9627(); + if (_currentTrackCurve != 0) + _currentTrackBankEnd = TRACK_BANK_NONE; + _currentTrackCurve = 0; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + case WIDX_SLOPE_DOWN_STEEP: + sub_6C9627(); + rideType = _currentTrackCovered & 2 ? RCT2_ADDRESS(0x0097D4F5, uint8)[ride->type * 8] : ride->type; + if (is_track_enabled(TRACK_HELIX_SMALL)) { + if (_currentTrackCurve == 1 && _currentTrackBankEnd == TRACK_BANK_LEFT) { + _currentTrackCurve = 349; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } else if (_currentTrackCurve == 2 && _currentTrackBankEnd == TRACK_BANK_RIGHT) { + _currentTrackCurve = 350; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } else if (_currentTrackCurve == 3 && _currentTrackBankEnd == TRACK_BANK_LEFT) { + _currentTrackCurve = 345; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } else if (_currentTrackCurve == 4 && _currentTrackBankEnd == TRACK_BANK_RIGHT) { + _currentTrackCurve = 346; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } + } + if (is_track_enabled(TRACK_HELIX_LARGE)) { + if (_currentTrackCurve == 1 && _currentTrackBankEnd == TRACK_BANK_LEFT) { + _currentTrackCurve = 360; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } else if (_currentTrackCurve == 2 && _currentTrackBankEnd == TRACK_BANK_RIGHT) { + _currentTrackCurve = 361; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } + } + if (is_track_enabled(TRACK_HELIX_LARGE_UNBANKED)) { + if (_currentTrackBankEnd == TRACK_BANK_NONE) { + if (_currentTrackCurve == 1) { + _currentTrackCurve = 364; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } else if (_currentTrackCurve == 2) { + _currentTrackCurve = 365; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } + } + } + if (w->widgets[WIDX_SLOPE_DOWN_STEEP].tooltip == STR_RIDE_CONSTRUCTION_STEEP_SLOPE_DOWN_TIP) { + loc_6C7502(8); + } else { + loc_6C7502(10); + } + break; + case WIDX_SLOPE_DOWN: + sub_6C9627(); + if (_rideConstructionState == 2 && _currentTrackBankEnd != TRACK_BANK_NONE) { + _currentTrackBankEnd = TRACK_BANK_NONE; + } + loc_6C7502(6); + break; + case WIDX_LEVEL: + sub_6C9627(); + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_FRONT && _previousTrackSlopeEnd == 6) { + if (_currentTrackCurve == 3) { + _currentTrackBankEnd = TRACK_BANK_LEFT; + } else if (_currentTrackCurve == 4) { + _currentTrackBankEnd = TRACK_BANK_RIGHT; + } + } else if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_BACK && _previousTrackSlopeEnd == 2) { + if (_currentTrackCurve == 3) { + _currentTrackBankEnd = TRACK_BANK_LEFT; + } else if (_currentTrackCurve == 4) { + _currentTrackBankEnd = TRACK_BANK_RIGHT; + } + } + loc_6C7502(0); + break; + case WIDX_SLOPE_UP: + sub_6C9627(); + if (_rideConstructionState == 1 && _currentTrackBankEnd != TRACK_BANK_NONE) { + _currentTrackBankEnd = TRACK_BANK_NONE; + } + if (ride->type == RIDE_TYPE_REVERSE_FREEFALL_COASTER || ride->type == RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER) { + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_FRONT && _currentTrackCurve == 0) { + _currentTrackCurve = 124 | 0x100; + sub_6C84CE(); + } + } else { + loc_6C7502(2); + } + break; + case WIDX_SLOPE_UP_STEEP: + sub_6C9627(); + rideType = _currentTrackCovered & 2 ? RCT2_ADDRESS(0x0097D4F5, uint8)[ride->type * 8] : ride->type; + if (is_track_enabled(TRACK_HELIX_SMALL)) { + if (_currentTrackCurve == 1 && _currentTrackBankEnd == TRACK_BANK_LEFT) { + _currentTrackCurve = 347; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } else if (_currentTrackCurve == 2 && _currentTrackBankEnd == TRACK_BANK_RIGHT) { + _currentTrackCurve = 348; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } else if (_currentTrackCurve == 3 && _currentTrackBankEnd == TRACK_BANK_LEFT) { + _currentTrackCurve = 343; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } else if (_currentTrackCurve == 4 && _currentTrackBankEnd == TRACK_BANK_RIGHT) { + _currentTrackCurve = 344; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } + } + if (is_track_enabled(TRACK_HELIX_LARGE)) { + if (_currentTrackCurve == 1 && _currentTrackBankEnd == TRACK_BANK_LEFT) { + _currentTrackCurve = 358; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } else if (_currentTrackCurve == 2 && _currentTrackBankEnd == TRACK_BANK_RIGHT) { + _currentTrackCurve = 359; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } + } + if (is_track_enabled(TRACK_HELIX_LARGE_UNBANKED)) { + if (_currentTrackBankEnd == TRACK_BANK_NONE) { + if (_currentTrackCurve == 1) { + _currentTrackCurve = 362; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } else if (_currentTrackCurve == 2) { + _currentTrackCurve = 363; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + } + } + } + if (w->widgets[WIDX_SLOPE_UP_STEEP].tooltip == STR_RIDE_CONSTRUCTION_STEEP_SLOPE_UP_TIP) { + loc_6C7502(4); + } else { + loc_6C7502(18); + } + break; + case WIDX_CHAIN_LIFT: + sub_6C9627(); + _currentTrackLiftHill ^= 1; + if (_currentTrackLiftHill & 1) { + _currentTrackCovered &= ~1; + } + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + case WIDX_BANK_LEFT: + sub_6C9627(); + if (RCT2_GLOBAL(0x00F440D3, uint8) == 0) { + _currentTrackBankEnd = TRACK_BANK_LEFT; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + } + break; + case WIDX_BANK_STRAIGHT: + sub_6C9627(); + if (RCT2_GLOBAL(0x00F440D3, uint8) == 0) { + _currentTrackBankEnd = TRACK_BANK_NONE; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + } else { + uint8 *brakesSpeedPtr = (uint8*)0x00F440CD; + uint8 maxBrakesSpeed = 30; + if (RCT2_GLOBAL(0x00F440D3, uint8) != 1) { + brakesSpeedPtr = (uint8*)0x00F440CE; + maxBrakesSpeed = RCT2_GLOBAL(0x0097CF40 + 6 + (ride->type * 8), uint8); + } + uint8 brakesSpeed = *brakesSpeedPtr + 2; + if (brakesSpeed <= maxBrakesSpeed) { + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_SELECTED) { + ride_construction_set_brakes_speed(brakesSpeed); + } else { + *brakesSpeedPtr = brakesSpeed; + sub_6C84CE(); + } + } + } + break; + case WIDX_BANK_RIGHT: + sub_6C9627(); + if (RCT2_GLOBAL(0x00F440D3, uint8) == 0) { + _currentTrackBankEnd = TRACK_BANK_RIGHT; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + } else { + uint8 *brakesSpeedPtr = (uint8*)0x00F440CD; + if (RCT2_GLOBAL(0x00F440D3, uint8) != 1) { + brakesSpeedPtr = (uint8*)0x00F440CE; + } + uint8 brakesSpeed = *brakesSpeedPtr - 2; + if (brakesSpeed >= 2) { + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_SELECTED) { + ride_construction_set_brakes_speed(brakesSpeed); + } else { + *brakesSpeedPtr = brakesSpeed; + sub_6C84CE(); + } + } + } + break; + case WIDX_SPECIAL_TRACK_DROPDOWN: + window_ride_construction_show_special_track_dropdown(w, widget); + break; + case WIDX_U_TRACK: + sub_6C9627(); + _currentTrackCovered &= ~1; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + case WIDX_O_TRACK: + sub_6C9627(); + _currentTrackCovered |= 1; + _currentTrackLiftHill &= ~1; + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); + break; + case WIDX_SEAT_ROTATION_ANGLE_SPINNER_UP: + if (_currentSeatRotationAngle < 15) { + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_SELECTED) { + ride_selected_track_set_seat_rotation(_currentSeatRotationAngle + 1); + } else { + _currentSeatRotationAngle++; + sub_6C84CE(); + } + } + break; + case WIDX_SEAT_ROTATION_ANGLE_SPINNER_DOWN: + if (_currentSeatRotationAngle > 0) { + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_SELECTED) { + ride_selected_track_set_seat_rotation(_currentSeatRotationAngle - 1); + } else { + _currentSeatRotationAngle--; + sub_6C84CE(); + } + } + break; + } +} + +/** + * + * rct2: 0x006C78CD + */ +static void window_ride_construction_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) +{ + if (widgetIndex != WIDX_SPECIAL_TRACK_DROPDOWN) + return; + if (dropdownIndex == -1) + return; + + sub_6C9627(); + _currentTrackPrice = MONEY32_UNDEFINED; + int trackPiece = _currentPossibleRideConfigurations[dropdownIndex]; + switch (trackPiece) { + case TRACK_ELEM_END_STATION: + case TRACK_ELEM_S_BEND_LEFT: + case TRACK_ELEM_S_BEND_RIGHT: + _currentTrackSlopeEnd = 0; + break; + case TRACK_ELEM_LEFT_VERTICAL_LOOP: + case TRACK_ELEM_RIGHT_VERTICAL_LOOP: + _currentTrackBankEnd = TRACK_BANK_NONE; + _currentTrackLiftHill &= ~1; + break; + } + _currentTrackCurve = trackPiece | 0x100; + sub_6C84CE(); +} + +/** + * + * rct2: 0x006C9F72 + */ +static void window_ride_construction_construct(rct_window *w) +{ + int trackType, trackDirection, rideIndex, edxRS16, x, y, z, properties; + track_begin_end trackBeginEnd; + + _currentTrackPrice = MONEY32_UNDEFINED; + RCT2_GLOBAL(0x00F44074, money32) = MONEY32_UNDEFINED; + sub_6C9627(); + if (sub_6CA2DF(&trackType, &trackDirection, &rideIndex, &edxRS16, &x, &y, &z, &properties)) { + sub_6C84CE(); + return; + } + + // If client, then we can't update 'next piece selection' code until server sends back command + if (network_get_mode() == NETWORK_MODE_CLIENT) { + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_BACK) { + game_command_callback = game_command_callback_ride_construct_placed_back; + } else if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_FRONT) { + game_command_callback = game_command_callback_ride_construct_placed_front; + } + } + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; + RCT2_GLOBAL(0x00F44074, money32) = game_do_command( + x, + (GAME_COMMAND_FLAG_APPLY) | (trackDirection << 8), + y, + rideIndex | (trackType << 8) | (edxRS16 << 16), + GAME_COMMAND_PLACE_TRACK, + z | (properties << 16), + 0 + ); + if (RCT2_GLOBAL(0x00F44074, money32) == MONEY32_UNDEFINED) { + if (network_get_mode() == NETWORK_MODE_CLIENT) + game_command_callback = 0; // don't do callback if we can't afford the track piece + sub_6C84CE(); + return; + } + + audio_play_sound_at_location(SOUND_PLACE_ITEM, x, y, z); + + if (RCT2_GLOBAL(RCT2_ADDRESS_ABOVE_GROUND_FLAGS, uint8) & TRACK_ELEMENT_LOCATION_IS_UNDERGROUND) { + viewport_set_visibility(1); + } + + if ( + (_currentTrackCurve >= 343 && _currentTrackCurve <= 350) || + (_currentTrackCurve >= 358 && _currentTrackCurve <= 365) || + (_currentTrackSlopeEnd != TRACK_SLOPE_NONE) + ) { + viewport_set_visibility(2); + } + + // *************** + // NOTE: the rest of this function (minus the network condition) is copied to game_command_callback_ride_construct_placed_front/back + // Please update both ends if there are any changes here + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_BACK) { + RCT2_GLOBAL(0x00F441D2, uint8) = _currentRideIndex; + trackDirection = _currentTrackPieceDirection ^ 2; + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; + if (!(trackDirection & 4)) { + x += TileDirectionDelta[trackDirection].x; + y += TileDirectionDelta[trackDirection].y; + } + + if (track_block_get_previous_from_zero(x, y, z, _currentRideIndex, trackDirection, &trackBeginEnd)) { + _currentTrackBeginX = trackBeginEnd.begin_x; + _currentTrackBeginY = trackBeginEnd.begin_y; + _currentTrackBeginZ = trackBeginEnd.begin_z; + _currentTrackPieceDirection = trackBeginEnd.begin_direction; + _currentTrackPieceType = trackBeginEnd.begin_element->properties.track.type; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; + _rideConstructionState = RIDE_CONSTRUCTION_STATE_SELECTED; + ride_select_previous_section(); + } else { + _rideConstructionState = RIDE_CONSTRUCTION_STATE_0; + } + } else { + RCT2_GLOBAL(0x00F441D2, uint8) = _currentRideIndex; + trackDirection = _currentTrackPieceDirection; + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; + if (!(trackDirection & 4)) { + x -= TileDirectionDelta[trackDirection].x; + y -= TileDirectionDelta[trackDirection].y; + } + + rct_xy_element next_track; + if (track_block_get_next_from_zero(x, y, z, _currentRideIndex, trackDirection, &next_track, &z, &trackDirection)) { + _currentTrackBeginX = next_track.x; + _currentTrackBeginY = next_track.y; + _currentTrackBeginZ = z; + _currentTrackPieceDirection = next_track.element->type & MAP_ELEMENT_DIRECTION_MASK; + _currentTrackPieceType = next_track.element->properties.track.type; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; + _rideConstructionState = RIDE_CONSTRUCTION_STATE_SELECTED; + ride_select_next_section(); + } else { + _rideConstructionState = RIDE_CONSTRUCTION_STATE_0; + } + } + + // returning early here makes it so that the construction window doesn't blink + if (network_get_mode() == NETWORK_MODE_CLIENT) + return; + + sub_6C84CE(); +} + +/** + * + * rct2: 0x006C9BA5 + */ +static void window_ride_construction_mouseup_demolish(rct_window* w) +{ + int x, y, z, direction, type; + rct_map_element *mapElement; + rct_xy_element inputElement, outputElement; + track_begin_end trackBeginEnd; + //bool gotoStartPlacementMode; + + _currentTrackPrice = MONEY32_UNDEFINED; sub_6C9627(); - RCT2_GLOBAL(0xF440B8, uint8) = 3; - if (RCT2_GLOBAL(0xF440A6, uint8) == 1){ - //6C9C4F + // Select the track element that is to be deleted + RCT2_GLOBAL(0x00F440B8, uint8) = 3; + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_FRONT) { + if (!ride_select_backwards_from_front()) { + sub_6C84CE(); + return; + } + RCT2_GLOBAL(0x00F440B8, uint8) = 1; + } else if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_BACK) { + if (!ride_select_forwards_from_back()) { + sub_6C84CE(); + return; + } + RCT2_GLOBAL(0x00F440B8, uint8) = 2; } - 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); + // Invalidate the selected track element or make sure its at origin??? + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; + direction = _currentTrackPieceDirection; + type = _currentTrackPieceType; + if (sub_6C683D(&x, &y, &z, direction & 3, type, 0, &mapElement, 0)) { + sub_6C84CE(); + return; } - int ride_id = RCT2_GLOBAL(0xF440A7, uint8); - RCT2_GLOBAL(0xF441D2, uint8) = ride_id; - //6c9BFE + // Get the previous track element to go to after the selected track element is deleted + inputElement.x = x; + inputElement.y = y; + inputElement.element = mapElement; + if (track_block_get_previous(x, y, mapElement, &trackBeginEnd)) { + x = trackBeginEnd.begin_x; + y = trackBeginEnd.begin_y; + z = trackBeginEnd.begin_z; + direction = trackBeginEnd.begin_direction; + type = trackBeginEnd.begin_element->properties.track.type; + gGotoStartPlacementMode = false; + } + else if (track_block_get_next(&inputElement, &outputElement, &z, &direction)) { + x = outputElement.x; + y = outputElement.y; + direction = outputElement.element->type & MAP_ELEMENT_DIRECTION_MASK; + type = outputElement.element->properties.track.type; + gGotoStartPlacementMode = false; + } else { + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; + direction = _currentTrackPieceDirection; + type = _currentTrackPieceType; + + if (sub_6C683D(&x, &y, &z, direction, type, 0, &mapElement, 0)) { + sub_6C84CE(); + return; + } + + const rct_preview_track *trackBlock = get_track_def_from_ride_index(_currentRideIndex, mapElement->properties.track.type); + z = (mapElement->base_height * 8) - trackBlock->z; + gGotoStartPlacementMode = true; + } + + money32 cost = ride_remove_track_piece( + _currentTrackBeginX, + _currentTrackBeginY, + _currentTrackBeginZ, + _currentTrackPieceDirection, + _currentTrackPieceType + ); + if (cost == MONEY32_UNDEFINED) { + sub_6C84CE(); + return; + } + + if (network_get_mode() == NETWORK_MODE_CLIENT) { + gRideRemoveTrackPieceCallbackX = x; + gRideRemoveTrackPieceCallbackY = y; + gRideRemoveTrackPieceCallbackZ = z; + gRideRemoveTrackPieceCallbackDirection = direction; + gRideRemoveTrackPieceCallbackType = type; + } else { + window_ride_construction_mouseup_demolish_next_piece(x, y, z, direction, type); + } } -void window_construction_maze_invalidate() +void window_ride_construction_mouseup_demolish_next_piece(int x, int y, int z, int direction, int type) { - 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) + int slope, slopeEnd, b2, bankEnd, bankStart, b5, b4; + if (gGotoStartPlacementMode) { + z &= 0xFFF0; + _currentTrackBeginZ = z; + _rideConstructionState = RIDE_CONSTRUCTION_STATE_FRONT; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; + direction = _currentTrackPieceDirection; + slope = _currentTrackCurve; + slopeEnd = _previousTrackSlopeEnd; + b2 = _currentTrackSlopeEnd; + bankEnd = _previousTrackBankEnd; + bankStart = _currentTrackBankEnd; + b5 = _currentTrackCovered; + b4 = _currentTrackLiftHill; + ride_construction_set_default_next_piece(); + sub_6C84CE(); + if (!sub_6CAF80(_currentRideIndex, NULL)) { + sub_6CC3FB(_currentRideIndex); + _currentTrackPieceDirection = direction; + if (!(slope & 0x100)) { + _currentTrackCurve = slope; + _previousTrackSlopeEnd = slopeEnd; + _currentTrackSlopeEnd = b2; + _previousTrackBankEnd = bankEnd; + _currentTrackBankEnd = bankStart; + _currentTrackCovered = b5; + _currentTrackLiftHill = b4; + sub_6C84CE(); + } + } + } + else { + if (RCT2_GLOBAL(0x00F440B8, uint8) == 3 || RCT2_GLOBAL(0x00F440B8, uint8) == 1) { + if (type == TRACK_ELEM_MIDDLE_STATION || type == TRACK_ELEM_BEGIN_STATION) { + type = TRACK_ELEM_END_STATION; + } + } + if (RCT2_GLOBAL(0x00F440B8, uint8) == 2) { + if (type == TRACK_ELEM_MIDDLE_STATION) { + type = TRACK_ELEM_BEGIN_STATION; + } + } + if (network_get_mode() == NETWORK_MODE_CLIENT) { + // rideConstructionState needs to be set again to the proper value, this only affects the client + _rideConstructionState = RIDE_CONSTRUCTION_STATE_SELECTED; + } + _currentTrackBeginX = x; + _currentTrackBeginY = y; + _currentTrackBeginZ = z; + _currentTrackPieceDirection = direction; + _currentTrackPieceType = type; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; + if (RCT2_GLOBAL(0x00F440B8, uint8) == 1) { + ride_select_next_section(); + } + else if (RCT2_GLOBAL(0x00F440B8, uint8) == 2) { + ride_select_previous_section(); + } + sub_6C84CE(); + } +} + +/** + * + * rct2: 0x006C78AA + */ +static void window_ride_construction_rotate(rct_window *w) +{ + _currentTrackPieceDirection = (_currentTrackPieceDirection + 1) & 3; + sub_6C9627(); + _currentTrackPrice = MONEY32_UNDEFINED; + sub_6C84CE(); +} + +/** + * + * rct2: 0x006C7802 + */ +static void window_ride_construction_entrance_click(rct_window *w) +{ + if (tool_set(w, WIDX_ENTRANCE, 12)) { + if (!sub_6CAF80(_currentRideIndex, NULL)) { + sub_6CC3FB(_currentRideIndex); + } + } else { + RCT2_GLOBAL(0x00F44191, uint8) = 0; + RCT2_GLOBAL(0x00F44192, uint8) = w->number & 0xFF; + RCT2_GLOBAL(0x00F44193, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint8) |= INPUT_FLAG_6; + sub_6C9627(); + if (_rideConstructionState != RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT) { + RCT2_GLOBAL(0x00F440CC, uint8) = _rideConstructionState; + _rideConstructionState = RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT; + } + sub_6C84CE(); + } +} + +/** + * + * rct2: 0x006C7866 + */ +static void window_ride_construction_exit_click(rct_window *w) +{ + if (tool_set(w, WIDX_EXIT, 12)) { + if (!sub_6CAF80(_currentRideIndex, NULL)) { + sub_6CC3FB(_currentRideIndex); + } + } else { + RCT2_GLOBAL(0x00F44191, uint8) = 1; + RCT2_GLOBAL(0x00F44192, uint8) = w->number & 0xFF; + RCT2_GLOBAL(0x00F44193, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint8) |= INPUT_FLAG_6; + sub_6C9627(); + if (_rideConstructionState != RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT) { + RCT2_GLOBAL(0x00F440CC, uint8) = _rideConstructionState; + _rideConstructionState = RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT; + } + sub_6C84CE(); + } +} + +/** + * + * rct2: 0x006C8374 + */ +static void window_ride_construction_update(rct_window *w) +{ + switch (_currentTrackCurve) { + case 429: + case 376: + case 369: + case 368: + widget_invalidate(w, WIDX_CONSTRUCT); + break; + } + + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_PLACE) { + if (!widget_is_active_tool(w, WIDX_CONSTRUCT)) { + window_close(w); + return; + } + } + + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT) { + if (!widget_is_active_tool(w, WIDX_ENTRANCE) && !widget_is_active_tool(w, WIDX_EXIT)) { + _rideConstructionState = RCT2_GLOBAL(0x00F440CC, uint8); + sub_6C84CE(); + } + } + + switch (_rideConstructionState) { + case RIDE_CONSTRUCTION_STATE_FRONT: + case RIDE_CONSTRUCTION_STATE_BACK: + case RIDE_CONSTRUCTION_STATE_SELECTED: + if ( + (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) == WC_RIDE_CONSTRUCTION + ) { + tool_cancel(); + } + break; + } + + sub_6C94D8(); +} + +/** + * + * rct2: 0x006CC538 + */ +static bool ride_get_place_position_from_screen_position(int screenX, int screenY, int *outX, int *outY) +{ + short mapX, mapY, mapZ; + int interactionType, direction; + rct_map_element *mapElement; + rct_viewport *viewport; + + if (!_trackPlaceCtrlState) { + if (RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & 2) { + get_map_coordinates_from_pos(screenX, screenY, 0xFCCA, &mapX, &mapY, &interactionType, &mapElement, &viewport); + if (interactionType != 0) { + _trackPlaceCtrlZ = mapElement->base_height * 8; + _trackPlaceCtrlState = true; + } + } + } else { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & 2)) { + _trackPlaceCtrlState = false; + } + } + + if (!_trackPlaceShiftState) { + if (RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & 1) { + _trackPlaceShiftState = true; + _trackPlaceShiftStartScreenX = screenX; + _trackPlaceShiftStartScreenY = screenY; + _trackPlaceShiftZ = 0; + } + } else { + if (RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & 1) { + _trackPlaceShiftZ = floor2(_trackPlaceShiftStartScreenY - screenY + 4, 8); + screenX = _trackPlaceShiftStartScreenX; + screenY = _trackPlaceShiftStartScreenY; + } else { + _trackPlaceShiftState = false; + } + } + + if (!_trackPlaceCtrlState) { + sub_68A15E(screenX, screenY, &mapX, &mapY, &direction, &mapElement); + if (mapX == (short)0x8000) + return false; + + _trackPlaceZ = 0; + if (_trackPlaceShiftState) { + mapElement = map_get_surface_element_at(mapX >> 5, mapY >> 5); + mapZ = floor2(mapElement->base_height * 8, 16); + mapZ += _trackPlaceShiftZ; + mapZ = max(mapZ, 16); + _trackPlaceZ = mapZ; + } + } else { + mapZ = _trackPlaceCtrlZ; + screen_get_map_xy_with_z(screenX, screenY, mapZ, &mapX, &mapY); + if (_trackPlaceShiftState != 0) { + mapZ += _trackPlaceShiftZ; + } + _trackPlaceZ = max(mapZ, 16); + } + + if (mapX == (short)0x8000) + return false; + + *outX = floor2(mapX, 32); + *outY = floor2(mapY, 32); + return true; +} + +/** + * + * rct2: 0x006C8229 + */ +static void window_ride_construction_toolupdate(rct_window* w, int widgetIndex, int x, int y) +{ + switch (widgetIndex) { + case WIDX_CONSTRUCT: + ride_construction_toolupdate_construct(x, y); + break; + case WIDX_ENTRANCE: + case WIDX_EXIT: + ride_construction_toolupdate_entrance_exit(x, y); + break; + } +} + +/** + * + * rct2: 0x006C8248 + */ +static void window_ride_construction_tooldown(rct_window* w, int widgetIndex, int x, int y) +{ + switch (widgetIndex) { + case WIDX_CONSTRUCT: + ride_construction_tooldown_construct(x, y); + break; + case WIDX_ENTRANCE: + case WIDX_EXIT: + ride_construction_tooldown_entrance_exit(x, y); + break; + } +} + +/** + * + * rct2: 0x006C6AD5 + */ +static void window_ride_construction_invalidate(rct_window *w) +{ + rct_ride *ride; + rct_string_id stringId; + + ride = GET_RIDE(_currentRideIndex); + + stringId = STR_RIDE_CONSTRUCTION_SPECIAL; + if (_currentTrackCurve >= 256) { + stringId = RCT2_ADDRESS(0x00999492, rct_string_id)[_currentTrackCurve - 256]; + if (stringId == STR_RAPIDS && ride->type == RIDE_TYPE_CAR_RIDE) + stringId = STR_LOG_BUMPS; + } + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = stringId; + + if (RCT2_GLOBAL(0x00F440D3, uint8) == 1) + RCT2_GLOBAL(0x013CE952 + 2, uint16) = ((RCT2_GLOBAL(0x00F440CD, uint8) * 9) >> 2) & 0xFFFF; + + window_ride_construction_widgets[WIDX_SEAT_ROTATION_ANGLE_SPINNER].image = + STR_RIDE_CONSTRUCTION_SEAT_ROTATION_ANGLE_NEG_180 + RCT2_GLOBAL(0x00F440CF, uint8); + + if (RCT2_GLOBAL(0x00F440D3, uint8) == 2) + RCT2_GLOBAL(0x013CE952 + 2, uint16) = ((RCT2_GLOBAL(0x00F440CE, uint8) * 9) >> 2) & 0xFFFF; + + // Set window title arguments + RCT2_GLOBAL(0x013CE952 + 4, uint16) = ride->name; + RCT2_GLOBAL(0x013CE952 + 6, uint32) = ride->name_arguments; +} + +/** + * + * rct2: 0x006C6B86 + */ +static void window_ride_construction_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ + rct_drawpixelinfo *clipdpi; + rct_widget *widget; + int x, y, width, height; + + window_draw_widgets(w, dpi); + + widget = &window_ride_construction_widgets[WIDX_CONSTRUCT]; + if (widget->type == WWT_EMPTY) + return; + + int trackType, trackDirection, rideIndex, edxRS16; + if (sub_6CA2DF(&trackType, &trackDirection, &rideIndex, &edxRS16, NULL, NULL, NULL, NULL)) + return; + + // Draw track piece + x = w->x + widget->left + 1; + y = w->y + widget->top + 1; + width = widget->right - widget->left - 1; + height = widget->bottom - widget->top - 1; + clipdpi = clip_drawpixelinfo(dpi, x, width, y, height); + if (clipdpi != NULL) { + window_ride_construction_draw_track_piece(w, clipdpi, rideIndex, trackType, trackDirection, edxRS16, width, height); + rct2_free(clipdpi); + } + + // Draw cost + x = w->x + (widget->left + widget->right) / 2; + y = w->y + widget->bottom - 23; + if (_rideConstructionState != RIDE_CONSTRUCTION_STATE_PLACE) + gfx_draw_string_centred(dpi, 1407, x, y, 0, w); + + y += 11; + if ( + _currentTrackPrice != MONEY32_UNDEFINED && + !(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) + ) { + gfx_draw_string_centred(dpi, 1408, x, y, 0, (void*)&_currentTrackPrice); + } +} + +static void window_ride_construction_draw_track_piece( + rct_window *w, rct_drawpixelinfo *dpi, + int rideIndex, int trackType, int trackDirection, int unknown, + int width, int height +) { + const rct_preview_track *trackBlock; + rct_ride *ride; + + ride = GET_RIDE(rideIndex); + + trackBlock = get_track_def_from_ride(ride, trackType); + while ((trackBlock + 1)->index != 0xFF) + trackBlock++; + + short x = trackBlock->x; + short z = trackBlock->z; + short y = trackBlock->y; + if (trackBlock->var_09 & 2) { + x = 0; + y = 0; + } + + short tmp; + switch (trackDirection & 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 = 4112 + (x / 2); + y = 4112 + (y / 2); + z = 1024 + z; + + short bx = ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE) ? + RCT2_GLOBAL(0x009984A2 + trackType * 8, sint8) : + RCT2_GLOBAL(0x00997CA2 + trackType * 8, sint8); + + z -= bx; + int start_x = x; + switch (get_current_rotation()) { + 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; + } + dpi->x += x - width / 2; + dpi->y += y - height / 2 - 16; + RCT2_GLOBAL(0x0140E9A8, rct_drawpixelinfo*) = dpi; + uint32_t d = unknown << 16; + d |= rideIndex; + d |= trackType << 8; + + sub_6CBCE2(rideIndex, trackType, trackDirection, d, 4096, 4096, 1024); +} + +static rct_map_element _tempTrackMapElement; +static rct_map_element _tempSideTrackMapElement = { 0x80, 0x8F, 128, 128, 0, 0, 0, 0 }; +static rct_map_element *_backupMapElementArrays[5]; + +/** + * + * rct2: 0x006CBCE2 + * bh: trackDirection + * dl: rideIndex + * dh: trackType + */ +static void sub_6CBCE2( + int rideIndex, int trackType, int trackDirection, int edx, + int originX, int originY, int originZ +) { + rct_ride *ride; + const rct_preview_track *trackBlock; + int preserve_current_viewport_flags; + int x, y, baseZ, clearanceZ, offsetX, offsetY; + uint64 preserve_map_size_vars; + + preserve_current_viewport_flags = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) = 0; + trackDirection &= 3; + + RCT2_GLOBAL(0x00EE7880, uint32) = 0x00F1A4CC; + painter_setup(); + + ride = GET_RIDE(rideIndex); + + preserve_map_size_vars = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint64); + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) = 255 * 32; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_MINUS_2, uint16) = (255 * 32) + 286; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) = 256; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16) = (256 * 32) - 1; + + trackBlock = get_track_def_from_ride(ride, trackType); + while (trackBlock->index != 255) { + int bl = trackBlock->var_08; + int bh; + switch (trackDirection) { + case 0: + offsetX = trackBlock->x; + offsetY = trackBlock->y; + break; case 1: - tmp = x; - x = y; - y = -tmp; + offsetX = trackBlock->y; + offsetY = -trackBlock->x; + bl = rol8(bl, 1); + bh = bl; + bh = ror8(bh, 4); + bl &= 0xEE; + bh &= 0x11; + bl |= bh; break; case 2: - x = -x; - y = -y; + offsetX = -trackBlock->x; + offsetY = -trackBlock->y; + bl = rol8(bl, 2); + bh = bl; + bh = ror8(bh, 4); + bl &= 0xCC; + bh &= 0x33; + bl |= bh; break; case 3: - tmp = x; - x = -y; - y = tmp; - break; - case 0: + offsetX = -trackBlock->y; + offsetY = trackBlock->x; + bl = rol8(bl, 3); + bh = bl; + bh = ror8(bh, 4); + bl &= 0x88; + bh &= 0x77; + bl |= bh; 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); + x = originX + offsetX; + y = originY + offsetY; + baseZ = (originZ + trackBlock->z) >> 3; + clearanceZ = ((trackBlock->var_07 + RCT2_GLOBAL(0x0097D219 + (ride->type * 8), uint8)) >> 3) + baseZ + 4; + + int tileX = x >> 5; + int tileY = y >> 5; + + // Replace map elements with temporary ones containing track + _backupMapElementArrays[0] = map_get_first_element_at(tileX + 0, tileY + 0); + _backupMapElementArrays[1] = map_get_first_element_at(tileX + 1, tileY + 0); + _backupMapElementArrays[2] = map_get_first_element_at(tileX - 1, tileY + 0); + _backupMapElementArrays[3] = map_get_first_element_at(tileX + 0, tileY + 1); + _backupMapElementArrays[4] = map_get_first_element_at(tileX + 0, tileY - 1); + map_set_tile_elements(tileX + 0, tileY + 0, &_tempTrackMapElement); + map_set_tile_elements(tileX + 1, tileY + 0, &_tempSideTrackMapElement); + map_set_tile_elements(tileX - 1, tileY + 0, &_tempSideTrackMapElement); + map_set_tile_elements(tileX + 0, tileY + 1, &_tempSideTrackMapElement); + map_set_tile_elements(tileX + 0, tileY - 1, &_tempSideTrackMapElement); + + // Set the temporary track element + _tempTrackMapElement.type = trackDirection | MAP_ELEMENT_TYPE_TRACK | (edx & 0x10000 ? 0x80 : 0); + _tempTrackMapElement.flags = (bl & 0x0F) | MAP_ELEMENT_FLAG_LAST_TILE; + _tempTrackMapElement.base_height = baseZ; + _tempTrackMapElement.clearance_height = clearanceZ; + _tempTrackMapElement.properties.track.type = trackType; + _tempTrackMapElement.properties.track.sequence = trackBlock->index; + _tempTrackMapElement.properties.track.colour = (edx & 0x20000 ? 4 : 0); + _tempTrackMapElement.properties.track.ride_index = rideIndex; + + // Draw this map tile + sub_68B2B7(x, y); + + // Restore map elements + map_set_tile_elements(tileX + 0, tileY + 0, _backupMapElementArrays[0]); + map_set_tile_elements(tileX + 1, tileY + 0, _backupMapElementArrays[1]); + map_set_tile_elements(tileX - 1, tileY + 0, _backupMapElementArrays[2]); + map_set_tile_elements(tileX + 0, tileY + 1, _backupMapElementArrays[3]); + map_set_tile_elements(tileX + 0, tileY - 1, _backupMapElementArrays[4]); + + trackBlock++; + } + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint64) = preserve_map_size_vars; + + sub_688217(); + sub_688485(); + + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_VIEWPORT_FLAGS, uint16) = preserve_current_viewport_flags; +} + +/** + * + * rct2: 0x006C84CE + */ +void sub_6C84CE() +{ + rct_window *w; + rct_map_element *mapElement; + + window_ride_construction_update_enabled_track_pieces(); + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w == NULL) + return; + + window_ride_construction_update_map_selection(); + + RCT2_GLOBAL(0x00F440D0, uint8) = 255; + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_SELECTED) { + int x = _currentTrackBeginX; + int y = _currentTrackBeginY; + int z = _currentTrackBeginZ; + if (!sub_6C683D(&x, &y, &z, _currentTrackPieceDirection & 3, _currentTrackPieceType, 0, &mapElement, 0)) { + RCT2_GLOBAL(0x00F440D0, uint8) = mapElement->properties.track.type; + if (mapElement->properties.track.type == 99) + RCT2_GLOBAL(0x00F440CD, uint8) = (mapElement->properties.track.sequence >> 4) << 1; + _currentSeatRotationAngle = mapElement->properties.track.colour >> 4; + } + } + + window_ride_construction_update_possible_ride_configurations(); + window_ride_construction_update_widgets(w); +} + +/** + * + * rct2: 0x006CA2DF + * bh: trackRotation (out) + * dl: ??? (out) + * dh: trackType (out) + * edx >> 16: ??? (out) + */ +static bool sub_6CA2DF(int *trackType, int *trackDirection, int *rideIndex, int *edxRS16, int *x, int *y, int *z, int *properties) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + if (RCT2_CALLFUNC_X(0x006CA2DF, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp) & 0x100) + return true; + + if (trackType != NULL) *trackType = (edx >> 8) & 0xFF; + if (trackDirection != NULL) *trackDirection = (ebx >> 8) & 0xFF; + if (rideIndex != NULL) *rideIndex = edx & 0xFF; + if (edxRS16 != NULL) *edxRS16 = (edx >> 16) & 0xFFFF; + if (x != NULL) *x = eax & 0xFFFF; + if (y != NULL) *y = ecx & 0xFFFF; + if (z != NULL) *z = edi & 0xFFFF; + if (properties != NULL) *properties = (edi >> 16) & 0xFFFF; + return false; +} + +/** + * + * rct2: 0x006C6A77 + */ +static void window_ride_construction_update_enabled_track_pieces() +{ + rct_ride *ride = GET_RIDE(_currentRideIndex); + rct_ride_type *rideEntry = ride_get_entry(ride); + + int rideType = _currentTrackCovered & 2 ? RCT2_ADDRESS(0x0097D4F5, uint8)[ride->type * 8] : ride->type; + _enabledRidePiecesA = rideEntry->enabledTrackPiecesA & RCT2_ADDRESS(0x01357444, uint32)[rideType]; + _enabledRidePiecesB = rideEntry->enabledTrackPiecesB & RCT2_ADDRESS(0x01357644, uint32)[rideType]; +} + +/** + * + * rct2: 0x006CA162 + */ +money32 sub_6CA162(int rideIndex, int trackType, int trackDirection, int edxRS16, int x, int y, int z) +{ + rct_ride *ride; + money32 result; + + sub_6C96C0(); + ride = GET_RIDE(rideIndex); + if (ride->type == RIDE_TYPE_MAZE) { + result = game_do_command(x, 105 | (4 << 8), y, rideIndex | (trackType << 8) | (edxRS16 << 16), GAME_COMMAND_SET_MAZE_TRACK, z, 0); + if (result == MONEY32_UNDEFINED) + return result; + + RCT2_GLOBAL(0x00F440C5, uint16) = x; + RCT2_GLOBAL(0x00F440C7, uint16) = y; + RCT2_GLOBAL(0x00F440C9, uint16) = z; + RCT2_GLOBAL(0x00F440CB, uint8) = trackDirection; + _currentTrackSelectionFlags |= 2; + viewport_set_visibility(RCT2_GLOBAL(RCT2_ADDRESS_ABOVE_GROUND_FLAGS, uint8) & TRACK_ELEMENT_LOCATION_IS_UNDERGROUND ? 1 : 3); + if (_currentTrackSlopeEnd != 0) + viewport_set_visibility(2); + + return result; + } else { + result = game_do_command(x, 105 | (trackDirection << 8), y, rideIndex | (trackType << 8) | (edxRS16 << 16), GAME_COMMAND_PLACE_TRACK, z, 0); + if (result == MONEY32_UNDEFINED) + return result; + + RCT2_GLOBAL(0x00F440C5, uint16) = x; + RCT2_GLOBAL(0x00F440C7, uint16) = y; + z += ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE) ? + RCT2_GLOBAL(0x009972BD + (trackType * 10), uint16) : + RCT2_GLOBAL(0x009968BD + (trackType * 10), uint16); + + RCT2_GLOBAL(0x00F440C9, uint16) = z; + RCT2_GLOBAL(0x00F440CB, uint8) = trackDirection; + _currentTrackSelectionFlags |= 2; + viewport_set_visibility(RCT2_GLOBAL(RCT2_ADDRESS_ABOVE_GROUND_FLAGS, uint8) & TRACK_ELEMENT_LOCATION_IS_UNDERGROUND ? 1 : 3); + if (_currentTrackSlopeEnd != 0) + viewport_set_visibility(2); + + return result; + } +} + +/** + * + * rct2: 0x006C94D8 + */ +void sub_6C94D8() +{ + int x, y, z, direction, type, rideIndex, edxRS16; + + // Recheck if area is fine for new track. + // Set by footpath placement + if (_currentTrackSelectionFlags & 8) { + sub_6C9627(); + _currentTrackSelectionFlags &= ~8; + } + + switch (_rideConstructionState) { + case RIDE_CONSTRUCTION_STATE_FRONT: + case RIDE_CONSTRUCTION_STATE_BACK: + if (!(_currentTrackSelectionFlags & 2)) { + if (sub_6CA2DF(&type, &direction, &rideIndex, &edxRS16, &x, &y, &z, NULL)) { + sub_6C96C0(); + } else { + _currentTrackPrice = sub_6CA162(rideIndex, type, direction, edxRS16, x, y, z); + sub_6C84CE(); + } + } + _rideConstructionArrowPulseTime--; + if (_rideConstructionArrowPulseTime >= 0) + break; + + _rideConstructionArrowPulseTime = 5; + _currentTrackSelectionFlags ^= 1; + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; + direction = _currentTrackPieceDirection; + type = _currentTrackPieceType; + 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; + if (direction >= 4) + direction += 4; + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_BACK) + direction ^= 2; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_DIRECTION, uint8) = direction; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~4; + if (_currentTrackSelectionFlags & 1) + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 4; + map_invalidate_tile_full(x, y); + break; + case RIDE_CONSTRUCTION_STATE_SELECTED: + _rideConstructionArrowPulseTime--; + if (_rideConstructionArrowPulseTime >= 0) + break; + + _rideConstructionArrowPulseTime = 5; + _currentTrackSelectionFlags ^= 1; + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; + direction = _currentTrackPieceDirection & 3; + type = _currentTrackPieceType; + if (sub_6C683D(&x, &y, &z, direction, type, 0, NULL, _currentTrackSelectionFlags & 1 ? 2 : 1)) { + sub_6C96C0(); + _rideConstructionState = RIDE_CONSTRUCTION_STATE_0; + } + break; + case 6: + case 7: + case 8: + _rideConstructionArrowPulseTime--; + if (_rideConstructionArrowPulseTime >= 0) + break; + + _rideConstructionArrowPulseTime = 5; + _currentTrackSelectionFlags ^= 1; + x = _currentTrackBeginX & 0xFFE0; + y = _currentTrackBeginY & 0xFFE0; + z = _currentTrackBeginZ + 15; + 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; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_DIRECTION, uint8) = 4; + if (((_currentTrackBeginX & 0x1F) | (_currentTrackBeginY & 0x1F)) != 0) { + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_DIRECTION, uint8) = 6; + if (((_currentTrackBeginX & 0x1F) & (_currentTrackBeginY & 0x1F)) == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_DIRECTION, uint8) = 5; + if ((_currentTrackBeginY & 0x1F) == 0) + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_DIRECTION, uint8) = 7; + } + } + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~4; + if (_currentTrackSelectionFlags & 1) + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 4; + map_invalidate_tile_full(x, y); + break; + } +} + +/** + * + * rct2: 0x006C84E2 + */ +static void window_ride_construction_update_map_selection() +{ + rct_ride *ride; + int trackType, trackDirection, x, y; + + map_invalidate_map_selection_tiles(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 10; + + switch (_rideConstructionState) { + case RIDE_CONSTRUCTION_STATE_0: + trackDirection = _currentTrackPieceDirection; + trackType = 0; + x = _currentTrackBeginX; + y = _currentTrackBeginY; + break; + case RIDE_CONSTRUCTION_STATE_SELECTED: + trackDirection = _currentTrackPieceDirection; + trackType = _currentTrackPieceType; + x = _currentTrackBeginX; + y = _currentTrackBeginY; + break; + default: + if (sub_6CA2DF(&trackType, &trackDirection, NULL, NULL, &x, &y, NULL, NULL)) { + trackDirection = _currentTrackPieceDirection; + trackType = 0; + x = _currentTrackBeginX; + y = _currentTrackBeginY; + } + break; + } + + ride = GET_RIDE(_currentRideIndex); + window_ride_construction_select_map_tiles(ride, trackType, trackDirection, x, y); + map_invalidate_map_selection_tiles(); +} + +/** + * + * rct2: 0x006C8648 + */ +static void window_ride_construction_update_possible_ride_configurations() +{ + rct_ride *ride; + int trackType; + int edx, edi; + + ride = GET_RIDE(_currentRideIndex); + + RCT2_GLOBAL(0x00F440D3, uint8) = 0; + if (_currentTrackCovered & 2) + edi = RCT2_GLOBAL(0x0097D4F5 + (ride->type * 8), uint8); + else + edi = ride->type; + + int currentPossibleRideConfigurationIndex = 0; + _numCurrentPossibleSpecialTrackPieces = 0; + for (trackType = 0; trackType < 256; trackType++) { + edx = ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE) ? + gFlatRideTrackDefinitions[trackType].type : + gTrackDefinitions[trackType].type; + + if (edx == 0) + continue; + + if (edx & 0x80) { + edx &= 0x7F; + if (edx != edi) + continue; + } else if (!is_track_enabled(edx)) { + continue; + } + + int slope, bank; + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_FRONT || _rideConstructionState == RIDE_CONSTRUCTION_STATE_PLACE) { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { + slope = gFlatRideTrackDefinitions[trackType].vangle_start; + bank = gFlatRideTrackDefinitions[trackType].bank_start; + } else { + slope = gTrackDefinitions[trackType].vangle_start; + bank = gTrackDefinitions[trackType].bank_start; + } + } else if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_BACK) { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { + slope = gFlatRideTrackDefinitions[trackType].vangle_end; + bank = gFlatRideTrackDefinitions[trackType].bank_end; + } else { + slope = gTrackDefinitions[trackType].vangle_end; + bank = gTrackDefinitions[trackType].bank_end; + } + } else { + continue; + } + + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { + if ( + gTrackDefinitions[trackType].type == TRACK_HELIX_SMALL || + gTrackDefinitions[trackType].type == TRACK_HELIX_LARGE + ) { + if (bank != _previousTrackBankEnd) { + if (_previousTrackBankEnd != TRACK_BANK_NONE) + continue; + + if (bank != TRACK_BANK_LEFT) + continue; + } + } + } + + if (bank == TRACK_BANK_UPSIDE_DOWN && bank != _previousTrackBankEnd) + continue; + + _currentPossibleRideConfigurations[currentPossibleRideConfigurationIndex] = trackType; + RCT2_GLOBAL(0x00F4409C, uint32) |= (1 << currentPossibleRideConfigurationIndex); + if ( + _currentTrackPieceDirection < 4 && + slope == _previousTrackSlopeEnd && + bank == _previousTrackBankEnd && + (trackType != TRACK_ELEM_TOWER_BASE || ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_29)) + ) { + RCT2_GLOBAL(0x00F4409C, uint32) &= ~(1 << currentPossibleRideConfigurationIndex); + _numCurrentPossibleSpecialTrackPieces++; + } + currentPossibleRideConfigurationIndex++; + } + _numCurrentPossibleRideConfigurations = currentPossibleRideConfigurationIndex; +} + +/** + * + * rct2: 0x006C87F5 + */ +static void window_ride_construction_update_widgets(rct_window *w) +{ + uint8 rideIndex = _currentRideIndex; + rct_ride *ride = GET_RIDE(rideIndex); + int rideType = ride_get_alternative_type(ride); + + w->hold_down_widgets = 0; + if (ride_type_has_flag(rideType, RIDE_TYPE_FLAG_IS_SHOP)) { + window_ride_construction_widgets[WIDX_ENTRANCE_EXIT_GROUPBOX].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_ENTRANCE].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_EXIT].type = WWT_EMPTY; + } else { + window_ride_construction_widgets[WIDX_ENTRANCE_EXIT_GROUPBOX].type = WWT_GROUPBOX; + window_ride_construction_widgets[WIDX_ENTRANCE].type = WWT_DROPDOWN_BUTTON; + window_ride_construction_widgets[WIDX_EXIT].type = WWT_DROPDOWN_BUTTON; + } + + if (_numCurrentPossibleSpecialTrackPieces == 0) { + window_ride_construction_widgets[WIDX_SPECIAL_TRACK_DROPDOWN].type = WWT_EMPTY; + } else { + window_ride_construction_widgets[WIDX_SPECIAL_TRACK_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + } + + if (is_track_enabled(TRACK_STRAIGHT)) { + window_ride_construction_widgets[WIDX_STRAIGHT].type = WWT_FLATBTN; + } else { + window_ride_construction_widgets[WIDX_STRAIGHT].type = WWT_EMPTY; + } + + if (ride_type_has_flag(rideType, RIDE_TYPE_FLAG_30)) { + window_ride_construction_widgets[WIDX_LEFT_CURVE_LARGE].type = WWT_FLATBTN; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_LARGE].type = WWT_FLATBTN; + } else { + window_ride_construction_widgets[WIDX_LEFT_CURVE_LARGE].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_LARGE].type = WWT_EMPTY; + } + + window_ride_construction_widgets[WIDX_LEFT_CURVE].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_RIGHT_CURVE].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_LEFT_CURVE_SMALL].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_SMALL].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_LEFT_CURVE_VERY_SMALL].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_VERY_SMALL].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_LEFT_CURVE_SMALL].left = 28; + window_ride_construction_widgets[WIDX_LEFT_CURVE_SMALL].right = 49; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_SMALL].left = 116; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_SMALL].right = 137; + window_ride_construction_widgets[WIDX_LEFT_CURVE_SMALL].image = 5138; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_SMALL].image = 5139; + if (is_track_enabled(TRACK_CURVE_VERTICAL)) { + window_ride_construction_widgets[WIDX_LEFT_CURVE_SMALL].type = WWT_FLATBTN; + window_ride_construction_widgets[WIDX_LEFT_CURVE_SMALL].left = 6; + window_ride_construction_widgets[WIDX_LEFT_CURVE_SMALL].right = 27; + window_ride_construction_widgets[WIDX_LEFT_CURVE_SMALL].image = 5140; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_SMALL].type = WWT_FLATBTN; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_SMALL].left = 138; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_SMALL].right = 159; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_SMALL].image = 5141; + } + if (is_track_enabled(TRACK_CURVE)) { + window_ride_construction_widgets[WIDX_LEFT_CURVE].type = WWT_FLATBTN; + window_ride_construction_widgets[WIDX_RIGHT_CURVE].type = WWT_FLATBTN; + window_ride_construction_widgets[WIDX_LEFT_CURVE_SMALL].left = 6; + window_ride_construction_widgets[WIDX_LEFT_CURVE_SMALL].right = 27; + window_ride_construction_widgets[WIDX_LEFT_CURVE_SMALL].image = 5140; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_SMALL].left = 138; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_SMALL].right = 159; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_SMALL].image = 5141; + } + if (is_track_enabled(TRACK_CURVE_SMALL)) { + window_ride_construction_widgets[WIDX_LEFT_CURVE_SMALL].type = WWT_FLATBTN; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_SMALL].type = WWT_FLATBTN; + } + if (is_track_enabled(TRACK_CURVE_VERY_SMALL)) { + window_ride_construction_widgets[WIDX_LEFT_CURVE_VERY_SMALL].type = WWT_FLATBTN; + window_ride_construction_widgets[WIDX_RIGHT_CURVE_VERY_SMALL].type = WWT_FLATBTN; + } + + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_SLOPE_DOWN].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_LEVEL].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_SLOPE_UP].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].image = 5144; + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].tooltip = STR_RIDE_CONSTRUCTION_STEEP_SLOPE_DOWN_TIP; + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].image = 5148; + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].tooltip = STR_RIDE_CONSTRUCTION_STEEP_SLOPE_UP_TIP; + if (rideType == RIDE_TYPE_REVERSE_FREEFALL_COASTER || rideType == RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER) { + window_ride_construction_widgets[WIDX_LEVEL].type = WWT_FLATBTN; + window_ride_construction_widgets[WIDX_SLOPE_UP].type = WWT_FLATBTN; + } + if (is_track_enabled(TRACK_SLOPE) || is_track_enabled(TRACK_SLOPE_STEEP)) { + window_ride_construction_widgets[WIDX_LEVEL].type = WWT_FLATBTN; + } + if (is_track_enabled(TRACK_SLOPE)) { + window_ride_construction_widgets[WIDX_SLOPE_DOWN].type = WWT_FLATBTN; + window_ride_construction_widgets[WIDX_SLOPE_UP].type = WWT_FLATBTN; + } + if ( + is_track_enabled(TRACK_HELIX_SMALL) && + _currentTrackBankEnd != TRACK_BANK_NONE && + _currentTrackSlopeEnd == TRACK_SLOPE_NONE + ) { + if (_currentTrackCurve >= TRACK_CURVE_LEFT && _currentTrackCurve <= TRACK_CURVE_RIGHT_SMALL) { + // Enable helix + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].type = WWT_FLATBTN; + if (rideType != RIDE_TYPE_SPLASH_BOATS) + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].type = WWT_FLATBTN; + } + } + + if (is_track_enabled(TRACK_SLOPE_STEEP)) { + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].type = WWT_FLATBTN; + if (rideType != RIDE_TYPE_SPLASH_BOATS) + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].type = WWT_FLATBTN; + } + + int x; + if (is_track_enabled(TRACK_LIFT_HILL) && _currentTrackCurve < 256) { + window_ride_construction_widgets[WIDX_CHAIN_LIFT].type = WWT_FLATBTN; + x = 9; + } else { + window_ride_construction_widgets[WIDX_CHAIN_LIFT].type = WWT_EMPTY; + x = 23; + } + + for (int i = WIDX_SLOPE_DOWN_STEEP; i <= WIDX_SLOPE_UP_STEEP; i++) { + window_ride_construction_widgets[i].left = x; + window_ride_construction_widgets[i].right = x + 23; + x += 24; + } + + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].image = 5148; + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].tooltip = STR_RIDE_CONSTRUCTION_STEEP_SLOPE_UP_TIP; + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].image = 5144; + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].tooltip = STR_RIDE_CONSTRUCTION_STEEP_SLOPE_DOWN_TIP; + if (is_track_enabled(TRACK_SLOPE_VERTICAL)) { + if (_previousTrackSlopeEnd == TRACK_SLOPE_UP_60 || _previousTrackSlopeEnd == TRACK_SLOPE_UP_90) { + int originalSlopeUpSteepLeft = window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].left; + int originalSlopeUpSteepRight = window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].right; + for (int i = WIDX_SLOPE_UP_STEEP; i > WIDX_SLOPE_DOWN_STEEP; i--) { + window_ride_construction_widgets[i].left = window_ride_construction_widgets[i - 1].left; + window_ride_construction_widgets[i].right = window_ride_construction_widgets[i - 1].right; + } + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].left = originalSlopeUpSteepLeft; + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].right = originalSlopeUpSteepRight; + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].image = 5149; + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].tooltip = STR_RIDE_CONSTRUCTION_VERTICAL_RISE_TIP; + } else if (_previousTrackSlopeEnd == TRACK_SLOPE_DOWN_60 || _previousTrackSlopeEnd == TRACK_SLOPE_DOWN_90) { + int originalSlopeDownSteepLeft = window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].left; + int originalSlopeDownSteepRight = window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].right; + for (int i = WIDX_SLOPE_DOWN_STEEP; i < WIDX_SLOPE_UP_STEEP; i++) { + window_ride_construction_widgets[i].left = window_ride_construction_widgets[i + 1].left; + window_ride_construction_widgets[i].right = window_ride_construction_widgets[i + 1].right; + } + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].left = originalSlopeDownSteepLeft; + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].right = originalSlopeDownSteepRight; + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].image = 5150; + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].tooltip = STR_RIDE_CONSTRUCTION_VERTICAL_DROP_TIP; + } + } + + if ( + is_track_enabled(TRACK_HELIX_LARGE_UNBANKED) && + _currentTrackSlopeEnd == TRACK_SLOPE_NONE && + _currentTrackBankEnd == TRACK_BANK_NONE && + (_currentTrackCurve == TRACK_CURVE_LEFT || _currentTrackCurve == TRACK_CURVE_RIGHT) + ) { + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].image = 5151; + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].tooltip = STR_RIDE_CONSTRUCTION_HELIX_DOWN_TIP; + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].image = 5152; + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].tooltip = STR_RIDE_CONSTRUCTION_HELIX_UP_TIP; + + int tmp = window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].left; + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].left = window_ride_construction_widgets[WIDX_SLOPE_DOWN].left; + window_ride_construction_widgets[WIDX_SLOPE_DOWN].left = tmp; + + tmp = window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].right; + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].right = window_ride_construction_widgets[WIDX_SLOPE_DOWN].right; + window_ride_construction_widgets[WIDX_SLOPE_DOWN].right = tmp; + + tmp = window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].right; + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].right = window_ride_construction_widgets[WIDX_SLOPE_UP].right; + window_ride_construction_widgets[WIDX_SLOPE_UP].right = tmp; + } + + if ( + (is_track_enabled(TRACK_HELIX_LARGE) || is_track_enabled(TRACK_HELIX_SMALL)) && + (_currentTrackCurve >= TRACK_CURVE_LEFT && _currentTrackCurve <= TRACK_CURVE_RIGHT_SMALL) && + _currentTrackSlopeEnd == TRACK_SLOPE_NONE && + _currentTrackBankEnd != TRACK_BANK_NONE + ) { + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].image = 5151; + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].tooltip = STR_RIDE_CONSTRUCTION_HELIX_DOWN_TIP; + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].image = 5152; + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].tooltip = STR_RIDE_CONSTRUCTION_HELIX_UP_TIP; + + int tmp = window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].left; + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].left = window_ride_construction_widgets[WIDX_SLOPE_DOWN].left; + window_ride_construction_widgets[WIDX_SLOPE_DOWN].left = tmp; + + tmp = window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].right; + window_ride_construction_widgets[WIDX_SLOPE_DOWN_STEEP].right = window_ride_construction_widgets[WIDX_SLOPE_DOWN].right; + window_ride_construction_widgets[WIDX_SLOPE_DOWN].right = tmp; + + tmp = window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].left; + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].left = window_ride_construction_widgets[WIDX_SLOPE_UP].left; + window_ride_construction_widgets[WIDX_SLOPE_UP].left = tmp; + + tmp = window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].right; + window_ride_construction_widgets[WIDX_SLOPE_UP_STEEP].right = window_ride_construction_widgets[WIDX_SLOPE_UP].right; + window_ride_construction_widgets[WIDX_SLOPE_UP].right = tmp; + } + + window_ride_construction_widgets[WIDX_BANKING_GROUPBOX].image = STR_RIDE_CONSTRUCTION_ROLL_BANKING; + window_ride_construction_widgets[WIDX_BANK_LEFT].image = 5153; + window_ride_construction_widgets[WIDX_BANK_LEFT].tooltip = STR_RIDE_CONSTRUCTION_ROLL_FOR_LEFT_CURVE_TIP; + window_ride_construction_widgets[WIDX_BANK_LEFT].left = 47; + window_ride_construction_widgets[WIDX_BANK_LEFT].right = 70; + window_ride_construction_widgets[WIDX_BANK_LEFT].top = 132; + window_ride_construction_widgets[WIDX_BANK_LEFT].bottom = 155; + window_ride_construction_widgets[WIDX_BANK_STRAIGHT].image = 5154; + window_ride_construction_widgets[WIDX_BANK_STRAIGHT].tooltip = STR_RIDE_CONSTRUCTION_NO_ROLL_TIP; + window_ride_construction_widgets[WIDX_BANK_STRAIGHT].left = 71; + window_ride_construction_widgets[WIDX_BANK_STRAIGHT].right = 94; + window_ride_construction_widgets[WIDX_BANK_STRAIGHT].top = 132; + window_ride_construction_widgets[WIDX_BANK_STRAIGHT].bottom = 155; + window_ride_construction_widgets[WIDX_BANK_RIGHT].image = 5155; + window_ride_construction_widgets[WIDX_BANK_RIGHT].tooltip = STR_RIDE_CONSTRUCTION_ROLL_FOR_RIGHT_CURVE_TIP; + window_ride_construction_widgets[WIDX_BANK_RIGHT].left = 95; + window_ride_construction_widgets[WIDX_BANK_RIGHT].right = 118; + window_ride_construction_widgets[WIDX_BANK_RIGHT].top = 132; + window_ride_construction_widgets[WIDX_BANK_RIGHT].bottom = 155; + window_ride_construction_widgets[WIDX_BANK_LEFT].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_BANK_STRAIGHT].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_BANK_RIGHT].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_U_TRACK].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_O_TRACK].type = WWT_EMPTY; + if (RCT2_GLOBAL(0x00F440D0, uint8) != 99 && _currentTrackCurve != 355) { + if (is_track_enabled(TRACK_FLAT_ROLL_BANKING)) { + window_ride_construction_widgets[WIDX_BANK_LEFT].type = WWT_FLATBTN; + window_ride_construction_widgets[WIDX_BANK_STRAIGHT].type = WWT_FLATBTN; + window_ride_construction_widgets[WIDX_BANK_RIGHT].type = WWT_FLATBTN; + } + if (ride_type_has_flag(rideType, RIDE_TYPE_FLAG_TRACK_ELEMENTS_HAVE_TWO_VARIETIES)) { + if (rideType == RIDE_TYPE_WATER_COASTER) { + window_ride_construction_widgets[WIDX_U_TRACK].image = 5158; + window_ride_construction_widgets[WIDX_O_TRACK].image = 5159; + window_ride_construction_widgets[WIDX_U_TRACK].tooltip = STR_RIDE_CONSTRUCTION_STANDARD_RC_TRACK_TIP; + window_ride_construction_widgets[WIDX_O_TRACK].tooltip = STR_RIDE_CONSTRUCTION_WATER_CHANNEL_TIP; + if (_currentTrackCurve < TRACK_CURVE_LEFT_SMALL && _currentTrackSlopeEnd == TRACK_SLOPE_NONE && _currentTrackBankEnd == TRACK_BANK_NONE) { + window_ride_construction_widgets[WIDX_BANKING_GROUPBOX].image = STR_RIDE_CONSTRUCTION_TRACK_STYLE; + window_ride_construction_widgets[WIDX_U_TRACK].type = WWT_FLATBTN; + window_ride_construction_widgets[WIDX_O_TRACK].type = WWT_FLATBTN; + } + } else { + window_ride_construction_widgets[WIDX_U_TRACK].image = 5156; + window_ride_construction_widgets[WIDX_O_TRACK].image = 5157; + window_ride_construction_widgets[WIDX_U_TRACK].tooltip = STR_RIDE_CONSTRUCTION_U_SHAPED_OPEN_TRACK_TIP; + window_ride_construction_widgets[WIDX_O_TRACK].tooltip = STR_RIDE_CONSTRUCTION_O_SHAPED_ENCLOSED_TRACK_TIP; + window_ride_construction_widgets[WIDX_BANKING_GROUPBOX].image = STR_RIDE_CONSTRUCTION_TRACK_STYLE; + window_ride_construction_widgets[WIDX_U_TRACK].type = WWT_FLATBTN; + window_ride_construction_widgets[WIDX_O_TRACK].type = WWT_FLATBTN; + } + } + } else { + window_ride_construction_widgets[WIDX_BANKING_GROUPBOX].image = STR_RIDE_CONSTRUCTION_BRAKE_SPEED; + RCT2_GLOBAL(0x00F440D3, uint8) = 1; + window_ride_construction_widgets[WIDX_BANK_LEFT].image = 1675; + window_ride_construction_widgets[WIDX_BANK_LEFT].tooltip = STR_RIDE_CONSTRUCTION_BRAKE_SPEED_LIMIT_TIP; + window_ride_construction_widgets[WIDX_BANK_STRAIGHT].tooltip = STR_RIDE_CONSTRUCTION_BRAKE_SPEED_LIMIT_TIP; + window_ride_construction_widgets[WIDX_BANK_RIGHT].tooltip = STR_RIDE_CONSTRUCTION_BRAKE_SPEED_LIMIT_TIP; + window_ride_construction_widgets[WIDX_BANK_LEFT].type = WWT_SPINNER; + window_ride_construction_widgets[WIDX_BANK_LEFT].left = 12; + window_ride_construction_widgets[WIDX_BANK_LEFT].right = 83; + window_ride_construction_widgets[WIDX_BANK_LEFT].top = 138; + window_ride_construction_widgets[WIDX_BANK_LEFT].bottom = 149; + window_ride_construction_widgets[WIDX_BANK_STRAIGHT].type = WWT_DROPDOWN_BUTTON; + window_ride_construction_widgets[WIDX_BANK_STRAIGHT].image = STR_NUMERIC_UP; + window_ride_construction_widgets[WIDX_BANK_STRAIGHT].left = 72; + window_ride_construction_widgets[WIDX_BANK_STRAIGHT].right = 82; + window_ride_construction_widgets[WIDX_BANK_STRAIGHT].top = 139; + window_ride_construction_widgets[WIDX_BANK_STRAIGHT].bottom = 143; + window_ride_construction_widgets[WIDX_BANK_RIGHT].type = WWT_DROPDOWN_BUTTON; + window_ride_construction_widgets[WIDX_BANK_RIGHT].image = STR_NUMERIC_DOWN; + window_ride_construction_widgets[WIDX_BANK_RIGHT].left = 72; + window_ride_construction_widgets[WIDX_BANK_RIGHT].right = 82; + window_ride_construction_widgets[WIDX_BANK_RIGHT].top = 144; + window_ride_construction_widgets[WIDX_BANK_RIGHT].bottom = 148; + w->hold_down_widgets |= (1 << WIDX_BANK_STRAIGHT) | (1 << WIDX_BANK_RIGHT); + } + + window_ride_construction_widgets[WIDX_BANKING_GROUPBOX].right = 162; + window_ride_construction_widgets[WIDX_SEAT_ROTATION_GROUPBOX].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_SEAT_ROTATION_ANGLE_SPINNER].type = 0; + window_ride_construction_widgets[WIDX_SEAT_ROTATION_ANGLE_SPINNER_UP].type = 0; + window_ride_construction_widgets[WIDX_SEAT_ROTATION_ANGLE_SPINNER_DOWN].type = 0; + if ( + (rideType == RIDE_TYPE_MULTI_DIMENSION_ROLLER_COASTER || rideType == RIDE_TYPE_38) && + RCT2_GLOBAL(0x00F440D0, uint8) != 99 && + _currentTrackCurve != 355 + ) { + window_ride_construction_widgets[WIDX_SEAT_ROTATION_GROUPBOX].type = WWT_GROUPBOX; + window_ride_construction_widgets[WIDX_SEAT_ROTATION_ANGLE_SPINNER].type = WWT_SPINNER; + window_ride_construction_widgets[WIDX_SEAT_ROTATION_ANGLE_SPINNER_UP].type = WWT_DROPDOWN_BUTTON; + window_ride_construction_widgets[WIDX_SEAT_ROTATION_ANGLE_SPINNER_DOWN].type = WWT_DROPDOWN_BUTTON; + window_ride_construction_widgets[WIDX_BANKING_GROUPBOX].right = 92; + if (window_ride_construction_widgets[WIDX_BANK_LEFT].type != WWT_SPINNER) { + for (int i = WIDX_BANK_LEFT; i <= WIDX_BANK_RIGHT; i++) { + window_ride_construction_widgets[i].left -= 36; + window_ride_construction_widgets[i].right -= 36; + } + } + } + + uint64 pressedWidgets = w->pressed_widgets & ( + (1 << WIDX_BACKGROUND) | + (1 << WIDX_TITLE) | + (1 << WIDX_CLOSE) | + (1 << WIDX_DIRECTION_GROUPBOX) | + (1 << WIDX_SLOPE_GROUPBOX) | + (1 << WIDX_BANKING_GROUPBOX) | + (1 << WIDX_CONSTRUCT) | + (1 << WIDX_DEMOLISH) | + (1 << WIDX_PREVIOUS_SECTION) | + (1 << WIDX_NEXT_SECTION) | + (1 << WIDX_ENTRANCE_EXIT_GROUPBOX) | + (1 << WIDX_ENTRANCE) | + (1 << WIDX_EXIT) + ); + + window_ride_construction_widgets[WIDX_CONSTRUCT].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_DEMOLISH].type = WWT_FLATBTN; + window_ride_construction_widgets[WIDX_ROTATE].type = WWT_EMPTY; + if (ride_type_has_flag(rideType, RIDE_TYPE_FLAG_CANNOT_HAVE_GAPS)) { + window_ride_construction_widgets[WIDX_PREVIOUS_SECTION].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_NEXT_SECTION].type = WWT_EMPTY; + } else { + window_ride_construction_widgets[WIDX_PREVIOUS_SECTION].type = WWT_FLATBTN; + window_ride_construction_widgets[WIDX_NEXT_SECTION].type = WWT_FLATBTN; + } + + switch (_rideConstructionState) { + case RIDE_CONSTRUCTION_STATE_FRONT: + window_ride_construction_widgets[WIDX_CONSTRUCT].type = WWT_IMGBTN; + window_ride_construction_widgets[WIDX_NEXT_SECTION].type = WWT_EMPTY; + break; + case RIDE_CONSTRUCTION_STATE_BACK: + window_ride_construction_widgets[WIDX_CONSTRUCT].type = WWT_IMGBTN; + window_ride_construction_widgets[WIDX_PREVIOUS_SECTION].type = WWT_EMPTY; + break; + case RIDE_CONSTRUCTION_STATE_PLACE: + window_ride_construction_widgets[WIDX_CONSTRUCT].type = WWT_IMGBTN; + window_ride_construction_widgets[WIDX_DEMOLISH].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_NEXT_SECTION].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_PREVIOUS_SECTION].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_ROTATE].type = WWT_FLATBTN; + break; + case RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT: + window_ride_construction_widgets[WIDX_DEMOLISH].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_NEXT_SECTION].type = WWT_EMPTY; + window_ride_construction_widgets[WIDX_PREVIOUS_SECTION].type = WWT_EMPTY; + break; + default: + w->pressed_widgets = pressedWidgets; + window_invalidate(w); + return; + } + + int widgetIndex; + switch (_currentTrackCurve) { + case TRACK_CURVE_NONE: + widgetIndex = WIDX_STRAIGHT; + break; + case TRACK_CURVE_LEFT: + widgetIndex = WIDX_LEFT_CURVE; + break; + case TRACK_CURVE_RIGHT: + widgetIndex = WIDX_RIGHT_CURVE; + break; + case TRACK_CURVE_LEFT_SMALL: + widgetIndex = WIDX_LEFT_CURVE_SMALL; + break; + case TRACK_CURVE_RIGHT_SMALL: + widgetIndex = WIDX_RIGHT_CURVE_SMALL; + break; + case TRACK_CURVE_LEFT_VERY_SMALL: + widgetIndex = WIDX_LEFT_CURVE_VERY_SMALL; + break; + case TRACK_CURVE_RIGHT_VERY_SMALL: + widgetIndex = WIDX_RIGHT_CURVE_VERY_SMALL; + break; + case TRACK_CURVE_LEFT_LARGE: + widgetIndex = WIDX_LEFT_CURVE_LARGE; + break; + case TRACK_CURVE_RIGHT_LARGE: + widgetIndex = WIDX_RIGHT_CURVE_LARGE; + break; + default: + widgetIndex = WIDX_SPECIAL_TRACK_DROPDOWN; + break; + } + pressedWidgets |= (1ULL << widgetIndex); + + switch (_currentTrackSlopeEnd) { + case TRACK_SLOPE_DOWN_60: + case TRACK_SLOPE_UP_90: + widgetIndex = WIDX_SLOPE_DOWN_STEEP; + break; + case TRACK_SLOPE_DOWN_25: + widgetIndex = WIDX_SLOPE_DOWN; + break; + case TRACK_SLOPE_UP_25: + widgetIndex = WIDX_SLOPE_UP; + break; + case TRACK_SLOPE_UP_60: + case TRACK_SLOPE_DOWN_90: + widgetIndex = WIDX_SLOPE_UP_STEEP; + break; + default: + widgetIndex = WIDX_LEVEL; + break; + } + pressedWidgets |= (1ULL << widgetIndex); + + if (RCT2_GLOBAL(0x00F440D3, uint8) == 0) { + if (ride_type_has_flag(rideType, RIDE_TYPE_FLAG_TRACK_ELEMENTS_HAVE_TWO_VARIETIES)) { + if (_currentTrackCovered & 1) { + w->pressed_widgets |= (1ULL << WIDX_O_TRACK); + } else { + w->pressed_widgets |= (1ULL << WIDX_U_TRACK); + } + } + switch (_currentTrackBankEnd) { + case TRACK_BANK_LEFT: + widgetIndex = WIDX_BANK_LEFT; + break; + case TRACK_BANK_NONE: + widgetIndex = WIDX_BANK_STRAIGHT; + break; + default: + widgetIndex = WIDX_BANK_RIGHT; + break; + } + pressedWidgets |= (1ULL << widgetIndex); + } + + if (_currentTrackLiftHill & 1) + pressedWidgets |= (1 << WIDX_CHAIN_LIFT); + + w->pressed_widgets = pressedWidgets; + window_invalidate(w); +} + +static void window_ride_construction_select_map_tiles(rct_ride *ride, int trackType, int trackDirection, int x, int y) +{ + const rct_preview_track *trackBlock; + int offsetX, offsetY; + + trackBlock = get_track_def_from_ride(ride, trackType); + trackDirection &= 3; + int selectionTileIndex = 0; + while (trackBlock->index != 255) { + switch (trackDirection) { + case 0: + offsetX = trackBlock->x; + offsetY = trackBlock->y; + break; + case 1: + offsetX = trackBlock->y; + offsetY = -trackBlock->x; + break; + case 2: + offsetX = -trackBlock->x; + offsetY = -trackBlock->y; + break; + case 3: + offsetX = -trackBlock->y; + offsetY = trackBlock->x; + break; + } + gMapSelectionTiles[selectionTileIndex].x = x + offsetX; + gMapSelectionTiles[selectionTileIndex].y = y + offsetY; + selectionTileIndex++; + trackBlock++; + } + gMapSelectionTiles[selectionTileIndex].x = -1; + gMapSelectionTiles[selectionTileIndex].y = -1; +} + +/** + * + * rct2: 0x006C776D + */ +static void window_ride_construction_show_special_track_dropdown(rct_window *w, rct_widget *widget) +{ + for (int i = 0; i < _numCurrentPossibleRideConfigurations; i++) { + uint8 trackPiece = _currentPossibleRideConfigurations[i]; + rct_string_id trackPieceStringId = RideConfigurationStringIds[trackPiece]; + if (trackPieceStringId == STR_RAPIDS) { + rct_ride *ride = GET_RIDE(_currentRideIndex); + if (ride->type == RIDE_TYPE_CAR_RIDE) + trackPieceStringId = STR_LOG_BUMPS; + } + gDropdownItemsFormat[i] = trackPieceStringId; + if ((trackPiece | 0x100) == _currentTrackCurve) { + gDropdownHighlightedIndex = i; + } + } + + window_dropdown_show_text_custom_width( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[1], + 0, + _numCurrentPossibleRideConfigurations, + widget->right - widget->left + ); + + gDropdownItemsDisabled = (uint64)RCT2_GLOBAL(0x00F4409C, uint32); +} + +/** + * + * rct2: 0x006C7630 + */ +static void ride_selected_track_set_seat_rotation(int seatRotation) +{ + int x, y, z; + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; + sub_6C683D(&x, &y, &z, _currentTrackPieceDirection & 3, _currentTrackPieceType, seatRotation, NULL, (1 << 5)); + sub_6C84CE(); +} + +/** + * + * rct2: 0x006C7502 + */ +static void loc_6C7502(int al) +{ + _currentTrackSlopeEnd = al; + _currentTrackPrice = MONEY32_UNDEFINED; + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_FRONT) { + if (al != 2 && al != 4 && al != 0) { + _currentTrackLiftHill &= ~1; + } + } + sub_6C84CE(); +} + +/** + * + * rct2: 0x006C76E9 + */ +static void ride_construction_set_brakes_speed(int brakesSpeed) +{ + rct_map_element *mapElement; + int x, y, z; + + x = _currentTrackBeginX; + y = _currentTrackBeginY; + z = _currentTrackBeginZ; + if (!sub_6C683D(&x, &y, &z, _currentTrackPieceDirection & 3, _currentTrackPieceType, 0, &mapElement, 0)) { + game_do_command( + _currentTrackBeginX, + GAME_COMMAND_FLAG_APPLY | ((brakesSpeed) << 8), + _currentTrackBeginY, + mapElement->properties.track.type, + GAME_COMMAND_SET_BRAKES_SPEED, + _currentTrackBeginZ, + 0 + ); + } + sub_6C84CE(); +} + +/** + * + * rct2: 0x006CC6A8 + */ +void ride_construction_toolupdate_construct(int screenX, int screenY) +{ + int x, y, z, highestZ; + rct_ride *ride; + const rct_preview_track *trackBlock; + + map_invalidate_map_selection_tiles(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 | 2 | 4); + if (!ride_get_place_position_from_screen_position(screenX, screenY, &x, &y)) { + sub_6C9627(); + map_invalidate_map_selection_tiles(); + return; + } + + z = _trackPlaceZ; + if (z == 0) + z = map_get_highest_z(x >> 5, y >> 5); + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 2; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~8; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 4; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_DIRECTION, uint8) = _currentTrackPieceDirection; + 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; + gMapSelectionTiles[0].x = x; + gMapSelectionTiles[0].y = y; + gMapSelectionTiles[1].x = -1; + gMapSelectionTiles[1].y = -1; + + int trackType, trackDirection, rideIndex, edxRS16; + if (sub_6CA2DF(&trackType, &trackDirection, &rideIndex, &edxRS16, NULL, NULL, NULL, NULL)) { + sub_6C9627(); + map_invalidate_map_selection_tiles(); + return; + } + _currentTrackPieceType = trackType; + ride = GET_RIDE(_currentRideIndex); + + // Re-using this other code, very slight difference from original + // - Original code checks for MSB mask instead of 255 on trackPart->var_00 + // - Original code checks this first as its already set origin tile, probably just a micro optimisation + window_ride_construction_select_map_tiles(ride, trackType, trackDirection, x, y); + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_Z, uint16) = z; + if (_trackPlaceZ == 0) { + // Raise z above all slopes and water + highestZ = 0; + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & 2) { + rct_xy16 *selectedTile = gMapSelectionTiles; + while (selectedTile->x != -1) { + if (selectedTile->x < (256 * 32) && selectedTile->y < (256 * 32)) { + z = map_get_highest_z(selectedTile->x >> 5, selectedTile->y >> 5); + if (z > highestZ) + highestZ = z; + } + selectedTile++; + } + } + // loc_6CC8BF: + // z = map_get_highest_z(x >> 5, y >> 5); + } + // loc_6CC91B: + trackBlock = get_track_def_from_ride(ride, trackType); + int bx = 0; + do { + bx = min(bx, trackBlock->z); + trackBlock++; + } while (trackBlock->index != 255); + z -= bx; + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_ARROW_Z, uint16) = z; + bx = 41; + _currentTrackBeginX = x; + _currentTrackBeginY = y; + _currentTrackBeginZ = z; + if ( + (_currentTrackSelectionFlags & 2) && + x == _previousTrackPieceX && + y == _previousTrackPieceY && + z == _previousTrackPieceZ + ) { + map_invalidate_map_selection_tiles(); + return; + } + + _previousTrackPieceX = x; + _previousTrackPieceY = y; + _previousTrackPieceZ = z; + if (ride->type == RIDE_TYPE_MAZE) { + for (;;) { + sub_6CA2DF(&trackType, &trackDirection, &rideIndex, &edxRS16, &x, &y, &z, NULL); + _currentTrackPrice = sub_6CA162(rideIndex, trackType, trackDirection, edxRS16, x, y, z); + if (_currentTrackPrice != MONEY32_UNDEFINED) + break; + + bx--; + if (bx == 0) + break; + + _currentTrackBeginZ -= 8; + if (_currentTrackBeginZ & 0x8000) + break; + + if (bx >= 0) + _currentTrackBeginZ += 16; + } + + window_maze_construction_update_pressed_widgets(); + map_invalidate_map_selection_tiles(); + return; + } + + for (;;) { + sub_6CA2DF(&trackType, &trackDirection, &rideIndex, &edxRS16, &x, &y, &z, NULL); + _currentTrackPrice = sub_6CA162(rideIndex, trackType, trackDirection, edxRS16, x, y, z); + if (_currentTrackPrice != MONEY32_UNDEFINED) + break; + + bx--; + if (bx == 0) + break; + + _currentTrackBeginZ -= 8; + if (_currentTrackBeginZ & 0x8000) + break; + + if (bx >= 0) + _currentTrackBeginZ += 16; + } + + sub_6C84CE(); + map_invalidate_map_selection_tiles(); +} + +/** + * + * rct2: 0x006CD354 + */ +void ride_construction_toolupdate_entrance_exit(int screenX, int screenY) +{ + int x, y, direction; + uint8 unk; + + map_invalidate_selection_rect(); + map_invalidate_map_selection_tiles(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 | 2 | 4); + ride_get_entrance_or_exit_position_from_screen_position(screenX, screenY, &x, &y, &direction); + if (RCT2_GLOBAL(0x00F44194, uint8) == 255) { + sub_6C9627(); + return; + } + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 1 | 4; + 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_ARROW_DIRECTION, uint8) = direction ^ 2; + 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) = RCT2_GLOBAL(0x00F44190, uint8) * 8; + map_invalidate_selection_rect(); + + direction = RCT2_GLOBAL(0x00F44194, uint8) ^ 2; + unk = RCT2_GLOBAL(0x00F44193, uint8); + if ( + !(_currentTrackSelectionFlags & 4) || + x != RCT2_GLOBAL(0x00F440BF, uint16) || + y != RCT2_GLOBAL(0x00F440C1, uint16) || + direction != RCT2_GLOBAL(0x00F440C3, uint8) || + unk != RCT2_GLOBAL(0x00F440C4, uint8) + ) { + _currentTrackPrice = ride_get_entrance_or_exit_price( + _currentRideIndex, x, y, direction, RCT2_GLOBAL(0x00F44191, uint8), unk + ); + sub_6C84CE(); + } +} + +/** + * + * rct2: 0x006CCA73 + */ +void ride_construction_tooldown_construct(int screenX, int screenY) +{ + int trackType, trackDirection, rideIndex, edxRS16, x, y, z, properties, highestZ; + rct_window *w; + + map_invalidate_map_selection_tiles(); + sub_6C9627(); + + if (sub_6CA2DF(&trackType, &trackDirection, &rideIndex, &edxRS16, &x, &y, &z, &properties)) + return; + + _currentTrackPieceType = trackType; + + // Raise z above all slopes and water + highestZ = 0; + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) & 2) { + rct_xy16 *selectedTile = gMapSelectionTiles; + while (selectedTile->x != -1) { + if (selectedTile->x >= (256 * 32) || selectedTile->y >= (256 * 32)) + continue; + + z = map_get_highest_z(selectedTile->x >> 5, selectedTile->y >> 5); + if (z > highestZ) + highestZ = z; + + selectedTile++; + } + } + + RCT2_GLOBAL(0x00F440E2, uint16) = z; + + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 | 2 | 4); + if (!ride_get_place_position_from_screen_position(screenX, screenY, &x, &y)) + return; + + z = _trackPlaceZ; + if (z == 0) + z = map_get_highest_z(x >> 5, y >> 5); + + tool_cancel(); + + rct_ride *ride = GET_RIDE(_currentRideIndex); + if (_trackPlaceZ == 0) { + const rct_preview_track *trackBlock = get_track_def_from_ride(ride, _currentTrackPieceType); + int bx = 0; + do { + bx = min(bx, trackBlock->z); + trackBlock++; + } while (trackBlock->index != 255); 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; + + // FIX not sure exactly why it starts trial and error place from a lower Z, but it causes issues with disable clearance + if (!gCheatsDisableClearanceChecks) { + z -= 16; + } + } else { + z = _trackPlaceZ; + } + + if (ride->type == RIDE_TYPE_MAZE) { + for (int zAttempts = 41; zAttempts >= 0; zAttempts--) { + _rideConstructionState = RIDE_CONSTRUCTION_STATE_MAZE_BUILD; + _currentTrackBeginX = x; + _currentTrackBeginY = y; + _currentTrackBeginZ = z; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; + window_maze_construction_update_pressed_widgets(); + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w == NULL) + break; + + RCT2_GLOBAL(0x009A8C29, uint8) |= 1; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_RIDE_CONSTRUCTION_CANT_CONSTRUCT_THIS_HERE; + RCT2_GLOBAL(0x00F44074, money32) = game_do_command( + _currentTrackBeginX, + GAME_COMMAND_FLAG_APPLY | (4 << 8), + _currentTrackBeginY, + _currentRideIndex, + GAME_COMMAND_SET_MAZE_TRACK, + _currentTrackBeginZ, + 0); + + RCT2_GLOBAL(0x009A8C29, uint8) &= ~1; + + if (RCT2_GLOBAL(0x00F44074, money32) == MONEY32_UNDEFINED) { + rct_string_id errorText = RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id); + z -= 8; + if ( + errorText == STR_NOT_ENOUGH_CASH_REQUIRES || + errorText == STR_CAN_ONLY_BUILD_THIS_UNDERWATER || + errorText == STR_CAN_ONLY_BUILD_THIS_ON_WATER || + errorText == STR_RIDE_CANT_BUILD_THIS_UNDERWATER || + errorText == STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND || + errorText == STR_TOO_HIGH_FOR_SUPPORTS || + zAttempts == 0 || + z < 0 + ) { + audio_play_sound_panned(SOUND_ERROR, RCT2_GLOBAL(0x0142406C, sint32), x, y, z); + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != NULL){ + tool_set(w, 23, 12); + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= (1 << 6); + RCT2_GLOBAL(0x00F44159, uint8) = 0; + RCT2_GLOBAL(0x00F4415C, uint8) = 0; + } + window_maze_construction_update_pressed_widgets(); + break; + } + else if (zAttempts >= 0) { + z += 16; + } + } + else { + window_close_by_class(WC_ERROR); + audio_play_sound_at_location(SOUND_PLACE_ITEM, _currentTrackBeginX, _currentTrackBeginY, _currentTrackBeginZ); + break; + } + } + return; + } + + for (int zAttempts = 41; zAttempts >= 0; zAttempts--) { + _rideConstructionState = RIDE_CONSTRUCTION_STATE_FRONT; + _currentTrackBeginX = x; + _currentTrackBeginY = y; + _currentTrackBeginZ = z; + _currentTrackSelectionFlags = 0; + _rideConstructionArrowPulseTime = 0; + sub_6C84CE(); + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w == NULL) 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; + + RCT2_GLOBAL(0x009A8C29, uint8) |= 1; + window_event_mouse_up_call(w, WIDX_CONSTRUCT); + RCT2_GLOBAL(0x009A8C29, uint8) &= ~1; + + if (RCT2_GLOBAL(0x00F44074, money32) == MONEY32_UNDEFINED) { + rct_string_id errorText = RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id); + z -= 8; + if ( + errorText == STR_NOT_ENOUGH_CASH_REQUIRES || + errorText == STR_CAN_ONLY_BUILD_THIS_UNDERWATER || + errorText == STR_CAN_ONLY_BUILD_THIS_ON_WATER || + errorText == STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND || + errorText == STR_TOO_HIGH_FOR_SUPPORTS || + zAttempts == 0 || + z < 0 + ) { + int saveTrackDirection = _currentTrackPieceDirection; + int saveCurrentTrackCurve = _currentTrackCurve; + int savePreviousTrackSlopeEnd = _previousTrackSlopeEnd; + int saveCurrentTrackSlopeEnd = _currentTrackSlopeEnd; + int savePreviousTrackBankEnd = _previousTrackBankEnd; + int saveCurrentTrackBankEnd = _currentTrackBankEnd; + int saveCurrentTrackCovered = _currentTrackCovered; + int saveCurrentTrackLiftHill = _currentTrackLiftHill; + + sub_6CC3FB(_currentRideIndex); + + _currentTrackPieceDirection = saveTrackDirection; + _currentTrackCurve = saveCurrentTrackCurve; + _previousTrackSlopeEnd = savePreviousTrackSlopeEnd; + _currentTrackSlopeEnd = saveCurrentTrackSlopeEnd; + _previousTrackBankEnd = savePreviousTrackBankEnd; + _currentTrackBankEnd = saveCurrentTrackBankEnd; + _currentTrackCovered = saveCurrentTrackCovered; + _currentTrackLiftHill = saveCurrentTrackLiftHill; + + audio_play_sound_panned(SOUND_ERROR, RCT2_GLOBAL(0x0142406C, sint32), x, y, z); + break; + } else if (zAttempts >= 0) { + z += 16; + } + } else { + window_close_by_class(WC_ERROR); + if (_rideConstructionState == RIDE_CONSTRUCTION_STATE_0) { + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != NULL) { + if (ride_are_all_possible_entrances_and_exits_built(ride)) { + window_close(w); + } else { + window_event_mouse_up_call(w, WIDX_ENTRANCE); + } + } + } 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() +/** + * + * rct2: 0x006CCA73 + */ +static void ride_construction_tooldown_entrance_exit(int screenX, int screenY) { - rct_window *w; - rct_drawpixelinfo *dpi; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); -} \ No newline at end of file + sub_6C9627(); + map_invalidate_selection_rect(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 | 4); + + int mapX, mapY, direction; + ride_get_entrance_or_exit_position_from_screen_position(screenX, screenY, &mapX, &mapY, &direction); + if (RCT2_GLOBAL(0x00F44194, uint8) == 255) + return; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = (RCT2_GLOBAL(0x00F44191, uint8) == 0) ? + STR_CANT_BUILD_MOVE_ENTRANCE_FOR_THIS_RIDE_ATTRACTION : + STR_CANT_BUILD_MOVE_EXIT_FOR_THIS_RIDE_ATTRACTION; + + money32 cost = game_do_command( + RCT2_GLOBAL(0x00F44188, uint16), + (GAME_COMMAND_FLAG_APPLY) | ((RCT2_GLOBAL(0x00F44194, uint8) ^ 2) << 8), + RCT2_GLOBAL(0x00F4418A, uint16), + RCT2_GLOBAL(0x00F44192, uint8) | (RCT2_GLOBAL(0x00F44191, uint8) << 8), + GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT, + RCT2_GLOBAL(0x00F44193, uint8), + 0 + ); + if (cost == MONEY32_UNDEFINED) { + return; + } + + audio_play_sound_at_location( + SOUND_PLACE_ITEM, + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16), + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16), + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) + ); + + rct_ride *ride = GET_RIDE(RCT2_GLOBAL(0x00F44192, uint8)); + if (ride_are_all_possible_entrances_and_exits_built(ride)) { + tool_cancel(); + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_15)) { + window_close_by_class(WC_RIDE_CONSTRUCTION); + } + } else { + RCT2_GLOBAL(0x00F44191, uint8) ^= 1; + window_invalidate_by_class(77); + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) = (RCT2_GLOBAL(0x00F44191, uint8) == 0) ? + WIDX_ENTRANCE : WIDX_EXIT; + } +} diff --git a/src/windows/ride_list.c b/src/windows/ride_list.c index c70fb45ac0..b557ca0f1c 100644 --- a/src/windows/ride_list.c +++ b/src/windows/ride_list.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 . *****************************************************************************/ @@ -71,46 +71,45 @@ static rct_widget window_ride_list_widgets[] = { { WIDGETS_END }, }; -static void window_ride_list_emptysub() { } -static void window_ride_list_mouseup(); -static void window_ride_list_resize(); +static void window_ride_list_mouseup(rct_window *w, int widgetIndex); +static void window_ride_list_resize(rct_window *w); static void window_ride_list_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_ride_list_dropdown(); +static void window_ride_list_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_ride_list_update(rct_window *w); -static void window_ride_list_scrollgetsize(); -static void window_ride_list_scrollmousedown(); -static void window_ride_list_scrollmouseover(); -static void window_ride_list_tooltip(); -static void window_ride_list_invalidate(); -static void window_ride_list_paint(); -static void window_ride_list_scrollpaint(); +static void window_ride_list_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_ride_list_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_ride_list_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_ride_list_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_ride_list_invalidate(rct_window *w); +static void window_ride_list_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_ride_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void* window_ride_list_events[] = { - window_ride_list_emptysub, +static rct_window_event_list window_ride_list_events = { + NULL, window_ride_list_mouseup, window_ride_list_resize, window_ride_list_mousedown, window_ride_list_dropdown, - window_ride_list_emptysub, + NULL, window_ride_list_update, - window_ride_list_emptysub, - window_ride_list_emptysub, - window_ride_list_emptysub, - window_ride_list_emptysub, - window_ride_list_emptysub, - window_ride_list_emptysub, - window_ride_list_emptysub, - window_ride_list_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_ride_list_scrollgetsize, window_ride_list_scrollmousedown, - window_ride_list_emptysub, + NULL, window_ride_list_scrollmouseover, - window_ride_list_emptysub, - window_ride_list_emptysub, - window_ride_list_emptysub, + NULL, + NULL, + NULL, window_ride_list_tooltip, - window_ride_list_emptysub, - window_ride_list_emptysub, + NULL, + NULL, window_ride_list_invalidate, window_ride_list_paint, window_ride_list_scrollpaint @@ -136,7 +135,7 @@ static void window_ride_list_close_all(rct_window *w); static void window_ride_list_open_all(rct_window *w); /** - * + * * rct2: 0x006B30BC */ void window_ride_list_open() @@ -146,7 +145,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, WF_10 | WF_RESIZABLE); + window = window_create_auto_pos(340, 240, &window_ride_list_events, WC_RIDE_LIST, WF_10 | WF_RESIZABLE); window->widgets = window_ride_list_widgets; window->enabled_widgets = (1 << WIDX_CLOSE) | @@ -174,16 +173,11 @@ void window_ride_list_open() } /** - * + * * rct2: 0x006B3511 */ -static void window_ride_list_mouseup() +static void window_ride_list_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -201,8 +195,9 @@ static void window_ride_list_mouseup() 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; + if (w->page != PAGE_RIDES && _window_ride_list_information_type > INFORMATION_TYPE_PROFIT) { + _window_ride_list_information_type = INFORMATION_TYPE_STATUS; + } window_invalidate(w); } break; @@ -216,15 +211,11 @@ static void window_ride_list_mouseup() } /** - * + * * rct2: 0x006B38A7 */ -static void window_ride_list_resize() +static void window_ride_list_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - w->min_width = 340; w->min_height = 124; if (w->width < w->min_width) { @@ -240,12 +231,12 @@ static void window_ride_list_resize() } /** - * + * * rct2: 0x006B3532 */ static void window_ride_list_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) { - int numItems, i; + int currentItem, lastItem, count; if (widgetIndex == WIDX_OPEN_CLOSE_ALL) { gDropdownItemsFormat[0] = STR_CLOSE_ALL; @@ -254,40 +245,38 @@ static void window_ride_list_mousedown(int widgetIndex, rct_window*w, rct_widget } else if (widgetIndex == WIDX_INFORMATION_TYPE_DROPDOWN) { widget--; - numItems = 9; - if (w->page != PAGE_RIDES) - numItems -= 5; - if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) - numItems--; + if (w->page == PAGE_RIDES) + lastItem = STR_GUESTS_FAVOURITE; + else + lastItem = STR_PROFIT; + + for (count = 0, currentItem = STR_STATUS; currentItem <= lastItem; currentItem++) { + if ((RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) && (currentItem == STR_PROFIT)) + continue; + gDropdownItemsFormat[count] = 1142; + gDropdownItemsArgs[count] = currentItem; + count++; + } - for (i = 0; i < numItems; i++) { - 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], DROPDOWN_FLAG_STAY_OPEN, - numItems, + count, widget->right - widget->left - 3 ); - gDropdownItemsChecked |= (1 << _window_ride_list_information_type); + dropdown_set_checked(_window_ride_list_information_type, true); } } /** - * + * * rct2: 0x006B3547 */ -static void window_ride_list_dropdown() +static void window_ride_list_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - short dropdownIndex, widgetIndex; - rct_window *w; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (widgetIndex == WIDX_OPEN_CLOSE_ALL) { if (dropdownIndex == 0) window_ride_list_close_all(w); @@ -303,7 +292,7 @@ static void window_ride_list_dropdown() } /** - * + * * rct2: 0x006B386B */ static void window_ride_list_update(rct_window *w) @@ -315,45 +304,35 @@ static void window_ride_list_update(rct_window *w) } /** - * + * * rct2: 0x006B35A1 */ -static void window_ride_list_scrollgetsize() +static void window_ride_list_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - int top, width, height; - rct_window *w; - - window_get_register(w); + int top; - height = w->no_list_items * 10; + *height = w->no_list_items * 10; if (w->selected_list_item != -1) { w->selected_list_item = -1; window_invalidate(w); } - top = height - window_ride_list_widgets[WIDX_LIST].bottom + window_ride_list_widgets[WIDX_LIST].top + 21; + top = *height - window_ride_list_widgets[WIDX_LIST].bottom + window_ride_list_widgets[WIDX_LIST].top + 21; if (top < 0) top = 0; if (top < w->scrolls[0].v_top) { w->scrolls[0].v_top = top; window_invalidate(w); } - - width = 0; - window_scrollsize_set_registers(width, height); } /** - * + * * rct2: 0x006B361F */ -static void window_ride_list_scrollmousedown() +static void window_ride_list_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) { int index; - short x, y, scrollIndex; - rct_window *w; - - window_scrollmouse_get_registers(w, scrollIndex, x, y); index = y / 10; if (index >= w->no_list_items) @@ -364,16 +343,12 @@ static void window_ride_list_scrollmousedown() } /** - * + * * rct2: 0x006B35EF */ -static void window_ride_list_scrollmouseover() +static void window_ride_list_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) { int index; - short x, y, scrollIndex; - rct_window *w; - - window_scrollmouse_get_registers(w, scrollIndex, x, y); index = y / 10; if (index >= w->no_list_items) @@ -384,25 +359,23 @@ static void window_ride_list_scrollmouseover() } /** - * + * * rct2: 0x006B3861 */ -static void window_ride_list_tooltip() +static void window_ride_list_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) { - RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = STR_LIST; } /** - * + * * rct2: 0x006B3182 */ -static void window_ride_list_invalidate() +static void window_ride_list_invalidate(rct_window *w) { 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; @@ -434,7 +407,7 @@ static void window_ride_list_invalidate() 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) { @@ -460,34 +433,25 @@ static void window_ride_list_invalidate() } /** - * + * * rct2: 0x006B3235 */ -static void window_ride_list_paint() +static void window_ride_list_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); window_ride_list_draw_tab_images(dpi, w); } /** - * + * * rct2: 0x006B3240 */ -static void window_ride_list_scrollpaint() +static void window_ride_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { int i, y, format, formatSecondary, argument; - rct_window *w; - rct_drawpixelinfo *dpi; rct_ride *ride; - window_paint_get_registers(w, dpi); - - gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width, dpi->y + dpi->height, RCT2_GLOBAL(0x0141FC48 + (w->colours[1] * 8), uint8)); + gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width, dpi->y + dpi->height, ColourMapA[w->colours[1]].mid_light); y = 0; for (i = 0; i < w->no_list_items; i++) { @@ -498,7 +462,7 @@ static void window_ride_list_scrollpaint() gfx_fill_rect(dpi, 0, y, 800, y + 9, 0x02000031); format = 1193; } - + // Get ride ride = &g_ride_list[w->list_item_positions[i]]; @@ -572,14 +536,14 @@ static void window_ride_list_scrollpaint() if (formatSecondary == STR_BROKEN_DOWN || formatSecondary == STR_CRASHED) format = 1192; - RCT2_GLOBAL(0x013CE952, uint16) = formatSecondary; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = formatSecondary; gfx_draw_string_left_clipped(dpi, format, (void*)0x013CE952, 0, 160, y - 1, 157); y += 10; } } /** - * + * * rct2: 0x006B38EA */ static void window_ride_list_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w) @@ -608,13 +572,14 @@ static void window_ride_list_draw_tab_images(rct_drawpixelinfo *dpi, rct_window /** - * + * * rct2: 0x006B39A8 */ static void window_ride_list_refresh_list(rct_window *w) { int i, countA, countB; rct_ride *ride, *otherRide; + char *bufferA, *bufferB; countA = countB = 0; FOR_ALL_RIDES(i, ride) { @@ -627,7 +592,7 @@ static void window_ride_list_refresh_list(rct_window *w) countB++; } } - + if (countB != 0) window_invalidate(w); @@ -644,13 +609,13 @@ static void window_ride_list_refresh_list(rct_window *w) int current_list_position = list_index; switch (w->list_information_type) { case INFORMATION_TYPE_STATUS: - RCT2_GLOBAL(0x013CE952, uint32) = ride->name_arguments; - RCT2_CALLPROC_X(0x006C2538, ride->name, 0, 0x013CE952, 0, 0, RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, 0); + bufferA = (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER; + bufferB = (char*)0x0141EF68; + format_string_to_upper(bufferA, ride->name, &ride->name_arguments); while (--current_list_position >= 0) { otherRide = &g_ride_list[w->list_item_positions[current_list_position]]; - RCT2_GLOBAL(0x013CE952, uint32) = otherRide->name_arguments; - RCT2_CALLPROC_X(0x006C2538, otherRide->name, 0, 0x013CE952, 0, 0, 0x0141EF68, 0); - if (strcmp((char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, (char*)0x0141EF68) >= 0) + format_string_to_upper(bufferB, otherRide->name, &otherRide->name_arguments); + if (strcmp(bufferA, bufferB) >= 0) break; window_bubble_list_item(w, current_list_position); diff --git a/src/windows/save_prompt.c b/src/windows/save_prompt.c index 61f5f40419..1b05645b3f 100644 --- a/src/windows/save_prompt.c +++ b/src/windows/save_prompt.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 . *****************************************************************************/ @@ -68,41 +68,41 @@ static rct_widget window_quit_prompt_widgets[] = { { WIDGETS_END }, }; -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_close(rct_window *w); +static void window_save_prompt_mouseup(rct_window *w, int widgetIndex); +static void window_save_prompt_invalidate(rct_window *w); +static void window_save_prompt_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_save_prompt_callback(int result); -static void* window_save_prompt_events[] = { +static rct_window_event_list window_save_prompt_events = { window_save_prompt_close, window_save_prompt_mouseup, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, - window_save_prompt_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_save_prompt_invalidate, window_save_prompt_paint, - window_save_prompt_emptysub + NULL }; /** @@ -147,7 +147,7 @@ void window_save_prompt_open() } } - if (RCT2_GLOBAL(0x009DEA66, uint16) < 3840) { + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, uint16) < 3840) { game_load_or_quit_no_save_prompt(); return; } @@ -181,7 +181,7 @@ void window_save_prompt_open() window = window_create_centred( width, height, - (uint32*)window_save_prompt_events, + &window_save_prompt_events, WC_SAVE_PROMPT, WF_TRANSPARENT | WF_STICK_TO_FRONT ); @@ -192,7 +192,7 @@ void window_save_prompt_open() // Pause the game RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) |= 2; - pause_sounds(); + audio_pause_sounds(); window_invalidate_by_class(WC_TOP_TOOLBAR); stringId = prompt_mode + STR_LOAD_GAME_PROMPT_TITLE; @@ -208,11 +208,11 @@ void window_save_prompt_open() * * rct2: 0x0066DF17 */ -static void window_save_prompt_close() +static void window_save_prompt_close(rct_window *w) { // Unpause the game RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) &= ~2; - unpause_sounds(); + audio_unpause_sounds(); window_invalidate_by_class(WC_TOP_TOOLBAR); } @@ -220,13 +220,8 @@ static void window_save_prompt_close() * * rct2: 0x0066DDF2 */ -static void window_save_prompt_mouseup() +static void window_save_prompt_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - 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: @@ -241,11 +236,9 @@ static void window_save_prompt_mouseup() } else { switch (widgetIndex) { case WIDX_SAVE: - if (!save_game()) { - // user pressed cancel - window_close(w); - return; - } + save_game_as(); + window_close(w); + gLoadSaveCallback = window_save_prompt_callback; break; case WIDX_DONT_SAVE: game_load_or_quit_no_save_prompt(); @@ -268,27 +261,21 @@ static void window_save_prompt_mouseup() return; } } - - if (RCT2_GLOBAL(0x009DEA66, uint16) < 3840) { - game_load_or_quit_no_save_prompt(); - return; - } } -static void window_save_prompt_invalidate() +static void window_save_prompt_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); } -static void window_save_prompt_paint() +static void window_save_prompt_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); +} + +static void window_save_prompt_callback(int result) +{ + if (result == MODAL_RESULT_OK) { + game_load_or_quit_no_save_prompt(); + } } \ No newline at end of file diff --git a/src/windows/scenery.c b/src/windows/scenery.c index aa495fd77b..8ca4deebd2 100644 --- a/src/windows/scenery.c +++ b/src/windows/scenery.c @@ -62,48 +62,47 @@ enum { WINDOW_SCENERY_TAB_20 }; -static void window_scenery_emptysub() { } -static void window_scenery_close(); -static void window_scenery_mouseup(); -static void window_scenery_resize(); +static void window_scenery_close(rct_window *w); +static void window_scenery_mouseup(rct_window *w, int widgetIndex); +static void window_scenery_resize(rct_window *w); static void window_scenery_mousedown(int widgetIndex, rct_window* w, rct_widget* widget); -static void window_scenery_dropdown(); +static void window_scenery_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_scenery_update(rct_window *w); -static void window_scenery_event_07(); -static void window_scenery_scrollgetsize(); -static void window_scenery_scrollmousedown(); -static void window_scenery_scrollmouseover(); -static void window_scenery_tooltip(); -static void window_scenery_invalidate(); -static void window_scenery_paint(); -static void window_scenery_scrollpaint(); +static void window_scenery_event_07(rct_window *w); +static void window_scenery_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_scenery_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_scenery_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_scenery_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_scenery_invalidate(rct_window *w); +static void window_scenery_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_scenery_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void* window_scenery_events[] = { +static rct_window_event_list window_scenery_events = { window_scenery_close, window_scenery_mouseup, window_scenery_resize, window_scenery_mousedown, window_scenery_dropdown, - window_scenery_emptysub, + NULL, window_scenery_update, window_scenery_event_07, - window_scenery_emptysub, - window_scenery_emptysub, - window_scenery_emptysub, - window_scenery_emptysub, - window_scenery_emptysub, - window_scenery_emptysub, - window_scenery_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_scenery_scrollgetsize, window_scenery_scrollmousedown, - window_scenery_emptysub, + NULL, window_scenery_scrollmouseover, - window_scenery_emptysub, - window_scenery_emptysub, - window_scenery_emptysub, + NULL, + NULL, + NULL, window_scenery_tooltip, - window_scenery_emptysub, - window_scenery_emptysub, + NULL, + NULL, window_scenery_invalidate, window_scenery_paint, window_scenery_scrollpaint, @@ -189,7 +188,7 @@ void window_scenery_update_scroll(rct_window *w); * 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 (RCT2_ADDRESS(0x01357BD0, sint32)[index >> 5] & (1u << (index & 0x1F))) { if (sceneryTabId != 0xFF) { for (int i = 0; i < SCENERY_ENTRIES_BY_TAB; i++) { if (window_scenery_tab_entries[sceneryTabId][i] == -1) @@ -247,7 +246,7 @@ void init_scenery() for (int i = 0; i < scenerySetEntry->entry_count; i++) { uint16 sceneryEntryId = scenerySetEntry->scenery_entries[i]; uint32 ecx = RCT2_ADDRESS(0x01357BD0, uint32)[sceneryEntryId >> 5]; - uint32 edx = 1 << (sceneryEntryId & 0x1F); + uint32 edx = 1u << (sceneryEntryId & 0x1F); if (ecx & edx) { window_scenery_tab_entries[scenerySetIndex][sceneryTabEntryCount] = sceneryEntryId; window_scenery_tab_entries[scenerySetIndex][++sceneryTabEntryCount] = -1; @@ -257,7 +256,7 @@ void init_scenery() } } - // small scenery + // small scenery for (uint16 sceneryId = 0; sceneryId < 0xFC; sceneryId++) { if ((uint32)g_smallSceneryEntries[sceneryId] == 0xFFFFFFFF) continue; @@ -313,11 +312,11 @@ void init_scenery() for (int widgetIndex = WIDX_SCENERY_TAB_1; widgetIndex < WIDX_SCENERY_LIST; widgetIndex++) window_scenery_widgets[widgetIndex].type = 0; - uint8 tabIndexes[0x13]; - uint8 order[0x13]; + uint8 tabIndexes[20]; + uint8 order[20]; int usedValues = 0; - for (int scenerySetId = 0; scenerySetId < 0x13; scenerySetId++) { + for (int scenerySetId = 0; scenerySetId < 19; scenerySetId++) { rct_scenery_set_entry* sceneryEntry = g_scenerySetEntries[scenerySetId]; if ((uint32)sceneryEntry == 0xFFFFFFFF) continue; @@ -346,7 +345,7 @@ void init_scenery() break; } - tabIndexes[usedValues] = 0x13; + tabIndexes[usedValues] = 19; usedValues++; uint16 left = 3; @@ -354,7 +353,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 != 19) { if (window_scenery_tab_entries[tabIndex][0] == -1) continue; @@ -367,7 +366,7 @@ void init_scenery() tabWidget->right = left + 0x1E; left += 0x1F; - if (tabIndex >= 0x13) + if (tabIndex >= 19) continue; tabWidget->image = g_scenerySetEntries[tabIndex]->image | 0x20000000; @@ -423,13 +422,13 @@ void window_scenery_open() init_scenery(); window = window_create( - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - WINDOW_SCENERY_WIDTH, + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - WINDOW_SCENERY_WIDTH, 0x1D, WINDOW_SCENERY_WIDTH, WINDOW_SCENERY_HEIGHT, - (uint32*)window_scenery_events, + &window_scenery_events, WC_SCENERY, - WF_2 + WF_NO_SCROLLING ); window->widgets = window_scenery_widgets; @@ -471,9 +470,9 @@ void window_scenery_open() 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) = MONEY32_UNDEFINED; - RCT2_GLOBAL(0x00F64EC0, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_COST, uint32) = MONEY32_UNDEFINED; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_ROTATION, 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 @@ -503,11 +502,8 @@ bool window_scenery_is_scenery_tool_active() { * * rct2: 0x006E1A73 */ -void window_scenery_close() { - rct_window *w; - - window_get_register(w); - +void window_scenery_close(rct_window *w) +{ scenery_remove_ghost_tool_placement(); hide_gridlines(); viewport_set_visibility(0); @@ -534,13 +530,8 @@ int window_scenery_scrollgetsize_num() * * rct2: 0x006BD94C */ -static void window_scenery_mouseup() +static void window_scenery_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_SCENERY_CLOSE: window_close(w); @@ -595,12 +586,8 @@ void window_scenery_update_scroll(rct_window *w) * * rct2: 0x006E1E48 */ -static void window_scenery_resize() +static void window_scenery_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - if (w->width < w->min_width) { window_invalidate(w); w->width = w->min_width; @@ -652,7 +639,7 @@ 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) = MONEY32_UNDEFINED; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_COST, uint32) = MONEY32_UNDEFINED; window_scenery_update_scroll(w); } } @@ -661,11 +648,8 @@ static void window_scenery_mousedown(int widgetIndex, rct_window* w, rct_widget* * * rct2: 0x006E1A54 */ -static void window_scenery_dropdown() { - rct_window* w; - short widgetIndex, dropdownIndex; - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - +static void window_scenery_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) +{ if (dropdownIndex == -1) return; @@ -686,11 +670,8 @@ static void window_scenery_dropdown() { * * rct2: 0x006E1B9F */ -static void window_scenery_event_07() { - rct_window *w; - - window_get_register(w); - +static void window_scenery_event_07(rct_window *w) +{ if (w->scenery.selected_scenery_id != -1) { w->scenery.selected_scenery_id = -1; } @@ -741,7 +722,7 @@ static void window_scenery_update(rct_window *w) } window_invalidate(w); - + if (!window_scenery_is_scenery_tool_active()){ window_close(w); return; @@ -777,14 +758,9 @@ static void window_scenery_update(rct_window *w) * * rct2: 0x006E1A91 */ -void window_scenery_scrollgetsize() +void window_scenery_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - int width, height; - - width = 0; - height = window_scenery_scrollgetsize_num(); - - window_scrollsize_set_registers(width, height); + *height = window_scenery_scrollgetsize_num(); } short get_scenery_id_by_cursor_pos(short x, short y) @@ -809,13 +785,8 @@ short get_scenery_id_by_cursor_pos(short x, short y) * * rct2: 0x006E1C4A */ -void window_scenery_scrollmousedown() +void window_scenery_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) { - short x, y, scrollIndex; - rct_window *w; - - window_scrollmouse_get_registers(w, scrollIndex, x, y); - short sceneryId = get_scenery_id_by_cursor_pos(x, y); if (sceneryId == -1) return; @@ -824,9 +795,9 @@ void window_scenery_scrollmousedown() window_scenery_selected_scenery_by_tab[tabIndex] = sceneryId; window_scenery_is_repaint_scenery_tool_on &= 0xFE; - sound_play_panned(4, (w->width >> 1) + w->x, 0, 0, 0); + audio_play_sound_panned(4, (w->width >> 1) + w->x, 0, 0, 0); w->scenery.hover_counter = -16; - RCT2_GLOBAL(0x00F64EB4, uint32) = MONEY32_UNDEFINED; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_COST, uint32) = MONEY32_UNDEFINED; window_invalidate(w); } @@ -834,12 +805,8 @@ void window_scenery_scrollmousedown() * * rct2: 0x006E1BB8 */ -void window_scenery_scrollmouseover() +void window_scenery_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) { - short x, y, scrollIndex; - rct_window *w; - - 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; @@ -851,16 +818,11 @@ void window_scenery_scrollmouseover() * * rct2: 0x006E1C05 */ -void window_scenery_tooltip() +void window_scenery_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) { - rct_window *w; - short widget; - - window_scroll_get_registers(w, widget); - - switch (widget) { + switch (widgetIndex) { case WIDX_SCENERY_LIST: - RCT2_GLOBAL(0x013CE952, uint16) = 3159; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = 3159; break; case WIDX_SCENERY_TAB_1: case WIDX_SCENERY_TAB_2: @@ -881,8 +843,10 @@ void window_scenery_tooltip() case WIDX_SCENERY_TAB_17: case WIDX_SCENERY_TAB_18: case WIDX_SCENERY_TAB_19: + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = g_scenerySetEntries[widgetIndex - WIDX_SCENERY_TAB_1]->name; + break; case WIDX_SCENERY_TAB_20: - RCT2_GLOBAL(0x013CE952, uint16) = g_scenerySetEntries[widget - WIDX_SCENERY_TAB_1]->name; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = 1813; break; } } @@ -891,18 +855,15 @@ void window_scenery_tooltip() * * rct2: 0x006E118B */ -void window_scenery_invalidate() +void window_scenery_invalidate(rct_window *w) { - rct_window* w; - - window_get_register(w); colour_scheme_update(w); uint16 tabIndex = window_scenery_active_tab_index; 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; @@ -912,10 +873,10 @@ void window_scenery_invalidate() 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; - + sint16 tabSelectedSceneryId = window_scenery_selected_scenery_by_tab[tabIndex]; if (tabSelectedSceneryId != -1) { if (tabSelectedSceneryId < 0x100) { @@ -942,7 +903,7 @@ void window_scenery_invalidate() window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WWT_EMPTY; window_scenery_widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WWT_EMPTY; window_scenery_widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WWT_EMPTY; - + if (window_scenery_is_repaint_scenery_tool_on & 1) { // repaint colored scenery tool is on window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WWT_COLORBTN; window_scenery_widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WWT_COLORBTN; @@ -953,7 +914,7 @@ void window_scenery_invalidate() if (tabSelectedSceneryId >= 0x400) { sceneryEntry = g_bannerSceneryEntries[tabSelectedSceneryId - 0x400]; - + if (sceneryEntry->banner.flags & 1) window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WWT_COLORBTN; } else if (tabSelectedSceneryId >= 0x300) { @@ -1018,24 +979,19 @@ void window_scenery_invalidate() * * rct2: 0x006E1462 */ -void window_scenery_paint() +void window_scenery_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); uint16 tabIndex = window_scenery_active_tab_index; uint16 selectedWidgetId = tabIndex + 4; uint32 imageId = ((w->colours[1] << 19) | window_scenery_widgets[selectedWidgetId].image) + 1ul; - + gfx_draw_sprite(dpi, imageId, w->x + window_scenery_widgets[selectedWidgetId].left, w->y + window_scenery_widgets[selectedWidgetId].top, selectedWidgetId); - + sint16 selectedSceneryEntryId = w->scenery.selected_scenery_id; if (selectedSceneryEntryId == -1) { if (window_scenery_is_repaint_scenery_tool_on & 1) // repaint colored scenery tool is on @@ -1067,11 +1023,11 @@ void window_scenery_paint() price = sceneryEntry->small_scenery.price * 10; } - if (w->scenery.selected_scenery_id == -1 && RCT2_GLOBAL(0x00F64EB4, uint32) != MONEY32_UNDEFINED) { - price = RCT2_GLOBAL(0x00F64EB4, uint32); + if (w->scenery.selected_scenery_id == -1 && RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_COST, uint32) != MONEY32_UNDEFINED) { + price = RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_COST, uint32); } - RCT2_GLOBAL(0x013CE952, uint32) = price; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) = price; if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) { // -14 @@ -1079,7 +1035,7 @@ void window_scenery_paint() w->x + w->width - 0x1A, w->y + w->height - 13); } - RCT2_GLOBAL(0x013CE952, uint16) = sceneryEntry->name; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = sceneryEntry->name; gfx_draw_string_left_clipped(dpi, 0x4A7, (void*)0x013CE952, 0, w->x + 3, w->y + w->height - 13, w->width - 19); } @@ -1088,24 +1044,19 @@ void window_scenery_paint() * * rct2: 0x006E15ED */ -void window_scenery_scrollpaint() +void window_scenery_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - - gfx_clear(dpi, ((char*)0x0141FC48)[w->colours[1] * 8] * 0x1010101); + gfx_clear(dpi, ColourMapA[w->colours[1]].mid_light * 0x1010101); uint8 tabIndex = window_scenery_active_tab_index; int sceneryTabItemIndex = 0; sint16 currentSceneryGlobalId = -1; sint16 left = 0, top = 0; - + while ((currentSceneryGlobalId = window_scenery_tab_entries[tabIndex][sceneryTabItemIndex]) != -1) { uint16 tabSelectedSceneryId = window_scenery_selected_scenery_by_tab[tabIndex]; - + if (window_scenery_is_repaint_scenery_tool_on == 1) { if (w->scenery.selected_scenery_id == currentSceneryGlobalId) { @@ -1168,8 +1119,8 @@ void window_scenery_scrollpaint() imageId &= 0xDFFFFFFF; tertiaryColour = window_scenery_tertiary_colour; } - - } + + } gfx_draw_sprite(clipdpi, imageId, 0x2F, (sceneryEntry->wall.height * 2) + 0x32, tertiaryColour); @@ -1226,7 +1177,7 @@ void window_scenery_scrollpaint() rct2_free(clipdpi); } } - + left += SCENERY_BUTTON_WIDTH; if (left >= 594) { top += SCENERY_BUTTON_HEIGHT; @@ -1234,4 +1185,4 @@ void window_scenery_scrollpaint() } sceneryTabItemIndex++; } -} \ No newline at end of file +} diff --git a/src/windows/server_list.c b/src/windows/server_list.c new file mode 100644 index 0000000000..75b50e7634 --- /dev/null +++ b/src/windows/server_list.c @@ -0,0 +1,759 @@ +/***************************************************************************** +* 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 "../interface/colour.h" +#include "../interface/themes.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../network/http.h" +#include "../network/network.h" +#include "../sprites.h" +#include "../windows/dropdown.h" +#include "../util/util.h" +#include "error.h" + +#define WWIDTH_MIN 500 +#define WHEIGHT_MIN 300 +#define WWIDTH_MAX 1200 +#define WHEIGHT_MAX 800 +#define ITEM_HEIGHT (3 + 9 + 3) + +typedef struct { + char *address; + utf8 *name; + bool requiresPassword; + utf8 *description; + char *version; + bool favorite; + uint8 players; + uint8 maxplayers; +} saved_server; + +char _playerName[32 + 1]; +saved_server *_savedServers = NULL; +int _numSavedServers = 0; +SDL_mutex *_mutex = 0; + +enum { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_PLAYER_NAME_INPUT, + WIDX_LIST, + WIDX_FETCH_SERVERS, + WIDX_ADD_SERVER, + WIDX_START_SERVER +}; + +enum { + WIDX_LIST_REMOVE, + WIDX_LIST_SPECTATE +}; + +static rct_widget window_server_list_widgets[] = { + { WWT_FRAME, 0, 0, 340, 0, 90, 0xFFFFFFFF, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, 338, 1, 14, STR_SERVER_LIST, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, 327, 337, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_TEXT_BOX, 1, 100, 344, 20, 31, (uint32)_playerName, STR_NONE }, // player name text box + { WWT_SCROLL, 1, 6, 337, 37, 50, STR_NONE, STR_NONE }, // server list + { WWT_DROPDOWN_BUTTON, 1, 6, 106, 53, 64, STR_FETCH_SERVERS, STR_NONE }, // fetch servers button + { WWT_DROPDOWN_BUTTON, 1, 112, 212, 53, 64, STR_ADD_SERVER, STR_NONE }, // add server button + { WWT_DROPDOWN_BUTTON, 1, 218, 318, 53, 64, STR_START_SERVER, STR_NONE }, // start server button + { WIDGETS_END }, +}; + +static void window_server_list_close(rct_window *w); +static void window_server_list_mouseup(rct_window *w, int widgetIndex); +static void window_server_list_resize(rct_window *w); +static void window_server_list_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); +static void window_server_list_update(rct_window *w); +static void window_server_list_scroll_getsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_server_list_scroll_mousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_server_list_scroll_mouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_server_list_textinput(rct_window *w, int widgetIndex, char *text); +static void window_server_list_invalidate(rct_window *w); +static void window_server_list_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_server_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); + +static rct_window_event_list window_server_list_events = { + window_server_list_close, + window_server_list_mouseup, + window_server_list_resize, + NULL, + window_server_list_dropdown, + NULL, + window_server_list_update, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_server_list_scroll_getsize, + window_server_list_scroll_mousedown, + NULL, + window_server_list_scroll_mouseover, + window_server_list_textinput, + NULL, + NULL, + NULL, + NULL, + NULL, + window_server_list_invalidate, + window_server_list_paint, + window_server_list_scrollpaint +}; + +enum { + DDIDX_JOIN, + DDIDX_FAVORITE +}; + +static int _hoverButtonIndex = -1; + +static void server_list_get_item_button(int buttonIndex, int x, int y, int width, int *outX, int *outY); +static void server_list_load_saved_servers(); +static void server_list_save_saved_servers(); +static void dispose_saved_server_list(); +static void dispose_saved_server(saved_server *serverInfo); +static saved_server* add_saved_server(char *address); +static void remove_saved_server(int index); +static void join_server(char *address); +static void fetch_servers(); +#ifndef DISABLE_HTTP +static void fetch_servers_callback(http_json_response* response); +#endif + +void window_server_list_open() +{ + rct_window* window; + + // Check if window is already open + window = window_bring_to_front_by_class(WC_SERVER_LIST); + if (window != NULL) + return; + + if (_mutex == 0) { + _mutex = SDL_CreateMutex(); + } + + window = window_create_centred(WWIDTH_MIN, WHEIGHT_MIN, &window_server_list_events, WC_SERVER_LIST, WF_10 | WF_RESIZABLE); + + window->widgets = window_server_list_widgets; + window->enabled_widgets = ( + (1 << WIDX_CLOSE) | + (1 << WIDX_PLAYER_NAME_INPUT) | + (1 << WIDX_FETCH_SERVERS) | + (1 << WIDX_ADD_SERVER) | + (1 << WIDX_START_SERVER) + ); + window_init_scroll_widgets(window); + window->no_list_items = 0; + window->selected_list_item = -1; + window->frame_no = 0; + window->min_width = 320; + window->min_height = 90; + window->max_width = window->min_width; + window->max_height = window->min_height; + + window->page = 0; + window->list_information_type = 0; + window->colours[0] = 1; + window->colours[1] = 26; + window->colours[2] = 26; + + window_set_resize(window, WWIDTH_MIN, WHEIGHT_MIN, WWIDTH_MAX, WHEIGHT_MAX); + + safe_strncpy(_playerName, gConfigNetwork.player_name, sizeof(_playerName)); + + server_list_load_saved_servers(); + window->no_list_items = _numSavedServers; + + fetch_servers(); +} + +static void window_server_list_close(rct_window *w) +{ + dispose_saved_server_list(); + if (_mutex) { + SDL_LockMutex(_mutex); + SDL_DestroyMutex(_mutex); + _mutex = 0; + } +} + +static void window_server_list_mouseup(rct_window *w, int widgetIndex) +{ + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_PLAYER_NAME_INPUT: + window_start_textbox(w, widgetIndex, 1170, (uint32)_playerName, 63); + break; + case WIDX_FETCH_SERVERS: + fetch_servers(); + break; + case WIDX_ADD_SERVER: + window_text_input_open(w, widgetIndex, STR_ADD_SERVER, STR_ENTER_HOSTNAME_OR_IP_ADDRESS, STR_NONE, 0, 128); + break; + case WIDX_START_SERVER: + window_server_start_open(); + break; + } +} + +static void window_server_list_resize(rct_window *w) +{ + window_set_resize(w, WWIDTH_MIN, WHEIGHT_MIN, WWIDTH_MAX, WHEIGHT_MAX); +} + +static void window_server_list_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) +{ + int serverIndex = w->selected_list_item; + if (serverIndex < 0) return; + if (serverIndex >= _numSavedServers) return; + + char *serverAddress = _savedServers[serverIndex].address; + + switch (dropdownIndex) { + case DDIDX_JOIN: + join_server(serverAddress); + break; + case DDIDX_FAVORITE: + _savedServers[serverIndex].favorite = !_savedServers[serverIndex].favorite; + server_list_save_saved_servers(); + break; + } +} + +static void window_server_list_update(rct_window *w) +{ + if (gCurrentTextBox.window.classification == w->classification && gCurrentTextBox.window.number == w->number) { + window_update_textbox_caret(); + widget_invalidate(w, WIDX_PLAYER_NAME_INPUT); + } +} + +static void window_server_list_scroll_getsize(rct_window *w, int scrollIndex, int *width, int *height) +{ + *width = 0; + *height = w->no_list_items * ITEM_HEIGHT; +} + +static void window_server_list_scroll_mousedown(rct_window *w, int scrollIndex, int x, int y) +{ + int serverIndex = w->selected_list_item; + if (serverIndex < 0) return; + if (serverIndex >= _numSavedServers) return; + + char *serverAddress = _savedServers[serverIndex].address; + + rct_widget *listWidget = &w->widgets[WIDX_LIST]; + int ddx = w->x + listWidget->left + x; + int ddy = w->y + listWidget->top + y; + + gDropdownItemsFormat[0] = STR_JOIN_GAME; + if (_savedServers[serverIndex].favorite) { + gDropdownItemsFormat[1] = STR_REMOVE_FROM_FAVORITES; + } else { + gDropdownItemsFormat[1] = STR_ADD_TO_FAVORITES; + } + window_dropdown_show_text(ddx, ddy, 0, COLOUR_GREY, 0, 2); +} + +static void window_server_list_scroll_mouseover(rct_window *w, int scrollIndex, int x, int y) +{ + // Item + int index = y / ITEM_HEIGHT; + if (index < 0 || index >= w->no_list_items) { + index = -1; + } + + int hoverButtonIndex = -1; + if (index != -1) { + int width = w->widgets[WIDX_LIST].right - w->widgets[WIDX_LIST].left; + int sy = index * ITEM_HEIGHT; + for (int i = 0; i < 2; i++) { + int bx, by; + + server_list_get_item_button(i, 0, sy, width, &bx, &by); + if (x >= bx && y >= by && x < bx + 24 && y < by + 24) { + hoverButtonIndex = i; + break; + } + } + } + + if (w->selected_list_item != index || _hoverButtonIndex != hoverButtonIndex) { + w->selected_list_item = index; + _hoverButtonIndex = hoverButtonIndex; + window_invalidate(w); + } +} + +static void window_server_list_textinput(rct_window *w, int widgetIndex, char *text) +{ + if (text == NULL || text[0] == 0) return; + + switch (widgetIndex) { + case WIDX_PLAYER_NAME_INPUT: + if (strcmp(_playerName, text) == 0) + return; + + if (strlen(text) == 0) { + memset(_playerName, 0, sizeof(_playerName)); + } else { + memset(_playerName, 0, sizeof(_playerName)); + safe_strncpy(_playerName, text, sizeof(_playerName)); + } + + if (strlen(_playerName) > 0) { + SafeFree(gConfigNetwork.player_name); + gConfigNetwork.player_name = _strdup(_playerName); + config_save_default(); + } + + widget_invalidate(w, WIDX_PLAYER_NAME_INPUT); + break; + + case WIDX_ADD_SERVER: + add_saved_server(text); + server_list_save_saved_servers(); + window_invalidate(w); + break; + } +} + +static void window_server_list_invalidate(rct_window *w) +{ + window_server_list_widgets[WIDX_BACKGROUND].right = w->width - 1; + window_server_list_widgets[WIDX_BACKGROUND].bottom = w->height - 1; + window_server_list_widgets[WIDX_TITLE].right = w->width - 2; + window_server_list_widgets[WIDX_CLOSE].left = w->width - 2 - 11; + window_server_list_widgets[WIDX_CLOSE].right = w->width - 2 - 11 + 10; + + window_server_list_widgets[WIDX_PLAYER_NAME_INPUT].right = w->width - 6; + window_server_list_widgets[WIDX_LIST].left = 6; + window_server_list_widgets[WIDX_LIST].right = w->width - 6; + window_server_list_widgets[WIDX_LIST].bottom = w->height - 6 - 11 - 6; + window_server_list_widgets[WIDX_FETCH_SERVERS].top = w->height - 6 - 11; + window_server_list_widgets[WIDX_FETCH_SERVERS].bottom = w->height - 6; + window_server_list_widgets[WIDX_ADD_SERVER].top = w->height - 6 - 11; + window_server_list_widgets[WIDX_ADD_SERVER].bottom = w->height - 6; + window_server_list_widgets[WIDX_START_SERVER].top = w->height - 6 - 11; + window_server_list_widgets[WIDX_START_SERVER].bottom = w->height - 6; + + w->no_list_items = _numSavedServers; +} + +static void window_server_list_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ + window_draw_widgets(w, dpi); + + gfx_draw_string_left(dpi, STR_PLAYER_NAME, NULL, COLOUR_WHITE, w->x + 6, w->y + w->widgets[WIDX_PLAYER_NAME_INPUT].top); +} + +static void window_server_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) +{ + uint32 colour; + + colour = ColourMapA[w->colours[1]].mid_light; + colour = (colour << 24) | (colour << 16) | (colour << 8) | colour; + gfx_clear(dpi, colour); + + int width = w->widgets[WIDX_LIST].right - w->widgets[WIDX_LIST].left; + + int y = 0; + for (int i = 0; i < w->no_list_items; i++) { + if (y >= dpi->y + dpi->height) continue; + // if (y + ITEM_HEIGHT < dpi->y) continue; + + saved_server *serverDetails = &_savedServers[i]; + bool highlighted = i == w->selected_list_item; + + // Draw hover highlight + if (highlighted) { + gfx_fill_rect(dpi, 0, y, width, y + ITEM_HEIGHT, 0x02000031); + } + + int colour = w->colours[1]; + if (serverDetails->favorite) { + colour = COLOUR_YELLOW; + } + + // Draw server information + if (highlighted) { + gfx_draw_string(dpi, serverDetails->address, colour, 3, y + 3); + } else { + gfx_draw_string(dpi, serverDetails->name, colour, 3, y + 3); + } + //gfx_draw_string(dpi, serverDetails->description, w->colours[1], 3, y + 14); + + + int right = width - 3 - 14; + + // Draw compatibility icon + right -= 10; + int compatibilitySpriteId; + if (str_is_null_or_empty(serverDetails->version)) { + // Server not online... + compatibilitySpriteId = SPR_G2_RCT1_CLOSE_BUTTON_0; + } else { + // Server online... check version + bool correctVersion = strcmp(serverDetails->version, OPENRCT2_VERSION) == 0; + compatibilitySpriteId = correctVersion ? SPR_G2_RCT1_OPEN_BUTTON_2 : SPR_G2_RCT1_CLOSE_BUTTON_2; + } + gfx_draw_sprite(dpi, compatibilitySpriteId, right, y + 1, 0); + right -= 4; + + // Draw lock icon + right -= 8; + if (serverDetails->requiresPassword) { + gfx_draw_sprite(dpi, SPR_G2_LOCKED, right, y + 4, 0); + } + right -= 6; + + // Draw number of players + char players[32]; + players[0] = 0; + if (serverDetails->maxplayers > 0) { + sprintf(players, "%d/%d", serverDetails->players, serverDetails->maxplayers); + } + int numPlayersStringWidth = gfx_get_string_width(players); + gfx_draw_string(dpi, players, w->colours[1], right - numPlayersStringWidth, y + 3); + + y += ITEM_HEIGHT; + } +} + +static void server_list_get_item_button(int buttonIndex, int x, int y, int width, int *outX, int *outY) +{ + *outX = width - 3 - 36 - (30 * buttonIndex); + *outY = y + 2; +} + +static char *freadstralloc(SDL_RWops *file) +{ + int capacity = 64; + char *buffer = malloc(capacity); + + int length = 0; + int c; + for (;;) { + c = 0; + if (SDL_RWread(file, &c, 1, 1) != 1) break; + if (c == 0) break; + + if (length > capacity) { + capacity *= 2; + buffer = realloc(buffer, capacity); + } + buffer[length] = c; + length++; + } + + buffer = realloc(buffer, length + 1); + buffer[length] = 0; + return buffer; +} + +static void server_list_load_saved_servers() +{ + utf8 path[MAX_PATH]; + SDL_RWops *file; + + platform_get_user_directory(path, NULL); + strcat(path, "servers.cfg"); + + file = SDL_RWFromFile(path, "rb"); + if (file == NULL) { + return; + } + + SDL_LockMutex(_mutex); + dispose_saved_server_list(); + + // Read number of saved servers + SDL_RWread(file, &_numSavedServers, sizeof(uint32), 1); + _savedServers = malloc(_numSavedServers * sizeof(saved_server)); + + // Load each saved server + for (int i = 0; i < _numSavedServers; i++) { + saved_server *serverInfo = &_savedServers[i]; + + serverInfo->address = freadstralloc(file); + serverInfo->name = freadstralloc(file); + serverInfo->requiresPassword = false; + serverInfo->description = freadstralloc(file); + serverInfo->version = _strdup(""); + serverInfo->favorite = true; + serverInfo->players = 0; + serverInfo->maxplayers = 0; + } + + SDL_RWclose(file); + SDL_UnlockMutex(_mutex); +} + +static void server_list_save_saved_servers() +{ + utf8 path[MAX_PATH]; + SDL_RWops *file; + + platform_get_user_directory(path, NULL); + strcat(path, "servers.cfg"); + + file = SDL_RWFromFile(path, "wb"); + if (file == NULL) { + log_error("Unable to save servers."); + return; + } + + SDL_LockMutex(_mutex); + int count = 0; + for (int i = 0; i < _numSavedServers; i++) { + saved_server *serverInfo = &_savedServers[i]; + if (serverInfo->favorite) { + count++; + } + } + // Write number of saved servers + SDL_RWwrite(file, &count, sizeof(uint32), 1); + + // Write each saved server + for (int i = 0; i < _numSavedServers; i++) { + saved_server *serverInfo = &_savedServers[i]; + if (serverInfo->favorite) { + SDL_RWwrite(file, serverInfo->address, strlen(serverInfo->address) + 1, 1); + SDL_RWwrite(file, serverInfo->name, strlen(serverInfo->name) + 1, 1); + SDL_RWwrite(file, serverInfo->description, strlen(serverInfo->description) + 1, 1); + } + } + + SDL_RWclose(file); + SDL_UnlockMutex(_mutex); +} + +static void dispose_saved_server_list() +{ + SDL_LockMutex(_mutex); + if (_savedServers != NULL) { + for (int i = 0; i < _numSavedServers; i++) { + dispose_saved_server(&_savedServers[i]); + } + free(_savedServers); + _savedServers = NULL; + } + _numSavedServers = 0; + SDL_UnlockMutex(_mutex); +} + +static void dispose_saved_server(saved_server *serverInfo) +{ + SafeFree(serverInfo->address); + SafeFree(serverInfo->name); + SafeFree(serverInfo->description); + SafeFree(serverInfo->version); +} + +static saved_server* add_saved_server(char *address) +{ + SDL_LockMutex(_mutex); + for (int i = 0; i < _numSavedServers; i++) { + if (strcmp(_savedServers[i].address, address) == 0) { + SDL_UnlockMutex(_mutex); + return &_savedServers[i]; + } + } + + _numSavedServers++; + if (_savedServers == NULL) { + _savedServers = malloc(_numSavedServers * sizeof(saved_server)); + } else { + _savedServers = realloc(_savedServers, _numSavedServers * sizeof(saved_server)); + } + + int index = _numSavedServers - 1; + saved_server* newserver = &_savedServers[index]; + newserver->address = _strdup(address); + newserver->name = _strdup(address); + newserver->requiresPassword = false; + newserver->description = _strdup(""); + newserver->version = _strdup(""); + newserver->favorite = false; + newserver->players = 0; + newserver->maxplayers = 0; + SDL_UnlockMutex(_mutex); + return newserver; +} + +static void remove_saved_server(int index) +{ + SDL_LockMutex(_mutex); + if (_numSavedServers > index) { + int serversToMove = _numSavedServers - index - 1; + memmove(&_savedServers[index], &_savedServers[index + 1], serversToMove * sizeof(saved_server)); + + _numSavedServers--; + _savedServers = realloc(_savedServers, _numSavedServers * sizeof(saved_server)); + } + SDL_UnlockMutex(_mutex); +} + +static char *substr(char *start, int length) +{ + char *result = malloc(length + 1); + memcpy(result, start, length); + result[length] = 0; + return result; +} + +static void join_server(char *address) +{ + int port = gConfigNetwork.default_port; + + bool addresscopied = false; + + char *endbracket = strrchr(address, ']'); + char *startbracket = strrchr(address, '['); + char *dot = strchr(address, '.'); + + char *colon = strrchr(address, ':'); + if (colon != NULL && (endbracket != NULL || dot != NULL)) { + address = substr(address, colon - address); + sscanf(colon + 1, "%d", &port); + addresscopied = true; + } + + if (startbracket && endbracket) { + address = substr(startbracket + 1, endbracket - startbracket - 1); + addresscopied = true; + } + + if (!network_begin_client(address, port)) { + window_error_open(STR_UNABLE_TO_CONNECT_TO_SERVER, STR_NONE); + } + + if (addresscopied) { + free(address); + } +} + +static void fetch_servers() +{ +#ifndef DISABLE_HTTP + const char *masterServerUrl = OPENRCT2_MASTER_SERVER_URL; + if (!str_is_null_or_empty(gConfigNetwork.master_server_url)) { + masterServerUrl = gConfigNetwork.master_server_url; + } + + SDL_LockMutex(_mutex); + for (int i = 0; i < _numSavedServers; i++) { + if (!_savedServers[i].favorite) { + remove_saved_server(i); + i = 0; + } + } + SDL_UnlockMutex(_mutex); + + http_json_request request; + request.url = masterServerUrl; + request.method = HTTP_METHOD_GET; + request.body = NULL; + http_request_json_async(&request, fetch_servers_callback); +#endif +} + +#ifndef DISABLE_HTTP +static void fetch_servers_callback(http_json_response* response) +{ + if (response == NULL) { + log_warning("Unable to connect to master server"); + return; + } + + json_t *jsonStatus = json_object_get(response->root, "status"); + if (!json_is_number(jsonStatus)) { + http_request_json_dispose(response); + log_warning("Invalid response from master server"); + return; + } + + int status = (int)json_integer_value(jsonStatus); + if (status != 200) { + http_request_json_dispose(response); + log_warning("Master server failed to return servers"); + return; + } + + json_t *jsonServers = json_object_get(response->root, "servers"); + if (!json_is_array(jsonServers)) { + http_request_json_dispose(response); + log_warning("Invalid response from master server"); + return; + } + + int count = json_array_size(jsonServers); + for (int i = 0; i < count; i++) { + json_t *server = json_array_get(jsonServers, i); + if (!json_is_object(server)) { + continue; + } + + json_t *port = json_object_get(server, "port"); + json_t *name = json_object_get(server, "name"); + json_t *description = json_object_get(server, "description"); + json_t *requiresPassword = json_object_get(server, "requiresPassword"); + json_t *version = json_object_get(server, "version"); + json_t *players = json_object_get(server, "players"); + json_t *maxPlayers = json_object_get(server, "maxPlayers"); + json_t *ip = json_object_get(server, "ip"); + json_t *ip4 = json_object_get(ip, "v4"); + json_t *ip6 = json_object_get(ip, "v6"); + json_t *addressIp = json_array_get(ip4, 0); + + char address[256]; + snprintf(address, sizeof(address), "%s:%d", json_string_value(addressIp), (int)json_integer_value(port)); + + SDL_LockMutex(_mutex); + saved_server* newserver = add_saved_server(address); + SafeFree(newserver->name); + SafeFree(newserver->description); + SafeFree(newserver->version); + newserver->name = _strdup(json_string_value(name)); + newserver->requiresPassword = json_boolean_value(requiresPassword); + newserver->description = _strdup(json_string_value(description)); + newserver->version = _strdup(json_string_value(version)); + newserver->players = (uint8)json_integer_value(players); + newserver->maxplayers = (uint8)json_integer_value(maxPlayers); + SDL_UnlockMutex(_mutex); + } + http_request_json_dispose(response); + + rct_window *window = window_find_by_class(WC_SERVER_LIST); + if (window != NULL) { + window_invalidate(window); + } +} +#endif diff --git a/src/windows/server_start.c b/src/windows/server_start.c new file mode 100644 index 0000000000..752c7efd4b --- /dev/null +++ b/src/windows/server_start.c @@ -0,0 +1,266 @@ +/***************************************************************************** +* 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 "../config.h" +#include "../interface/themes.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../network/network.h" +#include "../sprites.h" +#include "../util/util.h" +#include "error.h" + +char _port[7]; +char _name[65]; +char _password[33]; + +enum { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_PORT_INPUT, + WIDX_NAME_INPUT, + WIDX_PASSWORD_INPUT, + WIDX_MAXPLAYERS, + WIDX_MAXPLAYERS_INCREASE, + WIDX_MAXPLAYERS_DECREASE, + WIDX_ADVERTISE_CHECKBOX, + WIDX_START_SERVER +}; + +#define WW 300 +#define WH 120 + +static rct_widget window_server_start_widgets[] = { + { WWT_FRAME, 0, 0, WW-1, 0, WH-1, 0xFFFFFFFF, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, WW-2, 1, 14, STR_START_SERVER, 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_TEXT_BOX, 1, 120, WW-8, 20, 32, (uint32)_port, STR_NONE }, // port text box + { WWT_TEXT_BOX, 1, 120, WW-8, 36, 48, (uint32)_name, STR_NONE }, // name text box + { WWT_TEXT_BOX, 1, 120, WW-8, 52, 64, (uint32)_password, STR_NONE }, // password text box + { WWT_SPINNER, 1, 120, WW-8, 68, 77, 1871, STR_NONE }, // max players + { WWT_DROPDOWN_BUTTON, 1, WW-18, WW-8, 68, 72, STR_NUMERIC_UP, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, WW-18, WW-8, 72, 76, STR_NUMERIC_DOWN, STR_NONE }, + { WWT_CHECKBOX, 1, 6, WW-8, 85, 91, STR_ADVERTISE, STR_NONE }, // advertise checkbox + { WWT_DROPDOWN_BUTTON, 1, 6, 106, WH-6-11, WH-6, STR_START_SERVER, STR_NONE }, // start server button + { WIDGETS_END }, +}; + +static void window_server_start_close(rct_window *w); +static void window_server_start_mouseup(rct_window *w, int widgetIndex); +static void window_server_start_update(rct_window *w); +static void window_server_start_textinput(rct_window *w, int widgetIndex, char *text); +static void window_server_start_invalidate(rct_window *w); +static void window_server_start_paint(rct_window *w, rct_drawpixelinfo *dpi); + +static rct_window_event_list window_server_start_events = { + window_server_start_close, + window_server_start_mouseup, + NULL, + NULL, + NULL, + NULL, + window_server_start_update, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_server_start_textinput, + NULL, + NULL, + NULL, + NULL, + NULL, + window_server_start_invalidate, + window_server_start_paint, + NULL +}; + +void window_server_start_open() +{ + rct_window* window; + + // Check if window is already open + window = window_bring_to_front_by_class(WC_SERVER_START); + if (window != NULL) + return; + + window = window_create_centred(WW, WH, &window_server_start_events, WC_SERVER_START, WF_10); + + window->widgets = window_server_start_widgets; + window->enabled_widgets = ( + (1 << WIDX_CLOSE) | + (1 << WIDX_PORT_INPUT) | + (1 << WIDX_NAME_INPUT) | + (1 << WIDX_PASSWORD_INPUT) | + (1 << WIDX_MAXPLAYERS) | + (1 << WIDX_MAXPLAYERS_INCREASE) | + (1 << WIDX_MAXPLAYERS_DECREASE) | + (1 << WIDX_ADVERTISE_CHECKBOX) | + (1 << WIDX_START_SERVER) + ); + window_init_scroll_widgets(window); + window->no_list_items = 0; + window->selected_list_item = -1; + window->frame_no = 0; + window->min_width = window->width; + window->min_height = window->height; + window->max_width = window->min_width; + window->max_height = window->min_height; + + window->page = 0; + window->list_information_type = 0; + window->colours[0] = 1; + window->colours[1] = 26; + window->colours[2] = 26; + + sprintf(_port, "%lu", gConfigNetwork.default_port); + safe_strncpy(_name, gConfigNetwork.server_name, sizeof(_name)); +} + +static void window_server_start_close(rct_window *w) +{ + +} + +static void window_server_start_mouseup(rct_window *w, int widgetIndex) +{ + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_PORT_INPUT: + window_start_textbox(w, widgetIndex, 1170, (uint32)_port, 6); + break; + case WIDX_NAME_INPUT: + window_start_textbox(w, widgetIndex, 1170, (uint32)_name, 64); + break; + case WIDX_PASSWORD_INPUT: + window_start_textbox(w, widgetIndex, 1170, (uint32)_password, 32); + break; + case WIDX_MAXPLAYERS_INCREASE: + if (gConfigNetwork.maxplayers < 255) { + gConfigNetwork.maxplayers++; + } + config_save_default(); + window_invalidate(w); + break; + case WIDX_MAXPLAYERS_DECREASE: + if (gConfigNetwork.maxplayers > 1) { + gConfigNetwork.maxplayers--; + } + config_save_default(); + window_invalidate(w); + break; + case WIDX_ADVERTISE_CHECKBOX: + gConfigNetwork.advertise = !gConfigNetwork.advertise; + config_save_default(); + window_invalidate(w); + break; + case WIDX_START_SERVER: + network_set_password(_password); + window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME | LOADSAVETYPE_NETWORK, NULL); + break; + } +} + +static void window_server_start_update(rct_window *w) +{ + if (gCurrentTextBox.window.classification == w->classification && gCurrentTextBox.window.number == w->number) { + window_update_textbox_caret(); + widget_invalidate(w, WIDX_NAME_INPUT); + widget_invalidate(w, WIDX_PASSWORD_INPUT); + } +} + +static void window_server_start_textinput(rct_window *w, int widgetIndex, char *text) +{ + if (text == NULL) return; + + switch (widgetIndex) { + case WIDX_PORT_INPUT: + if (strcmp(_port, text) == 0) + return; + + memset(_port, 0, sizeof(_port)); + if (strlen(text) > 0) { + safe_strncpy(_port, text, sizeof(_port)); + } + + gConfigNetwork.default_port = atoi(_port); + config_save_default(); + + widget_invalidate(w, WIDX_NAME_INPUT); + break; + case WIDX_NAME_INPUT: + if (strcmp(_name, text) == 0) + return; + + memset(_name, 0, sizeof(_name)); + if (strlen(text) > 0) { + safe_strncpy(_name, text, sizeof(_name)); + } + + if (strlen(_name) > 0) { + SafeFree(gConfigNetwork.server_name); + gConfigNetwork.server_name = _strdup(_name); + config_save_default(); + } + + widget_invalidate(w, WIDX_NAME_INPUT); + break; + case WIDX_PASSWORD_INPUT: + if (strcmp(_password, text) == 0) + return; + + memset(_password, 0, sizeof(_password)); + if (strlen(text) > 0) { + safe_strncpy(_password, text, sizeof(_password)); + } + + widget_invalidate(w, WIDX_PASSWORD_INPUT); + break; + } +} + +static void window_server_start_invalidate(rct_window *w) +{ + widget_set_checkbox_value(w, WIDX_ADVERTISE_CHECKBOX, gConfigNetwork.advertise); + RCT2_GLOBAL(0x013CE964, uint16) = gConfigNetwork.maxplayers; +} + +static void window_server_start_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ + window_draw_widgets(w, dpi); + + gfx_draw_string_left(dpi, STR_PORT, NULL, w->colours[1], w->x + 6, w->y + w->widgets[WIDX_PORT_INPUT].top); + gfx_draw_string_left(dpi, STR_SERVER_NAME, NULL, w->colours[1], w->x + 6, w->y + w->widgets[WIDX_NAME_INPUT].top); + gfx_draw_string_left(dpi, STR_PASSWORD, NULL, w->colours[1], w->x + 6, w->y + w->widgets[WIDX_PASSWORD_INPUT].top); + gfx_draw_string_left(dpi, STR_MAX_PLAYERS, NULL, w->colours[1], w->x + 6, w->y + w->widgets[WIDX_MAXPLAYERS].top); +} diff --git a/src/windows/shortcut_key_change.c b/src/windows/shortcut_key_change.c index 01cf458ca6..912b1c8309 100644 --- a/src/windows/shortcut_key_change.c +++ b/src/windows/shortcut_key_change.c @@ -25,6 +25,8 @@ #include "../localisation/localisation.h" #include "../interface/themes.h" +extern const rct_string_id ShortcutStringIds[]; + #define WW 250 #define WH 60 @@ -42,41 +44,40 @@ static rct_widget window_shortcut_change_widgets[] = { { WIDGETS_END } }; -static void window_shortcut_change_emptysub(){} -static void window_shortcut_change_mouseup(); -static void window_shortcut_change_invalidate(); -static void window_shortcut_change_paint(); +static void window_shortcut_change_mouseup(rct_window *w, int widgetIndex); +static void window_shortcut_change_invalidate(rct_window *w); +static void window_shortcut_change_paint(rct_window *w, rct_drawpixelinfo *dpi); //0x9A3F7C -static void* window_shortcut_change_events[] = { - window_shortcut_change_emptysub, +static rct_window_event_list window_shortcut_change_events = { + NULL, window_shortcut_change_mouseup, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, - window_shortcut_change_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_shortcut_change_invalidate, window_shortcut_change_paint, - window_shortcut_change_emptysub + NULL }; void window_shortcut_change_open(int selected_key){ @@ -84,7 +85,7 @@ void window_shortcut_change_open(int selected_key){ window_close_by_class(WC_CHANGE_KEYBOARD_SHORTCUT); // Save the item we are selecting for new window RCT2_GLOBAL(0x9DE511, uint8) = selected_key; - rct_window* w = window_create_auto_pos(WW, WH, (uint32*)window_shortcut_change_events, WC_CHANGE_KEYBOARD_SHORTCUT, 0); + rct_window* w = window_create_auto_pos(WW, WH, &window_shortcut_change_events, WC_CHANGE_KEYBOARD_SHORTCUT, 0); w->widgets = window_shortcut_change_widgets; w->enabled_widgets = (1 << 2); @@ -95,23 +96,17 @@ void window_shortcut_change_open(int selected_key){ * * rct2: 0x006E3AE0 */ -static void window_shortcut_change_mouseup(){ - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - +static void window_shortcut_change_mouseup(rct_window *w, int widgetIndex) +{ switch (widgetIndex){ case WIDX_CLOSE: window_close(w); + break; } } -static void window_shortcut_change_invalidate() +static void window_shortcut_change_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); } @@ -119,17 +114,13 @@ static void window_shortcut_change_invalidate() * * rct2: 0x006E3A9F */ -static void window_shortcut_change_paint(){ - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +static void window_shortcut_change_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ window_draw_widgets(w, dpi); int x = w->x + 125; int y = w->y + 30; - RCT2_GLOBAL(0x13CE952, uint16) = 2493 + RCT2_GLOBAL(0x9DE511, uint8); - gfx_draw_string_centred_wrapped(dpi, (void*)0x13CE952, x, y, 242, 2785, RCT2_GLOBAL(0x9DEB8D, uint8)); + RCT2_GLOBAL(0x13CE952, uint16) = ShortcutStringIds[RCT2_GLOBAL(0x009DE511, uint8)]; + gfx_draw_string_centred_wrapped(dpi, (void*)0x013CE952, x, y, 242, 2785, RCT2_GLOBAL(0x9DEB8D, uint8)); } \ No newline at end of file diff --git a/src/windows/shortcut_keys.c b/src/windows/shortcut_keys.c index 24e6db0dd9..db3db113e1 100644 --- a/src/windows/shortcut_keys.c +++ b/src/windows/shortcut_keys.c @@ -24,6 +24,7 @@ #include "../interface/widget.h" #include "../localisation/localisation.h" #include "../platform/platform.h" +#include "../interface/keyboard_shortcut.h" #include "../interface/themes.h" #define WW 340 @@ -47,47 +48,92 @@ static rct_widget window_shortcut_widgets[] = { { WIDGETS_END } }; -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(); -static void window_shortcut_scrollmousedown(); -static void window_shortcut_scrollmouseover(); -static void window_shortcut_scrollpaint(); +static void window_shortcut_mouseup(rct_window *w, int widgetIndex); +static void window_shortcut_invalidate(rct_window *w); +static void window_shortcut_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_shortcut_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_shortcut_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_shortcut_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_shortcut_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_shortcut_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void* window_shortcut_events[] = { - window_shortcut_emptysub, +static rct_window_event_list window_shortcut_events = { + NULL, window_shortcut_mouseup, - window_shortcut_emptysub, - window_shortcut_emptysub, - window_shortcut_emptysub, - window_shortcut_emptysub, - window_shortcut_emptysub, - window_shortcut_emptysub, - window_shortcut_emptysub, - window_shortcut_emptysub, - window_shortcut_emptysub, - window_shortcut_emptysub, - window_shortcut_emptysub, - window_shortcut_emptysub, - window_shortcut_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_shortcut_scrollgetsize, window_shortcut_scrollmousedown, - window_shortcut_emptysub, + NULL, window_shortcut_scrollmouseover, - window_shortcut_emptysub, - window_shortcut_emptysub, - window_shortcut_emptysub, + NULL, + NULL, + NULL, window_shortcut_tooltip, - window_shortcut_emptysub, - window_shortcut_emptysub, + NULL, + NULL, window_shortcut_invalidate, window_shortcut_paint, window_shortcut_scrollpaint }; +const rct_string_id ShortcutStringIds[] = { + STR_SHORTCUT_CLOSE_TOP_MOST_WINDOW, + STR_SHORTCUT_CLOSE_ALL_FLOATING_WINDOWS, + STR_SHORTCUT_CANCEL_CONSTRUCTION_MODE, + STR_SHORTCUT_PAUSE_GAME, + STR_SHORTCUT_ZOOM_VIEW_OUT, + STR_SHORTCUT_ZOOM_VIEW_IN, + STR_SHORTCUT_ROTATE_VIEW_CLOCKWISE, + STR_SHORTCUT_ROTATE_VIEW_ANTICLOCKWISE, + STR_SHORTCUT_ROTATE_CONSTRUCTION_OBJECT, + STR_SHORTCUT_UNDERGROUND_VIEW_TOGGLE, + STR_SHORTCUT_REMOVE_BASE_LAND_TOGGLE, + STR_SHORTCUT_REMOVE_VERTICAL_LAND_TOGGLE, + STR_SHORTCUT_SEE_THROUGH_RIDES_TOGGLE, + STR_SHORTCUT_SEE_THROUGH_SCENERY_TOGGLE, + STR_SHORTCUT_INVISIBLE_SUPPORTS_TOGGLE, + STR_SHORTCUT_INVISIBLE_PEOPLE_TOGGLE, + STR_SHORTCUT_HEIGHT_MARKS_ON_LAND_TOGGLE, + STR_SHORTCUT_HEIGHT_MARKS_ON_RIDE_TRACKS_TOGGLE, + STR_SHORTCUT_HEIGHT_MARKS_ON_PATHS_TOGGLE, + STR_SHORTCUT_ADJUST_LAND, + STR_SHORTCUT_ADJUST_WATER, + STR_SHORTCUT_BUILD_SCENERY, + STR_SHORTCUT_BUILD_PATHS, + STR_SHORTCUT_BUILD_NEW_RIDE, + STR_SHORTCUT_SHOW_FINANCIAL_INFORMATION, + STR_SHORTCUT_SHOW_RESEARCH_INFORMATION, + STR_SHORTCUT_SHOW_RIDES_LIST, + STR_SHORTCUT_SHOW_PARK_INFORMATION, + STR_SHORTCUT_SHOW_GUEST_LIST, + STR_SHORTCUT_SHOW_STAFF_LIST, + STR_SHORTCUT_SHOW_RECENT_MESSAGES, + STR_SHORTCUT_SHOW_MAP, + STR_SHORTCUT_SCREENSHOT, + STR_SHORTCUT_REDUCE_GAME_SPEED, + STR_SHORTCUT_INCREASE_GAME_SPEED, + STR_SHORTCUT_OPEN_CHEATS_WINDOW, + STR_SHORTCUT_TOGGLE_VISIBILITY_OF_TOOLBARS, + STR_SHORTCUT_SCROLL_MAP_UP, + STR_SHORTCUT_SCROLL_MAP_LEFT, + STR_SHORTCUT_SCROLL_MAP_DOWN, + STR_SHORTCUT_SCROLL_MAP_RIGHT, + STR_SEND_MESSAGE, + STR_SHORTCUT_QUICK_SAVE_GAME, +}; + /** * * rct2: 0x006E3884 @@ -100,13 +146,13 @@ void window_shortcut_keys_open() if (w) return; - w = window_create_auto_pos(WW, WH, (uint32*)window_shortcut_events, WC_KEYBOARD_SHORTCUT_LIST, 0); + w = window_create_auto_pos(WW, WH, &window_shortcut_events, WC_KEYBOARD_SHORTCUT_LIST, 0); w->widgets = window_shortcut_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_RESET); window_init_scroll_widgets(w); - w->no_list_items = 32; + w->no_list_items = SHORTCUT_COUNT; w->selected_list_item = -1; } @@ -114,13 +160,8 @@ void window_shortcut_keys_open() * * rct2: 0x006E39E4 */ -static void window_shortcut_mouseup() +static void window_shortcut_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex){ case WIDX_CLOSE: window_close(w); @@ -133,11 +174,8 @@ static void window_shortcut_mouseup() } } -static void window_shortcut_invalidate() +static void window_shortcut_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); } @@ -145,13 +183,8 @@ static void window_shortcut_invalidate() * * rct2: 0x006E38E0 */ -static void window_shortcut_paint() +static void window_shortcut_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); } @@ -159,39 +192,26 @@ static void window_shortcut_paint() * * rct2: 0x006E3A0C */ -static void window_shortcut_tooltip() +static void window_shortcut_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) { - RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = STR_LIST; } /** * * rct2: 0x006E3A07 */ -static void window_shortcut_scrollgetsize() +static void window_shortcut_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - rct_window *w; - int width, height; - - window_get_register(w); - - width = 0; - height = 32 * 10; - - window_scrollsize_set_registers(width, height); + *height = w->no_list_items * 10; } /** * * rct2: 0x006E3A3E */ -static void window_shortcut_scrollmousedown() +static void window_shortcut_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) { - short x, y, scrollIndex; - rct_window *w; - - window_scrollmouse_get_registers(w, scrollIndex, x, y); - int selected_item = y / 10; if (selected_item >= w->no_list_items) return; @@ -203,35 +223,25 @@ static void window_shortcut_scrollmousedown() * * rct2: 0x006E3A16 */ -static void window_shortcut_scrollmouseover() +static void window_shortcut_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) { - short x, y, scrollIndex; - rct_window *w; - - window_scrollmouse_get_registers(w, scrollIndex, x, y); - int selected_item = y / 10; if (selected_item >= w->no_list_items) return; - + w->selected_list_item = selected_item; window_invalidate(w); } /** - * + * * rct2: 0x006E38E6 */ -static void window_shortcut_scrollpaint() +static void window_shortcut_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { - rct_window *w; - rct_drawpixelinfo *dpi; + gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, ColourMapA[w->colours[1]].mid_light); - 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]); - for (int i = 0; i < w->no_list_items; ++i) { int y = i * 10; if (y > dpi->y + dpi->height) @@ -244,27 +254,13 @@ static void window_shortcut_scrollpaint() gfx_fill_rect(dpi, 0, y, 800, y + 9, 0x2000031); } - RCT2_GLOBAL(0x13CE954, uint16) = i + STR_SHORTCUT_DESCRIPTION_0; - RCT2_GLOBAL(0x13CE956, uint16) = 0; - RCT2_GLOBAL(0x13CE958, uint16) = 0; - - uint16 shortcut_entry = gShortcutKeys[i]; - 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) - RCT2_GLOBAL(0x13CE956, uint16) = STR_CTRL_PLUS; - } + rct_string_id templateStringId = 2525; + char *templateString = (char*)language_get_string(templateStringId); + keyboard_shortcut_format_string(templateString, gShortcutKeys[i]); RCT2_GLOBAL(0x13CE952, uint16) = STR_SHORTCUT_ENTRY_FORMAT; + RCT2_GLOBAL(0x13CE954, uint16) = ShortcutStringIds[i]; + RCT2_GLOBAL(0x13CE956, uint16) = templateStringId; 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 934638a368..2599e7b256 100644 --- a/src/windows/sign.c +++ b/src/windows/sign.c @@ -61,81 +61,81 @@ rct_widget window_sign_widgets[] = { { WIDGETS_END }, }; -static void window_sign_emptysub() { } -static void window_sign_mouseup(); +static void window_sign_mouseup(rct_window *w, int widgetIndex); static void window_sign_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_sign_dropdown(); -static void window_sign_textinput(); -static void window_sign_invalidate(); -static void window_sign_paint(); -static void window_sign_unknown_14(); +static void window_sign_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); +static void window_sign_textinput(rct_window *w, int widgetIndex, char *text); +static void window_sign_unknown_14(rct_window *w); +static void window_sign_invalidate(rct_window *w); +static void window_sign_paint(rct_window *w, rct_drawpixelinfo *dpi); + // 0x98E44C -static void* window_sign_events[] = { - window_sign_emptysub, +static rct_window_event_list window_sign_events = { + NULL, window_sign_mouseup, - window_sign_emptysub, + NULL, window_sign_mousedown, window_sign_dropdown, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_sign_textinput, window_sign_unknown_14, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, + NULL, + NULL, + NULL, + NULL, window_sign_invalidate, window_sign_paint, - window_sign_emptysub + NULL }; -static void window_sign_small_mouseup(); -static void window_sign_small_dropdown(); -static void window_sign_small_invalidate(); +static void window_sign_small_mouseup(rct_window *w, int widgetIndex); +static void window_sign_small_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); +static void window_sign_small_invalidate(rct_window *w); // 0x9A410C -static void* window_sign_small_events[] = { - window_sign_emptysub, +static rct_window_event_list window_sign_small_events = { + NULL, window_sign_small_mouseup, - window_sign_emptysub, + NULL, window_sign_mousedown, window_sign_small_dropdown, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_sign_textinput, window_sign_unknown_14, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, - window_sign_emptysub, + NULL, + NULL, + NULL, + NULL, window_sign_small_invalidate, window_sign_paint, - window_sign_emptysub + NULL }; /** @@ -153,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, WF_2); + w = window_create_auto_pos(WW, WH, &window_sign_events, WC_BANNER, WF_NO_SCROLLING); w->widgets = window_sign_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | @@ -215,13 +215,8 @@ void window_sign_open(rct_windownumber number) } /* rct2: 0x6B9765*/ -static void window_sign_mouseup() +static void window_sign_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - rct_banner* banner = &gBanners[w->number]; int x = banner->x << 5; int y = banner->y << 5; @@ -253,8 +248,8 @@ static void window_sign_mouseup() 1 | ((map_element->type&0x3) << 8), y, map_element->base_height | ((map_element->properties.scenerymultiple.type >> 10) << 8), - GAME_COMMAND_REMOVE_LARGE_SCENERY, - 0, + GAME_COMMAND_REMOVE_LARGE_SCENERY, + 0, 0); break; case WIDX_SIGN_TEXT: @@ -275,8 +270,6 @@ static void window_sign_mouseup() /* rct2: 0x6B9784 & 0x6E6164 */ static void window_sign_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) { - rct_banner* banner = &gBanners[w->number]; - switch (widgetIndex) { case WIDX_MAIN_COLOR: window_dropdown_show_colour(w, widget, w->colours[1] | 0x80, (uint8)w->list_information_type); @@ -288,102 +281,39 @@ static void window_sign_mousedown(int widgetIndex, rct_window*w, rct_widget* wid } /* rct2: 0x6B979C */ -static void window_sign_dropdown() +static void window_sign_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - short widgetIndex, dropdownIndex; - rct_window* w; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - switch (widgetIndex){ case WIDX_MAIN_COLOR: if (dropdownIndex == -1) return; w->list_information_type = dropdownIndex; + game_do_command(1, GAME_COMMAND_FLAG_APPLY, w->number, dropdownIndex, GAME_COMMAND_SET_SIGN_STYLE, w->var_492, 1); break; case WIDX_TEXT_COLOR: if (dropdownIndex == -1) return; w->var_492 = dropdownIndex; + game_do_command(1, GAME_COMMAND_FLAG_APPLY, w->number, w->list_information_type, GAME_COMMAND_SET_SIGN_STYLE, dropdownIndex, 1); break; default: return; } - rct_banner* banner = &gBanners[w->number]; - int x = banner->x << 5; - int y = banner->y << 5; - - rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); - - while (1){ - 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) | - ((map_element->properties.scenerymultiple.colour[1] & 0xE0) >> 5); - if (id == w->number) - break; - } - } - map_element++; - } - - 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); window_invalidate(w); } /* rct2: 0x6B9791 & 0x6E6171*/ -static void window_sign_textinput() +static void window_sign_textinput(rct_window *w, int widgetIndex, char *text) { - short widgetIndex; - rct_window *w; - uint8 result; - uint8* text; - - window_text_input_get_registers(w, widgetIndex, result, text); - rct_banner* banner = &gBanners[w->number]; - int x = banner->x << 5; - int y = banner->y << 5; - - if (widgetIndex == WIDX_SIGN_TEXT && result) { - - if (*text != 0){ - 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 { - window_error_open(2984, RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id)); - } - } - else{ - int eax = x, ebx = 0, ecx = y, edx = 16, ebp = 0, edi = 0, esi = 0; - RCT2_CALLFUNC_X(0x6B7D86, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - if ((eax & 0xFF) == 0xFF)return; - banner->colour = eax & 0xFF; - banner->flags |= BANNER_FLAG_2; - - rct_string_id prev_string_id = banner->string_idx; - banner->string_idx = 778; - user_string_free(prev_string_id); - gfx_invalidate_screen(); - } + if (widgetIndex == WIDX_SIGN_TEXT && text != NULL) { + game_do_command(1, GAME_COMMAND_FLAG_APPLY, w->number, *((int*)(text + 0)), GAME_COMMAND_SET_SIGN_NAME, *((int*)(text + 8)), *((int*)(text + 4))); + game_do_command(2, GAME_COMMAND_FLAG_APPLY, w->number, *((int*)(text + 12)), GAME_COMMAND_SET_SIGN_NAME, *((int*)(text + 20)), *((int*)(text + 16))); + game_do_command(0, GAME_COMMAND_FLAG_APPLY, w->number, *((int*)(text + 24)), GAME_COMMAND_SET_SIGN_NAME, *((int*)(text + 32)), *((int*)(text + 28))); } } /* rct2: 0x006B96F5 */ -static void window_sign_invalidate() +static void window_sign_invalidate(rct_window *w) { - rct_window* w; - - window_get_register(w); colour_scheme_update(w); rct_widget* main_colour_btn = &window_sign_widgets[WIDX_MAIN_COLOR]; @@ -406,13 +336,8 @@ static void window_sign_invalidate() } /* rct2: 0x006B9754 & 0x006E6134 */ -static void window_sign_paint() +static void window_sign_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); // Draw viewport @@ -422,11 +347,8 @@ static void window_sign_paint() } /* rct2: 0x6B9A6C & 0x6E6424 */ -static void window_sign_unknown_14() +static void window_sign_unknown_14(rct_window *w) { - rct_window* w; - window_get_register(w); - rct_viewport* view = w->viewport; w->viewport = 0; @@ -471,7 +393,7 @@ void window_sign_small_open(rct_windownumber number){ if (w != NULL) return; - w = window_create_auto_pos(WW, WH, (uint32*)window_sign_small_events, WC_BANNER, 0); + w = window_create_auto_pos(WW, WH, &window_sign_small_events, WC_BANNER, 0); w->widgets = window_sign_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | @@ -488,7 +410,7 @@ void window_sign_small_open(rct_windownumber number){ int view_x = gBanners[w->number].x << 5; int view_y = gBanners[w->number].y << 5; - + rct_map_element* map_element = map_get_first_element_at(view_x / 32, view_y / 32); while (1){ @@ -506,7 +428,8 @@ void window_sign_small_open(rct_windownumber number){ w->frame_no = view_z; 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_492 = + ((map_element->properties.fence.item[1] >> 5) | ((map_element->flags & 0x60) >> 2)); w->var_48C = map_element->properties.fence.type; view_x += 16; @@ -529,18 +452,13 @@ void window_sign_small_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; + w->flags |= WF_NO_SCROLLING; window_invalidate(w); } /* rct2: 0x6E6145 */ -static void window_sign_small_mouseup() +static void window_sign_small_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - rct_banner* banner = &gBanners[w->number]; int x = banner->x << 5; int y = banner->y << 5; @@ -564,7 +482,7 @@ static void window_sign_small_mouseup() } map_element++; } - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1158; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_REMOVE_THIS; game_do_command( x, 1 | ((map_element->type & 0x3) << 8), @@ -590,59 +508,31 @@ static void window_sign_small_mouseup() } /* rct2: 0x6E617C */ -static void window_sign_small_dropdown() +static void window_sign_small_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - short widgetIndex, dropdownIndex; - rct_window* w; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + rct_banner* banner = &gBanners[w->number]; switch (widgetIndex){ case WIDX_MAIN_COLOR: if (dropdownIndex == -1) return; w->list_information_type = dropdownIndex; + game_do_command(1, GAME_COMMAND_FLAG_APPLY, w->number, dropdownIndex, GAME_COMMAND_SET_SIGN_STYLE, w->var_492, 0); break; case WIDX_TEXT_COLOR: if (dropdownIndex == -1) return; w->var_492 = dropdownIndex; + game_do_command(1, GAME_COMMAND_FLAG_APPLY, w->number, w->list_information_type, GAME_COMMAND_SET_SIGN_STYLE, dropdownIndex, 0); break; default: return; } - rct_banner* banner = &gBanners[w->number]; - int x = banner->x << 5; - int y = banner->y << 5; - - rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); - - while (1){ - 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; - } - } - map_element++; - } - - map_element->flags &= 0x9F; - map_element->properties.fence.item[1] = - w->list_information_type | - ((w->var_492 & 0x7) << 5); - map_element->flags |= ((w->var_492 & 0x18) << 2); - - gfx_invalidate_viewport_tile(x, y, map_element->base_height * 8, map_element->clearance_height * 8); window_invalidate(w); } /* rct2: 0x006E60D5 */ -static void window_sign_small_invalidate() +static void window_sign_small_invalidate(rct_window *w) { - rct_window* w; - - window_get_register(w); colour_scheme_update(w); rct_widget* main_colour_btn = &window_sign_widgets[WIDX_MAIN_COLOR]; @@ -662,4 +552,4 @@ static void window_sign_small_invalidate() main_colour_btn->image = (w->list_information_type << 19) | 0x600013C3; text_colour_btn->image = (w->var_492 << 19) | 0x600013C3; -} \ No newline at end of file +} diff --git a/src/windows/staff.c b/src/windows/staff.c index 117d41d9ee..9d4f41b29a 100644 --- a/src/windows/staff.c +++ b/src/windows/staff.c @@ -70,9 +70,7 @@ enum WINDOW_STAFF_WIDGET_IDX { WIDX_COSTUME_BTN, }; -void window_staff_emptysub(){}; - -rct_widget window_staff_overview_widgets[] = { +rct_widget window_staff_overview_widgets[] = { { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, STR_NONE }, // Panel / Background { WWT_CAPTION, 0, 1, WW - 2, 1, 14, 0x361, STR_WINDOW_TITLE_TIP }, // Title { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // Close x button @@ -92,7 +90,7 @@ rct_widget window_staff_overview_widgets[] = { }; //0x9AF910 -rct_widget window_staff_options_widgets[] = { +rct_widget window_staff_options_widgets[] = { { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, STR_NONE }, // Panel / Background { WWT_CAPTION, 0, 1, WW - 2, 1, 14, 0x361, STR_WINDOW_TITLE_TIP }, // Title { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // Close x button @@ -111,7 +109,7 @@ rct_widget window_staff_options_widgets[] = { }; //0x9AF9F4 -rct_widget window_staff_stats_widgets[] = { +rct_widget window_staff_stats_widgets[] = { { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, STR_NONE }, // Panel / Background { WWT_CAPTION, 0, 1, WW - 2, 1, 14, 0x361, STR_WINDOW_TITLE_TIP }, // Title { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // Close x button @@ -131,141 +129,141 @@ rct_widget *window_staff_page_widgets[] = { void window_staff_set_page(rct_window* w, int page); void window_staff_disable_widgets(rct_window* w); -void window_staff_unknown_05(); +void window_staff_unknown_05(rct_window *w); void window_staff_viewport_init(rct_window* w); -void window_staff_overview_close(); -void window_staff_overview_mouseup(); -void window_staff_overview_resize(); +void window_staff_overview_close(rct_window *w); +void window_staff_overview_mouseup(rct_window *w, int widgetIndex); +void window_staff_overview_resize(rct_window *w); void window_staff_overview_mousedown(int widgetIndex, rct_window* w, rct_widget* widget); -void window_staff_overview_dropdown(); +void window_staff_overview_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); void window_staff_overview_update(rct_window* w); -void window_staff_overview_invalidate(); -void window_staff_overview_paint(); +void window_staff_overview_invalidate(rct_window *w); +void window_staff_overview_paint(rct_window *w, rct_drawpixelinfo *dpi); void window_staff_overview_tab_paint(rct_window* w, rct_drawpixelinfo* dpi); -void window_staff_overview_tool_update(); -void window_staff_overview_tool_down(); -void window_staff_overview_tool_abort(); -void window_staff_overview_text_input(); -void window_staff_overview_viewport_init_wrapper(); +void window_staff_overview_tool_update(rct_window* w, int widgetIndex, int x, int y); +void window_staff_overview_tool_down(rct_window* w, int widgetIndex, int x, int y); +void window_staff_overview_tool_abort(rct_window *w, int widgetIndex); +void window_staff_overview_text_input(rct_window *w, int widgetIndex, char *text); +void window_staff_overview_unknown_14(rct_window *w); -void window_staff_options_mouseup(); +void window_staff_options_mouseup(rct_window *w, int widgetIndex); void window_staff_options_update(rct_window* w); -void window_staff_options_invalidate(); -void window_staff_options_paint(); +void window_staff_options_invalidate(rct_window *w); +void window_staff_options_paint(rct_window *w, rct_drawpixelinfo *dpi); void window_staff_options_tab_paint(rct_window* w, rct_drawpixelinfo* dpi); void window_staff_options_mousedown(int widgetIndex, rct_window* w, rct_widget* widget); -void window_staff_options_dropdown(); +void window_staff_options_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); -void window_staff_stats_mouseup(); -void window_staff_stats_resize(); +void window_staff_stats_mouseup(rct_window *w, int widgetIndex); +void window_staff_stats_resize(rct_window *w); void window_staff_stats_update(rct_window* w); -void window_staff_stats_invalidate(); -void window_staff_stats_paint(); +void window_staff_stats_invalidate(rct_window *w); +void window_staff_stats_paint(rct_window *w, rct_drawpixelinfo *dpi); void window_staff_stats_tab_paint(rct_window* w, rct_drawpixelinfo* dpi); void window_staff_set_colours(); // 0x992AEC -static void* window_staff_overview_events[] = { +static rct_window_event_list window_staff_overview_events = { window_staff_overview_close, window_staff_overview_mouseup, window_staff_overview_resize, window_staff_overview_mousedown, window_staff_overview_dropdown, - window_staff_emptysub, + NULL, window_staff_overview_update, - window_staff_emptysub, - window_staff_emptysub, + NULL, + NULL, window_staff_overview_tool_update, window_staff_overview_tool_down, - window_staff_emptysub, - window_staff_emptysub, + NULL, + NULL, window_staff_overview_tool_abort, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, window_staff_overview_text_input, - window_staff_overview_viewport_init_wrapper, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, + window_staff_overview_unknown_14, + NULL, + NULL, + NULL, + NULL, window_staff_overview_invalidate, //Invalidate window_staff_overview_paint, //Paint - window_staff_emptysub + NULL }; // 0x992B5C -static void* window_staff_options_events[] = { - window_staff_emptysub, +static rct_window_event_list window_staff_options_events = { + NULL, window_staff_options_mouseup, window_staff_stats_resize, window_staff_options_mousedown, window_staff_options_dropdown, window_staff_unknown_05, window_staff_options_update, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_staff_options_invalidate, //Invalidate window_staff_options_paint, //Paint - window_staff_emptysub + NULL }; // 0x992BCC -static void* window_staff_stats_events[] = { - window_staff_emptysub, +static rct_window_event_list window_staff_stats_events = { + NULL, window_staff_stats_mouseup, window_staff_stats_resize, - window_staff_emptysub, - window_staff_emptysub, + NULL, + NULL, window_staff_unknown_05, window_staff_stats_update, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, - window_staff_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_staff_stats_invalidate, //Invalidate window_staff_stats_paint, //Paint - window_staff_emptysub + NULL }; -void* window_staff_page_events[] = { - window_staff_overview_events, - window_staff_options_events, - window_staff_stats_events +static rct_window_event_list *window_staff_page_events[] = { + &window_staff_overview_events, + &window_staff_options_events, + &window_staff_stats_events }; uint32 window_staff_page_enabled_widgets[] = { @@ -299,11 +297,11 @@ uint32 window_staff_page_enabled_widgets[] = { * * rct2: 0x006BEE98 */ -void window_staff_open(rct_peep* peep) +rct_window *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, WF_10 | WF_RESIZABLE); + w = window_create_auto_pos(WW, WH, &window_staff_overview_events, WC_PEEP, WF_10 | WF_RESIZABLE); w->widgets = RCT2_GLOBAL(0x9AF81C, rct_widget*); w->enabled_widgets = RCT2_GLOBAL(0x9929B0, uint32); @@ -320,7 +318,6 @@ void window_staff_open(rct_peep* peep) w->min_height = WH; w->max_width = 500; w->max_height = 450; - } w->page = 0; window_invalidate(w); @@ -335,6 +332,8 @@ void window_staff_open(rct_peep* peep) window_staff_viewport_init(w); if (g_sprite_list[w->number].peep.state == PEEP_STATE_PICKED) window_event_mouse_up_call(w, WIDX_CHECKBOX_3); + + return w; } /** @@ -369,12 +368,8 @@ void window_staff_disable_widgets(rct_window* w) * Same as window_peep_overview_close. * rct2: 0x006BDFF8 */ -void window_staff_overview_close() +void window_staff_overview_close(rct_window *w) { - rct_window* w; - - window_get_register(w); - 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)) @@ -393,16 +388,16 @@ void window_staff_set_page(rct_window* w, int page) if(w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) && w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass)) tool_cancel(); - + } - + int listen = 0; if (page == WINDOW_STAFF_OVERVIEW && w->page == WINDOW_STAFF_OVERVIEW && w->viewport){ if (!(w->viewport->flags & VIEWPORT_FLAG_SOUND_ON)) listen = 1; } - + w->page = page; w->frame_no = 0; @@ -431,11 +426,8 @@ void window_staff_set_page(rct_window* w, int page) } /** rct2: 0x006BDF55 */ -void window_staff_overview_mouseup() +void window_staff_overview_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window* w; - window_widget_get_registers(w, widgetIndex); rct_peep* peep = GET_PEEP(w->number); switch (widgetIndex) { @@ -458,7 +450,7 @@ void window_staff_overview_mouseup() w->var_48C = peep->x; remove_peep_from_ride(peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); sprite_move( 0x8000, peep->y, peep->z, (rct_sprite*)peep); peep_decrement_num_riders(peep); @@ -475,11 +467,8 @@ void window_staff_overview_mouseup() } /** rct2: 0x006BE558 */ -void window_staff_overview_resize() +void window_staff_overview_resize(rct_window *w) { - rct_window* w; - window_get_register(w); - window_staff_disable_widgets(w); w->min_width = WW; @@ -525,7 +514,7 @@ void window_staff_overview_resize() window_staff_viewport_init(w); } -/** +/** * Handle the dropdown of patrol button. * rct2: 0x006BDF98 */ @@ -543,24 +532,19 @@ void window_staff_overview_mousedown(int widgetIndex, rct_window* w, rct_widget* int y = widget->top + w->y; int extray = widget->bottom - widget->top + 1; window_dropdown_show_text(x, y, extray, w->colours[1], 0, 2); - RCT2_GLOBAL(0x009DEBA2, sint16) = 0; + gDropdownHighlightedIndex = 0; rct_peep* peep = GET_PEEP(w->number); // Disable clear patrol area if no area is set. if (!(RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[peep->staff_id] & 2)) { - RCT2_GLOBAL(0x009DED34, sint32) |= 1 << 1; + gDropdownItemsDisabled |= (1ULL << 1); } } /** rct2: 0x006BDFA3 */ -void window_staff_overview_dropdown() +void window_staff_overview_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - short widgetIndex, dropdownIndex; - rct_window* w; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (widgetIndex != WIDX_PATROL) { return; } @@ -573,7 +557,7 @@ void window_staff_overview_dropdown() for (int i = 0; i < 128; i++) { - RCT2_ADDRESS(0x13B0E72 + (peep->staff_id * 512), uint32)[i] = 0; + RCT2_ADDRESS(RCT2_ADDRESS_STAFF_PATROL_AREAS + (peep->staff_id * 512), uint32)[i] = 0; } RCT2_ADDRESS(RCT2_ADDRESS_STAFF_MODE_ARRAY, uint8)[peep->staff_id] &= ~2; @@ -591,7 +575,7 @@ void window_staff_overview_dropdown() /** * Update the animation frame of the tab icon. - * rct2: 0x6BE602 + * rct2: 0x6BE602 */ void window_staff_overview_update(rct_window* w) { @@ -616,12 +600,8 @@ void window_staff_set_order(rct_window* w, int order_id) } /** rct2: 0x006BE7DB */ -void window_staff_options_mouseup() +void window_staff_options_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window* w; - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -648,12 +628,8 @@ void window_staff_options_update(rct_window* w) } /** rct2: 0x006BEBCF */ -void window_staff_stats_mouseup() +void window_staff_stats_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window* w; - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -667,16 +643,13 @@ void window_staff_stats_mouseup() } /** rct2: 0x006BEC1B and rct2: 0x006BE975 */ -void window_staff_stats_resize() +void window_staff_stats_resize(rct_window *w) { - rct_window* w; - window_get_register(w); - w->min_width = 190; - w->max_width = 190; + w->max_width = 190; w->min_height = 119; w->max_height = 119; - + if (w->width < w->min_width) { w->width = w->min_width; window_invalidate(w); @@ -705,24 +678,21 @@ void window_staff_stats_update(rct_window* w) widget_invalidate(w, WIDX_TAB_3); rct_peep* peep = GET_PEEP(w->number); - if (peep->var_45 & 0x10) { - peep->var_45 &= 0xEF; + if (peep->window_invalidate_flags & PEEP_INVALIDATE_STAFF_STATS) { + peep->window_invalidate_flags &= ~PEEP_INVALIDATE_STAFF_STATS; window_invalidate(w); } } /* rct2: 0x6BEC80, 0x6BE9DA */ -void window_staff_unknown_05(){ - rct_window* w; - window_get_register(w); - +void window_staff_unknown_05(rct_window *w) +{ widget_invalidate(w, WIDX_TAB_1); } /* rct2: 0x006BE9E9 */ -void window_staff_stats_invalidate(){ - rct_window* w; - window_get_register(w); +void window_staff_stats_invalidate(rct_window *w) +{ colour_scheme_update_by_class(w, (rct_windowclass)WC_STAFF); if (window_staff_page_widgets[w->page] != w->widgets){ @@ -753,9 +723,8 @@ void window_staff_stats_invalidate(){ /* rct2: 0x006BE62B */ -void window_staff_options_invalidate(){ - rct_window* w; - window_get_register(w); +void window_staff_options_invalidate(rct_window *w) +{ colour_scheme_update_by_class(w, (rct_windowclass)WC_STAFF); if (window_staff_page_widgets[w->page] != w->widgets){ @@ -826,9 +795,8 @@ void window_staff_options_invalidate(){ } /* rct2: 0x006BDD91 */ -void window_staff_overview_invalidate(){ - rct_window* w; - window_get_register(w); +void window_staff_overview_invalidate(rct_window *w) +{ colour_scheme_update_by_class(w, (rct_windowclass)WC_STAFF); if (window_staff_page_widgets[w->page] != w->widgets){ @@ -837,7 +805,7 @@ void window_staff_overview_invalidate(){ } w->pressed_widgets |= 1ULL << (w->page + WIDX_TAB_1); - + rct_peep* peep = GET_PEEP(w->number); RCT2_GLOBAL(0x13CE952, uint16) = peep->name_string_idx; @@ -880,12 +848,8 @@ void window_staff_overview_invalidate(){ } /* rct2: 0x6BDEAF */ -void window_staff_overview_paint(){ - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +void window_staff_overview_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ window_draw_widgets(w, dpi); window_staff_overview_tab_paint(w, dpi); window_staff_options_tab_paint(w, dpi); @@ -915,7 +879,8 @@ void window_staff_overview_paint(){ } /* rct2: 0x6BEC8F */ -void window_staff_options_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ +void window_staff_options_tab_paint(rct_window* w, rct_drawpixelinfo* dpi) +{ if (w->disabled_widgets & (1 << WIDX_TAB_2)) return; rct_widget* widget = &w->widgets[WIDX_TAB_2]; @@ -932,7 +897,8 @@ void window_staff_options_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ } /* rct2: 0x6BECD3 */ -void window_staff_stats_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ +void window_staff_stats_tab_paint(rct_window* w, rct_drawpixelinfo* dpi) +{ if (w->disabled_widgets & (1 << WIDX_TAB_3)) return; rct_widget* widget = &w->widgets[WIDX_TAB_3]; @@ -951,7 +917,8 @@ void window_staff_stats_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ /** * Based on rct2: 0x6983dd in window_guest to be remerged into one when peep file added. */ -void window_staff_overview_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ +void window_staff_overview_tab_paint(rct_window* w, rct_drawpixelinfo* dpi) +{ if (w->disabled_widgets & (1 << WIDX_TAB_1)) return; @@ -1011,12 +978,8 @@ void window_staff_overview_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ } /* rct2: 0x6BE7C6 */ -void window_staff_options_paint(){ - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +void window_staff_options_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ window_draw_widgets(w, dpi); window_staff_overview_tab_paint(w, dpi); window_staff_options_tab_paint(w, dpi); @@ -1024,12 +987,8 @@ void window_staff_options_paint(){ } /* rct2: 0x6BEA86 */ -void window_staff_stats_paint(){ - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +void window_staff_stats_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ window_draw_widgets(w, dpi); window_staff_overview_tab_paint(w, dpi); window_staff_options_tab_paint(w, dpi); @@ -1076,14 +1035,10 @@ void window_staff_stats_paint(){ } /* rct2: 0x006BDFD8 */ -void window_staff_overview_tool_update(){ - short widgetIndex; - rct_window* w; - short x, y; - - window_tool_get_registers(w, widgetIndex, x, y); - - if (widgetIndex != WIDX_PICKUP) return; +void window_staff_overview_tool_update(rct_window* w, int widgetIndex, int x, int y) +{ + if (widgetIndex != WIDX_PICKUP) + return; RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32) = -1; @@ -1109,22 +1064,16 @@ void window_staff_overview_tool_update(){ } /* rct2: 0x006BDFC3 */ -void window_staff_overview_tool_down(){ - short widgetIndex; - rct_window* w; - short x, y; - - window_tool_get_registers(w, widgetIndex, x, y); - - if (widgetIndex == WIDX_PICKUP){ - +void window_staff_overview_tool_down(rct_window* w, int widgetIndex, int x, int y) +{ + if (widgetIndex == WIDX_PICKUP) { 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 == (sint16)0x8000)return; - // Set the coordinate of destination to be exactly + // Set the coordinate of destination to be exactly // in the middle of a tile. dest_x += 16; dest_y += 16; @@ -1139,11 +1088,7 @@ void window_staff_overview_tool_down(){ return; } - int _edx; - _edx = (dest_z / 8) | (((dest_z / 8) + 1) << 8); - int flags = RCT2_CALLPROC_X(0x68B93A, tile_x, 0xF, tile_y, _edx, (int)w, 0, 0); - - if (flags & 0x100){ + if (!map_can_construct_at(tile_x, tile_y, dest_z / 8, (dest_z / 8) + 1, 15)){ if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) != 0x3A5){ if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) != 0x49B){ window_error_open(0x785, -1); @@ -1154,7 +1099,7 @@ void window_staff_overview_tool_down(){ rct_peep* peep = GET_PEEP(w->number); sprite_move(dest_x, dest_y, dest_z, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); peep_decrement_num_riders(peep); peep->state = PEEP_STATE_FALLING; peep_window_state_update(peep); @@ -1178,19 +1123,14 @@ void window_staff_overview_tool_down(){ } /* rct2: 0x6BDFAE */ -void window_staff_overview_tool_abort(){ - short widgetIndex; - rct_window* w; - short x, y; - - window_tool_get_registers(w, widgetIndex, x, y); - if (widgetIndex == WIDX_PICKUP){ - +void window_staff_overview_tool_abort(rct_window *w, int widgetIndex) +{ + if (widgetIndex == WIDX_PICKUP) { rct_peep* peep = GET_PEEP(w->number); if (peep->state != PEEP_STATE_PICKED) return; sprite_move(w->var_48C, peep->y, peep->z + 8, (rct_sprite*)peep); - invalidate_sprite((rct_sprite*)peep); + invalidate_sprite_2((rct_sprite*)peep); if (peep->x != (sint16)0x8000){ peep_decrement_num_riders(peep); @@ -1213,30 +1153,23 @@ void window_staff_overview_tool_abort(){ } /* rct2:0x6BDFED */ -void window_staff_overview_text_input(){ - short widgetIndex; - rct_window *w; - char _cl; - uint32* text; +void window_staff_overview_text_input(rct_window *w, int widgetIndex, char *text) +{ + if (widgetIndex != WIDX_RENAME) + return; - window_text_input_get_registers(w, widgetIndex, _cl, text); + if (text == NULL) + return; - if (widgetIndex != WIDX_RENAME)return; - - if (!_cl) return; - - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = 2979; - - game_do_command(1, 1, w->number, *text, GAME_COMMAND_22, *(text + 2), *(text + 1)); - game_do_command(2, 1, 0, *(text + 3), GAME_COMMAND_22, *(text + 5), *(text + 4)); - game_do_command(0, 1, 0, *(text + 6), GAME_COMMAND_22, *(text + 8), *(text + 7)); + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_NAME_STAFF_MEMBER; + game_do_command(1, GAME_COMMAND_FLAG_APPLY, w->number, *((int*)(text + 0)), GAME_COMMAND_SET_PEEP_NAME, *((int*)(text + 8)), *((int*)(text + 4))); + game_do_command(2, GAME_COMMAND_FLAG_APPLY, w->number, *((int*)(text + 12)), GAME_COMMAND_SET_PEEP_NAME, *((int*)(text + 20)), *((int*)(text + 16))); + game_do_command(0, GAME_COMMAND_FLAG_APPLY, w->number, *((int*)(text + 24)), GAME_COMMAND_SET_PEEP_NAME, *((int*)(text + 32)), *((int*)(text + 28))); } /* rct2: 0x006BE5FC */ -void window_staff_overview_viewport_init_wrapper(){ - rct_window* w; - window_get_register(w); - +void window_staff_overview_unknown_14(rct_window *w) +{ window_staff_viewport_init(w); } @@ -1244,7 +1177,7 @@ void window_staff_overview_viewport_init_wrapper(){ void window_staff_viewport_init(rct_window* w){ if (w->page != WINDOW_STAFF_OVERVIEW) return; - sprite_focus focus; + sprite_focus focus = { 0 }; focus.sprite_id = w->number; @@ -1255,7 +1188,7 @@ void window_staff_viewport_init(rct_window* w){ } else{ focus.type |= VIEWPORT_FOCUS_TYPE_SPRITE | VIEWPORT_FOCUS_TYPE_COORDINATE; - focus.rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + focus.rotation = get_current_rotation(); } uint16 viewport_flags; @@ -1295,7 +1228,7 @@ void window_staff_viewport_init(rct_window* w){ int height = view_widget->bottom - view_widget->top - 1; viewport_create(w, x, y, width, height, 0, 0, 0, 0, focus.type & VIEWPORT_FOCUS_TYPE_MASK, focus.sprite_id); - w->flags |= WF_2; + w->flags |= WF_NO_SCROLLING; window_invalidate(w); } } @@ -1338,7 +1271,7 @@ void window_staff_options_mousedown(int widgetIndex, rct_window* w, rct_widget* rct_peep* peep = GET_PEEP(w->number); int item_checked = 0; - //This will be moved below where Items Checked is when all + //This will be moved below where Items Checked is when all //of dropdown related functions are finished. This prevents //the dropdown from not working on first click. for (int i = 0; i < no_entries; ++i){ @@ -1352,34 +1285,28 @@ void window_staff_options_mousedown(int widgetIndex, rct_window* w, rct_widget* //Get the dropdown box widget instead of button. widget--; - + int x = widget->left + w->x; 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], DROPDOWN_FLAG_STAY_OPEN, no_entries, width); - + // See above note. gDropdownItemsChecked = item_checked; } /** rct2: 0x6BE809 */ -void window_staff_options_dropdown() +void window_staff_options_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - short widgetIndex, dropdownIndex; - rct_window* w; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (widgetIndex != WIDX_COSTUME_BTN) { return; } - if (dropdownIndex == -1)return; + if (dropdownIndex == -1) + return; rct_peep* peep = GET_PEEP(w->number); - 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); } diff --git a/src/windows/staff_fire_prompt.c b/src/windows/staff_fire_prompt.c index dcf4ae0c28..564888159c 100644 --- a/src/windows/staff_fire_prompt.c +++ b/src/windows/staff_fire_prompt.c @@ -50,50 +50,50 @@ static rct_widget window_staff_fire_widgets[] = { { WIDGETS_END } }; -static void window_staff_fire_emptysub(){} -static void window_staff_fire_mouseup(); -static void window_staff_fire_invalidate(); -static void window_staff_fire_paint(); +static void window_staff_fire_mouseup(rct_window *w, int widgetIndex); +static void window_staff_fire_invalidate(rct_window *w); +static void window_staff_fire_paint(rct_window *w, rct_drawpixelinfo *dpi); //0x9A3F7C -static void* window_staff_fire_events[] = { - window_staff_fire_emptysub, +static rct_window_event_list window_staff_fire_events = { + NULL, window_staff_fire_mouseup, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, - window_staff_fire_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_staff_fire_invalidate, window_staff_fire_paint, - window_staff_fire_emptysub + NULL }; /** Based off of rct2: 0x6C0A77 */ -void window_staff_fire_prompt_open(rct_peep* peep){ +void window_staff_fire_prompt_open(rct_peep* peep) +{ // Check if the confirm window already exists. if (window_bring_to_front_by_number(WC_FIRE_PROMPT, peep->sprite_index)) { return; } - rct_window* w = window_create_centred(WW, WH, (uint32*)0x992C3C, 0x1A, WF_TRANSPARENT); + rct_window* w = window_create_centred(WW, WH, &window_staff_fire_events, WC_FIRE_PROMPT, WF_TRANSPARENT); w->widgets = window_staff_fire_widgets; w->enabled_widgets |= (1 << WIDX_CLOSE) | (1 << WIDX_YES) | (1 << WIDX_CANCEL); @@ -109,14 +109,10 @@ void window_staff_fire_prompt_open(rct_peep* peep){ * * rct2: 0x006C0B40 */ -static void window_staff_fire_mouseup(){ - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - +static void window_staff_fire_mouseup(rct_window *w, int widgetIndex) +{ rct_peep* peep = &g_sprite_list[w->number].peep; - + switch (widgetIndex){ case WIDX_YES: game_do_command(peep->x, 1, peep->y, w->number, GAME_COMMAND_FIRE_STAFF_MEMBER, 0, 0); @@ -127,11 +123,8 @@ static void window_staff_fire_mouseup(){ } } -static void window_staff_fire_invalidate() +static void window_staff_fire_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); } @@ -139,21 +132,17 @@ static void window_staff_fire_invalidate() * * rct2: 0x006C0AF2 */ -static void window_staff_fire_paint(){ - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +static void window_staff_fire_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ window_draw_widgets(w, dpi); rct_peep* peep = &g_sprite_list[w->number].peep; - + RCT2_GLOBAL(0x13CE952, uint16) = peep->name_string_idx; RCT2_GLOBAL(0x13CE954, uint32) = peep->id; - + int x = w->x + WW / 2; int y = w->y + (WH / 2) - 3; - + gfx_draw_string_centred_wrapped(dpi, (void*)0x13CE952, x, y, WW - 4, STR_FIRE_STAFF_ID, 0); } diff --git a/src/windows/staff_list.c b/src/windows/staff_list.c index 18014ac40e..797531f490 100644 --- a/src/windows/staff_list.c +++ b/src/windows/staff_list.c @@ -23,16 +23,18 @@ #include "../game.h" #include "../drawing/drawing.h" #include "../input.h" +#include "../interface/themes.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 "../sprites.h" +#include "../world/footpath.h" #include "../world/sprite.h" #include "dropdown.h" -#include "../interface/themes.h" -#include "../sprites.h" +#include "error.h" enum { WINDOW_STAFF_LIST_TAB_HANDYMEN, @@ -43,49 +45,48 @@ enum { bool _quick_fire_mode = false; -static void window_staff_list_emptysub() { } -static void window_staff_list_close(); -static void window_staff_list_mouseup(); -static void window_staff_list_resize(); +static void window_staff_list_close(rct_window *w); +static void window_staff_list_mouseup(rct_window *w, int widgetIndex); +static void window_staff_list_resize(rct_window *w); static void window_staff_list_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_staff_list_dropdown(); +static void window_staff_list_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); static void window_staff_list_update(rct_window *w); -static void window_staff_list_tooldown(); -static void window_staff_list_toolabort(); -static void window_staff_list_scrollgetsize(); -static void window_staff_list_scrollmousedown(); -static void window_staff_list_scrollmouseover(); -static void window_staff_list_tooltip(); -static void window_staff_list_invalidate(); -static void window_staff_list_paint(); -static void window_staff_list_scrollpaint(); +static void window_staff_list_tooldown(rct_window *w, int widgetIndex, int x, int y); +static void window_staff_list_toolabort(rct_window *w, int widgetIndex); +static void window_staff_list_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_staff_list_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_staff_list_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_staff_list_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_staff_list_invalidate(rct_window *w); +static void window_staff_list_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_staff_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void* window_staff_list_events[] = { +static rct_window_event_list window_staff_list_events = { window_staff_list_close, window_staff_list_mouseup, window_staff_list_resize, window_staff_list_mousedown, window_staff_list_dropdown, - window_staff_list_emptysub, + NULL, window_staff_list_update, - window_staff_list_emptysub, - window_staff_list_emptysub, - window_staff_list_emptysub, - (void*)0x006BD990, // window_staff_list_tooldown - window_staff_list_emptysub, - window_staff_list_emptysub, + NULL, + NULL, + NULL, + window_staff_list_tooldown, + NULL, + NULL, window_staff_list_toolabort, - window_staff_list_emptysub, + NULL, window_staff_list_scrollgetsize, window_staff_list_scrollmousedown, - window_staff_list_emptysub, + NULL, window_staff_list_scrollmouseover, - window_staff_list_emptysub, - window_staff_list_emptysub, - window_staff_list_emptysub, + NULL, + NULL, + NULL, window_staff_list_tooltip, - window_staff_list_emptysub, - window_staff_list_emptysub, + NULL, + NULL, window_staff_list_invalidate, window_staff_list_paint, window_staff_list_scrollpaint, @@ -151,7 +152,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, WF_10 | WF_RESIZABLE); + window = window_create_auto_pos(320, 270, &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) | @@ -188,11 +189,8 @@ void window_staff_list_cancel_tools(rct_window *w) { /* * rct2: 0x006BD9B1 **/ -void window_staff_list_close() { - rct_window *w; - - window_get_register(w); - +void window_staff_list_close(rct_window *w) +{ window_staff_list_cancel_tools(w); } @@ -200,14 +198,10 @@ void window_staff_list_close() { * * rct2: 0x006BD94C */ -static void window_staff_list_mouseup() +static void window_staff_list_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; uint16 newStaffId; - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_STAFF_LIST_CLOSE: window_close(w); @@ -224,14 +218,11 @@ static void window_staff_list_mouseup() break; case WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON: - RCT2_CALLPROC_X(0x006BD9FF, 0, 0, 0, widgetIndex, (int)w, 0, 0); - - // TODO: The code below works, but due to some funny things, when clicking again on the show patrol area button to disable the tool, - // the mouseup event is getting called when it should not be - //tool_set(w, WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON, 0x0C); - //show_gridlines(); - //RCT2_GLOBAL(0x009DEA50, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8) | 0x8000; - //gfx_invalidate_screen(); + if (!tool_set(w, WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON, 12)) { + show_gridlines(); + RCT2_GLOBAL(0x009DEA50, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8) | 0x8000; + gfx_invalidate_screen(); + } break; case WIDX_STAFF_LIST_MAP: window_map_open(); @@ -247,12 +238,8 @@ static void window_staff_list_mouseup() * * rct2: 0x006BDD5D */ -static void window_staff_list_resize() +static void window_staff_list_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - w->min_width = 320; w->min_height = 270; if (w->width < w->min_width) { @@ -299,12 +286,8 @@ static void window_staff_list_mousedown(int widgetIndex, rct_window* w, rct_widg * * rct2: 0x006BD9A6 */ -static void window_staff_list_dropdown() +static void window_staff_list_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - rct_window* w; - short widgetIndex, dropdownIndex; - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (widgetIndex == WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER && dropdownIndex != -1) { update_staff_colour(RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8), dropdownIndex); } @@ -337,16 +320,69 @@ void window_staff_list_update(rct_window *w) } } +/** + * + * rct2: 0x006BD990 + */ +static void window_staff_list_tooldown(rct_window *w, int widgetIndex, int x, int y) +{ + int direction, distance, closestPeepDistance, selectedPeepType; + rct_map_element *mapElement; + rct_peep *peep, *closestPeep; + uint16 spriteIndex; + + if (widgetIndex == WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON) { + selectedPeepType = RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8); + + footpath_get_coordinates_from_pos(x, y, &x, &y, &direction, &mapElement); + if (x == 0x8000) + return; + + bool isPatrolAreaSet = staff_is_patrol_area_set(200 + selectedPeepType, x, y); + + closestPeep = NULL; + closestPeepDistance = INT_MAX; + FOR_ALL_STAFF(spriteIndex, peep) { + if (peep->staff_type != selectedPeepType) + continue; + + if (isPatrolAreaSet) { + if (!(gStaffModes[peep->staff_id] & 2)) { + continue; + } + if (!mechanic_is_location_in_patrol(peep, x, y)) { + continue; + } + } + + if (peep->x == (sint16)0x8000) { + continue; + } + + distance = abs(x - peep->x) + abs(y - peep->y); + if (distance < closestPeepDistance) { + closestPeepDistance = distance; + closestPeep = peep; + } + } + + if (closestPeep != NULL) { + tool_cancel(); + rct_window *staffWindow = window_staff_open(closestPeep); + window_event_dropdown_call(staffWindow, 11, 0); + } else { + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, rct_string_id) = STR_HANDYMAN_PLURAL + selectedPeepType; + window_error_open(STR_NO_THING_IN_PARK_YET, STR_NONE); + } + } +} + /** * * rct2: 0x006BD99B */ -void window_staff_list_toolabort() { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - +void window_staff_list_toolabort(rct_window *w, int widgetIndex) +{ if (widgetIndex == WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON) { hide_gridlines(); tool_cancel(); @@ -359,13 +395,10 @@ void window_staff_list_toolabort() { * * rct2: 0x006BDBE6 */ -void window_staff_list_scrollgetsize() +void window_staff_list_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - int i, width, height, spriteIndex; + int i, spriteIndex; rct_peep *peep; - rct_window *w; - - window_get_register(w); uint16 staffCount = 0; FOR_ALL_PEEPS(spriteIndex, peep) { @@ -379,9 +412,9 @@ void window_staff_list_scrollgetsize() RCT2_GLOBAL(RCT2_ADDRESS_STAFF_HIGHLIGHTED_INDEX, short) = -1; window_invalidate(w); } - - height = staffCount * 10; - i = height - 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) { @@ -389,22 +422,18 @@ void window_staff_list_scrollgetsize() window_invalidate(w); } - width = 420; - window_scrollsize_set_registers(width, height); + *width = 420; } /** * * rct2: 0x006BDC9A */ -void window_staff_list_scrollmousedown() { +void window_staff_list_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) +{ int i, spriteIndex; - short x, y, scrollIndex; - rct_window *w; rct_peep *peep; - window_scrollmouse_get_registers(w, scrollIndex, x, y); - i = y / 10; FOR_ALL_PEEPS(spriteIndex, peep) { if (peep->type != PEEP_TYPE_STAFF) @@ -429,12 +458,9 @@ void window_staff_list_scrollmousedown() { * * rct2: 0x006BDC6B */ -void window_staff_list_scrollmouseover() { +void window_staff_list_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) +{ int i; - short x, y, scrollIndex; - rct_window *w; - - window_scrollmouse_get_registers(w, scrollIndex, x, y); i = y / 10; if (i != RCT2_GLOBAL(RCT2_ADDRESS_STAFF_HIGHLIGHTED_INDEX, short)) { @@ -447,20 +473,17 @@ void window_staff_list_scrollmouseover() { * * rct2: 0x006BDC90 */ -void window_staff_list_tooltip() +void window_staff_list_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) { - RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = STR_LIST; } /** * * rct2: 0x006BD477 */ -void window_staff_list_invalidate() +void window_staff_list_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); int pressed_widgets = w->pressed_widgets & 0xFFFFFF0F; @@ -470,7 +493,7 @@ void window_staff_list_invalidate() w->pressed_widgets = pressed_widgets | (1 << widgetIndex); window_staff_list_widgets[WIDX_STAFF_LIST_HIRE_BUTTON].image = STR_HIRE_HANDYMAN + tabIndex; window_staff_list_widgets[WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER].type = WWT_EMPTY; - + if (tabIndex < 3) { window_staff_list_widgets[WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER].type = WWT_COLORBTN; window_staff_list_widgets[WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER].image = @@ -497,13 +520,10 @@ void window_staff_list_invalidate() * * rct2: 0x006BD533 */ -void window_staff_list_paint() { +void window_staff_list_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ int i; uint8 selectedTab; - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); // Widgets window_draw_widgets(w, dpi); @@ -553,8 +573,8 @@ void window_staff_list_paint() { window_staff_list_widgets[WIDX_STAFF_LIST_ENTERTAINERS_TAB].top + w->y + 1, window_staff_list_widgets[WIDX_STAFF_LIST_ENTERTAINERS_TAB].bottom - window_staff_list_widgets[WIDX_STAFF_LIST_ENTERTAINERS_TAB].top - 1 ); - - + + if (sprite_dpi != NULL) { // Entertainers tab image @@ -570,7 +590,7 @@ void window_staff_list_paint() { } if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) { - RCT2_GLOBAL(0x013CE952, uint32) = RCT2_ADDRESS(0x00992A00, uint16)[selectedTab]; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) = RCT2_ADDRESS(0x00992A00, uint16)[selectedTab]; gfx_draw_string_left(dpi, 1858, (void*)0x013CE952, 0, w->x + 0xA5, w->y + 0x20); } @@ -584,7 +604,7 @@ void window_staff_list_paint() { staffTypeStringId += 4; } - RCT2_GLOBAL(0x013CE952, uint16) = _window_staff_list_selected_type_count; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = _window_staff_list_selected_type_count; RCT2_GLOBAL(0x013CE952 + 2, uint16) = staffTypeStringId; gfx_draw_string_left(dpi, STR_STAFF_LIST_COUNTER, (void*)0x013CE952, 0, w->x + 4, window_staff_list_widgets[WIDX_STAFF_LIST_LIST].bottom + w->y + 2); @@ -594,18 +614,14 @@ void window_staff_list_paint() { * * rct2: 0x006BD785 */ -void window_staff_list_scrollpaint() +void window_staff_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { int spriteIndex, y, i, staffOrderIcon_x, staffOrders, staffOrderSprite; uint32 argument_1, argument_2; uint8 selectedTab; - rct_window *w; - rct_drawpixelinfo *dpi; rct_peep *peep; - window_paint_get_registers(w, dpi); - - 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_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, ColourMapA[w->colours[1]].mid_light); y = 0; i = 0; @@ -624,12 +640,12 @@ void window_staff_list_scrollpaint() format = (_quick_fire_mode ? 5299 : 1193); } - RCT2_GLOBAL(0x013CE952, uint16) = peep->name_string_idx; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = peep->name_string_idx; RCT2_GLOBAL(0x013CE952 + 2, uint32) = peep->id; gfx_draw_string_left_clipped(dpi, format, (void*)0x013CE952, 0, 0, y - 1, 107); get_arguments_from_action(peep, &argument_1, &argument_2); - RCT2_GLOBAL(0x013CE952, uint32) = argument_1; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) = argument_1; RCT2_GLOBAL(0x013CE952 + 4, uint32) = argument_2; gfx_draw_string_left_clipped(dpi, format, (void*)0x013CE952, 0, 175, y - 1, 305); @@ -640,7 +656,7 @@ void window_staff_list_scrollpaint() staffOrderIcon_x = 0x7D; if (peep->staff_type != 3) { - staffOrders = peep->var_C6; + staffOrders = peep->staff_orders; staffOrderSprite = RCT2_ADDRESS(0x00992A08, uint32)[selectedTab]; while (staffOrders != 0) { diff --git a/src/windows/text_input.c b/src/windows/text_input.c index c6dcfd9008..48cbef83d6 100644 --- a/src/windows/text_input.c +++ b/src/windows/text_input.c @@ -21,7 +21,7 @@ /** * Text Input Window * - * This is a new window created to replace the windows dialog box + * This is a new window created to replace the windows dialog box * that is used for inputing new text for ride names and peep names. */ @@ -31,6 +31,7 @@ #include "../interface/window.h" #include "../interface/widget.h" #include "../localisation/localisation.h" +#include "../util/util.h" #define WW 250 #define WH 90 @@ -53,44 +54,43 @@ static rct_widget window_text_input_widgets[] = { { WIDGETS_END } }; -static void window_text_input_emptysub(){} -static void window_text_input_mouseup(); -static void window_text_input_paint(); +static void window_text_input_close(rct_window *w); +static void window_text_input_mouseup(rct_window *w, int widgetIndex); +static void window_text_input_update7(rct_window *w); static void window_text_input_text(int key, rct_window* w); -static void window_text_input_update7(); -static void window_text_input_close(); -static void window_text_input_invalidate(); +static void window_text_input_invalidate(rct_window *w); +static void window_text_input_paint(rct_window *w, rct_drawpixelinfo *dpi); //0x9A3F7C -static void* window_text_input_events[] = { +static rct_window_event_list window_text_input_events = { window_text_input_close, window_text_input_mouseup, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, window_text_input_update7, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_text, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_emptysub, - window_text_input_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_text_input_invalidate, window_text_input_paint, - window_text_input_emptysub + NULL }; int input_text_description; @@ -118,12 +118,14 @@ void window_text_input_open(rct_window* call_w, int call_widget, rct_string_id t // from crashing the game. text_input[maxLength - 1] = '\0'; + utf8_remove_format_codes(text_input); + // 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); + safe_strncpy(wrapped_string, text_input, 512); int no_lines = 0, font_height = 0; @@ -135,9 +137,9 @@ void window_text_input_open(rct_window* call_w, int call_widget, rct_string_id t // Window will be in the center of the screen rct_window* w = window_create_centred( - WW, + WW, height, - (uint32*)window_text_input_events, + &window_text_input_events, WC_TEXTINPUT, WF_STICK_TO_FRONT ); @@ -173,7 +175,7 @@ void window_text_input_raw_open(rct_window* call_w, int call_widget, rct_string_ // Enter in the the text input buffer any existing // text. if (existing_text != NULL) - strncpy(text_input, existing_text, maxLength); + safe_strncpy(text_input, existing_text, maxLength); // In order to prevent strings that exceed the maxLength // from crashing the game. @@ -184,7 +186,7 @@ void window_text_input_raw_open(rct_window* call_w, int call_widget, rct_string_ // Work out the existing size of the window char wrapped_string[512]; - strcpy(wrapped_string, text_input); + safe_strncpy(wrapped_string, text_input, 512); int no_lines = 0, font_height = 0; @@ -198,7 +200,7 @@ void window_text_input_raw_open(rct_window* call_w, int call_widget, rct_string_ rct_window* w = window_create_centred( WW, height, - (uint32*)window_text_input_events, + &window_text_input_events, WC_TEXTINPUT, WF_STICK_TO_FRONT ); @@ -225,14 +227,11 @@ void window_text_input_raw_open(rct_window* call_w, int call_widget, rct_string_ /** * */ -static void window_text_input_mouseup(){ - short widgetIndex; - rct_window *w; +static void window_text_input_mouseup(rct_window *w, int widgetIndex) +{ rct_window *calling_w; - window_widget_get_registers(w, widgetIndex); calling_w = window_find_by_number(calling_class, calling_number); - switch (widgetIndex){ case WIDX_CANCEL: case WIDX_CLOSE: @@ -256,19 +255,15 @@ static void window_text_input_mouseup(){ /** * */ -static void window_text_input_paint(){ - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +static void window_text_input_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ window_draw_widgets(w, dpi); int y = w->y + 25; - + 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); @@ -278,7 +273,7 @@ static void window_text_input_paint(){ RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16) = 0; char wrapped_string[512]; - strcpy(wrapped_string, text_input); + safe_strncpy(wrapped_string, text_input, 512); // String length needs to add 12 either side of box // +13 for cursor when max length. @@ -292,16 +287,18 @@ static void window_text_input_paint(){ int char_count = 0; uint8 cur_drawn = 0; - for (int line = 0; line <= no_lines; ++line){ + int cursorX, cursorY; + for (int line = 0; line <= no_lines; line++) { gfx_draw_string(dpi, wrap_pointer, w->colours[1], w->x + 12, y); - int string_length = get_string_length(wrap_pointer); + int string_length = get_string_size(wrap_pointer) - 1; - if (!cur_drawn && (gTextInputCursorPosition <= char_count + string_length)){ + 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); + cursorX = w->x + 13 + gfx_get_string_width(temp_string); + cursorY = y; int width = 6; if ((uint32)gTextInputCursorPosition < strlen(text_input)){ @@ -313,13 +310,13 @@ static void window_text_input_paint(){ } 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); + uint8 colour = ColourMapA[w->colours[1]].mid_light; + gfx_fill_rect(dpi, cursorX, y + 9, cursorX + width, y + 9, colour + 5); } cur_drawn++; } - + wrap_pointer += string_length + 1; if (text_input[char_count + string_length] == ' ')char_count++; @@ -327,11 +324,28 @@ static void window_text_input_paint(){ y += 10; } + + if (!cur_drawn) { + cursorX = gLastDrawStringX; + cursorY = y - 10; + } + + // IME composition + if (gTextInputCompositionActive) { + int compositionWidth = gfx_get_string_width(gTextInputComposition); + int x = cursorX - (compositionWidth / 2); + int y = cursorY + 13; + int w = compositionWidth; + int h = 10; + + gfx_fill_rect(dpi, x - 1, y - 1, x + w + 1, y + h + 1, 12); + gfx_fill_rect(dpi, x, y, x + w, y + h, 0); + gfx_draw_string(dpi, gTextInputComposition, 12, x, y); + } } - -static void window_text_input_text(int key, rct_window* w){ - +void window_text_input_key(rct_window* w, int key) +{ int text = key; char new_char = platform_scancode_to_rct_keycode(0xFF&key); @@ -345,16 +359,12 @@ static void window_text_input_text(int key, rct_window* w){ if (calling_w) window_event_textinput_call(calling_w, calling_widget, text_input); } - + window_invalidate(w); } -void window_text_input_update7() +void window_text_input_update7(rct_window *w) { - 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. @@ -368,21 +378,18 @@ void window_text_input_update7() window_invalidate(w); } -static void window_text_input_close() +static void window_text_input_close(rct_window *w) { // Make sure that we take it out of the text input // mode otherwise problems may occur. platform_stop_text_input(); } -static void window_text_input_invalidate(){ - rct_window* w; - - window_get_register(w); - +static void window_text_input_invalidate(rct_window *w) +{ // Work out the existing size of the window char wrapped_string[512]; - strcpy(wrapped_string, text_input); + safe_strncpy(wrapped_string, text_input, 512); int no_lines = 0, font_height = 0; @@ -405,4 +412,4 @@ static void window_text_input_invalidate(){ 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 index 265da25fb9..51694d493d 100644 --- a/src/windows/themes.c +++ b/src/windows/themes.c @@ -34,6 +34,7 @@ #include "dropdown.h" #include "../interface/themes.h" #include "error.h" +#include "../util/util.h" enum { WINDOW_THEMES_TAB_SETTINGS, @@ -48,49 +49,47 @@ enum { 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_mouseup(rct_window *w, int widgetIndex); +static void window_themes_resize(rct_window *w); static void window_themes_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_themes_dropdown(); +static void window_themes_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); 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_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_themes_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_themes_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_themes_textinput(rct_window *w, int widgetIndex, char *text); +static void window_themes_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_themes_invalidate(rct_window *w); +static void window_themes_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_themes_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); static void window_themes_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w); -static void* window_themes_events[] = { - window_themes_close, +static rct_window_event_list window_themes_events = { + NULL, window_themes_mouseup, window_themes_resize, window_themes_mousedown, window_themes_dropdown, - window_themes_emptysub, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_themes_scrollgetsize, window_themes_scrollmousedown, - window_themes_emptysub, + NULL, window_themes_scrollmouseover, window_themes_textinput, - window_themes_emptysub, - window_themes_emptysub, + NULL, + NULL, window_themes_tooltip, - window_themes_emptysub, - window_themes_emptysub, + NULL, + NULL, window_themes_invalidate, window_themes_paint, window_themes_scrollpaint, @@ -240,6 +239,7 @@ static rct_windowclass window_themes_tab_5_classes[] = { static rct_windowclass window_themes_tab_6_classes[] = { WC_CHEATS, WC_THEMES, + WC_TITLE_EDITOR, WC_OPTIONS, WC_KEYBOARD_SHORTCUT_LIST, WC_CHANGE_KEYBOARD_SHORTCUT, @@ -368,7 +368,7 @@ void window_themes_open() if (window != NULL) return; - window = window_create_auto_pos(320, 107, (uint32*)window_themes_events, WC_THEMES, WF_10 | WF_RESIZABLE); + window = window_create_auto_pos(320, 107, &window_themes_events, WC_THEMES, WF_10 | WF_RESIZABLE); window->widgets = window_themes_widgets; window->enabled_widgets = (1 << WIDX_THEMES_CLOSE) | @@ -403,19 +403,8 @@ void window_themes_open() window->max_height = 107; } -void window_themes_close() { - rct_window *w; - - window_get_register(w); -} - -static void window_themes_mouseup() +static void window_themes_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_THEMES_CLOSE: window_close(w); @@ -442,12 +431,8 @@ static void window_themes_mouseup() } } -static void window_themes_resize() +static void window_themes_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - if (_selected_tab == WINDOW_THEMES_TAB_SETTINGS) { w->min_width = 320; w->min_height = 107; @@ -548,13 +533,13 @@ static void window_themes_mousedown(int widgetIndex, rct_window* w, rct_widget* widget--; gDropdownItemsFormat[0] = 2777; - gDropdownItemsArgs[0] = (uint64)&gConfigThemes.presets[1].name; + gDropdownItemsArgs[0] = (uint32)&gConfigThemes.presets[1].name; gDropdownItemsFormat[1] = 2777; - gDropdownItemsArgs[1] = (uint64)&gConfigThemes.presets[0].name; + gDropdownItemsArgs[1] = (uint32)&gConfigThemes.presets[0].name; for (i = 2; i < num_items; i++) { gDropdownItemsFormat[i] = 2777; - gDropdownItemsArgs[i] = (uint64)&gConfigThemes.presets[i].name; + gDropdownItemsArgs[i] = (uint32)&gConfigThemes.presets[i].name; } window_dropdown_show_text_custom_width( @@ -567,10 +552,11 @@ static void window_themes_mousedown(int widgetIndex, rct_window* w, rct_widget* widget->right - widget->left - 3 ); - if (gCurrentTheme == 0 || gCurrentTheme == 1) - gDropdownItemsChecked = 1 << (gCurrentTheme ^ 1); - else - gDropdownItemsChecked = 1 << (gCurrentTheme); + if (gCurrentTheme == 0 || gCurrentTheme == 1) { + dropdown_set_checked(gCurrentTheme ^ 1, true); + } else { + dropdown_set_checked(gCurrentTheme, true); + } break; case WIDX_THEMES_RCT1_RIDE_LIGHTS: if (gCurrentTheme >= 2) { @@ -605,16 +591,12 @@ static void window_themes_mousedown(int widgetIndex, rct_window* w, rct_widget* } } -static void window_themes_dropdown() +static void window_themes_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - 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; + 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; @@ -645,11 +627,8 @@ void window_themes_update(rct_window *w) } -void window_themes_scrollgetsize() { - rct_window *w; - - window_get_register(w); - +void window_themes_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) +{ if (_selected_tab == WINDOW_THEMES_TAB_SETTINGS || _selected_tab == WINDOW_THEMES_TAB_FEATURES) return; @@ -662,25 +641,12 @@ void window_themes_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; + *height = scrollHeight; } -void window_themes_scrollmousedown() { - short x, y, scrollIndex; - rct_window *w; - - window_scrollmouse_get_registers(w, scrollIndex, x, y); - +void window_themes_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) +{ if (y / _row_height < get_colour_scheme_tab_count()) { int y2 = y % _row_height; _color_index_1 = y / _row_height; @@ -718,41 +684,21 @@ void window_themes_scrollmousedown() { } } -void window_themes_scrollmouseover() { - short x, y, scrollIndex; - rct_window *w; - - window_scrollmouse_get_registers(w, scrollIndex, x, y); - +void window_themes_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) +{ //if (_selected_tab == WINDOW_THEMES_TAB_SETTINGS) // return; } -static bool valid_characters(const char *name) +static void window_themes_textinput(rct_window *w, int widgetIndex, char *text) { - 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) + if (text == NULL || text[0] == 0) return; switch (widgetIndex) { case WIDX_THEMES_DUPLICATE_BUTTON: case WIDX_THEMES_RENAME_BUTTON: - if (valid_characters(text)) { + if (filename_valid_characters(text)) { bool nameTaken = false; for (int i = 0; i < gConfigThemes.num_presets; i++) { if (strcmp(gConfigThemes.presets[i].name, text) == 0) { @@ -779,16 +725,13 @@ static void window_themes_textinput() } } -void window_themes_tooltip() +void window_themes_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) { - RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = STR_LIST; } -void window_themes_invalidate() +void window_themes_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); int pressed_widgets = w->pressed_widgets & 0xFFFFE00F; @@ -811,7 +754,7 @@ void window_themes_invalidate() 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; @@ -861,12 +804,8 @@ void window_themes_invalidate() } } -void window_themes_paint() { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - +void window_themes_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ // Widgets window_draw_widgets(w, dpi); window_themes_draw_tab_images(dpi, w); @@ -897,20 +836,16 @@ void window_themes_paint() { * * rct2: 0x006BD785 */ -void window_themes_scrollpaint() +void window_themes_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { 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); + //gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, ColourMapA[w->colours[1]].mid_light); + gfx_clear(dpi, ColourMapA[w->colours[1]].mid_light * 0x1010101); y = 0; for (int i = 0; i < get_colour_scheme_tab_count(); i++) { if (y > dpi->y + dpi->height) { @@ -927,9 +862,9 @@ void window_themes_scrollpaint() 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]; + colour = ColourMapA[w->colours[1]].mid_dark; 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]; + colour = ColourMapA[w->colours[1]].lightest; gfx_fill_rect(dpi, 0, y + _row_height - 1, window_themes_widgets[WIDX_THEMES_LIST].right, y + _row_height - 1, colour); } } @@ -947,7 +882,7 @@ void window_themes_scrollpaint() 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); + gfx_draw_string(dpi, (char*)CheckBoxMarkString, w->colours[1] & 0x7F, _button_offset_x + 12 * j, y + _check_offset_y); } } diff --git a/src/windows/tile_inspector.c b/src/windows/tile_inspector.c index 539b3a2f9b..e6e8122b24 100644 --- a/src/windows/tile_inspector.c +++ b/src/windows/tile_inspector.c @@ -31,6 +31,7 @@ enum WINDOW_TILE_INSPECTOR_WIDGET_IDX { WIDX_BACKGROUND, WIDX_TITLE, WIDX_CLOSE, + WIDX_CORRUPT, WIDX_CONTENT_PANEL, WIDX_SCROLL }; @@ -44,6 +45,7 @@ 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_CLOSEBOX, 1, WW - 150, WW - 3, 18, 39, STR_INSERT_CORRUPT, STR_INSERT_CORRUPT_TIP }, { 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 }, @@ -53,45 +55,44 @@ 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_close(rct_window *w); +static void window_tile_inspector_mouseup(rct_window *w, int widgetIndex); +static void window_tile_inspector_resize(rct_window *w); +static void window_tile_inspector_tool_update(rct_window* w, int widgetIndex, int x, int y); +static void window_tile_inspector_tool_down(rct_window* w, int widgetIndex, int x, int y); +static void window_tile_inspector_tool_abort(rct_window *w, int widgetIndex); +static void window_tile_inspector_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_tile_inspector_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_tile_inspector_invalidate(rct_window *w); +static void window_tile_inspector_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_tile_inspector_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void* window_tile_inspector_events[] = { +static rct_window_event_list 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_tile_inspector_tool_update, window_tile_inspector_tool_down, - window_tile_inspector_emptysub, - window_tile_inspector_emptysub, + NULL, + NULL, window_tile_inspector_tool_abort, - window_tile_inspector_emptysub, + NULL, window_tile_inspector_scrollgetsize, - window_tile_inspector_emptysub, - window_tile_inspector_emptysub, + NULL, + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_tile_inspector_invalidate, window_tile_inspector_paint, window_tile_inspector_scrollpaint @@ -111,12 +112,13 @@ void window_tile_inspector_open() 29, WW, WH, - (uint32*)window_tile_inspector_events, + &window_tile_inspector_events, WC_TILE_INSPECTOR, WF_RESIZABLE ); window->widgets = window_tile_inspector_widgets; window->enabled_widgets = (1 << WIDX_CLOSE); + window->disabled_widgets = (1 << WIDX_CORRUPT); window_init_scroll_widgets(window); window->colours[0] = 7; @@ -133,31 +135,39 @@ void window_tile_inspector_open() tool_set(window, WIDX_BACKGROUND, 12); } -static void window_tile_inspector_close() +static void window_tile_inspector_close(rct_window *w) { tool_cancel(); } -static void window_tile_inspector_mouseup() +void corrupt_element(int x, int y) { + rct_map_element* mapElement; + mapElement = map_get_first_element_at(x, y); + + while (!map_element_is_last_for_tile(mapElement++)); + mapElement--; + + mapElement = map_element_insert(x, y, mapElement->base_height, 0); + mapElement->type = (8 << 2); +} + +static void window_tile_inspector_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); break; + case WIDX_CORRUPT: + corrupt_element(window_tile_inspector_tile_x, window_tile_inspector_tile_y); + window_tile_inspector_item_count++; + w->scrolls[0].v_top = 0; + window_invalidate(w); + break; } } -static void window_tile_inspector_resize() +static void window_tile_inspector_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - w->min_width = WW; w->min_height = MIN_WH; if (w->width < w->min_width) { @@ -170,49 +180,46 @@ static void window_tile_inspector_resize() } } -static void window_tile_inspector_tool_update() +static void window_tile_inspector_tool_update(rct_window* w, int widgetIndex, int x, int y) { - short widgetIndex; - rct_window *w; - short x, y; int direction; + short mapX, mapY; - 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) { + mapX = x; + mapY = y; + screen_pos_to_map_pos(&mapX, &mapY, &direction); + if (mapX == (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_A_X, sint16) = mapX; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) = mapY; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) = mapX; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) = mapY; RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; map_invalidate_selection_rect(); } -static void window_tile_inspector_tool_down() +static void window_tile_inspector_tool_down(rct_window* w, int widgetIndex, int x, int y) { - short widgetIndex; - rct_window* w; - short x, y; int direction; + short mapX, mapY; - window_tool_get_registers(w, widgetIndex, x, y); - screen_pos_to_map_pos(&x, &y, &direction); - - if (x == (short)0x8000) { + mapX = x; + mapY = y; + screen_pos_to_map_pos(&mapX, &mapY, &direction); + if (mapX == (short)0x8000) { return; } - window_tile_inspector_tile_x = x >> 5; - window_tile_inspector_tile_y = y >> 5; + window_tile_inspector_tile_x = mapX >> 5; + window_tile_inspector_tile_y = mapY >> 5; rct_map_element *element = map_get_first_element_at(window_tile_inspector_tile_x, window_tile_inspector_tile_y); int numItems = 0; @@ -222,47 +229,31 @@ static void window_tile_inspector_tool_down() window_tile_inspector_item_count = numItems; + w->enabled_widgets |= (1 << WIDX_CORRUPT); + w->disabled_widgets &= ~(1ULL << WIDX_CORRUPT); + w->scrolls[0].v_top = 0; window_invalidate(w); } -static void window_tile_inspector_tool_abort() +static void window_tile_inspector_tool_abort(rct_window *w, int widgetIndex) { - rct_window *w; - short widgetIndex, x, y; - window_tool_get_registers(w, widgetIndex, x, y); window_close(w); } -static void window_tile_inspector_scrollgetsize() +static void window_tile_inspector_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - - 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); - + *width = WW - 30; + *height = window_tile_inspector_item_count * 11; } -static void window_tile_inspector_scrollmouseover() +static void window_tile_inspector_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) { - short x, y, scrollIndex; - rct_window *w; - - window_scrollmouse_get_registers(w, scrollIndex, x, y); window_invalidate(w); } -static void window_tile_inspector_invalidate() +static void window_tile_inspector_invalidate(rct_window *w) { - 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; @@ -272,15 +263,11 @@ static void window_tile_inspector_invalidate() window_tile_inspector_widgets[WIDX_SCROLL].bottom = w->height - 30; } -static void window_tile_inspector_paint() +static void window_tile_inspector_paint(rct_window *w, rct_drawpixelinfo *dpi) { 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; @@ -310,18 +297,14 @@ static void window_tile_inspector_paint() 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() +static void window_tile_inspector_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { 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; @@ -335,7 +318,7 @@ static void window_tile_inspector_scrollpaint() 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); + gfx_fill_rect(dpi, x - 15, y, x + WW - 20, y + 11, ColourMapA[w->colours[1]].lighter | 0x1000000); switch (type) { case MAP_ELEMENT_TYPE_SURFACE: @@ -353,12 +336,20 @@ static void window_tile_inspector_scrollpaint() uint8 pathType, pathDirection; pathType = element->properties.path.type >> 2; pathDirection = element->properties.path.type & 3; + if (footpath_element_is_queue(element)) { + sprintf( + buffer, + "Queue for (%d)", + element->properties.path.ride_index + ); + } else { + sprintf( + buffer, + "Path (%s)", + "" // TODO: queue? has bins? has benches? e.t.c. + ); + } } - sprintf( - buffer, - "Path (%s)", - "" // TODO: queue? has bins? has benches? e.t.c. - ); type_name = buffer; break; case MAP_ELEMENT_TYPE_TRACK: diff --git a/src/windows/title_command_editor.c b/src/windows/title_command_editor.c new file mode 100644 index 0000000000..9cc7a77199 --- /dev/null +++ b/src/windows/title_command_editor.c @@ -0,0 +1,580 @@ +/***************************************************************************** + * 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" +#include "../interface/title_sequences.h" +#include "../title.h" +#include "dropdown.h" + +typedef struct { + uint8 command; + rct_string_id nameStringId; + rct_string_id descStringId; +} TITLE_COMMAND_ORDER; + +TITLE_COMMAND_ORDER window_title_command_editor_orders[] = { + { TITLE_SCRIPT_LOAD, 5413, 5431 }, + { TITLE_SCRIPT_LOCATION, 5417, 5427 }, + { TITLE_SCRIPT_ROTATE, 5419, 5428 }, + { TITLE_SCRIPT_ZOOM, 5421, 5429 }, + { TITLE_SCRIPT_SPEED, 5445, 5444 }, + { TITLE_SCRIPT_WAIT, 5423, 5430 }, + { TITLE_SCRIPT_RESTART, 5425, STR_NONE }, + { TITLE_SCRIPT_END, 5426, STR_NONE }, +}; + +#define NUM_COMMANDS 8 + +enum WINDOW_WATER_WIDGET_IDX { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_COMMAND, + WIDX_COMMAND_DROPDOWN, + WIDX_TEXTBOX_FULL, + WIDX_TEXTBOX_X, + WIDX_TEXTBOX_Y, + WIDX_INPUT, + WIDX_INPUT_DROPDOWN, + WIDX_GET, + WIDX_OKAY, + WIDX_CANCEL +}; + +#define WW 200 +#define WH 120 +#define BY 32 +#define BY2 70 +#define WS 16 +#define WHA ((WW-WS*2)/2) + +static bool _window_title_command_editor_insert; +static int _window_title_command_editor_index; +#define BUF_SIZE 50 +static char textbox1Buffer[BUF_SIZE]; +static char textbox2Buffer[BUF_SIZE]; +static title_command command = { 6, 0, 0 }; + +static rct_widget window_title_command_editor_widgets[] = { + { WWT_FRAME, 1, 0, WW-1, 0, WH-1, -1, STR_NONE }, // panel / background + { WWT_CAPTION, 1, 1, WW-2, 1, 14, 5434, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 1, WW-13, WW-3, 2, 13, 824, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_DROPDOWN, 1, WS, WW-WS-1, BY, BY+11, STR_NONE, STR_NONE }, // Command dropdown + { WWT_DROPDOWN_BUTTON, 1, WW-WS-12, WW-WS-2, BY+1, BY+10, 876, STR_NONE }, + { WWT_TEXT_BOX, 1, WS, WW-WS-1, BY2, BY2+11, (uint32)textbox1Buffer, STR_NONE }, // full textbox + + { WWT_TEXT_BOX, 1, WS, WS+WHA-4, BY2, BY2+11, (uint32)textbox1Buffer, STR_NONE }, // x textbox + { WWT_TEXT_BOX, 1, WS+WHA+3, WW-WS-1, BY2, BY2+11, (uint32)textbox2Buffer, STR_NONE }, // y textbox + + { WWT_DROPDOWN, 1, 16, WW-17, BY2, BY2+11, STR_NONE, STR_NONE }, // Save dropdown + { WWT_DROPDOWN_BUTTON, 1, WW-28, WW-18, BY2+1, BY2+10, 876, STR_NONE }, + + { WWT_DROPDOWN_BUTTON, 1, WS+WHA+3, WW-WS-1, BY2-14, BY2-3, 5446, STR_NONE }, // Get location/zoom/etc + + { WWT_DROPDOWN_BUTTON, 1, 10, 80, WH-21, WH-10, STR_OK, STR_NONE }, // OKAY + { WWT_DROPDOWN_BUTTON, 1, WW-80, WW-10, WH-21, WH-10, STR_CANCEL, STR_NONE }, // Cancel + + { WIDGETS_END }, +}; + +static void window_title_command_editor_mouseup(rct_window *w, int widgetIndex); +static void window_title_command_editor_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); +static void window_title_command_editor_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); +static void window_title_command_editor_update(rct_window *w); +static void window_title_command_editor_invalidate(rct_window *w); +static void window_title_command_editor_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_title_command_editor_textinput(rct_window *w, int widgetIndex, char *text); +static void window_title_command_editor_inputsize(rct_window *w); +static int get_command_info_index(int index); +static TITLE_COMMAND_ORDER get_command_info(int index); +static rct_xy16 get_location(); +static uint8 get_zoom(); + +static rct_window_event_list window_title_command_editor_events = { + NULL, + window_title_command_editor_mouseup, + NULL, + window_title_command_editor_mousedown, + window_title_command_editor_dropdown, + NULL, + window_title_command_editor_update, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_title_command_editor_textinput, + NULL, + NULL, + NULL, + NULL, + NULL, + window_title_command_editor_invalidate, + window_title_command_editor_paint, + NULL +}; + +static int get_command_info_index(int index) +{ + for (int i = 0; i < NUM_COMMANDS; i++) { + if (window_title_command_editor_orders[i].command == index) + return i; + } + return 0; +} + +static TITLE_COMMAND_ORDER get_command_info(int index) +{ + for (int i = 0; i < NUM_COMMANDS; i++) { + if (window_title_command_editor_orders[i].command == index) + return window_title_command_editor_orders[i]; + } + return window_title_command_editor_orders[0]; +} + +static rct_xy16 get_location() +{ + rct_xy16 mapCoord = { 0 }; + rct_window *w = window_get_main(); + if (w != NULL) { + int interactionType; + rct_map_element *mapElement; + + get_map_coordinates_from_pos(w->viewport->view_width / 2, w->viewport->view_height / 2, VIEWPORT_INTERACTION_MASK_TERRAIN, &mapCoord.x, &mapCoord.y, &interactionType, &mapElement, NULL); + mapCoord.x -= 16; + mapCoord.x /= 32; + mapCoord.y -= 16; + mapCoord.y /= 32; + mapCoord.x++; + mapCoord.y++; + } + return mapCoord; +} + +static uint8 get_zoom() +{ + uint8 zoom = 0; + rct_window *w = window_get_main(); + if (w != NULL) { + zoom = w->viewport->zoom; + } + return zoom; +} + +void window_title_command_editor_open(int index, bool insert) +{ + rct_window* window; + + // Check if window is already open + if (window_find_by_class(WC_TITLE_COMMAND_EDITOR) != NULL) + return; + + window = window_create_centred( + WW, + WH, + &window_title_command_editor_events, + WC_TITLE_COMMAND_EDITOR, + WF_STICK_TO_FRONT + ); + window->widgets = window_title_command_editor_widgets; + window->enabled_widgets = + (1 << WIDX_CLOSE) | + (1 << WIDX_COMMAND) | + (1 << WIDX_COMMAND_DROPDOWN) | + (1 << WIDX_TEXTBOX_FULL) | + (1 << WIDX_TEXTBOX_X) | + (1 << WIDX_TEXTBOX_Y) | + (1 << WIDX_INPUT) | + (1 << WIDX_INPUT_DROPDOWN) | + (1 << WIDX_GET) | + (1 << WIDX_OKAY) | + (1 << WIDX_CANCEL); + window_init_scroll_widgets(window); + + _window_title_command_editor_index = index; + _window_title_command_editor_insert = insert; + if (!insert) { + command = gConfigTitleSequences.presets[gCurrentTitleSequence].commands[index]; + } + + switch (command.command) { + case TITLE_SCRIPT_LOAD: + if (command.saveIndex >= gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands) + command.saveIndex = 0xFF; + break; + case TITLE_SCRIPT_LOCATION: + snprintf(textbox1Buffer, BUF_SIZE, "%d", command.x); + snprintf(textbox2Buffer, BUF_SIZE, "%d", command.y); + break; + case TITLE_SCRIPT_ROTATE: + case TITLE_SCRIPT_ZOOM: + case TITLE_SCRIPT_WAIT: + snprintf(textbox1Buffer, BUF_SIZE, "%d", command.rotations); + break; + } +} + +static void window_title_command_editor_mouseup(rct_window *w, int widgetIndex) +{ + rct_window *title_editor_w; + rct_xy16 mapCoord; + uint8 zoom; + + switch (widgetIndex) { + case WIDX_CLOSE: + case WIDX_CANCEL: + window_close(w); + break; + case WIDX_TEXTBOX_FULL: + window_start_textbox(w, widgetIndex, 1170, (uint32)textbox1Buffer, 4); + break; + case WIDX_TEXTBOX_X: + window_start_textbox(w, widgetIndex, 1170, (uint32)textbox1Buffer, 4); + break; + case WIDX_TEXTBOX_Y: + window_start_textbox(w, widgetIndex, 1170, (uint32)textbox2Buffer, 4); + break; + case WIDX_GET: + if (command.command == TITLE_SCRIPT_LOCATION) { + mapCoord = get_location(); + command.x = (uint8)mapCoord.x; + command.y = (uint8)mapCoord.y; + snprintf(textbox1Buffer, BUF_SIZE, "%d", command.x); + snprintf(textbox2Buffer, BUF_SIZE, "%d", command.y); + } + else if (command.command == TITLE_SCRIPT_ZOOM) { + zoom = get_zoom(); + command.zoom = zoom; + snprintf(textbox1Buffer, BUF_SIZE, "%d", command.zoom); + } + window_invalidate(w); + break; + case WIDX_OKAY: + if (_window_title_command_editor_insert) { + title_sequence_insert_command(gCurrentTitleSequence, _window_title_command_editor_index, command); + } + else { + gConfigTitleSequences.presets[gCurrentTitleSequence].commands[_window_title_command_editor_index] = command; + title_sequence_save_preset_script(gCurrentTitleSequence); + } + title_editor_w = window_find_by_class(WC_TITLE_EDITOR); + if (title_editor_w != NULL) + title_editor_w->selected_list_item = _window_title_command_editor_index; + window_close(w); + break; + } +} + + +static void window_title_command_editor_mousedown(int widgetIndex, rct_window* w, rct_widget* widget) +{ + int num_items, i; + + widget--; + switch (widgetIndex) { + case WIDX_COMMAND_DROPDOWN: + num_items = NUM_COMMANDS; + for (i = 0; i < num_items; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = window_title_command_editor_orders[i].nameStringId; + } + + 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 + ); + + dropdown_set_checked(get_command_info_index(command.command), true); + break; + case WIDX_INPUT_DROPDOWN: + if (command.command == TITLE_SCRIPT_SPEED) { + num_items = 4; + for (i = 0; i < num_items; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = 5142 + i; + } + + 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 + ); + + dropdown_set_checked(command.speed - 1, true); + } + else if (command.command == TITLE_SCRIPT_LOAD) { + num_items = gConfigTitleSequences.presets[gCurrentTitleSequence].num_saves; + for (i = 0; i < num_items; i++) { + gDropdownItemsFormat[i] = 2777; + gDropdownItemsArgs[i] = (uint32)&gConfigTitleSequences.presets[gCurrentTitleSequence].saves[i]; + } + + 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 + ); + + dropdown_set_checked(command.saveIndex, true); + } + break; + } +} + +static void window_title_command_editor_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) +{ + rct_xy16 mapCoord; + + if (dropdownIndex == -1) + return; + + switch (widgetIndex) { + case WIDX_COMMAND_DROPDOWN: + if (dropdownIndex == get_command_info_index(command.command)) + break; + command.command = window_title_command_editor_orders[dropdownIndex].command; + switch (command.command) { + case TITLE_SCRIPT_LOCATION: + mapCoord = get_location(); + command.x = (uint8)mapCoord.x; + command.y = (uint8)mapCoord.y; + snprintf(textbox1Buffer, BUF_SIZE, "%d", command.x); + snprintf(textbox2Buffer, BUF_SIZE, "%d", command.y); + break; + case TITLE_SCRIPT_ROTATE: + command.rotations = 1; + snprintf(textbox1Buffer, BUF_SIZE, "%d", command.rotations); + break; + case TITLE_SCRIPT_ZOOM: + command.zoom = 0; + snprintf(textbox1Buffer, BUF_SIZE, "%d", command.zoom); + break; + case TITLE_SCRIPT_SPEED: + command.speed = 1; + break; + case TITLE_SCRIPT_WAIT: + command.seconds = 10; + snprintf(textbox1Buffer, BUF_SIZE, "%d", command.seconds); + break; + case TITLE_SCRIPT_LOAD: + command.saveIndex = 0; + if (command.saveIndex >= gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands) + command.saveIndex = 0xFF; + break; + } + window_invalidate(w); + break; + case WIDX_INPUT_DROPDOWN: + if (command.command == TITLE_SCRIPT_SPEED) { + if (dropdownIndex == command.speed - 1) + break; + command.speed = (uint8)(dropdownIndex + 1); + } + else if (command.command == TITLE_SCRIPT_LOAD) { + if (dropdownIndex == command.saveIndex) + break; + command.saveIndex = (uint8)dropdownIndex; + } + window_invalidate(w); + break; + } +} + +static void window_title_command_editor_textinput(rct_window *w, int widgetIndex, char *text) +{ + char *end; + int value; + + value = strtol(widgetIndex != WIDX_TEXTBOX_Y ? textbox1Buffer : textbox2Buffer, &end, 10); + if (value < 0) value = 0; + if (value > 255) value = 255; + switch (widgetIndex) { + case WIDX_TEXTBOX_FULL: + if (text == NULL) { + if (*end == '\0') { + if (command.command == TITLE_SCRIPT_ROTATE || command.command == TITLE_SCRIPT_ZOOM) { + if (value > 3) value = 3; + } + else if (command.command == TITLE_SCRIPT_WAIT) { + if (value < 1) value = 1; + } + command.rotations = (uint8)value; + } + snprintf(textbox1Buffer, BUF_SIZE, "%d", command.rotations); + window_invalidate(w); + } + else { + strcpy(textbox1Buffer, text); + } + break; + case WIDX_TEXTBOX_X: + if (text == NULL) { + if (*end == '\0') + command.x = (uint8)value; + snprintf(textbox1Buffer, BUF_SIZE, "%d", command.x); + window_invalidate(w); + } + else { + strcpy(textbox1Buffer, text); + } + break; + case WIDX_TEXTBOX_Y: + if (text == NULL) { + if (*end == '\0') + command.y = (uint8)value; + snprintf(textbox2Buffer, BUF_SIZE, "%d", command.y); + window_invalidate(w); + } + else { + strcpy(textbox2Buffer, text); + } + break; + } +} + +static void window_title_command_editor_update(rct_window *w) +{ + if (gCurrentTextBox.window.classification == w->classification && + gCurrentTextBox.window.number == w->number) { + window_update_textbox_caret(); + widget_invalidate(w, gCurrentTextBox.widget_index); + } +} + +static void window_title_command_editor_invalidate(rct_window *w) +{ + colour_scheme_update_by_class(w, WC_TITLE_EDITOR); + + window_title_command_editor_widgets[WIDX_TEXTBOX_FULL].type = WWT_EMPTY; + window_title_command_editor_widgets[WIDX_TEXTBOX_X].type = WWT_EMPTY; + window_title_command_editor_widgets[WIDX_TEXTBOX_Y].type = WWT_EMPTY; + window_title_command_editor_widgets[WIDX_INPUT].type = WWT_EMPTY; + window_title_command_editor_widgets[WIDX_INPUT_DROPDOWN].type = WWT_EMPTY; + window_title_command_editor_widgets[WIDX_GET].type = WWT_EMPTY; + switch (command.command) { + case TITLE_SCRIPT_LOAD: + case TITLE_SCRIPT_SPEED: + window_title_command_editor_widgets[WIDX_INPUT].type = WWT_DROPDOWN; + window_title_command_editor_widgets[WIDX_INPUT_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + break; + case TITLE_SCRIPT_LOCATION: + window_title_command_editor_widgets[WIDX_TEXTBOX_X].type = WWT_TEXT_BOX; + window_title_command_editor_widgets[WIDX_TEXTBOX_Y].type = WWT_TEXT_BOX; + window_title_command_editor_widgets[WIDX_GET].type = WWT_DROPDOWN_BUTTON; + break; + case TITLE_SCRIPT_ROTATE: + case TITLE_SCRIPT_WAIT: + window_title_command_editor_widgets[WIDX_TEXTBOX_FULL].type = WWT_TEXT_BOX; + break; + case TITLE_SCRIPT_ZOOM: + window_title_command_editor_widgets[WIDX_GET].type = WWT_DROPDOWN_BUTTON; + window_title_command_editor_widgets[WIDX_TEXTBOX_FULL].type = WWT_TEXT_BOX; + break; + } + + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) == SCREEN_FLAGS_TITLE_DEMO) + w->disabled_widgets |= (1 << WIDX_GET); + else + w->disabled_widgets &= ~(1 << WIDX_GET); +} + +static void window_title_command_editor_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ + window_draw_widgets(w, dpi); + + gfx_draw_string_left(dpi, 5432, NULL, w->colours[1], w->x + WS, w->y + BY - 14); + gfx_draw_string_left(dpi, get_command_info(command.command).descStringId, NULL, w->colours[1], w->x + WS, w->y + BY2 - 14); + + gfx_draw_string_left_clipped( + dpi, + get_command_info(command.command).nameStringId, + NULL, + w->colours[1], + w->x + w->widgets[WIDX_COMMAND].left + 1, + w->y + w->widgets[WIDX_COMMAND].top, + w->widgets[WIDX_COMMAND_DROPDOWN].left - w->widgets[WIDX_COMMAND].left - 4 + ); + + if (command.command == TITLE_SCRIPT_SPEED) { + gfx_draw_string_left_clipped( + dpi, + 5142 + command.speed - 1, + NULL, + w->colours[1], + w->x + w->widgets[WIDX_INPUT].left + 1, + w->y + w->widgets[WIDX_INPUT].top, + w->widgets[WIDX_INPUT_DROPDOWN].left - w->widgets[WIDX_INPUT].left - 4 + ); + } + else if (command.command == TITLE_SCRIPT_LOAD) { + if (command.saveIndex == 0xFF) { + gfx_draw_string_left_clipped( + dpi, + 5437, + NULL, + w->colours[1], + w->x + w->widgets[WIDX_INPUT].left + 1, + w->y + w->widgets[WIDX_INPUT].top, + w->widgets[WIDX_INPUT_DROPDOWN].left - w->widgets[WIDX_INPUT].left - 4 + ); + } + else { + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&gConfigTitleSequences.presets[gCurrentTitleSequence].saves[command.saveIndex]; + gfx_draw_string_left_clipped( + dpi, + 1170, + (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, + w->colours[1], + w->x + w->widgets[WIDX_INPUT].left + 1, + w->y + w->widgets[WIDX_INPUT].top, + w->widgets[WIDX_INPUT_DROPDOWN].left - w->widgets[WIDX_INPUT].left - 4 + ); + } + } +} diff --git a/src/windows/title_editor.c b/src/windows/title_editor.c new file mode 100644 index 0000000000..41c2974acd --- /dev/null +++ b/src/windows/title_editor.c @@ -0,0 +1,1002 @@ +/***************************************************************************** +* Copyright (c) 2014 Maciek Baron, D�niel 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 "dropdown.h" +#include "../interface/themes.h" +#include "../sprites.h" +#include "../title.h" +#include "../interface/title_sequences.h" +#include "error.h" +#include "../scenario.h" +#include "../util/util.h" + +enum { + WINDOW_TITLE_EDITOR_TAB_PRESETS, + WINDOW_TITLE_EDITOR_TAB_SAVES, + WINDOW_TITLE_EDITOR_TAB_SCRIPT, + WINDOW_TITLE_EDITOR_TAB_COUNT +} WINDOW_TITLE_EDITOR_TAB; + +static void window_title_editor_close(rct_window *w); +static void window_title_editor_mouseup(rct_window *w, int widgetIndex); +static void window_title_editor_resize(rct_window *w); +static void window_title_editor_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); +static void window_title_editor_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); +static void window_title_editor_update(rct_window *w); +static void window_title_editor_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_title_editor_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_title_editor_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_title_editor_textinput(rct_window *w, int widgetIndex, char *text); +static void window_title_editor_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_title_editor_invalidate(rct_window *w); +static void window_title_editor_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_title_editor_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); +static void window_title_editor_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w); + +static rct_window_event_list window_title_editor_events = { + window_title_editor_close, + window_title_editor_mouseup, + window_title_editor_resize, + window_title_editor_mousedown, + window_title_editor_dropdown, + NULL, + window_title_editor_update, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_title_editor_scrollgetsize, + window_title_editor_scrollmousedown, + NULL, + window_title_editor_scrollmouseover, + window_title_editor_textinput, + NULL, + NULL, + window_title_editor_tooltip, + NULL, + NULL, + window_title_editor_invalidate, + window_title_editor_paint, + window_title_editor_scrollpaint, +}; + +enum WINDOW_TITLE_EDITOR_WIDGET_IDX { + WIDX_TITLE_EDITOR_BACKGROUND, + WIDX_TITLE_EDITOR_TITLE, + WIDX_TITLE_EDITOR_CLOSE, + WIDX_TITLE_EDITOR_TAB_CONTENT_PANEL, + WIDX_TITLE_EDITOR_PRESETS_TAB, + WIDX_TITLE_EDITOR_SAVES_TAB, + WIDX_TITLE_EDITOR_SCRIPT_TAB, + WIDX_TITLE_EDITOR_LIST, + + // Presets Tab + WIDX_TITLE_EDITOR_PRESETS, + WIDX_TITLE_EDITOR_PRESETS_DROPDOWN, + WIDX_TITLE_EDITOR_NEW_BUTTON, + WIDX_TITLE_EDITOR_DUPLICATE_BUTTON, + WIDX_TITLE_EDITOR_DELETE_BUTTON, + WIDX_TITLE_EDITOR_RENAME_BUTTON, + + // Saves Tab + WIDX_TITLE_EDITOR_ADD, + WIDX_TITLE_EDITOR_REMOVE, + WIDX_TITLE_EDITOR_RENAME, + WIDX_TITLE_EDITOR_LOAD, + + // Script Tab + WIDX_TITLE_EDITOR_INSERT, + WIDX_TITLE_EDITOR_EDIT, + WIDX_TITLE_EDITOR_DELETE, + //WIDX_TITLE_EDITOR_RELOAD, + WIDX_TITLE_EDITOR_SKIP_TO, + + WIDX_TITLE_EDITOR_MOVE_UP, + WIDX_TITLE_EDITOR_MOVE_DOWN, + + WIDX_TITLE_EDITOR_REPLAY, + WIDX_TITLE_EDITOR_STOP, + WIDX_TITLE_EDITOR_PLAY, + WIDX_TITLE_EDITOR_SKIP, +}; + +// Increase BW if certain launguages do not fit +// BW should be a multiple of 4 +#define WW 320 +#define WH 270 +#define BX 8 +#define BW 72 +#define BY 52 +#define BH 63 +#define BS 18 +#define ROW_HEIGHT 11 +#define SCROLL_WIDTH 350 +#define WH2 127 + +static rct_widget window_title_editor_widgets[] = { + { WWT_FRAME, 0, 0, WW-1, 0, WH2-1, 0x0FFFFFFFF, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, WW-2, 1, 14, 5433, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, WW-13, WW-3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close button + { WWT_RESIZE, 1, 0, WW-1, 43, WH2-1, 0x0FFFFFFFF, STR_NONE }, // tab content panel + { WWT_TAB, 1, 3, 33, 17, 43, 0x02000144E, 5235 }, // presets tab + { WWT_TAB, 1, 34, 64, 17, 43, 0x02000144E, 5377 }, // saves tab + { WWT_TAB, 1, 65, 95, 17, 43, 0x02000144E, 5378 }, // script tab + { WWT_SCROLL, 1, BX+BW+9,WW-4, 48, WH-4, 3, STR_NONE }, // command/save list + + // Presets Tab + { WWT_DROPDOWN, 1, 125, 299, 60, 71, STR_NONE, STR_NONE }, // Preset title sequences + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 61, 70, 876, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 10, 100, 82, 93, 5254, 5255 }, // Create button + { WWT_DROPDOWN_BUTTON, 1, 10, 100, 82+20, 93+20, 5239, 5383 }, // Duplicate button + { WWT_DROPDOWN_BUTTON, 1, 110, 200, 82, 93, 3349, 5384 }, // Delete button + { WWT_DROPDOWN_BUTTON, 1, 210, 300, 82, 93, 3348, 5385 }, // Rename button + + // Saves Tab + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY, BH, 5407, 5392 }, // Add + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY+(BS*1), BH+(BS*1), 5408, 5393 }, // Remove + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY+(BS*2), BH+(BS*2), 3348, 5394 }, // Rename + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY+(BS*3), BH+(BS*3), 5413, 5395 }, // Load + + // Script Tab + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY, BH, 5409, 5386 }, // Insert + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY+(BS*1), BH+(BS*1), 5410, 5387 }, // Edit + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY+(BS*2), BH+(BS*2), 3349, 5388 }, // Delete + //{ WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY+(BS*3), BH+(BS*3), 5411, 5396 }, // Reload + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY+(BS*3), BH+(BS*3), 5412, 5389 }, // Skip to + + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW/2-1,BY+(BS*5),BH+(BS*5), 5375, 5390 }, // Move down + { WWT_DROPDOWN_BUTTON, 1, BX+BW/2,BX+BW-1,BY+(BS*5), BH+(BS*5), 5376, 5391 }, // Move up + + { WWT_IMGBTN, 1, BX, BX+BW/4-1, WH-32, WH-16, SPR_G2_TITLE_RESTART, 5382 }, // Replay + { WWT_IMGBTN, 1, BX+BW/4,BX+BW/2-1, WH-32, WH-16, SPR_G2_TITLE_STOP, 5381 }, // Stop + { WWT_IMGBTN, 1, BX+BW/2,BX+BW*3/4-1,WH-32, WH-16, SPR_G2_TITLE_PLAY, 5380 }, // Play + { WWT_IMGBTN, 1, BX+BW*3/4,BX+BW, WH-32, WH-16, SPR_G2_TITLE_SKIP, 5379 }, // Skip + + { WIDGETS_END }, +}; + +static sint16 _window_title_editor_highlighted_index; + + +static int window_title_editor_tab_animation_loops[] = { + 64, + 1, + 28 +}; +static int window_title_editor_tab_animation_divisor[] = { + 4, + 1, + 4 +}; +static int window_title_editor_tab_sprites[] = { + SPR_TAB_RIDE_0, + 5183, + SPR_TAB_STATS_0 +}; + +static void window_title_editor_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w) +{ + int sprite_idx; + int x, y; + + for (int i = 0; i < WINDOW_TITLE_EDITOR_TAB_COUNT; i++) { + x = 0; + y = 0; + sprite_idx = window_title_editor_tab_sprites[i]; + if (w->selected_tab == i) + sprite_idx += w->frame_no / window_title_editor_tab_animation_divisor[w->selected_tab]; + if (i == 1) { + x = 4; + y = 1; + } + gfx_draw_sprite(dpi, sprite_idx, w->x + w->widgets[WIDX_TITLE_EDITOR_PRESETS_TAB + i].left + x, w->y + w->widgets[WIDX_TITLE_EDITOR_PRESETS_TAB + i].top + y, 0); + } +} + +void window_title_editor_open(int tab) +{ + rct_window* window; + + // Check if window is already open + window = window_bring_to_front_by_class(WC_TITLE_EDITOR); + if (window != NULL) + return; + + window = window_create_auto_pos(WW, WH2, &window_title_editor_events, WC_TITLE_EDITOR, WF_10 | WF_RESIZABLE); + window->widgets = window_title_editor_widgets; + window->enabled_widgets = + (1 << WIDX_TITLE_EDITOR_CLOSE) | + (1 << WIDX_TITLE_EDITOR_PRESETS_TAB) | + (1 << WIDX_TITLE_EDITOR_SAVES_TAB) | + (1 << WIDX_TITLE_EDITOR_SCRIPT_TAB) | + + (1 << WIDX_TITLE_EDITOR_PRESETS) | + (1 << WIDX_TITLE_EDITOR_PRESETS_DROPDOWN) | + (1 << WIDX_TITLE_EDITOR_NEW_BUTTON) | + (1 << WIDX_TITLE_EDITOR_DUPLICATE_BUTTON) | + (1 << WIDX_TITLE_EDITOR_DELETE_BUTTON) | + (1 << WIDX_TITLE_EDITOR_RENAME_BUTTON) | + + (1 << WIDX_TITLE_EDITOR_ADD) | + (1 << WIDX_TITLE_EDITOR_REMOVE) | + (1 << WIDX_TITLE_EDITOR_RENAME) | + (1 << WIDX_TITLE_EDITOR_LOAD) | + + (1 << WIDX_TITLE_EDITOR_INSERT) | + (1 << WIDX_TITLE_EDITOR_EDIT) | + (1 << WIDX_TITLE_EDITOR_DELETE) | + //(1 << WIDX_TITLE_EDITOR_RELOAD) | + (1 << WIDX_TITLE_EDITOR_SKIP_TO) | + (1 << WIDX_TITLE_EDITOR_MOVE_DOWN) | + (1 << WIDX_TITLE_EDITOR_MOVE_UP) | + + (1 << WIDX_TITLE_EDITOR_PLAY) | + (1 << WIDX_TITLE_EDITOR_STOP) | + (1 << WIDX_TITLE_EDITOR_REPLAY) | + (1 << WIDX_TITLE_EDITOR_SKIP); + + window_init_scroll_widgets(window); + window->list_information_type = 0; + + window->selected_tab = tab; + window->selected_list_item = -1; + _window_title_editor_highlighted_index = -1; + window->scrolls[0].v_top = 0; + window->scrolls[0].h_left = 0; + + window->min_width = WW; + window->min_height = WH; + window->max_width = 500; + window->max_height = 450; + +} + +void window_title_editor_close(rct_window *w) +{ + rct_window *command_editor_w, *load_save_w; + + // Close the related windows + command_editor_w = window_find_by_class(WC_TITLE_COMMAND_EDITOR); + load_save_w = window_find_by_class(WC_LOADSAVE); + if (command_editor_w) + window_close(command_editor_w); + if (load_save_w && gLoadSaveTitleSequenceSave) + window_close(load_save_w); +} + +static void window_title_editor_mouseup(rct_window *w, int widgetIndex) +{ + char path[MAX_PATH]; + char separator = platform_get_path_separator(); + int defaultPreset, playing, inTitle, i, commandEditorOpen; + + defaultPreset = (gCurrentTitleSequence < TITLE_SEQUENCE_DEFAULT_PRESETS); + playing = (gCurrentTitleSequence == gCurrentPreviewTitleSequence) && ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) == SCREEN_FLAGS_TITLE_DEMO); + inTitle = ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) == SCREEN_FLAGS_TITLE_DEMO); + commandEditorOpen = (window_find_by_class(WC_TITLE_COMMAND_EDITOR) != NULL); + switch (widgetIndex) { + case WIDX_TITLE_EDITOR_CLOSE: + window_close(w); + break; + case WIDX_TITLE_EDITOR_NEW_BUTTON: + commandEditorOpen *= 2; + if (!commandEditorOpen) + window_text_input_open(w, widgetIndex, 5239, 5406, STR_NONE, 0, 64); + break; + case WIDX_TITLE_EDITOR_DUPLICATE_BUTTON: + commandEditorOpen *= 2; + if (!commandEditorOpen) + window_text_input_open(w, widgetIndex, 5239, 5406, 1170, (uint32)&gConfigTitleSequences.presets[gCurrentTitleSequence].name, 64); + break; + case WIDX_TITLE_EDITOR_DELETE_BUTTON: + defaultPreset *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !commandEditorOpen) + title_sequence_delete_preset(gCurrentTitleSequence); + break; + case WIDX_TITLE_EDITOR_RENAME_BUTTON: + defaultPreset *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !commandEditorOpen) + window_text_input_open(w, widgetIndex, 3348, 5406, 1170, (uint32)&gConfigTitleSequences.presets[gCurrentTitleSequence].name, 64); + break; + case WIDX_TITLE_EDITOR_ADD: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME, NULL); + gLoadSaveTitleSequenceSave = true; + } + break; + case WIDX_TITLE_EDITOR_REMOVE: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + if (w->selected_list_item != -1) { + title_sequence_remove_save(gCurrentTitleSequence, w->selected_list_item); + if (w->selected_list_item > 0) + w->selected_list_item--; + else if (w->selected_list_item > gConfigTitleSequences.presets[gCurrentTitleSequence].num_saves) + w->selected_list_item = gConfigTitleSequences.presets[gCurrentTitleSequence].num_saves - 1; + } + } + break; + case WIDX_TITLE_EDITOR_RENAME: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + if (w->selected_list_item != -1) + window_text_input_open(w, widgetIndex, 5435, 5405, 1170, (uint32)gConfigTitleSequences.presets[gCurrentTitleSequence].saves[w->selected_list_item], TITLE_SEQUENCE_MAX_SAVE_LENGTH - 1); + } + break; + case WIDX_TITLE_EDITOR_LOAD: + if (w->selected_list_item != -1) { + if (gConfigTitleSequences.presets[gCurrentTitleSequence].path[0]) { + safe_strncpy(path, gConfigTitleSequences.presets[gCurrentTitleSequence].path, MAX_PATH); + } + else { + platform_get_user_directory(path, "title sequences"); + strcat(path, gConfigTitleSequences.presets[gCurrentTitleSequence].name); + strncat(path, &separator, 1); + } + + strcat(path, gConfigTitleSequences.presets[gCurrentTitleSequence].saves[w->selected_list_item]); + game_load_save(path); + window_title_editor_open(1); + } + break; + case WIDX_TITLE_EDITOR_INSERT: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + if (w->selected_list_item != -1) + window_title_command_editor_open(w->selected_list_item + 1, true); + else + window_title_command_editor_open(gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands, true); + } + break; + case WIDX_TITLE_EDITOR_EDIT: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + if (w->selected_list_item != -1 && w->selected_list_item < gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands) + window_title_command_editor_open(w->selected_list_item, false); + } + break; + case WIDX_TITLE_EDITOR_DELETE: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + if (w->selected_list_item != -1 && w->selected_list_item < gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands) { + title_sequence_delete_command(gCurrentTitleSequence, w->selected_list_item); + if (w->selected_list_item > 0) + w->selected_list_item--; + else if (w->selected_list_item >= gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands) + w->selected_list_item = gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands - 1; + } + } + break; + /*case WIDX_TITLE_EDITOR_RELOAD: + playing *= 2; commandEditorOpen *= 2; + if (!playing && !commandEditorOpen) { + //title_sequence_open + } + break;*/ + case WIDX_TITLE_EDITOR_SKIP_TO: + if (playing && w->selected_list_item != -1 && w->selected_list_item < gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands) { + if (gTitleScriptCommand > w->selected_list_item) { + title_skip_from_beginning(); + } + if (gTitleScriptCommand != w->selected_list_item) { + for (i = gTitleScriptCommand + 1; i < gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands; i++) { + if (gConfigTitleSequences.presets[gCurrentTitleSequence].commands[i].command == TITLE_SCRIPT_LOAD || + gConfigTitleSequences.presets[gCurrentTitleSequence].commands[i].command == TITLE_SCRIPT_LOADMM) { + gTitleScriptSkipLoad = i; + } + if (i == w->selected_list_item) { + gTitleScriptSkipTo = i; + break; + } + } + } + } + break; + case WIDX_TITLE_EDITOR_MOVE_DOWN: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + if (w->selected_list_item != -1 && w->selected_list_item < gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands - 1) { + title_sequence_move_down_command(gCurrentTitleSequence, w->selected_list_item); + w->selected_list_item++; + } + } + break; + case WIDX_TITLE_EDITOR_MOVE_UP: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + if (w->selected_list_item != -1 && w->selected_list_item > 0) { + title_sequence_move_up_command(gCurrentTitleSequence, w->selected_list_item); + w->selected_list_item--; + } + } + break; + case WIDX_TITLE_EDITOR_REPLAY: + if (playing) { + title_refresh_sequence(); + } + break; + case WIDX_TITLE_EDITOR_STOP: + if (playing) { + gCurrentPreviewTitleSequence = 0; + title_refresh_sequence(); + } + break; + case WIDX_TITLE_EDITOR_PLAY: + if (gCurrentTitleSequence != gCurrentPreviewTitleSequence && inTitle) { + gCurrentPreviewTitleSequence = gCurrentTitleSequence; + title_refresh_sequence(); + } + break; + case WIDX_TITLE_EDITOR_SKIP: + if (playing) { + for (i = gTitleScriptCommand + 1; i < gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands; i++) { + if (gConfigTitleSequences.presets[gCurrentTitleSequence].commands[i].command == TITLE_SCRIPT_LOAD || + gConfigTitleSequences.presets[gCurrentTitleSequence].commands[i].command == TITLE_SCRIPT_LOADMM) { + gTitleScriptSkipLoad = i; + } + else if (gConfigTitleSequences.presets[gCurrentTitleSequence].commands[i].command == TITLE_SCRIPT_WAIT || + gConfigTitleSequences.presets[gCurrentTitleSequence].commands[i].command == TITLE_SCRIPT_END) { + gTitleScriptSkipTo = i; + break; + } + else if (gConfigTitleSequences.presets[gCurrentTitleSequence].commands[i].command == TITLE_SCRIPT_RESTART) { + gTitleScriptSkipLoad = -1; + gTitleScriptSkipTo = -1; + title_refresh_sequence(); + } + } + if (i == gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands && i - 1 > gTitleScriptCommand) { + gTitleScriptSkipTo = i - 1; + gTitleScriptSkipLoad = -1; + } + } + break; + } + if (defaultPreset == 2) + window_error_open(5400, STR_NONE); + else if (commandEditorOpen == 2) + window_error_open(5438, STR_NONE); + else if (playing == 2) + window_error_open(5398, 5399); +} + +static void window_title_editor_resize(rct_window *w) +{ + if (w->selected_tab == WINDOW_TITLE_EDITOR_TAB_PRESETS) { + w->min_width = WW; + w->min_height = WH2; + w->max_width = WW; + w->max_height = WH2; + + 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 = WW; + w->min_height = WH; + w->max_width = 500; + w->max_height = 580; + + 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_title_editor_mousedown(int widgetIndex, rct_window* w, rct_widget* widget) +{ + short newSelectedTab; + int num_items, i; + + switch (widgetIndex) { + case WIDX_TITLE_EDITOR_PRESETS_TAB: + case WIDX_TITLE_EDITOR_SAVES_TAB: + case WIDX_TITLE_EDITOR_SCRIPT_TAB: + newSelectedTab = widgetIndex - WIDX_TITLE_EDITOR_PRESETS_TAB; + if (w->selected_tab == newSelectedTab) + break; + w->selected_tab = newSelectedTab; + w->selected_list_item = -1; + _window_title_editor_highlighted_index = -1; + w->scrolls[0].v_top = 0; + w->frame_no = 0; + window_event_resize_call(w); + window_invalidate(w); + break; + case WIDX_TITLE_EDITOR_PRESETS_DROPDOWN: + if (window_find_by_class(WC_TITLE_COMMAND_EDITOR) != NULL) { + window_error_open(5438, STR_NONE); + } + else { + num_items = gConfigTitleSequences.num_presets; + + widget--; + for (i = 0; i < num_items; i++) { + gDropdownItemsFormat[i] = 2777; + gDropdownItemsArgs[i] = (uint32)&gConfigTitleSequences.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 + ); + + dropdown_set_checked(gCurrentTitleSequence, true); + } + break; + } +} + +static void window_title_editor_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) +{ + if (dropdownIndex == -1) + return; + + switch (widgetIndex) { + case WIDX_TITLE_EDITOR_PRESETS_DROPDOWN: + gCurrentTitleSequence = dropdownIndex; + window_invalidate(w); + break; + } +} + +void window_title_editor_update(rct_window *w) +{ + w->frame_no++; + if (w->frame_no >= window_title_editor_tab_animation_loops[w->selected_tab]) + w->frame_no = 0; + + if (!widget_is_highlighted(w, WIDX_TITLE_EDITOR_LIST)) { + _window_title_editor_highlighted_index = -1; + widget_invalidate(w, WIDX_TITLE_EDITOR_LIST); + } + + widget_invalidate(w, WIDX_TITLE_EDITOR_PRESETS_TAB + w->selected_tab); +} + +void window_title_editor_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) +{ + int i; + uint16 lineCount; + + lineCount = 1; + if (w->selected_tab == WINDOW_TITLE_EDITOR_TAB_SAVES) + lineCount = gConfigTitleSequences.presets[gCurrentTitleSequence].num_saves; + else if (w->selected_tab == WINDOW_TITLE_EDITOR_TAB_SCRIPT) + lineCount = gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands; + + *height = lineCount * ROW_HEIGHT; + i = *height - window_title_editor_widgets[WIDX_TITLE_EDITOR_LIST].bottom + window_title_editor_widgets[WIDX_TITLE_EDITOR_LIST].top + 21; + if (i < 0) + i = 0; + if (i < w->scrolls[0].v_top) { + w->scrolls[0].v_top = i; + window_invalidate(w); + } + + *width = SCROLL_WIDTH; +} + +void window_title_editor_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) +{ + int index; + + index = y / ROW_HEIGHT; + w->selected_list_item = -1; + switch (w->selected_tab) { + case WINDOW_TITLE_EDITOR_TAB_SAVES: + if (index < gConfigTitleSequences.presets[gCurrentTitleSequence].num_saves) { + w->selected_list_item = index; + widget_invalidate(w, WIDX_TITLE_EDITOR_LIST); + } + break; + case WINDOW_TITLE_EDITOR_TAB_SCRIPT: + if (index < gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands) { + w->selected_list_item = index; + widget_invalidate(w, WIDX_TITLE_EDITOR_LIST); + } + break; + } +} + +void window_title_editor_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) +{ + int index; + sint16 oldHighlightedIndex; + + index = y / ROW_HEIGHT; + switch (w->selected_tab) { + oldHighlightedIndex = _window_title_editor_highlighted_index; + _window_title_editor_highlighted_index = -1; + case WINDOW_TITLE_EDITOR_TAB_SAVES: + if (index < gConfigTitleSequences.presets[gCurrentTitleSequence].num_saves) + _window_title_editor_highlighted_index = (sint16)index; + break; + case WINDOW_TITLE_EDITOR_TAB_SCRIPT: + if (index < gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands) + _window_title_editor_highlighted_index = (sint16)index; + break; + } + // This check is disabled since for some reason it creates a problem with highlighting index 1 + //if (oldHighlightedIndex != _window_title_editor_highlighted_index) { + widget_invalidate(w, WIDX_TITLE_EDITOR_LIST); + //} +} + +static void window_title_editor_textinput(rct_window *w, int widgetIndex, char *text) +{ + if (text == NULL || text[0] == 0) + return; + + switch (widgetIndex) { + case WIDX_TITLE_EDITOR_NEW_BUTTON: + case WIDX_TITLE_EDITOR_DUPLICATE_BUTTON: + case WIDX_TITLE_EDITOR_RENAME_BUTTON: + if (filename_valid_characters(text)) { + if (!title_sequence_name_exists(text)) { + if (widgetIndex == WIDX_TITLE_EDITOR_NEW_BUTTON) { + title_sequence_create_preset(text); + } + else if (widgetIndex == WIDX_TITLE_EDITOR_DUPLICATE_BUTTON) { + title_sequence_duplicate_preset(gCurrentTitleSequence, text); + } + else { + title_sequence_rename_preset(gCurrentTitleSequence, text); + } + config_save_default(); + window_invalidate(w); + } + else { + window_error_open(5404, STR_NONE); + } + } + else { + window_error_open(5243, STR_NONE); + } + break; + case WIDX_TITLE_EDITOR_RENAME: + if (filename_valid_characters(text)) { + if (!title_sequence_save_exists(gCurrentTitleSequence, text)) { + title_sequence_rename_save(gCurrentTitleSequence, w->selected_list_item, text); + title_sequence_save_preset_script(gCurrentTitleSequence); + window_invalidate(w); + } + else { + window_error_open(5404, STR_NONE); + } + } + else { + window_error_open(5243, STR_NONE); + } + break; + } +} + +void window_title_editor_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) +{ + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = STR_LIST; +} + +void window_title_editor_invalidate(rct_window *w) +{ + colour_scheme_update(w); + + int pressed_widgets = w->pressed_widgets & 0xFFFFFF8F; + uint8 widgetIndex = w->selected_tab + 4; + + w->pressed_widgets = pressed_widgets | (1 << widgetIndex); + + window_title_editor_widgets[WIDX_TITLE_EDITOR_LIST].type = WWT_EMPTY; + + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS_DROPDOWN].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_NEW_BUTTON].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_DUPLICATE_BUTTON].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_DELETE_BUTTON].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_RENAME_BUTTON].type = WWT_EMPTY; + + window_title_editor_widgets[WIDX_TITLE_EDITOR_ADD].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_REMOVE].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_RENAME].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_LOAD].type = WWT_EMPTY; + + window_title_editor_widgets[WIDX_TITLE_EDITOR_INSERT].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_EDIT].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_DELETE].type = WWT_EMPTY; + //window_title_editor_widgets[WIDX_TITLE_EDITOR_RELOAD].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP_TO].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_MOVE_UP].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_MOVE_DOWN].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_PLAY].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_STOP].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_REPLAY].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP].type = WWT_EMPTY; + + switch (w->selected_tab) { + case WINDOW_TITLE_EDITOR_TAB_PRESETS: + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS].type = WWT_DROPDOWN; + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_NEW_BUTTON].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_DUPLICATE_BUTTON].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_DELETE_BUTTON].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_RENAME_BUTTON].type = WWT_DROPDOWN_BUTTON; + break; + case WINDOW_TITLE_EDITOR_TAB_SAVES: + window_title_editor_widgets[WIDX_TITLE_EDITOR_LIST].type = WWT_SCROLL; + window_title_editor_widgets[WIDX_TITLE_EDITOR_ADD].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_REMOVE].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_RENAME].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_LOAD].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_PLAY].type = WWT_IMGBTN; + window_title_editor_widgets[WIDX_TITLE_EDITOR_STOP].type = WWT_IMGBTN; + window_title_editor_widgets[WIDX_TITLE_EDITOR_REPLAY].type = WWT_IMGBTN; + window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP].type = WWT_IMGBTN; + break; + case WINDOW_TITLE_EDITOR_TAB_SCRIPT: + window_title_editor_widgets[WIDX_TITLE_EDITOR_LIST].type = WWT_SCROLL; + window_title_editor_widgets[WIDX_TITLE_EDITOR_INSERT].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_EDIT].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_DELETE].type = WWT_DROPDOWN_BUTTON; + //window_title_editor_widgets[WIDX_TITLE_EDITOR_RELOAD].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP_TO].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_MOVE_UP].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_MOVE_DOWN].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_PLAY].type = WWT_IMGBTN; + window_title_editor_widgets[WIDX_TITLE_EDITOR_STOP].type = WWT_IMGBTN; + window_title_editor_widgets[WIDX_TITLE_EDITOR_REPLAY].type = WWT_IMGBTN; + window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP].type = WWT_IMGBTN; + break; + } + + window_title_editor_widgets[WIDX_TITLE_EDITOR_BACKGROUND].right = w->width - 1; + window_title_editor_widgets[WIDX_TITLE_EDITOR_BACKGROUND].bottom = w->height - 1; + window_title_editor_widgets[WIDX_TITLE_EDITOR_TAB_CONTENT_PANEL].right = w->width - 1; + window_title_editor_widgets[WIDX_TITLE_EDITOR_TAB_CONTENT_PANEL].bottom = w->height - 1; + window_title_editor_widgets[WIDX_TITLE_EDITOR_TITLE].right = w->width - 2; + window_title_editor_widgets[WIDX_TITLE_EDITOR_CLOSE].left = w->width - 2 - 0x0B; + window_title_editor_widgets[WIDX_TITLE_EDITOR_CLOSE].right = w->width - 2 - 0x0B + 0x0A; + window_title_editor_widgets[WIDX_TITLE_EDITOR_LIST].right = w->width - 4; + window_title_editor_widgets[WIDX_TITLE_EDITOR_LIST].bottom = w->height - 16; + + window_title_editor_widgets[WIDX_TITLE_EDITOR_REPLAY].top = w->height - 32; + window_title_editor_widgets[WIDX_TITLE_EDITOR_REPLAY].bottom = w->height - 16; + window_title_editor_widgets[WIDX_TITLE_EDITOR_STOP].top = w->height - 32; + window_title_editor_widgets[WIDX_TITLE_EDITOR_STOP].bottom = w->height - 16; + window_title_editor_widgets[WIDX_TITLE_EDITOR_PLAY].top = w->height - 32; + window_title_editor_widgets[WIDX_TITLE_EDITOR_PLAY].bottom = w->height - 16; + window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP].top = w->height - 32; + window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP].bottom = w->height - 16; + + int defaultPreset, playing, inTitle; + + defaultPreset = (gCurrentTitleSequence < TITLE_SEQUENCE_DEFAULT_PRESETS); + playing = (gCurrentTitleSequence == gCurrentPreviewTitleSequence) && ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) == SCREEN_FLAGS_TITLE_DEMO); + inTitle = ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) == SCREEN_FLAGS_TITLE_DEMO); + + if (!inTitle) + w->disabled_widgets |= (1 << WIDX_TITLE_EDITOR_PLAY); + else + w->disabled_widgets &= ~(1 << WIDX_TITLE_EDITOR_PLAY); + if (!playing) + w->disabled_widgets |= (1 << WIDX_TITLE_EDITOR_REPLAY) | (1 << WIDX_TITLE_EDITOR_STOP) | (1 << WIDX_TITLE_EDITOR_SKIP) | (1 << WIDX_TITLE_EDITOR_SKIP_TO); + else + w->disabled_widgets &= ~((1 << WIDX_TITLE_EDITOR_REPLAY) | (1 << WIDX_TITLE_EDITOR_STOP) | (1 << WIDX_TITLE_EDITOR_SKIP) | (1 << WIDX_TITLE_EDITOR_SKIP_TO)); +} + +void window_title_editor_paint(rct_window *w, rct_drawpixelinfo *dpi) +{ + // Widgets + window_draw_widgets(w, dpi); + window_title_editor_draw_tab_images(dpi, w); + + // Draw strings + switch (w->selected_tab) { + case WINDOW_TITLE_EDITOR_TAB_PRESETS: + + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&gConfigTitleSequences.presets[gCurrentTitleSequence].name; + gfx_draw_string_left(dpi, 5304, NULL, w->colours[1], w->x + 10, w->y + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS].top + 1); + gfx_draw_string_left_clipped( + dpi, + 1170, + (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, + w->colours[1], + w->x + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS].left + 1, + w->y + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS].top, + w->x + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS_DROPDOWN].left - window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS].left - 4 + ); + + break; + case WINDOW_TITLE_EDITOR_TAB_SAVES: + + break; + case WINDOW_TITLE_EDITOR_TAB_SCRIPT: + + break; + } +} + +void window_title_editor_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) +{ + char buffer[256]; + bool selected, hover, error, inTitle; + int y, x, x2, width; + + gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, ColourMapA[w->colours[1]].mid_light); + + title_sequence *title = &gConfigTitleSequences.presets[gCurrentTitleSequence]; + + inTitle = ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) == SCREEN_FLAGS_TITLE_DEMO); + y = 0; x = 0; x2 = 0; width = 0; + width = w->widgets[WIDX_TITLE_EDITOR_LIST].right - w->widgets[WIDX_TITLE_EDITOR_LIST].left; + if (w->selected_tab == WINDOW_TITLE_EDITOR_TAB_SAVES) { + + for (int i = 0; i < title->num_saves; i++, y += ROW_HEIGHT) { + selected = false; + hover = false; + if (i == w->selected_list_item) { + selected = true; + gfx_fill_rect(dpi, x, y, x + SCROLL_WIDTH + 100, y + ROW_HEIGHT - 1, ColourMapA[w->colours[1]].dark); + } + else if (i == _window_title_editor_highlighted_index || (i == gTitleScriptSave && inTitle && gCurrentTitleSequence == gCurrentPreviewTitleSequence)) { + hover = true; + gfx_fill_rect(dpi, x, y, x + SCROLL_WIDTH + 100, y + ROW_HEIGHT - 1, ColourMapA[w->colours[1]].mid_dark); + } + else if (i & 1) { + gfx_fill_rect(dpi, x, y, x + SCROLL_WIDTH + 100, y + ROW_HEIGHT - 1, ColourMapA[w->colours[1]].lighter | 0x1000000); + } + + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&title->saves[i]; + if (selected || hover) { + format_string(buffer, 1170, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS); + } + else { + format_string(buffer + 1, 1170, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS); + buffer[0] = FORMAT_BLACK; + } + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&buffer; + gfx_draw_string_left(dpi, 1170, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, w->colours[1], x + 5, y); + } + } + else if (w->selected_tab == WINDOW_TITLE_EDITOR_TAB_SCRIPT) { + + x2 = 92; + for (int i = 0; i < title->num_commands; i++, y += ROW_HEIGHT) { + title_command *command = &title->commands[i]; + selected = false; + hover = false; + error = false; + if (i == w->selected_list_item) { + selected = true; + gfx_fill_rect(dpi, x, y, x + SCROLL_WIDTH + 100, y + ROW_HEIGHT - 1, ColourMapA[w->colours[1]].dark); + } + else if (i == (int)_window_title_editor_highlighted_index || (i == gTitleScriptCommand && inTitle && gCurrentTitleSequence == gCurrentPreviewTitleSequence)) { + hover = true; + gfx_fill_rect(dpi, x, y, x + SCROLL_WIDTH + 100, y + ROW_HEIGHT - 1, ColourMapA[w->colours[1]].mid_dark); + } + else if (i & 1) { + gfx_fill_rect(dpi, x, y, x + SCROLL_WIDTH + 100, y + ROW_HEIGHT - 1, ColourMapA[w->colours[1]].lighter | 0x1000000); + } + + rct_string_id commandName = STR_NONE; + switch (command->command) { + case TITLE_SCRIPT_LOAD: + commandName = 5415; + if (command->saveIndex == 0xFF) { + commandName = 5416; + error = true; + } + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&title->saves[command->saveIndex]; + break; + case TITLE_SCRIPT_LOADMM: + commandName = 5414; + break; + case TITLE_SCRIPT_LOCATION: + commandName = 5418; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = command->x; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 2, uint16) = command->y; + break; + case TITLE_SCRIPT_ROTATE: + commandName = 5420; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = command->rotations; + break; + case TITLE_SCRIPT_ZOOM: + commandName = 5422; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = command->zoom; + break; + case TITLE_SCRIPT_SPEED: + commandName = 5443; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = (uint16)(5142 + command->speed - 1); + break; + case TITLE_SCRIPT_WAIT: + commandName = 5424; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = command->seconds; + break; + case TITLE_SCRIPT_RESTART: + commandName = 5425; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = command->zoom; + break; + case TITLE_SCRIPT_END: + commandName = 5426; + break; + default: + log_warning("Unknown command %d", command->command); + } + + if ((selected || hover) && !error) { + format_string(buffer, commandName, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS); + } + else { + format_string(buffer + 1, commandName, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS); + buffer[0] = (error ? ((selected || hover) ? FORMAT_LIGHTPINK : FORMAT_RED) : FORMAT_BLACK); + } + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&buffer; + gfx_draw_string_left(dpi, 1170, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, w->colours[1], x + 5, y); + } + } +} diff --git a/src/windows/title_exit.c b/src/windows/title_exit.c index 37ea4942fd..7bcefd86a8 100644 --- a/src/windows/title_exit.c +++ b/src/windows/title_exit.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 . *****************************************************************************/ @@ -32,40 +32,39 @@ static rct_widget window_title_exit_widgets[] = { { WIDGETS_END }, }; -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_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_title_exit_mouseup(rct_window *w, int widgetIndex); +static void window_title_exit_invalidate(rct_window *w); -static void* window_title_exit_events[] = { - window_title_exit_emptysub, +static rct_window_event_list window_title_exit_events = { + NULL, window_title_exit_mouseup, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, - window_title_exit_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_title_exit_invalidate, window_title_exit_paint, - window_title_exit_emptysub + NULL }; /** @@ -77,9 +76,9 @@ void window_title_exit_open() rct_window* window; window = window_create( - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - 40, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) - 64, + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 40, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - 64, 40, 64, - (uint32*)window_title_exit_events, + &window_title_exit_events, WC_TITLE_EXIT, WF_STICK_TO_BACK | WF_TRANSPARENT ); @@ -92,13 +91,8 @@ void window_title_exit_open() * * rct2: 0x0066B83C */ -static void window_title_exit_mouseup() +static void window_title_exit_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - if (RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) != 0) return; @@ -108,22 +102,15 @@ static void window_title_exit_mouseup() } /** -* +* * rct2: 0x0066B836 */ -static void window_title_exit_paint() +static void window_title_exit_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); } -static void window_title_exit_invalidate() +static void window_title_exit_invalidate(rct_window *w) { - 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 dbb473c4bf..9e338a8e63 100644 --- a/src/windows/title_logo.c +++ b/src/windows/title_logo.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 . *****************************************************************************/ @@ -29,38 +29,37 @@ static rct_widget window_title_logo_widgets[] = { { WIDGETS_END }, }; -static void window_title_logo_emptysub() {} -static void window_title_logo_paint(); +static void window_title_logo_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void* window_title_logo_events[] = { - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, - window_title_logo_emptysub, +static rct_window_event_list window_title_logo_events = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_title_logo_paint, - window_title_logo_emptysub + NULL }; static void window_title_logo_draw_expansion_packs(rct_drawpixelinfo *dpi); @@ -73,7 +72,7 @@ void window_title_logo_open() { int i, packs; rct_window *window; - + // Count number of expansion packs packs = 0; for (i = 0; i < 16; i++) @@ -86,7 +85,7 @@ void window_title_logo_open() 0, 200, 106 + (10 * packs), - (uint32*)window_title_logo_events, + &window_title_logo_events, WC_TITLE_LOGO, WF_STICK_TO_BACK | WF_TRANSPARENT ); @@ -101,13 +100,8 @@ void window_title_logo_open() * * rct2: 0x0066B872 */ -static void window_title_logo_paint() +static void window_title_logo_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - // 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); diff --git a/src/windows/title_menu.c b/src/windows/title_menu.c index fc65c97a2c..ddc684d58f 100644 --- a/src/windows/title_menu.c +++ b/src/windows/title_menu.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 . *****************************************************************************/ @@ -35,6 +35,7 @@ enum { WIDX_CONTINUE_SAVED_GAME, WIDX_SHOW_TUTORIAL, WIDX_GAME_TOOLS, + WIDX_MULTIPLAYER }; static rct_widget window_title_menu_widgets[] = { @@ -42,46 +43,46 @@ static rct_widget window_title_menu_widgets[] = { { WWT_IMGBTN, 2, 82, 163, 0, 81, SPR_MENU_LOAD_GAME, STR_CONTINUE_SAVED_GAME_TIP }, { WWT_IMGBTN, 2, 164, 245, 0, 81, SPR_MENU_TUTORIAL, STR_SHOW_TUTORIAL_TIP }, { WWT_IMGBTN, 2, 246, 327, 0, 81, SPR_MENU_TOOLBOX, STR_GAME_TOOLS }, + { WWT_DROPDOWN_BUTTON, 2, 82, 245, 88, 99, STR_MULTIPLAYER, STR_NONE }, { WIDGETS_END }, }; -static void window_title_menu_emptysub() { } -static void window_title_menu_mouseup(); +static void window_title_menu_mouseup(rct_window *w, int widgetIndex); static void window_title_menu_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -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_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); +static void window_title_menu_cursor(rct_window *w, int widgetIndex, int x, int y, int *cursorId); +static void window_title_menu_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_title_menu_invalidate(rct_window *w); -static void* window_title_menu_events[] = { - window_title_menu_emptysub, +static rct_window_event_list window_title_menu_events = { + NULL, window_title_menu_mouseup, - window_title_menu_emptysub, + NULL, window_title_menu_mousedown, window_title_menu_dropdown, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_emptysub, - window_title_menu_unknown17, - window_title_menu_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_title_menu_cursor, + NULL, window_title_menu_invalidate, window_title_menu_paint, - window_title_menu_emptysub + NULL }; /** @@ -93,28 +94,44 @@ void window_title_menu_open() rct_window* window; window = window_create( - (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - 328) / 2, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) - 142, - 328, 82, - (uint32*)window_title_menu_events, + (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 328) / 2, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - 142, + 328, 100, + &window_title_menu_events, WC_TITLE_MENU, - WF_STICK_TO_BACK | WF_TRANSPARENT + WF_STICK_TO_BACK | WF_TRANSPARENT | WF_NO_BACKGROUND ); window->widgets = window_title_menu_widgets; - window->enabled_widgets |= (8 | 4 | 2 | 1); + window->enabled_widgets = ( + (1 << WIDX_START_NEW_GAME) | + (1 << WIDX_CONTINUE_SAVED_GAME) | + (1 << WIDX_SHOW_TUTORIAL) | + (1 << WIDX_GAME_TOOLS) | + (1 << WIDX_MULTIPLAYER) + ); + + // Disable tutorial button + window->disabled_widgets = (1 << WIDX_SHOW_TUTORIAL); + +#if DISABLE_NETWORK + // Disable multiplayer + window->widgets[WIDX_MULTIPLAYER].type = WWT_EMPTY; +#endif + window_init_scroll_widgets(window); } -static void window_title_menu_mouseup() +static void window_title_menu_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window* w; - - window_widget_get_registers(w, widgetIndex); - - if (widgetIndex == WIDX_START_NEW_GAME) { + switch (widgetIndex) { + case WIDX_START_NEW_GAME: window_scenarioselect_open(); - } else if (widgetIndex == WIDX_CONTINUE_SAVED_GAME) { + break; + case WIDX_CONTINUE_SAVED_GAME: game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 0, 0); + break; + case WIDX_MULTIPLAYER: + window_server_list_open(); + break; } } @@ -148,13 +165,8 @@ static void window_title_menu_mousedown(int widgetIndex, rct_window*w, rct_widge } } -static void window_title_menu_dropdown() +static void window_title_menu_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - short widgetIndex, dropdownIndex; - rct_window *w; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - if (widgetIndex == WIDX_SHOW_TUTORIAL) { tutorial_start(dropdownIndex); } else if (widgetIndex == WIDX_GAME_TOOLS) { @@ -175,24 +187,30 @@ static void window_title_menu_dropdown() } } -static void window_title_menu_unknown17() +static void window_title_menu_cursor(rct_window *w, int widgetIndex, int x, int y, int *cursorId) { RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, sint16) = 2000; } -static void window_title_menu_paint() +static void window_title_menu_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); + gfx_fill_rect(dpi, w->x, w->y, w->x + w->width - 1, w->y + 82 - 1, 0x2000000 | 51); + rct_widget *multiplayerButtonWidget = &window_title_menu_widgets[WIDX_MULTIPLAYER]; + if (multiplayerButtonWidget->type != WWT_EMPTY) { + gfx_fill_rect( + dpi, + w->x + multiplayerButtonWidget->left, + w->y + multiplayerButtonWidget->top, + w->x + multiplayerButtonWidget->right, + w->y + multiplayerButtonWidget->bottom, + 0x2000000 | 51 + ); + } window_draw_widgets(w, dpi); } -static void window_title_menu_invalidate() +static void window_title_menu_invalidate(rct_window *w) { - 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 index 39be909cbd..f841862d37 100644 --- a/src/windows/title_options.c +++ b/src/windows/title_options.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 . *****************************************************************************/ @@ -31,40 +31,39 @@ static rct_widget window_title_options_widgets[] = { { 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_mouseup(rct_window *w, int widgetIndex); +static void window_title_options_invalidate(rct_window *w); +static void window_title_options_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void* window_title_options_events[] = { - window_title_options_emptysub, +static rct_window_event_list window_title_options_events = { + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_title_options_invalidate, window_title_options_paint, - window_title_options_emptysub + NULL }; /** @@ -75,9 +74,9 @@ void window_title_options_open() rct_window* window; window = window_create( - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - 80, 0, + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 80, 0, 80, 12, - (uint32*)window_title_options_events, + &window_title_options_events, WC_TITLE_OPTIONS, WF_STICK_TO_BACK | WF_TRANSPARENT ); @@ -86,13 +85,8 @@ void window_title_options_open() window_init_scroll_widgets(window); } -static void window_title_options_mouseup() +static void window_title_options_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - if (RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) != 0) return; @@ -100,19 +94,12 @@ static void window_title_options_mouseup() window_options_open(); } -static void window_title_options_paint() +static void window_title_options_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); } -static void window_title_options_invalidate() +static void window_title_options_invalidate(rct_window *w) { - 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 8fdf3fc80c..cc20a5ca8c 100644 --- a/src/windows/title_scenarioselect.c +++ b/src/windows/title_scenarioselect.c @@ -28,6 +28,7 @@ #include "../interface/widget.h" #include "../interface/window.h" #include "../interface/themes.h" +#include "../util/util.h" enum { WIDX_BACKGROUND, @@ -58,49 +59,48 @@ static rct_widget window_scenarioselect_widgets[] = { static void window_scenarioselect_init_tabs(); -static void window_scenarioselect_emptysub() { } -static void window_scenarioselect_mouseup(); +static void window_scenarioselect_mouseup(rct_window *w, int widgetIndex); static void window_scenarioselect_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); -static void window_scenarioselect_scrollgetsize(); -static void window_scenarioselect_scrollmousedown(); -static void window_scenarioselect_scrollmouseover(); -static void window_scenarioselect_invalidate(); -static void window_scenarioselect_paint(); -static void window_scenarioselect_scrollpaint(); +static void window_scenarioselect_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_scenarioselect_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_scenarioselect_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_scenarioselect_invalidate(rct_window *w); +static void window_scenarioselect_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_scenarioselect_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void* window_scenarioselect_events[] = { - window_scenarioselect_emptysub, +static rct_window_event_list window_scenarioselect_events = { + NULL, window_scenarioselect_mouseup, - window_scenarioselect_emptysub, + NULL, window_scenarioselect_mousedown, - window_scenarioselect_emptysub, - window_scenarioselect_emptysub, - window_scenarioselect_emptysub, - window_scenarioselect_emptysub, - window_scenarioselect_emptysub, - window_scenarioselect_emptysub, - window_scenarioselect_emptysub, - window_scenarioselect_emptysub, - window_scenarioselect_emptysub, - window_scenarioselect_emptysub, - window_scenarioselect_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_scenarioselect_scrollgetsize, window_scenarioselect_scrollmousedown, - window_scenarioselect_emptysub, + NULL, window_scenarioselect_scrollmouseover, - window_scenarioselect_emptysub, - window_scenarioselect_emptysub, - window_scenarioselect_emptysub, - window_scenarioselect_emptysub, - window_scenarioselect_emptysub, - window_scenarioselect_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_scenarioselect_invalidate, window_scenarioselect_paint, window_scenarioselect_scrollpaint }; /** - * + * * rct2: 0x006781B5 */ void window_scenarioselect_open() @@ -116,12 +116,12 @@ void window_scenarioselect_open() window = window_create_centred( 610, 334, - (uint32*)window_scenarioselect_events, + &window_scenarioselect_events, WC_SCENARIO_SELECT, WF_10 ); window->widgets = window_scenarioselect_widgets; - + window->enabled_widgets = 0x04 | 0x10 | 0x20 | 0x40 | 0x80 | 0x100; window_init_scroll_widgets(window); window->viewport_focus_coordinates.var_480 = -1; @@ -133,7 +133,7 @@ void window_scenarioselect_open() } /** - * + * * rct2: 0x00677C8A */ static void window_scenarioselect_init_tabs() @@ -164,13 +164,8 @@ static void window_scenarioselect_init_tabs() } } -static void window_scenarioselect_mouseup() +static void window_scenarioselect_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w; - - window_widget_get_registers(w, widgetIndex); - if (widgetIndex == WIDX_CLOSE) window_close(w); } @@ -188,37 +183,27 @@ static void window_scenarioselect_mousedown(int widgetIndex, rct_window*w, rct_w } } -static void window_scenarioselect_scrollgetsize() +static void window_scenarioselect_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - int i, width, height; - rct_window *w; + int i; rct_scenario_basic *scenario; - window_get_register(w); - - width = 0; - height = 0; + *height = 0; for (i = 0; i < gScenarioListCount; i++) { scenario = &gScenarioList[i]; if (scenario->category != w->selected_tab) continue; if (scenario->flags & SCENARIO_FLAGS_VISIBLE) - height += 24; + *height += 24; } - - window_scrollsize_set_registers(width, height); } /* rct2: 0x6780FE */ -static void window_scenarioselect_scrollmousedown() +static void window_scenarioselect_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) { int i; - short x, y, scrollIndex; - rct_window *w; rct_scenario_basic *scenario; - window_scrollmouse_get_registers(w, scrollIndex, x, y); - for (i = 0; i < gScenarioListCount; i++) { scenario = &gScenarioList[i]; if (scenario->category != w->selected_tab) @@ -230,22 +215,18 @@ static void window_scenarioselect_scrollmousedown() if (y >= 0) continue; - sound_play_panned(SOUND_CLICK_1, w->width / 2 + w->x, 0, 0, 0); + audio_play_sound_panned(SOUND_CLICK_1, w->width / 2 + w->x, 0, 0, 0); scenario_load_and_play(scenario); break; } } /* rct2: 0x678162 */ -static void window_scenarioselect_scrollmouseover() +static void window_scenarioselect_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) { int i; - short x, y, scrollIndex; - rct_window *w; rct_scenario_basic *scenario, *selected; - window_scrollmouse_get_registers(w, scrollIndex, x, y); - selected = NULL; for (i = 0; i < gScenarioListCount; i++) { scenario = &gScenarioList[i]; @@ -267,29 +248,22 @@ static void window_scenarioselect_scrollmouseover() } } -static void window_scenarioselect_invalidate() +static void window_scenarioselect_invalidate(rct_window *w) { - 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); } -static void window_scenarioselect_paint() +static void window_scenarioselect_paint(rct_window *w, rct_drawpixelinfo *dpi) { int i, x, y, format; - rct_window *w; - rct_drawpixelinfo *dpi; rct_widget *widget; rct_scenario_basic *scenario; - 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 @@ -309,20 +283,16 @@ static void window_scenarioselect_paint() if (scenario == NULL) return; - // Draw SixFlags image - if (scenario->flags & SCENARIO_FLAGS_SIXFLAGS) - gfx_draw_sprite(dpi, SPR_SIX_FLAGS, w->x + w->width - 55, w->y + w->height - 75, 0); - // Scenario name x = w->x + window_scenarioselect_widgets[WIDX_SCENARIOLIST].right + 4; y = w->y + window_scenarioselect_widgets[WIDX_TABCONTENT].top + 5; - strcpy((char*)0x009BC677, scenario->name); + safe_strncpy((char*)0x009BC677, scenario->name, 64); RCT2_GLOBAL(0x013CE952 + 0, short) = 3165; gfx_draw_string_centred_clipped(dpi, 1193, (void*)0x013CE952, 0, x + 85, y, 170); y += 15; // Scenario details - strcpy((char*)0x009BC677, scenario->details); + safe_strncpy((char*)0x009BC677, scenario->details, 256); RCT2_GLOBAL(0x013CE952 + 0, short) = 3165; y += gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x, y, 170, 1191, 0) + 5; @@ -335,23 +305,19 @@ static void window_scenarioselect_paint() // Scenario score if (scenario->flags & SCENARIO_FLAGS_COMPLETED) { - strcpy((char*)0x009BC677, scenario->completed_by); + safe_strncpy((char*)0x009BC677, scenario->completed_by, 64); RCT2_GLOBAL(0x013CE952 + 0, short) = 3165; RCT2_GLOBAL(0x013CE952 + 2, int) = scenario->company_value; y += gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x, y, 170, STR_COMPLETED_BY_WITH_COMPANY_VALUE, 0); } } -static void window_scenarioselect_scrollpaint() +static void window_scenarioselect_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { int i, y, colour, highlighted, highlighted_format, unhighlighted_format; - rct_window *w; - rct_drawpixelinfo *dpi; rct_scenario_basic *scenario; - window_paint_get_registers(w, dpi); - - colour = ((char*)0x0141FC48)[w->colours[1] * 8]; + colour = ColourMapA[w->colours[1]].mid_light; colour = (colour << 24) | (colour << 16) | (colour << 8) | colour; gfx_clear(dpi, colour); @@ -376,8 +342,8 @@ static void window_scenarioselect_scrollpaint() gfx_fill_rect(dpi, 0, y, w->width, y + 23, 0x02000031); // Draw scenario name - strcpy((char*)0x009BC677, scenario->name); - RCT2_GLOBAL(0x013CE952, short) = 3165; + safe_strncpy((char*)0x009BC677, scenario->name, 64); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, short) = 3165; gfx_draw_string_centred(dpi, highlighted ? highlighted_format : unhighlighted_format, 210, y + 1, 0, (void*)0x013CE952); // Check if scenario is completed @@ -386,8 +352,8 @@ static void window_scenarioselect_scrollpaint() gfx_draw_sprite(dpi, 0x5A9F, 395, y + 1, 0); // Draw completion score - strcpy((char*)0x009BC677, scenario->completed_by); - RCT2_GLOBAL(0x013CE952, short) = 2793; + safe_strncpy((char*)0x009BC677, scenario->completed_by, 64); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, short) = 2793; RCT2_GLOBAL(0x013CE954, short) = 3165; gfx_draw_string_centred(dpi, highlighted ? 1193 : 1191, 210, y + 11, 0, (void*)0x013CE952); } diff --git a/src/windows/tooltip.c b/src/windows/tooltip.c index 8a6e8a11e2..724e42e331 100644 --- a/src/windows/tooltip.c +++ b/src/windows/tooltip.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 . *****************************************************************************/ @@ -33,40 +33,39 @@ static rct_widget window_tooltip_widgets[] = { { WIDGETS_END }, }; -static void window_tooltip_emptysub() { } -static void window_tooltip_onclose(); +static void window_tooltip_onclose(rct_window *w); static void window_tooltip_update(rct_window *w); -static void window_tooltip_paint(); +static void window_tooltip_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void* window_tooltip_events[] = { +static rct_window_event_list window_tooltip_events = { window_tooltip_onclose, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, window_tooltip_update, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, - window_tooltip_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_tooltip_paint, - window_tooltip_emptysub + NULL }; void window_tooltip_reset(int x, int y) @@ -80,30 +79,11 @@ void window_tooltip_reset(int x, int y) } uint8* gTooltip_text_buffer = RCT2_ADDRESS(RCT2_ADDRESS_TOOLTIP_TEXT_BUFFER, uint8); -/** - * - * rct2: 0x006EA10D - */ -void window_tooltip_open(rct_window *widgetWindow, int widgetIndex, int x, int y) + +void window_tooltip_show(rct_string_id id, int x, int y) { rct_window *w; - rct_widget *widget; int width, height; - - if (widgetWindow == NULL || widgetIndex == -1) - return; - - widget = &widgetWindow->widgets[widgetIndex]; - window_event_invalidate_call(widgetWindow); - if (widget->tooltip == 0xFFFF) - return; - - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) = widgetWindow->classification; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) = widgetWindow->number; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = widgetIndex; - - if (window_event_tooltip_call(widgetWindow, widgetIndex) == (rct_string_id)STR_NONE) - return; w = window_find_by_class(WC_ERROR); if (w != NULL) @@ -112,30 +92,27 @@ void window_tooltip_open(rct_window *widgetWindow, int widgetIndex, int x, int y RCT2_GLOBAL(0x0142006C, sint32) = -1; char* buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); - format_string(buffer, widget->tooltip, (void*)0x013CE952); - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; - - int tooltip_text_width = 0, tooltip_text_height = 0; + format_string(buffer, id, (void*)0x013CE952); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = FONT_SPRITE_BASE_MEDIUM; + int tooltip_text_width; tooltip_text_width = gfx_get_string_width_new_lined(buffer); buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, char); - tooltip_text_width &= 0xFFFF; - if (tooltip_text_width > 196) - tooltip_text_width = 196; + tooltip_text_width = min(tooltip_text_width, 196); - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = FONT_SPRITE_BASE_MEDIUM; - int fontHeight; - tooltip_text_width = gfx_wrap_string(buffer, tooltip_text_width + 1, &tooltip_text_height, &fontHeight); + int numLines, fontSpriteBase; + tooltip_text_width = gfx_wrap_string(buffer, tooltip_text_width + 1, &numLines, &fontSpriteBase); - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TEXT_HEIGHT, sint16) = tooltip_text_height; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TEXT_HEIGHT, sint16) = numLines; width = tooltip_text_width + 3; - height = ((tooltip_text_height + 1) * 10) + 4; + height = ((numLines + 1) * font_get_line_height(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16))) + 4; window_tooltip_widgets[WIDX_BACKGROUND].right = width; window_tooltip_widgets[WIDX_BACKGROUND].bottom = height; memcpy(gTooltip_text_buffer, buffer, 512); - + x = clamp(0, x - (width / 2), RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - width); int max_y = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - height; @@ -151,17 +128,43 @@ void window_tooltip_open(rct_window *widgetWindow, int widgetIndex, int x, int y y, width, height, - (uint32*)window_tooltip_events, + &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; } /** - * + * + * rct2: 0x006EA10D + */ +void window_tooltip_open(rct_window *widgetWindow, int widgetIndex, int x, int y) +{ + rct_widget *widget; + + if (widgetWindow == NULL || widgetIndex == -1) + return; + + widget = &widgetWindow->widgets[widgetIndex]; + window_event_invalidate_call(widgetWindow); + if (widget->tooltip == 0xFFFF) + return; + + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) = widgetWindow->classification; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) = widgetWindow->number; + RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = widgetIndex; + + if (window_event_tooltip_call(widgetWindow, widgetIndex) == (rct_string_id)STR_NONE) + return; + + window_tooltip_show(widget->tooltip, x, y); +} + +/** + * * rct2: 0x006E98C6 */ void window_tooltip_close() @@ -174,16 +177,16 @@ void window_tooltip_close() } /** - * + * * rct2: 0x006EA578 */ -static void window_tooltip_onclose() +static void window_tooltip_onclose(rct_window *w) { RCT2_GLOBAL(0x009BC3B0, uint8) = 0; } /** - * + * * rct2: 0x006EA580 */ static void window_tooltip_update(rct_window *w) @@ -193,16 +196,11 @@ static void window_tooltip_update(rct_window *w) } /** - * + * * rct2: 0x006EA41D */ -static void window_tooltip_paint() +static void window_tooltip_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - int left = w->x; int top = w->y; int right = w->x + w->width - 1; @@ -223,9 +221,9 @@ static void window_tooltip_paint() gfx_draw_pixel(dpi, right - 1, top + 1, 0x0200002F); gfx_draw_pixel(dpi, left + 1, bottom - 1, 0x0200002F); gfx_draw_pixel(dpi, right - 1, bottom - 1, 0x0200002F); - + // Text left = w->x + ((w->width + 1) / 2) - 1; top = w->y + 1; - draw_string_centred_raw(dpi, left, top, RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TEXT_HEIGHT, uint16), gTooltip_text_buffer); -} \ No newline at end of file + draw_string_centred_raw(dpi, left, top, RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TEXT_HEIGHT, uint16), (char *)gTooltip_text_buffer); +} diff --git a/src/windows/tooltip.h b/src/windows/tooltip.h index adff1c3ed6..b5b649463c 100644 --- a/src/windows/tooltip.h +++ b/src/windows/tooltip.h @@ -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 . *****************************************************************************/ @@ -24,6 +24,7 @@ #include "../interface/window.h" void window_tooltip_reset(int x, int y); +void window_tooltip_show(rct_string_id id, int x, int y); void window_tooltip_open(rct_window *widgetWindow, int widgetIndex, int x, int y); void window_tooltip_close(); diff --git a/src/windows/top_toolbar.c b/src/windows/top_toolbar.c index 7079828796..881c4a845c 100644 --- a/src/windows/top_toolbar.c +++ b/src/windows/top_toolbar.c @@ -8,17 +8,18 @@ * 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 "../cheats.h" #include "../config.h" #include "../editor.h" #include "../game.h" @@ -30,8 +31,10 @@ #include "../interface/window.h" #include "../interface/viewport.h" #include "../localisation/localisation.h" +#include "../network/network.h" #include "../network/twitch.h" #include "../scenario.h" +#include "../util/util.h" #include "../world/scenery.h" #include "../world/banner.h" #include "dropdown.h" @@ -63,6 +66,8 @@ enum { WIDX_DEBUG, WIDX_FINANCES, WIDX_RESEARCH, + WIDX_NEWS, + WIDX_NETWORK, WIDX_SEPARATOR, }; @@ -70,16 +75,17 @@ enum { 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 + DDIDX_SAVE_GAME_AS = 2, + // separator + DDIDX_ABOUT = 4, + DDIDX_OPTIONS = 5, + DDIDX_SCREENSHOT = 6, + DDIDX_GIANT_SCREENSHOT = 7, + // separator + DDIDX_QUIT_TO_MENU = 9, + DDIDX_EXIT_OPENRCT2 = 10, + // separator + DDIDX_ENABLE_TWITCH = 12 } FILE_MENU_DDIDX; typedef enum { @@ -97,9 +103,23 @@ typedef enum { typedef enum { DDIDX_CONSOLE = 0, - DDIDX_TILE_INSPECTOR = 1 + DDIDX_TILE_INSPECTOR = 1, + DDIDX_OBJECT_SELECTION = 2, + DDIDX_INVENTIONS_LIST = 3, + DDIDX_SCENARIO_OPTIONS = 4 } TOP_TOOLBAR_DEBUG_DDIDX; +typedef enum { + DDIDX_PLAYER_LIST = 0 +} TOP_TOOLBAR_NETWORK_DDIDX; + +enum { + DDIDX_CHEATS, + DDIDX_ENABLE_SANDBOX_MODE = 2, + DDIDX_DISABLE_CLEARANCE_CHECKS, + DDIDX_DISABLE_SUPPORT_LIMITS +}; + #pragma region Toolbar_widget_ordering // from left to right @@ -107,6 +127,7 @@ static const int left_aligned_widgets_order[] = { WIDX_PAUSE, WIDX_FASTFORWARD, WIDX_FILE_MENU, + WIDX_NETWORK, WIDX_CHEATS, WIDX_DEBUG, @@ -121,6 +142,7 @@ static const int left_aligned_widgets_order[] = { // from right to left static const int right_aligned_widgets_order[] = { + WIDX_NEWS, WIDX_GUESTS, WIDX_STAFF, WIDX_PARK, @@ -135,7 +157,7 @@ static const int right_aligned_widgets_order[] = { WIDX_SCENERY, WIDX_WATER, WIDX_LAND, - WIDX_CLEAR_SCENERY, + WIDX_CLEAR_SCENERY }; #pragma endregion @@ -160,63 +182,70 @@ static rct_widget window_top_toolbar_widgets[] = { { 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_TRNBTN, 0, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, STR_GAME_SPEED_TIP }, // Fast forward + { WWT_TRNBTN, 0, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, STR_CHEATS_TIP }, // Cheats + { WWT_TRNBTN, 0, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, STR_DEBUG_TIP }, // Debug + { WWT_TRNBTN, 3, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, STR_SCENARIO_OPTIONS_FINANCIAL_TIP },// Finances + { WWT_TRNBTN, 3, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, STR_FINANCES_RESEARCH_TIP }, // Research + { WWT_TRNBTN, 3, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, STR_SHOW_RECENT_MESSAGES_TIP }, // News + { WWT_TRNBTN, 0, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, STR_SHOW_MULTIPLAYER_STATUS_TIP }, // Network + { 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_mouseup(rct_window *w, int widgetIndex); 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_dropdown(rct_window *w, int widgetIndex, int dropdownIndex); +static void window_top_toolbar_tool_update(rct_window* w, int widgetIndex, int x, int y); +static void window_top_toolbar_tool_down(rct_window* w, int widgetIndex, int x, int y); +static void window_top_toolbar_tool_drag(rct_window* w, int widgetIndex, int x, int y); +static void window_top_toolbar_tool_up(rct_window* w, int widgetIndex, int x, int y); +static void window_top_toolbar_tool_abort(rct_window *w, int widgetIndex); +static void window_top_toolbar_invalidate(rct_window *w); +static void window_top_toolbar_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void* window_top_toolbar_events[] = { - window_top_toolbar_emptysub, +static rct_window_event_list window_top_toolbar_events = { + NULL, window_top_toolbar_mouseup, - window_top_toolbar_emptysub, + NULL, 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... + NULL, + NULL, + NULL, + NULL, // 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_tool_up, // editor: 0x0066fC44 (Exactly the same) + window_top_toolbar_tool_abort, // editor: 0x0066fA74 (Exactly the same) + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_top_toolbar_invalidate, window_top_toolbar_paint, - window_top_toolbar_emptysub + NULL }; 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_rotate_menu(rct_window *window, rct_widget *widget); +void top_toolbar_rotate_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 top_toolbar_init_network_menu(rct_window *window, rct_widget *widget); +void top_toolbar_network_menu_dropdown(short dropdownIndex); void toggle_footpath_window(); void toggle_land_window(rct_window *topToolbar, int widgetIndex); @@ -238,10 +267,10 @@ void window_top_toolbar_open() window = window_create( 0, 0, - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16), 28, - (uint32*)window_top_toolbar_events, + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16), 28, + &window_top_toolbar_events, WC_TOP_TOOLBAR, - WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_5 + WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_NO_BACKGROUND ); window->widgets = window_top_toolbar_widgets; @@ -249,19 +278,18 @@ void window_top_toolbar_open() } /** - * + * * rct2: 0x0066C957 */ -static void window_top_toolbar_mouseup() +static void window_top_toolbar_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w, *mainWindow; - - window_widget_get_registers(w, widgetIndex); + rct_window *mainWindow; switch (widgetIndex) { case WIDX_PAUSE: - game_do_command(0, 1, 0, 0, GAME_COMMAND_TOGGLE_PAUSE, 0, 0); + if (network_get_mode() != NETWORK_MODE_CLIENT) { + game_do_command(0, 1, 0, 0, GAME_COMMAND_TOGGLE_PAUSE, 0, 0); + } break; case WIDX_ZOOM_OUT: if ((mainWindow = window_get_main()) != NULL) @@ -271,10 +299,6 @@ static void window_top_toolbar_mouseup() 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; @@ -314,14 +338,14 @@ static void window_top_toolbar_mouseup() case WIDX_RESEARCH: window_research_open(); break; - case WIDX_CHEATS: - window_cheats_open(); + case WIDX_NEWS: + window_news_open(); break; } } /** - * + * * rct2: 0x0066CA3B */ static void window_top_toolbar_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) @@ -359,23 +383,24 @@ static void window_top_toolbar_mousedown(int widgetIndex, rct_window*w, rct_widg } 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; + gDropdownItemsFormat[2] = STR_SAVE_GAME_AS; + gDropdownItemsFormat[3] = 0; + gDropdownItemsFormat[4] = STR_ABOUT; + gDropdownItemsFormat[5] = STR_OPTIONS; + gDropdownItemsFormat[6] = STR_SCREENSHOT; + gDropdownItemsFormat[7] = STR_GIANT_SCREENSHOT; + gDropdownItemsFormat[8] = 0; + gDropdownItemsFormat[9] = STR_QUIT_TO_MENU; + gDropdownItemsFormat[10] = STR_EXIT_OPENRCT2; + numItems = 11; #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; + gDropdownItemsFormat[11] = 0; + gDropdownItemsFormat[12] = 1156; + gDropdownItemsArgs[12] = STR_TWITCH_ENABLE; + numItems = 13; } #endif } @@ -389,10 +414,40 @@ static void window_top_toolbar_mousedown(int widgetIndex, rct_window*w, rct_widg ); #ifndef DISABLE_TWITCH - if (_menuDropdownIncludesTwitch && gTwitchEnable) - gDropdownItemsChecked |= (1 << 11); + if (_menuDropdownIncludesTwitch && gTwitchEnable) { + dropdown_set_checked(11, true); + } #endif break; + case WIDX_CHEATS: + gDropdownItemsFormat[0] = 1156; + gDropdownItemsFormat[1] = 0; + gDropdownItemsFormat[2] = 1156; + gDropdownItemsFormat[3] = 1156; + gDropdownItemsFormat[4] = 1156; + gDropdownItemsArgs[0] = 5217; + gDropdownItemsArgs[2] = STR_ENABLE_SANDBOX_MODE; + gDropdownItemsArgs[3] = STR_DISABLE_CLEARANCE_CHECKS; + gDropdownItemsArgs[4] = STR_DISABLE_SUPPORT_LIMITS; + window_dropdown_show_text( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[0] | 0x80, + 0, + 5 + ); + if (gCheatsSandboxMode) { + dropdown_set_checked(DDIDX_ENABLE_SANDBOX_MODE, true); + } + if (gCheatsDisableClearanceChecks) { + dropdown_set_checked(DDIDX_DISABLE_CLEARANCE_CHECKS, true); + } + if (gCheatsDisableSupportLimits) { + dropdown_set_checked(DDIDX_DISABLE_SUPPORT_LIMITS, true); + } + RCT2_GLOBAL(0x009DEBA2, uint16) = 0; + break; case WIDX_VIEW_MENU: top_toolbar_init_view_menu(w, widget); break; @@ -413,31 +468,38 @@ static void window_top_toolbar_mousedown(int widgetIndex, rct_window*w, rct_widg 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_ROTATE: + top_toolbar_init_rotate_menu(w, widget); + break; case WIDX_DEBUG: top_toolbar_init_debug_menu(w, widget); break; + case WIDX_NETWORK: + top_toolbar_init_network_menu(w, widget); + break; } } /** - * + * * rct2: 0x0066C9EA */ -static void window_top_toolbar_dropdown() +static void window_top_toolbar_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - short widgetIndex, dropdownIndex; - rct_window* w; - - window_dropdown_get_registers(w, widgetIndex, dropdownIndex); - switch (widgetIndex) { case WIDX_FILE_MENU: + + // Quicksave is only available in the normal game. Skip one position to avoid incorrect mappings in the menus of the other modes. + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_SCENARIO_EDITOR) && dropdownIndex > DDIDX_LOAD_GAME) + dropdownIndex += 1; + + // Track designer and track designs manager start with About, not Load/save if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)) dropdownIndex += DDIDX_ABOUT; @@ -446,12 +508,17 @@ static void window_top_toolbar_dropdown() game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 0, 0); break; case DDIDX_SAVE_GAME: + tool_cancel(); + save_game(); + break; + case DDIDX_SAVE_GAME_AS: 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 { + } + else { tool_cancel(); - save_game(); + save_game_as(); } break; case DDIDX_ABOUT: @@ -481,6 +548,23 @@ static void window_top_toolbar_dropdown() #endif } break; + case WIDX_CHEATS: + if (dropdownIndex == -1) dropdownIndex = RCT2_GLOBAL(0x009DEBA2, uint16); + switch (dropdownIndex) { + case DDIDX_CHEATS: + window_cheats_open(); + break; + case DDIDX_ENABLE_SANDBOX_MODE: + gCheatsSandboxMode = !gCheatsSandboxMode; + break; + case DDIDX_DISABLE_CLEARANCE_CHECKS: + gCheatsDisableClearanceChecks = !gCheatsDisableClearanceChecks; + break; + case DDIDX_DISABLE_SUPPORT_LIMITS: + gCheatsDisableSupportLimits = !gCheatsDisableSupportLimits; + break; + } + break; case WIDX_VIEW_MENU: top_toolbar_view_menu_dropdown(dropdownIndex); break; @@ -503,23 +587,27 @@ static void window_top_toolbar_dropdown() case WIDX_FASTFORWARD: top_toolbar_fastforward_menu_dropdown(dropdownIndex); break; + case WIDX_ROTATE: + top_toolbar_rotate_menu_dropdown(dropdownIndex); + break; case WIDX_DEBUG: top_toolbar_debug_menu_dropdown(dropdownIndex); break; + case WIDX_NETWORK: + top_toolbar_network_menu_dropdown(dropdownIndex); + break; } } /** - * + * * rct2: 0x0066C810 */ -static void window_top_toolbar_invalidate() +static void window_top_toolbar_invalidate(rct_window *w) { int i, x, enabledWidgets, widgetIndex, widgetWidth, firstAlignment; - rct_window *w; rct_widget *widget; - window_get_register(w); colour_scheme_update(w); // Enable / disable buttons @@ -545,6 +633,8 @@ static void window_top_toolbar_invalidate() 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; + window_top_toolbar_widgets[WIDX_NEWS].type = WWT_TRNBTN; + window_top_toolbar_widgets[WIDX_NETWORK].type = WWT_TRNBTN; 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; @@ -555,6 +645,8 @@ static void window_top_toolbar_invalidate() 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; + window_top_toolbar_widgets[WIDX_NEWS].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_NETWORK].type = WWT_EMPTY; if (g_editor_step != EDITOR_STEP_LANDSCAPE_EDITOR) { window_top_toolbar_widgets[WIDX_MAP].type = WWT_EMPTY; @@ -564,7 +656,7 @@ static void window_top_toolbar_invalidate() 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; @@ -585,10 +677,25 @@ static void window_top_toolbar_invalidate() if (!gConfigInterface.toolbar_show_cheats) window_top_toolbar_widgets[WIDX_CHEATS].type = WWT_EMPTY; + + if (!gConfigInterface.toolbar_show_news) + window_top_toolbar_widgets[WIDX_NEWS].type = WWT_EMPTY; + + switch (network_get_mode()) { + case NETWORK_MODE_SERVER: + window_top_toolbar_widgets[WIDX_FASTFORWARD].type = WWT_EMPTY; + break; + case NETWORK_MODE_CLIENT: + window_top_toolbar_widgets[WIDX_PAUSE].type = WWT_EMPTY; + window_top_toolbar_widgets[WIDX_FASTFORWARD].type = WWT_EMPTY; + break; + default: + window_top_toolbar_widgets[WIDX_NETWORK].type = WWT_EMPTY; + } } enabledWidgets = 0; - for (i = WIDX_PAUSE; i <= WIDX_RESEARCH; i++) + for (i = WIDX_PAUSE; i <= WIDX_NETWORK; i++) if (window_top_toolbar_widgets[i].type != WWT_EMPTY) enabledWidgets |= (1 << i); w->enabled_widgets = enabledWidgets; @@ -615,7 +722,7 @@ static void window_top_toolbar_invalidate() // Align right hand side toolbar buttons firstAlignment = 1; - x = max(640, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16)); + x = max(640, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16)); for (int i = 0; i < countof(right_aligned_widgets_order); ++i) { widgetIndex = right_aligned_widgets_order[i]; widget = &window_top_toolbar_widgets[widgetIndex]; @@ -639,12 +746,6 @@ static void window_top_toolbar_invalidate() 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 @@ -661,16 +762,12 @@ static void window_top_toolbar_invalidate() } /** - * + * * rct2: 0x0066C8EC */ -static void window_top_toolbar_paint() +static void window_top_toolbar_paint(rct_window *w, rct_drawpixelinfo *dpi) { int x, y, imgId; - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); window_draw_widgets(w, dpi); @@ -701,9 +798,6 @@ static void window_top_toolbar_paint() 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 @@ -712,7 +806,7 @@ static void window_top_toolbar_paint() y = w->y + window_top_toolbar_widgets[WIDX_CHEATS].top - 1; if (widget_is_pressed(w, WIDX_CHEATS)) y++; - imgId = SPR_TAB_OBJECTIVE_0; + imgId = SPR_G2_SANDBOX; gfx_draw_sprite(dpi, imgId, x, y, 3); } @@ -745,6 +839,26 @@ static void window_top_toolbar_paint() imgId = SPR_FINANCE; gfx_draw_sprite(dpi, imgId, x, y, 0); } + + // Draw news button + if (window_top_toolbar_widgets[WIDX_NEWS].type != WWT_EMPTY) { + x = w->x + window_top_toolbar_widgets[WIDX_NEWS].left + 3; + y = w->y + window_top_toolbar_widgets[WIDX_NEWS].top + 0; + if (widget_is_pressed(w, WIDX_NEWS)) + y++; + imgId = SPR_G2_TAB_NEWS; + gfx_draw_sprite(dpi, imgId, x, y, 0); + } + + // Draw network button + if (window_top_toolbar_widgets[WIDX_NETWORK].type != WWT_EMPTY) { + x = w->x + window_top_toolbar_widgets[WIDX_NETWORK].left + 3; + y = w->y + window_top_toolbar_widgets[WIDX_NETWORK].top + 0; + if (widget_is_pressed(w, WIDX_NETWORK)) + y++; + imgId = SPR_SHOW_GUESTS_ON_THIS_RIDE_ATTRACTION; + gfx_draw_sprite(dpi, imgId, x, y, 0); + } } /* rct2: 0x006E3158 */ @@ -776,13 +890,13 @@ static void repaint_scenery_tool_down(sint16 x, sint16 y, sint16 widgetIndex){ SMALL_SCENERY_FLAG10))) return; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 3103; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_REPAINT_THIS; 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, + GAME_COMMAND_SET_SCENERY_COLOUR, 0, window_scenery_primary_colour | (window_scenery_secondary_colour << 8)); break; @@ -797,13 +911,13 @@ static void repaint_scenery_tool_down(sint16 x, sint16 y, sint16 widgetIndex){ WALL_SCENERY_FLAG2))) return; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 3103; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_REPAINT_THIS; 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, + GAME_COMMAND_SET_FENCE_COLOUR, 0, window_scenery_secondary_colour | (window_scenery_tertiary_colour << 8)); break; @@ -817,13 +931,13 @@ static void repaint_scenery_tool_down(sint16 x, sint16 y, sint16 widgetIndex){ (1 << 0))) return; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 3103; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_REPAINT_THIS; 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, + GAME_COMMAND_SET_LARGE_SCENERY_COLOUR, 0, window_scenery_primary_colour | (window_scenery_secondary_colour << 8)); break; @@ -838,13 +952,13 @@ static void repaint_scenery_tool_down(sint16 x, sint16 y, sint16 widgetIndex){ (1 << 0))) return; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 3103; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_REPAINT_THIS; game_do_command( grid_x, 1, grid_y, map_element->base_height | ((map_element->properties.banner.position & 0x3) << 8), - GAME_COMMAND_55, + GAME_COMMAND_SET_BANNER_COLOUR, 0, window_scenery_primary_colour | (window_scenery_secondary_colour << 8)); break; @@ -854,56 +968,7 @@ static void repaint_scenery_tool_down(sint16 x, sint16 y, sint16 widgetIndex){ } } -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 +/* rct2: 0x006E1F34 * Outputs * eax : grid_x * ebx : parameter_1 @@ -935,7 +1000,7 @@ void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sin type = 1; } - if (type == 0){ + if (type == 0 && !gCheatsDisableSupportLimits) { RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_CTRL_PRESSED, uint8) = 0; RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) = 0; } @@ -991,7 +1056,7 @@ void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sin } } } - + switch (scenery_type){ case 0: { @@ -1002,7 +1067,7 @@ void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sin // If CTRL not pressed if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_CTRL_PRESSED, uint8) == 0){ - sub_689604(x, y, grid_x, grid_y, &cl); + screen_get_map_xy_quadrant(x, y, grid_x, grid_y, &cl); if (*grid_x == (sint16)0x8000) return; @@ -1032,7 +1097,7 @@ void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sin else{ sint16 z = RCT2_GLOBAL(RCT2_ADDRESS_CTRL_PRESS_Z_COORDINATE, sint16); - sub_68964B(x, y, z, grid_x, grid_y, &cl); + screen_get_map_xy_quadrant_with_z(x, y, z, grid_x, grid_y, &cl); // If SHIFT pressed if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ @@ -1052,10 +1117,10 @@ void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sin uint8 rotation = window_scenery_rotation; if (!(scenery->small_scenery.flags & SMALL_SCENERY_FLAG4)){ - rotation = scenario_rand() & 0xFF; + rotation = util_rand() & 0xFF; } - rotation -= RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + rotation -= get_current_rotation(); rotation &= 0x3; // Also places it in lower but think thats for clobering @@ -1067,7 +1132,7 @@ void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sin // If CTRL not pressed if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_CTRL_PRESSED, uint8) == 0){ - uint16 flags = + uint16 flags = VIEWPORT_INTERACTION_MASK_TERRAIN & VIEWPORT_INTERACTION_MASK_WATER; int interaction_type = 0; @@ -1108,7 +1173,7 @@ void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sin } else{ sint16 z = RCT2_GLOBAL(RCT2_ADDRESS_CTRL_PRESS_Z_COORDINATE, sint16); - sub_6894D4(x, y, z, grid_x, grid_y); + screen_get_map_xy_with_z(x, y, z, grid_x, grid_y); // If SHIFT pressed if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ @@ -1130,10 +1195,10 @@ void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sin uint8 rotation = window_scenery_rotation; if (!(scenery->small_scenery.flags & SMALL_SCENERY_FLAG4)){ - rotation = scenario_rand() & 0xFF; + rotation = util_rand() & 0xFF; } - rotation -= RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + rotation -= get_current_rotation(); rotation &= 0x3; // Also places it in lower but think thats for clobering @@ -1146,7 +1211,7 @@ void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sin { // Path bits - uint16 flags = + uint16 flags = VIEWPORT_INTERACTION_MASK_FOOTPATH & VIEWPORT_INTERACTION_MASK_FOOTPATH_ITEM; int interaction_type = 0; @@ -1174,7 +1239,7 @@ void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sin 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); + screen_get_map_xy_side(x, y, grid_x, grid_y, &cl); if (*grid_x == (sint16)0x8000) return; @@ -1202,7 +1267,7 @@ void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sin } else{ sint16 z = RCT2_GLOBAL(RCT2_ADDRESS_CTRL_PRESS_Z_COORDINATE, sint16); - sub_6896DC(x, y, z, grid_x, grid_y, &cl); + screen_get_map_xy_side_with_z(x, y, z, grid_x, grid_y, &cl); // If SHIFT pressed if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ @@ -1261,7 +1326,7 @@ void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sin } else{ sint16 z = RCT2_GLOBAL(RCT2_ADDRESS_CTRL_PRESS_Z_COORDINATE, sint16); - sub_6894D4(x, y, z, grid_x, grid_y); + screen_get_map_xy_with_z(x, y, z, grid_x, grid_y); // If SHIFT pressed if (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0){ @@ -1282,7 +1347,7 @@ void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sin *grid_y &= 0xFFE0; uint8 rotation = window_scenery_rotation; - rotation -= RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + rotation -= get_current_rotation(); rotation &= 0x3; *parameter_1 = (rotation << 8); @@ -1309,9 +1374,9 @@ void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sin } uint8 rotation = window_scenery_rotation; - rotation -= RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + rotation -= get_current_rotation(); rotation &= 0x3; - + sint16 z = map_element->base_height; if (map_element->properties.path.type & (1 << 2)){ @@ -1332,222 +1397,226 @@ void sub_6E1F34(sint16 x, sint16 y, uint16 selected_scenery, sint16* grid_x, sin } /** - * rct2: 0x6e2cc6 + * + * rct2: 0x006E2CC6 */ -static void window_top_toolbar_scenery_tool_down(short x, short y, rct_window* w, short widgetIndex){ +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){ + 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; + int selectedTab = window_scenery_selected_scenery_by_tab[window_scenery_active_tab_index]; + uint8 sceneryType = (selectedTab & 0xFF00) >> 8; + uint8 selectedScenery = selectedTab & 0xFF; - if (selected_tab == -1) return; + if (selectedTab == -1) return; - sint16 grid_x, grid_y; - int ebp = selected_tab; + sint16 gridX, gridY; + int ebp = selectedTab; uint32 parameter_1, parameter_2, parameter_3; - sub_6E1F34(x, y, selected_tab, &grid_x, &grid_y, ¶meter_1, ¶meter_2, ¶meter_3); + sub_6E1F34(x, y, selectedTab, &gridX, &gridY, ¶meter_1, ¶meter_2, ¶meter_3); - if (grid_x == (sint16)0x8000)return; - - switch (scenery_type){ - case 0: + if (gridX == (sint16)0x8000) return; + + switch (sceneryType){ + case SCENERY_TYPE_SMALL: { - int cluster_size = 1; - if (window_scenery_is_build_cluster_tool_on){ - cluster_size = 35; + int quantity = 1; + if (window_scenery_is_build_cluster_tool_on) { + quantity = 35; } - for (; cluster_size > 0; cluster_size--){ - - int cluster_z_coordinate = RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16); + int successfulPlacements = 0; + for (int q = 0; q < quantity; q++) { + int zCoordinate = 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; + sint16 cur_grid_x = gridX; + sint16 cur_grid_y = gridY; 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; + parameter_2 |= util_rand() & 3; } - cur_grid_x += ((scenario_rand() % 16) - 8) * 32; - cur_grid_y += ((scenario_rand() % 16) - 8) * 32; + cur_grid_x += ((util_rand() % 16) - 8) * 32; + cur_grid_y += ((util_rand() % 16) - 8) * 32; if (!(scenery->small_scenery.flags & SMALL_SCENERY_FLAG4)){ - RCT2_GLOBAL(0x00F64EC0, uint16)++; - RCT2_GLOBAL(0x00F64EC0, uint16) &= 3; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_ROTATION, uint16)++; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_ROTATION, 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 zAttemptRange = 1; + if ( + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) != 0 && + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0 + ) { + zAttemptRange = 20; } - uint8 success = 0; - for (; bl != 0; bl--){ + bool success = false; + for (; zAttemptRange != 0; zAttemptRange--){ + int flags = GAME_COMMAND_FLAG_APPLY | (parameter_1 & 0xFF00); + 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(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_POSITION_THIS_HERE; + int cost = game_do_command( + cur_grid_x, + flags, + cur_grid_y, + parameter_2, + GAME_COMMAND_PLACE_SCENERY, + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_ROTATION, 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; + audio_play_sound_at_location(SOUND_PLACE_ITEM, RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16)); + success = true; break; } - if (RCT2_GLOBAL(0x00141E9AC, rct_string_id) == 827 || - RCT2_GLOBAL(0x00141E9AC, rct_string_id) == 1032){ + if ( + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) == STR_NOT_ENOUGH_CASH_REQUIRES || + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) == STR_CAN_ONLY_BUILD_THIS_ON_WATER + ) { 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; + if (success) { + successfulPlacements++; + } else { + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) == STR_NOT_ENOUGH_CASH_REQUIRES) { + break; + } } + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = zCoordinate; + } - RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) = cluster_z_coordinate; + if (successfulPlacements > 0) { + window_close_by_class(WC_ERROR); + } else { + audio_play_sound_at_location(SOUND_ERROR, RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16)); } break; } - case 1: + case SCENERY_TYPE_PATH_ITEM: { - // Path Bits - int ebx = parameter_1; - ebx &= 0xFF00; - ebx |= 0x81; + int flags = GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_7 | (parameter_1 & 0xFF00); - 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; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_POSITION_THIS_HERE; + int cost = game_do_command(gridX, flags, gridY, parameter_2, GAME_COMMAND_PLACE_PATH, parameter_3, 0); + if (cost != MONEY32_UNDEFINED) { + audio_play_sound_at_location(SOUND_PLACE_ITEM, RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16)); } - - sound_play_panned(SOUND_PLACE_ITEM, 0x8001, RCT2_GLOBAL(0x009DEA5E, uint16), RCT2_GLOBAL(0x009DEA60, uint16), RCT2_GLOBAL(0x009DEA62, uint16)); break; } - case 2: + case SCENERY_TYPE_WALL: { - // 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; + uint8 zAttemptRange = 1; + if ( + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) != 0 && + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0 + ) { + zAttemptRange = 20; } - for (; bl != 0; bl--){ + for (; zAttemptRange != 0; zAttemptRange--) { + int flags = (parameter_1 & 0xFF00) | GAME_COMMAND_FLAG_APPLY; + 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(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_BUILD_PARK_ENTRANCE_HERE; + int cost = game_do_command(gridX, flags, gridY, parameter_2, GAME_COMMAND_PLACE_FENCE, 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)); + audio_play_sound_at_location(SOUND_PLACE_ITEM, RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16)); return; } - if (RCT2_GLOBAL(0x00141E9AC, rct_string_id) == 827 || - RCT2_GLOBAL(0x00141E9AC, rct_string_id) == 1032){ + if ( + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) == STR_NOT_ENOUGH_CASH_REQUIRES || + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) == STR_CAN_ONLY_BUILD_THIS_ON_WATER + ) { 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)); + audio_play_sound_at_location(SOUND_ERROR, RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16)); break; } - case 3: + case SCENERY_TYPE_LARGE: { - // 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; + uint8 zAttemptRange = 1; + if ( + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) != 0 && + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TOOL_SHIFT_PRESSED, uint8) != 0 + ) { + zAttemptRange = 20; } - for (; bl != 0; bl--){ + for (; zAttemptRange != 0; zAttemptRange--) { + int flags = (parameter_1 & 0xFF00) | GAME_COMMAND_FLAG_APPLY; + 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(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_POSITION_THIS_HERE; + int cost = game_do_command(gridX, flags, gridY, 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)); + audio_play_sound_at_location(SOUND_PLACE_ITEM, RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16)); return; } - if (RCT2_GLOBAL(0x00141E9AC, rct_string_id) == 827 || - RCT2_GLOBAL(0x00141E9AC, rct_string_id) == 1032){ + if ( + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) == STR_NOT_ENOUGH_CASH_REQUIRES || + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) == STR_CAN_ONLY_BUILD_THIS_ON_WATER + ) { 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)); - } + audio_play_sound_at_location(SOUND_ERROR, RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16)); break; - case 4: + } + case SCENERY_TYPE_BANNER: { - // Banners - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1161; + int flags = (parameter_1 & 0xFF00) | GAME_COMMAND_FLAG_APPLY; - // The return value will be banner id but the input is colour (param 3) - int banner_id = parameter_3; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_POSITION_THIS_HERE; + registers regs = { + .eax = gridX, + .ebx = flags, + .ecx = gridY, + .edx = parameter_2, + .esi = GAME_COMMAND_PLACE_BANNER, + .edi = parameter_3 + }; + money32 cost = game_do_command_p(GAME_COMMAND_PLACE_BANNER, ®s.eax, ®s.ebx, ®s.ecx, ®s.edx, ®s.esi, ®s.edi, ®s.ebp); + if (cost != MONEY32_UNDEFINED) { + int bannerId = regs.edi; - 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); + audio_play_sound_at_location(SOUND_PLACE_ITEM, RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16), RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16)); + window_banner_open(bannerId); } - - 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; } } @@ -1562,7 +1631,7 @@ void top_toolbar_tool_update_scenery_clear(sint16 x, sint16 y){ RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); rct_xy16 mapTile = { 0 }; - sub_688972(x, y, &mapTile.x, &mapTile.y, NULL); + screen_get_map_xy(x, y, &mapTile.x, &mapTile.y, NULL); if (mapTile.x == (sint16)0x8000){ if (RCT2_GLOBAL(0x00F1AD62, money32) != MONEY32_UNDEFINED){ @@ -1623,13 +1692,11 @@ void top_toolbar_tool_update_scenery_clear(sint16 x, sint16 y){ 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 - ); + int eax = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16); + int ecx = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16); + int edi = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16); + int ebp = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16); + money32 cost = game_do_command(eax, 0, ecx, 0, GAME_COMMAND_CLEAR_SCENERY, edi, ebp); if (RCT2_GLOBAL(0x00F1AD62, money32) != cost){ RCT2_GLOBAL(0x00F1AD62, money32) = cost; @@ -1643,7 +1710,7 @@ void top_toolbar_tool_update_land_paint(sint16 x, sint16 y){ RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); rct_xy16 mapTile = { 0 }; - sub_688972(x, y, &mapTile.x, &mapTile.y, NULL); + screen_get_map_xy(x, y, &mapTile.x, &mapTile.y, NULL); if (mapTile.x == (sint16)0x8000){ if (RCT2_GLOBAL(0x00F1AD62, money32) != MONEY32_UNDEFINED){ @@ -1719,7 +1786,7 @@ void top_toolbar_tool_update_land(sint16 x, sint16 y){ 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 || + 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; @@ -1732,7 +1799,7 @@ void top_toolbar_tool_update_land(sint16 x, sint16 y){ rct_xy16 mapTile = { .x = x, .y = y }; RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0); - if (tool_size == 1){ + if (tool_size == 1 && !gLandMountainMode){ int direction; screen_pos_to_map_pos(&mapTile.x, &mapTile.y, &direction); @@ -1798,7 +1865,7 @@ void top_toolbar_tool_update_land(sint16 x, sint16 y){ return; } - sub_688972(x, y, &mapTile.x, &mapTile.y, NULL); + screen_get_map_xy(x, y, &mapTile.x, &mapTile.y, NULL); if (mapTile.x == (sint16)0x8000){ money32 lower_cost = MONEY32_UNDEFINED; @@ -1825,7 +1892,7 @@ void top_toolbar_tool_update_land(sint16 x, sint16 y){ state_changed++; } - + if (tool_size == 0) tool_size = 1; @@ -1914,11 +1981,11 @@ void top_toolbar_tool_update_water(sint16 x, sint16 y){ 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, + x, + y, + VIEWPORT_INTERACTION_MASK_TERRAIN & VIEWPORT_INTERACTION_MASK_WATER, + &mapTile.x, + &mapTile.y, &interaction_type, NULL, NULL); @@ -1943,8 +2010,8 @@ void top_toolbar_tool_update_water(sint16 x, sint16 y){ state_changed++; } - if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) != 4){ - RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; + if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) != 5){ + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 5; state_changed++; } @@ -2009,7 +2076,7 @@ void top_toolbar_tool_update_water(sint16 x, sint16 y){ } } -/* rct2: 0x006E24F6 +/* rct2: 0x006E24F6 * On failure returns MONEY32_UNDEFINED * On success places ghost scenery and returns cost to place proper */ @@ -2026,40 +2093,48 @@ money32 try_place_ghost_scenery(rct_xy16 map_tile, uint32 parameter_1, uint32 pa // Small Scenery //6e252b cost = game_do_command( - map_tile.x, + map_tile.x, parameter_1 | 0x69, - map_tile.y, - parameter_2, - GAME_COMMAND_PLACE_SCENERY, - parameter_3, - RCT2_GLOBAL(0x00F64ED4, sint16)); + map_tile.y, + parameter_2, + GAME_COMMAND_PLACE_SCENERY, + parameter_3, + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, 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; + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_X, sint16) = map_tile.x; + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Y, sint16) = map_tile.y; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_ROTATION, uint16) = (uint16)(parameter_3 & 0xFFFF); + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_SELECTED_OBJECT, sint16) = selected_tab; + + mapElement = RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_MAP_ELEMENT, rct_map_element*); + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Z, uint8) = mapElement->base_height; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_MAP_ELEMENT_TYPE, uint8) = mapElement->type; if (RCT2_GLOBAL(0x00F64F14, uint8) & (1 << 1)){ + //Set underground on viewport_set_visibility(4); } else{ + //Set underground off viewport_set_visibility(5); } - RCT2_GLOBAL(0x00F64F0D, uint8) |= (1 << 0); + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) |= (1 << 0); break; case 1: // Path Bits //6e265b cost = game_do_command( map_tile.x, - parameter_1 | 0xE9, + (parameter_1 & 0xFF00) | ( + GAME_COMMAND_FLAG_APPLY | + GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | + GAME_COMMAND_FLAG_5 | + GAME_COMMAND_FLAG_GHOST | + GAME_COMMAND_FLAG_7 + ), map_tile.y, parameter_2, GAME_COMMAND_PLACE_PATH, @@ -2069,14 +2144,14 @@ money32 try_place_ghost_scenery(rct_xy16 map_tile, uint32 parameter_1, uint32 pa 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(RCT2_ADDRESS_GHOST_SCENERY_X, sint16) = map_tile.x; + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Y, sint16) = map_tile.y; + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Z, uint8) = (parameter_2 & 0xFF); + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TARGET_PATH_INCLINE, uint8) = ((parameter_1 >> 8) & 0xFF); + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TARGET_PATH_TYPE, uint8) = ((parameter_2 >> 8) & 0xFF); + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_PATH_OBJECT_TYPE, uint32) = parameter_3; - RCT2_GLOBAL(0x00F64F0D, uint8) |= (1 << 1); + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) |= (1 << 1); break; case 2: // Walls @@ -2086,21 +2161,21 @@ money32 try_place_ghost_scenery(rct_xy16 map_tile, uint32 parameter_1, uint32 pa parameter_1 | 0x69, map_tile.y, parameter_2, - GAME_COMMAND_41, - RCT2_GLOBAL(0x00F64ED4, uint16), + GAME_COMMAND_PLACE_FENCE, + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, 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(RCT2_ADDRESS_GHOST_SCENERY_X, sint16) = map_tile.x; + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Y, sint16) = map_tile.y; + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_WALL_ROTATION, uint8) = (parameter_2 & 0xFF); - RCT2_GLOBAL(0x00F64F0D, uint8) |= (1 << 2); + mapElement = RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_MAP_ELEMENT, rct_map_element*); + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Z, uint8) = mapElement->base_height; + + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) |= (1 << 2); break; case 3: // Large Scenery @@ -2112,26 +2187,28 @@ money32 try_place_ghost_scenery(rct_xy16 map_tile, uint32 parameter_1, uint32 pa parameter_2, GAME_COMMAND_PLACE_LARGE_SCENERY, parameter_3, - RCT2_GLOBAL(0x00F64ED4, uint16)); + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, 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); + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_X, sint16) = map_tile.x; + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Y, sint16) = map_tile.y; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_ROTATION, uint8) = ((parameter_1 >> 8) & 0xFF); - mapElement = RCT2_GLOBAL(0x00F64EBC, rct_map_element*); - RCT2_GLOBAL(0x00F64F09, uint8) = mapElement->base_height; + mapElement = RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_MAP_ELEMENT, rct_map_element*); + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Z, uint8) = mapElement->base_height; if (RCT2_GLOBAL(0x00F64F14, uint8) & (1 << 1)){ + //Set underground on viewport_set_visibility(4); } else{ + //Set underground off viewport_set_visibility(5); } - RCT2_GLOBAL(0x00F64F0D, uint8) |= (1 << 3); + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) |= (1 << 3); break; case 4: // Banners @@ -2148,11 +2225,11 @@ money32 try_place_ghost_scenery(rct_xy16 map_tile, uint32 parameter_1, uint32 pa 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); + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_X, sint16) = map_tile.x; + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Y, sint16) = map_tile.y; + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Z, uint8) = (parameter_2 & 0xFF) * 2 + 2; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_ROTATION, uint8) = ((parameter_2 >> 8) & 0xFF); + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) |= (1 << 4); break; } @@ -2190,7 +2267,7 @@ void top_toolbar_tool_update_scenery(sint16 x, sint16 y){ scenery_remove_ghost_tool_placement(); return; } - + rct_scenery_entry* scenery; uint8 bl; money32 cost; @@ -2213,13 +2290,13 @@ void top_toolbar_tool_update_scenery(sint16 x, sint16 y){ 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) && + if ((RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) & (1 << 0)) && + mapTile.x == RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_X, sint16) && + mapTile.y == RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Y, 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; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_SELECTED_OBJECT, uint16) == selected_tab){ + return; } scenery_remove_ghost_tool_placement(); @@ -2246,7 +2323,7 @@ void top_toolbar_tool_update_scenery(sint16 x, sint16 y){ RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) += 8; } - RCT2_GLOBAL(0x00F64EB4, money32) = cost; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_COST, money32) = cost; break; case 1: RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); @@ -2259,10 +2336,10 @@ void top_toolbar_tool_update_scenery(sint16 x, sint16 y){ 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)){ + if ((RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) & (1 << 1)) && + mapTile.x == RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_X, sint16) && + mapTile.y == RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Y, sint16) && + (parameter2 & 0xFF) == RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Z, uint8)){ return; } @@ -2275,7 +2352,7 @@ void top_toolbar_tool_update_scenery(sint16 x, sint16 y){ parameter3, selected_tab); - RCT2_GLOBAL(0x00F64EB4, money32) = cost; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_COST, money32) = cost; break; case 2: RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); @@ -2288,10 +2365,10 @@ void top_toolbar_tool_update_scenery(sint16 x, sint16 y){ 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) && + if ((RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) & (1 << 2)) && + mapTile.x == RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_X, sint16) && + mapTile.y == RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Y, sint16) && + (parameter2 & 0xFF) == RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_WALL_ROTATION, uint8) && RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) == RCT2_GLOBAL(0x00F64F0A, sint16) ){ return; @@ -2299,7 +2376,7 @@ void top_toolbar_tool_update_scenery(sint16 x, sint16 y){ scenery_remove_ghost_tool_placement(); - RCT2_GLOBAL(0x00F64F11, uint8) = (parameter2 & 0xFF); + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_WALL_ROTATION, uint8) = (parameter2 & 0xFF); RCT2_GLOBAL(0x00F64F0A, sint16) = RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16); bl = 1; @@ -2322,16 +2399,16 @@ void top_toolbar_tool_update_scenery(sint16 x, sint16 y){ RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) += 8; } - RCT2_GLOBAL(0x00F64EB4, money32) = cost; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_COST, 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 + rct_xy16 tileLocation = { + .x = tile->x_offset, + .y = tile->y_offset }; rotate_map_coordinates(&tileLocation.x, &tileLocation.y, (parameter1 >> 8) & 0xFF); @@ -2349,17 +2426,17 @@ void top_toolbar_tool_update_scenery(sint16 x, sint16 y){ 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) && + if ((RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) & (1 << 3)) && + mapTile.x == RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_X, sint16) && + mapTile.y == RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Y, sint16) && RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) == RCT2_GLOBAL(0x00F64F0A, sint16) && - (parameter3 & 0xFFFF) == RCT2_GLOBAL(0x00F64EDA, uint16)){ + (parameter3 & 0xFFFF) == RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_SELECTED_OBJECT, uint16)){ return; } scenery_remove_ghost_tool_placement(); - RCT2_GLOBAL(0x00F64EDA, uint16) = (parameter3 & 0xFFFF); + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_SELECTED_OBJECT, uint16) = (parameter3 & 0xFFFF); RCT2_GLOBAL(0x00F64F0A, sint16) = RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16); bl = 1; @@ -2382,7 +2459,7 @@ void top_toolbar_tool_update_scenery(sint16 x, sint16 y){ RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_Z_COORDINATE, sint16) += 8; } - RCT2_GLOBAL(0x00F64EB4, money32) = cost; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_COST, money32) = cost; break; case 4: RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= (1 << 0); @@ -2395,11 +2472,11 @@ void top_toolbar_tool_update_scenery(sint16 x, sint16 y){ 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)){ + if ((RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) & (1 << 4)) && + mapTile.x == RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_X, sint16) && + mapTile.y == RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Y, sint16) && + (parameter2 & 0xFF) == RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Z, uint8) && + ((parameter2 >> 8) & 0xFF) == RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_ROTATION, uint8)){ return; } @@ -2412,7 +2489,7 @@ void top_toolbar_tool_update_scenery(sint16 x, sint16 y){ parameter3, selected_tab); - RCT2_GLOBAL(0x00F64EB4, money32) = cost; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_COST, money32) = cost; break; } } @@ -2421,20 +2498,14 @@ void top_toolbar_tool_update_scenery(sint16 x, sint16 y){ * * rct2: 0x0066CB25 */ -static void window_top_toolbar_tool_update() +static void window_top_toolbar_tool_update(rct_window* w, int widgetIndex, int x, int y) { - short widgetIndex; - rct_window *w; - short x, y; - - window_tool_get_registers(w, widgetIndex, x, y); - - switch (widgetIndex){ + switch (widgetIndex) { case WIDX_CLEAR_SCENERY: top_toolbar_tool_update_scenery_clear(x, y); break; case WIDX_LAND: - if (LandPaintMode) + if (gLandPaintMode) top_toolbar_tool_update_land_paint(x, y); else top_toolbar_tool_update_land(x, y); @@ -2451,25 +2522,20 @@ static void window_top_toolbar_tool_update() /** * 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); - +static void window_top_toolbar_tool_down(rct_window* w, int widgetIndex, int x, int 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; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_UNABLE_TO_REMOVE_ALL_SCENERY_FROM_HERE; game_do_command( RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), 1, RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), - 0, + (gClearSmallScenery | gClearLargeScenery << 1 | gClearFootpath << 2), GAME_COMMAND_CLEAR_SCENERY, RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) @@ -2478,7 +2544,7 @@ static void window_top_toolbar_tool_down(){ 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; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_CHANGE_LAND_TYPE; game_do_command( RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), 1, @@ -2503,7 +2569,7 @@ static void window_top_toolbar_tool_down(){ } /** -* +* * rct2: 0x006644DD */ money32 selection_raise_land(uint8 flags) @@ -2516,8 +2582,8 @@ money32 selection_raise_land(uint8 flags) 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) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_RAISE_LAND_HERE; + if (gLandMountainMode) { 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); @@ -2538,8 +2604,8 @@ money32 selection_lower_land(uint8 flags) 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) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_LOWER_LAND_HERE; + if (gLandMountainMode) { 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); @@ -2618,7 +2684,7 @@ void window_top_toolbar_water_tool_drag(short x, short y) 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; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_RAISE_WATER_LEVEL_HERE; game_do_command( RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), @@ -2640,7 +2706,7 @@ void window_top_toolbar_water_tool_drag(short x, short y) 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; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_LOWER_WATER_LEVEL_HERE; game_do_command( RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), @@ -2662,14 +2728,8 @@ void window_top_toolbar_water_tool_drag(short x, short y) * * rct2: 0x0066CB4E */ -static void window_top_toolbar_tool_drag() +static void window_top_toolbar_tool_drag(rct_window* w, int widgetIndex, int x, int y) { - 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) @@ -2678,13 +2738,13 @@ static void window_top_toolbar_tool_drag() 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; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_UNABLE_TO_REMOVE_ALL_SCENERY_FROM_HERE; game_do_command( RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), 1, RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16), - 0, + (gClearSmallScenery | gClearLargeScenery << 1 | gClearFootpath << 2), GAME_COMMAND_CLEAR_SCENERY, RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16), RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) @@ -2693,9 +2753,9 @@ static void window_top_toolbar_tool_drag() break; case WIDX_LAND: // Custom setting to only change land style instead of raising or lowering land - if (LandPaintMode) { + if (gLandPaintMode) { if (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16)&(1 << 0)){ - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, rct_string_id) = 1387; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_CHANGE_LAND_TYPE; game_do_command( RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16), 1, @@ -2722,6 +2782,45 @@ static void window_top_toolbar_tool_drag() } } +/** + * + * rct2: 0x0066CC5B + */ +static void window_top_toolbar_tool_up(rct_window* w, int widgetIndex, int x, int y) +{ + switch (widgetIndex) { + case WIDX_LAND: + map_invalidate_selection_rect(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= 0xFFFE; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = 0x12; + break; + case WIDX_WATER: + map_invalidate_selection_rect(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= 0xFFFE; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = 0x13; + break; + case WIDX_CLEAR_SCENERY: + map_invalidate_selection_rect(); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= 0xFFFE; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = 0x0C; + break; + } +} + +/** + * + * rct2: 0x0066CA58 + */ +static void window_top_toolbar_tool_abort(rct_window *w, int widgetIndex) +{ + switch (widgetIndex) { + case WIDX_LAND: + case WIDX_WATER: + case WIDX_CLEAR_SCENERY: + hide_gridlines(); + break; + } +} void top_toolbar_init_fastforward_menu(rct_window* w, rct_widget* widget) { int num_items = 4; @@ -2740,7 +2839,7 @@ void top_toolbar_init_fastforward_menu(rct_window* w, rct_widget* widget) { gDropdownItemsArgs[1] = 5143; gDropdownItemsArgs[2] = 5144; gDropdownItemsArgs[3] = 5145; - + window_dropdown_show_text( w->x + widget->left, @@ -2752,10 +2851,12 @@ void top_toolbar_init_fastforward_menu(rct_window* w, rct_widget* widget) { ); // Set checkmarks - if (gGameSpeed <= 4) - gDropdownItemsChecked |= (1 << (gGameSpeed - 1)); - if (gGameSpeed == 8) - gDropdownItemsChecked |= (1 << 5); + if (gGameSpeed <= 4) { + dropdown_set_checked(gGameSpeed - 1, true); + } + if (gGameSpeed == 8) { + dropdown_set_checked(5, true); + } if (gConfigGeneral.debugging_tools) RCT2_GLOBAL(0x9DEBA2, uint16) = (gGameSpeed == 8 ? 0 : gGameSpeed); @@ -2776,9 +2877,9 @@ void top_toolbar_fastforward_menu_dropdown(short dropdownIndex) { } } -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; +void top_toolbar_init_rotate_menu(rct_window* w, rct_widget* widget) { + gDropdownItemsFormat[0] = STR_ROTATE_CLOCKWISE; + gDropdownItemsFormat[1] = STR_ROTATE_ANTI_CLOCKWISE; window_dropdown_show_text( w->x + widget->left, @@ -2787,6 +2888,55 @@ void top_toolbar_init_debug_menu(rct_window* w, rct_widget* widget) { w->colours[1] | 0x80, 0, 2 + ); + + RCT2_GLOBAL(0x9DEBA2, uint16) = 0; +} + +void top_toolbar_rotate_menu_dropdown(short dropdownIndex) { + if (dropdownIndex == -1) dropdownIndex = RCT2_GLOBAL(0x9DEBA2, uint16); + rct_window* w = window_get_main(); + if (w) { + if (dropdownIndex == 0) { + window_rotate_camera(w, 1); + window_invalidate(w); + } + else if (dropdownIndex == 1){ + window_rotate_camera(w, -1); + 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; + gDropdownItemsFormat[2] = STR_DEBUG_DROPDOWN_OBJECT_SELECTION; + gDropdownItemsFormat[3] = STR_DEBUG_DROPDOWN_INVENTIONS_LIST; + gDropdownItemsFormat[4] = STR_DEBUG_DROPDOWN_SCENARIO_OPTIONS; + + window_dropdown_show_text( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[0] | 0x80, + 0, + 5 + ); + + RCT2_GLOBAL(0x9DEBA2, uint16) = 0; +} + +void top_toolbar_init_network_menu(rct_window* w, rct_widget* widget) { + gDropdownItemsFormat[0] = STR_PLAYER_LIST; + + window_dropdown_show_text( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[0] | 0x80, + 0, + 1 ); RCT2_GLOBAL(0x9DEBA2, uint16) = 0; @@ -2803,6 +2953,28 @@ void top_toolbar_debug_menu_dropdown(short dropdownIndex) { case DDIDX_TILE_INSPECTOR: window_tile_inspector_open(); break; + case DDIDX_OBJECT_SELECTION: + window_close_all(); + window_editor_object_selection_open(); + break; + case DDIDX_INVENTIONS_LIST: + window_editor_inventions_list_open(); + break; + case DDIDX_SCENARIO_OPTIONS: + window_editor_scenario_options_open(); + break; + } + } +} + +void top_toolbar_network_menu_dropdown(short dropdownIndex) { + if (dropdownIndex == -1) dropdownIndex = RCT2_GLOBAL(0x9DEBA2, uint16); + rct_window* w = window_get_main(); + if (w) { + switch (dropdownIndex) { + case DDIDX_PLAYER_LIST: + window_player_list_open(); + break; } } } @@ -2848,25 +3020,25 @@ void top_toolbar_init_view_menu(rct_window* w, rct_widget* widget) { // Set checkmarks rct_viewport* mainViewport = window_get_main()->viewport; if (mainViewport->flags & VIEWPORT_FLAG_UNDERGROUND_INSIDE) - gDropdownItemsChecked |= (1 << 0); + dropdown_set_checked(0, true); if (mainViewport->flags & VIEWPORT_FLAG_HIDE_BASE) - gDropdownItemsChecked |= (1 << 1); + dropdown_set_checked(1, true); if (mainViewport->flags & VIEWPORT_FLAG_HIDE_VERTICAL) - gDropdownItemsChecked |= (1 << 2); + dropdown_set_checked(2, true); if (mainViewport->flags & VIEWPORT_FLAG_SEETHROUGH_RIDES) - gDropdownItemsChecked |= (1 << 4); + dropdown_set_checked(4, true); if (mainViewport->flags & VIEWPORT_FLAG_SEETHROUGH_SCENERY) - gDropdownItemsChecked |= (1 << 5); + dropdown_set_checked(5, true); if (mainViewport->flags & VIEWPORT_FLAG_INVISIBLE_SUPPORTS) - gDropdownItemsChecked |= (1 << 6); + dropdown_set_checked(6, true); if (mainViewport->flags & VIEWPORT_FLAG_INVISIBLE_PEEPS) - gDropdownItemsChecked |= (1 << 7); + dropdown_set_checked(7, true); if (mainViewport->flags & VIEWPORT_FLAG_LAND_HEIGHTS) - gDropdownItemsChecked |= (1 << 9); + dropdown_set_checked(9, true); if (mainViewport->flags & VIEWPORT_FLAG_TRACK_HEIGHTS) - gDropdownItemsChecked |= (1 << 10); + dropdown_set_checked(10, true); if (mainViewport->flags & VIEWPORT_FLAG_PATH_HEIGHTS) - gDropdownItemsChecked |= (1 << 11); + dropdown_set_checked(11, true); RCT2_GLOBAL(0x9DEBA2, uint16) = 0; } @@ -2981,3 +3153,18 @@ void toggle_water_window(rct_window *topToolbar, int widgetIndex) window_water_open(); } } + +/** + * + * rct2: 0x0066D104 + */ +bool land_tool_is_active() +{ + if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) + return false; + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_TOP_TOOLBAR) + return false; + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, sint16) != WIDX_LAND) + return false; + return true; +} diff --git a/src/windows/track_list.c b/src/windows/track_list.c index 416d6db0e1..fedc79a3e7 100644 --- a/src/windows/track_list.c +++ b/src/windows/track_list.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 . *****************************************************************************/ @@ -29,6 +29,8 @@ #include "../sprites.h" #include "error.h" #include "../interface/themes.h" +#include "../rct1.h" +#include "../network/network.h" enum { WIDX_BACKGROUND, @@ -37,60 +39,61 @@ enum { WIDX_TRACK_LIST, WIDX_TRACK_PREVIEW, WIDX_ROTATE, - WIDX_TOGGLE_SCENERY + WIDX_TOGGLE_SCENERY, + WIDX_BACK, }; static rct_widget window_track_list_widgets[] = { { WWT_FRAME, 0, 0, 599, 0, 399, 0xFFFFFFFF, STR_NONE }, { WWT_CAPTION, 0, 1, 598, 1, 14, STR_SELECT_DESIGN, STR_WINDOW_TITLE_TIP }, { WWT_CLOSEBOX, 0, 587, 597, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, - { WWT_SCROLL, 0, 4, 221, 18, 395, 2, STR_CLICK_ON_DESIGN_TO_BUILD_IT_TIP }, + { WWT_SCROLL, 0, 4, 221, 33, 395, 2, STR_CLICK_ON_DESIGN_TO_BUILD_IT_TIP }, { WWT_FLATBTN, 0, 224, 595, 18, 236, 0xFFFFFFFF, STR_NONE }, { WWT_FLATBTN, 0, 574, 597, 374, 397, 5169, STR_ROTATE_90_TIP }, { WWT_FLATBTN, 0, 574, 597, 350, 373, 5171, STR_TOGGLE_SCENERY_TIP }, + { WWT_13, 0, 4, 221, 18, 29, STR_SELECT_OTHER_RIDE, STR_NONE }, { WIDGETS_END }, }; -static void window_track_list_emptysub() { } -static void window_track_list_close(); -static void window_track_list_mouseup(); -static void window_track_list_scrollgetsize(); -static void window_track_list_scrollmousedown(); -static void window_track_list_scrollmouseover(); -static void window_track_list_tooltip(); -static void window_track_list_invalidate(); -static void window_track_list_paint(); -static void window_track_list_scrollpaint(); +static void window_track_list_close(rct_window *w); +static void window_track_list_mouseup(rct_window *w, int widgetIndex); +static void window_track_list_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height); +static void window_track_list_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); +static void window_track_list_scrollmouseover(rct_window *w, int scrollIndex, int x, int y); +static void window_track_list_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId); +static void window_track_list_invalidate(rct_window *w); +static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_track_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex); -static void* window_track_list_events[] = { - (uint32*)window_track_list_close, - (uint32*)window_track_list_mouseup, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_scrollgetsize, - (uint32*)window_track_list_scrollmousedown, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_scrollmouseover, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_tooltip, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_emptysub, - (uint32*)window_track_list_invalidate, - (uint32*)window_track_list_paint, - (uint32*)window_track_list_scrollpaint +static rct_window_event_list window_track_list_events = { + window_track_list_close, + window_track_list_mouseup, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + window_track_list_scrollgetsize, + window_track_list_scrollmousedown, + NULL, + window_track_list_scrollmouseover, + NULL, + NULL, + NULL, + window_track_list_tooltip, + NULL, + NULL, + window_track_list_invalidate, + window_track_list_paint, + window_track_list_scrollpaint }; ride_list_item _window_track_list_item; @@ -130,12 +133,12 @@ void window_track_list_open(ride_list_item item) y, 600, 400, - (uint32*)window_track_list_events, + &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); + w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_ROTATE) | (1 << WIDX_TOGGLE_SCENERY) | (1 << WIDX_BACK); window_init_scroll_widgets(w); w->track_list.var_480 = 0xFFFF; w->track_list.var_482 = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER ? 0 : 1; @@ -143,6 +146,13 @@ void window_track_list_open(ride_list_item item) RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) = 0; window_push_others_right(w); RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = 2; + +#ifndef NETWORK_DISABLE + // TODO: FIX NETWORK TRACKS + // Until tracks work with the network this will disable them + if (network_get_mode() != NETWORK_MODE_NONE) + RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, utf8)[0] = 0; +#endif } /** @@ -151,12 +161,12 @@ void window_track_list_open(ride_list_item item) */ static void window_track_list_select(rct_window *w, int index) { - uint8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); + utf8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, utf8); rct_track_design *trackDesign; w->track_list.var_480 = index; - sound_play_panned(SOUND_CLICK_1, w->x + (w->width / 2), 0, 0, 0); + audio_play_sound_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_track_list_item); @@ -170,7 +180,7 @@ static void window_track_list_select(rct_window *w, int index) index--; trackDesignItem = trackDesignList + (index * 128); - RCT2_GLOBAL(0x00F4403C, uint8*) = trackDesignItem; + RCT2_GLOBAL(0x00F4403C, utf8*) = trackDesignItem; window_track_list_format_name( (char*)0x009BC313, @@ -230,7 +240,7 @@ static int window_track_list_get_list_item_index_from_position(int x, int y) * * rct2: 0x006CFD76 */ -static void window_track_list_close() +static void window_track_list_close(rct_window *w) { free(RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, void*)); } @@ -239,13 +249,8 @@ static void window_track_list_close() * * rct2: 0x006CFA31 */ -static void window_track_list_mouseup() +static void window_track_list_mouseup(rct_window *w, int widgetIndex) { - rct_window *w; - short widgetIndex; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -265,6 +270,16 @@ static void window_track_list_mouseup() reset_track_list_cache(); window_invalidate(w); break; + case WIDX_BACK: + window_close(w); + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { + window_close_by_number(WC_MANAGE_TRACK_DESIGN, w->number); + window_close_by_number(WC_TRACK_DELETE_PROMPT, w->number); + trackmanager_load(); + } else { + window_new_ride_open(); + } + break; } } @@ -272,38 +287,25 @@ static void window_track_list_mouseup() * * rct2: 0x006CFAB0 */ -static void window_track_list_scrollgetsize() +static void window_track_list_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - rct_window *w; - int width, height; uint8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); - window_get_register(w); - - width = 0; - height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER ? 0 : 10; + *height = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER ? 0 : 10; for (trackDesignItem = trackDesignList; *trackDesignItem != 0; trackDesignItem += 128) - height += 10; - - window_scrollsize_set_registers(width, height); + *height += 10; } /** * * rct2: 0x006CFB39 */ -static void window_track_list_scrollmousedown() +static void window_track_list_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) { - rct_window *w; - short i, x, y, scrollIndex; - - window_scrollmouse_get_registers(w, scrollIndex, x, y); + int i; if (w->track_list.var_484 & 1) 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) @@ -314,17 +316,12 @@ static void window_track_list_scrollmousedown() * * rct2: 0x006CFAD7 */ -static void window_track_list_scrollmouseover() +static void window_track_list_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) { - rct_window *w; - short i, x, y, scrollIndex; - - window_scrollmouse_get_registers(w, scrollIndex, x, y); + int i; if (w->track_list.var_484 & 1) return; - 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 && w->track_list.var_482 != i) { @@ -337,31 +334,29 @@ static void window_track_list_scrollmouseover() * * rct2: 0x006CFD6C */ -static void window_track_list_tooltip() +static void window_track_list_tooltip(rct_window* w, int widgetIndex, rct_string_id *stringId) { - RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = STR_LIST; } /** * * rct2: 0x006CF2D6 */ -static void window_track_list_invalidate() +static void window_track_list_invalidate(rct_window *w) { - rct_window *w; rct_ride_type *entry; 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->flags & RIDE_ENTRY_FLAG_SEPERATE_RIDE_NAME)) + if (!(entry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) || rideTypeShouldLoseSeparateFlag(entry)) stringId = _window_track_list_item.type + 2; - RCT2_GLOBAL(0x013CE952, uint16) = stringId; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint16) = stringId; if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { window_track_list_widgets[WIDX_TITLE].image = STR_TRACK_DESIGNS; window_track_list_widgets[WIDX_TRACK_LIST].tooltip = STR_CLICK_ON_DESIGN_TO_RENAME_OR_DELETE_IT; @@ -391,20 +386,17 @@ static void window_track_list_invalidate() * * rct2: 0x006CF387 */ -static void window_track_list_paint() +static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_widget *widget; rct_track_design *trackDesign = NULL; - uint8 *image, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); + uint8 *image; + utf8 *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, utf8); uint16 holes, speed, drops, dropHeight, inversions; fixed32_2dp rating; int trackIndex, x, y, colour, gForces, airTime; rct_g1_element tmpElement, *subsituteElement; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); trackIndex = w->track_list.var_482; @@ -419,7 +411,7 @@ static void window_track_list_paint() widget = &window_track_list_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); + colour = ColourMapA[w->colours[0]].darkest; gfx_fill_rect(dpi, x, y, x + 369, y + 216, colour); trackDesign = track_get_info(trackIndex, &image); @@ -467,11 +459,6 @@ static void window_track_list_paint() x = w->x + widget->left + 1; y = w->y + widget->bottom + 2; - 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); @@ -536,7 +523,7 @@ static void window_track_list_paint() } } } - + if (ride_type_has_flag(track_td6->type, RIDE_TYPE_FLAG_HAS_DROPS)) { // Drops drops = track_td6->drops & 0x3F; @@ -577,17 +564,13 @@ static void window_track_list_paint() * * rct2: 0x006CF8CD */ -static void window_track_list_scrollpaint() +static void window_track_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_string_id stringId, stringId2; int i, x, y, colour; - uint8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); + utf8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, utf8); - window_paint_get_registers(w, dpi); - - colour = RCT2_GLOBAL(0x00141FC48 + (w->colours[0] * 8), uint8); + colour = ColourMapA[w->colours[0]].mid_light; colour = (colour << 24) | (colour << 16) | (colour << 8) | colour; gfx_clear(dpi, colour); diff --git a/src/windows/track_manage.c b/src/windows/track_manage.c index 9f9bea901f..4b1ac29344 100644 --- a/src/windows/track_manage.c +++ b/src/windows/track_manage.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 . *****************************************************************************/ @@ -61,82 +61,78 @@ static rct_widget window_track_delete_prompt_widgets[] = { #pragma region Events -static void window_track_manage_emptysub() { } +static void window_track_manage_close(rct_window *w); +static void window_track_manage_mouseup(rct_window *w, int widgetIndex); +static void window_track_manage_textinput(rct_window *w, int widgetIndex, char *text); +static void window_track_manage_invalidate(rct_window *w); +static void window_track_manage_paint(rct_window *w, rct_drawpixelinfo *dpi); -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(); +static void window_track_delete_prompt_mouseup(rct_window *w, int widgetIndex); +static void window_track_delete_prompt_invalidate(rct_window *w); +static void window_track_delete_prompt_paint(rct_window *w, rct_drawpixelinfo *dpi); // 0x009940EC -static void* window_track_manage_events[] = { +static rct_window_event_list 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_track_manage_textinput, - window_track_manage_emptysub, - window_track_manage_emptysub, - window_track_manage_emptysub, - window_track_manage_emptysub, - window_track_manage_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, window_track_manage_invalidate, window_track_manage_paint, - window_track_manage_emptysub + NULL }; // 0x0099415C -static void* window_track_delete_prompt_events[] = { - window_track_delete_prompt_emptysub, +static rct_window_event_list window_track_delete_prompt_events = { + NULL, 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, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_track_delete_prompt_invalidate, window_track_delete_prompt_paint, - window_track_delete_prompt_emptysub + NULL }; #pragma endregion @@ -156,7 +152,7 @@ void window_track_manage_open() w = window_create_centred( 250, 44, - (uint32*)window_track_manage_events, + &window_track_manage_events, WC_MANAGE_TRACK_DESIGN, WF_STICK_TO_FRONT | WF_TRANSPARENT ); @@ -176,28 +172,23 @@ void window_track_manage_open() * * rct2: 0x006D364C */ -static void window_track_manage_close() +static void window_track_manage_close(rct_window *w) { - rct_window *w; - - w = window_find_by_class(WC_TRACK_DESIGN_LIST); - if (w != NULL) - w->track_list.var_484 &= ~1; + rct_window *trackDesignListWindow = window_find_by_class(WC_TRACK_DESIGN_LIST); + if (trackDesignListWindow != NULL) + trackDesignListWindow->track_list.var_484 &= ~1; } /** * * rct2: 0x006D3523 */ -static void window_track_manage_mouseup() +static void window_track_manage_mouseup(rct_window *w, int widgetIndex) { uint8 *trackDesignList = (uint8*)0x00F441EC; - rct_window *w, *trackDesignListWindow; - short widgetIndex; + rct_window *trackDesignListWindow; char *dst, *src; - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -223,16 +214,9 @@ static void window_track_manage_mouseup() * * rct2: 0x006D3523 */ -static void window_track_manage_textinput() +static void window_track_manage_textinput(rct_window *w, int widgetIndex, char *text) { - rct_window *w; - short widgetIndex; - uint8 result; - char *text; - - window_textinput_get_registers(w, widgetIndex, result, text); - - if (widgetIndex != WIDX_RENAME || !result) + if (widgetIndex != WIDX_RENAME || text == NULL) return; if (track_rename(text)) { @@ -243,11 +227,8 @@ static void window_track_manage_textinput() } } -static void window_track_manage_invalidate() +static void window_track_manage_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); } @@ -255,13 +236,8 @@ static void window_track_manage_invalidate() * * rct2: 0x006D3523 */ -static void window_track_manage_paint() +static void window_track_manage_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); } @@ -280,7 +256,7 @@ static void window_track_delete_prompt_open() (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 44) / 2, 250, 74, - (uint32*)window_track_delete_prompt_events, + &window_track_delete_prompt_events, WC_TRACK_DELETE_PROMPT, WF_STICK_TO_FRONT ); @@ -297,13 +273,8 @@ static void window_track_delete_prompt_open() * * rct2: 0x006D3823 */ -static void window_track_delete_prompt_mouseup() +static void window_track_delete_prompt_mouseup(rct_window *w, int widgetIndex) { - rct_window *w; - short widgetIndex; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: case WIDX_PROMPT_CANCEL: @@ -319,11 +290,8 @@ static void window_track_delete_prompt_mouseup() } } -static void window_track_delete_prompt_invalidate() +static void window_track_delete_prompt_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); } @@ -331,14 +299,10 @@ static void window_track_delete_prompt_invalidate() * * rct2: 0x006D37EE */ -static void window_track_delete_prompt_paint() +static void window_track_delete_prompt_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; rct_string_id stringId; - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); stringId = 3155; diff --git a/src/windows/track_place.c b/src/windows/track_place.c index 7e8bcbf35f..e52fedbafb 100644 --- a/src/windows/track_place.c +++ b/src/windows/track_place.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 . *****************************************************************************/ @@ -56,46 +56,45 @@ static rct_widget window_track_place_widgets[] = { { WIDGETS_END }, }; -static void window_track_place_emptysub() { } -static void window_track_place_close(); -static void window_track_place_mouseup(); +static void window_track_place_close(rct_window *w); +static void window_track_place_mouseup(rct_window *w, int widgetIndex); static void window_track_place_update(rct_window *w); -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_toolupdate(rct_window* w, int widgetIndex, int x, int y); +static void window_track_place_tooldown(rct_window* w, int widgetIndex, int x, int y); +static void window_track_place_toolabort(rct_window *w, int widgetIndex); +static void window_track_place_unknown14(rct_window *w); +static void window_track_place_invalidate(rct_window *w); +static void window_track_place_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void* window_track_place_events[] = { +static rct_window_event_list window_track_place_events = { window_track_place_close, window_track_place_mouseup, - window_track_place_emptysub, - window_track_place_emptysub, - window_track_place_emptysub, - window_track_place_emptysub, + NULL, + NULL, + NULL, + NULL, window_track_place_update, - window_track_place_emptysub, - window_track_place_emptysub, + NULL, + NULL, window_track_place_toolupdate, window_track_place_tooldown, - window_track_place_emptysub, - window_track_place_emptysub, + NULL, + NULL, window_track_place_toolabort, - window_track_place_emptysub, - window_track_place_emptysub, - window_track_place_emptysub, - window_track_place_emptysub, - window_track_place_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_track_place_unknown14, - window_track_place_emptysub, - window_track_place_emptysub, - window_track_place_emptysub, - window_track_place_emptysub, - window_track_place_emptysub, + NULL, + NULL, + NULL, + NULL, window_track_place_invalidate, window_track_place_paint, - window_track_place_emptysub + NULL }; static uint8 *_window_track_place_mini_preview; @@ -130,7 +129,7 @@ static void window_track_place_draw_mini_preview() int i, rotation, pass, x, y, pixelX, pixelY, originX, originY, minX, minY, maxX, maxY; rct_maze_element *mazeElement; rct_track_element *trackElement; - rct_preview_track *trackBlock; + const rct_preview_track *trackBlock; window_track_place_clear_mini_preview(); @@ -151,7 +150,7 @@ static void window_track_place_draw_mini_preview() if (track->type != RIDE_TYPE_MAZE) { #pragma region Track - rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); + rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) + get_current_rotation(); trackElement = RCT2_ADDRESS(0x009D821B, rct_track_element); while (trackElement->type != 255) { @@ -163,11 +162,11 @@ static void window_track_place_draw_mini_preview() colour = RCT2_ADDRESS(0x0099BA64, uint8)[trackType * 16] & 0x10 ? 222 : 218; // Follow a single track piece shape - trackBlock = RCT2_ADDRESS(0x00994638, rct_preview_track*)[trackType]; - while (trackBlock->var_00 != 255) { + trackBlock = TrackBlocks[trackType]; + while (trackBlock->index != 255) { x = originX; y = originY; - + switch (rotation & 3) { case 0: x += trackBlock->x; @@ -235,9 +234,9 @@ static void window_track_place_draw_mini_preview() originY += track_coordinate->x; break; } - rotation += track_coordinate->rotation_positive - track_coordinate->rotation_negative; + rotation += track_coordinate->rotation_end - track_coordinate->rotation_begin; rotation &= 3; - if (track_coordinate->rotation_positive & 4) + if (track_coordinate->rotation_end & 4) rotation |= 4; if (!(rotation & 4)) { originX += RCT2_GLOBAL(0x00993CCC + (rotation * 4), sint16); @@ -250,7 +249,7 @@ static void window_track_place_draw_mini_preview() } else { #pragma region Maze - rotation = (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) & 3; + rotation = (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) + get_current_rotation()) & 3; mazeElement = RCT2_ADDRESS(0x009D821B, rct_maze_element); while (mazeElement->all != 0) { x = mazeElement->x * 32; @@ -311,7 +310,7 @@ static void window_track_place_clear_provisional() if (_window_track_place_last_was_valid) { sub_6D01B3( 6, - RCT2_GLOBAL(0x00F440EB, uint8), + RCT2_GLOBAL(0x00F440EB, uint8), _window_track_place_last_valid_x, _window_track_place_last_valid_y, _window_track_place_last_valid_z @@ -328,7 +327,7 @@ static int window_track_place_get_base_z(int x, int y) { rct_map_element *mapElement; int z; - + mapElement = map_get_surface_element_at(x >> 5, y >> 5); z = mapElement->base_height * 8; @@ -344,7 +343,7 @@ static int window_track_place_get_base_z(int x, int y) // Increase Z above water if (mapElement->properties.surface.terrain & 0x1F) z = max(z, (mapElement->properties.surface.terrain & 0x1F) << 4); - + return z + sub_6D01B3(3, 0, x, y, z); } @@ -353,11 +352,12 @@ static void window_track_place_attempt_placement(int x, int y, int z, int bl, mo int eax, ebx, ecx, edx, esi, edi, ebp; money32 result; + edx = esi = ebp = 0; eax = x; ebx = bl; ecx = y; edi = z; - result = game_do_command_p(GAME_COMMAND_PLACE_TRACK, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + result = game_do_command_p(GAME_COMMAND_PLACE_TRACK_DESIGN, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); if (cost != NULL) *cost = result; if (rideIndex != NULL) *rideIndex = edi & 0xFF; @@ -381,7 +381,7 @@ void window_track_place_open() 29, 200, 124, - (uint32*)window_track_place_events, + &window_track_place_events, WC_TRACK_DESIGN_PLACE, 0 ); @@ -394,7 +394,7 @@ void window_track_place_open() show_gridlines(); _window_track_place_last_cost = MONEY32_UNDEFINED; _window_track_place_last_x = 0xFFFF; - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = (-RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)) & 3; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = (2 - get_current_rotation()) & 3; window_track_place_draw_mini_preview(); } @@ -402,7 +402,7 @@ void window_track_place_open() * * rct2: 0x006D0119 */ -static void window_track_place_close() +static void window_track_place_close(rct_window *w) { window_track_place_clear_provisional(); viewport_set_visibility(0); @@ -416,13 +416,8 @@ static void window_track_place_close() * * rct2: 0x006CFEAC */ -static void window_track_place_mouseup() +static void window_track_place_mouseup(rct_window *w, int widgetIndex) { - rct_window *w; - short widgetIndex; - - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -463,96 +458,90 @@ static void window_track_place_update(rct_window *w) * * rct2: 0x006CFF2D */ -static void window_track_place_toolupdate() +static void window_track_place_toolupdate(rct_window* w, int widgetIndex, int x, int y) { - rct_window *w; - short widgetIndex, x, y; - int i, z; + int i; + short mapX, mapY, mapZ; money32 cost; uint8 rideIndex; - window_tool_get_registers(w, widgetIndex, x, y); - 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, NULL, NULL); - if (x == (short)0x8000) { + sub_68A15E(x, y, &mapX, &mapY, NULL, NULL); + if (mapX == (short)0x8000) { window_track_place_clear_provisional(); return; } // 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, 0, x, y, 0); + if (mapX == _window_track_place_last_x && mapY == _window_track_place_last_y) { + sub_6D01B3(0, 0, mapX, mapY, 0); return; } cost = MONEY32_UNDEFINED; // Get base Z position - z = window_track_place_get_base_z(x, y); + mapZ = window_track_place_get_base_z(mapX, mapY); 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 for (i = 0; i < 7; i++) { - window_track_place_attempt_placement(x, y, z, 105, &cost, &rideIndex); + window_track_place_attempt_placement(mapX, mapY, mapZ, 105, &cost, &rideIndex); if (cost != MONEY32_UNDEFINED) { RCT2_GLOBAL(0x00F440EB, uint16) = rideIndex; - _window_track_place_last_valid_x = x; - _window_track_place_last_valid_y = y; - _window_track_place_last_valid_z = z; + _window_track_place_last_valid_x = mapX; + _window_track_place_last_valid_y = mapY; + _window_track_place_last_valid_z = mapZ; _window_track_place_last_was_valid = 1; break; } - z += 8; + mapZ += 8; } } - _window_track_place_last_x = x; - _window_track_place_last_y = y; + _window_track_place_last_x = mapX; + _window_track_place_last_y = mapY; if (cost != _window_track_place_last_cost) { _window_track_place_last_cost = cost; widget_invalidate(w, WIDX_PRICE); } - - sub_6D01B3(0, 0, x, y, z); + + sub_6D01B3(0, 0, mapX, mapY, mapZ); } /** * * rct2: 0x006CFF34 */ -static void window_track_place_tooldown() +static void window_track_place_tooldown(rct_window* w, int widgetIndex, int x, int y) { - rct_window *w; - short widgetIndex, x, y, z; int i; + short mapX, mapY, mapZ; money32 cost; uint8 rideIndex; - window_tool_get_registers(w, widgetIndex, x, y); - window_track_place_clear_provisional(); map_invalidate_map_selection_tiles(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~7; - sub_68A15E(x, y, &x, &y, NULL, NULL); - if (x == (short)0x8000) + sub_68A15E(x, y, &mapX, &mapY, NULL, NULL); + if (mapX == (short)0x8000) return; - + // Try increasing Z until a feasible placement is found - z = window_track_place_get_base_z(x, y); + mapZ = window_track_place_get_base_z(mapX, mapY); for (i = 0; i < 7; i++) { RCT2_GLOBAL(0x009A8C29, uint8) |= 1; - window_track_place_attempt_placement(x, y, z, 1, &cost, &rideIndex); + window_track_place_attempt_placement(mapX, mapY, mapZ, 1, &cost, &rideIndex); RCT2_GLOBAL(0x009A8C29, uint8) &= ~1; if (cost != MONEY32_UNDEFINED) { window_close_by_class(WC_ERROR); - sound_play_panned(SOUND_PLACE_ITEM, 0x8001, x, y, z); + audio_play_sound_at_location(SOUND_PLACE_ITEM, mapX, mapY, mapZ); RCT2_GLOBAL(0x00F440A7, uint8) = rideIndex; if (RCT2_GLOBAL(0x00F4414E, uint8) & 1) { @@ -570,18 +559,18 @@ static void window_track_place_tooldown() if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) == 827) break; - z += 8; + mapZ += 8; } // Unable to build track - sound_play_panned(SOUND_ERROR, 0x8001, x, y, z); + audio_play_sound_at_location(SOUND_ERROR, mapX, mapY, mapZ); } /** * * rct2: 0x006D015C */ -static void window_track_place_toolabort() +static void window_track_place_toolabort(rct_window *w, int widgetIndex) { window_track_place_clear_provisional(); } @@ -590,16 +579,13 @@ static void window_track_place_toolabort() * * rct2: 0x006CFF01 */ -static void window_track_place_unknown14() +static void window_track_place_unknown14(rct_window *w) { window_track_place_draw_mini_preview(); } -static void window_track_place_invalidate() +static void window_track_place_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); } @@ -607,13 +593,10 @@ static void window_track_place_invalidate() * * rct2: 0x006CFD9D */ -static void window_track_place_paint() +static void window_track_place_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi, *clippedDpi; + rct_drawpixelinfo *clippedDpi; rct_g1_element tmpElement, *subsituteElement; - - window_paint_get_registers(w, dpi); window_draw_widgets(w, dpi); diff --git a/src/windows/viewport.c b/src/windows/viewport.c index c40ea69850..9a09015bb0 100644 --- a/src/windows/viewport.c +++ b/src/windows/viewport.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 . *****************************************************************************/ @@ -57,42 +57,41 @@ static rct_widget window_viewport_widgets[] = { { WIDGETS_END }, }; -static void window_viewport_empty(){} -static void window_viewport_mouseup(); -static void window_viewport_resize(); +static void window_viewport_mouseup(rct_window *w, int widgetIndex); +static void window_viewport_resize(rct_window *w); static void window_viewport_update(rct_window *w); -static void window_viewport_invalidate(); -static void window_viewport_paint(); +static void window_viewport_invalidate(rct_window *w); +static void window_viewport_paint(rct_window *w, rct_drawpixelinfo *dpi); -void* window_viewport_events[] = { - window_viewport_empty, +static rct_window_event_list window_viewport_events = { + NULL, window_viewport_mouseup, window_viewport_resize, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, + NULL, + NULL, + NULL, window_viewport_update, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, - window_viewport_empty, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_viewport_invalidate, window_viewport_paint, - window_viewport_empty + NULL }; static int _viewportNumber = 1; @@ -108,7 +107,7 @@ void window_viewport_open() w = window_create_auto_pos( INITIAL_WIDTH, INITIAL_HEIGHT, - (uint32*)window_viewport_events, + &window_viewport_events, WC_VIEWPORT, WF_RESIZABLE ); @@ -120,7 +119,7 @@ void window_viewport_open() (1 << WIDX_LOCATE); w->number = _viewportNumber++; - rotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, sint32); + rotation = get_current_rotation(); // Create viewport viewport_create(w, w->x, w->y, w->width, w->height, 0, 128 * 32, 128 * 32, 0, 1, -1); @@ -147,14 +146,11 @@ static void window_viewport_anchor_border_widgets(rct_window *w) w->widgets[WIDX_CLOSE].right = w->width - 3; } -static void window_viewport_mouseup() +static void window_viewport_mouseup(rct_window *w, int widgetIndex) { - short widgetIndex; - rct_window *w, *mainWindow; + rct_window *mainWindow; sint16 x, y; - window_widget_get_registers(w, widgetIndex); - switch (widgetIndex) { case WIDX_CLOSE: window_close(w); @@ -181,12 +177,8 @@ static void window_viewport_mouseup() } } -static void window_viewport_resize() +static void window_viewport_resize(rct_window *w) { - rct_window *w; - - window_get_register(w); - w->flags |= WF_RESIZABLE; window_set_resize(w, 200, 200, 2000, 2000); } @@ -208,14 +200,12 @@ static void window_viewport_update(rct_window *w) //widget_invalidate(w, WIDX_VIEWPORT); } -static void window_viewport_invalidate() +static void window_viewport_invalidate(rct_window *w) { - rct_window *w; rct_widget *viewportWidget; rct_viewport *viewport; int i; - window_get_register(w); colour_scheme_update(w); viewportWidget = &window_viewport_widgets[WIDX_VIEWPORT]; @@ -239,7 +229,7 @@ static void window_viewport_invalidate() w->disabled_widgets |= 1 << WIDX_ZOOM_IN; if (viewport->zoom >= 3) w->disabled_widgets |= 1 << WIDX_ZOOM_OUT; - + viewport->x = w->x + viewportWidget->left; viewport->y = w->y + viewportWidget->top; viewport->width = viewportWidget->right - viewportWidget->left; @@ -248,16 +238,11 @@ static void window_viewport_invalidate() viewport->view_height = viewport->height << viewport->zoom; } -static void window_viewport_paint() +static void window_viewport_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; - - window_paint_get_registers(w, dpi); - window_draw_widgets(w, dpi); // Draw viewport if (w->viewport != NULL) window_draw_viewport(dpi, w); -} \ No newline at end of file +} diff --git a/src/windows/water.c b/src/windows/water.c index ff74724149..85ccc87f36 100644 --- a/src/windows/water.c +++ b/src/windows/water.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 . *****************************************************************************/ @@ -27,6 +27,9 @@ #include "../world/map.h" #include "../interface/themes.h" +#define MINIMUM_TOOL_SIZE 1 +#define MAXIMUM_TOOL_SIZE 64 + enum WINDOW_WATER_WIDGET_IDX { WIDX_BACKGROUND, WIDX_TITLE, @@ -48,48 +51,47 @@ static rct_widget window_water_widgets[] = { static int window_water_should_close(); -static void window_water_emptysub() { } -static void window_water_close(); -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_close(rct_window *w); +static void window_water_mouseup(rct_window *w, int widgetIndex); +static void window_water_update(rct_window *w); +static void window_water_invalidate(rct_window *w); +static void window_water_paint(rct_window *w, rct_drawpixelinfo *dpi); +static void window_water_textinput(rct_window *w, int widgetIndex, char *text); static void window_water_inputsize(rct_window *w); -static void* window_water_events[] = { +static rct_window_event_list window_water_events = { window_water_close, window_water_mouseup, - window_water_emptysub, - window_water_emptysub, - window_water_emptysub, - window_water_emptysub, + NULL, + NULL, + NULL, + NULL, window_water_update, - window_water_emptysub, - window_water_emptysub, - window_water_emptysub, - window_water_emptysub, - window_water_emptysub, - window_water_emptysub, - window_water_emptysub, - window_water_emptysub, - window_water_emptysub, - window_water_emptysub, - window_water_emptysub, - window_water_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, window_water_textinput, - window_water_emptysub, - window_water_emptysub, - window_water_emptysub, - window_water_emptysub, - window_water_emptysub, + NULL, + NULL, + NULL, + NULL, + NULL, window_water_invalidate, window_water_paint, - window_water_emptysub + NULL }; /** - * + * * rct2: 0x006E6A40 */ void window_water_open() @@ -101,11 +103,11 @@ void window_water_open() return; window = window_create( - RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - 76, + RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 76, 29, 76, 77, - (uint32*)window_water_events, + &window_water_events, WC_WATER, 0 ); @@ -122,7 +124,7 @@ void window_water_open() * * rct2: 0x006E6B65 */ -static void window_water_close() +static void window_water_close(rct_window *w) { // If the tool wasn't changed, turn tool off if (!window_water_should_close()) @@ -133,39 +135,22 @@ static void window_water_close() * * rct2: 0x006E6B4E */ -static void window_water_mouseup() +static void window_water_mouseup(rct_window *w, int widgetIndex) { - 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; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = max(MINIMUM_TOOL_SIZE, RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)-1); // Invalidate the window window_invalidate(w); break; case WIDX_INCREMENT: // Increment land tool size - RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)++; - - // FEATURE: maximum size is always 7 - //limit = 7; - limit = 64; - // limit = (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2 ? 7 : 5); - - if (RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) > limit) - RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = limit; + RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = min(MAXIMUM_TOOL_SIZE, RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)+1); // Invalidate the window window_invalidate(w); @@ -176,33 +161,28 @@ static void window_water_mouseup() } } -static void window_water_textinput() +static void window_water_textinput(rct_window *w, int widgetIndex, char *text) { - 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) + if (widgetIndex != WIDX_PREVIEW || text == NULL) return; size = strtol(text, &end, 10); if (*end == '\0') { - if (size < 1) size = 1; - if (size > 64) size = 64; + size = max(MINIMUM_TOOL_SIZE,size); + size = min(MAXIMUM_TOOL_SIZE,size); 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; + ((uint16*)TextInputDescriptionArgs)[0] = MINIMUM_TOOL_SIZE; + ((uint16*)TextInputDescriptionArgs)[1] = MAXIMUM_TOOL_SIZE; window_text_input_open(w, WIDX_PREVIEW, 5128, 5129, STR_NONE, STR_NONE, 3); } @@ -221,11 +201,8 @@ static void window_water_update(rct_window *w) * * rct2: 0x006E6AB8 */ -static void window_water_invalidate() +static void window_water_invalidate(rct_window *w) { - rct_window *w; - - window_get_register(w); colour_scheme_update(w); // Set the preview image button to be pressed down @@ -244,25 +221,17 @@ static void window_water_invalidate() * * rct2: 0x006E6ACF */ -static void window_water_paint() +static void window_water_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_window *w; - rct_drawpixelinfo *dpi; int x, y; - window_paint_get_registers(w, dpi); - x = w->x + (window_water_widgets[WIDX_PREVIEW].left + window_water_widgets[WIDX_PREVIEW].right) / 2; y = w->y + (window_water_widgets[WIDX_PREVIEW].top + window_water_widgets[WIDX_PREVIEW].bottom) / 2; window_draw_widgets(w, dpi); - // FEATURE larger land tool size support + // Draw number for tool sizes bigger than 7 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); + gfx_draw_string_centred(dpi, STR_LAND_TOOL_SIZE_VALUE, x, y - 2, 0, &RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16)); } y = w->y + window_water_widgets[WIDX_PREVIEW].bottom + 5; diff --git a/src/world/balloon.c b/src/world/balloon.c new file mode 100644 index 0000000000..1d05313edc --- /dev/null +++ b/src/world/balloon.c @@ -0,0 +1,84 @@ +#include "../audio/audio.h" +#include "../scenario.h" +#include "../util/util.h" +#include "sprite.h" + +/** + * + * rct2: 0x006736C7 + */ +void create_balloon(int x, int y, int z, int colour, uint8 bl) +{ + 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; + } +} + +void balloon_pop(rct_balloon *balloon) +{ + balloon->popped = 1; + balloon->var_26 = 0; + audio_play_sound_at_location(SOUND_BALLOON_POP, balloon->x, balloon->y, balloon->z); +} + +/** + * + * rct: 0x0067342C + */ +void balloon_update(rct_balloon *balloon) +{ + invalidate_sprite_2((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 = util_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 + ); +} diff --git a/src/world/banner.c b/src/world/banner.c index 306b1cad26..44521c90f2 100644 --- a/src/world/banner.c +++ b/src/world/banner.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,7 +21,9 @@ #include "../addresses.h" #include "../game.h" #include "../localisation/localisation.h" +#include "../ride/ride.h" #include "banner.h" +#include "map.h" rct_banner *gBanners = (rct_banner*)0x0135A124; @@ -29,39 +31,144 @@ rct_banner *gBanners = (rct_banner*)0x0135A124; * * rct2: 0x006B9CB0 */ -void banner_init() { - for(int i = 0; i < MAX_BANNERS; i++) { - gBanners[i].type = BANNER_NULL; - } +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. + * + * rct2: 0x006BA278 */ -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; - } - } +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 (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]; + 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; - } + 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 +} + +rct_map_element *banner_get_map_element(int bannerIndex) +{ + rct_banner *banner = &gBanners[bannerIndex]; + rct_map_element *mapElement = map_get_first_element_at(banner->x, banner->y); + do { + if (map_element_get_banner_index(mapElement) == bannerIndex) { + return mapElement; + } + } while (!map_element_is_last_for_tile(mapElement++)); + return NULL; +} + +/** + * + * rct2: 0x006B7EAB + */ +static int banner_get_ride_index_at(int x, int y, int z) +{ + rct_map_element *mapElement; + rct_ride *ride; + int rideIndex, resultRideIndex; + + resultRideIndex = -1; + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + + rideIndex = mapElement->properties.track.ride_index; + ride = GET_RIDE(rideIndex); + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP)) + continue; + + if ((mapElement->clearance_height * 8) + 32 <= z) + continue; + + resultRideIndex = rideIndex; + } while (!map_element_is_last_for_tile(mapElement++)); + + return resultRideIndex; +} + +/** + * + * rct2: 0x006B7D86 + */ +int banner_get_closest_ride_index(int x, int y, int z) +{ + int i, rideIndex; + rct_ride *ride; + + static const rct_xy16 NeighbourCheckOrder[] = { + { 32, 0 }, + { -32, 0 }, + { 0, 32 }, + { 0, -32 }, + { -32, +32 }, + { +32, -32 }, + { +32, +32 }, + { -32, +32 }, + { 0, 0 } + }; + + for (i = 0; i < countof(NeighbourCheckOrder); i++) { + rideIndex = banner_get_ride_index_at(x + NeighbourCheckOrder[i].x, y + NeighbourCheckOrder[i].y, z); + if (rideIndex != -1) { + return rideIndex; + } + } + + rideIndex = -1; + int resultDistance = INT_MAX; + FOR_ALL_RIDES(i, ride) { + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP)) + continue; + + uint16 xy = ride->overall_view; + if (xy == 0xFFFF) + continue; + + int rideX = (xy & 0xFF) * 32; + int rideY = (xy >> 8) * 32; + int distance = abs(x - rideX) + abs(y - rideY); + if (distance < resultDistance) { + resultDistance = distance; + rideIndex = i; + } + } + + return rideIndex; +} + +void fix_banner_count() +{ + for (int banner_index = 0; banner_index < MAX_BANNERS; banner_index++){ + rct_map_element *map_element = banner_get_map_element(banner_index); + if(map_element==NULL) + gBanners[banner_index].type = BANNER_NULL; + } +} diff --git a/src/world/banner.h b/src/world/banner.h index 3944fd7c9c..7b836d0815 100644 --- a/src/world/banner.h +++ b/src/world/banner.h @@ -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,7 @@ #define _BANNER_H_ #include "../common.h" +#include "../world/map.h" #define BANNER_NULL 255 #define MAX_BANNERS 250 @@ -46,5 +47,8 @@ extern rct_banner *gBanners; void banner_init(); int create_new_banner(uint8 flags); +rct_map_element *banner_get_map_element(int bannerIndex); +int banner_get_closest_ride_index(int x, int y, int z); +void fix_banner_count(); #endif diff --git a/src/world/climate.c b/src/world/climate.c index 79e231c2da..787438bf90 100644 --- a/src/world/climate.c +++ b/src/world/climate.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,10 +21,13 @@ #include "../addresses.h" #include "../audio/audio.h" #include "../audio/mixer.h" +#include "../config.h" #include "../drawing/drawing.h" +#include "../game.h" #include "../localisation/date.h" #include "../scenario.h" #include "../interface/window.h" +#include "../util/util.h" #include "climate.h" enum { @@ -42,36 +45,33 @@ typedef struct { // 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; -#define _climateCurrentWeatherEffect RCT2_GLOBAL(0x013CA74E, uint8) +#define _climateCurrentWeatherEffect RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WEATHER_EFFECT, uint8) -#define _climateNextTemperature RCT2_GLOBAL(0x013CA74D, uint8) -#define _climateNextWeatherEffect RCT2_GLOBAL(0x013CA74F, uint8) -#define _climateNextWeatherGloom RCT2_GLOBAL(0x013CA751, uint8) -#define _climateNextRainLevel RCT2_GLOBAL(0x013CA753, uint8) +#define _climateNextTemperature RCT2_GLOBAL(RCT2_ADDRESS_NEXT_TEMPERATURE, uint8) +#define _climateNextWeatherEffect RCT2_GLOBAL(RCT2_ADDRESS_NEXT_WEATHER_EFFECT, uint8) +#define _climateNextWeatherGloom RCT2_GLOBAL(RCT2_ADDRESS_NEXT_WEATHER_GLOOM, uint8) +#define _climateNextRainLevel RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RAIN_LEVEL, uint8) static const rct_weather_transition* climate_transitions[4]; // Sound data static int _rainVolume = 1; -static rct_sound _rainSoundInstance; -static void* _rainSoundChannel = 0; static unsigned int _lightningTimer, _thunderTimer; -static rct_sound _thunderSoundInstance[MAX_THUNDER_INSTANCES]; static void* _thunderSoundChannels[MAX_THUNDER_INSTANCES]; static int _thunderStatus[MAX_THUNDER_INSTANCES] = { THUNDER_STATUS_NULL, THUNDER_STATUS_NULL }; static unsigned int _thunderSoundId; static int _thunderVolume; static int _thunderStereoEcho = 0; -static void climate_determine_future_weather(); +static void climate_determine_future_weather(int randomDistribution); static void climate_update_rain_sound(); static void climate_update_thunder_sound(); @@ -105,22 +105,15 @@ 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 + audio_stop_rain_sound(); _rainVolume = 1; } - climate_determine_future_weather(); + climate_determine_future_weather(util_rand()); } sint8 step_weather_level(sint8 cur_weather_level, sint8 next_weather_level) { @@ -141,7 +134,7 @@ void toggle_climate_lock() /** * Weather & climate update iteration. * Gradually changes the weather parameters towards their determined next values. - * + * * rct2: 0x006C46B1 */ void climate_update() @@ -167,8 +160,8 @@ void climate_update() RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE_UPDATE_TIMER, sint16)--; - } else if (!(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, sint32) & 0x7F)) { - + } else if (!(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 0x7F)) { + if (temperature == target_temperature) { if (cur_gloom == next_gloom) { _climateCurrentWeatherEffect = _climateNextWeatherEffect; @@ -177,7 +170,7 @@ void climate_update() if (cur_rain == next_rain) { RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WEATHER, sint8) = gClimateNextWeather; - climate_determine_future_weather(); + climate_determine_future_weather(scenario_rand()); 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); @@ -202,49 +195,49 @@ 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(); } /** * Calculates future weather development. - * RCT2 implements this as discrete probability distributions dependant on month and climate + * RCT2 implements this as discrete probability distributions dependant on month and climate * for next_weather. The other weather parameters are then looked up depending only on the * next weather. * * rct2: 0x006C461C */ -static void climate_determine_future_weather() +static void climate_determine_future_weather(int randomDistribution) { sint8 climate = RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE, sint8); const rct_weather_transition* climate_table = climate_transitions[climate]; sint8 month = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, sint16) & 7; rct_weather_transition transition = climate_table[month]; - + // Generate a random variable with values 0 upto distribution_size-1 and chose weather from the distribution table accordingly - sint8 next_weather = transition.distribution[ ((rand() & 0xFF) * transition.distribution_size) >> 8 ]; + sint8 next_weather = transition.distribution[ ((randomDistribution & 0xFF) * transition.distribution_size) >> 8 ]; gClimateNextWeather = next_weather; _climateNextTemperature = transition.base_temperature + climate_weather_data[next_weather].temp_delta; _climateNextWeatherEffect = climate_weather_data[next_weather].effect_level; _climateNextWeatherGloom = climate_weather_data[next_weather].gloom_level; _climateNextRainLevel = climate_weather_data[next_weather].rain_level; - + RCT2_GLOBAL(RCT2_ADDRESS_CLIMATE_UPDATE_TIMER, sint16) = 1920; } /** - * + * * rct2: 0x006BCB91 */ void climate_update_sound() { if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) == 0xFFFFFFFF) return; - if (RCT2_GLOBAL(0x009AF59C, uint8) != 0) + if (gGameSoundsOff) return; - if (!(RCT2_GLOBAL(0x009AF59D, uint8) & 1)) + if (!gConfigSound.sound) return; if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) return; @@ -256,48 +249,28 @@ void climate_update_sound() static void climate_update_rain_sound() { if (_climateCurrentWeatherEffect == 1 || _climateCurrentWeatherEffect == 2) { + // Start playing the rain sound + if (!gRainSoundChannel) { + gRainSoundChannel = Mixer_Play_Effect(SOUND_RAIN_1, MIXER_LOOP_INFINITE, DStoMixerVolume(-4000), 0.5f, 1, 0); + } if (_rainVolume == 1) { - // Start playing the rain sound -#ifdef USE_MIXER - if (!_rainSoundChannel) { - _rainSoundChannel = Mixer_Play_Effect(SOUND_RAIN_1, MIXER_LOOP_INFINITE, DStoMixerVolume(-4000), 0.5f, 1, 0); - } -#else - if (sound_prepare(SOUND_RAIN_1, &_rainSoundInstance, 1, RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, uint32))) - sound_play(&_rainSoundInstance, 1, -4000, 0, 0); -#endif _rainVolume = -4000; } else { // Increase rain sound _rainVolume = min(-1400, _rainVolume + 80); -#ifdef USE_MIXER - if (_rainSoundChannel) { - Mixer_Channel_Volume(_rainSoundChannel, DStoMixerVolume(_rainVolume)); + if (gRainSoundChannel) { + Mixer_Channel_Volume(gRainSoundChannel, DStoMixerVolume(_rainVolume)); } -#else - sound_set_volume(&_rainSoundInstance, _rainVolume); -#endif } } else if (_rainVolume != 1) { // Decrease rain sound _rainVolume -= 80; if (_rainVolume > -4000) { -#ifdef USE_MIXER - if (_rainSoundChannel) { - Mixer_Channel_Volume(_rainSoundChannel, DStoMixerVolume(_rainVolume)); + if (gRainSoundChannel) { + Mixer_Channel_Volume(gRainSoundChannel, DStoMixerVolume(_rainVolume)); } -#else - sound_set_volume(&_rainSoundInstance, _rainVolume); -#endif } else { -#ifdef USE_MIXER - if (_rainSoundChannel) { - Mixer_Stop_Channel(_rainSoundChannel); - _rainSoundChannel = 0; - } -#else - sound_stop(&_rainSoundInstance); -#endif + audio_stop_rain_sound(); _rainVolume = 1; } } @@ -327,17 +300,10 @@ static void climate_update_thunder_sound() if (_thunderStatus[i] == THUNDER_STATUS_NULL) continue; -#ifdef USE_MIXER if (!Mixer_Channel_IsPlaying(_thunderSoundChannels[i])) { Mixer_Stop_Channel(_thunderSoundChannels[i]); _thunderStatus[i] = THUNDER_STATUS_NULL; } -#else - if (!sound_is_playing(&_thunderSoundInstance[i])) { - sound_stop(&_thunderSoundInstance[i]); - _thunderStatus[i] = THUNDER_STATUS_NULL; - } -#endif } } @@ -380,20 +346,11 @@ static void climate_update_thunder() static int climate_play_thunder(int instanceIndex, int soundId, int volume, int pan) { -#ifdef USE_MIXER _thunderSoundChannels[instanceIndex] = Mixer_Play_Effect(soundId, MIXER_LOOP_NONE, DStoMixerVolume(volume), DStoMixerPan(pan), 1, 0); if (_thunderSoundChannels[instanceIndex]) { _thunderStatus[instanceIndex] = THUNDER_STATUS_PLAYING; return 1; } -#else - if (sound_prepare(soundId, &_thunderSoundInstance[instanceIndex], 1, RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, uint32))) { - sound_play(&_thunderSoundInstance[instanceIndex], 0, volume, pan, 0); - - _thunderStatus[instanceIndex] = THUNDER_STATUS_PLAYING; - return 1; - } -#endif return 0; } diff --git a/src/world/climate.h b/src/world/climate.h index 0ab10b5be3..147b6445ac 100644 --- a/src/world/climate.h +++ b/src/world/climate.h @@ -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 . *****************************************************************************/ @@ -49,7 +49,7 @@ typedef struct { // This still needs to be read / written when loading and saving // extern int gClimateNextWeather; -#define gClimateNextWeather RCT2_GLOBAL(0x013CA74B, uint8) +#define gClimateNextWeather RCT2_GLOBAL(RCT2_ADDRESS_NEXT_WEATHER, uint8) extern const rct_weather climate_weather_data[6]; diff --git a/src/world/duck.c b/src/world/duck.c new file mode 100644 index 0000000000..1e500247ca --- /dev/null +++ b/src/world/duck.c @@ -0,0 +1,309 @@ +#include "../addresses.h" +#include "../audio/audio.h" +#include "../localisation/date.h" +#include "../scenario.h" +#include "sprite.h" + +enum { + DUCK_STATE_FLY_TO_WATER, + DUCK_STATE_SWIM, + DUCK_STATE_DRINK, + DUCK_STATE_DOUBLE_DRINK, + DUCK_STATE_FLY_AWAY +}; + +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: 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) +{ + invalidate_sprite_0((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) +{ + audio_play_sound_at_location(SOUND_QUACK, 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); + } +} diff --git a/src/world/entrance.h b/src/world/entrance.h index 6705c623f0..291a14f905 100644 --- a/src/world/entrance.h +++ b/src/world/entrance.h @@ -26,8 +26,8 @@ typedef struct { rct_string_id string_idx; // 0x00 uint32 image_id; // 0x02 - uint8 var_06; - uint8 var_07; + uint8 scrolling_mode; // 0x06 + uint8 text_height; // 0x07 } rct_entrance_type; #endif \ No newline at end of file diff --git a/src/world/footpath.c b/src/world/footpath.c index 7caa8dbadf..ee57d5e0b4 100644 --- a/src/world/footpath.c +++ b/src/world/footpath.c @@ -8,39 +8,58 @@ * 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 "../cheats.h" +#include "../config.h" #include "../game.h" #include "../localisation/localisation.h" +#include "../management/finance.h" #include "../util/util.h" #include "footpath.h" #include "map.h" +#include "map_animation.h" #include "scenery.h" -#include "../cheats.h" -#include "../config.h" void footpath_interrupt_peeps(int x, int y, int z); +void sub_6A7642(int x, int y, rct_map_element *mapElement); +void sub_6A76E9(int rideIndex); -enum { - FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED = 1 << 3 -}; - -const rct_xy16 word_981D6C[] = { +const rct_xy16 word_981D6C[4] = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 } }; +// rct2: 0x0097B974 +static const uint16 EntranceDirections[] = { + (4 ), 0, 0, 0, 0, 0, 0, 0, // ENTRANCE_TYPE_RIDE_ENTRANCE, + (4 ), 0, 0, 0, 0, 0, 0, 0, // ENTRANCE_TYPE_RIDE_EXIT, + (4 | 1), 0, 0, 0, 0, 0, 0, 0, // ENTRANCE_TYPE_PARK_ENTRANCE +}; + +static int entrance_get_directions(rct_map_element *mapElement) +{ + uint8 entranceType = mapElement->properties.entrance.type; + uint8 sequence = mapElement->properties.entrance.index & 0x0F; + return EntranceDirections[(entranceType * 8) + sequence]; +} + +static bool entrance_has_direction(rct_map_element *mapElement, int direction) +{ + return entrance_get_directions(mapElement) & (1 << direction); +} + /** * * rct2: 0x006A65AD @@ -94,7 +113,7 @@ rct_map_element *map_get_footpath_element_slope(int x, int y, int z, int slope) return mapElement; } } while (!map_element_is_last_for_tile(mapElement++)); - + return NULL; } @@ -102,7 +121,7 @@ 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))) { + if ((mapElement->properties.path.type & 4) && !(flags & GAME_COMMAND_FLAG_GHOST)) { direction = mapElement->properties.path.type & 3; z = mapElement->base_height; map_remove_intersecting_walls(x, y, z, z + 6, direction ^ 2); @@ -110,14 +129,14 @@ static void loc_6A6620(int flags, int x, int y, rct_map_element *mapElement) mapElement = map_get_footpath_element(x / 32, y / 32, z); } - if (!(flags & (1 << 7))) - sub_6A6C66(x, y, mapElement, flags); + if (!(flags & GAME_COMMAND_FLAG_7)) + footpath_connect_edges(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) +static money32 footpath_element_insert(int type, int x, int y, int z, int slope, int flags, uint8 pathItemType) { rct_map_element *mapElement; int bl, zHigh; @@ -125,8 +144,8 @@ static money32 footpath_element_insert(int type, int x, int y, int z, int slope, 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)); + if ((flags & GAME_COMMAND_FLAG_APPLY) && !(flags & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST))) + footpath_remove_litter(x, y, RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16)); // loc_6A649D: RCT2_GLOBAL(0x00F3EFD9, money32) += MONEY(12, 00); @@ -140,16 +159,16 @@ static money32 footpath_element_insert(int type, int x, int y, int z, int slope, 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)) + if (!gCheatsDisableClearanceChecks && !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(0x00F3EFA4, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8); + if (!gCheatsDisableClearanceChecks && (RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) & ELEMENT_IS_UNDERWATER)) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CANT_BUILD_THIS_UNDERWATER; return MONEY32_UNDEFINED; } @@ -165,16 +184,16 @@ static money32 footpath_element_insert(int type, int x, int y, int z, int slope, 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.additions = pathItemType; mapElement->properties.path.addition_status = 255; mapElement->flags &= ~MAP_ELEMENT_FLAG_BROKEN; if (flags & (1 << 6)) - mapElement->flags |= 1 << 4; + mapElement->flags |= MAP_ELEMENT_FLAG_GHOST; RCT2_GLOBAL(0x00F3EFF4, uint32) = 0x00F3EFF8; if (!(flags & (1 << 7))) - sub_6A6AA7(x, y, mapElement); + footpath_remove_edges_at(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); @@ -184,24 +203,24 @@ static money32 footpath_element_insert(int type, int x, int y, int z, int slope, 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) +static money32 footpath_element_update(int x, int y, rct_map_element *mapElement, int type, int flags, uint8 pathItemType) { 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) { + } else if (pathItemType != 0) { if ( - !(flags & (1 << 6)) && - (mapElement->properties.path.additions & 0x0F) == RCT2_GLOBAL(0x00F3EF88, uint16) && + !(flags & GAME_COMMAND_FLAG_GHOST) && + (mapElement->properties.path.additions & 0x0F) == pathItemType && !(mapElement->flags & MAP_ELEMENT_FLAG_BROKEN) ) { - if (flags & (1 << 4)) + if (flags & GAME_COMMAND_FLAG_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]; + if (pathItemType != 0) { + rct_scenery_entry* scenery_entry = g_pathBitSceneryEntries[pathItemType - 1]; uint16 unk6 = scenery_entry->path_bit.var_06; if ((unk6 & 0x80) && (mapElement->properties.path.type & 4)) { @@ -209,17 +228,17 @@ static money32 footpath_element_update(int x, int y, rct_map_element *mapElement return MONEY32_UNDEFINED; } - if ((unk6 & 0x40) && (mapElement->type & 1)) { + if ((unk6 & 0x40) && footpath_element_is_queue(mapElement)) { 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) { + 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)) { + if ((unk6 & 0x100) && !footpath_element_is_queue(mapElement)) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CAN_ONLY_PLACE_THESE_ON_QUEUE_AREA; return MONEY32_UNDEFINED; } @@ -227,10 +246,10 @@ static money32 footpath_element_update(int x, int y, rct_map_element *mapElement RCT2_GLOBAL(0x00F3EFD9, money32) += scenery_entry->path_bit.price; } - if (flags & (1 << 4)) + if (flags & GAME_COMMAND_FLAG_4) return MONEY32_UNDEFINED; - if (flags & (1 << 6)) { + if (flags & GAME_COMMAND_FLAG_GHOST) { if (mapElement->properties.path.additions & 0x0F) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_NONE; return MONEY32_UNDEFINED; @@ -244,22 +263,16 @@ static money32 footpath_element_update(int x, int y, rct_map_element *mapElement 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) - ) + (pathItemType != 0 && !(flags & GAME_COMMAND_FLAG_GHOST)) || + (pathItemType == 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]; + mapElement->properties.path.additions = (mapElement->properties.path.additions & 0xF0) | pathItemType; + mapElement->flags &= ~MAP_ELEMENT_FLAG_BROKEN; + if (pathItemType != 0) { + rct_scenery_entry* scenery_entry = g_pathBitSceneryEntries[pathItemType - 1]; uint16 unk6 = scenery_entry->path_bit.var_06; if (unk6 & 1) mapElement->properties.path.addition_status = 255; @@ -268,18 +281,18 @@ static money32 footpath_element_update(int x, int y, rct_map_element *mapElement return RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : RCT2_GLOBAL(0x00F3EFD9, money32); } - if (flags & (1 << 4)) + if (flags & GAME_COMMAND_FLAG_4) return MONEY32_UNDEFINED; if (flags & GAME_COMMAND_FLAG_APPLY) { RCT2_GLOBAL(0x00F3EFF4, uint32) = 0x00F3EFF8; - if (!(flags & (1 << 7))) - sub_6A6AA7(x, y, mapElement); + if (!(flags & GAME_COMMAND_FLAG_7)) + footpath_remove_edges_at(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->properties.path.additions = (mapElement->properties.path.additions & 0xF0) | pathItemType; mapElement->flags &= ~MAP_ELEMENT_FLAG_BROKEN; loc_6A6620(flags, x, y, mapElement); @@ -288,16 +301,16 @@ static money32 footpath_element_update(int x, int y, rct_map_element *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) +static money32 footpath_place_real(int type, int x, int y, int z, int slope, int flags, uint8 pathItemType) { 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; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = z * 8; - if (!(flags & FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED) && RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0 && !gConfigCheat.build_in_pause_mode) { + if (!(flags & GAME_COMMAND_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; } @@ -307,14 +320,13 @@ static money32 footpath_place_real(int type, int x, int y, int z, int slope, int 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)) + if (!((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(x, y, z * 8)) return MONEY32_UNDEFINED; if (slope & 8) { @@ -332,10 +344,16 @@ static money32 footpath_place_real(int type, int x, int y, int z, int slope, int return MONEY32_UNDEFINED; } + // Force ride construction to recheck area + RCT2_GLOBAL(0x00F440B0, uint8) |= 8; + + footpath_provisional_remove(); 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); + if (mapElement == NULL) { + return footpath_element_insert(type, x, y, z, slope, flags, pathItemType); + } else { + return footpath_element_update(x, y, mapElement, type, flags, pathItemType); + } } /* rct2: 0x006BA23E */ @@ -353,12 +371,12 @@ 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; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = z * 8; - if (!(flags & FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED) && RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0 && !gConfigCheat.build_in_pause_mode) { + if (!(flags & GAME_COMMAND_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; } @@ -368,14 +386,14 @@ money32 footpath_remove_real(int x, int y, int z, int flags) 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)) + if (!((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !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); + footpath_remove_edges_at(x, y, mapElement); map_invalidate_tile_full(x, y); map_element_remove(mapElement); sub_6A759F(); @@ -390,10 +408,121 @@ money32 footpath_remove_real(int x, int y, int z, int flags) */ 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); + *ebx = footpath_place_real( + (*edx >> 8) & 0xFF, + *eax & 0xFFFF, + *ecx & 0xFFFF, + *edx & 0xFF, + (*ebx >> 8) & 0xFF, + *ebx & 0xFF, + *edi & 0xFF + ); +} + +static money32 footpath_place_from_track(int type, int x, int y, int z, int slope, int edges, int flags) +{ + rct_map_element *mapElement; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = z * 8; + + if (!(flags & GAME_COMMAND_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; + + if (!map_is_location_owned(x, y, z * 8) && !gCheatsSandboxMode) { + return MONEY32_UNDEFINED; + } + + if (!((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && !map_is_location_owned(x, y, z * 8)) + 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; + } + + if (flags & GAME_COMMAND_FLAG_APPLY) { + if (!(flags & (GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_GHOST))) { + footpath_remove_litter(x, y, z * 8); + } + } + + RCT2_GLOBAL(0x00F3EFD9, money32) += 120; + uint8 bl = 15; + int 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 (!gCheatsDisableClearanceChecks && !map_can_construct_with_clear_at(x, y, z, zHigh, (void*)0x006A6733, bl)) + return MONEY32_UNDEFINED; + + RCT2_GLOBAL(0x00F3EFA4, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8); + if (!gCheatsDisableClearanceChecks && (RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) & ELEMENT_IS_UNDERWATER)) { + 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 = 0; + mapElement->properties.path.addition_status = 255; + mapElement->properties.path.edges = edges & 0xF; + mapElement->flags &= ~MAP_ELEMENT_FLAG_BROKEN; + if (flags & (1 << 6)) + mapElement->flags |= MAP_ELEMENT_FLAG_GHOST; + + map_invalidate_tile_full(x, y); + } + return RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY ? 0 : RCT2_GLOBAL(0x00F3EFD9, money32); +} + +/* + * rct2: 0x006A68AE + */ +void game_command_place_footpath_from_track(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + *ebx = footpath_place_from_track( + (*edx >> 8) & 0xFF, + *eax & 0xFFFF, + *ecx & 0xFFFF, + *edx & 0xFF, + ((*ebx >> 13) & 0x3) | ((*ebx >> 10) & 0x4), + (*ebx >> 8) & 0xF, + *ebx & 0xFF + ); } /** @@ -416,7 +545,7 @@ void footpath_remove(int x, int y, int z, int flags) } /** - * + * * rct2: 0x006A76FF */ money32 footpath_provisional_set(int type, int x, int y, int z, int slope) @@ -425,7 +554,7 @@ money32 footpath_provisional_set(int type, int x, int y, int z, int slope) 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); + cost = footpath_place(type, x, y, z, slope, GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_5 | GAME_COMMAND_FLAG_4 | GAME_COMMAND_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; @@ -439,7 +568,7 @@ money32 footpath_provisional_set(int type, int x, int y, int z, int slope) } /** - * + * * rct2: 0x006A77FF */ void footpath_provisional_remove() @@ -451,13 +580,13 @@ void footpath_provisional_remove() RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Y, uint16), RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Z, uint16), - (1 << 0) | FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED | (1 << 5) + GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_5 ); } } /** - * + * * rct2: 0x006A7831 */ void footpath_provisional_update() @@ -490,7 +619,7 @@ void footpath_provisional_update() */ void footpath_get_coordinates_from_pos(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement) { - int z, interactionType; + int z = 0, interactionType; rct_map_element *myMapElement; rct_viewport *viewport; rct_xy16 map_pos = { 0 }; @@ -560,7 +689,7 @@ void footpath_get_coordinates_from_pos(int screenX, int screenY, int *x, int *y, } /** - * + * * rct2: 0x0068A0C9 * screenX: eax * screenY: ebx @@ -582,27 +711,25 @@ void footpath_bridge_get_info_from_pos(int screenX, int screenY, int *x, int *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)); + && map_element_get_type(*mapElement) == MAP_ELEMENT_TYPE_ENTRANCE + ) { + int directions = entrance_get_directions(*mapElement); + if (directions & 0x0F) { + int bx = bitscanforward(directions); 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)); + int directions = entrance_get_directions(*mapElement); + if (directions & 0x0F) { + int bx = bitscanforward(directions); bx += (*mapElement)->type; // First two bits seem to contain the direction of entrance/exit bx &= 3; if (direction != NULL) *direction = bx; @@ -615,7 +742,7 @@ void footpath_bridge_get_info_from_pos(int screenX, int screenY, int *x, int *y, } /** - * + * * rct2: 0x00673883 */ void footpath_remove_litter(int x, int y, int z) @@ -632,7 +759,7 @@ void footpath_remove_litter(int x, int y, int z) if (sprite->linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_LITTER) { int distanceZ = abs(sprite->z - z); if (distanceZ <= 32) { - sub_6EC60B((rct_sprite*)sprite); + invalidate_sprite_0((rct_sprite*)sprite); sprite_remove((rct_sprite*)sprite); } } @@ -641,7 +768,7 @@ void footpath_remove_litter(int x, int y, int z) } /** - * + * * rct2: 0x0069A48B */ void footpath_interrupt_peeps(int x, int y, int z) @@ -657,7 +784,7 @@ void footpath_interrupt_peeps(int x, int y, int z) 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) { + if (peep->z == z) { peep_decrement_num_riders(peep); peep->state = PEEP_STATE_WALKING; peep_window_state_update(peep); @@ -672,26 +799,592 @@ void footpath_interrupt_peeps(int x, int y, int z) } } +/* rct2: 0x006E59DC */ +bool fence_in_the_way(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->flags & MAP_ELEMENT_FLAG_GHOST) + continue; + if (z0 >= mapElement->clearance_height) + continue; + if (z1 <= mapElement->base_height) + continue; + if ((mapElement->type & MAP_ELEMENT_DIRECTION_MASK) != direction) + continue; + + return true; + } while (!map_element_is_last_for_tile(mapElement++)); + return false; +} + +bool map_is_edge(int x, int y) +{ + return ( + x < 32 || + y < 32 || + x >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) || + y >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) + ); +} + +static rct_map_element *footpath_connect_corners_get_neighbour(int x, int y, int z, int requireEdges) +{ + 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 (footpath_element_is_queue(mapElement)) + continue; + if (mapElement->base_height != z) + continue; + if (!(mapElement->properties.path.edges & requireEdges)) + continue; + + return mapElement; + } while (!map_element_is_last_for_tile(mapElement++)); + return NULL; +} + /** - * + * Sets the corner edges of four path tiles. + * The function will search for a path in the direction given, then check clockwise to see if it there is a path and again until + * it reaches the initial path. In other words, checks if there are four paths together so that it can set the inner corners of + * each one. + * + * rct2: 0x006A70EB + */ +static void footpath_connect_corners(int initialX, int initialY, rct_map_element *initialMapElement) +{ + rct_map_element *mapElement[4]; + + if (footpath_element_is_queue(initialMapElement)) + return; + if (footpath_element_is_sloped(initialMapElement)) + return; + + mapElement[0] = initialMapElement; + int z = initialMapElement->base_height; + for (int initialDirection = 0; initialDirection < 4; initialDirection++) { + int x = initialX; + int y = initialY; + int direction = initialDirection; + + x += TileDirectionDelta[direction].x; + y += TileDirectionDelta[direction].y; + mapElement[1] = footpath_connect_corners_get_neighbour(x, y, z, (1 << (direction ^ 2))); + if (mapElement[1] == NULL) + continue; + + direction = (direction + 1) & 3; + x += TileDirectionDelta[direction].x; + y += TileDirectionDelta[direction].y; + mapElement[2] = footpath_connect_corners_get_neighbour(x, y, z, (1 << (direction ^ 2))); + if (mapElement[2] == NULL) + continue; + + direction = (direction + 1) & 3; + x += TileDirectionDelta[direction].x; + y += TileDirectionDelta[direction].y; + // First check link to previous tile + mapElement[3] = footpath_connect_corners_get_neighbour(x, y, z, (1 << (direction ^ 2))); + if (mapElement[3] == NULL) + continue; + // Second check link to initial tile + mapElement[3] = footpath_connect_corners_get_neighbour(x, y, z, (1 << ((direction + 1) & 3))); + if (mapElement[3] == NULL) + continue; + + direction = (direction + 1) & 3; + mapElement[3]->properties.path.edges |= (1 << (direction + 4)); + map_invalidate_element(x, y, mapElement[3]); + + direction = (direction - 1) & 3; + mapElement[2]->properties.path.edges |= (1 << (direction + 4)); + map_invalidate_element(x, y, mapElement[2]); + + direction = (direction - 1) & 3; + mapElement[1]->properties.path.edges |= (1 << (direction + 4)); + map_invalidate_element(x, y, mapElement[1]); + + direction = initialDirection; + mapElement[0]->properties.path.edges |= (1 << (direction + 4)); + map_invalidate_element(x, y, mapElement[0]); + } +} + +typedef struct { + uint8 order; + uint8 direction; + uint8 ride_index; +} rct_neighbour; + +typedef struct { + rct_neighbour items[8]; + int count; +} rct_neighbour_list; + +static int rct_neighbour_compare(const void *a, const void *b) +{ + uint8 va = ((rct_neighbour*)a)->order; + uint8 vb = ((rct_neighbour*)b)->order; + if (va < vb) return 1; + else if (va > vb) return -1; + else { + uint8 da = ((rct_neighbour*)a)->direction; + uint8 db = ((rct_neighbour*)b)->direction; + if (va < vb) return -1; + else if (va > vb) return 1; + else return 0; + } +} + +static void neighbour_list_init(rct_neighbour_list *neighbourList) +{ + neighbourList->count = 0; +} + +static void neighbour_list_push(rct_neighbour_list *neighbourList, int order, int direction, uint8 rideIndex) +{ + neighbourList->items[neighbourList->count].order = order; + neighbourList->items[neighbourList->count].direction = direction; + neighbourList->items[neighbourList->count].ride_index = rideIndex; + neighbourList->count++; +} + +static bool neighbour_list_pop(rct_neighbour_list *neighbourList, rct_neighbour *outNeighbour) +{ + if (neighbourList->count == 0) + return false; + + *outNeighbour = neighbourList->items[0]; + for (int i = 0; i < neighbourList->count - 1; i++) + neighbourList->items[i] = neighbourList->items[i + 1]; + neighbourList->count--; + return true; +} + +static void neighbour_list_remove(rct_neighbour_list *neighbourList, int index) +{ + int itemsRemaining = neighbourList->count - index - 1; + if (itemsRemaining > 0) { + memmove(&neighbourList->items[index], &neighbourList->items[index + 1], sizeof(rct_neighbour) * itemsRemaining); + } + neighbourList->count--; +} + +static void neighbour_list_sort(rct_neighbour_list *neighbourList) +{ + qsort(neighbourList->items, neighbourList->count, sizeof(rct_neighbour), rct_neighbour_compare); +} + +static rct_map_element *footpath_get_element(int x, int y, int z0, int z1, int direction) +{ + rct_map_element *mapElement; + int slope; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH) + continue; + + if (z1 == mapElement->base_height) { + if (footpath_element_is_sloped(mapElement)) { + slope = footpath_element_get_slope_direction(mapElement); + if (slope != direction) + break; + } + return mapElement; + } + if (z0 == mapElement->base_height) { + if (!footpath_element_is_sloped(mapElement)) + break; + + slope = footpath_element_get_slope_direction(mapElement) ^ 2; + if (slope != direction) + break; + + return mapElement; + } + } while (!map_element_is_last_for_tile(mapElement++)); + return NULL; +} + +static bool sub_footpath_disconnect_queue_from_path(int x, int y, rct_map_element *mapElement, int action, int direction) { + if (((mapElement->properties.path.edges & (1 << direction)) == 0) ^ (action < 0)) + return false; + if ((action < 0) && fence_in_the_way(x, y, mapElement->base_height, mapElement->clearance_height, direction)) + return false; + + int x1 = x + TileDirectionDelta[direction].x; + int y1 = y + TileDirectionDelta[direction].y; + int z = mapElement->base_height; + rct_map_element *otherMapElement = footpath_get_element(x1, y1, z - 2, z, direction); + if (otherMapElement != NULL && !footpath_element_is_queue(otherMapElement)) { + mapElement->properties.path.type &= 0xFC; + if (action > 0) { + mapElement->properties.path.edges &= ~(1 << direction); + otherMapElement->properties.path.edges &= ~(1 << ((direction + 2) & 3)); + if (action >= 2) mapElement->properties.path.type |= direction; + } + else if (action < 0) { + mapElement->properties.path.edges |= (1 << direction); + otherMapElement->properties.path.edges |= (1 << ((direction + 2) & 3)); + } + if (action != 0) map_invalidate_tile_full(x1, y1); + return true; + } + return false; +} + +static bool footpath_disconnect_queue_from_path(int x, int y, rct_map_element *mapElement, int action) { + if (!footpath_element_is_queue(mapElement)) return false; + + if (footpath_element_is_sloped(mapElement)) return false; + + uint8 c = RCT2_ADDRESS(0x0098D7F0, uint8)[mapElement->properties.path.edges & 0x0F]; + if ((action < 0) ? (c >= 2) : (c < 2)) return false; + + if (action < 0) { + if (sub_footpath_disconnect_queue_from_path(x, y, mapElement, action, mapElement->properties.path.type & 3)) + return true; + } + + for (int direction = 0; direction < 4; direction++) { + if ((action < 0) && (direction == (mapElement->properties.path.type & 3))) continue; + if (sub_footpath_disconnect_queue_from_path(x, y, mapElement, action, direction)) + return true; + } + + return false; +} + +static bool footpath_is_queue_connected_to_path(int x, int y, rct_map_element *mapElement, int direction) +{ + if (!footpath_element_is_queue(mapElement)) return false; + if (!(mapElement->properties.path.edges & (1 << direction))) return false; + + x += TileDirectionDelta[direction].x; + y += TileDirectionDelta[direction].y; + mapElement = map_get_path_element_at(x / 32, y / 32, mapElement->base_height); + if (mapElement == NULL) return false; + if (footpath_element_is_queue(mapElement)) return false; + if (mapElement->properties.path.edges & ((1 << direction) ^ 2)) return true; + return false; +} + +/** + * + * rct2: 0x006A6D7E + */ +static void loc_6A6D7E( + int initialX, int initialY, int z, int direction, rct_map_element *initialMapElement, + int flags, bool query, rct_neighbour_list *neighbourList +) { + int x = initialX + TileDirectionDelta[direction].x; + int y = initialY + TileDirectionDelta[direction].y; + if (((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode) && map_is_edge(x, y)) { + if (query) { + neighbour_list_push(neighbourList, 7, direction, 255); + } + } else { + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_PATH: + if (z == mapElement->base_height) { + if (footpath_element_is_sloped(mapElement) && footpath_element_get_slope_direction(mapElement) != direction) { + return; + } else { + goto loc_6A6F1F; + } + } + if (z - 2 == mapElement->base_height) { + if (!footpath_element_is_sloped(mapElement) || footpath_element_get_slope_direction(mapElement) != (direction ^ 2)) { + return; + } + goto loc_6A6F1F; + } + break; + case MAP_ELEMENT_TYPE_TRACK: + if (z == mapElement->base_height) { + rct_ride *ride = GET_RIDE(mapElement->properties.track.ride_index); + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { + continue; + } + uint16 di = (mapElement->properties.track.sequence & 0x0F) | (mapElement->properties.track.type << 4); + if (!(RCT2_ADDRESS(0x0099CA64, uint8)[di] & (1 << 5))) { + return; + } + uint16 dx = ((direction - mapElement->type) & 3) ^ 2; + if (!(RCT2_ADDRESS(0x0099CA64, uint16)[di / 2] & (1 << dx))) { + return; + } + if (query) { + neighbour_list_push(neighbourList, 1, direction, mapElement->properties.track.ride_index); + } + goto loc_6A6FD2; + } + break; + case MAP_ELEMENT_TYPE_ENTRANCE: + if (z == mapElement->base_height) { + if (entrance_has_direction(mapElement, ((direction - mapElement->type) & 3) ^ 2)) { + if (query) { + neighbour_list_push(neighbourList, 8, direction, mapElement->properties.entrance.ride_index); + } else { + if (mapElement->properties.entrance.type != ENTRANCE_TYPE_PARK_ENTRANCE) { + sub_6A76E9(mapElement->properties.entrance.ride_index); + } + } + goto loc_6A6FD2; + } + } + break; + } + } while (!map_element_is_last_for_tile(mapElement++)); + return; + + loc_6A6F1F: + if (query) { + if (fence_in_the_way(x, y, mapElement->base_height, mapElement->clearance_height, direction ^ 2)) { + return; + } + if (footpath_element_is_queue(mapElement)) { + if (RCT2_ADDRESS(0x0098D7F0, uint8)[mapElement->properties.path.edges & 0x0F] < 2) { + neighbour_list_push(neighbourList, 4, direction, mapElement->properties.path.ride_index); + } else { + if (map_element_get_type(initialMapElement) == MAP_ELEMENT_TYPE_PATH && + footpath_element_is_queue(initialMapElement)) { + if (footpath_disconnect_queue_from_path(x, y, mapElement, 0)) { + neighbour_list_push(neighbourList, 3, direction, mapElement->properties.path.ride_index); + } + } + } + } else { + neighbour_list_push(neighbourList, 2, direction, 255); + } + } else { + footpath_disconnect_queue_from_path(x, y, mapElement, 1 + ((flags >> 6) & 1)); + mapElement->properties.path.edges |= (1 << (direction ^ 2)); + if (footpath_element_is_queue(mapElement)) { + sub_6A76E9(mapElement->properties.path.ride_index); + } + } + if (!(flags & 0x48)) { + footpath_interrupt_peeps(x, y, mapElement->base_height * 8); + } + map_invalidate_element(x, y, mapElement); + } + +loc_6A6FD2: + if (map_element_get_type(initialMapElement) == MAP_ELEMENT_TYPE_PATH) { + if (!query) { + initialMapElement->properties.path.edges |= (1 << direction); + map_invalidate_element(initialX, initialY, initialMapElement); + } + } +} + +static void loc_6A6C85( + int x, int y, int direction, rct_map_element *mapElement, + int flags, bool query, rct_neighbour_list *neighbourList +) { + if (query && fence_in_the_way(x, y, mapElement->base_height, mapElement->clearance_height, direction)) + return; + + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_ENTRANCE) { + if (!entrance_has_direction(mapElement, (direction - mapElement->type) & 3)) { + return; + } + } + + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_TRACK) { + rct_ride *ride = GET_RIDE(mapElement->properties.track.ride_index); + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { + return; + } + uint16 di = (mapElement->properties.track.sequence & 0x0F) | (mapElement->properties.track.type << 4); + if (!(RCT2_ADDRESS(0x0099CA64, uint8)[di] & (1 << 5))) { + return; + } + uint16 dx = (direction - mapElement->type) & 3; + if (!(RCT2_ADDRESS(0x0099CA64, uint16)[di / 2] & (1 << dx))) { + return; + } + } + + int z = mapElement->base_height; + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH) { + if (footpath_element_is_sloped(mapElement)) { + if ((footpath_element_get_slope_direction(mapElement) - direction) & 1) { + return; + } + if (footpath_element_get_slope_direction(mapElement) == direction) { + z += 2; + } + } + } + + loc_6A6D7E(x, y, z, direction, mapElement, flags, query, neighbourList); +} + +/** + * * rct2: 0x006A6C66 */ -void sub_6A6C66(int x, int y, rct_map_element *mapElement, int flags) +void footpath_connect_edges(int x, int y, rct_map_element *mapElement, int flags) { - RCT2_CALLPROC_X(0x006A6C66, x, flags, y, 0, (int)mapElement, 0, 0); + rct_neighbour_list neighbourList; + rct_neighbour neighbour; + + sub_6A759F(); + + neighbour_list_init(&neighbourList); + + sub_6A7642(x, y, mapElement); + for (int direction = 0; direction < 4; direction++) { + loc_6A6C85(x, y, direction, mapElement, flags, true, &neighbourList); + } + + neighbour_list_sort(&neighbourList); + + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH && footpath_element_is_queue(mapElement)) { + int rideIndex = -1; + for (int i = 0; i < neighbourList.count; i++) { + if (neighbourList.items[i].ride_index != 255) { + if (rideIndex == -1) { + rideIndex = neighbourList.items[i].ride_index; + } else if (rideIndex != neighbourList.items[i].ride_index) { + neighbour_list_remove(&neighbourList, i); + } + } + } + + neighbourList.count = min(neighbourList.count, 2); + } + + while (neighbour_list_pop(&neighbourList, &neighbour)) { + loc_6A6C85(x, y, neighbour.direction, mapElement, flags, false, NULL); + } + + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH) { + footpath_connect_corners(x, y, mapElement); + } } /** - * + * * rct2: 0x006A742F */ -void sub_6A742F(int rideIndex, int entranceIndex, int x, int y, rct_map_element *mapElement, int direction) +void footpath_chain_ride_queue(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); + rct_map_element *lastPathElement, *lastQueuePathElement; + int lastPathX, lastPathY, lastPathDirection; + + lastPathElement = NULL; + lastQueuePathElement = NULL; + int z = mapElement->base_height; + for (;;) { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH) { + lastPathElement = mapElement; + lastPathX = x; + lastPathY = y; + lastPathDirection = direction; + if (footpath_element_is_sloped(mapElement)) { + if (footpath_element_get_slope_direction(mapElement) == direction) { + z += 2; + } + } + } + + x += TileDirectionDelta[direction].x; + y += TileDirectionDelta[direction].y; + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (lastQueuePathElement == mapElement) + continue; + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH) + continue; + if (mapElement->base_height == z) { + if (footpath_element_is_sloped(mapElement)) { + if (footpath_element_get_slope_direction(mapElement) != direction) + break; + } + goto foundNextPath; + } + if (mapElement->base_height == z - 2) { + if (!footpath_element_is_sloped(mapElement)) + break; + + if ((footpath_element_get_slope_direction(mapElement) ^ 2) != direction) + break; + + z -= 2; + goto foundNextPath; + } + } while (!map_element_is_last_for_tile(mapElement++)); + break; + + foundNextPath: + if (footpath_element_is_queue(mapElement)) { + // Fix #2051: Stop queue paths that are already connected to two other tiles + // from connecting to the tile we are coming from. + int edges = mapElement->properties.path.edges; + int numEdges = bitcount(edges); + if (numEdges >= 2) { + int requiredEdgeMask = 1 << (direction ^ 2); + if (!(edges & requiredEdgeMask)) { + break; + } + } + + mapElement->properties.path.type &= ~(1 << 3); + mapElement->properties.path.edges |= (1 << (direction ^ 2)); + mapElement->properties.path.ride_index = rideIndex; + mapElement->properties.path.additions &= 0x8F; + mapElement->properties.path.additions |= (entranceIndex & 7) << 4; + + if (lastQueuePathElement == NULL) { + lastQueuePathElement = mapElement; + } + + if (mapElement->properties.path.edges & (1 << direction)) + continue; + + direction = (direction + 1) & 3; + if (mapElement->properties.path.edges & (1 << direction)) + continue; + + direction ^= 2; + if (mapElement->properties.path.edges & (1 << direction)) + continue; + } + break; + } + + if (rideIndex != 255 && lastPathElement != NULL) { + if (footpath_element_is_queue(lastPathElement)) { + lastPathElement->properties.path.type |= (1 << 3); + lastPathElement->type &= 0x3F; + lastPathElement->type |= lastPathDirection << 6; + + map_animation_create( + MAP_ANIMATION_TYPE_QUEUE_BANNER, + lastPathX, + lastPathY, + lastPathElement->base_height + ); + } + } + } /** - * + * * rct2: 0x006A759F */ void sub_6A759F() @@ -725,8 +1418,529 @@ void sub_6A759F() continue; direction = (mapElement->type & 3) ^ 2; - sub_6A742F(rideIndex, i, x << 5, y << 5, mapElement, direction); + footpath_chain_ride_queue(rideIndex, i, x << 5, y << 5, mapElement, direction); } while (!map_element_is_last_for_tile(mapElement++)); } } } + +/** + * + * rct2: 0x0069ADBD + */ +static void footpath_unown(int x, int y, rct_map_element *pathElement) +{ + int ownershipUnk = 0; + int z = pathElement->base_height; + rct_map_element *surfaceElement = map_get_surface_element_at(x >> 5, y >> 5); + if (surfaceElement->base_height != z) { + z -= 2; + if (surfaceElement->base_height != z) { + ownershipUnk = (surfaceElement->properties.surface.ownership & 0xCF) >> 4; + } + } + map_buy_land_rights(x, y, x, y, 6, 1); +} + +bool get_next_direction(int edges, int *direction) +{ + int index = bitscanforward(edges); + if (index == -1) + return false; + + *direction = index; + return true; +} + +/** + * + * rct2: 0x0069AC1A + */ +int footpath_is_connected_to_map_edge_recurse( + int x, int y, int z, int direction, int flags, + int level, int distanceFromJunction, int junctionTolerance +) { + rct_map_element *mapElement; + int edges, slopeDirection; + + x += TileDirectionDelta[direction].x; + y += TileDirectionDelta[direction].y; + if (++level > 250) + return FOOTPATH_SEARCH_TOO_COMPLEX; + + // Check if we are at edge of map + if (x < 32 || y < 32) + return FOOTPATH_SEARCH_SUCCESS; + if (x >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) || y >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16)) + return FOOTPATH_SEARCH_SUCCESS; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH) + continue; + + if ( + footpath_element_is_sloped(mapElement) && + (slopeDirection = footpath_element_get_slope_direction(mapElement)) != direction + ) { + if ((slopeDirection ^ 2) != direction) continue; + if (mapElement->base_height + 2 != z) continue; + } else if (mapElement->base_height != z) { + continue; + } + + if (mapElement->type & RCT2_GLOBAL(0x00F1AEE0, uint8)) continue; + + if (flags & 0x20) { + footpath_unown(x, y, mapElement); + } + edges = mapElement->properties.path.edges & 0x0F; + direction ^= 2; + if (!(flags & 0x80)) { + if (mapElement[1].type == MAP_ELEMENT_TYPE_BANNER) { + for (int i = 1; i < 4; i++) { + if (map_element_is_last_for_tile(&mapElement[i - 1])) break; + if (mapElement[i].type != MAP_ELEMENT_TYPE_BANNER) break; + edges &= mapElement[i].properties.banner.flags; + } + } + if (mapElement[2].type == MAP_ELEMENT_TYPE_BANNER && mapElement[1].type != MAP_ELEMENT_TYPE_PATH) { + for (int i = 1; i < 6; i++) { + if (map_element_is_last_for_tile(&mapElement[i - 1])) break; + if (mapElement[i].type != MAP_ELEMENT_TYPE_BANNER) break; + edges &= mapElement[i].properties.banner.flags; + } + } + } + goto searchFromFootpath; + } while (!map_element_is_last_for_tile(mapElement++)); + return level == 1 ? FOOTPATH_SEARCH_NOT_FOUND : FOOTPATH_SEARCH_INCOMPLETE; + +searchFromFootpath: + // Exclude direction we came from + z = mapElement->base_height; + edges &= ~(1 << direction); + + // Find next direction to go + if (!get_next_direction(edges, &direction)) { + return FOOTPATH_SEARCH_INCOMPLETE; + } + + edges &= ~(1 << direction); + if (edges == 0) { + // Only possible direction to go + if (footpath_element_is_sloped(mapElement) && footpath_element_get_slope_direction(mapElement) == direction) { + z += 2; + } + return footpath_is_connected_to_map_edge_recurse( + x, y, z, direction, flags, + level, distanceFromJunction + 1, junctionTolerance + ); + } else { + // We have reached a junction + if (distanceFromJunction != 0) { + junctionTolerance--; + } + junctionTolerance--; + if (junctionTolerance < 0) { + return FOOTPATH_SEARCH_TOO_COMPLEX; + } + + do { + edges &= ~(1 << direction); + if (footpath_element_is_sloped(mapElement) && footpath_element_get_slope_direction(mapElement) == direction) { + z += 2; + } + int result = footpath_is_connected_to_map_edge_recurse(x, y, z, direction, flags, level, 0, junctionTolerance); + if (result == FOOTPATH_SEARCH_SUCCESS) { + return result; + } + } while (get_next_direction(edges, &direction)); + + return FOOTPATH_SEARCH_INCOMPLETE; + } +} + +int footpath_is_connected_to_map_edge(int x, int y, int z, int direction, int flags) +{ + RCT2_GLOBAL(0x00F1AEE0, uint8) = 1; + return footpath_is_connected_to_map_edge_recurse(x, y, z, direction, flags, 0, 0, 16); +} + +bool footpath_element_is_sloped(rct_map_element *mapElement) +{ + return mapElement->properties.path.type & 4; +} + +int footpath_element_get_slope_direction(rct_map_element *mapElement) +{ + return mapElement->properties.path.type & 3; +} + +bool footpath_element_is_queue(rct_map_element *mapElement) +{ + return mapElement->type & 1; +} + +bool footpath_element_is_wide(rct_map_element *mapElement) +{ + return mapElement->type & 2; +} + +/** +* +* rct2: 0x006A8B12 +* clears the wide footpath flag for all footpaths +* at location +*/ +static void footpath_clear_wide(int x, int y) +{ + 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; + mapElement->type &= ~0x2; + } while (!map_element_is_last_for_tile(mapElement++)); +} + +/** +* +* rct2: 0x006A8ACF +* returns footpath element if it can be made wide +* returns NULL if it can not be made wide +*/ +static rct_map_element* footpath_can_be_wide(int x, int y, uint8 height) +{ + 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; + if (height != mapElement->base_height) + continue; + if (footpath_element_is_queue(mapElement)) + continue; + if (footpath_element_is_sloped(mapElement)) + continue; + return mapElement; + } while (!map_element_is_last_for_tile(mapElement++)); + + return NULL; +} + + +/** +* +* rct2: 0x006A87BB +*/ +void footpath_update_path_wide_flags(int x, int y) +{ + if (x < 0x20) + return; + if (y < 0x20) + return; + if (x > 0x1FDF) + return; + if (y > 0x1FDF) + return; + + footpath_clear_wide(x, y); + x += 0x20; + footpath_clear_wide(x, y); + y += 0x20; + footpath_clear_wide(x, y); + x -= 0x20; + footpath_clear_wide(x, y); + y -= 0x20; + + if (!(x & 0xE0)) + return; + if (!(y & 0xE0)) + return; + + 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; + + if (footpath_element_is_queue(mapElement)) + continue; + + if (footpath_element_is_sloped(mapElement)) + continue; + + uint8 height = mapElement->base_height; + + // pathList is a list of elements, set by sub_6A8ACF adjacent to x,y + // Spanned from 0x00F3EFA8 to 0x00F3EFC7 (8 elements) in the original + rct_map_element *pathList[8]; + + x -= 0x20; + y -= 0x20; + pathList[0] = footpath_can_be_wide(x, y, height); + y += 0x20; + pathList[1] = footpath_can_be_wide(x, y, height); + y += 0x20; + pathList[2] = footpath_can_be_wide(x, y, height); + x += 0x20; + pathList[3] = footpath_can_be_wide(x, y, height); + x += 0x20; + pathList[4] = footpath_can_be_wide(x, y, height); + y -= 0x20; + pathList[5] = footpath_can_be_wide(x, y, height); + y -= 0x20; + pathList[6] = footpath_can_be_wide(x, y, height); + x -= 0x20; + pathList[7] = footpath_can_be_wide(x, y, height); + y += 0x20; + + uint8 F3EFA5 = 0; + if (mapElement->properties.path.edges & 8) { + F3EFA5 |= 0x80; + if (pathList[7] != NULL) { + if (footpath_element_is_wide(pathList[7])) { + F3EFA5 &= ~0x80; + } + } + } + + if (mapElement->properties.path.edges & 1) { + F3EFA5 |= 0x2; + if (pathList[1] != NULL) { + if (footpath_element_is_wide(pathList[1])) { + F3EFA5 &= ~0x2; + } + } + } + + if (mapElement->properties.path.edges & 2) { + F3EFA5 |= 0x8; + if (pathList[3] != NULL) { + if (footpath_element_is_wide(pathList[3])) { + F3EFA5 &= ~0x8; + } + } + } + + if (mapElement->properties.path.edges & 4) { + F3EFA5 |= 0x20; + if (pathList[5] != NULL) { + if (footpath_element_is_wide(pathList[5])) { + F3EFA5 &= ~0x20; + } + } + } + + if ((F3EFA5 & 0x80) && (pathList[7] != NULL) && !(footpath_element_is_wide(pathList[7]))) { + if ((F3EFA5 & 2) && + (pathList[0] != NULL) && (!footpath_element_is_wide(pathList[0])) && + ((pathList[0]->properties.path.edges & 6) == 6) && // N E + (pathList[1] != NULL) && (!footpath_element_is_wide(pathList[1]))) { + F3EFA5 |= 0x1; + } + + if ((F3EFA5 & 0x20) && + (pathList[6] != NULL) && (!footpath_element_is_wide(pathList[6])) && + ((pathList[6]->properties.path.edges & 3) == 3) && // N W + (pathList[5] != NULL) && (!footpath_element_is_wide(pathList[5]))) { + F3EFA5 |= 0x40; + } + } + + + if ((F3EFA5 & 0x8) && (pathList[3] != NULL) && !(pathList[3]->type & 2)) { + if ((F3EFA5 & 2) && + (pathList[2] != NULL) && (!footpath_element_is_wide(pathList[2])) && + ((pathList[2]->properties.path.edges & 0xC) == 0xC) && + (pathList[1] != NULL) && (!footpath_element_is_wide(pathList[1]))) { + F3EFA5 |= 0x4; + } + + if ((F3EFA5 & 0x20) && + (pathList[4] != NULL) && (!footpath_element_is_wide(pathList[4])) && + ((pathList[4]->properties.path.edges & 9) == 9) && + (pathList[5] != NULL) && (!footpath_element_is_wide(pathList[5]))) { + F3EFA5 |= 0x10; + } + } + + if ((F3EFA5 & 0x80) && (F3EFA5 & (0x40 | 0x1))) + F3EFA5 &= ~0x80; + + if ((F3EFA5 & 0x2) && (F3EFA5 & (0x4 | 0x1))) + F3EFA5 &= ~0x2; + + if ((F3EFA5 & 0x8) && (F3EFA5 & (0x10 | 0x4))) + F3EFA5 &= ~0x8; + + if ((F3EFA5 & 0x20) && (F3EFA5 & (0x40 | 0x10))) + F3EFA5 &= ~0x20; + + if (!(F3EFA5 & (0x2 | 0x8 | 0x20 | 0x80))) { + uint8 e = mapElement->properties.path.edges; + if ((e != 0xAF) && (e != 0x5F) && (e != 0xEF)) + mapElement->type |= 2; + } + } while (!map_element_is_last_for_tile(mapElement++)); +} + + +/** + * + * rct2: 0x006A76E9 + */ +void sub_6A76E9(int rideIndex) +{ + if (rideIndex == 255) + return; + + *(RCT2_GLOBAL(0x00F3EFF4, uint8*)) = rideIndex; + RCT2_GLOBAL(0x00F3EFF4, uint8*)++; +} + +/** + * + * rct2: 0x006A7642 + */ +void sub_6A7642(int x, int y, rct_map_element *mapElement) +{ + int elementType = map_element_get_type(mapElement); + switch (elementType) { + case MAP_ELEMENT_TYPE_PATH: + if (footpath_element_is_queue(mapElement)) { + sub_6A76E9(mapElement->properties.path.ride_index); + for (int direction = 0; direction < 4; direction++) { + if (mapElement->properties.path.edges & (1 << direction)) { + footpath_chain_ride_queue(255, 0, x, y, mapElement, direction); + } + } + mapElement->properties.path.ride_index = 255; + } + break; + case MAP_ELEMENT_TYPE_ENTRANCE: + if (mapElement->properties.entrance.type == ENTRANCE_TYPE_RIDE_ENTRANCE) { + sub_6A76E9(mapElement->properties.entrance.ride_index); + footpath_chain_ride_queue(255, 0, x, y, mapElement, (mapElement->type & MAP_ELEMENT_DIRECTION_MASK) ^ 2); + } + break; + } +} + +/** + * + * rct2: 0x006A6B7F + */ +static void footpath_remove_edges_towards_here(int x, int y, int z, int direction, rct_map_element *mapElement, bool isQueue) +{ + int d; + + if (footpath_element_is_queue(mapElement)) { + sub_6A76E9(mapElement->properties.path.ride_index); + } + + d = direction ^ 2; + mapElement->properties.path.edges &= ~(1 << d); + d = ((d - 1) & 3) + 4; + mapElement->properties.path.edges &= ~(1 << d); + d = (((d - 4) + 1) & 3) + 4; + mapElement->properties.path.edges &= ~(1 << d); + map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + + if (isQueue) footpath_disconnect_queue_from_path(x, y, mapElement, -1); + + direction = (direction + 1) & 3; + x += TileDirectionDelta[direction].x; + y += TileDirectionDelta[direction].y; + + 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 (footpath_element_is_sloped(mapElement)) + break; + + d = ((direction + 1) & 3) + 4; + mapElement->properties.path.edges &= ~(1 << d); + map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + break; + } while (!map_element_is_last_for_tile(mapElement++)); +} + +/** + * + * rct2: 0x006A6B14 + */ +static void footpath_remove_edges_towards(int x, int y, int z0, int z1, int direction, bool isQueue) +{ + rct_map_element *mapElement; + int slope; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH) + continue; + + if (z1 == mapElement->base_height) { + if (footpath_element_is_sloped(mapElement)) { + slope = footpath_element_get_slope_direction(mapElement); + if (slope != direction) + break; + } + footpath_remove_edges_towards_here(x, y, z1, direction, mapElement, isQueue); + break; + } + if (z0 == mapElement->base_height) { + if (!footpath_element_is_sloped(mapElement)) + break; + + slope = footpath_element_get_slope_direction(mapElement) ^ 2; + if (slope != direction) + break; + + footpath_remove_edges_towards_here(x, y, z1, direction, mapElement, isQueue); + break; + } + } while (!map_element_is_last_for_tile(mapElement++)); +} + +/** + * + * rct2: 0x006A6AA7 + * @param x x-coordinate in units (not tiles) + * @param y y-coordinate in units (not tiles) + */ +void footpath_remove_edges_at(int x, int y, rct_map_element *mapElement) +{ + rct_ride *ride; + int z0, z1, slope; + + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_TRACK) { + int rideIndex = mapElement->properties.track.ride_index; + ride = GET_RIDE(rideIndex); + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) + return; + } + + sub_6A7642(x, y, mapElement); + + for (int direction = 0; direction < 4; direction++) { + z1 = mapElement->base_height; + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH) { + if (footpath_element_is_sloped(mapElement)) { + slope = footpath_element_get_slope_direction(mapElement); + if ((slope - direction) & 1) + continue; + + z1 += slope == direction ? 2 : 0; + } + } + z0 = z1 - 2; + footpath_remove_edges_towards(x + TileDirectionDelta[direction].x, y + TileDirectionDelta[direction].y, + z0, z1, direction, footpath_element_is_queue(mapElement)); + } + + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH) + mapElement->properties.path.edges = 0; +} diff --git a/src/world/footpath.h b/src/world/footpath.h index 047773a653..05c5ad43ad 100644 --- a/src/world/footpath.h +++ b/src/world/footpath.h @@ -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 . *****************************************************************************/ @@ -37,9 +37,20 @@ typedef struct { uint8 flags; // 0x0B } rct_path_type; +enum { + FOOTPATH_SEARCH_SUCCESS, + FOOTPATH_SEARCH_NOT_FOUND, + FOOTPATH_SEARCH_INCOMPLETE, + FOOTPATH_SEARCH_TOO_COMPLEX +}; + #define g_pathTypeEntries ((rct_path_type**)object_entry_groups[OBJECT_TYPE_PATHS].chunks) +extern const rct_xy16 word_981D6C[4]; + +money32 footpath_remove_real(int x, int y, int z, int flags); void game_command_place_footpath(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_place_footpath_from_track(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); @@ -49,7 +60,19 @@ 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 footpath_connect_edges(int x, int y, rct_map_element *mapElement, int flags); void sub_6A759F(); +bool fence_in_the_way(int x, int y, int z0, int z1, int direction); +void footpath_chain_ride_queue(int rideIndex, int entranceIndex, int x, int y, rct_map_element *mapElement, int direction); +void footpath_update_path_wide_flags(int x, int y); + +void footpath_bridge_get_info_from_pos(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement); + +int footpath_is_connected_to_map_edge(int x, int y, int z, int direction, int flags); +bool footpath_element_is_sloped(rct_map_element *mapElement); +int footpath_element_get_slope_direction(rct_map_element *mapElement); +bool footpath_element_is_queue(rct_map_element *mapElement); +bool footpath_element_is_wide(rct_map_element *mapElement); +void footpath_remove_edges_at(int x, int y, rct_map_element *mapElement); #endif diff --git a/src/world/fountain.c b/src/world/fountain.c index c034d2fc46..3c720c9474 100644 --- a/src/world/fountain.c +++ b/src/world/fountain.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 . *****************************************************************************/ @@ -216,7 +216,7 @@ void jumping_fountain_update(rct_jumping_fountain *jumpingFountain) if (original_var_26a <= 255 - 160) return; - sub_6EC60B((rct_sprite*)jumpingFountain); + invalidate_sprite_0((rct_sprite*)jumpingFountain); jumpingFountain->var_26b++; switch (jumpingFountain->misc_identifier) { @@ -279,7 +279,7 @@ static void jumping_fountain_continue(rct_jumping_fountain *jumpingFountain) jumping_fountain_split(jumpingFountain, x, y, z, availableDirections); return; } - + jumping_fountain_random(jumpingFountain, x, y, z, availableDirections); } @@ -310,7 +310,7 @@ static bool is_jumping_fountain(int type, int x, int y, int z) return true; } while (!map_element_is_last_for_tile(mapElement++)); - + return false; } @@ -340,7 +340,7 @@ static void jumping_fountain_goto_edge(rct_jumping_fountain *jumpingFountain, in jumping_fountain_split(jumpingFountain, x, y, z, availableDirections); return; } - + direction = randomIndex & 7; while (!(availableDirections & (1 << direction))) direction = (direction + 1) & 7; diff --git a/src/world/fountain.h b/src/world/fountain.h index d7b63fe148..68f04449a6 100644 --- a/src/world/fountain.h +++ b/src/world/fountain.h @@ -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 . *****************************************************************************/ diff --git a/src/world/map.c b/src/world/map.c index 6de77a8521..6af8a11c14 100644 --- a/src/world/map.c +++ b/src/world/map.c @@ -8,23 +8,30 @@ * 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 "../cheats.h" +#include "../config.h" +#include "../cursors.h" #include "../game.h" #include "../interface/window.h" #include "../localisation/date.h" #include "../localisation/localisation.h" #include "../management/finance.h" +#include "../openrct2.h" +#include "../ride/ride_data.h" +#include "../ride/track.h" +#include "../ride/track_data.h" #include "../scenario.h" #include "banner.h" #include "climate.h" @@ -33,9 +40,8 @@ #include "map_animation.h" #include "park.h" #include "scenery.h" -#include "../cheats.h" -#include "../config.h" +/* Replaces 0x00993CCC & 0x00993CCE */ const rct_xy16 TileDirectionDelta[] = { { -32, 0 }, { 0, +32 }, @@ -47,25 +53,30 @@ const rct_xy16 TileDirectionDelta[] = { { -32, -32 } }; +rct_map_element *gMapElements = (rct_map_element*)RCT2_ADDRESS_MAP_ELEMENTS; +rct_map_element **gMapElementTilePointers = (rct_map_element**)RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS; rct_xy16 *gMapSelectionTiles = (rct_xy16*)0x009DE596; +rct2_peep_spawn *gPeepSpawns = (rct2_peep_spawn*)RCT2_ADDRESS_PEEP_SPAWNS; -bool LandPaintMode; +bool gLandMountainMode; +bool gLandPaintMode; 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); +static void sub_68AE2A(int x, int y); +static void translate_3d_to_2d(int rotation, int *x, int *y); +static void map_obstruction_set_error_text(rct_map_element *mapElement); -void rotate_map_coordinates(sint16* x, sint16* y, uint8 rotation){ +void rotate_map_coordinates(sint16 *x, sint16 *y, int rotation) +{ int temp; - switch (rotation){ + + switch (rotation) { case MAP_ELEMENT_DIRECTION_WEST: break; case MAP_ELEMENT_DIRECTION_NORTH: @@ -85,6 +96,30 @@ void rotate_map_coordinates(sint16* x, sint16* y, uint8 rotation){ } } +rct_xy16 coordinate_3d_to_2d(const rct_xyz16* coordinate_3d, int rotation){ + rct_xy16 coordinate_2d; + + switch (rotation){ + case 0: + coordinate_2d.x = coordinate_3d->y - coordinate_3d->x; + coordinate_2d.y = (coordinate_3d->y + coordinate_3d->x) / 2 - coordinate_3d->z; + break; + case 1: + coordinate_2d.x = -coordinate_3d->y - coordinate_3d->x; + coordinate_2d.y = (coordinate_3d->y - coordinate_3d->x) / 2 - coordinate_3d->z; + break; + case 2: + coordinate_2d.x = -coordinate_3d->y + coordinate_3d->x; + coordinate_2d.y = (-coordinate_3d->y - coordinate_3d->x) / 2 - coordinate_3d->z; + break; + case 3: + coordinate_2d.x = coordinate_3d->y + coordinate_3d->x; + coordinate_2d.y = (-coordinate_3d->y + coordinate_3d->x) / 2 - coordinate_3d->z; + break; + } + return coordinate_2d; +} + void map_element_iterator_begin(map_element_iterator *it) { it->x = 0; @@ -127,14 +162,22 @@ void map_element_iterator_restart_for_tile(map_element_iterator *it) 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"); + 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); } +void map_set_tile_elements(int x, int y, rct_map_element *elements) +{ + if (x < 0 || y < 0 || x > 255 || y > 255) { + log_error("Trying to access element outside of range"); + return; + } + TILE_MAP_ELEMENT_POINTER(x + y * 256) = elements; +} + int map_element_is_last_for_tile(rct_map_element *element) { return element->flags & MAP_ELEMENT_FLAG_LAST_TILE; @@ -145,6 +188,11 @@ int map_element_get_type(rct_map_element *element) return element->type & MAP_ELEMENT_TYPE_MASK; } +int map_element_get_direction(rct_map_element *element) +{ + return element->type & MAP_ELEMENT_DIRECTION_MASK; +} + int map_element_get_terrain(rct_map_element *element) { int terrain = (element->properties.surface.terrain >> 5) & 7; @@ -211,7 +259,6 @@ rct_map_element* map_get_path_element_at(int x, int y, int z){ 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) @@ -224,8 +271,30 @@ rct_map_element* map_get_path_element_at(int x, int y, int z){ return NULL; } + +rct_map_element* map_get_banner_element_at(int x, int y, int z, uint8 position) { + rct_map_element *mapElement = map_get_first_element_at(x, y); + + if (mapElement == NULL) + return NULL; + + // Find the banner element at known z and position + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_BANNER) + continue; + if (mapElement->base_height != z) + continue; + if (mapElement->properties.banner.position != position) + continue; + + return mapElement; + } while (!map_element_is_last_for_tile(mapElement++)); + + return NULL; +} + /** - * + * * rct2: 0x0068AB4C */ void map_init(int size) @@ -253,21 +322,20 @@ void map_init(int size) } RCT2_GLOBAL(RCT2_ADDRESS_GRASS_SCENERY_TILEPOS, sint16) = 0; - _sub_6A876D_save_x = 0; - _sub_6A876D_save_y = 0; + RCT2_GLOBAL(0x013CE774, sint16) = 0; + RCT2_GLOBAL(0x013CE776, sint16) = 0; 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); - + map_remove_out_of_range_elements(); climate_reset(CLIMATE_WARM); } /** - * + * * rct2: 0x0068AFFD */ void map_update_tile_pointers() @@ -282,12 +350,11 @@ void map_update_tile_pointers() for (y = 0; y < 256; y++) { for (x = 0; x < 256; x++) { *tile++ = mapElement; - do { } while (!map_element_is_last_for_tile(mapElement++)); + while (!map_element_is_last_for_tile(mapElement++)); } } - // Possible next free map element - RCT2_GLOBAL(0x0140E9A4, rct_map_element*) = mapElement; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*) = mapElement; } /** @@ -303,7 +370,7 @@ int map_element_height(int x, int y) rct_map_element *mapElement; // Off the map - if (x >= 8192 || y >= 8192) + if ((unsigned)x >= 8192 || (unsigned)y >= 8192) return 16; // Truncate subtile coordinates @@ -464,23 +531,21 @@ void sub_68B089() if (mapElement == mapElementFirst) return; - // + // TILE_MAP_ELEMENT_POINTER(i) = mapElement; do { *mapElement = *mapElementFirst; mapElementFirst->base_height = 255; - mapElement++; mapElementFirst++; - } while (!map_element_is_last_for_tile(mapElement - 1)); + } while (!map_element_is_last_for_tile(mapElement++)); - // Update next free element? - mapElement = RCT2_GLOBAL(0x0140E9A4, rct_map_element*); + mapElement = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*); do { mapElement--; } while (mapElement->base_height == 255); mapElement++; - RCT2_GLOBAL(0x0140E9A4, rct_map_element*) = mapElement; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*) = mapElement; } @@ -520,20 +585,20 @@ int map_coord_is_connected(int x, int y, int z, uint8 faceDirection) * * rct2: 0x006A876D */ -void sub_6A876D() +void map_update_path_wide_flags() { int i, x, y; if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)) return; - // Presumebly sub_6A87BB is too computationally expensive to call for every + // Presumebly update_path_wide_flags is too computationally expensive to call for every // tile every update, so word_13CE774 and word_13CE776 store the x and y // progress. A maximum of 128 calls is done per update. - x = _sub_6A876D_save_x; - y = _sub_6A876D_save_y; + x = RCT2_GLOBAL(0x013CE774, sint16); + y = RCT2_GLOBAL(0x013CE776, sint16); for (i = 0; i < 128; i++) { - sub_6A87BB(x, y); + footpath_update_path_wide_flags(x, y); // Next x, y tile x += 32; @@ -544,17 +609,8 @@ void sub_6A876D() y = 0; } } - _sub_6A876D_save_x = x; - _sub_6A876D_save_y = y; -} - -/** - * - * rct2: 0x006A87BB - */ -static void sub_6A87BB(int x, int y) -{ - RCT2_CALLPROC_X(0x006A87BB, x, 0, y, 0, 0, 0, 0); + RCT2_GLOBAL(0x013CE774, sint16) = x; + RCT2_GLOBAL(0x013CE776, sint16) = y; } /** @@ -599,7 +655,7 @@ int map_is_location_owned(int x, int y, int z) } } - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 1729; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_LAND_NOT_OWNED_BY_PARK; return 0; } @@ -613,22 +669,26 @@ 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 == NULL) + return 0; if (mapElement->properties.surface.ownership & OWNERSHIP_OWNED) return 1; } - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 1729; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_LAND_NOT_OWNED_BY_PARK; return 0; } -/** - * - * rct2: 0x006ECB60 - * NOTE: x, y and z are in pixels, not tile units - */ -void map_invalidate_tile(int x, int y, int zLow, int zHigh) +bool map_is_location_owned_or_has_rights(int x, int y) { - RCT2_CALLPROC_X(0x006ECB60, x, 0, y, 0, zHigh, zLow, 0); + 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 & OWNERSHIP_OWNED) return true; + if (mapElement->properties.surface.ownership & OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED) return true; + } + return false; } /** @@ -642,23 +702,24 @@ void game_command_remove_scenery(int* eax, int* ebx, int* ecx, int* edx, int* es uint8 base_height = *edx; uint8 scenery_type = *edx >> 8; uint8 map_element_type = *ebx >> 8; + uint8 flags = *ebx & 0xFF; money32 cost; - + rct_scenery_entry *entry = g_smallSceneryEntries[scenery_type]; cost = entry->small_scenery.removal_price * 10; 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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint32) = x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint32) = y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint32) = base_height * 8; - if (!(*ebx & 0x40) && RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0 && !gConfigCheat.build_in_pause_mode) { + if (!(flags & GAME_COMMAND_FLAG_GHOST) && 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) && !(*ebx & 0x40) && !gSandboxMode) { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !(flags & GAME_COMMAND_FLAG_GHOST) && !gCheatsSandboxMode) { // 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) { @@ -669,26 +730,35 @@ void game_command_remove_scenery(int* eax, int* ebx, int* ecx, int* edx, int* es } // Check if the land is owned - if (!map_is_location_owned(x, y, RCT2_GLOBAL(0x009DEA62, uint32))){ + if (!map_is_location_owned(x, y, RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint32))){ *ebx = MONEY32_UNDEFINED; return; } } + bool sceneryFound = false; 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; - } + do { + if (map_element->type != map_element_type) + continue; + if (map_element->base_height != base_height) + continue; + if (map_element->properties.scenery.type != scenery_type) + continue; + if ((flags & GAME_COMMAND_FLAG_GHOST) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)) + continue; + + sceneryFound = true; + break; + } while (!map_element_is_last_for_tile(map_element++)); + + if (sceneryFound == false){ + *ebx = 0; + return; } // Remove element - if (*ebx & GAME_COMMAND_FLAG_APPLY) { + if (flags & GAME_COMMAND_FLAG_APPLY) { map_invalidate_tile_full(x, y); map_element_remove(map_element); } @@ -702,23 +772,24 @@ void game_command_remove_scenery(int* eax, int* ebx, int* ecx, int* edx, int* es void game_command_remove_large_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) { uint8 base_height = *edx; - uint8 scenerymultiple_index = *edx >> 8; + uint8 tileIndex = *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) { + uint8 flags = *ebx & 0xFF; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = z; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; + + if (!(flags & GAME_COMMAND_FLAG_GHOST) && 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; + bool element_found = false; 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) @@ -727,34 +798,32 @@ void game_command_remove_large_scenery(int* eax, int* ebx, int* ecx, int* edx, i if (map_element->base_height != base_height) continue; - if ((map_element->properties.scenerymultiple.type >> 10) != scenerymultiple_index) + if ((map_element->properties.scenerymultiple.type >> 10) != tileIndex) continue; if ((map_element->type & MAP_ELEMENT_DIRECTION_MASK) != map_element_direction) continue; - element_found = 1; + // If we are removing ghost elements + if((flags & GAME_COMMAND_FLAG_GHOST) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)) + continue; + + element_found = true; 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)){ + if (element_found == false){ *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 + rct_xyz16 firstTile = { + .x = scenery_entry->large_scenery.tiles[tileIndex].x_offset, + .y = scenery_entry->large_scenery.tiles[tileIndex].y_offset, + .z = (base_height * 8) - scenery_entry->large_scenery.tiles[tileIndex].z_offset }; rotate_map_coordinates(&firstTile.x, &firstTile.y, map_element_direction); @@ -762,6 +831,7 @@ void game_command_remove_large_scenery(int* eax, int* ebx, int* ecx, int* edx, i firstTile.x = x - firstTile.x; firstTile.y = y - firstTile.y; + bool calculate_cost = true; for (int i = 0; scenery_entry->large_scenery.tiles[i].x_offset != -1; i++){ rct_xyz16 currentTile = { @@ -776,7 +846,7 @@ void game_command_remove_large_scenery(int* eax, int* ebx, int* ecx, int* edx, i currentTile.y += firstTile.y; currentTile.z += firstTile.z; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode){ + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode){ if (!map_is_location_owned(currentTile.x, currentTile.y, currentTile.z)){ *ebx = MONEY32_UNDEFINED; return; @@ -784,11 +854,17 @@ void game_command_remove_large_scenery(int* eax, int* ebx, int* ecx, int* edx, i } // If not applying then no need to delete the actual element - if (!(*ebx & GAME_COMMAND_FLAG_APPLY)) + if (!(flags & GAME_COMMAND_FLAG_APPLY)) { + if (flags & (1 << 7)) { + if (map_element->flags & (1 << 6)) + calculate_cost = false; + map_element->flags |= (1 << 6); + } continue; - + } + rct_map_element* sceneryElement = map_get_first_element_at(currentTile.x / 32, currentTile.y / 32); - uint8 tile_not_found = 1; + element_found = false; do { if (map_element_get_type(sceneryElement) != MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) @@ -803,19 +879,24 @@ void game_command_remove_large_scenery(int* eax, int* ebx, int* ecx, int* edx, i if (sceneryElement->base_height != currentTile.z / 8) continue; + // If we are removing ghost elements + if ((flags & GAME_COMMAND_FLAG_GHOST) && !(sceneryElement->flags & MAP_ELEMENT_FLAG_GHOST)) + continue; + map_invalidate_tile_full(currentTile.x, currentTile.y); map_element_remove(sceneryElement); - tile_not_found = 0; + element_found = true; break; } while (!map_element_is_last_for_tile(sceneryElement++)); - if (tile_not_found){ + if (element_found == false){ 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){ + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY || + calculate_cost == false){ *ebx = 0; } return; @@ -831,38 +912,43 @@ void game_command_remove_banner(int* eax, int* ebx, int* ecx, int* edx, int* esi int y = *ecx; uint8 base_height = *edx; uint8 banner_position = *edx >> 8; + uint8 flags = *ebx & 0xFF; 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_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = z; + + if(!(flags & GAME_COMMAND_FLAG_GHOST) && 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)){ + + if(!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && !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; - } + + // Slight modification to the code so that it now checks height as well + // This was causing a bug with banners on two paths stacked. + rct_map_element* map_element = map_get_banner_element_at(x / 32, y / 32, base_height, banner_position); + if (map_element == NULL){ + *ebx = MONEY32_UNDEFINED; + return; } + rct_banner *banner = &gBanners[map_element->properties.banner.index]; - uint8 bannerType = banner->type; - if (*ebx & GAME_COMMAND_FLAG_APPLY) { + rct_scenery_entry *scenery_entry = g_bannerSceneryEntries[banner->type]; + + if (flags & GAME_COMMAND_FLAG_APPLY) { map_element_remove_banner_entry(map_element); - map_invalidate_tile(x, y, z, z + 32); + map_invalidate_tile_zoom1(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; } @@ -874,47 +960,48 @@ void game_command_remove_banner(int* eax, int* ebx, int* ecx, int* edx, int* esi */ 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; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; 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; + uint8 flags = *ebx & 0xFF; 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){ + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = z; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode){ 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)){ + // Previously it would do a search for type of bh (set from calling function) instead of just small scenery + // Unsure if this was a mistake. + rct_map_element* map_element = map_get_small_scenery_element_at(x, y, base_height, scenery_type); + + if (map_element == NULL) { *ebx = 0; return; } - if(*ebx & GAME_COMMAND_FLAG_APPLY){ + + if((flags & GAME_COMMAND_FLAG_GHOST) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)){ + *ebx = 0; + return; + } + + if(flags & 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; } @@ -924,7 +1011,7 @@ void game_command_set_scenery_colour(int* eax, int* ebx, int* ecx, int* edx, int */ 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; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; int x = *eax; int y = *ecx; uint8 map_element_direction = *edx; @@ -932,43 +1019,50 @@ void game_command_set_fence_colour(int* eax, int* ebx, int* ecx, int* edx, int* uint8 color1 = *ebx >> 8; uint8 color2 = *ebp; uint8 color3 = *ebp >> 8; + uint8 flags = *ebx & 0xFF; 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 { + + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = z; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && + !map_is_location_in_park(x, y) && + !gCheatsSandboxMode) { + *ebx = MONEY32_UNDEFINED; + return; } + + bool fence_found = false; + rct_map_element* map_element = map_get_fence_element_at(x, y, base_height, map_element_direction); + + if (map_element == NULL) { + *ebx = 0; + return; + } + + if ((flags & GAME_COMMAND_FLAG_GHOST) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)) { + *ebx = 0; + return; + } + + if(flags & GAME_COMMAND_FLAG_APPLY){ + rct_scenery_entry* scenery_entry = g_wallSceneryEntries[map_element->properties.fence.type]; + map_element->properties.fence.item[1] &= 0xE0; + map_element->properties.fence.item[1] |= color1; + map_element->properties.fence.item[1] &= 0x1F; + map_element->flags &= 0x9F; + 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_zoom1(x, y, z, z + 72); + } + + *ebx = 0; } /** @@ -977,113 +1071,80 @@ void game_command_set_fence_colour(int* eax, int* ebx, int* ecx, int* edx, int* */ 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; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; int x = *eax; int y = *ecx; uint8 map_element_direction = *ebx >> 8; + uint8 flags = *ebx & 0xFF; uint8 base_height = *edx; - uint8 scenerymultiple_index = *edx >> 8; + uint8 tileIndex = *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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = z; + rct_map_element *map_element = map_get_large_scenery_segment(x, y, base_height, map_element_direction, tileIndex); - 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)){ + if(map_element == NULL){ *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; + + if((flags & GAME_COMMAND_FLAG_GHOST) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)){ + *ebx = 0; + return; } - 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)){ + + rct_scenery_entry* scenery_entry = RCT2_ADDRESS(RCT2_ADDRESS_LARGE_SCENERY_ENTRIES, rct_scenery_entry*)[map_element->properties.scenerymultiple.type & 0x3FF]; + + // Work out the base tile coordinates (Tile with index 0) + rct_xyz16 baseTile = { + .x = scenery_entry->large_scenery.tiles[tileIndex].x_offset, + .y = scenery_entry->large_scenery.tiles[tileIndex].y_offset, + .z = (base_height * 8) - scenery_entry->large_scenery.tiles[tileIndex].z_offset + }; + rotate_map_coordinates(&baseTile.x, &baseTile.y, map_element_direction); + baseTile.x = x - baseTile.x; + baseTile.y = y - baseTile.y; + + for (int i = 0; scenery_entry->large_scenery.tiles[i].x_offset != -1; ++i) { + assert(i < 256); + + // Work out the current tile coordinates + 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 += baseTile.x; + currentTile.y += baseTile.y; + currentTile.z += baseTile.z; + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode){ + if (!map_is_location_owned(currentTile.x, currentTile.y, currentTile.z)){ *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); + if(flags & GAME_COMMAND_FLAG_APPLY){ + rct_map_element* mapElement = map_get_large_scenery_segment( + currentTile.x, + currentTile.y, + base_height, + map_element_direction, + i); + + mapElement->properties.scenerymultiple.colour[0] &= 0xE0; + mapElement->properties.scenerymultiple.colour[0] |= color1; + mapElement->properties.scenerymultiple.colour[1] &= 0xE0; + mapElement->properties.scenerymultiple.colour[1] |= color2; + + map_invalidate_tile_full(currentTile.x, currentTile.y); } - - i++; } *ebx = 0; } @@ -1094,18 +1155,18 @@ void game_command_set_large_scenery_colour(int* eax, int* ebx, int* ecx, int* ed */ 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; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; 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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = z; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode){ + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode){ if (!map_is_location_owned(x, y, z - 16)){ *ebx = MONEY32_UNDEFINED; return; @@ -1114,34 +1175,33 @@ void game_command_set_banner_colour(int* eax, int* ebx, int* ecx, int* edx, int* 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; - } + + bool found = false; + do { + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_BANNER) + continue; + + if (map_element->properties.banner.position != banner_position) + continue; + + found = true; + break; + } while (!map_element_is_last_for_tile(map_element++)); + + if (found == false){ + *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); + map_invalidate_tile_zoom1(x, y, z, z + 32); } - - *ebx = 0; -} -money32 sub_6A67C0(int x, int y, int z, int flags) -{ - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = x * 32; - ecx = y * 32; - ebx = flags & 0xFF; - edx = z & 0xFF; - RCT2_CALLFUNC_X(0x006A67C0, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - return ebx; + *ebx = 0; } // This will cause clear scenery to remove paths @@ -1152,7 +1212,7 @@ money32 sub_6A67C0(int x, int y, int z, int flags) * * rct2: 0x0068DFE4 */ -money32 map_clear_scenery_from_tile(int x, int y, int flags) +money32 map_clear_scenery_from_tile(int x, int y, int clear, int flags) { int type; money32 cost, totalCost; @@ -1166,8 +1226,14 @@ restart_from_beginning: type = map_element_get_type(mapElement); switch (type) { case MAP_ELEMENT_TYPE_PATH: - if (gClearFootpath) { - cost = sub_6A67C0(x, y, mapElement->base_height, flags); + if (clear & (1 << 2)) { + int eax = x * 32; + int ebx = flags; + int ecx = y * 32; + int edx = mapElement->base_height; + int edi = 0, ebp = 0; + cost = game_do_command(eax, ebx, ecx, edx, GAME_COMMAND_REMOVE_PATH, edi, ebp); + if (cost == MONEY32_UNDEFINED) return MONEY32_UNDEFINED; @@ -1176,14 +1242,13 @@ restart_from_beginning: goto restart_from_beginning; } break; case MAP_ELEMENT_TYPE_SCENERY: - if (gClearSmallScenery) { + if (clear & (1 << 0)) { 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; + int edi = 0, ebp = 0; + cost = game_do_command(eax, ebx, ecx, edx, GAME_COMMAND_REMOVE_SCENERY, edi, ebp); if (cost == MONEY32_UNDEFINED) return MONEY32_UNDEFINED; @@ -1194,14 +1259,13 @@ restart_from_beginning: } break; case MAP_ELEMENT_TYPE_FENCE: - if (gClearSmallScenery) { + if (clear & (1 << 0)) { 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; + int edi = 0, ebp = 0; + cost = game_do_command(eax, ebx, ecx, edx, GAME_COMMAND_REMOVE_FENCE, edi, ebp); if (cost == MONEY32_UNDEFINED) return MONEY32_UNDEFINED; @@ -1212,14 +1276,13 @@ restart_from_beginning: } break; case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: - if (gClearLargeScenery) { + if (clear & (1 << 1)) { 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; + int edi = 0, ebp = 0; + cost = game_do_command(eax, ebx | (1 << 7), ecx, edx, GAME_COMMAND_REMOVE_LARGE_SCENERY, edi, ebp); if (cost == MONEY32_UNDEFINED) return MONEY32_UNDEFINED; @@ -1236,37 +1299,65 @@ restart_from_beginning: return totalCost; } -money32 map_clear_scenery(int x0, int y0, int x1, int y1, int flags) +/* Function to clear the flag that is set to prevent cost duplication + * when using the clear scenery tool with large scenery. + */ +void map_reset_clear_large_scenery_flag(){ + rct_map_element* mapElement; + // TODO: Improve efficiency of this + for (int y = 0; y <= 255; y++) { + for (int x = 0; x <= 255; x++) { + mapElement = map_get_first_element_at(x, y); + do { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) { + mapElement->flags &= ~(1 << 6); + } + } while (!map_element_is_last_for_tile(mapElement++)); + } + } +} + +money32 map_clear_scenery(int x0, int y0, int x1, int y1, int clear, int flags) { int x, y, z; money32 totalCost, cost; + bool noValidTiles; RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; 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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = z; 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)); + noValidTiles = true; totalCost = 0; 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; - - totalCost += cost; + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || gCheatsSandboxMode || map_is_location_owned_or_has_rights(x, y)) { + cost = map_clear_scenery_from_tile(x / 32, y / 32, clear, flags); + if (cost != MONEY32_UNDEFINED) { + noValidTiles = false; + totalCost += cost; + } + } else { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_LAND_NOT_OWNED_BY_PARK; + } } } - return totalCost; + if (clear & (1 << 1)) { + map_reset_clear_large_scenery_flag(); + } + + return noValidTiles ? MONEY32_UNDEFINED : totalCost; } /** @@ -1280,6 +1371,7 @@ void game_command_clear_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi (sint16)(*ecx & 0xFFFF), (sint16)(*edi & 0xFFFF), (sint16)(*ebp & 0xFFFF), + *edx, *ebx & 0xFF ); } @@ -1287,7 +1379,7 @@ void game_command_clear_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi /* 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; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; x0 = max(x0, 32); y0 = max(y0, 32); @@ -1301,9 +1393,9 @@ money32 map_change_surface_style(int x0, int y0, int x1, int y1, uint8 surfaceSt int heightMid = map_element_height(xMid, yMid); - RCT2_GLOBAL(0x009DEA5E, uint16) = xMid; - RCT2_GLOBAL(0x009DEA60, uint16) = yMid; - RCT2_GLOBAL(0x009DEA62, uint16) = heightMid; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = xMid; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = yMid; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = heightMid; RCT2_GLOBAL(0x009E32B4, uint32) = 0; money32 cost = 0; @@ -1313,7 +1405,7 @@ money32 map_change_surface_style(int x0, int y0, int x1, int y1, uint8 surfaceSt 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) { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && 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; } @@ -1323,10 +1415,10 @@ money32 map_change_surface_style(int x0, int y0, int x1, int y1, uint8 surfaceSt if (x > 0x1FFF) continue; if (y > 0x1FFF) continue; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode) { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) { 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){ @@ -1347,7 +1439,7 @@ money32 map_change_surface_style(int x0, int y0, int x1, int y1, uint8 surfaceSt 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); + footpath_remove_litter(x, y, map_element_height(x, y)); } } } @@ -1373,7 +1465,7 @@ money32 map_change_surface_style(int x0, int y0, int x1, int y1, uint8 surfaceSt } } } - + if (flags & 1) { if (!(mapElement->properties.surface.terrain & MAP_ELEMENT_SURFACE_TERRAIN_MASK)) { if (!(mapElement->type & MAP_ELEMENT_DIRECTION_MASK)) { @@ -1424,14 +1516,14 @@ const uint8 map_element_lower_styles[5][32] = { { 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) +static money32 map_set_land_height(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_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) { 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; @@ -1461,7 +1553,7 @@ static money32 sub_66397F(int flags, int x, int y, int height, int style, int se return MONEY32_UNDEFINED; } - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode) { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode) { if (!map_is_location_in_park(x, y)) { return MONEY32_UNDEFINED; } @@ -1472,12 +1564,72 @@ static money32 sub_66397F(int flags, int x, int y, int height, int style, int se return ebx; } +void game_command_set_land_height(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + *ebx = map_set_land_height( + *ebx & 0xFF, + *eax & 0xFFFF, + *ecx & 0xFFFF, + *edx & 0xFF, + (*edx >> 8) & 0xFF, + *edi >> 5 + ); +} + +money32 map_set_land_ownership(uint8 flags, sint16 x1, sint16 y1, sint16 x2, sint16 y2, uint8 newOwnership) { + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LAND_PURCHASE * 4; + + if (!(flags & GAME_COMMAND_FLAG_APPLY)) + return 0; + + RCT2_GLOBAL(0x009E2E28, uint8) = 0; + + for (sint16 y = y1; y <= y2; y += 32) { + for (sint16 x = x1; x <= x2; x += 32) { + if (x > RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, sint16)) + continue; + if (y > RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, sint16)) + continue; + + map_buy_land_rights(x, y, x2, y2, 6, flags | (newOwnership << 8)); + } + } + + if (!(RCT2_GLOBAL(0x9E2E28, uint8) & 1)) { + return 0; + } + + sint16 x = clamp(0, x1, RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, sint16)); + sint16 y = clamp(0, y1, RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, sint16)); + + x += 16; + y += 16; + + sint16 z = map_element_height(x, y) & 0xFFFF; + audio_play_sound_at_location(SOUND_PLACE_ITEM, x, y, z); + return 0; +} + +/* rct2: 0x006648E3*/ +void game_command_set_land_ownership(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + *ebx = map_set_land_ownership( + *ebx & 0xFF, + *eax & 0xFFFF, + *ecx & 0xFFFF, + *edi & 0xFFFF, + *ebp & 0xFFFF, + *edx & 0xFF + ); +} + + 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); + audio_play_sound_at_location(SOUND_PLACE_ITEM, x, y, z); } uint8 min_height = 0xFF; @@ -1508,20 +1660,23 @@ money32 raise_land(int flags, int x, int y, int z, int ax, int ay, int bx, int b height += 2; newStyle &= ~0x20; } - money32 tileCost = sub_66397F(flags, xi, yi, height, newStyle, selectionType); + money32 tileCost = map_set_land_height(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; + // Force ride construction to recheck area + RCT2_GLOBAL(0x00F440B0, uint8) |= 8; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint32) = x; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint32) = y; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint32) = z; return cost; } @@ -1530,7 +1685,7 @@ money32 lower_land(int flags, int x, int y, int z, int ax, int ay, int bx, int b money32 cost = 0; if ((flags & GAME_COMMAND_FLAG_APPLY) && RCT2_GLOBAL(0x009A8C28, uint8) == 1) { - sound_play_panned(SOUND_PLACE_ITEM, 0x8001, x, y, z); + audio_play_sound_at_location(SOUND_PLACE_ITEM, x, y, z); } uint8 max_height = 0; @@ -1572,20 +1727,23 @@ money32 lower_land(int flags, int x, int y, int z, int ax, int ay, int bx, int b height -= 2; newStyle &= ~0x20; } - money32 tileCost = sub_66397F(flags, xi, yi, height, newStyle, selectionType); + money32 tileCost = map_set_land_height(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; + // Force ride construction to recheck area + RCT2_GLOBAL(0x00F440B0, uint8) |= 8; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint32) = x; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint32) = y; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint32) = z; return cost; } @@ -1627,11 +1785,11 @@ money32 raise_water(sint16 x0, sint16 y0, sint16 x1, sint16 y1, uint8 flags) } else { height = map_element->base_height + 2; } - - money32 tileCost = game_do_command(xi, flags, yi, (max_height << 8) + height, GAME_COMMAND_16, 0, 0); + + money32 tileCost = game_do_command(xi, flags, yi, (max_height << 8) + height, GAME_COMMAND_SET_WATER_HEIGHT, 0, 0); if (tileCost == MONEY32_UNDEFINED) return MONEY32_UNDEFINED; - + cost += tileCost; } } @@ -1647,12 +1805,15 @@ money32 raise_water(sint16 x0, sint16 y0, sint16 x1, sint16 y1, uint8 flags) 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); + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint32) = x; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint32) = y; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint32) = z; + audio_play_sound_at_location(SOUND_LAYING_OUT_WATER, x, y, z); } + // Force ride construction to recheck area + RCT2_GLOBAL(0x00F440B0, uint8) |= 8; + return cost; } @@ -1691,7 +1852,7 @@ money32 lower_water(sint16 x0, sint16 y0, sint16 x1, sint16 y1, uint8 flags) if (height < min_height) continue; height -= 2; - int tileCost = game_do_command(xi, flags, yi, (min_height << 8) + height, GAME_COMMAND_16, 0, 0); + int tileCost = game_do_command(xi, flags, yi, (min_height << 8) + height, GAME_COMMAND_SET_WATER_HEIGHT, 0, 0); if (tileCost == MONEY32_UNDEFINED) return MONEY32_UNDEFINED; cost += tileCost; @@ -1709,12 +1870,15 @@ money32 lower_water(sint16 x0, sint16 y0, sint16 x1, sint16 y1, uint8 flags) 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); + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint32) = x; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint32) = y; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint32) = z; + audio_play_sound_at_location(SOUND_LAYING_OUT_WATER, x, y, z); } + // Force ride construction to recheck area + RCT2_GLOBAL(0x00F440B0, uint8) |= 8; + return cost; } @@ -1756,6 +1920,328 @@ void game_command_lower_land(int* eax, int* ebx, int* ecx, int* edx, int* esi, i ); } +static int map_get_corner_height(rct_map_element *mapElement, int direction) +{ + int z = mapElement->base_height; + int slope = mapElement->properties.surface.slope & MAP_ELEMENT_SLOPE_MASK; + switch (direction) { + case 0: + if (slope & 1) { + z += 2; + if (slope == 27) { + z += 2; + } + } + break; + case 1: + if (slope & 2) { + z += 2; + if (slope == 23) { + z += 2; + } + } + break; + case 2: + if (slope & 4) { + z += 2; + if (slope == 30) { + z += 2; + } + } + break; + case 3: + if (slope & 8) { + z += 2; + if (slope == 29) { + z += 2; + } + } + break; + } + return z; +} + +/** + * + * rct2: 0x0068C3B2 slope 1, style 0 + * rct2: 0x0068C47A slope 2, style 1 + * rct2: 0x0068C222 slope 4, style 2 + * rct2: 0x0068C2EA slope 8, style 3 + */ +static money32 smooth_land_tile(int direction, uint8 flags, int x, int y, int targetBaseZ, int minBaseZ) +{ + // Check if inside map bounds + if (x < 0 || y < 0 || x >= (256 * 32) || y >= (256 * 32)) { + return MONEY32_UNDEFINED; + } + + // Get height of tile + rct_map_element *mapElement = map_get_surface_element_at(x >> 5, y >> 5); + int baseZ = map_get_corner_height(mapElement, direction); + + // Check if tile is same height as target tile + if (baseZ == targetBaseZ) { + // No need to raise or lower + return MONEY32_UNDEFINED; + } + + uint8 style; + if (targetBaseZ <= baseZ) { + baseZ = baseZ - targetBaseZ; + if (baseZ <= minBaseZ) { + return MONEY32_UNDEFINED; + } + targetBaseZ = mapElement->base_height; + int slope = mapElement->properties.surface.slope & MAP_ELEMENT_SLOPE_MASK; + style = map_element_lower_styles[direction][slope]; + if (style & 0x20) { + targetBaseZ -= 2; + style &= ~0x20; + } + } else { + baseZ = targetBaseZ - baseZ; + if (baseZ <= minBaseZ) { + return MONEY32_UNDEFINED; + } + targetBaseZ = mapElement->base_height; + int slope = mapElement->properties.surface.slope & MAP_ELEMENT_SLOPE_MASK; + style = map_element_raise_styles[direction][slope]; + if ((style & 0x20) != 0) { + targetBaseZ += 2; + style &= ~0x20; + } + } + + return game_do_command(x, flags, y, targetBaseZ | (style << 8), GAME_COMMAND_SET_LAND_HEIGHT, 0, 0); +} + +money32 smooth_land(int flags, int centreX, int centreY, int mapLeft, int mapTop, int mapRight, int mapBottom, int command) +{ + // Cap bounds to map + mapLeft = max(mapLeft, 32); + mapTop = max(mapTop, 32); + mapRight = min(mapRight, 255 * 32); + mapBottom = min(mapBottom, 255 * 32); + + int commandType; + int centreZ = map_element_height(centreX, centreY); + int mapLeftRight = mapLeft | (mapRight << 16); + int mapTopBottom = mapTop | (mapBottom << 16); + + // Play sound (only once) + if ((flags & GAME_COMMAND_FLAG_APPLY) && RCT2_GLOBAL(0x009A8C28, uint8) == 1) { + audio_play_sound_at_location(SOUND_PLACE_ITEM, centreX, centreY, centreZ); + } + + money32 totalCost = 0; + + // First raise / lower the centre tile + money32 result; + commandType = command == 1 ? GAME_COMMAND_RAISE_LAND : GAME_COMMAND_LOWER_LAND; + result = game_do_command(centreX, flags, centreY, mapLeftRight, commandType, 4, mapTopBottom); + if (result != MONEY32_UNDEFINED) { + totalCost += result; + } + + int x, y, z; + rct_map_element *mapElement; + + x = mapLeft; + y = mapTop; + mapElement = map_get_surface_element_at(x >> 5, y >> 5); + int slope = mapElement->properties.surface.slope & MAP_ELEMENT_SLOPE_MASK; + if (slope != 0) { + commandType = command == 0xFFFF ? GAME_COMMAND_RAISE_LAND : GAME_COMMAND_LOWER_LAND; + result = game_do_command(centreX, flags, centreY, mapLeftRight, commandType, 4, mapTopBottom); + if (result != MONEY32_UNDEFINED) { + totalCost += result; + } + + x = mapLeft; + y = mapTop; + mapElement = map_get_surface_element_at(x >> 5, y >> 5); + slope = mapElement->properties.surface.slope & MAP_ELEMENT_SLOPE_MASK; + if (slope != 0) { + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint32) = centreX; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint32) = centreY; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint32) = centreZ; + return totalCost * 4; + } + } + + x = mapLeft; + y = mapTop; + int size = ((mapRight - mapLeft) >> 5) + 1; + int initialMinZ = -2; + + for (; size <= 256; size += 2) { + initialMinZ += 2; + int minZ = initialMinZ * 2; + x -= 32; + y -= 32; + + // Corner (North-West) + mapElement = map_get_surface_element_at(mapLeft >> 5, mapTop >> 5); + z = map_get_corner_height(mapElement, 2); + result = smooth_land_tile(0, flags, x, y, z, minZ); + if (result != MONEY32_UNDEFINED) { + totalCost += result; + } + y += 32; + + // Side (West) + for (int i = 0; i < size; i++) { + int y2 = clamp(mapTop, y, mapBottom); + mapElement = map_get_surface_element_at(mapLeft >> 5, y2 >> 5); + z = map_get_corner_height(mapElement, 2); + result = smooth_land_tile(1, flags, x, y, z, minZ); + if (result != MONEY32_UNDEFINED) { + totalCost += result; + } + minZ -= 2; + if (y >= mapTop) { + minZ += 2; + if (y > mapBottom) { + minZ += 2; + } + } + z = map_get_corner_height(mapElement, 3); + result = smooth_land_tile(0, flags, x, y, z, minZ); + if (result != MONEY32_UNDEFINED) { + totalCost += result; + } + + y += 32; + } + + // Corner (South-West) + mapElement = map_get_surface_element_at(mapLeft >> 5, mapBottom >> 5); + z = map_get_corner_height(mapElement, 3); + result = smooth_land_tile(1, flags, x, y, z, minZ); + if (result != MONEY32_UNDEFINED) { + totalCost += result; + } + x += 32; + + // Side (South) + for (int i = 0; i < size; i++) { + int x2 = clamp(mapLeft, x, mapRight); + mapElement = map_get_surface_element_at(x2 >> 5, mapBottom >> 5); + z = map_get_corner_height(mapElement, 3); + result = smooth_land_tile(2, flags, x, y, z, minZ); + if (result != MONEY32_UNDEFINED) { + totalCost += result; + } + minZ -= 2; + if (x >= mapLeft) { + minZ += 2; + if (x > mapRight) { + minZ += 2; + } + } + z = map_get_corner_height(mapElement, 0); + result = smooth_land_tile(1, flags, x, y, z, minZ); + if (result != MONEY32_UNDEFINED) { + totalCost += result; + } + + x += 32; + } + + // Corner (South-East) + mapElement = map_get_surface_element_at(mapRight >> 5, mapBottom >> 5); + z = map_get_corner_height(mapElement, 0); + result = smooth_land_tile(2, flags, x, y, z, minZ); + if (result != MONEY32_UNDEFINED) { + totalCost += result; + } + y -= 32; + + // Side (East) + for (int i = 0; i < size; i++) { + int y2 = clamp(mapTop, y, mapBottom); + mapElement = map_get_surface_element_at(mapRight >> 5, y2 >> 5); + z = map_get_corner_height(mapElement, 0); + result = smooth_land_tile(3, flags, x, y, z, minZ); + if (result != MONEY32_UNDEFINED) { + totalCost += result; + } + minZ -= 2; + if (y <= mapBottom) { + minZ += 2; + if (y < mapTop) { + minZ += 2; + } + } + z = map_get_corner_height(mapElement, 1); + result = smooth_land_tile(2, flags, x, y, z, minZ); + if (result != MONEY32_UNDEFINED) { + totalCost += result; + } + + y -= 32; + } + + // Corner (North-East) + mapElement = map_get_surface_element_at(mapRight >> 5, mapTop >> 5); + z = map_get_corner_height(mapElement, 1); + result = smooth_land_tile(3, flags, x, y, z, minZ); + if (result != MONEY32_UNDEFINED) { + totalCost += result; + } + x -= 32; + + // Side (North) + for (int i = 0; i < size; i++) { + int x2 = clamp(mapLeft, x, mapRight); + mapElement = map_get_surface_element_at(x2 >> 5, mapTop >> 5); + z = map_get_corner_height(mapElement, 1); + result = smooth_land_tile(0, flags, x, y, z, minZ); + if (result != MONEY32_UNDEFINED) { + totalCost += result; + } + minZ -= 2; + if (x <= mapRight) { + minZ += 2; + if (x < mapLeft) { + minZ += 2; + } + } + z = map_get_corner_height(mapElement, 2); + result = smooth_land_tile(3, flags, x, y, z, minZ); + if (result != MONEY32_UNDEFINED) { + totalCost += result; + } + + x -= 32; + } + } + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint32) = centreX; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint32) = centreY; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint32) = centreZ; + return totalCost * 4; +} + +/** + * + * rct2: 0x0068BC01 + */ +void game_command_smooth_land(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + int flags = *ebx & 0xFF; + int centreX = *eax & 0xFFFF; + int centreY = *ecx & 0xFFFF; + int mapLeft = (sint16)(*edx & 0xFFFF); + int mapTop = (sint16)(*ebp & 0xFFFF); + int mapRight = (sint16)(*edx >> 16); + int mapBottom = (sint16)(*ebp >> 16); + int command = *edi; + *ebx = smooth_land(flags, centreX, centreY, mapLeft, mapTop, mapRight, mapBottom, command); +} + /** * * rct2: 0x006E66A0 @@ -1778,14 +2264,102 @@ void game_command_raise_water(int* eax, int* ebx, int* ecx, int* edx, int* esi, 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), + (sint16)(*eax & 0xFFFF), + (sint16)(*ecx & 0xFFFF), + (sint16)(*edi & 0xFFFF), + (sint16)(*ebp & 0xFFFF), (uint8)*ebx ); } +/** + * + * rct2: 0x006E650F + */ +void game_command_set_water_height(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) +{ + int x = *eax; + int y = *ecx; + uint8 base_height = *edx; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, sint16) = x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, sint16) = y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint32) = base_height * 8; + if(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) && !gCheatsSandboxMode && RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_FORBIDDEN_BY_THE_LOCAL_AUTHORITY; + *ebx = MONEY32_UNDEFINED; + return; + } + + if(base_height < 2){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TOO_LOW; + *ebx = MONEY32_UNDEFINED; + return; + } + + if(base_height >= 58){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TOO_HIGH; + *ebx = MONEY32_UNDEFINED; + return; + } + + if(x >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, sint16) || y >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, sint16)){ + 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) && !gCheatsSandboxMode && !map_is_location_in_park(x, y)){ + *ebx = MONEY32_UNDEFINED; + return; + } + + if(*ebx & GAME_COMMAND_FLAG_APPLY){ + int element_height = map_element_height(x, y); + footpath_remove_litter(x, y, element_height); + map_remove_walls_at_z(x, y, element_height); + } + + rct_map_element* map_element = map_get_surface_element_at(x / 32, y / 32); + int zHigh = map_element->base_height; + int zLow = base_height; + if(map_element->properties.surface.terrain & 0x1F){ + zHigh = (map_element->properties.surface.terrain & 0x1F) * 2; + } + if(zLow > zHigh){ + int temp = zHigh; + zHigh = zLow; + zLow = temp; + } + + if(map_can_construct_at(x, y, zLow, zHigh, 0xFF)){ + if(map_element->type & 0x40){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 0; + *ebx = MONEY32_UNDEFINED; + return; + } + if(*ebx & GAME_COMMAND_FLAG_APPLY){ + int new_terrain = map_element->properties.surface.terrain & 0xE0; + if(base_height > map_element->base_height){ + new_terrain |= (base_height / 2); + } + map_element->properties.surface.terrain = new_terrain; + map_invalidate_tile_full(x, y); + } + *ebx = 250; + if(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY){ + *ebx = 0; + } + }else{ + *ebx = MONEY32_UNDEFINED; + } +} + /** * * rct2: 0x006E5597 @@ -1797,13 +2371,13 @@ void game_command_remove_fence(int* eax, int* ebx, int* ecx, int* edx, int* esi, uint8 base_height = (*edx >> 8); uint8 direction = *edx; - RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = 12; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; 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)){ + if(!(*ebx & 0x40) && !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && !map_is_location_owned(x, y, base_height * 8)){ *ebx = MONEY32_UNDEFINED; return; } @@ -1825,7 +2399,7 @@ void game_command_remove_fence(int* eax, int* ebx, int* ecx, int* edx, int* esi, } map_element_remove_banner_entry(map_element); - map_invalidate_tile(x, y, map_element->base_height * 8, (map_element->base_height * 8) + 72); + map_invalidate_tile_zoom1(x, y, map_element->base_height * 8, (map_element->base_height * 8) + 72); map_element_remove(map_element); *ebx = 0; } @@ -1842,10 +2416,10 @@ void game_command_place_banner(int* eax, int* ebx, int* ecx, int* edx, int* esi, 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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint32) = x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint32) = y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint32) = base_height * 16; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; 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); @@ -1861,7 +2435,7 @@ void game_command_place_banner(int* eax, int* ebx, int* ecx, int* edx, int* esi, return; } } - if(!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gSandboxMode && !map_is_location_owned(x, y, base_height * 16)){ + if(!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && !map_is_location_owned(x, y, base_height * 16)){ *ebx = MONEY32_UNDEFINED; return; } @@ -1920,7 +2494,7 @@ void game_command_place_banner(int* eax, int* ebx, int* ecx, int* edx, int* esi, */ 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; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; int x = (uint16)*eax; int y = (uint16)*ecx; uint8 color2 = *edi >> 16; @@ -1935,15 +2509,15 @@ void game_command_place_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi if(base_height & 0xFFFF0000){ base_height >>= 16; } - RCT2_GLOBAL(0x009DEA5E, uint16) = x; - RCT2_GLOBAL(0x009DEA60, uint16) = y; - RCT2_GLOBAL(0x009DEA62, uint16) = base_height; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = base_height; if(F64EC8){ base_height = F64EC8; - RCT2_GLOBAL(0x009DEA62, uint16) = base_height; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = base_height; } - RCT2_GLOBAL(0x009DEA5E, uint16) += 16; - RCT2_GLOBAL(0x009DEA60, uint16) += 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) += 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, 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))){ @@ -1972,21 +2546,21 @@ void game_command_place_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi 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)){ + if(!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && !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); + if(!gCheatsDisableClearanceChecks && (scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_ALLOW_WALLS)) { + map_remove_walls_at(x, y, F64EC8, F64EC8 + scenery_entry->small_scenery.height); } } 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){ + if(!gCheatsDisableClearanceChecks && (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; @@ -1994,7 +2568,7 @@ void game_command_place_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi return; } } - if(!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG18)){ + if(!gCheatsDisableClearanceChecks && !(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; @@ -2008,8 +2582,8 @@ void game_command_place_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi } } } - 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){ + if(gCheatsDisableClearanceChecks || !(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE) || z != 0 || F64F1D != 0 || !(map_element->properties.surface.slope & 0x1F)){ + if(gCheatsDisableSupportLimits || scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG18 || z == 0){ l_6E0B78: ; int bp = quadrant; int zLow = F64EC8 / 8; @@ -2050,12 +2624,12 @@ void game_command_place_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi 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(gCheatsDisableClearanceChecks || map_can_construct_with_clear_at(x, y, zLow, zHigh, (void*)0x006E0D6E, bl)){ + RCT2_GLOBAL(0x00F64F14, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, 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; + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_MAP_ELEMENT, rct_map_element*) = new_map_element; uint8 type = quadrant << 6; type |= MAP_ELEMENT_TYPE_SCENERY; type |= rotation; @@ -2104,230 +2678,648 @@ void game_command_place_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi *ebx = MONEY32_UNDEFINED; } +static bool map_is_location_at_edge(int x, int y) +{ + return x < 32 || y < 32 || x >= ((256 - 1) * 32) || y >= ((256 - 1) * 32); +} + +/** + * + * rct2: 0x006E5CBA + */ +static bool map_place_fence_check_obstruction_with_track(rct_scenery_entry *wall, int x, int y, int z0, int z1, int edge, rct_map_element *trackElement) +{ + const rct_preview_track *trackBlock; + int z, direction; + + int trackType = trackElement->properties.track.type; + int sequence = trackElement->properties.track.sequence & 0x0F; + int typeAndSequence = (trackType << 4) | sequence; + direction = (edge - trackElement->type) & 3; + rct_ride *ride = GET_RIDE(trackElement->properties.track.ride_index); + + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { + if (RCT2_ADDRESS(0x0099AA94, uint8)[typeAndSequence] & (1 << direction)) { + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_18)) { + return true; + } + } + } else { + if (RCT2_ADDRESS(0x00999A94, uint8)[typeAndSequence] & (1 << direction)) { + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_18)) { + return true; + } + } + } + + if (!(wall->wall.flags & WALL_SCENERY_FLAG5)) { + return false; + } + + if (!(RideData4[ride->type].flags & RIDE_TYPE_FLAG4_0)) { + return false; + } + + rct_ride_type *rideEntry = GET_RIDE_ENTRY(ride->subtype); + if (rideEntry->flags & RIDE_ENTRY_FLAG_16) { + return false; + } + + RCT2_GLOBAL(0x0141F725, uint8) |= 1; + if (z0 & 1) { + return false; + } + + if (sequence == 0) { + if (RCT2_GLOBAL(0x0099BA64 + (trackType * 16), uint8) & 0x40) { + return false; + } + + if (gTrackDefinitions[trackType].bank_start == 0) { + if (!(RCT2_ADDRESS(0x009968BB, uint8)[trackType * 10] & 4)) { + direction = (trackElement->type & 3) ^ 2; + if (direction == edge) { + trackBlock = &TrackBlocks[trackType][sequence]; + z = RCT2_GLOBAL(0x009968BD + (trackType * 10), uint8); + z = trackElement->base_height + ((z - trackBlock->z) * 8); + if (z == z0) { + return true; + } + } + } + } + } + + trackBlock = &TrackBlocks[trackType][sequence + 1]; + if (trackBlock->index != 0xFF) { + return false; + } + + if (gTrackDefinitions[trackType].bank_end != 0) { + return false; + } + + direction = RCT2_ADDRESS(0x009968BC, uint8)[trackType * 10]; + if (direction & 4) { + return false; + } + + direction = (trackElement->type + direction) & 3; + if (direction != edge) { + return false; + } + + trackBlock = &TrackBlocks[trackType][sequence]; + z = RCT2_GLOBAL(0x009968BF + (trackType * 10), uint8); + z = trackElement->base_height + ((z - trackBlock->z) * 8); + if (z != z0) { + return false; + } + + return true; +} + +/** + * + * rct2: 0x006E5C1A + */ +static bool map_place_fence_check_obstruction(rct_scenery_entry *wall, int x, int y, int z0, int z1, int edge) +{ + int entryType, sequence; + rct_scenery_entry *entry; + rct_large_scenery_tile *tile; + + RCT2_GLOBAL(0x0141F725, uint8) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) = 1; + if (map_is_location_at_edge(x, y)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_OFF_EDGE_OF_MAP; + return false; + } + + rct_map_element *mapElement = map_get_first_element_at(x / 32, y / 32); + do { + int elementType = map_element_get_type(mapElement); + if (elementType == MAP_ELEMENT_TYPE_SURFACE) continue; + if (z0 >= mapElement->clearance_height) continue; + if (z1 <= mapElement->base_height) continue; + if (elementType == MAP_ELEMENT_TYPE_FENCE) { + int direction = mapElement->type & 3; + if (edge == direction) { + map_obstruction_set_error_text(mapElement); + return false; + } + continue; + } + if ((mapElement->flags & 0x0F) == 0) continue; + + switch (elementType) { + case MAP_ELEMENT_TYPE_ENTRANCE: + map_obstruction_set_error_text(mapElement); + return false; + case MAP_ELEMENT_TYPE_PATH: + if (mapElement->properties.path.edges & (1 << edge)) { + map_obstruction_set_error_text(mapElement); + return false; + } + break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + entryType = mapElement->properties.scenerymultiple.type & 0x3FF; + sequence = mapElement->properties.scenerymultiple.type >> 10; + entry = g_largeSceneryEntries[entryType]; + tile = &entry->large_scenery.tiles[sequence]; + + int direction = ((edge - mapElement->type) & 3) + 8; + if (!(tile->var_7 & (1 << direction))) { + map_obstruction_set_error_text(mapElement); + return false; + } + break; + case MAP_ELEMENT_TYPE_SCENERY: + entryType = mapElement->properties.scenery.type; + entry = g_smallSceneryEntries[entryType]; + if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_ALLOW_WALLS) { + map_obstruction_set_error_text(mapElement); + return false; + } + break; + case MAP_ELEMENT_TYPE_TRACK: + if (!map_place_fence_check_obstruction_with_track(wall, x, y, z0, z1, edge, mapElement)) { + return false; + } + break; + } + } while (!map_element_is_last_for_tile(mapElement++)); + return true; +} + +/** + * + * rct2: 0x006E519A + */ +void game_command_place_fence(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp){ + rct_xyz16 position = { + .x = *eax & 0xFFFF, + .y = *ecx & 0xFFFF, + .z = *edi & 0xFFFF + }; + + uint8 flags = *ebx & 0xFF; + uint8 fence_type = (*ebx >> 8) & 0xFF; + uint8 primary_colour = (*edx >> 8) & 0xFF; + uint8 secondary_colour = *ebp & 0xFF; + uint8 tertiary_colour = (*ebp >> 8) & 0xFF; + uint8 edge = *edx & 0xFF; + + // *not used* + RCT2_GLOBAL(0x00141F726, uint8) = secondary_colour; + // *not used* + RCT2_GLOBAL(0x00141F727, uint8) = tertiary_colour; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; + // Banner index *not used* + RCT2_GLOBAL(0x00141F728, uint8) = 0xFF; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, sint16) = position.x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, sint16) = position.y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, sint16) = position.z; + + if (position.z == 0){ + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, sint16) = map_element_height(position.x, position.y) & 0xFFFF; + } + + 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; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) && + !(flags & (1 << 7)) && !gCheatsSandboxMode){ + + if (position.z == 0){ + if (!map_is_location_in_park(position.x, position.y)){ + *ebx = MONEY32_UNDEFINED; + return; + } + } + else if (!map_is_location_owned(position.x, position.y, position.z)){ + *ebx = MONEY32_UNDEFINED; + return; + } + } + + uint8 bp = 0; + if (position.z == 0){ + rct_map_element* map_element = map_get_surface_element_at(position.x / 32, position.y / 32); + if (map_element == NULL){ + *ebx = MONEY32_UNDEFINED; + return; + } + position.z = map_element->base_height * 8; + + uint8 slope = map_element->properties.surface.slope & MAP_ELEMENT_SLOPE_MASK; + bp = RCT2_ADDRESS(0x009A3FEC, uint8)[slope + (edge & 3) * 32]; + if (bp & (1 << 0)){ + position.z += 16; + bp &= ~(1 << 0); + } + } + + RCT2_GLOBAL(0x00141F721, uint16) = position.z / 8; + RCT2_GLOBAL(0x00141F720, uint8) = primary_colour; + RCT2_GLOBAL(0x00141F723, uint8) = bp; + + rct_map_element* map_element = map_get_surface_element_at(position.x / 32, position.y / 32); + if (map_element == NULL){ + *ebx = MONEY32_UNDEFINED; + return; + } + + if (map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK){ + uint16 water_height = map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK; + water_height *= 16; + + if (position.z < water_height){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CANT_BUILD_THIS_UNDERWATER; + *ebx = MONEY32_UNDEFINED; + return; + } + } + + if (position.z / 8 < map_element->base_height){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (!(bp & 0xC0)){ + uint8 new_edge = (edge + 2) & 3; + uint8 new_base_height = map_element->base_height; + new_base_height += 2; + if (map_element->properties.surface.slope & (1 << new_edge)){ + if (position.z / 8 < new_base_height){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (map_element->properties.surface.slope & (1 << 4)){ + new_edge = (new_edge - 1) & 3; + + if (map_element->properties.surface.slope & (1 << new_edge)){ + new_edge = (new_edge + 2) & 3; + if (map_element->properties.surface.slope & (1 << new_edge)){ + new_base_height += 2; + if (position.z / 8 < new_base_height){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + *ebx = MONEY32_UNDEFINED; + return; + } + new_base_height -= 2; + } + } + } + } + + new_edge = (edge + 3) & 3; + if (map_element->properties.surface.slope & (1 << new_edge)){ + if (position.z / 8 < new_base_height){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (map_element->properties.surface.slope & (1 << 4)){ + new_edge = (new_edge - 1) & 3; + + if (map_element->properties.surface.slope & (1 << new_edge)){ + new_edge = (new_edge + 2) & 3; + if (map_element->properties.surface.slope & (1 << new_edge)){ + new_base_height += 2; + if (position.z / 8 < new_base_height){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + *ebx = MONEY32_UNDEFINED; + return; + } + } + } + } + } + } + int banner_index = 0xFF; + rct_scenery_entry* fence = g_wallSceneryEntries[fence_type]; + if (fence->wall.var_0D != 0xFF){ + banner_index = create_new_banner(fence->wall.var_0D); + + RCT2_GLOBAL(0x00141F728, uint8) = banner_index; + if (banner_index == 0xFF){ + *ebx = MONEY32_UNDEFINED; + return; + } + + rct_banner* banner = &gBanners[banner_index]; + if (flags & GAME_COMMAND_FLAG_APPLY){ + banner->flags |= (1 << 3); + banner->type = 0; + banner->x = position.x / 32; + banner->y = position.y / 32; + + int rideIndex = banner_get_closest_ride_index(position.x, position.y, position.z); + if (rideIndex != -1) { + banner->colour = rideIndex & 0xFF; + banner->flags |= BANNER_FLAG_2; + } + } + } + + bp = RCT2_GLOBAL(0x00141F723, uint8); + + RCT2_GLOBAL(0x00141F722, uint8) = position.z / 8; + if (bp & 0xC0){ + if (fence->wall.flags & WALL_SCENERY_FLAG3){ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = 3133; + *ebx = MONEY32_UNDEFINED; + return; + } + RCT2_GLOBAL(0x00141F722, uint8) += 2; + } + RCT2_GLOBAL(0x00141F722, uint8) += fence->wall.height; + + if (!(flags & (1 << 7)) && !gCheatsDisableClearanceChecks){ + if (!map_place_fence_check_obstruction(fence, position.x, position.y, RCT2_GLOBAL(0x00141F721, uint8), RCT2_GLOBAL(0x00141F722, uint8), edge)) { + *ebx = MONEY32_UNDEFINED; + return; + } + } + + if (!sub_68B044()){ + *ebx = MONEY32_UNDEFINED; + return; + } + + if (flags & GAME_COMMAND_FLAG_APPLY){ + map_element = map_element_insert(position.x / 32, position.y / 32, position.z / 8, 0); + + map_animation_create(MAP_ANIMATION_TYPE_WALL, position.x, position.y, position.z / 8); + + map_element->clearance_height = RCT2_GLOBAL(0x00141F722, uint8); + + map_element->type = bp | edge | MAP_ELEMENT_TYPE_FENCE; + + map_element->properties.fence.item[1] = primary_colour; + map_element->properties.fence.item[1] |= (secondary_colour & 7) << 5; + map_element->flags |= (secondary_colour & 0x18) << 2; + + if (RCT2_GLOBAL(0x00141F725, uint8) & 1){ + map_element->properties.fence.item[2] |= (1 << 2); + } + + map_element->properties.fence.type = fence_type; + if (banner_index != 0xFF){ + map_element->properties.fence.item[0] = banner_index; + } + + if (fence->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR){ + map_element->properties.fence.item[0] = tertiary_colour; + } + + if (flags & (1 << 6)){ + map_element->flags |= MAP_ELEMENT_FLAG_GHOST; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_MAP_ELEMENT, rct_map_element*) = map_element; + map_invalidate_tile_zoom1(position.x, position.y, map_element->base_height * 8, map_element->base_height * 8 + 72); + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY){ + *ebx = 0; + } + else{ + *ebx = fence->wall.price; + } +} + +money32 map_place_fence( + int type, int x, int y, int z, int edge, int primaryColour, int secondaryColour, int tertiaryColour, int flags +) { + int eax, ebx, ecx, edx, esi, edi, ebp; + + eax = x; + ebx = flags | (type << 8); + ecx = y; + edx = edge | (primaryColour << 8); + edi = z; + ebp = secondaryColour | (tertiaryColour << 8); + game_command_place_fence(&eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return ebx; +} + /** * * 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; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; int x = (sint16)*eax; int y = (sint16)*ecx; - int z = (sint16)*ebp; + 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(RCT2_ADDRESS_COMMAND_MAP_X, sint16) = x + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, sint16) = y + 16; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, 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; - } + // Supports cost + RCT2_GLOBAL(0x00F4389A, money32) = 0; - 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; - } + if (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 (!sub_68B044()) { + *ebx = MONEY32_UNDEFINED; + return; + } + + 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; } - }else{ - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; - } - *ebx = MONEY32_UNDEFINED; -} -/** - * - * rct2: 0x006EC6D7 - */ -void map_invalidate_tile_full(int x, int y) -{ - RCT2_CALLPROC_X(0x006EC6D7, x, 0, y, 0, 0, 0, 0); + 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 rideIndex = banner_get_closest_ride_index(x, y, z); + if (rideIndex != -1) { + banner->colour = rideIndex; + banner->flags |= BANNER_FLAG_2; + } + } + } + + + sint16 maxHeight = 0xFFFF; + for (rct_large_scenery_tile* tile = scenery_entry->large_scenery.tiles; + tile->x_offset != -1; + tile++) { + + rct_xy16 curTile = { + .x = tile->x_offset, + .y = tile->y_offset + }; + + rotate_map_coordinates(&curTile.x, &curTile.y, rotation); + + curTile.x += x; + curTile.y += y; + + if(curTile.x >= 0x1FFF || curTile.y >= 0x1FFF || curTile.x < 0 || curTile.y < 0){ + continue; + } + + rct_map_element* map_element = map_get_surface_element_at(curTile.x / 32, curTile.y / 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 > maxHeight){ + maxHeight = height; + } + } + } + + if(z != 0){ + maxHeight = z; + } + + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, sint16) = maxHeight; + uint8 tile_num = 0; + for (rct_large_scenery_tile* tile = scenery_entry->large_scenery.tiles; + tile->x_offset != -1; + tile++, tile_num++) { + + rct_xy16 curTile = { + .x = tile->x_offset, + .y = tile->y_offset + }; + + rotate_map_coordinates(&curTile.x, &curTile.y, rotation); + + curTile.x += x; + curTile.y += y; + + int zLow = (tile->z_offset + maxHeight) / 8; + int zHigh = (tile->z_clearance / 8) + zLow; + + int bx = tile->var_7 >> 12; + bx <<= rotation; + uint8 bl = bx; + uint8 bh = bl >> 4; + bl &= 0xF; + bl |= bh; + uint8 F43887 = bl; + + RCT2_GLOBAL(0x00F43892, sint16) = curTile.x; + RCT2_GLOBAL(0x00F43894, sint16) = curTile.y; + RCT2_GLOBAL(0x00F43896, uint32) = (uint32)(ebx - 3); // this is how ebx flags var is passed to 0x006B8D88 + if (!gCheatsDisableClearanceChecks && !map_can_construct_with_clear_at(curTile.x, curTile.y, zLow, zHigh, (void*)0x006B8D88, bl)) { + *ebx = MONEY32_UNDEFINED; + return; + } + + if ((RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) & ELEMENT_IS_UNDERWATER) || (RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) & 2)) { + *ebx = MONEY32_UNDEFINED; + return; + } + + int b = RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) & 0x3; + if (!gCheatsDisableClearanceChecks) { + 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 (curTile.x >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) || curTile.y >= 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(curTile.x, curTile.y, zLow * 8) && + !gCheatsSandboxMode) { + *ebx = MONEY32_UNDEFINED; + return; + } + + if (flags & GAME_COMMAND_FLAG_APPLY) { + if (!(flags & GAME_COMMAND_FLAG_GHOST)) { + footpath_remove_litter(curTile.x, curTile.y, zLow * 8); + if (!gCheatsDisableClearanceChecks) { + map_remove_walls_at(curTile.x, curTile.y, zLow * 8, zHigh * 8); + } + } + rct_map_element *new_map_element = map_element_insert(curTile.x / 32, curTile.y / 32, zLow, F43887); + map_animation_create(MAP_ANIMATION_TYPE_LARGE_SCENERY, curTile.x, curTile.y, zLow); + + new_map_element->clearance_height = zHigh; + new_map_element->type = MAP_ELEMENT_TYPE_SCENERY_MULTIPLE | rotation; + + new_map_element->properties.scenerymultiple.type = + (tile_num << 10) | + entry_index; + + new_map_element->properties.scenerymultiple.colour[0] = color1; + new_map_element->properties.scenerymultiple.colour[1] = color2; + + if (banner_id != 0xFF) { + new_map_element->type |= banner_id & 0xC0; + new_map_element->properties.scenerymultiple.colour[0] |= (banner_id & 0x38) << 2; + new_map_element->properties.scenerymultiple.colour[1] |= (banner_id & 7) << 5; + } + + if (flags & GAME_COMMAND_FLAG_GHOST) { + new_map_element->flags |= MAP_ELEMENT_FLAG_GHOST; + } + + if (tile_num == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_MAP_ELEMENT, rct_map_element*) = new_map_element; + } + map_invalidate_tile_full(curTile.x, curTile.y); + } + } + + // Force ride construction to recheck area + RCT2_GLOBAL(0x00F440B0, uint8) |= 8; + + *ebx = (scenery_entry->large_scenery.price * 10) + RCT2_GLOBAL(0x00F4389A, money32); + if(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY){ + *ebx = 0; + } } int map_get_station(rct_map_element *mapElement) @@ -2341,18 +3333,17 @@ int map_get_station(rct_map_element *mapElement) */ void map_element_remove(rct_map_element *mapElement) { - RCT2_CALLPROC_X(0x0068B280, 0, 0, 0, 0, (int)mapElement, 0, 0); -} + if (!map_element_is_last_for_tile(mapElement)){ + do{ + *mapElement = *(mapElement + 1); + } while (!map_element_is_last_for_tile(++mapElement)); + } + (mapElement - 1)->flags |= MAP_ELEMENT_FLAG_LAST_TILE; + mapElement->base_height = 0xFF; -/** - * - * rct2: 0x006A6AA7 - * @param x x-coordinate in units (not tiles) - * @param y y-coordinate in units (not tiles) - */ -void sub_6A6AA7(int x, int y, rct_map_element *mapElement) -{ - RCT2_CALLPROC_X(0x006A6AA7, x, 0, y, 0, (int)mapElement, 0, 0); + if ((mapElement + 1) == RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*)){ + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*)--; + } } /** @@ -2379,7 +3370,7 @@ void map_remove_all_rides() // fall-through case MAP_ELEMENT_TYPE_TRACK: sub_6A7594(); - sub_6A6AA7(it.x * 32, it.y * 32, it.element); + footpath_remove_edges_at(it.x * 32, it.y * 32, it.element); map_element_remove(it.element); map_element_iterator_restart_for_tile(&it); break; @@ -2402,25 +3393,66 @@ void map_invalidate_map_selection_tiles() map_invalidate_tile_full(position->x, position->y); } +void map_get_bounding_box(int ax, int ay, int bx, int by, int *left, int *top, int *right, int *bottom) +{ + int x, y; + x = ax; + y = ay; + translate_3d_to_2d(get_current_rotation(), &x, &y); + *left = x; + *right = x; + *top = y; + *bottom = y; + x = bx; + y = ay; + translate_3d_to_2d(get_current_rotation(), &x, &y); + if (x < *left) *left = x; + if (x > *right) *right = x; + if (y > *bottom) *bottom = y; + if (y < *top) *top = y; + x = bx; + y = by; + translate_3d_to_2d(get_current_rotation(), &x, &y); + if (x < *left) *left = x; + if (x > *right) *right = x; + if (y > *bottom) *bottom = y; + if (y < *top) *top = y; + x = ax; + y = by; + translate_3d_to_2d(get_current_rotation(), &x, &y); + if (x < *left) *left = x; + if (x > *right) *right = x; + if (y > *bottom) *bottom = y; + if (y < *top) *top = y; +} + /** * * rct2: 0x0068AAE1 */ void map_invalidate_selection_rect() { - int x, y, x0, y0, x1, y1; + int x0, y0, x1, y1, left, right, top, bottom; + rct_viewport **vp; 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); + x0 = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, sint16) + 16; + y0 = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, sint16) + 16; + x1 = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, sint16) + 16; + y1 = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, sint16) + 16; + map_get_bounding_box(x0, y0, x1, y1, &left, &top, &right, &bottom); + left -= 32; + right += 32; + bottom += 32; + top -= 32 + 2080; - for (x = x0; x <= x1; x++) - for (y = y0; y <= y1; y++) - map_invalidate_tile_full(x, y); + vp = RCT2_ADDRESS(RCT2_ADDRESS_ACTIVE_VIEWPORT_PTR_ARRAY, rct_viewport*); + while (*vp != NULL) { + viewport_invalidate(*vp, left, top, right, bottom); + vp++; + } } /** @@ -2429,7 +3461,37 @@ void map_invalidate_selection_rect() */ void map_reorganise_elements() { - RCT2_CALLPROC_EBPSAFE(0x0068B111); + platform_set_cursor(CURSOR_ZZZ); + + rct_map_element* new_map_elements = rct2_malloc(0x30000 * sizeof(rct_map_element)); + rct_map_element* new_elements_pointer = new_map_elements; + + if (new_map_elements == NULL || new_map_elements == (rct_map_element*)-1){ + error_string_quit(4370, 0xFFFF); + return; + } + + uint32 num_elements; + + for (int y = 0; y < 256; y++) { + for (int x = 0; x < 256; x++) { + rct_map_element *startElement = map_get_first_element_at(x, y); + rct_map_element *endElement = startElement; + while (!map_element_is_last_for_tile(endElement++)); + + num_elements = endElement - startElement; + memcpy(new_elements_pointer, startElement, num_elements * sizeof(rct_map_element)); + new_elements_pointer += num_elements; + } + } + + num_elements = (new_elements_pointer - new_map_elements); + memcpy(RCT2_ADDRESS(RCT2_ADDRESS_MAP_ELEMENTS, rct_map_element), new_map_elements, num_elements * sizeof(rct_map_element)); + memset(RCT2_ADDRESS(RCT2_ADDRESS_MAP_ELEMENTS, rct_map_element) + num_elements, 0, (0x30000 - num_elements) * sizeof(rct_map_element)); + + rct2_free(new_map_elements); + + map_update_tile_pointers(); } /** @@ -2438,7 +3500,23 @@ void map_reorganise_elements() */ int sub_68B044() { - return (RCT2_CALLPROC_X(0x0068B044, 0, 0, 0, 0, 0, 0, 0) & 0x100) == 0; + if (RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*) <= RCT2_ADDRESS(RCT2_ADDRESS_MAP_ELEMENTS_END, rct_map_element)) + return 1; + + for (int i = 1000; i != 0; --i) + sub_68B089(); + + if (RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*) <= RCT2_ADDRESS(RCT2_ADDRESS_MAP_ELEMENTS_END, rct_map_element)) + return 1; + + map_reorganise_elements(); + + if (RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*) <= RCT2_ADDRESS(RCT2_ADDRESS_MAP_ELEMENTS_END, rct_map_element)) + return 1; + else{ + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = 894; + return 0; + } } /** @@ -2451,7 +3529,7 @@ rct_map_element *map_element_insert(int x, int y, int z, int flags) sub_68B044(); - newMapElement = RCT2_GLOBAL(0x00140E9A4, rct_map_element*); + newMapElement = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*); originalMapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x); // Set tile index pointer to point to new element block @@ -2492,17 +3570,171 @@ rct_map_element *map_element_insert(int x, int y, int z, int flags) } while (!((newMapElement - 1)->flags & MAP_ELEMENT_FLAG_LAST_TILE)); } - RCT2_GLOBAL(0x00140E9A4, rct_map_element*) = newMapElement; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_FREE_MAP_ELEMENT, rct_map_element*) = newMapElement; return insertedElement; } +/** + * + * rct2: 0x0068BB18 + */ +static void map_obstruction_set_error_text(rct_map_element *mapElement) +{ + rct_string_id errorStringId; + rct_ride *ride; + rct_scenery_entry *sceneryEntry; + + errorStringId = STR_OBJECT_IN_THE_WAY; + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_SURFACE: + errorStringId = STR_RAISE_OR_LOWER_LAND_FIRST; + break; + case MAP_ELEMENT_TYPE_PATH: + errorStringId = STR_FOOTPATH_IN_THE_WAY; + break; + case MAP_ELEMENT_TYPE_TRACK: + ride = GET_RIDE(mapElement->properties.track.ride_index); + errorStringId = STR_X_IN_THE_WAY; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = ride->name; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 2, uint32) = ride->name_arguments; + break; + case MAP_ELEMENT_TYPE_SCENERY: + sceneryEntry = g_smallSceneryEntries[mapElement->properties.scenery.type]; + errorStringId = STR_X_IN_THE_WAY; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = sceneryEntry->name; + break; + case MAP_ELEMENT_TYPE_ENTRANCE: + switch (mapElement->properties.entrance.type) { + case ENTRANCE_TYPE_RIDE_ENTRANCE: + errorStringId = STR_RIDE_ENTRANCE_IN_THE_WAY; + break; + case ENTRANCE_TYPE_RIDE_EXIT: + errorStringId = STR_RIDE_EXIT_IN_THE_WAY; + break; + case ENTRANCE_TYPE_PARK_ENTRANCE: + errorStringId = STR_PARK_ENTRANCE_IN_THE_WAY; + break; + } + break; + case MAP_ELEMENT_TYPE_FENCE: + sceneryEntry = g_wallSceneryEntries[mapElement->properties.scenery.type]; + errorStringId = STR_X_IN_THE_WAY; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = sceneryEntry->name; + break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + sceneryEntry = g_largeSceneryEntries[mapElement->properties.scenery.type]; + errorStringId = STR_X_IN_THE_WAY; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = sceneryEntry->name; + break; + } + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = errorStringId; +} + /** * * 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; + // return (RCT2 CALLPROC X(0x0068B932, x, bl, y, (zHigh << 8) | zLow, 0, 0, (int)clearFunc) & 0x100) == 0; + RCT2_GLOBAL(0x00F1AD40, void*) = clearFunc; + RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) = 1; + if (x >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, sint16) || y >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, sint16) || x < 32 || y < 32) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_OFF_EDGE_OF_MAP; + return false; + } + 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_SURFACE) { + if (zLow < map_element->clearance_height && zHigh > map_element->base_height && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)) { + if (map_element->flags & (bl & 0x0F)) { + goto loc_68BABC; + } + } + continue; + } + int water_height = ((map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) * 2); + if (water_height && water_height > zLow && map_element->base_height < zHigh) { + RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) |= 4; + if (water_height < zHigh) { + goto loc_68BAE6; + } + } + loc_68B9B7: + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_HIGH_CONSTRUCTION) { + int al = zHigh - map_element->base_height; + if (al >= 0) { + if (al > 18) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_LOCAL_AUTHORITY_WONT_ALLOW_CONSTRUCTION_ABOVE_TREE_HEIGHT; + return false; + } + } + } + if ((bl & 0xF0) != 0xF0) { + if (map_element->base_height >= zHigh) { + // loc_68BA81 + RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) |= 2; + RCT2_GLOBAL(RCT2_ADDRESS_ELEMENT_LOCATION_COMPARED_TO_GROUND_AND_WATER, uint8) &= 0xFE; + } else { + int al = map_element->base_height; + int ah = al; + int cl = al; + int ch = al; + uint8 slope = map_element->properties.surface.slope & MAP_ELEMENT_SLOPE_MASK; + if (slope & 1) { + al += 2; + if (slope == 0x1B) + al += 2; + } + if (slope & 2) { + ah += 2; + if (slope == 0x17) + ah += 2; + } + if (slope & 4) { + cl += 2; + if (slope == 0x1E) + cl += 2; + } + if (slope & 8) { + ch += 2; + if (slope == 0x1D) + ch += 2; + } + int bh = zLow + 4; + if ((!(bl & 1) || ((bl & 0x10 || zLow >= al) && bh >= al)) && + (!(bl & 2) || ((bl & 0x20 || zLow >= ah) && bh >= ah)) && + (!(bl & 4) || ((bl & 0x40 || zLow >= cl) && bh >= cl)) && + (!(bl & 8) || ((bl & 0x80 || zLow >= ch) && bh >= ch))) { + continue; + } + loc_68BABC: + if (RCT2_GLOBAL(0x00F1AD40, void*) != (void*)0xFFFFFFFF) { + int zero = 0; + if (!(RCT2_CALLFUNC_X((int)RCT2_GLOBAL(0x00F1AD40, void*), &zero, &zero, &zero, &zero, (int*)&map_element, &zero, &zero) & 0x100)) { + continue; + } + } + if (map_element != (rct_map_element*)0xFFFFFFF) { + map_obstruction_set_error_text(map_element); + } + return false; + loc_68BAE6: + if (RCT2_GLOBAL(0x00F1AD40, void*) != (void*)0xFFFFFFFF) { + int zero = 0; + if (!(RCT2_CALLFUNC_X((int)RCT2_GLOBAL(0x00F1AD40, void*), &zero, &zero, &zero, &zero, (int*)&map_element, &zero, &zero) & 0x100)) { + goto loc_68B9B7; + } + } + if (map_element != (rct_map_element*)0xFFFFFFF) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_CANNOT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_WATER; + } + return false; + } + } + } while (!map_element_is_last_for_tile(map_element++)); + return true; } /** @@ -2516,17 +3748,6 @@ int map_can_construct_at(int x, int y, int zLow, int zHigh, uint8 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) @@ -2545,7 +3766,7 @@ void map_remove_intersecting_walls(int x, int y, int z0, int z1, int direction) continue; map_element_remove_banner_entry(mapElement); - map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->base_height * 8 + 72); + map_invalidate_tile_zoom1(x, y, mapElement->base_height * 8, mapElement->base_height * 8 + 72); map_element_remove(mapElement); mapElement--; } while (!map_element_is_last_for_tile(mapElement++)); @@ -2654,7 +3875,7 @@ static void map_set_grass_length(int x, int y, rct_map_element *mapElement, int mapElement->properties.surface.grass_length = length; z0 = mapElement->base_height * 8; z1 = z0 + 16; - gfx_invalidate_viewport_tile(x, y, z0, z1); + map_invalidate_tile(x, y, z0, z1); } void sub_6A7594() @@ -2701,4 +3922,946 @@ void map_element_remove_banner_entry(rct_map_element *mapElement) banner->type = BANNER_NULL; user_string_free(banner->string_idx); } -} \ No newline at end of file +} + +/** + * Removes elements that are out of the map size range and crops the park perimeter. + * rct2: 0x0068ADBC + */ +void map_remove_out_of_range_elements() +{ + int mapMaxXY = RCT2_GLOBAL(RCT2_ADDRESS_MAP_MAX_XY, uint16); + + for (int y = 0; y < (256 * 32); y += 32) { + for (int x = 0; x < (256 * 32); x += 32) { + if (x == 0 || y == 0 || x >= mapMaxXY || y >= mapMaxXY) { + sub_68AE2A(x, y); + } else if (x >= mapMaxXY - 32 || y >= mapMaxXY - 32) { + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) += 32; + map_buy_land_rights(x, y, x, y, 6, GAME_COMMAND_FLAG_APPLY); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) -= 32; + } + } + } +} + +/** + * Copies the terrain and slope from the edge of the map to the new tiles. Used when increasing the size of the map. + * rct2: 0x0068AC15 + */ +void map_extend_boundary_surface() +{ + rct_map_element *existingMapElement, *newMapElement; + int x, y, z, slope; + + y = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) - 2; + for (x = 0; x < 256; x++) { + existingMapElement = map_get_surface_element_at(x, y - 1); + newMapElement = map_get_surface_element_at(x, y); + + newMapElement->type = (newMapElement->type & 0x7C) | (existingMapElement->type & 0x83); + newMapElement->properties.surface.slope = existingMapElement->properties.surface.slope & 0xE0; + newMapElement->properties.surface.terrain = existingMapElement->properties.surface.terrain; + newMapElement->properties.surface.grass_length = existingMapElement->properties.surface.grass_length; + newMapElement->properties.surface.ownership = 0; + + z = existingMapElement->base_height; + slope = existingMapElement->properties.surface.slope & 9; + if (slope == 9) { + z += 2; + slope = 0; + if (existingMapElement->properties.surface.slope & 0x10) { + slope = 1; + if (existingMapElement->properties.surface.slope & 0x04) { + slope = 8; + if (existingMapElement->properties.surface.slope & 0x02) { + slope = 0; + } + } + } + } + if (slope & 1) slope |= 2; + if (slope & 8) slope |= 4; + + newMapElement->properties.surface.slope |= slope; + newMapElement->base_height = z; + newMapElement->clearance_height = z; + } + + x = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) - 2; + for (y = 0; y < 256; y++) { + existingMapElement = map_get_surface_element_at(x - 1, y); + newMapElement = map_get_surface_element_at(x, y); + + newMapElement->type = (newMapElement->type & 0x7C) | (existingMapElement->type & 0x83); + newMapElement->properties.surface.slope = existingMapElement->properties.surface.slope & 0xE0; + newMapElement->properties.surface.terrain = existingMapElement->properties.surface.terrain; + newMapElement->properties.surface.grass_length = existingMapElement->properties.surface.grass_length; + newMapElement->properties.surface.ownership = 0; + + z = existingMapElement->base_height; + slope = existingMapElement->properties.surface.slope & 3; + if (slope == 3) { + z += 2; + slope = 0; + if (existingMapElement->properties.surface.slope & 0x10) { + slope = 1; + if (existingMapElement->properties.surface.slope & 0x04) { + slope = 2; + if (existingMapElement->properties.surface.slope & 0x08) { + slope = 0; + } + } + } + } + if (slope & 1) slope |= 8; + if (slope & 2) slope |= 4; + + newMapElement->properties.surface.slope |= slope; + newMapElement->base_height = z; + newMapElement->clearance_height = z; + } + +} + +static void sub_68AE2A(int x, int y) +{ + for (;;) { + rct2_peep_spawn *peepSpawns = RCT2_ADDRESS(RCT2_ADDRESS_PEEP_SPAWNS, rct2_peep_spawn); + for (int i = 0; i < 2; i++) { + if ((peepSpawns[i].x & 0xFFE0) == x && (peepSpawns[i].y & 0xFFE0) == y) { + peepSpawns[i].x = 0xFFFF; + } + } + + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + next_element: + switch (map_element_get_type(mapElement)) { + case MAP_ELEMENT_TYPE_SURFACE: + mapElement->base_height = 2; + mapElement->clearance_height = 2; + mapElement->properties.surface.slope = 0; + mapElement->properties.surface.terrain = 0; + mapElement->properties.surface.grass_length = 1; + mapElement->properties.surface.ownership = 0; + if (!map_element_is_last_for_tile(mapElement++)) + goto next_element; + + return; + case MAP_ELEMENT_TYPE_ENTRANCE: + viewport_interaction_remove_park_entrance(mapElement, x, y); + break; + case MAP_ELEMENT_TYPE_FENCE: + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_REMOVE_THIS; + game_do_command( + x, + GAME_COMMAND_FLAG_APPLY, + y, + (mapElement->type & MAP_ELEMENT_DIRECTION_MASK) | (mapElement->base_height << 8), + GAME_COMMAND_REMOVE_FENCE, + 0, + 0 + ); + break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_REMOVE_THIS; + game_do_command( + x, + (GAME_COMMAND_FLAG_APPLY) | (mapElement->type & MAP_ELEMENT_DIRECTION_MASK), + y, + (mapElement->base_height) | (((mapElement->properties.scenerymultiple.type >> 8) >> 2) << 8), + GAME_COMMAND_REMOVE_LARGE_SCENERY, + 0, + 0 + ); + break; + case MAP_ELEMENT_TYPE_BANNER: + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = STR_CANT_REMOVE_THIS; + game_do_command( + x, + GAME_COMMAND_FLAG_APPLY, + y, + (mapElement->base_height) | ((mapElement->properties.banner.position & 3) << 8), + GAME_COMMAND_REMOVE_BANNER, + 0, + 0 + ); + break; + default: + map_element_remove(mapElement); + break; + } + } +} + +int map_get_highest_z(int tileX, int tileY) +{ + rct_map_element *mapElement; + int z; + + mapElement = map_get_surface_element_at(tileX, tileY); + if (mapElement == NULL) + return -1; + + z = mapElement->base_height * 8; + + // Raise z so that is above highest point of land and water on tile + if ((mapElement->properties.surface.slope & 0x0F) != 0) + z += 16; + if ((mapElement->properties.surface.slope & 0x10) != 0) + z += 16; + + z = max(z, (mapElement->properties.surface.terrain & 0x1F) * 16); + return z; +} + +bool map_element_is_underground(rct_map_element *mapElement) +{ + do { + mapElement++; + if (map_element_is_last_for_tile(mapElement - 1)) + return false; + } while (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_SURFACE); + return true; +} + +rct_map_element *map_get_large_scenery_segment(int x, int y, int z, int direction, int sequence) +{ + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) + continue; + if (mapElement->base_height != z) + continue; + if ((mapElement->properties.scenerymultiple.type >> 10) != sequence) + continue; + if ((mapElement->type & MAP_ELEMENT_DIRECTION_MASK) != direction) + continue; + + return mapElement; + } while (!map_element_is_last_for_tile(mapElement++)); + return NULL; +} + +rct_map_element *map_get_fence_element_at(int x, int y, int z, int direction) +{ + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_FENCE) + continue; + if (mapElement->base_height != z) + continue; + if (map_element_get_direction(mapElement) != direction) + continue; + + return mapElement; + } while (!map_element_is_last_for_tile(mapElement++)); + return NULL; +} + +rct_map_element *map_get_small_scenery_element_at(int x, int y, int z, int type) +{ + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_SCENERY) + continue; + if (mapElement->base_height != z) + continue; + if (mapElement->properties.scenery.type != type) + continue; + + return mapElement; + } while (!map_element_is_last_for_tile(mapElement++)); + return NULL; +} + +bool map_large_scenery_get_origin( + int x, int y, int z, int direction, int sequence, + int *outX, int *outY, int *outZ, rct_map_element** outElement +) { + rct_map_element *mapElement; + rct_scenery_entry *sceneryEntry; + rct_large_scenery_tile *tile; + sint16 offsetX, offsetY; + + mapElement = map_get_large_scenery_segment(x, y, z, direction, sequence); + if (mapElement == NULL) + return false; + + sceneryEntry = g_largeSceneryEntries[(mapElement->properties.scenerymultiple.type) & 0x3FF]; + tile = &sceneryEntry->large_scenery.tiles[sequence]; + + offsetX = tile->x_offset; + offsetY = tile->y_offset; + rotate_map_coordinates(&offsetX, &offsetY, direction); + + *outX = x - offsetX; + *outY = y - offsetY; + *outZ = (z * 8) - tile->z_offset; + if (outElement != NULL) + *outElement = mapElement; + return true; +} + +/** + * + * rct2: 0x006B9B05 + */ +void sign_set_colour(int x, int y, int z, int direction, int sequence, uint8 mainColour, uint8 textColour) +{ + rct_map_element *mapElement; + rct_scenery_entry *sceneryEntry; + rct_large_scenery_tile *sceneryTiles, *tile; + sint16 offsetX, offsetY; + int x0, y0, z0; + + if (!map_large_scenery_get_origin(x, y, z, direction, sequence, &x0, &y0, &z0, &mapElement)); + + sceneryEntry = g_largeSceneryEntries[(mapElement->properties.scenerymultiple.type) & 0x3FF]; + sceneryTiles = sceneryEntry->large_scenery.tiles; + + // Iterate through each tile of the large scenery element + sequence = 0; + for (tile = sceneryTiles; tile->x_offset != -1; tile++, sequence++) { + offsetX = tile->x_offset; + offsetY = tile->y_offset; + rotate_map_coordinates(&offsetX, &offsetY, direction); + + x = x0 + offsetX; + y = y0 + offsetY; + z = (z0 + tile->z_offset) / 8; + mapElement = map_get_large_scenery_segment(x, y, z, direction, sequence); + if (mapElement != NULL) { + mapElement->properties.scenerymultiple.colour[0] &= 0xE0; + mapElement->properties.scenerymultiple.colour[1] &= 0xE0; + mapElement->properties.scenerymultiple.colour[0] |= mainColour; + mapElement->properties.scenerymultiple.colour[1] |= textColour; + + map_invalidate_tile(x, y, mapElement->base_height * 8 , mapElement->clearance_height * 8); + } + } +} + +/** + * + * rct2: 0x006E588E + */ +void map_remove_walls_at(int x, int y, int z0, int z1) +{ + rct_map_element *mapElement; + + z0 /= 8; + z1 /= 8; +repeat: + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_FENCE) + continue; + if (z0 >= mapElement->clearance_height) + continue; + if (z1 <= mapElement->base_height) + continue; + + map_element_remove_banner_entry(mapElement); + map_invalidate_tile_zoom1(x, y, mapElement->base_height * 8, mapElement->base_height * 8 + 72); + map_element_remove(mapElement); + goto repeat; + } while (!map_element_is_last_for_tile(mapElement++)); +} + +/** + * + * rct2: 0x006E57E6 + */ +void map_remove_walls_at_z(int x, int y, int z) +{ + map_remove_walls_at(x, y, z, z + 48); +} + +static void translate_3d_to_2d(int rotation, int *x, int *y) +{ + int rx, ry; + + switch (rotation & 3) { + case 0: + rx = (*y) - (*x); + ry = (*x) + (*y); + break; + case 1: + rx = -(*x) - (*y); + ry = (*y) - (*x); + break; + case 2: + rx = (*x) - (*y); + ry = -(*x) - (*y); + break; + case 3: + rx = (*x) + (*y); + ry = (*x) - (*y); + break; + } + ry /= 2; + + *x = rx; + *y = ry; +} + +void map_invalidate_tile_under_zoom(int x, int y, int z0, int z1, int maxZoom) +{ + int x1, y1, x2, y2; + rct_viewport **vp; + + x += 16; + y += 16; + translate_3d_to_2d(get_current_rotation(), &x, &y); + + x1 = x - 32; + y1 = y - 32 - z1; + x2 = x + 32; + y2 = y + 32 - z0; + + vp = RCT2_ADDRESS(RCT2_ADDRESS_ACTIVE_VIEWPORT_PTR_ARRAY, rct_viewport*); + while (!gOpenRCT2Headless && *vp != 0) { + if (maxZoom == -1 || (*vp)->zoom <= maxZoom) { + viewport_invalidate(*vp, x1, y1, x2, y2); + } + vp++; + } +} + +/** + * + * rct2: 0x006EC847 + */ +void map_invalidate_tile(int x, int y, int z0, int z1) +{ + map_invalidate_tile_under_zoom(x, y, z0, z1, -1); +} + +/** + * + * rct2: 0x006ECB60 + */ +void map_invalidate_tile_zoom1(int x, int y, int z0, int z1) +{ + map_invalidate_tile_under_zoom(x, y, z0, z1, 1); +} + +/** + * + * rct2: 0x006EC9CE + */ +void map_invalidate_tile_zoom0(int x, int y, int z0, int z1) +{ + map_invalidate_tile_under_zoom(x, y, z0, z1, 0); +} + +/** + * + * rct2: 0x006EC6D7 + */ +void map_invalidate_tile_full(int x, int y) +{ + map_invalidate_tile(x, y, 0, 2080); +} + +void map_invalidate_element(int x, int y, rct_map_element *mapElement) +{ + map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); +} + +int map_get_tile_side(int mapX, int mapY) +{ + int subMapX = mapX & (32 - 1); + int subMapY = mapY & (32 - 1); + return (subMapX < subMapY) ? + ((subMapX + subMapY) < 32 ? 0 : 1): + ((subMapX + subMapY) < 32 ? 3 : 2); +} + +int map_get_tile_quadrant(int mapX, int mapY) +{ + int subMapX = mapX & (32 - 1); + int subMapY = mapY & (32 - 1); + return (subMapX > 16) ? + (subMapY < 16 ? 1 : 0): + (subMapY < 16 ? 2 : 3); +} + +/* rct2: 0x00693BFF */ +bool map_surface_is_blocked(sint16 x, sint16 y){ + rct_map_element *mapElement; + if (x >= 8192 || y >= 8192) + return true; + + mapElement = map_get_surface_element_at(x / 32, y / 32); + + sint16 water_height = mapElement->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK; + water_height *= 2; + if (water_height > mapElement->base_height) + return true; + + sint16 base_z = mapElement->base_height; + sint16 clear_z = mapElement->base_height + 2; + if (mapElement->properties.surface.slope & (1 << 4)) + clear_z += 2; + + while (!map_element_is_last_for_tile(mapElement++)){ + if (clear_z >= mapElement->clearance_height) + continue; + + if (base_z < mapElement->base_height) + continue; + + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH || + map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_FENCE) + continue; + + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_SCENERY) + return true; + + rct_scenery_entry* scenery = g_smallSceneryEntries[mapElement->properties.scenery.type]; + if (scenery->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE) + return true; + } + return false; +} + +/* Clears all map elements, to be used before generating a new map */ +void map_clear_all_elements() +{ + for (int y = 0; y < (256 * 32); y += 32) { + for (int x = 0; x < (256 * 32); x += 32) { + sub_68AE2A(x, y); + } + } +} + +money32 place_park_entrance(int flags, sint16 x, sint16 y, sint16 z, uint8 direction) { + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LAND_PURCHASE * 4; + + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, sint16) = y; + // ?? + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, sint16) = (z & 0xFF) << 4; + + if (!sub_68B044()) { + return MONEY32_UNDEFINED; + } + + if (x <= 32 || y <= 32 || x >= (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, sint16) - 32) || y >= (RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, sint16) - 32)) { + RCT2_GLOBAL(0x00141E9AC, rct_string_id) = 3215; + return MONEY32_UNDEFINED; + } + + sint8 entranceNum = -1; + for (uint8 i = 0; i < 4; ++i) { + if (RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[i] == (sint16)0x8000) { + entranceNum = i; + break; + } + } + + if (entranceNum == -1) { + RCT2_GLOBAL(0x00141E9AC, rct_string_id) = 3227; + return MONEY32_UNDEFINED; + } + + if (flags & GAME_COMMAND_FLAG_APPLY) { + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_X, sint16)[entranceNum] = x; + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Y, sint16)[entranceNum] = y; + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_Z, sint16)[entranceNum] = (z & 0xFF) << 4; + RCT2_ADDRESS(RCT2_ADDRESS_PARK_ENTRANCE_DIRECTION, uint8)[entranceNum] = direction; + } + + sint8 zLow = (z & 0xFF) * 2; + sint8 zHigh = zLow + 12; + if (!map_can_construct_at(x, y, zLow, zHigh, 0xF)) { + return MONEY32_UNDEFINED; + } + + if (flags & GAME_COMMAND_FLAG_APPLY) { + + if (!(flags & GAME_COMMAND_FLAG_GHOST)) { + rct_map_element* surfaceElement = map_get_surface_element_at(x / 32, y / 32); + surfaceElement->properties.surface.ownership = 0; + } + + rct_map_element* newElement = map_element_insert(x / 32, y / 32, zLow, 0xF); + newElement->clearance_height = zHigh; + + if (flags & GAME_COMMAND_FLAG_GHOST) { + newElement->flags |= MAP_ELEMENT_FLAG_GHOST; + } + + newElement->type = MAP_ELEMENT_TYPE_ENTRANCE; + newElement->type |= direction; + newElement->properties.entrance.index = 0; + newElement->properties.entrance.type = ENTRANCE_TYPE_PARK_ENTRANCE; + newElement->properties.entrance.path_type = RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, uint16) & 0xFF; + + if (!(flags & GAME_COMMAND_FLAG_GHOST)) { + footpath_connect_edges(x, y, newElement, 1); + } + + 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); + + map_invalidate_tile(x, y, newElement->base_height * 8, newElement->clearance_height * 8); + + map_animation_create(MAP_ANIMATION_TYPE_PARK_ENTRANCE, x, y, zLow); + } + + x += TileDirectionDelta[(direction - 1) & 0x3].x; + y += TileDirectionDelta[(direction - 1) & 0x3].y; + + if (!map_can_construct_at(x, y, zLow, zHigh, 0xF)) { + return MONEY32_UNDEFINED; + } + + if (flags & GAME_COMMAND_FLAG_APPLY) { + + if (!(flags & GAME_COMMAND_FLAG_GHOST)) { + rct_map_element* surfaceElement = map_get_surface_element_at(x / 32, y / 32); + surfaceElement->properties.surface.ownership = 0; + } + + rct_map_element* newElement = map_element_insert(x / 32, y / 32, zLow, 0xF); + newElement->clearance_height = zHigh; + + if (flags & GAME_COMMAND_FLAG_GHOST) { + newElement->flags |= MAP_ELEMENT_FLAG_GHOST; + } + + newElement->type = MAP_ELEMENT_TYPE_ENTRANCE; + newElement->type |= direction; + newElement->properties.entrance.index = 1; + newElement->properties.entrance.type = ENTRANCE_TYPE_PARK_ENTRANCE; + + 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); + + map_invalidate_tile(x, y, newElement->base_height * 8, newElement->clearance_height * 8); + } + + x += TileDirectionDelta[(direction + 1) & 0x3].x * 2; + y += TileDirectionDelta[(direction + 1) & 0x3].y * 2; + + if (!map_can_construct_at(x, y, zLow, zHigh, 0xF)) { + return MONEY32_UNDEFINED; + } + + if (flags & GAME_COMMAND_FLAG_APPLY) { + + if (!(flags & GAME_COMMAND_FLAG_GHOST)) { + rct_map_element* surfaceElement = map_get_surface_element_at(x / 32, y / 32); + surfaceElement->properties.surface.ownership = 0; + } + + rct_map_element* newElement = map_element_insert(x / 32, y / 32, zLow, 0xF); + newElement->clearance_height = zHigh; + + if (flags & GAME_COMMAND_FLAG_GHOST) { + newElement->flags |= MAP_ELEMENT_FLAG_GHOST; + } + + newElement->type = MAP_ELEMENT_TYPE_ENTRANCE; + newElement->type |= direction; + newElement->properties.entrance.index = 2; + newElement->properties.entrance.type = ENTRANCE_TYPE_PARK_ENTRANCE; + + 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); + + map_invalidate_tile(x, y, newElement->base_height * 8, newElement->clearance_height * 8); + } + + return 0; +} + +/* rct2: 0x006666E7 */ +void game_command_place_park_entrance(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) { + *ebx = place_park_entrance( + *ebx & 0xFF, + *eax & 0xFFFF, + *ecx & 0xFFFF, + *edx & 0xFFFF, + (*ebx >> 8) & 0xFF); +} + +void game_command_set_banner_name(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) { + static char newName[128]; + + rct_banner* banner = &gBanners[*ecx]; + + int nameChunkIndex = *eax & 0xFFFF; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_RUNNING_COSTS * 4; + 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; + } + + utf8 *buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, uint8); + utf8 *dst = buffer; + dst = utf8_write_codepoint(dst, FORMAT_COLOUR_CODE_START + banner->text_colour); + strncpy(dst, newName, 32); + + rct_string_id stringId = user_string_allocate(128, buffer); + if (stringId) { + rct_string_id prev_string_id = banner->string_idx; + banner->string_idx = stringId; + user_string_free(prev_string_id); + rct_window* w = window_bring_to_front_by_number(WC_BANNER, *ecx); + if (w) { + window_invalidate(w); + } + } else { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 2984; + *ebx = MONEY32_UNDEFINED; + return; + } + + *ebx = 0; +} + +void game_command_set_sign_name(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) { + static char newName[128]; + + rct_banner* banner = &gBanners[*ecx]; + int x = banner->x << 5; + int y = banner->y << 5; + + int nameChunkIndex = *eax & 0xFFFF; + + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_RUNNING_COSTS * 4; + 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; + } + + if (newName[0] != 0) { + rct_string_id string_id = user_string_allocate(128, newName); + 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 { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 2984; + *ebx = MONEY32_UNDEFINED; + return; + } + } + else{ + int rideIndex = banner_get_closest_ride_index(x, y, 16); + if (rideIndex == -1) { + *ebx = 0; + return; + } + + banner->colour = rideIndex; + banner->flags |= BANNER_FLAG_2; + + rct_string_id prev_string_id = banner->string_idx; + banner->string_idx = 778; + user_string_free(prev_string_id); + gfx_invalidate_screen(); + } + + *ebx = 0; +} + +void game_command_set_banner_style(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) { + rct_banner* banner = &gBanners[*ecx]; + + banner->colour = (uint8)*edx; + banner->text_colour = (uint8)*edi; + banner->flags = (uint8)*ebp; + + uint8 bannerIndex = *ecx & 0xFF; + + int x = banner->x << 5; + int y = banner->y << 5; + + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + bool bannerFound = false; + do { + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_BANNER) + continue; + + if (map_element->properties.banner.index != bannerIndex) + continue; + + bannerFound = true; + break; + } while (!map_element_is_last_for_tile(map_element++)); + + if (bannerFound == false) { + *ebx = MONEY32_UNDEFINED; + return; + } + + map_element->properties.banner.flags = 0xFF; + if (banner->flags & BANNER_FLAG_NO_ENTRY){ + map_element->properties.banner.flags &= ~(1 << map_element->properties.banner.position); + } + + int colourCodepoint = FORMAT_COLOUR_CODE_START + banner->text_colour; + + uint8 buffer[256]; + format_string(buffer, banner->string_idx, 0); + int firstCodepoint = utf8_get_next(buffer, NULL); + if (firstCodepoint >= FORMAT_COLOUR_CODE_START && firstCodepoint <= FORMAT_COLOUR_CODE_END) { + utf8_write_codepoint(buffer, colourCodepoint); + } else { + utf8_insert_codepoint(buffer, colourCodepoint); + } + + rct_string_id stringId = user_string_allocate(128, buffer); + if (stringId != 0) { + rct_string_id prev_string_id = banner->string_idx; + banner->string_idx = stringId; + user_string_free(prev_string_id); + rct_window* w = window_bring_to_front_by_number(WC_BANNER, *ecx); + if (w) { + window_invalidate(w); + } + } else { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 2984; + *ebx = MONEY32_UNDEFINED; + return; + } + + *ebx = 0; +} + +void game_command_set_sign_style(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) { + uint8 bannerId = *ecx & 0xFF; + rct_banner *banner = &gBanners[bannerId]; + int x = banner->x << 5; + int y = banner->y << 5; + + uint8 mainColour = (uint8)*edx; + uint8 textColour = (uint8)*edi; + + if (*ebp == 0) { // small sign + + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + bool fence_found = false; + do{ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_FENCE) + continue; + + rct_scenery_entry* scenery_entry = g_wallSceneryEntries[map_element->properties.fence.type]; + if (scenery_entry->wall.var_0D == 0xFF) + continue; + if (map_element->properties.fence.item[0] != bannerId) + continue; + fence_found = true; + break; + } while (!map_element_is_last_for_tile(map_element++)); + + if (fence_found == false) { + *ebx = MONEY32_UNDEFINED; + return; + } + map_element->flags &= 0x9F; + map_element->properties.fence.item[1] = + mainColour | + ((textColour & 0x7) << 5); + map_element->flags |= ((textColour & 0x18) << 2); + + map_invalidate_tile(x, y, map_element->base_height * 8, map_element->clearance_height * 8); + } else { // large sign + rct_map_element *mapElement = banner_get_map_element(bannerId); + if (mapElement == NULL || map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 2984; + *ebx = MONEY32_UNDEFINED; + return; + } + + sign_set_colour( + banner->x * 32, + banner->y * 32, + mapElement->base_height, + mapElement->type & 3, + mapElement->properties.scenerymultiple.type >> 10, + mainColour, + textColour + ); + } + + rct_window* w = window_bring_to_front_by_number(WC_BANNER, *ecx); + if (w) { + window_invalidate(w); + } + + *ebx = 0; +} + +/** + * Gets the map element at x, y, z. + * @param x x units, not tiles. + * @param y y units, not tiles. + * @param z Base height. + */ +rct_map_element *map_get_track_element_at(int x, int y, int z) +{ + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) continue; + if (mapElement->base_height != z) continue; + + return mapElement; + } while (!map_element_is_last_for_tile(mapElement++)); + + return NULL; +} + +/** + * Gets the map element at x, y, z. + * @param x x units, not tiles. + * @param y y units, not tiles. + * @param z Base height. + */ +rct_map_element *map_get_track_element_at_of_type(int x, int y, int z, int trackType) +{ + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) continue; + if (mapElement->base_height != z) continue; + if (mapElement->properties.track.type != trackType) continue; + + return mapElement; + } while (!map_element_is_last_for_tile(mapElement++)); + + return NULL; +} diff --git a/src/world/map.h b/src/world/map.h index db3cda5299..d2db49fefa 100644 --- a/src/world/map.h +++ b/src/world/map.h @@ -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 . *****************************************************************************/ @@ -34,7 +34,10 @@ typedef struct { uint8 type; //4 uint8 additions; //5 uint8 edges; //6 - uint8 addition_status; //7 + union { + uint8 addition_status; //7 + uint8 ride_index; + }; } rct_map_element_path_properties; typedef struct { @@ -121,6 +124,10 @@ enum { MAP_ELEMENT_TYPE_BANNER = (7 << 2) }; +enum { + MAP_ELEMENT_TYPE_FLAG_HIGHLIGHT = (1 << 6) +}; + enum { MAP_ELEMENT_DIRECTION_WEST, MAP_ELEMENT_DIRECTION_NORTH, @@ -196,6 +203,10 @@ enum { ENTRANCE_TYPE_PARK_ENTRANCE }; +enum { + ELEMENT_IS_UNDERWATER = 4, +}; + #define MAP_ELEMENT_QUADRANT_MASK 0xC0 #define MAP_ELEMENT_TYPE_MASK 0x3C #define MAP_ELEMENT_DIRECTION_MASK 0x03 @@ -220,6 +231,10 @@ typedef struct { uint8 x, y; } rct_xy8; +typedef struct{ + uint8 x, y, z, direction; +} rct_xyzd8; + typedef struct { sint16 x, y; } rct_xy16; @@ -241,9 +256,16 @@ typedef struct { } rct2_peep_spawn; extern const rct_xy16 TileDirectionDelta[]; + +extern rct_map_element *gMapElements; +extern rct_map_element **gMapElementTilePointers; + extern rct_xy16 *gMapSelectionTiles; +extern rct2_peep_spawn *gPeepSpawns; +// Used in the land tool window to enable mountain tool / land smoothing +extern bool gLandMountainMode; // Used in the land tool window to allow dragging and changing land styles -extern bool LandPaintMode; +extern bool gLandPaintMode; // Used in the land rights tool window to either buy land rights or construction rights extern bool LandRightsMode; // Used in the clear scenery tool @@ -254,26 +276,30 @@ extern bool gClearFootpath; void map_init(int size); void map_update_tile_pointers(); rct_map_element *map_get_first_element_at(int x, int y); +void map_set_tile_elements(int x, int y, rct_map_element *elements); int map_element_is_last_for_tile(rct_map_element *element); int map_element_get_type(rct_map_element *element); +int map_element_get_direction(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_banner_element_at(int x, int y, int z, uint8 direction); 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); +rct_map_element *map_get_fence_element_at(int x, int y, int z, int direction); +rct_map_element *map_get_small_scenery_element_at(int x, int y, int z, int type); int map_element_height(int x, int y); void sub_68B089(); int map_coord_is_connected(int x, int y, int z, uint8 faceDirection); -void sub_6A876D(); +void map_update_path_wide_flags(); 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); +bool map_is_location_owned_or_has_rights(int x, int y); +bool map_surface_is_blocked(sint16 x, sint16 y); 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(); @@ -282,12 +308,15 @@ 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); +void rotate_map_coordinates(sint16 *x, sint16 *y, int rotation); +rct_xy16 coordinate_3d_to_2d(const rct_xyz16* coordinate_3d, int rotation); +money32 map_clear_scenery(int x0, int y0, int x1, int y1, int clear, 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); +money32 map_place_fence(int type, int x, int y, int z, int edge, int primaryColour, int secondaryColour, int tertiaryColour, int flags); +void game_command_set_land_height(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void game_command_set_land_ownership(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); 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); @@ -299,12 +328,20 @@ void game_command_clear_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi 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_smooth_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_set_water_height(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_fence(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); +void game_command_place_park_entrance(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_set_banner_name(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_set_sign_name(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_set_banner_style(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); +void game_command_set_sign_style(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]) @@ -321,9 +358,39 @@ 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(); +int map_get_highest_z(int tileX, int tileY); void sub_6A7594(); int map_element_get_banner_index(rct_map_element *mapElement); void map_element_remove_banner_entry(rct_map_element *mapElement); +bool map_element_is_underground(rct_map_element *mapElement); + +void map_remove_out_of_range_elements(); +void map_extend_boundary_surface(); + +void sign_set_colour(int x, int y, int z, int direction, int sequence, uint8 mainColour, uint8 textColour); +void map_remove_walls_at(int x, int y, int z0, int z1); +void map_remove_walls_at_z(int x, int y, int z); + +void map_invalidate_tile(int x, int y, int z0, int z1); +void map_invalidate_tile_zoom1(int x, int y, int z0, int z1); +void map_invalidate_tile_zoom0(int x, int y, int z0, int z1); +void map_invalidate_tile_full(int x, int y); +void map_invalidate_element(int x, int y, rct_map_element *mapElement); + +int map_get_tile_side(int mapX, int mapY); +int map_get_tile_quadrant(int mapX, int mapY); + +void map_clear_all_elements(); + +rct_map_element *map_get_large_scenery_segment(int x, int y, int z, int direction, int sequence); +bool map_large_scenery_get_origin( + int x, int y, int z, int direction, int sequence, + int *outX, int *outY, int *outZ, rct_map_element** outElement +); + +rct_map_element *map_get_track_element_at(int x, int y, int z); +rct_map_element *map_get_track_element_at_of_type(int x, int y, int z, int trackType); + #endif diff --git a/src/world/map_animation.c b/src/world/map_animation.c index 3a31fe5d82..ab45491527 100644 --- a/src/world/map_animation.c +++ b/src/world/map_animation.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,7 @@ #include "../ride/ride.h" #include "../ride/ride_data.h" #include "../ride/track.h" +#include "../interface/viewport.h" #include "map_animation.h" #include "map.h" #include "scenery.h" @@ -36,7 +37,7 @@ static const map_animation_invalidate_event_handler _animatedObjectEventHandlers rct_map_animation *gAnimatedObjects = (rct_map_animation*)0x013886A0; /** - * + * * rct2: 0x0068AF67 * * @param type (dh) @@ -48,6 +49,10 @@ void map_animation_create(int type, int x, int y, int z) { rct_map_animation *aobj = &gAnimatedObjects[0]; int numAnimatedObjects = RCT2_GLOBAL(0x0138B580, uint16); + if (numAnimatedObjects >= 2000) { + log_error("Exceeded the maximum number of animations"); + return; + } for (int i = 0; i < numAnimatedObjects; i++, aobj++) { if (aobj->x != x) continue; @@ -124,7 +129,7 @@ static bool map_animation_invalidate_ride_entrance(int x, int y, int baseZ) entranceDefinition = &RideEntranceDefinitions[ride->entrance_style]; int height = (mapElement->base_height * 8) + entranceDefinition->height + 8; - map_invalidate_tile(x, y, height, height + 16); + map_invalidate_tile_zoom1(x, y, height, height + 16); return false; } while (!map_element_is_last_for_tile(mapElement++)); @@ -150,10 +155,10 @@ static bool map_animation_invalidate_queue_banner(int x, int y, int baseZ) if (!(mapElement->properties.path.type & PATH_FLAG_QUEUE_BANNER)) continue; - int direction = ((mapElement->type >> 6) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)) & 3; + int direction = ((mapElement->type >> 6) + get_current_rotation()) & 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); + map_invalidate_tile_zoom1(x, y, baseZ + 16, baseZ + 30); } return false; } while (!map_element_is_last_for_tile(mapElement++)); @@ -183,13 +188,13 @@ static bool map_animation_invalidate_small_scenery(int x, int y, int baseZ) 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); + map_invalidate_tile_zoom1(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)) { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 0x3FF) && RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0) { int direction = mapElement->type & 3; int x2 = x - TileDirectionDelta[direction].x; int y2 = y - TileDirectionDelta[direction].y; @@ -212,11 +217,11 @@ static bool map_animation_invalidate_small_scenery(int x, int y, int baseZ) 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); + invalidate_sprite_1((rct_sprite*)peep); break; } } - map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + map_invalidate_tile_zoom1(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); return false; } } while (!map_element_is_last_for_tile(mapElement++)); @@ -243,7 +248,7 @@ static bool map_animation_invalidate_park_entrance(int x, int y, int baseZ) continue; baseZ = mapElement->base_height * 8; - map_invalidate_tile(x, y, baseZ + 32, baseZ + 64); + map_invalidate_tile_zoom1(x, y, baseZ + 32, baseZ + 64); return false; } while (!map_element_is_last_for_tile(mapElement++)); @@ -267,7 +272,7 @@ static bool map_animation_invalidate_track_waterfall(int x, int y, int baseZ) if (mapElement->properties.track.type == TRACK_ELEM_WATERFALL) { int z = mapElement->base_height * 8; - map_invalidate_tile(x, y, z + 14, z + 46); + map_invalidate_tile_zoom1(x, y, z + 14, z + 46); return false; } } while (!map_element_is_last_for_tile(mapElement++)); @@ -292,7 +297,7 @@ static bool map_animation_invalidate_track_rapids(int x, int y, int baseZ) if (mapElement->properties.track.type == TRACK_ELEM_RAPIDS) { int z = mapElement->base_height * 8; - map_invalidate_tile(x, y, z + 14, z + 18); + map_invalidate_tile_zoom1(x, y, z + 14, z + 18); return false; } } while (!map_element_is_last_for_tile(mapElement++)); @@ -318,7 +323,10 @@ static bool map_animation_invalidate_track_onridephoto(int x, int y, int baseZ) 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); + map_invalidate_tile_zoom1(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0) { + return false; + } if (mapElement->properties.track.sequence & 0xF0) { mapElement->properties.track.sequence -= 0x10; return false; @@ -348,7 +356,7 @@ static bool map_animation_invalidate_track_whirlpool(int x, int y, int baseZ) if (mapElement->properties.track.type == TRACK_ELEM_WHIRLPOOL) { int z = mapElement->base_height * 8; - map_invalidate_tile(x, y, z + 14, z + 18); + map_invalidate_tile_zoom1(x, y, z + 14, z + 18); return false; } } while (!map_element_is_last_for_tile(mapElement++)); @@ -373,7 +381,7 @@ static bool map_animation_invalidate_track_spinningtunnel(int x, int y, int base if (mapElement->properties.track.type == TRACK_ELEM_SPINNING_TUNNEL) { int z = mapElement->base_height * 8; - map_invalidate_tile(x, y, z + 14, z + 32); + map_invalidate_tile_zoom1(x, y, z + 14, z + 32); return false; } } while (!map_element_is_last_for_tile(mapElement++)); @@ -404,9 +412,9 @@ static bool map_animation_invalidate_banner(int x, int y, int 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); + map_invalidate_tile_zoom1(x, y, baseZ, baseZ + 16); return false; } while (!map_element_is_last_for_tile(mapElement++)); @@ -433,7 +441,7 @@ static bool map_animation_invalidate_large_scenery(int x, int y, int baseZ) 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); + map_invalidate_tile_zoom1(x, y, z, z + 16); wasInvalidated = true; } } while (!map_element_is_last_for_tile(mapElement++)); @@ -445,7 +453,7 @@ static bool map_animation_invalidate_large_scenery(int x, int y, int baseZ) * * rct2: 0x006E5B50 */ -static bool map_animation_invalidate_wall_unknown(int x, int y, int baseZ) +static bool map_animation_invalidate_wall_door(int x, int y, int baseZ) { rct_map_element *mapElement; rct_scenery_entry *sceneryEntry; @@ -484,11 +492,13 @@ static bool map_animation_invalidate_wall_unknown(int x, int y, int baseZ) } } } - + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0) { + return false; + } mapElement->properties.fence.item[2] = bl; if (di & 1) { int z = mapElement->base_height * 8; - map_invalidate_tile(x, y, z, z + 32); + map_invalidate_tile_zoom1(x, y, z, z + 32); } if (di & 2) wasInvalidated = true; @@ -519,7 +529,7 @@ static bool map_animation_invalidate_wall(int x, int y, int baseZ) continue; int z = mapElement->base_height * 8; - map_invalidate_tile(x, y, z, z + 16); + map_invalidate_tile_zoom1(x, y, z, z + 16); wasInvalidated = true; } while (!map_element_is_last_for_tile(mapElement++)); @@ -540,6 +550,6 @@ static const map_animation_invalidate_event_handler _animatedObjectEventHandlers map_animation_invalidate_remove, map_animation_invalidate_banner, map_animation_invalidate_large_scenery, - map_animation_invalidate_wall_unknown, + map_animation_invalidate_wall_door, map_animation_invalidate_wall -}; \ No newline at end of file +}; diff --git a/src/world/map_animation.h b/src/world/map_animation.h index ce749b6110..2bf35cd1c5 100644 --- a/src/world/map_animation.h +++ b/src/world/map_animation.h @@ -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 . *****************************************************************************/ diff --git a/src/world/map_helpers.c b/src/world/map_helpers.c index be2644ecaf..773def8cb9 100644 --- a/src/world/map_helpers.c +++ b/src/world/map_helpers.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 . *****************************************************************************/ @@ -61,8 +61,8 @@ int map_smooth(int l, int t, int r, int b) 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 + // 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){ @@ -297,14 +297,14 @@ int map_smooth_wavy(int l, int t, int r, int b) 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 || diff --git a/src/world/map_helpers.h b/src/world/map_helpers.h index 423bb4c25e..3a2dffa630 100644 --- a/src/world/map_helpers.h +++ b/src/world/map_helpers.h @@ -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 . *****************************************************************************/ diff --git a/src/world/mapgen.c b/src/world/mapgen.c index b71fd3c6ca..4650b4307e 100644 --- a/src/world/mapgen.c +++ b/src/world/mapgen.c @@ -8,23 +8,20 @@ * 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 "../util/util.h" #include "map.h" #include "map_helpers.h" #include "mapgen.h" @@ -109,6 +106,8 @@ void mapgen_generate_blank(mapgen_settings *settings) int x, y; rct_map_element *mapElement; + map_clear_all_elements(); + map_init(settings->mapSize); for (y = 1; y < settings->mapSize - 1; y++) { for (x = 1; x < settings->mapSize - 1; x++) { @@ -128,7 +127,7 @@ void mapgen_generate(mapgen_settings *settings) int x, y, mapSize, floorTexture, wallTexture, waterLevel; rct_map_element *mapElement; - srand((unsigned int)time(NULL)); + util_srand((unsigned int)time(NULL)); mapSize = settings->mapSize; floorTexture = settings->floor; @@ -136,7 +135,7 @@ void mapgen_generate(mapgen_settings *settings) waterLevel = settings->waterLevel; if (floorTexture == -1) - floorTexture = BaseTerrain[rand() % countof(BaseTerrain)]; + floorTexture = BaseTerrain[util_rand() % countof(BaseTerrain)]; if (wallTexture == -1) { // Base edge type on surface type @@ -153,6 +152,8 @@ void mapgen_generate(mapgen_settings *settings) } } + map_clear_all_elements(); + // Initialise the base map map_init(mapSize); for (y = 1; y < mapSize - 1; y++) { @@ -172,7 +173,7 @@ void mapgen_generate(mapgen_settings *settings) if (1) { mapgen_simplex(settings); - mapgen_smooth_height(2 + (rand() % 6)); + mapgen_smooth_height(2 + (util_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. @@ -200,7 +201,7 @@ void mapgen_generate(mapgen_settings *settings) // Add sandy beaches int beachTexture = floorTexture; if (settings->floor == -1 && floorTexture == TERRAIN_GRASS) { - switch (rand() % 4) { + switch (util_rand() % 4) { case 0: beachTexture = TERRAIN_SAND; break; @@ -235,7 +236,7 @@ static void mapgen_place_tree(int type, int x, int y) 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->type = MAP_ELEMENT_TYPE_SCENERY | (util_rand() % 3); mapElement->properties.scenery.type = type; mapElement->properties.scenery.age = 0; mapElement->properties.scenery.colour_1 = 26; @@ -310,7 +311,7 @@ static void mapgen_place_trees() // Shuffle list for (i = 0; i < availablePositionsCount; i++) { - rindex = rand() % availablePositionsCount; + rindex = util_rand() % availablePositionsCount; if (rindex == i) continue; @@ -320,7 +321,7 @@ static void mapgen_place_trees() } // Place trees - float treeToLandRatio = (10 + (rand() % 30)) / 100.0f; + float treeToLandRatio = (10 + (util_rand() % 30)) / 100.0f; int numTrees = max(4, (int)(availablePositionsCount * treeToLandRatio)); mapSize = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, sint16); @@ -336,7 +337,7 @@ static void mapgen_place_trees() if (numGrassTreeIds == 0) break; - type = grassTreeIds[rand() % numGrassTreeIds]; + type = grassTreeIds[util_rand() % numGrassTreeIds]; break; case TERRAIN_SAND: @@ -345,15 +346,15 @@ static void mapgen_place_trees() if (numDesertTreeIds == 0) break; - if (rand() % 4 == 0) - type = desertTreeIds[rand() % numDesertTreeIds]; + if (util_rand() % 4 == 0) + type = desertTreeIds[util_rand() % numDesertTreeIds]; break; case TERRAIN_ICE: if (numSnowTreeIds == 0) break; - - type = snowTreeIds[rand() % numSnowTreeIds]; + + type = snowTreeIds[util_rand() % numSnowTreeIds]; break; } @@ -392,15 +393,15 @@ static void mapgen_blobs(int count, int lowSize, int highSize, int lowHeight, in int sizeRange = highSize - lowSize; int heightRange = highHeight - lowHeight; - int border = 2 + (rand() % 24); + int border = 2 + (util_rand() % 24); int borderRange = _heightSize - (border * 2); for (i = 0; i < count; i++) { - int radius = lowSize + (rand() % sizeRange); + int radius = lowSize + (util_rand() % sizeRange); mapgen_blob( - border + (rand() % borderRange), - border + (rand() % borderRange), + border + (util_rand() % borderRange), + border + (util_rand() % borderRange), (int)(M_PI * radius * radius), - lowHeight + (rand() % heightRange) + lowHeight + (util_rand() % heightRange) ); } } @@ -506,7 +507,7 @@ static void mapgen_blob(int cx, int cy, int size, int height) set_height(x, y, BLOB_HEIGHT); while (currentSize < size) { - if (rand() % 2 == 0) { + if (util_rand() % 2 == 0) { set_height(x, y, BLOB_HEIGHT); currentSize++; } @@ -620,7 +621,7 @@ static void mapgen_set_height() 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; @@ -655,7 +656,7 @@ static uint8 perm[512]; static void noise_rand() { for (int i = 0; i < countof(perm); i++) - perm[i] = rand() & 0xFF; + perm[i] = util_rand() & 0xFF; } static float fractal_noise(int x, int y, float frequency, int octaves, float lacunarity, float persistence) @@ -741,12 +742,6 @@ 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 @@ -776,4 +771,4 @@ static void mapgen_simplex(mapgen_settings *settings) } } -#pragma endregion \ No newline at end of file +#pragma endregion diff --git a/src/world/mapgen.h b/src/world/mapgen.h index ed6fd47450..fd83f9e3e8 100644 --- a/src/world/mapgen.h +++ b/src/world/mapgen.h @@ -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 . *****************************************************************************/ diff --git a/src/world/money_effect.c b/src/world/money_effect.c new file mode 100644 index 0000000000..b33565531f --- /dev/null +++ b/src/world/money_effect.c @@ -0,0 +1,109 @@ +#include "../localisation/localisation.h" +#include "../interface/viewport.h" +#include "../interface/window.h" +#include "sprite.h" + +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(RCT2_ADDRESS_COMMAND_MAP_X, uint16); + mapPosition.y = RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16); + mapPosition.z = RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16); + if (mapPosition.x == (sint16)0x8000) { + mainWindow = window_get_main(); + if (mainWindow == NULL) + return; + + mainViewport = mainWindow->viewport; + screen_get_map_xy( + mainViewport->x + (mainViewport->width / 2), + mainViewport->y + (mainViewport->height / 2), + &mapPosition.x, + &mapPosition.y, + NULL + ); + 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_2((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[get_current_rotation()].x; + int y = moneyEffect->y + _moneyEffectMoveOffset[get_current_rotation()].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); +} diff --git a/src/world/park.c b/src/world/park.c index abb2dd8c19..1111b8a4bd 100644 --- a/src/world/park.c +++ b/src/world/park.c @@ -8,18 +8,19 @@ * 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 "../interface/colour.h" #include "../interface/window.h" #include "../localisation/localisation.h" #include "../management/award.h" @@ -35,6 +36,12 @@ #include "sprite.h" #include "../config.h" +uint8 *gParkRatingHistory = RCT2_ADDRESS(RCT2_ADDRESS_PARK_RATING_HISTORY, uint8); +uint8 *gGuestsInParkHistory = RCT2_ADDRESS(RCT2_ADDRESS_GUESTS_IN_PARK_HISTORY, uint8); + +// If this value is more than or equal to 0, the park rating is forced to this value. Used for cheat +int gForcedParkRating = -1; + /** * In a difficult guest generation scenario, no guests will be generated if over this value. */ @@ -54,7 +61,7 @@ int park_is_open() } /** - * + * * rct2: 0x00667132 */ void park_init() @@ -63,13 +70,13 @@ void park_init() RCT2_GLOBAL(0x013CA740, uint8) = 0; 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; + RCT2_GLOBAL(RCT2_ADDRESS_HANDYMAN_COLOUR, uint8) = COLOUR_BRIGHT_RED; + RCT2_GLOBAL(RCT2_ADDRESS_MECHANIC_COLOUR, uint8) = COLOUR_LIGHT_BLUE; + RCT2_GLOBAL(RCT2_ADDRESS_SECURITY_COLOUR, uint8) = COLOUR_YELLOW; RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16) = 0; - RCT2_GLOBAL(0x01357BC8, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_LAST_GUESTS_IN_PARK, uint16) = 0; RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_HEADING_FOR_PARK, uint16) = 0; - RCT2_GLOBAL(0x013573FE, uint16) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_CHANGE_MODIFIER, uint16) = 0; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, uint16) = 0; _guestGenerationProbability = 0; RCT2_GLOBAL(RCT2_TOTAL_RIDE_VALUE, uint16) = 0; @@ -114,20 +121,19 @@ void park_init() } /** - * + * * rct2: 0x0066729F */ void park_reset_history() { - int i; - for (i = 0; i < 32; i++) { - RCT2_ADDRESS(RCT2_ADDRESS_PARK_RATING_HISTORY, uint8)[i] = 255; - RCT2_ADDRESS(RCT2_ADDRESS_GUESTS_IN_PARK_HISTORY, uint8)[i] = 255; + for (int i = 0; i < 32; i++) { + gParkRatingHistory[i] = 255; + gGuestsInParkHistory[i] = 255; } } /** - * + * * rct2: 0x0066A348 */ int park_calculate_size() @@ -149,56 +155,56 @@ int park_calculate_size() RCT2_GLOBAL(RCT2_ADDRESS_PARK_SIZE, uint16) = tiles; window_invalidate_by_class(WC_PARK_INFORMATION); } - + return tiles; } /** - * + * * rct2: 0x00669EAA */ int calculate_park_rating() { + if (gForcedParkRating >= 0) + return gForcedParkRating; + int result; result = 1150; - if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & 0x4000) + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_DIFFICULT_PARK_RATING) result = 1050; - + // Guests { rct_peep* peep; uint16 spriteIndex; int num_happy_peeps; - short _bp; - + int num_lost_guests; + // -150 to +3 based on a range of guests from 0 to 2000 result -= 150 - (min(2000, RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16)) / 13); - // Guests, happiness, ? + // Find the number of happy peeps and the number of peeps who can't find the park exit num_happy_peeps = 0; - _bp = 0; + num_lost_guests = 0; FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->var_2A != 0) + if (peep->outside_of_park != 0) continue; if (peep->happiness > 128) num_happy_peeps++; - if (!(peep->flags & PEEP_FLAGS_LEAVING_PARK)) - continue; - if (peep->var_C6 <= 89) - _bp++; + if ((peep->flags & PEEP_FLAGS_LEAVING_PARK) && (peep->peep_is_lost_countdown < 90)) + num_lost_guests++; } - + // Peep happiness -500 to +0 result -= 500; if (RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16) > 0) result += 2 * min(250, (num_happy_peeps * 300) / RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16)); - // ? - _bp -= 25; - if (_bp >= 0) - result -= _bp * 7; + // Up to 25 guests can be lost without affecting the park rating. + if (num_lost_guests > 25) + result -= (num_lost_guests - 25) * 7; } // Rides @@ -259,13 +265,13 @@ int calculate_park_rating() for (sprite_idx = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_LITTER, uint16); sprite_idx != SPRITE_INDEX_NULL; sprite_idx = litter->next) { litter = &(g_sprite_list[sprite_idx].litter); - // Guessing this eliminates recently dropped litter - if (litter->var_24 - RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) >= 7680) + // Ignore recently dropped litter + if (litter->creationTick - RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) >= 7680) num_litter++; } result -= 600 - (4 * (150 - min(150, num_litter))); } - + result -= RCT2_GLOBAL(0x0135882E, sint16); result = clamp(0, result, 999); return result; @@ -288,7 +294,7 @@ money32 calculate_ride_value(rct_ride *ride) } /** - * + * * rct2: 0x0066A3F6 */ money32 calculate_park_value() @@ -471,7 +477,7 @@ static rct_peep *park_generate_new_guest() peep = peep_generate(spawn.x, spawn.y, spawn.z * 16); if (peep != NULL) { peep->sprite_direction = spawn.direction << 3; - + // Get the centre point of the tile the peep is on peep->destination_x = (peep->x & 0xFFE0) + 16; peep->destination_y = (peep->y & 0xFFE0) + 16; @@ -531,7 +537,7 @@ void park_update() return; // Every 5 seconds approximately - if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint8) % 512 == 0) { + if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) % 512 == 0) { RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, uint16) = calculate_park_rating(); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_VALUE, money32) = calculate_park_value(); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_COMPANY_VALUE, money32) = calculate_company_value(); @@ -575,7 +581,55 @@ uint8 calculate_guest_initial_happiness(uint8 percentage) { */ void park_update_histories() { - RCT2_CALLPROC_EBPSAFE(0x0066A231); + int guestsInPark = RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16); + int lastGuestsInPark = RCT2_GLOBAL(RCT2_ADDRESS_LAST_GUESTS_IN_PARK, uint16); + RCT2_GLOBAL(RCT2_ADDRESS_LAST_GUESTS_IN_PARK, uint16) = guestsInPark; + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) |= 4; + + int changeInGuestsInPark = guestsInPark - lastGuestsInPark; + int guestChangeModifier = 1; + if (changeInGuestsInPark > -20) { + guestChangeModifier++; + if (changeInGuestsInPark < 20) + guestChangeModifier = 0; + } + RCT2_GLOBAL(RCT2_ADDRESS_GUEST_CHANGE_MODIFIER, uint8) = guestChangeModifier; + + // Update park rating history + for (int i = 31; i > 0; i--) + gParkRatingHistory[i] = gParkRatingHistory[i - 1]; + gParkRatingHistory[0] = calculate_park_rating() / 4; + window_invalidate_by_class(WC_PARK_INFORMATION); + + // Update guests in park history + for (int i = 31; i > 0; i--) + gGuestsInParkHistory[i] = gGuestsInParkHistory[i - 1]; + gGuestsInParkHistory[0] = min(guestsInPark, 5000) / 20; + window_invalidate_by_class(WC_PARK_INFORMATION); + + // Update current cash history + for (int i = 127; i > 0; i--) + gCashHistory[i] = gCashHistory[i - 1]; + gCashHistory[0] = DECRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, money32)) - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_LOAN, money32); + window_invalidate_by_class(WC_FINANCES); + + // Update weekly profit history + money32 currentWeeklyProfit = RCT2_GLOBAL(0x01358334, money32); + if (RCT2_GLOBAL(0x01358338, uint16) != 0) + currentWeeklyProfit /= RCT2_GLOBAL(0x01358338, uint16); + + for (int i = 127; i > 0; i--) + gWeeklyProfitHistory[i] = gWeeklyProfitHistory[i - 1]; + gWeeklyProfitHistory[0] = currentWeeklyProfit; + + RCT2_GLOBAL(0x01358334, money32) = 0; + RCT2_GLOBAL(0x01358338, uint16) = 0; + window_invalidate_by_class(WC_FINANCES); + + // Update park value history + for (int i = 127; i > 0; i--) + gParkValueHistory[i] = gParkValueHistory[i - 1]; + gParkValueHistory[0] = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_VALUE, money32); } void park_set_entrance_fee(money32 value) @@ -659,86 +713,6 @@ int park_get_entrance_index(int x, int y, int z) 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 @@ -749,7 +723,7 @@ void update_park_fences(int x, int y) return; if (y > 0x1FFF) return; - + rct_map_element* sufaceElement = map_get_surface_element_at(x / 32, y / 32); if (sufaceElement == NULL)return; @@ -762,7 +736,7 @@ void update_park_fences(int x, int y) do { if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_ENTRANCE) continue; - + if (mapElement->properties.entrance.type != ENTRANCE_TYPE_PARK_ENTRANCE) continue; @@ -799,7 +773,7 @@ void update_park_fences(int x, int y) if (sufaceElement->properties.surface.ownership != newOwnership) { int z0 = sufaceElement->base_height * 8; int z1 = z0 + 16; - gfx_invalidate_viewport_tile(x, y, z0, z1); + map_invalidate_tile(x, y, z0, z1); sufaceElement->properties.surface.ownership = newOwnership; } } @@ -817,7 +791,7 @@ void park_remove_entrance_segment(int x, int y, int z) 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_invalidate_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++)); @@ -835,10 +809,10 @@ void game_command_remove_park_entrance(int *eax, int *ebx, int *ecx, int *edx, i 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; + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LAND_PURCHASE * 4; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = z; if (!(*ebx & GAME_COMMAND_FLAG_APPLY)) { *ebx = 0; @@ -896,7 +870,7 @@ void game_command_set_park_name(int *eax, int *ebx, int *ecx, int *edx, int *esi int nameChunkIndex = *eax & 0xFFFF; RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; - if (*ebx & GAME_COMMAND_FLAG_APPLY) { + //if (*ebx & GAME_COMMAND_FLAG_APPLY) { // this check seems to be useless and causes problems in multiplayer int nameChunkOffset = nameChunkIndex - 1; if (nameChunkOffset < 0) nameChunkOffset = 2; @@ -904,7 +878,7 @@ void game_command_set_park_name(int *eax, int *ebx, int *ecx, int *edx, int *esi 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; @@ -943,174 +917,125 @@ void game_command_set_park_name(int *eax, int *ebx, int *ecx, int *edx, int *esi *ebx = 0; } -int map_buy_land_rights_for_tile(int x, int y, int setting, int flags) { - int y2; - int cost; - int tile_idx; +money32 map_buy_land_rights_for_tile(int x, int y, int setting, int flags) { + rct_map_element* surfaceElement = map_get_surface_element_at(x / 32, y / 32); + if (surfaceElement == NULL) + return MONEY32_UNDEFINED; - 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; + if ((surfaceElement->properties.surface.ownership & OWNERSHIP_OWNED) != 0) { // If the land is already owned + return 0; } - else if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 || (ownership & OWNERSHIP_AVAILABLE) == 0) { + + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 || (surfaceElement->properties.surface.ownership & OWNERSHIP_AVAILABLE) == 0) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 1726; // Land not for sale! - cost = 0;// MONEY32_UNDEFINED; - return cost; + return MONEY32_UNDEFINED; } - 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; + if (flags & GAME_COMMAND_FLAG_APPLY) { + surfaceElement->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 = 0; - break; + return RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, uint16); + case 1: + if (flags & GAME_COMMAND_FLAG_APPLY) { + surfaceElement->properties.surface.ownership &= ~(OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_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); + } + return 0; case 2: - if ((ownership & (OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)) != 0) { // If the land or construction rights are already owned - cost = 0; - return cost; + if ((surfaceElement->properties.surface.ownership & (OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)) != 0) { // If the land or construction rights are already owned + return 0; } - else if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 || (ownership & OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE) == 0) { + + if ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 || (surfaceElement->properties.surface.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; + return MONEY32_UNDEFINED; } - 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; + + if (flags & GAME_COMMAND_FLAG_APPLY) { + surfaceElement->properties.surface.ownership |= OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED; + uint16 baseHeight = surfaceElement->base_height * 8; + map_invalidate_tile(x, y, baseHeight, baseHeight + 16); } - break; + return RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCTION_RIGHTS_COST, uint16); 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); + if (flags & GAME_COMMAND_FLAG_APPLY) { + surfaceElement->properties.surface.ownership &= ~OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED; + uint16 baseHeight = surfaceElement->base_height * 8; + map_invalidate_tile(x, y, baseHeight, baseHeight + 16); } - cost = 0; - break; - break; + return 0; 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); + if (flags & GAME_COMMAND_FLAG_APPLY) { + surfaceElement->properties.surface.ownership |= OWNERSHIP_AVAILABLE; + uint16 baseHeight = surfaceElement->base_height * 8; + map_invalidate_tile(x, y, baseHeight, baseHeight + 16); } - cost = 0; - break; + return 0; 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); + if (flags & GAME_COMMAND_FLAG_APPLY) { + surfaceElement->properties.surface.ownership |= OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE; + uint16 baseHeight = surfaceElement->base_height * 8; + map_invalidate_tile(x, y, baseHeight, baseHeight + 16); } - cost = 0; - break; + return 0; default: - if (x <= 32) { + if (x <= 32 || y <= 32) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 3215; - cost = 0;// MONEY32_UNDEFINED; - return cost; + return MONEY32_UNDEFINED; } - 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; + + if (x >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) - 32 || y >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) - 32) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 3215; + return MONEY32_UNDEFINED; + } + + rct_map_element* mapElement = map_get_first_element_at(x / 32, y / 32); + do { + if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_ENTRANCE){ + return 0; } - 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 (!map_element_is_last_for_tile(mapElement++)); - } while ((TILE_MAP_ELEMENT_POINTER(((((y - 8) & 0xFFE0) * 256) + (x & 0xFFE0)) / 32)->flags & 0x80) == 0); + uint8 newOwnership = (flags & 0xFF00) >> 4; + if (newOwnership == (surfaceElement->properties.surface.ownership & 0xF0)) { + return 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; + if (!(flags & GAME_COMMAND_FLAG_APPLY)) { + return RCT2_GLOBAL(RCT2_ADDRESS_LAND_COST, uint16); + } - cost = 0; - return cost; + if ((newOwnership & 0xF0) != 0) { + rct2_peep_spawn *peepSpawns = gPeepSpawns; + + for (uint8 i = 0; i < 2; ++i) { + if (x == (peepSpawns[i].x & 0xFFE0)) { + if (y == (peepSpawns[i].y & 0xFFE0)) { + peepSpawns[i].x = 0xFFFF; + } } } } - break; + surfaceElement->properties.surface.ownership &= 0x0F; + surfaceElement->properties.surface.ownership |= newOwnership; + 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; + return 0; } - return cost; } int map_buy_land_rights(int x0, int y0, int x1, int y1, int setting, int flags) @@ -1127,9 +1052,9 @@ int map_buy_land_rights(int x0, int y0, int x1, int y1, int setting, int flags) 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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_COMMAND_MAP_Z, uint16) = z; // Game command modified to accept selection size totalCost = 0; @@ -1161,194 +1086,66 @@ void game_command_buy_land_rights(int *eax, int *ebx, int *ecx, int *edx, int *e (*edi & 0xFFFF), (*ebp & 0xFFFF), (*edx & 0xFF00) >> 8, - *ebx & 0xFF + *ebx & 0xFFFF ); - // 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); - }*/ +} + + +void set_forced_park_rating(int rating){ + gForcedParkRating = rating; + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, uint16) = calculate_park_rating(); + RCT2_GLOBAL(RCT2_ADDRESS_BTM_TOOLBAR_DIRTY_FLAGS, uint16) |= BTM_TB_DIRTY_FLAG_PARK_RATING; + window_invalidate_by_class(WC_PARK_INFORMATION); +} + +int get_forced_park_rating(){ + return gForcedParkRating; +} + +/** + * + * rct2: 0x00666F9E + */ +void park_remove_ghost_entrance() +{ + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_GHOST_EXISTS, uint8) & (1 << 0)) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_GHOST_EXISTS, uint8) &= ~(1 << 0); + game_do_command( + RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_GHOST_X, uint16), + 40 | GAME_COMMAND_FLAG_APPLY, + RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_GHOST_Y, uint16), + RCT2_GLOBAL(0x009E32D0, uint8), + GAME_COMMAND_REMOVE_PARK_ENTRANCE, + 0, + 0 + ); + } +} + +/** + * + * rct2: 0x00666F4E + */ +money32 park_place_ghost_entrance(int x, int y, int z, int direction) +{ + money32 result; + + park_remove_ghost_entrance(); + result = game_do_command( + x, + 104 | GAME_COMMAND_FLAG_APPLY | (direction << 8), + y, + z, + GAME_COMMAND_PLACE_PARK_ENTRANCE, + 0, + 0 + ); + if (result != MONEY32_UNDEFINED) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_GHOST_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_GHOST_Y, uint16) = y; + RCT2_GLOBAL(0x009E32D0, uint8) = z; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_GHOST_DIRECTION, uint8) = direction; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_GHOST_EXISTS, uint8) |= (1 << 0); + } + return result; } diff --git a/src/world/park.h b/src/world/park.h index 3bdab3fc5e..5f24a295e4 100644 --- a/src/world/park.h +++ b/src/world/park.h @@ -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 . *****************************************************************************/ @@ -35,16 +35,24 @@ 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_8 = (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_LOCK_REAL_NAMES_OPTION = (1 << 15), 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_SIX_FLAGS = (1 << 19) + PARK_FLAGS_SIX_FLAGS_DEPRECATED = (1 << 19) }; +extern uint8 *gParkRatingHistory; +extern uint8 *gGuestsInParkHistory; + +void set_forced_park_rating(); +int get_forced_park_rating(); + int park_is_open(); void park_init(); void park_reset_history(); @@ -58,6 +66,7 @@ void generate_new_guest(); void park_update(); void park_update_histories(); +void update_park_fences(int x, int y); uint8 calculate_guest_initial_happiness(uint8 percentage); @@ -66,12 +75,17 @@ 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); +int map_buy_land_rights(int x0, int y0, int x1, int y1, int setting, int flags); + 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); +void map_invalidate_tile(int x, int y, int z0, int z1); + +void park_remove_ghost_entrance(); +money32 park_place_ghost_entrance(int x, int y, int z, int direction); #endif diff --git a/src/world/particle.c b/src/world/particle.c new file mode 100644 index 0000000000..ecec4ff98d --- /dev/null +++ b/src/world/particle.c @@ -0,0 +1,124 @@ +#include "../audio/audio.h" +#include "../util/util.h" +#include "sprite.h" + +/** + * + * rct2: 0x006735A1 + */ +void crashed_vehicle_particle_create(rct_vehicle_colour colours, int x, int y, int z) +{ + rct_crashed_vehicle_particle *sprite = (rct_crashed_vehicle_particle*)create_sprite(2); + if (sprite != NULL) { + sprite->colour[0] = colours.body_colour; + sprite->colour[1] = colours.trim_colour; + sprite->sprite_width = 8; + sprite->sprite_height_negative = 8; + sprite->sprite_height_positive = 8; + sprite->sprite_identifier = SPRITE_IDENTIFIER_MISC; + sprite_move(x, y, z + 4, (rct_sprite*)sprite); + sprite->misc_identifier = SPRITE_MISC_CRASHED_VEHICLE_PARTICLE; + + sprite->var_26 = (util_rand() & 0xFF) * 12; + sprite->var_24 = (util_rand() & 0x7F) + 140; + sprite->var_2E = ((util_rand() & 0xFF) * 5) >> 8; + sprite->acceleration_x = (util_rand() & 0xFFFF) * 4; + sprite->acceleration_y = (util_rand() & 0xFFFF) * 4; + sprite->acceleration_z = (util_rand() & 0xFFFF) * 4 + 0x10000; + sprite->velocity_x = 0; + sprite->velocity_y = 0; + sprite->velocity_z = 0; + } +} + +/** + * + * rct: 0x00673298 + */ +void crashed_vehicle_particle_update(rct_crashed_vehicle_particle *particle) +{ + invalidate_sprite_0((rct_sprite*)particle); + particle->var_24--; + if (particle->var_24 == 0) { + sprite_remove((rct_sprite*)particle); + return; + } + + // Apply gravity + particle->acceleration_z -= 5041; + + // Apply air resistance + particle->acceleration_x -= (particle->acceleration_x / 256); + particle->acceleration_y -= (particle->acceleration_y / 256); + particle->acceleration_z -= (particle->acceleration_z / 256); + + // Update velocity and position + sint32 vx = particle->velocity_x + particle->acceleration_x; + sint32 vy = particle->velocity_y + particle->acceleration_y; + sint32 vz = particle->velocity_z + particle->acceleration_z; + + sint16 x = particle->x + (vx >> 16); + sint16 y = particle->y + (vy >> 16); + sint16 z = particle->z + (vz >> 16); + + particle->velocity_x = vx & 0xFFFF; + particle->velocity_y = vy & 0xFFFF; + particle->velocity_z = vz & 0xFFFF; + + // Check collision with land / water + uint32 waterLand = map_element_height(x, y); + sint16 landZ = (waterLand & 0xFFFF); + sint16 waterZ = (waterLand >> 16); + + if (waterZ != 0 && particle->z >= waterZ && z <= waterZ) { + // Splash + audio_play_sound_at_location(SOUND_WATER_2, particle->x, particle->y, waterZ); + crash_splash_create(particle->x, particle->y, waterZ); + sprite_remove((rct_sprite*)particle); + return; + } + + if (particle->z >= landZ && z <= landZ) { + // Bounce + particle->acceleration_z *= -1; + z = landZ; + } + sprite_move(x, y, z, (rct_sprite*)particle); + invalidate_sprite_0((rct_sprite*)particle); + + particle->var_26 += 85; + if (particle->var_26 >= 3072) { + particle->var_26 = 0; + } +} + +/** + * + * rct2: 0x00673699 + */ +void crash_splash_create(int x, int y, int z) +{ + rct_unk_sprite *sprite = (rct_unk_sprite*)create_sprite(2); + if (sprite != NULL) { + sprite->sprite_width = 33; + sprite->sprite_height_negative = 51; + sprite->sprite_height_positive = 16; + sprite->sprite_identifier = SPRITE_IDENTIFIER_MISC; + sprite_move(x, y, z + 3, (rct_sprite*)sprite); + sprite->misc_identifier = SPRITE_MISC_CRASH_SPLASH; + sprite->var_26 = 0; + } +} + +/** + * + * rct: 0x0067339D + */ +void crash_splash_update(rct_crash_splash *splash) +{ + invalidate_sprite_2((rct_sprite*)splash); + splash->var_26 += 85; + if (splash->var_26 >= 7168) { + sprite_remove((rct_sprite*)splash); + } +} diff --git a/src/world/scenery.c b/src/world/scenery.c index 3a05927927..9974593d96 100644 --- a/src/world/scenery.c +++ b/src/world/scenery.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 . *****************************************************************************/ @@ -82,7 +82,7 @@ void scenery_update_age(int x, int y, rct_map_element *mapElement) 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); + map_invalidate_tile_zoom1(x, y, mapElementAbove->base_height * 8, mapElementAbove->clearance_height * 8); scenery_increase_age(x, y, mapElement); return; case MAP_ELEMENT_TYPE_SCENERY: @@ -94,10 +94,10 @@ void scenery_update_age(int x, int y, rct_map_element *mapElement) break; } } - + // Reset age / water plant mapElement->properties.scenery.age = 0; - map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + map_invalidate_tile_zoom1(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); } void scenery_increase_age(int x, int y, rct_map_element *mapElement) @@ -107,35 +107,35 @@ void scenery_increase_age(int x, int y, rct_map_element *mapElement) if (mapElement->properties.scenery.age < 255) { mapElement->properties.scenery.age++; - map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); + map_invalidate_tile_zoom1(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8); } } - -/* 0x006E2712 */ +/* + * + * rct2: 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); + x = RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_X, sint16); + y = RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Y, sint16); + z = RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_Z, uint8); + if (RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) & (1 << 0)){ + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) &= ~(1 << 0); game_do_command( - x, - 105 | (RCT2_GLOBAL(0x00F64F0C, uint8) << 8), - y, - z | (RCT2_GLOBAL(0x00F64EDA, uint8) << 8), + x, + 105 | (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_MAP_ELEMENT_TYPE, uint8) << 8), + y, + z | (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_SELECTED_OBJECT, uint8) << 8), GAME_COMMAND_REMOVE_SCENERY, - 0, + 0, 0); } - if (RCT2_GLOBAL(0x00F64F0D, uint8) & (1 << 1)){ - RCT2_GLOBAL(0x00F64F0D, uint8) &= ~(1 << 1); - + if (RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) & (1 << 1)){ + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) &= ~(1 << 1); rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); do{ @@ -147,35 +147,33 @@ void scenery_remove_ghost_tool_placement(){ game_do_command( x, - 233 | (RCT2_GLOBAL(0x00F64F0F, uint8) << 8), + 233 | (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TARGET_PATH_INCLINE, uint8) << 8), y, - z | (RCT2_GLOBAL(0x00F64F10, uint8) << 8), + z | (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_TARGET_PATH_TYPE, uint8) << 8), GAME_COMMAND_PLACE_PATH, - RCT2_GLOBAL(0x00F64EAC, uint32) & 0xFFFF0000, + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_PATH_OBJECT_TYPE, 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); - + if (RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) & (1 << 2)){ + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) &= ~(1 << 2); game_do_command( x, - 105 | (RCT2_GLOBAL(0x00F64F0C, uint8) << 8), + 105 | (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_MAP_ELEMENT_TYPE, uint8) << 8), y, - RCT2_GLOBAL(0x00F64F11, uint8) |(z << 8), + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_WALL_ROTATION, uint8) |(z << 8), GAME_COMMAND_REMOVE_FENCE, 0, 0); } - if (RCT2_GLOBAL(0x00F64F0D, uint8) & (1 << 3)){ - RCT2_GLOBAL(0x00F64F0D, uint8) &= ~(1 << 3); - + if (RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) & (1 << 3)){ + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) &= ~(1 << 3); game_do_command( x, - 105 | (RCT2_GLOBAL(0x00F64EC0, uint8) << 8), + 105 | (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_ROTATION, uint8) << 8), y, z, GAME_COMMAND_REMOVE_LARGE_SCENERY, @@ -183,14 +181,13 @@ void scenery_remove_ghost_tool_placement(){ 0); } - if (RCT2_GLOBAL(0x00F64F0D, uint8) & (1 << 4)){ - RCT2_GLOBAL(0x00F64F0D, uint8) &= ~(1 << 4); - + if (RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) & (1 << 4)){ + RCT2_GLOBAL(RCT2_ADDRESS_GHOST_SCENERY_TYPE, uint8) &= ~(1 << 4); game_do_command( x, 105, y, - z | (RCT2_GLOBAL(0x00F64EC0, uint8) << 8), + z | (RCT2_GLOBAL(RCT2_ADDRESS_SCENERY_ROTATION, uint8) << 8), GAME_COMMAND_REMOVE_BANNER, 0, 0); diff --git a/src/world/scenery.h b/src/world/scenery.h index c35704f13d..7f68bae88b 100644 --- a/src/world/scenery.h +++ b/src/world/scenery.h @@ -54,7 +54,7 @@ typedef enum { 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_ALLOW_WALLS = (1 << 18), // 0x40000 SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR = (1 << 19), // 0x80000 SMALL_SCENERY_FLAG20 = (1 << 20), // 0x100000 SMALL_SCENERY_FLAG21 = (1 << 21), // 0x200000 @@ -68,7 +68,7 @@ typedef struct { sint16 x_offset; sint16 y_offset; sint16 z_offset; - uint8 var_6; + uint8 z_clearance; uint16 var_7; } rct_large_scenery_tile; @@ -92,7 +92,7 @@ typedef struct { uint8 flags2; // 0x09 sint16 price; // 0x0A uint8 scenery_tab_id; // 0x0C - uint8 var_0D; + uint8 var_0D; } rct_wall_scenery_entry; typedef enum { @@ -115,7 +115,7 @@ typedef struct { } rct_path_bit_scenery_entry; typedef struct { - uint8 var_06; + uint8 scrolling_mode; // 0x06 uint8 flags; // 0x07 sint16 price; // 0x08 uint8 scenery_tab_id; // 0x0A @@ -149,6 +149,14 @@ enum { PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW = 1 << 5 }; +enum { + SCENERY_TYPE_SMALL, + SCENERY_TYPE_PATH_ITEM, + SCENERY_TYPE_WALL, + SCENERY_TYPE_LARGE, + SCENERY_TYPE_BANNER +}; + #define SCENERY_ENTRIES_BY_TAB 128 #define g_smallSceneryEntries ((rct_scenery_entry**)object_entry_groups[OBJECT_TYPE_SMALL_SCENERY].chunks) @@ -156,7 +164,7 @@ enum { #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 +// 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) diff --git a/src/world/sprite.c b/src/world/sprite.c index ede41f10d8..3be296848e 100644 --- a/src/world/sprite.c +++ b/src/world/sprite.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 . *****************************************************************************/ @@ -27,552 +27,57 @@ #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, uint8 bl) +static uint16 sprite_get_first_in_quadrant(int x, int y) { - 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; - } + int offset = ((x & 0x1FE0) << 3) | (y >> 5); + return RCT2_ADDRESS(0x00F1EF60, uint16)[offset]; } -void balloon_pop(rct_balloon *balloon) +static void invalidate_sprite_max_zoom(rct_sprite *sprite, int maxZoom) { - balloon->popped = 1; - balloon->var_26 = 0; - sound_play_panned(SOUND_BALLOON_POP, 0x8001, balloon->x, balloon->y, balloon->z); -} + if (sprite->unknown.sprite_left == SPRITE_LOCATION_NULL) return; -/** - * - * 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; - - for (rct_viewport** viewport_p = RCT2_ADDRESS(RCT2_ADDRESS_ACTIVE_VIEWPORT_PTR_ARRAY, rct_viewport*); *viewport_p != NULL; viewport_p++){ + for (rct_viewport** viewport_p = RCT2_ADDRESS(RCT2_ADDRESS_ACTIVE_VIEWPORT_PTR_ARRAY, rct_viewport*); *viewport_p != NULL; viewport_p++) { rct_viewport* viewport = *viewport_p; - int left, right, top, bottom; - left = sprite->unknown.sprite_left; - right = sprite->unknown.sprite_right; - top = sprite->unknown.sprite_top; - bottom = sprite->unknown.sprite_bottom; - - if (viewport->zoom >= 3)continue; - if (right <= viewport->view_x)continue; - if (bottom <= viewport->view_y) continue; - - int viewport_right = viewport->view_x + viewport->view_width; - int viewport_bottom = viewport->view_y + viewport->view_height; - - if (left >= viewport_right)continue; - if (top >= viewport_bottom)continue; - - left = max(left, viewport->view_x); - right = min(right, viewport_right); - top = max(top, viewport->view_y); - bottom = min(bottom, viewport_bottom); - - left -= viewport->view_x; - top -= viewport->view_y; - right -= viewport->view_x; - bottom -= viewport->view_y; - - int zoom = 1 << viewport->zoom; - left /= zoom; - top /= zoom; - right /= zoom; - bottom /= zoom; - - gfx_set_dirty_blocks(left + viewport->x, top + viewport->y, right + viewport->x, bottom + viewport->y); + if (viewport->zoom <= maxZoom) { + viewport_invalidate( + viewport, + sprite->unknown.sprite_left, + sprite->unknown.sprite_top, + sprite->unknown.sprite_right, + sprite->unknown.sprite_bottom + ); + } } } /** - * Similar to invalidate sprite... - * rct2: 0x006EC60B + * Invalidate the sprite if at closest zoom. + * rct2: 0x006EC60B */ -void sub_6EC60B(rct_sprite* sprite) +void invalidate_sprite_0(rct_sprite* sprite) { - RCT2_CALLPROC_X(0x006EC60B, 0, 0, 0, 0, (int)sprite, 0, 0); + invalidate_sprite_max_zoom(sprite, 0); +} + +/** + * Invalidate sprite if at closest zoom or next zoom up from closest. + * rct2: 0x006EC53F + */ +void invalidate_sprite_1(rct_sprite *sprite) +{ + invalidate_sprite_max_zoom(sprite, 1); +} + +/** +* Invalidate sprite if not at furthest zoom. +* rct2: 0x006EC473 +*/ +void invalidate_sprite_2(rct_sprite *sprite) +{ + invalidate_sprite_max_zoom(sprite, 2); } /* @@ -581,7 +86,7 @@ void sub_6EC60B(rct_sprite* sprite) */ void reset_sprite_list(){ RCT2_GLOBAL(0x1388698, uint16) = 0; - memset(g_sprite_list, 0, sizeof(rct_sprite)* 0x2710); + memset(g_sprite_list, 0, sizeof(rct_sprite) * MAX_SPRITES); for (int i = 0; i < 6; ++i){ RCT2_ADDRESS(RCT2_ADDRESS_SPRITES_NEXT_INDEX, uint16)[i] = -1; @@ -591,8 +96,8 @@ void reset_sprite_list(){ rct_sprite* previous_spr = (rct_sprite*)SPRITE_INDEX_NULL; rct_sprite* spr = g_sprite_list; - for (int i = 0; i < 0x2710; ++i){ - spr->unknown.sprite_identifier = 0xFF; + for (int i = 0; i < MAX_SPRITES; ++i){ + spr->unknown.sprite_identifier = SPRITE_IDENTIFIER_NULL; spr->unknown.sprite_index = i; spr->unknown.next = SPRITE_INDEX_NULL; spr->unknown.linked_list_type_offset = 0; @@ -609,7 +114,7 @@ void reset_sprite_list(){ spr++; } - RCT2_GLOBAL(0x13573C8, uint16) = 0x2710; + RCT2_GLOBAL(0x13573C8, uint16) = MAX_SPRITES; reset_0x69EBE4(); } @@ -625,12 +130,11 @@ void reset_0x69EBE4(){ rct_sprite* spr = g_sprite_list; for (; spr < (rct_sprite*)RCT2_ADDRESS_SPRITES_NEXT_INDEX; spr++){ - if (spr->unknown.sprite_identifier != 0xFF){ + if (spr->unknown.sprite_identifier != SPRITE_IDENTIFIER_NULL){ uint32 edi = spr->unknown.x; - if ((uint16)(spr->unknown.x) == SPRITE_LOCATION_NULL){ + if (spr->unknown.x == SPRITE_LOCATION_NULL){ edi = 0x10000; - } - else{ + } else { int ecx = spr->unknown.y; ecx >>= 5; edi &= 0x1FE0; @@ -652,7 +156,7 @@ 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; @@ -715,7 +219,7 @@ rct_sprite *create_sprite(uint8 bl) /* * rct2: 0x0069ED0B * This function moves a sprite to the specified sprite linked list. -* There are 5/6 of those, and cl specifies a pointer offset +* There are 5/6 of those, and cl specifies a pointer offset * of the desired linked list in a uint16 array. Known valid values are * 2, 4, 6, 8 or 10 (SPRITE_LINKEDLIST_OFFSET_...) */ @@ -727,7 +231,7 @@ void move_sprite_to_list(rct_sprite *sprite, uint8 cl) if (unkSprite->linked_list_type_offset == cl) return; - // If the sprite is currently the head of the list, the + // If the sprite is currently the head of the list, the // sprite following this one becomes the new head of the list. if (unkSprite->previous == SPRITE_INDEX_NULL) { @@ -764,6 +268,87 @@ void move_sprite_to_list(rct_sprite *sprite, uint8 cl) ++(RCT2_GLOBAL(0x13573C8 + cl, uint16)); } +/** + * + * rct: 0x00673200 + */ +static void sprite_misc_0_update(rct_sprite *sprite) +{ + invalidate_sprite_2(sprite); + + int original_var24 = sprite->unknown.var_24; + sprite->unknown.var_24 += 0x5555; + if (sprite->unknown.var_24 < 0x5555) { + sprite_move(sprite->unknown.x, sprite->unknown.y, sprite->unknown.z + 1, sprite); + } + sprite->unknown.var_26 += 64; + if (sprite->unknown.var_26 >= (56 * 64)) { + sprite_remove(sprite); + } +} + +/** + * + * rct2: 0x0067363D + */ +void sprite_misc_3_create(int x, int y, int z) +{ + rct_unk_sprite *sprite = (rct_unk_sprite*)create_sprite(2); + if (sprite != NULL) { + sprite->sprite_width = 44; + sprite->sprite_height_negative = 32; + sprite->sprite_height_positive = 34; + sprite->sprite_identifier = SPRITE_IDENTIFIER_MISC; + sprite_move(x, y, z + 4, (rct_sprite*)sprite); + sprite->misc_identifier = SPRITE_MISC_3; + sprite->var_26 = 0; + } +} + +/** + * + * rct: 0x00673385 + */ +static void sprite_misc_3_update(rct_sprite *sprite) +{ + invalidate_sprite_2(sprite); + sprite->unknown.var_26 += 128; + if (sprite->unknown.var_26 >= (36 * 128)) { + sprite_remove(sprite); + } +} + +/** + * + * rct2: 0x0067366B + */ +void sprite_misc_5_create(int x, int y, int z) +{ + rct_unk_sprite *sprite = (rct_unk_sprite*)create_sprite(2); + if (sprite != NULL) { + sprite->sprite_width = 25; + sprite->sprite_height_negative = 85; + sprite->sprite_height_positive = 8; + sprite->sprite_identifier = SPRITE_IDENTIFIER_MISC; + sprite_move(x, y, z + 4, (rct_sprite*)sprite); + sprite->misc_identifier = SPRITE_MISC_5; + sprite->var_26 = 0; + } +} + +/** + * + * rct: 0x006733B4 + */ +static void sprite_misc_5_update(rct_sprite *sprite) +{ + invalidate_sprite_2(sprite); + sprite->unknown.var_26 += 64; + if (sprite->unknown.var_26 >= (124 * 64)) { + sprite_remove(sprite); + } +} + /** * * rct: 0x006731CD @@ -772,22 +357,22 @@ 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); + sprite_misc_0_update(sprite); 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); + case SPRITE_MISC_CRASHED_VEHICLE_PARTICLE: + crashed_vehicle_particle_update((rct_crashed_vehicle_particle*)sprite); break; case SPRITE_MISC_3: - RCT2_CALLPROC_X(0x00673385, 0, 0, 0, 0, (int)sprite, 0, 0); + sprite_misc_3_update(sprite); break; - case SPRITE_MISC_4: - RCT2_CALLPROC_X(0x0067339D, 0, 0, 0, 0, (int)sprite, 0, 0); + case SPRITE_MISC_CRASH_SPLASH: + crash_splash_update((rct_crash_splash*)sprite); break; case SPRITE_MISC_5: - RCT2_CALLPROC_X(0x006733B4, 0, 0, 0, 0, (int)sprite, 0, 0); + sprite_misc_5_update(sprite); break; case SPRITE_MISC_JUMPING_FOUNTAIN_WATER: case SPRITE_MISC_JUMPING_FOUNTAIN_SNOW: @@ -828,17 +413,17 @@ void sprite_misc_update_all() */ void sprite_move(sint16 x, sint16 y, sint16 z, rct_sprite* sprite){ if (x < 0 || y < 0 || x > 0x1FFF || y > 0x1FFF) - x = 0x8000; + x = SPRITE_LOCATION_NULL; int new_position = x; - if (x == (sint16)0x8000)new_position = 0x10000; + if (x == SPRITE_LOCATION_NULL)new_position = 0x10000; else{ new_position &= 0x1FE0; new_position = (y >> 5) | (new_position << 3); } int current_position = sprite->unknown.x; - if (sprite->unknown.x == (sint16)0x8000)current_position = 0x10000; + if (sprite->unknown.x == SPRITE_LOCATION_NULL)current_position = 0x10000; else{ current_position &= 0x1FE0; current_position = (sprite->unknown.y >> 5) | (current_position << 3); @@ -858,15 +443,15 @@ void sprite_move(sint16 x, sint16 y, sint16 z, rct_sprite* sprite){ sprite->unknown.next_in_quadrant = temp_sprite_idx; } - if (x == (sint16)0x8000){ - sprite->unknown.sprite_left = 0x8000; + if (x == SPRITE_LOCATION_NULL){ + sprite->unknown.sprite_left = SPRITE_LOCATION_NULL; sprite->unknown.x = x; sprite->unknown.y = y; sprite->unknown.z = z; return; } sint16 new_x = x, new_y = y, start_x = x; - switch (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)){ + switch (get_current_rotation()){ case 0: new_x = new_y - new_x; new_y = (new_y + start_x) / 2 - z; @@ -900,5 +485,119 @@ void sprite_move(sint16 x, sint16 y, sint16 z, rct_sprite* sprite){ */ void sprite_remove(rct_sprite *sprite) { - RCT2_CALLPROC_X(0x0069EDB6, 0, 0, 0, 0, (int)sprite, 0, 0); -} \ No newline at end of file + move_sprite_to_list(sprite, SPRITE_LINKEDLIST_OFFSET_NULL); + user_string_free(sprite->unknown.name_string_idx); + sprite->unknown.sprite_identifier = SPRITE_IDENTIFIER_NULL; + + uint32 quadrantIndex = sprite->unknown.x; + if (sprite->unknown.x == SPRITE_LOCATION_NULL) { + quadrantIndex = 0x10000; + } else { + quadrantIndex = (floor2(sprite->unknown.x, 32) << 3) | (sprite->unknown.y >> 5); + } + + uint16 *spriteIndex = &RCT2_ADDRESS(0x00F1EF60, uint16)[quadrantIndex]; + rct_sprite *quadrantSprite; + while ((quadrantSprite = &g_sprite_list[*spriteIndex]) != sprite) { + spriteIndex = &quadrantSprite->unknown.next_in_quadrant; + } + *spriteIndex = sprite->unknown.next_in_quadrant; +} + +static bool litter_can_be_at(int x, int y, int z) +{ + rct_map_element *mapElement; + + if (!map_is_location_owned(x & 0xFFE0, y & 0xFFE0, z)) + return false; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH) + continue; + + int pathZ = mapElement->base_height * 8; + if (pathZ < z || pathZ >= z + 32) + continue; + + if (map_element_is_underground(mapElement)) + return false; + + return true; + } while (!map_element_is_last_for_tile(mapElement++)); + return false; +} + +/** + * + * rct2: 0x0067375D + */ +void litter_create(int x, int y, int z, int direction, int type) +{ + rct_litter *litter, *newestLitter; + uint16 spriteIndex, nextSpriteIndex; + uint32 newestLitterCreationTick; + + x += TileDirectionDelta[direction >> 3].x / 8; + y += TileDirectionDelta[direction >> 3].y / 8; + + if (!litter_can_be_at(x, y, z)) + return; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_COUNT_LITTER, uint16) >= 500) { + newestLitter = NULL; + newestLitterCreationTick = 0; + 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; + if (newestLitterCreationTick <= litter->creationTick) { + newestLitterCreationTick = litter->creationTick; + newestLitter = litter; + } + } + + if (newestLitter != NULL) { + invalidate_sprite_0((rct_sprite*)newestLitter); + sprite_remove((rct_sprite*)newestLitter); + } + } + + litter = (rct_litter*)create_sprite(1); + if (litter == NULL) + return; + + move_sprite_to_list((rct_sprite*)litter, SPRITE_LINKEDLIST_OFFSET_LITTER); + litter->sprite_direction = direction; + litter->sprite_width = 6; + litter->sprite_height_negative = 6; + litter->sprite_height_positive = 3; + litter->sprite_identifier = SPRITE_IDENTIFIER_LITTER; + litter->type = type; + sprite_move(x, y, z, (rct_sprite*)litter); + invalidate_sprite_0((rct_sprite*)litter); + litter->creationTick = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32); +} + +/** + * + * rct2: 0x006738E1 + */ +void litter_remove_at(int x, int y, int z) +{ + uint16 spriteIndex = sprite_get_first_in_quadrant(x, y); + while (spriteIndex != SPRITE_INDEX_NULL) { + rct_sprite *sprite = &g_sprite_list[spriteIndex]; + uint16 nextSpriteIndex = sprite->unknown.next_in_quadrant; + if (sprite->unknown.linked_list_type_offset == SPRITE_LINKEDLIST_OFFSET_LITTER) { + rct_litter *litter = &sprite->litter; + + if (abs(litter->z - z) <= 16) { + if (abs(litter->x - x) <= 8 && abs(litter->y - y) <= 8) { + invalidate_sprite_0(sprite); + sprite_remove(sprite); + } + } + } + spriteIndex = nextSpriteIndex; + } +} diff --git a/src/world/sprite.h b/src/world/sprite.h index ed2cfe109a..89fdb512d2 100644 --- a/src/world/sprite.h +++ b/src/world/sprite.h @@ -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 . *****************************************************************************/ @@ -26,7 +26,7 @@ #include "../ride/vehicle.h" #define SPRITE_INDEX_NULL 0xFFFF -#define SPRITE_LOCATION_NULL 0x8000 +#define SPRITE_LOCATION_NULL ((sint16)0x8000) #define MAX_SPRITES 10000 enum SPRITE_IDENTIFIER{ @@ -71,7 +71,9 @@ typedef struct { uint8 sprite_direction; //direction of sprite? 0x1e uint8 pad_1F[3]; // 0x1f uint16 name_string_idx; // 0x22 - uint8 pad_24[7]; + uint16 var_24; + uint16 var_26; + uint8 var_28[3]; uint8 var_2B; uint8 pad_2C[0x45]; uint8 var_71; @@ -79,19 +81,23 @@ typedef struct { typedef struct { uint8 sprite_identifier; // 0x00 - uint8 var_01; // 0x01 + uint8 type; // 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 pad_09; + uint8 sprite_height_negative; // 0x09 uint16 sprite_index; // 0x0A uint16 pad_0C; sint16 x; // 0x0E sint16 y; // 0x10 sint16 z; // 0x12 - uint8 pad_14[0x10]; - uint32 var_24; + uint8 sprite_width; // 0x14 + uint8 sprite_height_positive; // 0x15 + uint8 pad_16[8]; + uint8 sprite_direction; // 0x1E + uint8 pad_1F[5]; + uint32 creationTick; // 0x24 } rct_litter; typedef struct { @@ -120,6 +126,7 @@ typedef struct { }; uint8 pad_28[4]; uint8 colour; // 0x2C + uint8 var_2D; } rct_balloon; typedef struct { @@ -204,6 +211,77 @@ typedef struct { uint16 wiggle; // 0x46 } rct_money_effect; +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_... + // 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 + // 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; //direction of sprite? 0x1e + uint8 pad_1F[3]; // 0x1f + uint16 name_string_idx; // 0x22 + uint16 var_24; + uint16 var_26; + uint8 var_28[3]; + uint8 var_2B; + uint8 colour[2]; + uint16 var_2E; + sint16 velocity_x; // 0x30 + sint16 velocity_y; // 0x32 + sint16 velocity_z; // 0x34 + uint16 pad_36; + sint32 acceleration_x; // 0x38 + sint32 acceleration_y; // 0x3C + sint32 acceleration_z; // 0x40 + uint8 pad_44[0x2D]; + uint8 var_71; +} rct_crashed_vehicle_particle; + +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_... + // 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 + // 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; //direction of sprite? 0x1e + uint8 pad_1F[3]; // 0x1f + uint16 name_string_idx; // 0x22 + uint16 var_24; + uint16 var_26; +} rct_crash_splash; + /** * Sprite structure. * size: 0x0100 @@ -218,14 +296,16 @@ typedef union { rct_duck duck; rct_jumping_fountain jumping_fountain; rct_money_effect money_effect; + rct_crashed_vehicle_particle crashed_vehicle_particle; + rct_crash_splash crash_splash; } rct_sprite; enum { SPRITE_MISC_0, SPRITE_MISC_MONEY_EFFECT, - SPRITE_MISC_2, // (related to vehicle crash, probably crash particles) + SPRITE_MISC_CRASHED_VEHICLE_PARTICLE, SPRITE_MISC_3, // (related to vehicle crash, probably crash particles) - SPRITE_MISC_4, // (related to vehicle crash, probably crash particles) + SPRITE_MISC_CRASH_SPLASH, SPRITE_MISC_5, // (related to vehicle crash, probably crash particles) SPRITE_MISC_JUMPING_FOUNTAIN_WATER, SPRITE_MISC_BALLOON, @@ -236,12 +316,6 @@ enum { // rct2: 0x010E63BC extern rct_sprite* g_sprite_list; -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(); @@ -249,8 +323,42 @@ void sprite_clear_all_unused(); void move_sprite_to_list(rct_sprite *sprite, uint8 cl); 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 invalidate_sprite_0(rct_sprite* sprite); +void invalidate_sprite_1(rct_sprite *sprite); +void invalidate_sprite_2(rct_sprite *sprite); void sprite_remove(rct_sprite *sprite); +void litter_create(int x, int y, int z, int direction, int type); +void litter_remove_at(int x, int y, int z); +void sprite_misc_3_create(int x, int y, int z); +void sprite_misc_5_create(int x, int y, int z); + +/////////////////////////////////////////////////////////////// +// Balloon +/////////////////////////////////////////////////////////////// +void create_balloon(int x, int y, int z, int colour, uint8 bl); +void balloon_update(rct_balloon *balloon); +void balloon_press(rct_balloon *balloon); + +/////////////////////////////////////////////////////////////// +// Duck +/////////////////////////////////////////////////////////////// +void create_duck(int targetX, int targetY); +void duck_update(rct_duck *duck); +void duck_press(rct_duck *duck); +void duck_remove_all(); + +/////////////////////////////////////////////////////////////// +// Money effect +/////////////////////////////////////////////////////////////// +void money_effect_create(money32 value); +void money_effect_update(rct_money_effect *moneyEffect); + +/////////////////////////////////////////////////////////////// +// Crash particles +/////////////////////////////////////////////////////////////// +void crashed_vehicle_particle_create(rct_vehicle_colour colours, int x, int y, int z); +void crashed_vehicle_particle_update(rct_crashed_vehicle_particle *particle); +void crash_splash_create(int x, int y, int z); +void crash_splash_update(rct_crash_splash *splash); #endif diff --git a/test/tests.c b/test/tests.c index 487306343d..6963f14517 100644 --- a/test/tests.c +++ b/test/tests.c @@ -41,7 +41,7 @@ int cmdline_for_test(const char **argv, int argc) CuSuite* new_suite(void) { CuSuite* suite = CuSuiteNew(); - + // Test Finance SUITE_ADD_TEST(suite, test_finance_setup); SUITE_ADD_TEST(suite, test_finance_loan_increase);