diff --git a/.travis.yml b/.travis.yml index ada6a796a8..7fa2eb782b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,16 +16,20 @@ 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_C_COMPILER=gcc-4.8 -DCMAKE_CXX_COMPILER=g++-4.8" + - OPENRCT2_CMAKE_OPTS="-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++" - 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 + # Following entries used to be included in testing, but they only proved useful while changing things in CMake setup. + # They are meant to be used when there are changes to CMakeLists.txt + # - 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="-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 sudo: required dist: trusty diff --git a/CMakeLists.txt b/CMakeLists.txt index 7bd8c6c612..9f1d51d61e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,8 +125,8 @@ if (APPLE) endif (APPLE) # force 32bit build for now and set necessary flags to compile code as is -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -std=gnu99 -fno-omit-frame-pointer -fno-pie") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32 -std=gnu++11 -fno-omit-frame-pointer -fno-pie") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -std=gnu99 -fno-omit-frame-pointer -fno-pie -fstrict-aliasing -Werror=strict-aliasing") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32 -std=gnu++11 -fno-omit-frame-pointer -fno-pie -fstrict-aliasing -Werror=strict-aliasing") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}") diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 1e0b1c12fa..499f451a07 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ D41B74731C2125E50080A7B9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D41B74721C2125E50080A7B9 /* Assets.xcassets */; }; D435325F1C3472E500BA219B /* libpng.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D435325E1C3472E500BA219B /* libpng.dylib */; }; D43532601C34730200BA219B /* libpng.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D435325E1C3472E500BA219B /* libpng.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + D46105CE1C38828D00DB1EE3 /* scenario_sources.c in Sources */ = {isa = PBXBuildFile; fileRef = D46105CD1C38828D00DB1EE3 /* scenario_sources.c */; }; D4ABAB061C2F812B0080CAD9 /* news_options.c in Sources */ = {isa = PBXBuildFile; fileRef = D4ABAB051C2F812B0080CAD9 /* news_options.c */; }; D4D4DF141C34697B0048BE43 /* image_io.c in Sources */ = {isa = PBXBuildFile; fileRef = D4D4DF121C34697B0048BE43 /* image_io.c */; }; D4EC47DF1C26342F0024B507 /* addresses.c in Sources */ = {isa = PBXBuildFile; fileRef = D4EC46D61C26342F0024B507 /* addresses.c */; }; @@ -90,7 +91,6 @@ D4EC48281C26342F0024B507 /* scenario_list.c in Sources */ = {isa = PBXBuildFile; fileRef = D4EC476D1C26342F0024B507 /* scenario_list.c */; }; D4EC48291C26342F0024B507 /* scenario.c in Sources */ = {isa = PBXBuildFile; fileRef = D4EC476E1C26342F0024B507 /* scenario.c */; }; D4EC482A1C26342F0024B507 /* title.c in Sources */ = {isa = PBXBuildFile; fileRef = D4EC47711C26342F0024B507 /* title.c */; }; - D4EC482B1C26342F0024B507 /* tutorial.c in Sources */ = {isa = PBXBuildFile; fileRef = D4EC47731C26342F0024B507 /* tutorial.c */; }; D4EC482C1C26342F0024B507 /* sawyercoding.c in Sources */ = {isa = PBXBuildFile; fileRef = D4EC47761C26342F0024B507 /* sawyercoding.c */; }; D4EC482D1C26342F0024B507 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = D4EC47781C26342F0024B507 /* util.c */; }; D4EC482E1C26342F0024B507 /* about.c in Sources */ = {isa = PBXBuildFile; fileRef = D4EC477B1C26342F0024B507 /* about.c */; }; @@ -219,6 +219,7 @@ D41B741C1C210A7A0080A7B9 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; }; D41B74721C2125E50080A7B9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = distribution/osx/Assets.xcassets; sourceTree = SOURCE_ROOT; }; D435325E1C3472E500BA219B /* libpng.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libpng.dylib; sourceTree = ""; }; + D46105CD1C38828D00DB1EE3 /* scenario_sources.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = scenario_sources.c; path = src/scenario_sources.c; sourceTree = ""; }; D4895D321C23EFDD000CD788 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = distribution/osx/Info.plist; sourceTree = SOURCE_ROOT; }; D497D0781C20FD52002BF46A /* OpenRCT2.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OpenRCT2.app; sourceTree = BUILT_PRODUCTS_DIR; }; D4ABAB051C2F812B0080CAD9 /* news_options.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = news_options.c; sourceTree = ""; }; @@ -370,8 +371,6 @@ D4EC47701C26342F0024B507 /* sprites.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sprites.h; path = src/sprites.h; sourceTree = ""; }; D4EC47711C26342F0024B507 /* title.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = title.c; path = src/title.c; sourceTree = ""; }; D4EC47721C26342F0024B507 /* title.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = title.h; path = src/title.h; sourceTree = ""; }; - D4EC47731C26342F0024B507 /* tutorial.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tutorial.c; path = src/tutorial.c; sourceTree = ""; }; - D4EC47741C26342F0024B507 /* tutorial.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tutorial.h; path = src/tutorial.h; sourceTree = ""; }; D4EC47761C26342F0024B507 /* sawyercoding.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sawyercoding.c; sourceTree = ""; }; D4EC47771C26342F0024B507 /* sawyercoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sawyercoding.h; sourceTree = ""; }; D4EC47781C26342F0024B507 /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = ""; }; @@ -626,13 +625,12 @@ D4EC47591C26342F0024B507 /* rct2.c */, D4EC475A1C26342F0024B507 /* rct2.h */, D4EC476D1C26342F0024B507 /* scenario_list.c */, + D46105CD1C38828D00DB1EE3 /* scenario_sources.c */, D4EC476E1C26342F0024B507 /* scenario.c */, D4EC476F1C26342F0024B507 /* scenario.h */, D4EC47701C26342F0024B507 /* sprites.h */, D4EC47711C26342F0024B507 /* title.c */, D4EC47721C26342F0024B507 /* title.h */, - D4EC47731C26342F0024B507 /* tutorial.c */, - D4EC47741C26342F0024B507 /* tutorial.h */, D4163F671C2A044D00B83136 /* version.h */, ); name = Sources; @@ -1312,7 +1310,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "cachedir=\".cache\"\nliburl=\"https://openrct2.website/files/orctlibs-osx.zip\"\n# keep in sync with version in build.sh\nsha256sum=\"02ebc8e7fd8b9b02b7144721784c5d96202a17398bc8652da163c8c85b66a7db\"\n\n[[ ! -e \"${SRCROOT}/libversion\" || $(head -n 1 \"${SRCROOT}/libversion\") != $sha256sum ]]\noutdated=$?\n\nif [[ $outdated -eq 0 ]] || [[ ! -f \"${SRCROOT}/$cachedir/orctlibs.zip\" ]]; then\n if [[ ! -d \"${SRCROOT}/$cachedir\" ]]; then mkdir \"${SRCROOT}/$cachedir\"; fi\n if [[ -f \"${SRCROOT}/$cachedir/orctlibs.zip\" ]]; then rm \"${SRCROOT}/$cachedir/orctlibs.zip\"; fi\n curl -L -o \"${SRCROOT}/$cachedir/orctlibs.zip\" \"$liburl\"\n if [[ -d \"${SRCROOT}/$cachedir/orctlibs\" ]]; then rm -rf \"${SRCROOT}/$cachedir/orctlibs\"; fi\n mkdir \"${SRCROOT}/$cachedir/orctlibs\"\n unzip -uaq -d \"${SRCROOT}/$cachedir/orctlibs\" \"${SRCROOT}/$cachedir/orctlibs.zip\"\nfi\n\nif [[ $outdated -eq 0 ]] || [[ ! -d \"${SRCROOT}/lib\" ]]; then\n if [[ -d \"${SRCROOT}/lib\" ]]; then rm -r \"${SRCROOT}/lib\"; fi\n cp -Rf \"${SRCROOT}/$cachedir/orctlibs/local\" \"${SRCROOT}/lib\"\nfi\nif [[ $outdated -eq 0 ]] || [[ ! -d \"${SRCROOT}/libxc\" ]]; then\n if [[ -d \"${SRCROOT}/libxc\" ]]; then rm -r \"${SRCROOT}/libxc\"; fi\n cp -Rf \"${SRCROOT}/$cachedir/orctlibs/glob\" \"${SRCROOT}/libxc\"\nfi\n\nif [[ $outdated -eq 0 ]]; then\n newsha=$(shasum -a 256 \"${SRCROOT}/$cachedir/orctlibs.zip\" | cut -f1 -d\" \")\n echo $newsha > \"${SRCROOT}/libversion\"\n [[ \"$newsha\" == \"$sha256sum\" ]]\nfi"; + shellScript = "cachedir=\".cache\"\nliburl=\"https://openrct2.website/files/orctlibs-osx.zip\"\n# keep in sync with version in build.sh\nsha256sum=\"6562ce9e1f37f125e3345bfd8b961777800436bf607b30dc7c964e0e6991ad2c\"\n\n[[ ! -e \"${SRCROOT}/libversion\" || $(head -n 1 \"${SRCROOT}/libversion\") != $sha256sum ]]\noutdated=$?\n\nif [[ $outdated -eq 0 ]] || [[ ! -f \"${SRCROOT}/$cachedir/orctlibs.zip\" ]]; then\n if [[ ! -d \"${SRCROOT}/$cachedir\" ]]; then mkdir \"${SRCROOT}/$cachedir\"; fi\n if [[ -f \"${SRCROOT}/$cachedir/orctlibs.zip\" ]]; then rm \"${SRCROOT}/$cachedir/orctlibs.zip\"; fi\n curl -L -o \"${SRCROOT}/$cachedir/orctlibs.zip\" \"$liburl\"\n if [[ -d \"${SRCROOT}/$cachedir/orctlibs\" ]]; then rm -rf \"${SRCROOT}/$cachedir/orctlibs\"; fi\n mkdir \"${SRCROOT}/$cachedir/orctlibs\"\n unzip -uaq -d \"${SRCROOT}/$cachedir/orctlibs\" \"${SRCROOT}/$cachedir/orctlibs.zip\"\nfi\n\nif [[ $outdated -eq 0 ]] || [[ ! -d \"${SRCROOT}/lib\" ]]; then\n if [[ -d \"${SRCROOT}/lib\" ]]; then rm -r \"${SRCROOT}/lib\"; fi\n cp -Rf \"${SRCROOT}/$cachedir/orctlibs/local\" \"${SRCROOT}/lib\"\nfi\nif [[ $outdated -eq 0 ]] || [[ ! -d \"${SRCROOT}/libxc\" ]]; then\n if [[ -d \"${SRCROOT}/libxc\" ]]; then rm -r \"${SRCROOT}/libxc\"; fi\n cp -Rf \"${SRCROOT}/$cachedir/orctlibs/glob\" \"${SRCROOT}/libxc\"\nfi\n\nif [[ $outdated -eq 0 ]]; then\n newsha=$(shasum -a 256 \"${SRCROOT}/$cachedir/orctlibs.zip\" | cut -f1 -d\" \")\n echo $newsha > \"${SRCROOT}/libversion\"\n [[ \"$newsha\" == \"$sha256sum\" ]]\nfi"; }; /* End PBXShellScriptBuildPhase section */ @@ -1382,7 +1380,6 @@ D4EC48231C26342F0024B507 /* station.c in Sources */, D4EC484D1C26342F0024B507 /* new_ride.c in Sources */, D4EC484A1C26342F0024B507 /* music_credits.c in Sources */, - D4EC482B1C26342F0024B507 /* tutorial.c in Sources */, D4EC48241C26342F0024B507 /* track.c in Sources */, D4EC47DF1C26342F0024B507 /* addresses.c in Sources */, D4EC484B1C26342F0024B507 /* network_status.c in Sources */, @@ -1450,6 +1447,7 @@ D4EC482D1C26342F0024B507 /* util.c in Sources */, D4EC47EA1C26342F0024B507 /* line.c in Sources */, D4EC48271C26342F0024B507 /* vehicle.c in Sources */, + D46105CE1C38828D00DB1EE3 /* scenario_sources.c in Sources */, D4EC48281C26342F0024B507 /* scenario_list.c in Sources */, D4EC48581C26342F0024B507 /* scenery.c in Sources */, D4EC48061C26342F0024B507 /* LanguagePack.cpp in Sources */, diff --git a/appveyor.yml b/appveyor.yml index 081ac5567d..c2beb58a80 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,5 @@ version: 0.0.4.{build} +os: Previous Visual Studio 2015 build_script: - ps: >- .\setenv.ps1 diff --git a/data/language/chinese_traditional.txt b/data/language/chinese_traditional.txt index aa8fbe1452..8b5d74b464 100644 --- a/data/language/chinese_traditional.txt +++ b/data/language/chinese_traditional.txt @@ -3946,6 +3946,32 @@ STR_5603 :遊客已離開遊樂設施 STR_5604 :遊客已購買物品 STR_5605 :遊客已使用設施 STR_5606 :遊客已死亡 +STR_5607 :{SMALLFONT}{BLACK}強制移除選中的地圖元素. +STR_5608 :BH +STR_5609 :CH +STR_5610 :{SMALLFONT}{BLACK}移除選中的地圖元素. 使用時請注意. 因為強制移除地圖元素並不會對遊戲中的現金做成影響. +STR_5611 :G +STR_5612 :{SMALLFONT}{BLACK}Ghost flag +STR_5613 :B +STR_5614 :{SMALLFONT}{BLACK}Broken flag +STR_5615 :L +STR_5616 :{SMALLFONT}{BLACK}Last element for tile flag +STR_5617 :{SMALLFONT}{BLACK}將選中的元素移到上面. +STR_5618 :{SMALLFONT}{BLACK}將選中的元素移到下面. +STR_5619 :夢幻遊樂園 +STR_5620 :夢幻遊樂園: 資料片1 +STR_5621 :夢幻遊樂園: 資料片2 +STR_5622 :模擬樂園2 +STR_5623 :瘋狂世界 +STR_5624 :時空歷險 +STR_5625 :{OPENQUOTES}真實的{ENDQUOTES}樂園 +STR_5626 :其他樂園 +STR_5627 :樂園列表的排序方式: +STR_5628 :出處的遊戲 +STR_5629 :困難程度 +STR_5630 :允許劇情解鎖 +STR_5631 :額外下載的官方樂園 +STR_5632 :建設你的.. ##################### diff --git a/data/language/english_uk.txt b/data/language/english_uk.txt index 202cc767e4..b275753414 100644 --- a/data/language/english_uk.txt +++ b/data/language/english_uk.txt @@ -3677,8 +3677,8 @@ 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_5339 :{SMALLFONT}{BLACK}Base height +STR_5340 :{SMALLFONT}{BLACK}Clearance height STR_5341 :Flags STR_5342 :Choose a map tile STR_5343 :Automatically place staff @@ -3945,6 +3945,474 @@ STR_5603 :Guest has left ride STR_5604 :Guest has bought item STR_5605 :Guest has used facility STR_5606 :Guest has died +STR_5607 :{SMALLFONT}{BLACK}Forcefully remove selected map element. +STR_5608 :BH +STR_5609 :CH +STR_5610 :{SMALLFONT}{BLACK}Remove the currently selected map element. This will forcefully remove it, so no cash will be used/gained. Use with caution. +STR_5611 :G +STR_5612 :{SMALLFONT}{BLACK}Ghost flag +STR_5613 :B +STR_5614 :{SMALLFONT}{BLACK}Broken flag +STR_5615 :L +STR_5616 :{SMALLFONT}{BLACK}Last element for tile flag +STR_5617 :{SMALLFONT}{BLACK}Move selected element up. +STR_5618 :{SMALLFONT}{BLACK}Move selected element down. +STR_5619 :RollerCoaster Tycoon +STR_5620 :Added Attractions +STR_5621 :Loopy Landscapes +STR_5622 :RollerCoaster Tycoon 2 +STR_5623 :Wacky Worlds +STR_5624 :Time Twister +STR_5625 :{OPENQUOTES}Real{ENDQUOTES} Parks +STR_5626 :Other Parks +STR_5627 :Group scenario list by: +STR_5628 :Source game +STR_5629 :Difficulty level +STR_5630 :Enable unlocking of scenarios +STR_5631 :Original DLC Parks +STR_5632 :Build your own... + +############# +# Scenarios # +################ +# RCT Original # +################ + +STR_SCNR :Forest Frontiers +STR_PARK :Forest Frontiers +STR_DTLS :Deep in the forest, build a thriving theme park in a large cleared area + + +STR_SCNR :Dynamite Dunes +STR_PARK :Dynamite Dunes +STR_DTLS :Built in the middle of the desert, this theme park contains just one roller coaster but has space for expansion + + +STR_SCNR :Leafy Lake +STR_PARK :Leafy Lake +STR_DTLS :Starting from scratch, build a theme park around a large lake + + +STR_SCNR :Diamond Heights +STR_PARK :Diamond Heights +STR_DTLS :Diamond Heights is already a successful theme park with great rides - develop it to double its value + + +STR_SCNR :Evergreen Gardens +STR_PARK :Evergreen Gardens +STR_DTLS :Convert the beautiful Evergreen Gardens into a thriving theme park + + +STR_SCNR :Bumbly Beach +STR_PARK :Bumbly Beach +STR_DTLS :Develop Bumbly Beach's small amusement park into a thriving theme park + + +STR_SCNR :Trinity Islands +STR_PARK :Trinity Islands +STR_DTLS :Several islands form the basis for this new park + + +STR_SCNR :Katie's Dreamland +STR_PARK :Katie's Dreamland +STR_DTLS :A small theme park with a few rides and room for expansion - Your aim is to double the park value + + +STR_SCNR :Pokey Park +STR_PARK :Pokey Park +STR_DTLS :A small, cramped amusement park which requires major expansion + + +STR_SCNR :White Water Park +STR_PARK :White Water Park +STR_DTLS :A park with some excellent water-based rides requires expansion + + +STR_SCNR :Millennium Mines +STR_PARK :Millennium Mines +STR_DTLS :Convert a large abandoned mine from a tourist attraction into a theme park + + +STR_SCNR :Karts & Coasters +STR_PARK :Karts & Coasters +STR_DTLS :A large park hidden in the forest, with only go-kart tracks and wooden roller coasters + + +STR_SCNR :Mel's World +STR_PARK :Mel's World +STR_DTLS :This theme park has some well-designed modern rides, but plenty of space for expansion + + +STR_SCNR :Mystic Mountain +STR_PARK :Mystic Mountain +STR_DTLS :In the hilly forests of Mystic Mountain, build a theme park from scratch + + +STR_SCNR :Pacific Pyramids +STR_PARK :Pacific Pyramids +STR_DTLS :Convert the Egyptian Ruins tourist attraction into a thriving theme park + + +STR_SCNR :Crumbly Woods +STR_PARK :Crumbly Woods +STR_DTLS :A large park with well-designed but rather old rides - Replace the old rides or add new rides to make the park more popular + + +STR_SCNR :Paradise Pier +STR_PARK :Paradise Pier +STR_DTLS :Convert this sleepy town's pier into a thriving attraction + + +STR_SCNR :Lightning Peaks +STR_PARK :Lightning Peaks +STR_DTLS :The beautiful mountains of Lightning Peaks are popular with walkers and sightseers - Use the available land to attract a new thrill-seeking clientele + + +STR_SCNR :Ivory Towers +STR_PARK :Ivory Towers +STR_DTLS :A well-established park, which has a few problems + + +STR_SCNR :Rainbow Valley +STR_PARK :Rainbow Valley +STR_DTLS :Rainbow Valley's local authority won't allow any landscape changes or large tree removal, but you must develop the area into a large theme park + + +STR_SCNR :Thunder Rock +STR_PARK :Thunder Rock +STR_DTLS :Thunder Rock stands in the middle of a desert and attracts many tourists - Use the available space to build rides to attract more people + + +STR_SCNR :Mega Park +STR_PARK :Mega Park +STR_DTLS :Just for fun! + +## Added Attractions + +STR_SCNR :Whispering Cliffs +STR_PARK :Whispering Cliffs +STR_DTLS :Develop the seaside cliffs into a thriving amusement park + + +STR_SCNR :Three Monkeys Park +STR_PARK :Three Monkeys Park +STR_DTLS :Central to this large developing park is a giant triple-track racing/duelling steel coaster + + +STR_SCNR :Canary Mines +STR_PARK :Canary Mines +STR_DTLS :This abandoned mine already has the makings of a tourist attraction with its minature railway and a pair of vertical drop roller coasters + + +STR_SCNR :Barony Bridge +STR_PARK :Barony Bridge +STR_DTLS :An old redundant bridge is yours to develop into an amusement park + + +STR_SCNR :Funtopia +STR_PARK :Funtopia +STR_DTLS :Covering land both sides of a highway, this park has several rides already operating + + +STR_SCNR :Haunted Harbor +STR_PARK :Haunted Harbor +STR_DTLS :The local authority has agreed to sell nearby land cheaply to this small seaside park, on the condition that certain rides are preserved + + +STR_SCNR :Fun Fortress +STR_PARK :Fun Fortress +STR_DTLS :This castle is all yours to turn into a theme park + + +STR_SCNR :Future World +STR_PARK :Future World +STR_DTLS :This futuristic park has plenty of space for new rides on its alien landscape + + +STR_SCNR :Gentle Glen +STR_PARK :Gentle Glen +STR_DTLS :The local population prefer gentle and relaxing rides, so it is your job to expand this park to suit their tastes + + +STR_SCNR :Jolly Jungle +STR_PARK :Jolly Jungle +STR_DTLS :Deep in the jungle lies a large area of land ready to be turned into a theme park + + +STR_SCNR :Hydro Hills +STR_PARK :Hydro Hills +STR_DTLS :A series of stepped lakes form the basis for this new park + + +STR_SCNR :Sprightly Park +STR_PARK :Sprightly Park +STR_DTLS :This elderly park has many historical rides but is badly in debt + + +STR_SCNR :Magic Quarters +STR_PARK :Magic Quarters +STR_DTLS :A large area of land has been cleared and partially themed ready for you to develop into a landscaped theme park + + +STR_SCNR :Fruit Farm +STR_PARK :Fruit Farm +STR_DTLS :A thriving fruit farm has built a railroad to boost its income, your job is to develop it into a full-blown amusement park + + +STR_SCNR :Butterfly Dam +STR_PARK :Butterfly Dam +STR_DTLS :The area around a dam is available for you to develop into an amusement park + + +STR_SCNR :Coaster Canyon +STR_PARK :Coaster Canyon +STR_DTLS :A vast canyon is yours to turn into a theme park + + +STR_SCNR :Thunderstorm Park +STR_PARK :Thunderstorm Park +STR_DTLS :The weather is so wet here that a giant pyramid has been built to allow some rides to be built under cover + + +STR_SCNR :Harmonic Hills +STR_PARK :Harmonic Hills +STR_DTLS :The local authority won't allow you to build above tree height in this park + + +STR_SCNR :Roman Village +STR_PARK :Roman Village +STR_DTLS :Develop this Roman-themed park by adding rides and roller coasters + + +STR_SCNR :Swamp Cove +STR_PARK :Swamp Cove +STR_DTLS :Built partly on a series of small islands, this park already has a pair of large roller coasters as its centerpiece + + +STR_SCNR :Adrenaline Heights +STR_PARK :Adrenaline Heights +STR_DTLS :Build a park to appeal to the high-intensity thrill-seeking local people + + +STR_SCNR :Utopia Park +STR_PARK :Utopia Park +STR_DTLS :An oasis in the middle of the desert provides an unusual opportunity to build an amusement park + + +STR_SCNR :Rotting Heights +STR_PARK :Rotting Heights +STR_DTLS :Overgrown and dilapidated, can you resurrect this once-great amusement park? + + +STR_SCNR :Fiasco Forest +STR_PARK :Fiasco Forest +STR_DTLS :Full of badly designed and dangerous rides, you have a very limited budget and time to fix the problems and turn the park around + + +STR_SCNR :Pickle Park +STR_PARK :Pickle Park +STR_DTLS :The local authority will not allow any kind of advertising or promotion, so this park must succeed by reputation only + + +STR_SCNR :Giggle Downs +STR_PARK :Giggle Downs +STR_DTLS :A four lane steeplechase ride is the centerpiece of this expanding park + + +STR_SCNR :Mineral Park +STR_PARK :Mineral Park +STR_DTLS :Turn this abandoned stone quarry into a place to attract thrill-seeking tourists + + +STR_SCNR :Coaster Crazy +STR_PARK :Coaster Crazy +STR_DTLS :You have limited funds but unlimited time to turn this mountainside area into a vast roller coaster park + + +STR_SCNR :Urban Park +STR_PARK :Urban Park +STR_DTLS :A tiny park has done a deal with the nearby town to allow expansion through the town itself + + +STR_SCNR :Geoffrey Gardens +STR_PARK :Geoffrey Gardens +STR_DTLS :A large garden park needs turning into a thriving theme park + + +## Loopy Landscapes + +STR_SCNR :Iceberg Islands +STR_PARK :Iceberg Islands +STR_DTLS :A collection of icebergs make a cold setting for this ambitious theme park + + +STR_SCNR :Volcania +STR_PARK :Volcania +STR_DTLS :A dormant volcano is the setting of this coaster-building challenge + + +STR_SCNR :Arid Heights +STR_PARK :Arid Heights +STR_DTLS :Free of any financial limits, your challenge is to develop this desert park while keeping the guests happy + + +STR_SCNR :Razor Rocks +STR_PARK :Razor Rocks +STR_DTLS :Your task is to build a massive coaster-filled park in amongst Razor Rocks + + +STR_SCNR :Crater Lake +STR_PARK :Crater Lake +STR_DTLS :A large lake in an ancient crater is the setting for this park + + +STR_SCNR :Vertigo Views +STR_PARK :Vertigo Views +STR_DTLS :This large park already has an excellent hyper-coaster, but your task is to massively increase its profit + + +STR_SCNR :Paradise Pier 2 +STR_PARK :Paradise Pier 2 +STR_DTLS :Paradise Pier has expanded its network of walkways over the sea, and your task is to expand the park to use the extra space + + +STR_SCNR :Dragon's Cove +STR_PARK :Dragon's Cove +STR_DTLS :This sea-side cove is the setting for this coaster-building challenge + + +STR_SCNR :Good Knight Park +STR_PARK :Good Knight Park +STR_DTLS :A castle with a pair of roller coasters needs developing into a larger theme park + + +STR_SCNR :Wacky Warren +STR_PARK :Wacky Warren +STR_DTLS :A park which has much of its footpaths and coasters underground + + +STR_SCNR :Grand Glacier +STR_PARK :Grand Glacier +STR_DTLS :A glacier-filled valley is yours to develop into a theme park + + +STR_SCNR :Crazy Craters +STR_PARK :Crazy Craters +STR_DTLS :In a far-off world where money is not needed, you must build an entertainment centre to keep the people happy + + +STR_SCNR :Dusty Desert +STR_PARK :Dusty Desert +STR_DTLS :Five coasters require completion in this desert park + + +STR_SCNR :Woodworm Park +STR_PARK :Woodworm Park +STR_DTLS :This historical park is only allowed to build older-styled rides + + +STR_SCNR :Icarus Park +STR_PARK :Icarus Park +STR_DTLS :Develop this alien park to maximize its profit + + +STR_SCNR :Sunny Swamps +STR_PARK :Sunny Swamps +STR_DTLS :This well-themed amusement park already has several rides, but has plenty of space for expansion + + +STR_SCNR :Frightmare Hills +STR_PARK :Frightmare Hills +STR_DTLS :A scary park with a giant centrepiece coaster + + +STR_SCNR :Thunder Rocks +STR_PARK :Thunder Rocks +STR_DTLS :Two large hunks of rock stick out of the sand, upon which the beginnings of a theme park are constructed + + +STR_SCNR :Octagon Park +STR_PARK :Octagon Park +STR_DTLS :In this large park you must design and build ten large coasters + + +STR_SCNR :Pleasure Island +STR_PARK :Pleasure Island +STR_DTLS :A long thin island makes a challenging setting to build a selection of coasters + + +STR_SCNR :Icicle Worlds +STR_PARK :Icicle Worlds +STR_DTLS :An icy landscape needs turning into a thriving theme park + + +STR_SCNR :Southern Sands +STR_PARK :Southern Sands +STR_DTLS :A desert park with some cleverly designed coasters is yours to expand + + +STR_SCNR :Tiny Towers +STR_PARK :Tiny Towers +STR_DTLS :In this tiny park you must finish building the five existing coasters + + +STR_SCNR :Nevermore Park +STR_PARK :Nevermore Park +STR_DTLS :A large park with a novel transporation system around its edge + + +STR_SCNR :Pacifica +STR_PARK :Pacifica +STR_DTLS :This large island is all yours to develop as an amusement park + + +STR_SCNR :Urban Jungle +STR_PARK :Urban Jungle +STR_DTLS :A giant abandoned skyscraper is a unique opportunity for a theme park developer + + +STR_SCNR :Terror Town +STR_PARK :Terror Town +STR_DTLS :This urban area is all yours to develop into as an amusement park + + +STR_SCNR :Megaworld Park +STR_PARK :Megaworld Park +STR_DTLS :A giant park already packed full of rides needs improving + + +STR_SCNR :Venus Ponds +STR_PARK :Venus Ponds +STR_DTLS :On a far-away planet this area of land needs turning into a theme park + + +STR_SCNR :Micro Park +STR_PARK :Micro Park +STR_DTLS :Try to create the world's smallest profitable park + +## Real Parks from RCT1 +# None of them had details + +STR_SCNR :Alton Towers +STR_PARK :Alton Towers +STR_DTLS : + + +STR_SCNR :Heide-Park +STR_PARK :Heide-Park +STR_DTLS : + + +STR_SCNR :Blackpool Pleasure Beach +STR_PARK :Blackpool Pleasure Beach +STR_DTLS : + +## Misc parks from RCT1 +# Had no details + +STR_SCNR :Fort Anachronism +STR_PARK :Fort Anachronism +STR_DTLS : ##################### # Rides/attractions # diff --git a/data/language/english_us.txt b/data/language/english_us.txt index 25860add99..8ce410de46 100644 --- a/data/language/english_us.txt +++ b/data/language/english_us.txt @@ -3646,8 +3646,8 @@ 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_5306 :RollerCoaster Tycoon 1 (CF) +STR_5307 :RollerCoaster Tycoon 1 (CF + LL) STR_5308 :RollerCoaster Tycoon 2 STR_5309 :OpenRCT2 STR_5310 :Random @@ -3679,8 +3679,8 @@ 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_5339 :{SMALLFONT}{BLACK}Base height +STR_5340 :{SMALLFONT}{BLACK}Clearance height STR_5341 :Flags STR_5342 :Choose a map tile STR_5343 :Automatically place staff @@ -3926,6 +3926,494 @@ STR_5582 :Trap mouse cursor in window STR_5583 :{COMMA1DP16}ms{POWERNEGATIVEONE} STR_5584 :SI STR_5585 :{SMALLFONT}{BLACK}Unlocks ride operation limits, allowing for things like {VELOCITY} lift hills +STR_5586 :Automatically open shops and stalls +STR_5587 :{SMALLFONT}{BLACK}When enabled, shops and stalls will be automatically opened after building them +STR_5588 :{SMALLFONT}{BLACK}Play with other players +STR_5589 :Notification Settings +STR_5590 :Park awards +STR_5591 :Marketing campaign has finished +STR_5592 :Park warnings +STR_5593 :Park rating warnings +STR_5594 :Ride has broken down +STR_5595 :Ride has crashed +STR_5596 :Ride warnings +STR_5597 :Ride / scenery researched +STR_5598 :Guest warnings +STR_5599 :Guest is lost +STR_5600 :Guest has left the park +STR_5601 :Guest is queuing for ride +STR_5602 :Guest is on ride +STR_5603 :Guest has left ride +STR_5604 :Guest has bought item +STR_5605 :Guest has used facility +STR_5606 :Guest has died +STR_5607 :{SMALLFONT}{BLACK}Forcefully remove selected map element. +STR_5608 :BH +STR_5609 :CH +STR_5610 :{SMALLFONT}{BLACK}Remove the currently selected map element. This will forcefully remove it, so no cash will be used/gained. Use with caution. +STR_5611 :G +STR_5612 :{SMALLFONT}{BLACK}Ghost flag +STR_5613 :B +STR_5614 :{SMALLFONT}{BLACK}Broken flag +STR_5615 :L +STR_5616 :{SMALLFONT}{BLACK}Last element for tile flag +STR_5617 :{SMALLFONT}{BLACK}Move selected element up. +STR_5618 :{SMALLFONT}{BLACK}Move selected element down. +STR_5619 :RollerCoaster Tycoon +STR_5620 :Corkscrew Follies +STR_5621 :Loopy Landscapes +STR_5622 :RollerCoaster Tycoon 2 +STR_5623 :Wacky Worlds +STR_5624 :Time Twister +STR_5625 :{OPENQUOTES}Real{ENDQUOTES} Parks +STR_5626 :Other Parks +STR_5627 :Group scenario list by: +STR_5628 :Source game +STR_5629 :Difficulty level +STR_5630 :Enable unlocking of scenarios +STR_5631 :Original DLC Parks +STR_5632 :Build your own... + +############# +# Scenarios # +############# + +## RCT Original + +STR_SCNR :Forest Frontiers +STR_PARK :Forest Frontiers +STR_DTLS :Deep in the forest, build a thriving theme park in a large cleared area + + +STR_SCNR :Dynamite Dunes +STR_PARK :Dynamite Dunes +STR_DTLS :Built in the middle of the desert, this theme park contains just one roller coaster but has space for expansion + + +STR_SCNR :Leafy Lake +STR_PARK :Leafy Lake +STR_DTLS :Starting from scratch, build a theme park around a large lake + + +STR_SCNR :Diamond Heights +STR_PARK :Diamond Heights +STR_DTLS :Diamond Heights is already a successful theme park with great rides - develop it to double its value + + +STR_SCNR :Evergreen Gardens +STR_PARK :Evergreen Gardens +STR_DTLS :Convert the beautiful Evergreen Gardens into a thriving theme park + + +STR_SCNR :Bumbly Beach +STR_PARK :Bumbly Beach +STR_DTLS :Develop Bumbly Beach's small amusement park into a thriving theme park + + +STR_SCNR :Trinity Islands +STR_PARK :Trinity Islands +STR_DTLS :Several islands form the basis for this new park + + +STR_SCNR :Katie's World +STR_PARK :Katie's World +STR_DTLS :A small theme park with a few rides and room for expansion - Your aim is to double the park value + + +STR_SCNR :Dinky Park +STR_PARK :Dinky Park +STR_DTLS :A small, cramped amusement park which requires major expansion + + +STR_SCNR :Aqua Park +STR_PARK :Aqua Park +STR_DTLS :A park with some excellent water-based rides requires expansion + + +STR_SCNR :Millennium Mines +STR_PARK :Millennium Mines +STR_DTLS :Convert a large abandoned mine from a tourist attraction into a theme park + + +STR_SCNR :Karts & Coasters +STR_PARK :Karts & Coasters +STR_DTLS :A large park hidden in the forest, with only go-kart tracks and wooden roller coasters + + +STR_SCNR :Mel's World +STR_PARK :Mel's World +STR_DTLS :This theme park has some well-designed modern rides, but plenty of space for expansion + + +STR_SCNR :Mothball Mountain +STR_PARK :Mothball Mountain +STR_DTLS :In the hilly forests of Mothball Mountain, build a theme park from scratch + + +STR_SCNR :Pacific Pyramids +STR_PARK :Pacific Pyramids +STR_DTLS :Convert the Egyptian Ruins tourist attraction into a thriving theme park + + +STR_SCNR :Crumbly Woods +STR_PARK :Crumbly Woods +STR_DTLS :A large park with well-designed but rather old rides - Replace the old rides or add new rides to make the park more popular + + +STR_SCNR :Big Pier +STR_PARK :Big Pier +STR_DTLS :Convert this sleepy town's pier into a thriving attraction + + +STR_SCNR :Lightning Peaks +STR_PARK :Lightning Peaks +STR_DTLS :The beautiful mountains of Lightning Peaks are popular with walkers and sightseers - Use the available land to attract a new thrill-seeking clientele + + +STR_SCNR :Ivory Towers +STR_PARK :Ivory Towers +STR_DTLS :A well-established park, which has a few problems + + +STR_SCNR :Rainbow Valley +STR_PARK :Rainbow Valley +STR_DTLS :Rainbow Valley's local authority won't allow any landscape changes or large tree removal, but you must develop the area into a large theme park + + +STR_SCNR :Thunder Rock +STR_PARK :Thunder Rock +STR_DTLS :Thunder Rock stands in the middle of a desert and attracts many tourists - Use the available space to build rides to attract more people + + +STR_SCNR :Mega Park +STR_PARK :Mega Park +STR_DTLS :Just for fun! + +## Corkscrew Follies + +STR_SCNR :Whispering Cliffs +STR_PARK :Whispering Cliffs +STR_DTLS :Develop the seaside cliffs into a thriving amusement park + + +STR_SCNR :Three Monkeys Park +STR_PARK :Three Monkeys Park +STR_DTLS :Central to this large developing park is a giant triple-track racing/duelling steel coaster + + +STR_SCNR :Canary Mines +STR_PARK :Canary Mines +STR_DTLS :This abandoned mine already has the makings of a tourist attraction with its minature railway and a pair of vertical drop roller coasters + + +STR_SCNR :Barony Bridge +STR_PARK :Barony Bridge +STR_DTLS :An old redundant bridge is yours to develop into an amusement park + + +STR_SCNR :Funtopia +STR_PARK :Funtopia +STR_DTLS :Covering land both sides of a highway, this park has several rides already operating + + +STR_SCNR :Haunted Harbor +STR_PARK :Haunted Harbor +STR_DTLS :The local authority has agreed to sell nearby land cheaply to this small seaside park, on the condition that certain rides are preserved + + +STR_SCNR :Fun Fortress +STR_PARK :Fun Fortress +STR_DTLS :This castle is all yours to turn into a theme park + + +STR_SCNR :Future World +STR_PARK :Future World +STR_DTLS :This futuristic park has plenty of space for new rides on its alien landscape + + +STR_SCNR :Gentle Glen +STR_PARK :Gentle Glen +STR_DTLS :The local population prefer gentle and relaxing rides, so it is your job to expand this park to suit their tastes + + +STR_SCNR :Jolly Jungle +STR_PARK :Jolly Jungle +STR_DTLS :Deep in the jungle lies a large area of land ready to be turned into a theme park + + +STR_SCNR :Hydro Hills +STR_PARK :Hydro Hills +STR_DTLS :A series of stepped lakes form the basis for this new park + + +STR_SCNR :Sprightly Park +STR_PARK :Sprightly Park +STR_DTLS :This elderly park has many historical rides but is badly in debt + + +STR_SCNR :Magic Quarters +STR_PARK :Magic Quarters +STR_DTLS :A large area of land has been cleared and partially themed ready for you to develop into a landscaped theme park + + +STR_SCNR :Fruit Farm +STR_PARK :Fruit Farm +STR_DTLS :A thriving fruit farm has built a railroad to boost its income, your job is to develop it into a full-blown amusement park + + +STR_SCNR :Butterfly Dam +STR_PARK :Butterfly Dam +STR_DTLS :The area around a dam is available for you to develop into an amusement park + + +STR_SCNR :Coaster Canyon +STR_PARK :Coaster Canyon +STR_DTLS :A vast canyon is yours to turn into a theme park + + +STR_SCNR :Thunderstorm Park +STR_PARK :Thunderstorm Park +STR_DTLS :The weather is so wet here that a giant pyramid has been built to allow some rides to be built under cover + + +STR_SCNR :Harmonic Hills +STR_PARK :Harmonic Hills +STR_DTLS :The local authority won't allow you to build above tree height in this park + + +STR_SCNR :Roman Village +STR_PARK :Roman Village +STR_DTLS :Develop this Roman-themed park by adding rides and roller coasters + + +STR_SCNR :Swamp Cove +STR_PARK :Swamp Cove +STR_DTLS :Built partly on a series of small islands, this park already has a pair of large roller coasters as its centerpiece + + +STR_SCNR :Adrenaline Heights +STR_PARK :Adrenaline Heights +STR_DTLS :Build a park to appeal to the high-intensity thrill-seeking local people + + +STR_SCNR :Utopia Park +STR_PARK :Utopia Park +STR_DTLS :An oasis in the middle of the desert provides an unusual opportunity to build an amusement park + + +STR_SCNR :Rotting Heights +STR_PARK :Rotting Heights +STR_DTLS :Overgrown and dilapidated, can you resurrect this once-great amusement park? + + +STR_SCNR :Fiasco Forest +STR_PARK :Fiasco Forest +STR_DTLS :Full of badly designed and dangerous rides, you have a very limited budget and time to fix the problems and turn the park around + + +STR_SCNR :Pickle Park +STR_PARK :Pickle Park +STR_DTLS :The local authority will not allow any kind of advertising or promotion, so this park must succeed by reputation only + + +STR_SCNR :Giggle Downs +STR_PARK :Giggle Downs +STR_DTLS :A four lane steeplechase ride is the centerpiece of this expanding park + + +STR_SCNR :Mineral Park +STR_PARK :Mineral Park +STR_DTLS :Turn this abandoned stone quarry into a place to attract thrill-seeking tourists + + +STR_SCNR :Coaster Crazy +STR_PARK :Coaster Crazy +STR_DTLS :You have limited funds but unlimited time to turn this mountainside area into a vast roller coaster park + + +STR_SCNR :Urban Park +STR_PARK :Urban Park +STR_DTLS :A tiny park has done a deal with the nearby town to allow expansion through the town itself + + +STR_SCNR :Geoffrey Gardens +STR_PARK :Geoffrey Gardens +STR_DTLS :A large garden park needs turning into a thriving theme park + +## Loopy Landscapes + +STR_SCNR :Iceberg Islands +STR_PARK :Iceberg Islands +STR_DTLS :A collection of icebergs make a cold setting for this ambitious theme park + + +STR_SCNR :Volcania +STR_PARK :Volcania +STR_DTLS :A dormant volcano is the setting of this coaster-building challenge + + +STR_SCNR :Arid Heights +STR_PARK :Arid Heights +STR_DTLS :Free of any financial limits, your challenge is to develop this desert park while keeping the guests happy + + +STR_SCNR :Razor Rocks +STR_PARK :Razor Rocks +STR_DTLS :Your task is to build a massive coaster-filled park in amongst Razor Rocks + + +STR_SCNR :Crater Lake +STR_PARK :Crater Lake +STR_DTLS :A large lake in an ancient crater is the setting for this park + + +STR_SCNR :Vertigo Views +STR_PARK :Vertigo Views +STR_DTLS :This large park already has an excellent hyper-coaster, but your task is to massively increase its profit + + +STR_SCNR :Big Pier 2 +STR_PARK :Big Pier 2 +STR_DTLS :Big Pier has expanded its network of walkways over the sea, and your task is to expand the park to use the extra space + + +STR_SCNR :Dragon's Cove +STR_PARK :Dragon's Cove +STR_DTLS :This sea-side cove is the setting for this coaster-building challenge + + +STR_SCNR :Good Knight Park +STR_PARK :Good Knight Park +STR_DTLS :A castle with a pair of roller coasters needs developing into a larger theme park + + +STR_SCNR :Wacky Warren +STR_PARK :Wacky Warren +STR_DTLS :A park which has much of its footpaths and coasters underground + + +STR_SCNR :Grand Glacier +STR_PARK :Grand Glacier +STR_DTLS :A glacier-filled valley is yours to develop into a theme park + + +STR_SCNR :Crazy Craters +STR_PARK :Crazy Craters +STR_DTLS :In a far-off world where money is not needed, you must build an entertainment centre to keep the people happy + + +STR_SCNR :Dusty Desert +STR_PARK :Dusty Desert +STR_DTLS :Five coasters require completion in this desert park + + +STR_SCNR :Woodworm Park +STR_PARK :Woodworm Park +STR_DTLS :This historical park is only allowed to build older-styled rides + + +STR_SCNR :Icarus Park +STR_PARK :Icarus Park +STR_DTLS :Develop this alien park to maximize its profit + + +STR_SCNR :Sunny Swamps +STR_PARK :Sunny Swamps +STR_DTLS :This well-themed amusement park already has several rides, but has plenty of space for expansion + + +STR_SCNR :Frightmare Hills +STR_PARK :Frightmare Hills +STR_DTLS :A scary park with a giant centrepiece coaster + + +STR_SCNR :Thunder Rocks +STR_PARK :Thunder Rocks +STR_DTLS :Two large hunks of rock stick out of the sand, upon which the beginnings of a theme park are constructed + + +STR_SCNR :Octagon Park +STR_PARK :Octagon Park +STR_DTLS :In this large park you must design and build ten large coasters + + +STR_SCNR :Pleasure Island +STR_PARK :Pleasure Island +STR_DTLS :A long thin island makes a challenging setting to build a selection of coasters + + +STR_SCNR :Icicle Worlds +STR_PARK :Icicle Worlds +STR_DTLS :An icy landscape needs turning into a thriving theme park + + +STR_SCNR :Southern Sands +STR_PARK :Southern Sands +STR_DTLS :A desert park with some cleverly designed coasters is yours to expand + + +STR_SCNR :Tiny Towers +STR_PARK :Tiny Towers +STR_DTLS :In this tiny park you must finish building the five existing coasters + + +STR_SCNR :Nevermore Park +STR_PARK :Nevermore Park +STR_DTLS :A large park with a novel transporation system around its edge + + +STR_SCNR :Pacifica +STR_PARK :Pacifica +STR_DTLS :This large island is all yours to develop as an amusement park + + +STR_SCNR :Urban Jungle +STR_PARK :Urban Jungle +STR_DTLS :A giant abandoned skyscraper is a unique opportunity for a theme park developer + + +STR_SCNR :Terror Town +STR_PARK :Terror Town +STR_DTLS :This urban area is all yours to develop into as an amusement park + + +STR_SCNR :Megaworld Park +STR_PARK :Megaworld Park +STR_DTLS :A giant park already packed full of rides needs improving + + +STR_SCNR :Venus Ponds +STR_PARK :Venus Ponds +STR_DTLS :On a far-away planet this area of land needs turning into a theme park + + +STR_SCNR :Micro Park +STR_PARK :Micro Park +STR_DTLS :Try to create the world's smallest profitable park + +## Real Parks from RCT1 +# None of them had details + +STR_SCNR :Alton Towers +STR_PARK :Alton Towers +STR_DTLS : + + +STR_SCNR :Heide-Park +STR_PARK :Heide-Park +STR_DTLS : + + +STR_SCNR :Blackpool Pleasure Beach +STR_PARK :Blackpool Pleasure Beach +STR_DTLS : + +## Misc parks from RCT1 +# Had no details + +STR_SCNR :Fort Anachronism +STR_PARK :Fort Anachronism +STR_DTLS : ######### # Rides # diff --git a/data/language/german.txt b/data/language/german.txt index b2903cfcc1..830d2fa09a 100644 --- a/data/language/german.txt +++ b/data/language/german.txt @@ -3278,9 +3278,9 @@ STR_3269 :Landschaftsänderungen 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_3273 :Höhere Schwierigkeitsgrad für Parkbewertung STR_3274 :{SMALLFONT}{BLACK}Machen Sie die Parkbewertung schwieriger -STR_3275 :Höhere Schwierigkeitsstufe für Besuchergewinnung +STR_3275 :Höhere Schwierigkeitsgrad für Besuchergewinnung 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: @@ -3672,8 +3672,8 @@ STR_5335 :Attraktionseingang STR_5336 :Attraktionsausgang STR_5337 :Parkeingang STR_5338 :Elementtyp -STR_5339 :Basishöhe -STR_5340 :Lichte Höhe +STR_5339 :{SMALLFONT}{BLACK}Basishöhe +STR_5340 :{SMALLFONT}{BLACK}Lichte Höhe STR_5341 :Kennzeichen STR_5342 :Eine Kachel auf der Karte auswählen STR_5343 :Personal automatisch platzieren @@ -3898,7 +3898,7 @@ 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_5565 :{SMALLFONT}{BLACK}Fügt ein fehlerhaftes Kartenelement auf{NEWLINE}der Kachel ein, dadurch werden alle Elemente darüber versteckt. STR_5566 :Passwort: STR_5567 :Veröffentlichen STR_5568 :Passwort benötigt @@ -3919,6 +3919,495 @@ STR_5582 :Mauszeiger im Fenster fangen STR_5583 :{COMMA1DP16}ms{POWERNEGATIVEONE} STR_5584 :SI STR_5585 :{SMALLFONT}{BLACK}Hebt Beschränkungen von Attraktionen auf, um Dinge wie {VELOCITY} schnelle Lifthügel zu erlauben +STR_5586 :Läden und Stände automatisch öffnen +STR_5587 :{SMALLFONT}{BLACK}Wenn aktiviert, werden Läden und Stände nach dem Bauen automatisch geöffnet +STR_5588 :{SMALLFONT}{BLACK}Mit anderen Spielern spielen +STR_5589 :Benachrichtigungseinstellungen +STR_5590 :Parkauszeichnungen +STR_5591 :Marketingkampage wurde beendet +STR_5592 :Parkwarnungen +STR_5593 :Parkbewertungswarnungen +STR_5594 :Attraktion ist ausgefallen +STR_5595 :Attraktion ist verunglückt +STR_5596 :Attraktionswarnungen +STR_5597 :Attraktion / Szenerie erforscht +STR_5598 :Besucherwarnungen +STR_5599 :Besucher hat sich verirrt +STR_5600 :Besucher hat den Park verlassen +STR_5601 :Besucher steht für eine Attraktion schlange +STR_5602 :Besucher ist auf einer Attraktion +STR_5603 :Besucher hat eine Attraktion verlassen +STR_5604 :Besucher hat einen Gegenstand gekauft +STR_5605 :Besucher hat eine Einrichtung benutzt +STR_5606 :Besucher ist gestorben +STR_5607 :{SMALLFONT}{BLACK}Erzwingt das Löschen des{NEWLINE}ausgewählten Elements +STR_5608 :BH +STR_5609 :LH +STR_5610 :{SMALLFONT}{BLACK}Entfernt das ausgewählte Kartenelement. Das Löschen wird erzwungen und dadurch kein Geld verwendet/gutgeschrieben. Mit Vorsicht zu verwenden. +STR_5611 :G +STR_5612 :{SMALLFONT}{BLACK}Flag für Ghost-Element +STR_5613 :D +STR_5614 :{SMALLFONT}{BLACK}Flag für defektes Element +STR_5615 :L +STR_5616 :{SMALLFONT}{BLACK}Flag für letztes Element der Kachel +STR_5617 :{SMALLFONT}{BLACK}Ausgewähltes Element nach oben bewegen +STR_5618 :{SMALLFONT}{BLACK}Ausgewähltes Element nach unten bewegen +STR_5619 :RollerCoaster Tycoon +STR_5620 :Added Attractions +STR_5621 :Loopy Landscapes +STR_5622 :RollerCoaster Tycoon 2 +STR_5623 :Wacky Worlds +STR_5624 :Time Twister +STR_5625 :{OPENQUOTES}Reale{ENDQUOTES} Parks +STR_5626 :Sonstige Parks +STR_5627 :Szenarioliste ordnen nach: +STR_5628 :Spielherkunft +STR_5629 :Schwierigkeitsgrad +STR_5630 :Freispielen der Szenarios aktivieren +STR_5631 :Originale DLC Parks +STR_5632 :Bauen Sie Ihren eigenen... + +############# +# Scenarios # +################ +# RCT Original # +################ + +STR_SCNR :Forest Frontiers +STR_PARK :Forest Frontiers +STR_DTLS :Bauen Sie tief im Wald auf einem großen freigelegten Gelände einen erfolgreichen Freizeitpark. + + +STR_SCNR :Dynamite Dunes +STR_PARK :Dynamite Dunes +STR_DTLS :Dieser Freizeitpark inmitten der Wüste besitzt nur eine Achterbahn, hat aber genug Platz für Erweiterungen. + + +STR_SCNR :Leafy Lake +STR_PARK :Leafy Lake +STR_DTLS :Fangen Sie bei Null an und bauen Sie einen Freizeitpark um einen großen See herum. + + +STR_SCNR :Diamond Heights +STR_PARK :Diamond Heights +STR_DTLS :Diamond Heights ist bereits ein erfolgreicher Freizeitpark mit tollen Attraktionen. Entwickeln Sie ihn weiter und verdoppeln Sie seinen Verkehrswert. + + +STR_SCNR :Evergreen Gardens +STR_PARK :Evergreen Gardens +STR_DTLS :Wandeln Sie die schönen Evergreen Gardens in einen gut besuchten Freizeitpark um. + + +STR_SCNR :Bumbly Beach +STR_PARK :Bumbly Beach +STR_DTLS :Machen Sie aus dem kleinen Vergnügungspark Bumbly Beach einen florierenden Freizeitpark. + + +STR_SCNR :Trinity Islands +STR_PARK :Trinity Islands +STR_DTLS :Mehrere Inseln bilden den Ausgangspunkt für diesen neuen Park. + + +STR_SCNR :Katie's Dreamland +STR_PARK :Katie's Dreamland +STR_DTLS :Ein kleiner Freizeitpark mit wenigen Attraktionen, aber genug Gelände zur Erweiterung. Ihr Ziel ist es, den Verkehrswert des Parks zu verdoppeln. + + +STR_SCNR :Pokey Park +STR_PARK :Pokey Park +STR_DTLS :Ein kleiner, eng zusammengedrängter Vergnügungspark, bei dem eine Erweiterung in großem Ausmaß erforderlich ist. + + +STR_SCNR :White Water Park +STR_PARK :White Water Park +STR_DTLS :Dieser Park mit verschiedenen hervorragenden Wasser-Attraktionen hat einen Ausbau nötig. + + +STR_SCNR :Millennium Mines +STR_PARK :Millennium Mines +STR_DTLS :Machen Sie einen Freizeitpark aus dieser weitläufigen, verlassenen Mine, die zur Zeit nur von Touristen besichtigt wird. + + +STR_SCNR :Karts & Coasters +STR_PARK :Karts & Coasters +STR_DTLS :Ein großer Park, versteckt im Wald gelegen, der nur Gokartbahnen und Holzachterbahnen aufzuweisen hat. + + +STR_SCNR :Mel's World +STR_PARK :Mel's World +STR_DTLS :Dieser Freizeitpark verfügt über ein paar ausgezeichnete moderne Attraktionen und jede Menge Platz für Erweiterungen. + + +STR_SCNR :Mystic Mountain +STR_PARK :Mystic Mountain +STR_DTLS :Bauen Sie in den bergigen Wäldern der Mystic Mountains einen neuen Freizeitpark. + + +STR_SCNR :Pacific Pyramids +STR_PARK :Pacific Pyramids +STR_DTLS :Verwandeln Sie die Touristenattraktion mit ägyptischen Ruinen in einen erfolgreichen Freizeitpark. + + +STR_SCNR :Crumbly Woods +STR_PARK :Crumbly Woods +STR_DTLS :Ein großer Park mit guten, aber ziemlich alten Attraktionen. Ersetzen Sie die alten Attraktionen oder fügen Sie neue hinzu, damit der Park mehr Leute anzieht. + + +STR_SCNR :Paradise Pier +STR_PARK :Paradise Pier +STR_DTLS :Verwandeln Sie die Anlegestelle dieser verschlafenen Stadt in einen wohlbekannten und gutgehenden Anziehungspunkt. + + +STR_SCNR :Lightning Peaks +STR_PARK :Lightning Peaks +STR_DTLS :Die herrlichen Berge von Lightning Peaks sind beliebt bei Wanderern und Leuten, die gern interessante Orte besichtigen. Nutzen Sie das zur Verfügung stehende Gelände, um jene Besucher anzulocken, die auf der Suche nach einem aufregenden Kick sind. + + +STR_SCNR :Ivory Towers +STR_PARK :Ivory Towers +STR_DTLS :Ein gut geführter Park, der jedoch ein paar Probleme hat. + + +STR_SCNR :Rainbow Valley +STR_PARK :Rainbow Valley +STR_DTLS :Die örtlichen Behörden von Rainbow Valley werden landschaftliche Veränderungen oder größere Baumrodungen nicht erlauben, aber Sie sollen in dem Gebiet einen großen Freizeitpark entstehen lassen. + + +STR_SCNR :Thunder Rock +STR_PARK :Thunder Rock +STR_DTLS :Thunder Rock befindet sich mitten in einer Wüste und zieht viele Touristen an. Bauen Sie auf dem verfügbaren Platz Attraktionen, die noch mehr Leute herlocken. + + +STR_SCNR :Mega Park +STR_PARK :Mega Park +STR_DTLS :Nur zum Spaß! + +## Added Attractions + +STR_SCNR :Whispering Cliffs +STR_PARK :Whispering Cliffs +STR_DTLS :Lassen Sie in diesen Klippen am Meer einen florierenden Vergnügungspark entstehen. + + +STR_SCNR :Three Monkeys Park +STR_PARK :Three Monkeys Park +STR_DTLS :Mitten in diesem großen, aufstrebenden Park steht eine riesige Dreispur-Achterbahn, in der die Fahrt wie ein Kopf-an-Kopf-Rennen abläuft. + + +STR_SCNR :Canary Mines +STR_PARK :Canary Mines +STR_DTLS :Dieses verlassene Bergwerk bietet mit der Miniatureisenbahn und den Sturzachterbahnen bereits gute Voraussetzungen, eine Touristenattraktion zu werden. + + +STR_SCNR :Barony Bridge +STR_PARK :Barony Bridge +STR_DTLS :Wandeln Sie eine alte, nicht mehr benutzte Brücke in einen attraktiven Park um. + + +STR_SCNR :Funtopia +STR_PARK :Funtopia +STR_DTLS :In diesem Park zu beiden Seiten einer Autobahn sind bereits verschiedene Attraktionen in Betrieb. + + +STR_SCNR :Haunted Harbor +STR_PARK :Haunted Harbor +STR_DTLS :Die örtlichen Behörden haben zugestimmt, dem kleinen Park an der Küste umliegendes Gelände günstig zu verkaufen, unter der Bedingung, dass bestimmte Attraktionen erhalten werden. + + +STR_SCNR :Fun Fortress +STR_PARK :Fun Fortress +STR_DTLS :Sie können Ihrer Fantasie freien Lauf lassen, damit ein Themenpark aus diesem Schloss entsteht. + + +STR_SCNR :Future World +STR_PARK :Future World +STR_DTLS :Dieser futuristische Park bietet auf seinem fremdartigen Gelände viel Platz für neue Attraktionen. + + +STR_SCNR :Gentle Glen +STR_PARK :Gentle Glen +STR_DTLS :Die Bevölkerung in der Umgebung bevorzugt gemäßigte Attraktionen, auf denen man sich erholen kann. Ihre Aufgabe ist es, diesen Ansprüchen gerecht zu werden. + + +STR_SCNR :Jolly Jungle +STR_PARK :Jolly Jungle +STR_DTLS :Ein riesiges Gelände tief im Dschungel wartet darauf, von Ihnen in einen Themenpark umgewandelt zu werden. + + +STR_SCNR :Hydro Hills +STR_PARK :Hydro Hills +STR_DTLS :Eine Reihe terrassenförmig angeordneter Seen sind der Ausgangsort für den neuen Park. + + +STR_SCNR :Sprightly Park +STR_PARK :Sprightly Park +STR_DTLS :Dieser ältere Park besitzt viele historisch interessante Attraktionen, ist aber hoch verschuldet. + + +STR_SCNR :Magic Quarters +STR_PARK :Magic Quarters +STR_DTLS :Ein großes Gelände wurde freigeräumt und teilweise thematisch gestaltet. Sie sollen daraus einen interessante Themenlandschaft machen. + + +STR_SCNR :Fruit Farm +STR_PARK :Fruit Farm +STR_DTLS :Eine gutgehende Obstplantage hat eine Miniatureisenbahn bauen lassen, um die Einnahmen zu steigern. Entwickeln Sie jetzt daraus einen Vergnügungspark mit allem Drum und Dran. + + +STR_SCNR :Butterfly Dam +STR_PARK :Butterfly Dam +STR_DTLS :Das Gebiet rings um einen Damm steht Ihnen zur Verfügung, damit daraus ein Vergnügungspark entsteht. + + +STR_SCNR :Coaster Canyon +STR_PARK :Coaster Canyon +STR_DTLS :Ein weitläufiger Canyon steht Ihnen zur Verfügung, um in einen Themenpark verwandelt zu werden. + + +STR_SCNR :Thunderstorm Park +STR_PARK :Thunderstorm Park +STR_DTLS :Das Wetter in dieser Gegend ist so feucht, dass bereits eine riesengroße Pyramide gebaut wurde, damit wenigstens einige Attraktionen überdacht sind. + + +STR_SCNR :Harmonic Hills +STR_PARK :Harmonic Hills +STR_DTLS :Die Baubehörde dieser Gegend erlaubt in diesem Park keine Konstruktionen über Baumhöhe. + + +STR_SCNR :Roman Village +STR_PARK :Roman Village +STR_DTLS :Entwickeln Sie diesen römisch gestalteten Park weiter, indem Sie Achterbahnen und andere Attraktionen hinzufügen. + + +STR_SCNR :Swamp Cove +STR_PARK :Swamp Cove +STR_DTLS :Dieser Park, der sich über eine Reihe kleiner Inseln erstreckt, besitzt ein Paar einer großen Achterbahn als Hauptattraktion. + + +STR_SCNR :Adrenaline Heights +STR_PARK :Adrenaline Heights +STR_DTLS :Bauen Sie einen Park für die Menschen dieser Gegend, die hohe Intensität und Nervenkitzel bevorzugen. + + +STR_SCNR :Utopia Park +STR_PARK :Utopia Park +STR_DTLS :Eine Oase inmitten der Wüste ist sicher eine ungewöhnliche Herausforderung für Planer eines Vergnügungsparks. + + +STR_SCNR :Rotting Heights +STR_PARK :Rotting Heights +STR_DTLS :Überwuchert und verfallen. Können Sie diesen einst großartigen Vergnügungspark wieder zum Leben erwecken? + + +STR_SCNR :Fiasco Forest +STR_PARK :Fiasco Forest +STR_DTLS :Hier gibt es fast nur gefährliche und schlecht geplante Attraktionen. Sie haben nur sehr begrenzte finanzielle Mittel und wenig Zeit, die Probleme zu beheben und den Park umzukrempeln. + + +STR_SCNR :Pickle Park +STR_PARK :Pickle Park +STR_DTLS :Die strengen örtlichen Ämter erlauben keinerlei Werbung oder Propaganda. Dieser Park kann also nur durch seinen Ruf zum Erfolg gelangen. + + +STR_SCNR :Giggle Downs +STR_PARK :Giggle Downs +STR_DTLS :Eine vierspurige Bahn mit Renncharakter ist das Herzstück dieses aufstrebenden Parks. + + +STR_SCNR :Mineral Park +STR_PARK :Mineral Park +STR_DTLS :Verwandeln Sie diesen verlassenen Steinbruch in einen Ort, der Touristen anzieht, die den besonderen Kick suchen. + + +STR_SCNR :Coaster Crazy +STR_PARK :Coaster Crazy +STR_DTLS :Sie haben nur begrenzt Geld, aber jede Menge Zeit, aus diesem Berggelände einen riesigen Achterbahn-Park zu machen. + + +STR_SCNR :Urban Park +STR_PARK :Urban Park +STR_DTLS :Ein winzig kleiner Park hat mit der nahe gelegenen Stadt vereinbart, dass er sich durch die Stadt hindurch ausbreiten darf. + + +STR_SCNR :Geoffrey Gardens +STR_PARK :Geoffrey Gardens +STR_DTLS :Eine große gepflegte Parkanlage soll in einen erfolgreichen Themenpark umgestaltet werden. + + +## Loopy Landscapes + +STR_SCNR :Iceberg Islands +STR_PARK :Iceberg Islands +STR_DTLS :Eine Anzahl Eisberge bilden die kalte Umgebung dieses anspruchsvollen Parkprojekts. + + +STR_SCNR :Volcania +STR_PARK :Volcania +STR_DTLS :Ein untätiger Vulkan fordert geradezu heraus, an ihm eine Achterbahnanlage zu bauen. + + +STR_SCNR :Arid Heights +STR_PARK :Arid Heights +STR_DTLS :Ohne jegliche finanzielle Einschränkungen sollen Sie diesen Wüstenpark ausbauen und dabei die Besucher bei Laune halten. + + +STR_SCNR :Razor Rocks +STR_PARK :Razor Rocks +STR_DTLS :Ihre Aufgabe ist es, zwischen den zerklüfteten Felsen einen Park mit dicht gedrängten Achterbahnen zu bauen. + + +STR_SCNR :Crater Lake +STR_PARK :Crater Lake +STR_DTLS :Ein großer See in einem alten Krater ist Ausgangspunkt für diesen Park. + + +STR_SCNR :Vertigo Views +STR_PARK :Vertigo Views +STR_DTLS :Dieser große Park besitzt bereits eine ausgezeichnete Hyper-Achterbahn, aber Ihre Aufgabe ist es, die Erträge beträchtlich zu steigern. + + +STR_SCNR :Paradise Pier 2 +STR_PARK :Paradise Pier 2 +STR_DTLS :Paradise Pier hat sein Netz von Spazierwegen über dem Meer erweitert. Sie sollen den Park erweitern, indem Sie den neu gewonnenen Platz nutzen. + + +STR_SCNR :Dragon's Cove +STR_PARK :Dragon's Cove +STR_DTLS :Eine Meeresbucht ist der Rahmen für dieses anspruchsvolle Achterbahn-Bauvorhaben. + + +STR_SCNR :Good Knight Park +STR_PARK :Good Knight Park +STR_DTLS :Ein Schloss mit ein paar Achterbahnen soll zu einem großen Vergnügungspark entwickelt werden. + + +STR_SCNR :Wacky Warren +STR_PARK :Wacky Warren +STR_DTLS :Ein Park, dessen Gehwege und Achterbahnen größtenteils unterirdisch angelegt sind. + + +STR_SCNR :Grand Glacier +STR_PARK :Grand Glacier +STR_DTLS :Es steht Ihnen ein Gletschertal zur Verfügung, das in einen Vergnügungspark zu verwandeln ist. + + +STR_SCNR :Crazy Craters +STR_PARK :Crazy Craters +STR_DTLS :In einer weit entfernten Welt, wo man Geld nicht braucht, sollen Sie ein Unterhaltungszentrum bauen, damit die Leute glücklich und zufrieden bleiben. + + +STR_SCNR :Dusty Desert +STR_PARK :Dusty Desert +STR_DTLS :Fünf Achterbahnen müssen in diesem Wüstenpark fertiggestellt werden. + + +STR_SCNR :Woodworm Park +STR_PARK :Woodworm Park +STR_DTLS :In diesem historischen Park dürfen nur Attraktionen im altmodischen Stil gebaut werden. + + +STR_SCNR :Icarus Park +STR_PARK :Icarus Park +STR_DTLS :Verbessern Sie diesen außerirdischen Park, damit höchste Erträge erzielt werden. + + +STR_SCNR :Sunny Swamps +STR_PARK :Sunny Swamps +STR_DTLS :In diesem nach Themen angelegten Park gibt es zwar verschiedene Attraktionen, aber noch viel Platz für Erweiterungen. + + +STR_SCNR :Frightmare Hills +STR_PARK :Frightmare Hills +STR_DTLS :Ein Gruselpark mit einer Riesenachterbahn als Herzstück. + + +STR_SCNR :Thunder Rocks +STR_PARK :Thunder Rocks +STR_DTLS :Zwei enorme Gesteinsbrocken ragen aus dem Wüstensand, auf denen mit den ersten Bauten für einen Vergnügungspark bereits begonnen wurde. + + +STR_SCNR :Octagon Park +STR_PARK :Octagon Park +STR_DTLS :In diesem weitläufigen Park sollen Sie zehn große Achterbahnen entwerfen und konstruieren. + + +STR_SCNR :Pleasure Island +STR_PARK :Pleasure Island +STR_DTLS :Diese lange, schmale Insel ist Anreiz genug, eine Auswahl an Achterbahnen zu errichten. + + +STR_SCNR :Icicle Worlds +STR_PARK :Icicle Worlds +STR_DTLS :Eine Eislandschaft soll in einen florierenden Vergnügungspark verwandelt werden. + + +STR_SCNR :Southern Sands +STR_PARK :Southern Sands +STR_DTLS :Ein Park in der Wüste mit ein paar durchdachten Achterbahnen steht Ihnen zur Verfügung und soll erweitert werden. + + +STR_SCNR :Tiny Towers +STR_PARK :Tiny Towers +STR_DTLS :In diesem winzigen Park sollten Sie die fünf angefangenen Achterbahnen fertigstellen. + + +STR_SCNR :Nevermore Park +STR_PARK :Nevermore Park +STR_DTLS :Ein großer Park mit einem neuartigen Transportsystem, das durch die Randbereiche führt. + + +STR_SCNR :Pacifica +STR_PARK :Pacifica +STR_DTLS :Diese große Insel steht zu Ihrer Verfügung, machen Sie einen Vergnügungspark daraus. + + +STR_SCNR :Urban Jungle +STR_PARK :Urban Jungle +STR_DTLS :Ein gigantischer, verlassener Wolkenkratzer ist eine einmalige Gelegenheit für einen Vergnügungsparkbetreiber. + + +STR_SCNR :Terror Town +STR_PARK :Terror Town +STR_DTLS :Aus diesem Stadtgebiet können Sie einen Vergnügungspark zaubern. + + +STR_SCNR :Megaworld Park +STR_PARK :Megaworld Park +STR_DTLS :Ein ausgedehnter Park, der bereits mit Attraktionen vollgepackt ist, bedarf der Verbesserung. + + +STR_SCNR :Venus Ponds +STR_PARK :Venus Ponds +STR_DTLS :Auf einem weit entfernten Planeten soll dieses Stück Land in einen Vergnügungspark umgewandelt werden. + + +STR_SCNR :Micro Park +STR_PARK :Micro Park +STR_DTLS :Versuchen Sie, den kleinsten Park der Welt anzulegen und dabei möglichst viel Gewinn zu erzielen. + +## Real Parks from RCT1 +# None of them had details + +STR_SCNR :Alton Towers +STR_PARK :Alton Towers +STR_DTLS : + + +STR_SCNR :Heide-Park +STR_PARK :Heide-Park +STR_DTLS : + + +STR_SCNR :Blackpool Pleasure Beach +STR_PARK :Blackpool Pleasure Beach +STR_DTLS : + +## Misc parks from RCT1 +# Had no details + +STR_SCNR :Fort Anachronism +STR_PARK :Fort Anachronism +STR_DTLS : ####################### # Bahnen/Attraktionen # diff --git a/data/language/japanese.txt b/data/language/japanese.txt index dacfabf07d..7aed535d54 100644 --- a/data/language/japanese.txt +++ b/data/language/japanese.txt @@ -604,172 +604,172 @@ STR_0599 :A compact roller coaster with individual cars and smooth twisting d 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_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 :Mechanic {INT32} STR_0770 :Security Guard {INT32} STR_0771 :Entertainer {INT32} @@ -779,7 +779,7 @@ 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_0778 :バナー STR_0779 :1日 STR_0780 :2日 STR_0781 :3日 @@ -829,12 +829,12 @@ 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_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}Disk and game options STR_0835 :Game initialisation failed STR_0836 :Unable to start game in a minimised state @@ -884,16 +884,16 @@ STR_0878 :高すぎる! 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_0882 :ゲームを再更新する +STR_0883 :ゲームをセーブする +STR_0884 :景色を再更新する +STR_0885 :景色をセーブする +STR_0886 :ゲームを閉じる +STR_0887 :Scenario Editorを閉じる +STR_0888 :Roller Coaster Designerを閉じる +STR_0889 :Track Designs Managerを閉じる STR_0890 :SCR{COMMA16}.BMP -STR_0891 :Screenshot +STR_0891 :スクリーンショット STR_0892 :Screenshot saved to disk as '{STRINGID}' STR_0893 :Screenshot failed ! STR_0894 :Landscape data area full ! @@ -952,9 +952,9 @@ 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_0950 :ゲームを再更新する +STR_0951 :ゲームを閉じる +STR_0952 :ゲームを閉じる STR_0953 :Load Landscape STR_0954 : STR_0955 :{SMALLFONT}{BLACK}Select seat rotation angle for this track section @@ -974,7 +974,7 @@ STR_0968 :+360{DEGREE} STR_0969 :+405{DEGREE} STR_0970 :+450{DEGREE} STR_0971 :+495{DEGREE} -STR_0972 :Cancel +STR_0972 :キャンセル STR_0973 :OK STR_0974 :Rides STR_0975 :Shops and Stalls @@ -1112,11 +1112,11 @@ STR_1106 :Crashing! STR_1107 :Crashed! STR_1108 :Travelling at {VELOCITY} STR_1109 :Swinging -STR_1110 :Rotating -STR_1111 :Rotating +STR_1110 :回転させる +STR_1111 :回転させる STR_1112 :Operating STR_1113 :Showing film -STR_1114 :Rotating +STR_1114 :回転させる STR_1115 :Operating STR_1116 :Operating STR_1117 :Doing circus show @@ -1170,7 +1170,7 @@ 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_1168 :設定 STR_1169 :(None) STR_1170 :{STRING} STR_1171 :{RED}Closed - - @@ -1465,7 +1465,7 @@ STR_1459 :Track style STR_1460 :{SMALLFONT}{BLACK}'U' shaped open track STR_1461 :{SMALLFONT}{BLACK}'O' shaped enclosed track STR_1462 :Too steep for lift hill -STR_1463 :Guests +STR_1463 :来客 STR_1464 :Helix up (small) STR_1465 :Helix up (large) STR_1466 :Helix down (small) @@ -1695,14 +1695,14 @@ STR_1689 :Block brakes STR_1690 :{WINDOW_COLOUR_2}{STRINGID}{NEWLINE}{BLACK}{STRINGID} STR_1691 :{WINDOW_COLOUR_2} Cost: {BLACK}{CURRENCY} STR_1692 :{WINDOW_COLOUR_2} Cost: {BLACK}from {CURRENCY} -STR_1693 :{SMALLFONT}{BLACK}Guests +STR_1693 :{SMALLFONT}{BLACK}来客 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_1700 :便利屋を雇います STR_1701 :Hire new Mechanic STR_1702 :Hire new Security Guard STR_1703 :Hire new Entertainer @@ -1756,8 +1756,8 @@ 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_1754 :{BLACK}{COMMA16} 来客 +STR_1755 :{BLACK}{COMMA16} 来客 STR_1756 :{WINDOW_COLOUR_2}Admission price: STR_1757 :{WINDOW_COLOUR_2}Reliability: {MOVE_X}{255}{BLACK}{COMMA16}% STR_1758 :{SMALLFONT}{BLACK}Build mode @@ -1848,9 +1848,9 @@ 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_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}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 @@ -1861,11 +1861,11 @@ 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_1859 :便利屋 STR_1860 :Mechanics STR_1861 :Security Guards STR_1862 :Entertainers -STR_1863 :Handyman +STR_1863 :便利屋 STR_1864 :Mechanic STR_1865 :Security Guard STR_1866 :Entertainer @@ -1880,15 +1880,15 @@ 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_1878 :{WINDOW_COLOUR_2}改めるの: +STR_1879 :毎10分 +STR_1880 :毎20分 +STR_1881 :毎30分 +STR_1882 :毎45分 +STR_1883 :毎1時間 +STR_1884 :毎2時間 +STR_1885 :改めない +STR_1886 :{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}% @@ -2025,24 +2025,24 @@ 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_2021 :ドリンク +STR_2022 :バーガー +STR_2023 :フライ +STR_2024 :ソフトクリーム +STR_2025 :綿菓子 +STR_2026 :空き缶 +STR_2027 :ごみ STR_2028 :Empty Burger Boxes -STR_2029 :Pizzas +STR_2029 :ピザ STR_2030 :Vouchers -STR_2031 :Popcorn -STR_2032 :Hot Dogs +STR_2031 :ポップコーン +STR_2032 :ホットドッグ STR_2033 :Tentacles -STR_2034 :Hats +STR_2034 :帽子 STR_2035 :Toffee Apples -STR_2036 :T-Shirts -STR_2037 :Doughnuts -STR_2038 :Coffees +STR_2036 :ティーシャツ +STR_2037 :ドーナツ +STR_2038 :コーヒー STR_2039 :Empty Cups STR_2040 :Fried Chicken STR_2041 :Lemonade @@ -2331,13 +2331,13 @@ 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_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) @@ -2345,7 +2345,7 @@ STR_2337 :ドイツマルク (DM) STR_2338 :円 ({YEN}) STR_2339 :ペセタ (Pts) STR_2340 :リラ (L) -STR_2341 :Guilders (fl.) +STR_2341 :フローリン (fl.) STR_2342 :クローナ (kr) STR_2343 :ユーロ ({EURO}) STR_2344 :Imperial @@ -2440,7 +2440,7 @@ 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_2436 :1週間 STR_2437 : STR_2438 : STR_2439 : @@ -2727,26 +2727,26 @@ STR_2718 :Up STR_2719 :New file STR_2720 :{UINT16}秒 STR_2721 :{UINT16}秒 -STR_2722 :{UINT16}分:{UINT16}sec -STR_2723 :{UINT16}分:{UINT16}secs -STR_2724 :{UINT16}分:{UINT16}sec -STR_2725 :{UINT16}分:{UINT16}secs +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}min -STR_2729 :{UINT16}時間:{UINT16}mins -STR_2730 :{UINT16}時間:{UINT16}min -STR_2731 :{UINT16}時間:{UINT16}mins +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 :{MONTH}, 第{COMMA16}年 -STR_2737 :{STRINGID} {MONTH}, 第{COMMA16}年 +STR_2736 :{MONTH}月 {COMMA16}年 +STR_2737 :{STRINGID} {MONTH}月 {COMMA16}年 STR_2738 :Title screen music: STR_2739 :None -STR_2740 :ローラーコースター タイクーン 1 -STR_2741 :ローラーコースター タイクーン 2 +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 :[ @@ -2782,7 +2782,7 @@ STR_2772 :Faster Gamespeed STR_2773 :Windowed STR_2774 :Fullscreen STR_2775 :Fullscreen (desktop) -STR_2776 :Language: +STR_2776 :言語: STR_2777 :{MOVE_X}{SMALLFONT}{STRING} STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING} STR_2779 :Viewport #{COMMA16} @@ -2998,7 +2998,7 @@ 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_2991 :バナー STR_2992 :Sign text STR_2993 :Enter new text for this sign: STR_2994 :{SMALLFONT}{BLACK}Change text on sign @@ -3138,7 +3138,7 @@ 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_3131 :キャンセル 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) @@ -3449,11 +3449,11 @@ STR_3436 :{SMALLFONT}{BLACK}While waiting for our first riders, we could cust 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_3440 :1ページ目 +STR_3441 :2ページ目 +STR_3442 :3ページ目 +STR_3443 :4ページ目 +STR_3444 :5ページ目 STR_3445 :Set Patrol Area STR_3446 :Cancel Patrol Area @@ -3498,10 +3498,10 @@ 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 :{POP16}{MONTH} {PUSH16}{PUSH16}{STRINGID}, Year {POP16}{COMMA16} +STR_5160 :{POP16}{MONTH} {PUSH16}{PUSH16}{STRINGID} {POP16}{COMMA16}年 STR_5161 :Date Format: -STR_5162 :Day/Month/Year -STR_5163 :Month/Day/Year +STR_5162 :日月年 +STR_5163 :月日年 STR_5164 :Twitch Channel name STR_5165 :Name peeps after followers STR_5166 :{SMALLFONT}{BLACK}Will name peeps after channel's Twitch followers @@ -3634,8 +3634,8 @@ 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_5296 :{SMALLFONT}{BLACK}遊園地を閉める +STR_5297 :{SMALLFONT}{BLACK}遊園地を開ける STR_5298 :{RED}{STRINGID} STR_5299 :{LIGHTPINK}{STRINGID} STR_5300 :{SMALLFONT}{BLACK}Quick fire staff @@ -3643,10 +3643,10 @@ STR_5301 :{MEDIUMFONT}{BLACK}Clear your loan STR_5302 :Clear loan STR_5303 :Allow building in pause mode STR_5304 :Title Sequence: -STR_5305 :ローラーコースター タイクーン 1 -STR_5306 :ローラーコースター タイクーン 1 (AA) -STR_5307 :ローラーコースター タイクーン 1 (AA + 遊園地再生計画) -STR_5308 :ローラーコースター タイクーン 2 +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 :ランダム STR_5311 :{SMALLFONT}{BLACK}デバグツール @@ -3819,7 +3819,7 @@ STR_5477 :Map rendering STR_5478 :Controls STR_5479 :Toolbar STR_5480 :Show toolbar buttons for: -STR_5481 :Themes +STR_5481 :スタイル STR_5482 :{WINDOW_COLOUR_2}Time since last inspection: {BLACK}1 minute STR_5483 :{BLACK}({COMMA16} weeks remaining) STR_5484 :{BLACK}({COMMA16} week remaining) @@ -3850,7 +3850,7 @@ 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_5512 :名前を保存 STR_5513 :(Quick) save game STR_5514 :Disable vandalism STR_5515 :{SMALLFONT}{BLACK}Stops guests from vandalising your park when they're angry @@ -3888,9 +3888,9 @@ STR_5546 :{SMALLFONT}{BLACK}Bright pink STR_5547 :{SMALLFONT}{BLACK}Light pink STR_5548 :Show all operating modes STR_5549 :年月日 -STR_5550 :{POP16}{POP16}第{COMMA16}年, {PUSH16}{PUSH16}{MONTH} {PUSH16}{PUSH16}{STRINGID} -STR_5551 :Year/Day/Month -STR_5552 :{POP16}{POP16}第{COMMA16}年, {PUSH16}{PUSH16}{PUSH16}{STRINGID} {MONTH} +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 :Pause game when Steam overlay is open STR_5554 :{SMALLFONT}{BLACK}Enable mountain tool STR_5555 :Show vehicles from other track types diff --git a/data/language/korean.txt b/data/language/korean.txt index 4a2dfc67dd..0baa603c90 100644 --- a/data/language/korean.txt +++ b/data/language/korean.txt @@ -8,7 +8,7 @@ STR_0003 :스탠드업 롤러코스터 STR_0004 :서스펜디드 스윙잉 코스터 STR_0005 :인버티드 롤러코스터 STR_0006 :주니어 롤러코스터 -STR_0007 :미니어처 레일웨이 +STR_0007 :모형 기차 STR_0008 :모노레일 STR_0009 :미니 서스펜디드 롤러코스터 STR_0010 :보트 라이드 @@ -45,9 +45,9 @@ STR_0040 :모션 시뮬레이터 STR_0041 :3D 영화관 STR_0042 :톱 스핀 STR_0043 :스페이스 링 -STR_0044 :리버스 프리폴 코스터 +STR_0044 :역방향 자유낙하 코스터 STR_0045 :리프트 -STR_0046 :버티컬 드롭 롤러코스터 +STR_0046 :수직 낙하 롤러코스터 STR_0047 :현금 지급기 STR_0048 :트위스트 STR_0049 :귀신의 집 @@ -93,7 +93,7 @@ STR_0088 :인버티트 임펄스 코스터 STR_0089 :미니 롤러코스터 STR_0090 :마인 라이드 STR_0091 :알 수 없는 놀이기구 (59) -STR_0092 :LIM 런치드 롤러코스터 +STR_0092 :LIM 발진 롤러코스터 STR_0093 : STR_0094 : STR_0095 : @@ -518,7 +518,7 @@ STR_0513 :손님들이 일어선 자세로 탑승하는 루핑 롤러코스 STR_0514 :코너를 돌 때 롤러코스터 트랙 아래에 달린 차량이 흔들리는 열차입니다. STR_0515 :복잡하고 꼬인 트랙 요소를 가진 트랙 아래를 달리는 스틸 롤러코스터 차량입니다. STR_0516 :큰 놀이기구를 탈 용기가 없는 사람들을 위한 얌전한 롤러코스터입니다. -STR_0517 :손님들이 협궤 선로를 따라 달리는 미니어처 열차에 탑승하는 놀이기구입니다. +STR_0517 :손님들이 협궤 선로를 따라 달리는 모형 열차에 탑승하는 놀이기구입니다. STR_0518 :손님들이 모노레일 트랙을 따라 달리는 전기 차량에 탑승하는 놀이기구입니다. STR_0519 :손님들이 단선 트랙 아래에 달려서 코너를 돌 때마다 좌우로 흔들리는 작은 차량에 탑승하는 놀이기구입니다. STR_0520 :손님들이 물 위를 다니는 배를 운전하거나 또는 저을 수 있는 선착장입니다. @@ -528,7 +528,7 @@ STR_0523 :정해진 트랙을 따라 천천히 움직이는 놀이기구입 STR_0524 :자유낙하 차량은 공기 압축 방식으로 높은 철제 탑을 향해 차량을 쏘아올려 자유낙하하는 차량입니다. STR_0525 :손님들이 반원형으로 휘어있고 꼬여있는 트랙을 따라 이동합니다. STR_0526 :손님들이 높은 곳으로 회전하면서 올라가는 관망대 캐빈에 탑승하는 놀이기구입니다. -STR_0527 :버티컬 루프를 사용할 수 있는 부드러운 철제 트랙의 롤러코스터입니다. +STR_0527 :수직 루프를 사용할 수 있는 부드러운 철제 트랙의 롤러코스터입니다. STR_0528 :손님들이 공기를 넣은 고무 보트를 타고 반원이나 원형의 튜브 트랙을 따라 이동하는 놀이기구입니다. STR_0529 :오래된 기차 선로처럼 보이게 만든 철제 트랙을 따라 움직이는 탄광 열차 테마를 한 롤러코스터 차량입니다. STR_0530 :철제 케이블에 달린 차량이 연속적으로 놀이기구의 한쪽 끝에서 다른쪽 끝을 왕복 운행합니다. @@ -588,7 +588,7 @@ STR_0583 : STR_0584 :탑승객이 스스로 페달을 밟아 이동해야 하는, 특별한 철제 모노레일 트랙 위를 이동하는 자전거입니다 STR_0585 :탑승객은 트랙 밑에 매달린 좌석 한 쌍에 앉아 루프와 트위스트를 급격히 통과합니다 STR_0586 :보트 모양의 차량이 꼬인 커브와 급강하가 가능한 롤러코스터 트랙을 달리며, 강 섹션의 물에서는 물보라를 일으키며 감속합니다 -STR_0587 :아주 짜릿한 공기 압축 방식으로 발진하여 차량이 수직 트랙을 향해 속력을 높인 뒤, 꼭대기에 다다르면 다시 수직으로 하강하며 다른 탑승장에 도착합니다 +STR_0587 :아주 짜릿한 공기 압축 방식으로 발진하여 차량이 수직 트랙을 향해 속력을 높인 뒤, 꼭대기에 다다르면 다시 수직으로 하강하며 다시 탑승장에 도착합니다 STR_0588 :개별적인 차량이 헤이펀 커브와 급강하를 포함한 지그재그 모양의 트랙 아래를 이동합니다 STR_0589 : STR_0590 :탑승객들은 잠수가 가능한 잠수함을 타고 수중 코스를 돕니다 @@ -933,8 +933,8 @@ STR_0927 :여기에 건설할 수 없습니다... STR_0928 :{SMALLFONT}{BLACK}경사를 오르기 위한 체인 리프트 STR_0929 :S자 트랙 (왼쪽) STR_0930 :S자 트랙 (오른쪽) -STR_0931 :버티컬 루프 (왼쪽) -STR_0932 :버티컬 루프 (오른쪽) +STR_0931 :수직 루프 (왼쪽) +STR_0932 :수직 루프 (오른쪽) STR_0933 :땅을 먼저 올리거나 내리세요 STR_0934 :놀이기구 입구가 있습니다 STR_0935 :놀이기구 출구가 있습니다 @@ -1004,14 +1004,14 @@ 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_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_1008 :{SMALLFONT}{BLACK}놀이기구/시설을 개장/폐장/테스트합니다 +STR_1009 :{SMALLFONT}{BLACK}모든 놀이기구/시설을 개장/폐장합니다 STR_1010 :{SMALLFONT}{BLACK}공원을 열거나 닫습니다 STR_1011 :모두 닫기 STR_1012 :모두 열기 @@ -1029,7 +1029,7 @@ STR_1023 :1대당 {POP16}{POP16}{POP16}{COMMA16}량의 차량 STR_1024 :1대당 {COMMA16}량의 차량 STR_1025 :1대당 {COMMA16}량의 차량 STR_1026 :탑승장이 너무 깁니다! -STR_1027 :{SMALLFONT}{BLACK}여기로 이동 +STR_1027 :{SMALLFONT}{BLACK}여기로 이동합니다 STR_1028 :지도 끝을 벗어납니다! STR_1029 :일부분만 수면 위로 나오도록 건설할 수 없습니다! STR_1030 :수중에만 건설할 수 있습니다! @@ -1212,13 +1212,13 @@ STR_1206 :{WINDOW_COLOUR_2}출발: STR_1207 :{WINDOW_COLOUR_2}다른 열차가 탑승장에 도착하면 열차를 출발시킴 STR_1208 :{WINDOW_COLOUR_2}다른 보트가 탑승장에 도착하면 보트를 출발시킴 STR_1209 :{SMALLFONT}{BLACK}출발하기 전에 승객을 기다릴지 여부를 선택하세요 -STR_1210 :{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_1213 :{SMALLFONT}{BLACK}출발하기 전에 반드시 기다릴 시간 +STR_1214 :{SMALLFONT}{BLACK}출발하기 전에 최대한 기다릴 시간 STR_1215 :{WINDOW_COLOUR_2}인접한 탑승장과 같이 출발시킴 -STR_1216 :{SMALLFONT}{BLACK}모든 인접한 탑승장과 차량을 동시에 출발시킬지 여부를 선택하세요 +STR_1216 :{SMALLFONT}{BLACK}체크하면 모든 인접한 탑승장의 차량을 동시에 출발시킵니다 STR_1217 :{COMMA16}초 STR_1218 :{BLACK}{SMALLUP} STR_1219 :{BLACK}{SMALLDOWN} @@ -1434,10 +1434,10 @@ STR_1428 :{WINDOW_COLOUR_2}입장료: STR_1429 :{POP16}{POP16}{POP16}{CURRENCY2DP} STR_1430 :무료 STR_1431 :걷는 중 -STR_1432 :{STRINGID}(으)로 향하는 중 -STR_1433 :{STRINGID}(에)서 대기 중 +STR_1432 :목적지 : {STRINGID} +STR_1433 :{STRINGID} 대기 중 STR_1434 :물에 빠짐 -STR_1435 :{STRINGID} 위에 +STR_1435 :{STRINGID} 탑승중 STR_1436 :{STRINGID} 안에 STR_1437 :{STRINGID}에 STR_1438 :앉음 @@ -1446,7 +1446,7 @@ STR_1440 :잔디 깎는 중 STR_1441 :보도 청소 중 STR_1442 :쓰레기통 비우는 중 STR_1443 :정원에 물을 주는 중 -STR_1444 :{STRINGID}(을)를 보는 중 +STR_1444 :{STRINGID} 구경 중 STR_1445 :{STRINGID}의 건설 장면을 보는 중 STR_1446 :풍경을 보는 중 STR_1447 :공원을 떠나는 중 @@ -1713,7 +1713,7 @@ STR_1707 :게임에 직원이 너무 많습니다 STR_1708 :{SMALLFONT}{BLACK}이 직원이 순찰할 영역을 지정합니다 STR_1709 :직원 해고 STR_1710 :예 -STR_1711 :{WINDOW_COLOUR_1}{STRINGID}(을)를 정말 해고하시겠습니까? +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}쓰레기통 비우기 @@ -1892,7 +1892,7 @@ 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_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. @@ -1944,12 +1944,12 @@ 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_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}선택한 종류의 직원을 새로 고용합니다 @@ -2214,15 +2214,15 @@ 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_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_2218 :{RED}{POP16}{POP16}{STRINGID}의 {PUSH16}{PUSH16}{PUSH16}{PUSH16}{PUSH16}{STRINGID}(이)가 {POP16}{POP16}{POP16}{STRINGID}으로 아직 돌아오지 않았습니다!{NEWLINE}놀이기구가 멈춰있거나 오도가도 못하고 있는지 확인하세요. STR_2219 :{RED}{COMMA16}명의 손님이 {STRINGID} 사고로 사망하였습니다! STR_2220 :{WINDOW_COLOUR_2}공원 등급: {BLACK}{COMMA16} STR_2221 :{SMALLFONT}{BLACK}공원 등급: {COMMA16} @@ -2300,15 +2300,15 @@ 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_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} 디자인 선택 @@ -2366,7 +2366,7 @@ STR_2358 :유닛 STR_2359 :실제 값 STR_2360 :{WINDOW_COLOUR_2}해상도: STR_2361 :땅 테두리를 부드럽게 -STR_2362 :{SMALLFONT}{BLACK}땅의 테두리를 부드럽게 보입니다 +STR_2362 :{SMALLFONT}{BLACK}땅의 테두리를 부드럽게 보이게 만듭니다 STR_2363 :땅에 격자선 보이기 STR_2364 :{SMALLFONT}{BLACK}땅에 격자선을 보여줍니다 STR_2365 :은행이 대출을 증가시키는 것을 거절했습니다! @@ -2481,7 +2481,7 @@ STR_2473 :{SMALLFONT}{BLACK}새 스릴있는 놀이기구를 개발합니다 STR_2474 :{SMALLFONT}{BLACK}새 물 놀이기구를 개발합니다 STR_2475 :{SMALLFONT}{BLACK}새 상점/매점을 개발합니다 STR_2476 :{SMALLFONT}{BLACK}새 풍경/테마를 개발합니다 -STR_2477 :{SMALLFONT}{BLACK}이 놀이기구/시설의 운영 모드를 선택합니다 +STR_2477 :{SMALLFONT}{BLACK}이 놀이기구/시설의 운영 모드 선택 STR_2478 :{SMALLFONT}{BLACK}시간에 따른 속력 그래프를 보여줍니다 STR_2479 :{SMALLFONT}{BLACK}시간에 따른 고도 그래프를 보여줍니다 STR_2480 :{SMALLFONT}{BLACK}시간에 따른 수직 가속도 그래프를 보여줍니다 @@ -2810,8 +2810,8 @@ 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_2803 :{SMALLFONT}{BLACK}이 손님들을 지도에 표시합니다 +STR_2804 :{SMALLFONT}{BLACK}이 직원들을 지도에 표시합니다 STR_2805 :{SMALLFONT}{BLACK}공원의 지도를 표시합니다 STR_2806 :{RED}손님들이 공원의 더러운 보도 청소 상태에 대해 불평하고 있습니다{NEWLINE}미화원을 더 고용하거나 미화원의 업무 효율성을 점검하세요 STR_2807 :{RED}손님들이 공원에 널린 쓰레기에 대해 불평하고 있습니다{NEWLINE}미화원을 더 고용하거나 미화원의 업무 효율성을 점검하세요 @@ -2898,7 +2898,7 @@ STR_2887 :{WINDOW_COLOUR_2}Brimble's Beat: (Allister Brimble) copyright {CO 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_2891 :{WINDOW_COLOUR_2}블록buster: (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 @@ -3465,7 +3465,7 @@ STR_5125 :모두 파괴 가능 STR_5126 :무작위 타이틀 음악 STR_5127 :{SMALLFONT}{BLACK}땅을 올리거나 내리지 않음 STR_5128 :선택 도구 크기 -STR_5129 :선택 도구 크기를 {COMMA16}에서 {COMMA16} 사이의 값으로 입력하세요 +STR_5129 :{COMMA16}에서 {COMMA16} 사이의 값을 입력하세요 STR_5130 :지도 크기 STR_5131 :지도 크기를 {COMMA16}에서 {COMMA16} 사이의 값으로 입력하세요 STR_5132 :모든 놀이기구 수리 @@ -3844,8 +3844,8 @@ STR_5504 :{SMALLFONT}{BLACK}멀티플레이 창을 엽니다 STR_5505 :서버에 접속할 수 없습니다 STR_5506 :손님이 격렬도를 무시하고 탐 STR_5507 :미화원이 기본적으로 잔디를 깎음 -STR_5508 :올바르지 않은 체크합을 가진 파일 불러오기 허용 -STR_5509 :{SMALLFONT}{BLACK}데모에서 저장한 시나리오나 손상된 저장 파일과 같이 올바르지 않은 체크합을 가진 시나리오나 저장 파일을 불러오는 것을 허용합니다. +STR_5508 :올바르지 않은 검사합을 가진 파일 불러오기 허용 +STR_5509 :{SMALLFONT}{BLACK}데모에서 저장한 시나리오나 손상된 저장 파일과 같이 올바르지 않은 검사합을 가진 시나리오나 저장 파일을 불러오는 것을 허용합니다. STR_5510 :기본 사운드 장치 STR_5511 :(알 수 없음) STR_5512 :다른 이름으로 저장 @@ -3943,14 +3943,481 @@ STR_5603 :손님의 놀이기구 하차 STR_5604 :손님의 물건 구입 STR_5605 :손님의 시설 사용 STR_5606 :손님의 사망 +STR_5607 :{SMALLFONT}{BLACK}선택한 맵 요소를 강제로 제거합니다. +STR_5608 :BH +STR_5609 :CH +STR_5610 :{SMALLFONT}{BLACK}현재 선택한 맵 요소를 제거합니다. 강제로 삭제하기 때문에 돈이 들어오거나 빠지진 않을 것입니다. 주의해서 사용하세요. +STR_5611 :G +STR_5612 :{SMALLFONT}{BLACK}유령 플래그 +STR_5613 :B +STR_5614 :{SMALLFONT}{BLACK}깨짐 플래그 +STR_5615 :L +STR_5616 :{SMALLFONT}{BLACK}타일 플래그의 마지막 요소 +STR_5617 :{SMALLFONT}{BLACK}선택한 요소를 위로 이동합니다. +STR_5618 :{SMALLFONT}{BLACK}선택한 요소를 아래로 이동합니다. +STR_5619 :롤러코스터 타이쿤 +STR_5620 :애디드 어트랙션 +STR_5621 :루피 랜드스케이프 +STR_5622 :롤러코스터 타이쿤 2 +STR_5623 :와키 월드 +STR_5624 :타임 트위스터 +STR_5625 :{OPENQUOTES}실제{ENDQUOTES} 공원 +STR_5626 :기타 공원 +STR_5627 :시나리오 목록 분류 방식: +STR_5628 :게임별 +STR_5629 :난이도별 +STR_5630 :시나리오 클리어시 새 시나리오 열기 켜기 +STR_5631 :오리지널 다운로드 콘텐츠 공원 +STR_5632 :직접 만들기... +############# +# Scenarios # +################ +# RCT Original # +################ + +STR_SCNR :Forest Frontiers +STR_PARK :미개척된 숲 +STR_DTLS :깊은 숲 속 넓은 공터에 번창한 놀이공원을 건설하세요. + + +STR_SCNR :Dynamite Dunes +STR_PARK :다이너마이트 모래언덕 +STR_DTLS :사막 한가운데 건설된 이 놀이공원에는 롤러코스터 한 대만이 있지만 확장할 수 있는 곳이 많습니다. + + +STR_SCNR :Leafy Lake +STR_PARK :나뭇잎 호수 +STR_DTLS :처음부터 시작하여 큰 호수 주변에 놀이공원을 건설하세요. + + +STR_SCNR :Diamond Heights +STR_PARK :다이아몬드 언덕 +STR_DTLS :다이아몬드 언덕은 멋진 놀이기구를 통해 이미 성공한 놀이공원입니다. 공원의 가치를 두 배로 늘려 보세요. + + +STR_SCNR :Evergreen Gardens +STR_PARK :상록수 정원 +STR_DTLS :아름다운 상록수 정원을 번창한 놀이공원으로 바꿔보세요. + + +STR_SCNR :Bumbly Beach +STR_PARK :범블리 해변 +STR_DTLS :범블리 해변의 작은 놀이공원을 번창한 놀이공원으로 발전시키세요. + + +STR_SCNR :Trinity Islands +STR_PARK :삼위일체 섬 +STR_DTLS :몇 개의 섬이 이 새로운 공원의 기반입니다. + + +STR_SCNR :Katie's Dreamland +STR_PARK :케이티의 드림랜드 +STR_DTLS :몇 개의 놀이기구와 확장할 공간이 있는 작은 놀이공원으로, 여러분의 목표는 공원 가치를 두 배로 늘리는 것입니다. + + +STR_SCNR :Pokey Park +STR_PARK :비좁은 공원 +STR_DTLS :대대적인 확장을 해야하는 비좁은 놀이공원 + + +STR_SCNR :White Water Park +STR_PARK :맑은 물 공원 +STR_DTLS :훌륭한 물 놀이기구를 몇 개 갖고있지만 확장이 필요한 공원 + + +STR_SCNR :Millennium Mines +STR_PARK :밀레니엄 광산 +STR_DTLS :버려져있는 커다란 탄광을 관광시설에서 놀이공원으로 바꿔보세요. + + +STR_SCNR :Karts & Coasters +STR_PARK :카트 & 코스터 +STR_DTLS :몇 개의 고 카트 트랙과 우든 롤러코스터만이 숲 속에 숨겨져 있는 대형 놀이공원 + + +STR_SCNR :Mel's World +STR_PARK :멜의 세계 +STR_DTLS :이 놀이공원에는 잘 디자인된 현대식 놀이기구가 있지만 아직도 확장해야 할 곳이 많습니다. + + +STR_SCNR :Mystic Mountain +STR_PARK :신비한 산 +STR_DTLS :비밀스런 숲 속 언덕에 처음부터 놀이공원을 건설하세요. + + +STR_SCNR :Pacific Pyramids +STR_PARK :평화로운 피라미드 +STR_DTLS :이집트 유적 관광지를 번창한 놀이공원으로 바꿔 보세요. + + +STR_SCNR :Crumbly Woods +STR_PARK :부서지기 쉬운 숲 +STR_DTLS :잘 디자인되었지만 다소 낡은 놀이기구를 가진 대형 공원입니다. 오래된 놀이기구를 교체하거나 새로운 놀이기구를 추가하여 보다 인기있는 공원을 만들어보세요. + + +STR_SCNR :Paradise Pier +STR_PARK :파라다이스 부두 +STR_DTLS :이 조용한 마을의 부두를 번창한 놀이공원으로 바꿔보세요. + + +STR_SCNR :Lightning Peaks +STR_PARK :번개치는 산꼭대기 +STR_DTLS :번개치는 산꼭대기의 아름다운 산은 경치를 즐기며 산책을 즐기는 사람들에게 인기가 높습니다. 사용 가능한 땅을 이용해서 스릴을 찾는 새로운 고객을 유혹해보세요. + + +STR_SCNR :Ivory Towers +STR_PARK :상아 탑 +STR_DTLS :문제가 몇 가지 있지만 잘 구성된 공원 + + +STR_SCNR :Rainbow Valley +STR_PARK :무지개 계곡 +STR_DTLS :무지개 계곡의 지역 당국은 풍경을 바꾸거나 큰 나무를 제거할 수 없게 했지만, 이 지역을 개발하여 대형 놀이공원으로 바꿔야만 합니다. + + +STR_SCNR :Thunder Rock +STR_PARK :천둥 바위 +STR_DTLS :천둥 바위는 사막 한가운데에서 많은 관광객을 끌어 모으고 있습니다. 사용 가능한 공간을 이용해 놀이기구를 건설해서 더 많은 사람들을 끌어 보세요. + + +STR_SCNR :Mega Park +STR_PARK :대공원 +STR_DTLS :그냥 즐기세요! + +## Added Attractions + +STR_SCNR :Whispering Cliffs +STR_PARK :속삭이는 절벽 +STR_DTLS :해변의 절벽을 인기있는 놀이공원으로 발전시키세요. + + +STR_SCNR :Three Monkeys Park +STR_PARK :세 원숭이 공원 +STR_DTLS :개발 중인 이 거대한 공원의 한 가운데에는 동시에 경주하는 거대한 세 쌍둥이 스틸 롤러코스터가 있습니다. + + +STR_SCNR :Canary Mines +STR_PARK :카나리아 광산 +STR_DTLS :이 버려진 탄광은 모형 기차와 수직 낙하 롤러코스터로 이미 관광객의 인기를 끌고 있습니다. + + +STR_SCNR :Barony Bridge +STR_PARK :남작의 다리 +STR_DTLS :필요없는 오래된 다리를 놀이공원으로 개발할 수 있습니다. + + +STR_SCNR :Funtopia +STR_PARK :펀토피아 +STR_DTLS :고속도로 양쪽을 잘 활용한 이 공원은 이미 몇 가지 놀이기구를 운영하고 있습니다. + + +STR_SCNR :Haunted Harbor +STR_PARK :유령 항구 +STR_DTLS :지역 당국은 특정 놀이기구는 파괴할 수 없다는 조건을 걸고 이 작은 해변 공원 근처의 땅을 저렴하게 팔기로 합의했습니다. + + +STR_SCNR :Fun Fortress +STR_PARK :즐거운 요새 +STR_DTLS :이 성은 놀이공원으로 탈바꿈하기 위해 온전히 당신의 소유가 되었습니다. + + +STR_SCNR :Future World +STR_PARK :미래 세계 +STR_DTLS :이 미래지향적인 공원에는 새로운 놀이기구를 그 외계 지형 위에 지을 많은 공간이 있습니다. + + +STR_SCNR :Gentle Glen +STR_PARK :얌전한 골짜기 +STR_DTLS :이 지역의 주민들은 격렬하지 않고 얌전한 놀이기구를 선호하기 때문에 이 공원을 그들의 취향에 맞게 확장하는 것이 여러분의 임무입니다. + + +STR_SCNR :Jolly Jungle +STR_PARK :즐거운 정글 +STR_DTLS :정글 속 깊은 곳에 놀이공원으로 탈바꿈할 수 있는 넓은 대지가 있습니다. + + +STR_SCNR :Hydro Hills +STR_PARK :하이드로 언덕 +STR_DTLS :몇 개의 호수를 기반으로 새로운 공원을 건설할 수 있습니다. + + +STR_SCNR :Sprightly Park +STR_PARK :활기 넘치는 공원 +STR_DTLS :이 오래된 공원에는 아주 역사적인 놀이기구가 많이 있지만 심각한 적자에 시달리고 있습니다. + + +STR_SCNR :Magic Quarters +STR_PARK :매직 쿼터 +STR_DTLS :비어있는 넓은 지역의 일부분을 아름다운 풍경의 테마파크로 개발될 준비가 되었습니다. + + +STR_SCNR :Fruit Farm +STR_PARK :과일 농장 +STR_DTLS :무성한 과일 농장에 모형 기차를 건설해서 수익을 극대화하고 있습니다. 여러분의 임무는 이 농장을 최고의 놀이공원으로 만드는 것입니다. + + +STR_SCNR :Butterfly Dam +STR_PARK :나비 댐 +STR_DTLS :댐 주변 지역을 놀이공원으로 개발할 수 있습니다. + + +STR_SCNR :Coaster Canyon +STR_PARK 코스터 협곡 +STR_DTLS :광대한 협곡을 테마파크로 개발할 수 있습니다. + + +STR_SCNR :Thunderstorm Park +STR_PARK :폭풍우 공원 +STR_DTLS :날씨가 너무 습해서 거대한 피라미드를 짓고 몇몇 놀이기구를 그 밑에 두기로 했습니다. + + +STR_SCNR :Harmonic Hills +STR_PARK :조화로운 언덕 +STR_DTLS :지역 당국은 이 공원에서 나무 높이 이상의 건설을 허용하지 않습니다. + + +STR_SCNR :Roman Village +STR_PARK :로마의 마을 +STR_DTLS :이 로마 스타일의 테마파크에 놀이기구와 롤러코스터를 추가해서 더욱 발전시켜보세요. + + +STR_SCNR :Swamp Cove +STR_PARK :습지 골짜기 +STR_DTLS :몇 개의 작은 섬에 부분 부분 건설된 이 공원에는 이미 중앙에 한 쌍의 거대한 롤러코스터가 있습니다. + + +STR_SCNR :Adrenaline Heights +STR_PARK :아드레날린 언덕 +STR_DTLS :격렬한 스릴을 즐기는 사람들을 위한 공원을 건설하세요. + + +STR_SCNR :Utopia Park +STR_PARK :유토피아 공원 +STR_DTLS :사막 한가운데의 오아시스에 놀이공원을 건설해보세요. + + +STR_SCNR :Rotting Heights +STR_PARK :썩어버린 언덕 +STR_DTLS :지나치게 성장해서 황폐화되어버린 이 곳을 다시 멋진 공원으로 바꿀 수 있습니까? + + +STR_SCNR :Fiasco Forest +STR_PARK :실패한 숲 +STR_DTLS :위험하고 잘못 설계된 놀이기구가 많이 있습니다. 공원을 둘러보고 문제를 수정할 시간과 예산이 매우 부족합니다. + + +STR_SCNR :Pickle Park +STR_PARK :피클 공원 +STR_DTLS :지역 당국에서는 광고나 홍보를 허용하지 않으므로 이 공원은 사람들의 입을 통해서만 알릴 수 있습니다. + + +STR_SCNR :Giggle Downs +STR_PARK :웃기는 구릉 지대 +STR_DTLS :이 넓은 공원의 중앙에는 네 쌍둥이 스티플체이스 놀이기구가 있습니다. + + +STR_SCNR :Mineral Park +STR_PARK :광물 공원 +STR_DTLS :이 버려진 채석장을 스릴을 찾는 사람들을 유혹할만한 장소로 바꿔보세요. + + +STR_SCNR :Coaster Crazy +STR_PARK :미친 코스터 +STR_DTLS :이 산악 지대에 다양한 롤러코스터를 건설해보세요. 예산은 한정되어 있지만 시간은 제한이 없습니다. + + +STR_SCNR :Urban Park +STR_PARK :도시 공원 +STR_DTLS :이 작은 공원은 이 도시뿐만 아니라 근교 도시의 주민들에게까지 인기를 모으고 있습니다. + + +STR_SCNR :Geoffrey Gardens +STR_PARK :제프리의 정원 +STR_DTLS :대규모의 정원 공원을 북적이는 놀이공원으로 바꿔해야 합니다. + + +## Loopy Landscapes + +STR_SCNR :Iceberg Islands +STR_PARK :빙산 섬 +STR_DTLS :빙산이 이 야심찬 놀이공원에 차가운 이미지를 더하고 있습니다. + + +STR_SCNR :Volcania +STR_PARK :볼케이니아 +STR_DTLS :이번 롤러코스터 건설 도전에서는 휴화산이 무대가 됩니다. + + +STR_SCNR :Arid Heights +STR_PARK :건조한 언덕 +STR_DTLS :아무런 재정적 제한 없는 상황에서, 지속적으로 손님들을 행복하게 만들 수 있는 공원을 사막에 건설해보세요. + + +STR_SCNR :Razor Rocks +STR_PARK :날카로운 바위 +STR_DTLS :여러분의 임무는 날카로운 바위 사이에 롤러코스터로 가득한 거대한 공원을 만드는 것입니다. + + +STR_SCNR :Crater Lake +STR_PARK :분화구 호수 +STR_DTLS :이 공원의 부지는 고대 분화구에 만들어진긴 커다란 호수입니다. + + +STR_SCNR :Vertigo Views +STR_PARK :어지러운 풍경 +STR_DTLS :이 거대한 공원에는 이미 훌륭한 하이퍼코스터가 있습니다. 여러분의 임무는 그 매출을 아주 극대화시키는 것입니다. + + +STR_SCNR :Paradise Pier 2 +STR_PARK :파라다이스 부두 2 +STR_DTLS :파라다이스 부두는 바다 위의 산책로를 확장했습니다. 여러분의 임무는 이 새로운 공간을 이용하여 공원을 확장하는 것 입니다. + + +STR_SCNR :Dragon's Cove +STR_PARK :용의 동굴 +STR_DTLS :이번 롤러코스터 건설 도전에서는 해안 동굴이 무대가 됩니다. + + +STR_SCNR :Good Knight Park +STR_PARK :훌륭한 기사 공원 +STR_DTLS :한 쌍의 롤러코스터가 있는 성을 더 큰 놀이공원으로 발전시켜야 합니다. + + +STR_SCNR :Wacky Warren +STR_PARK :괴짜 미로 +STR_DTLS :대부분의 보도와 롤러코스터가 지하에 있는 공원입니다. + + +STR_SCNR :Grand Glacier +STR_PARK :웅장한 빙하 +STR_DTLS :놀이공원으로 만들기 위해 당신에게 빙하가 가득한 계곡이 주어졌습니다. + + +STR_SCNR :Crazy Craters +STR_PARK :미친 분화구 +STR_DTLS :돈이 필요없는 머나먼 세상에서, 여러분은 사람들을 행복하게 해줄 놀이공원을 건설해야 합니다. + + +STR_SCNR :Dusty Desert +STR_PARK :먼지투성이 사막 +STR_DTLS :이 사막 공원에 있는 다섯 대의 롤러코스터를 완성하십시오. + + +STR_SCNR :Woodworm Park +STR_PARK :나무좀벌레 공원 +STR_DTLS :이 역사적인 공원에는 오직 오래된 스타일의 놀이기구만을 건설할 수 있습니다. + + +STR_SCNR :Icarus Park +STR_PARK :이카루스 공원 +STR_DTLS :이 외계 공원을 개발하여 최대한의 매출을 올리세요. + + +STR_SCNR :Sunny Swamps +STR_PARK :맑은 늪지 +STR_DTLS :이 잘 구성된 놀이공원에는 이미 몇 개의 놀이기구가 있지만, 아직 확장할 수 있는 공간은 충분합니다. + + +STR_SCNR :Frightmare Hills +STR_PARK :무시무시한 언덕 +STR_DTLS :거대한 롤러코스터가 공원 가운데에 있는 무시무시한 공원 + + +STR_SCNR :Thunder Rocks +STR_PARK :천둥 바위들 +STR_DTLS :놀이공원의 기초가 될 두 개의 커다란 바위가 사막의 모래 위에 솟아 있습니다. + + +STR_SCNR :Octagon Park +STR_PARK :팔각형 공원 +STR_DTLS :이 거대한 공원에 여러분은 10개의 거대한 롤러코스터를 디자인하고 만들어야 합니다. + + +STR_SCNR :Pleasure Island +STR_PARK :즐거운 섬 +STR_DTLS :길고 가느다란 섬에서 롤러코스터 건설에 도전해보세요. + + +STR_SCNR :Icicle Worlds +STR_PARK :고드름 세상 +STR_DTLS :얼음으로 덮인 땅을 번창하는 놀이공원으로 바꿔보세요. + + +STR_SCNR :Southern Sands +STR_PARK :남부 사막 +STR_DTLS :빈틈없이 세워진 롤러코스터가 있는 사막 공원이 확장을 위해 여러분에게 주어졌습니다. + + +STR_SCNR :Tiny Towers +STR_PARK :조그마한 탑 +STR_DTLS :이 조그마한 공원에 있는 다섯 개의 미완성된 롤러코스터를 모두 완성해야 합니다. + + +STR_SCNR :Nevermore Park +STR_PARK :네버모어 공원 +STR_DTLS :공원 주변에 참신한 운송수단이 설치된 거대한 공원 + + +STR_SCNR :Pacifica +STR_PARK :패시피카 +STR_DTLS :놀이공원으로 개발하기 위해 이 거대한 섬이 여러분에게 주어졌습니다. + + +STR_SCNR :Urban Jungle +STR_PARK :도시의 정글 +STR_DTLS :버려진 거대한 마천루 빌딩은 놀이공원 개발자에게는 독특한 기회일 것입니다. + + +STR_SCNR :Terror Town +STR_PARK :공포스러운 마을 +STR_DTLS :놀이공원으로 개발하기 위해 이 도시 지역이 여러분에게 주어졌습니다. + + +STR_SCNR :Megaworld Park +STR_PARK :대세상 공원 +STR_DTLS :이미 놀이기구로 가득한 거대한 공원을 확장해야 합니다. + + +STR_SCNR :Venus Ponds +STR_PARK :비너스의 연못 +STR_DTLS :멀리 떨어진 행성에 있는 이 지역을 놀이공원으로 바꿔야 합니다. + + +STR_SCNR :Micro Park +STR_PARK :마이크로 공원 +STR_DTLS :세상에서 가장 작지만 수익이 좋은 공원을 만들어보세요. + +## Real Parks from RCT1 +# None of them had details + +STR_SCNR :Alton Towers +STR_PARK :알턴 타워스 +STR_DTLS : + + +STR_SCNR :Heide-Park +STR_PARK :하이데 파르크 +STR_DTLS : + + +STR_SCNR :Blackpool Pleasure Beach +STR_PARK :블랙풀 플레져 비치 +STR_DTLS : + +## Misc parks from RCT1 +# Had no details + +STR_SCNR :Fort Anachronism +STR_PARK :역사적인 성채 +STR_DTLS : ############################################################################### ## RCT2 Objects ############################################################################### [AML1] STR_NAME :미국 스타일 증기 기관차 -STR_DESC :부드러운 천으로 된 지붕을 가진 나무 객차와 증기 기관차 모형으로 이루어진 미니어처 증기 기관차 차량 +STR_DESC :부드러운 천으로 된 지붕을 가진 나무 객차와 증기 기관차 모형으로 이루어진 모형 증기 기관차 차량 STR_CPTY :차량당 6명의 승객 [CLIFT1] @@ -3985,12 +4452,12 @@ STR_CPTY :차량당 4명의 승객 [NRL] STR_NAME :증기 기관차 -STR_DESC :나무 객차와 증기 기관차 모형으로 이루어진 미니어처 증기 기관차 차량 +STR_DESC :나무 객차와 증기 기관차 모형으로 이루어진 모형 증기 기관차 차량 STR_CPTY :객차당 6명의 승객 [NRL2] STR_NAME :천장이 있는 증기 기관차 -STR_DESC :부드러운 천으로 된 지붕을 가진 나무 객차와 증기 기관차 모형으로 이루어진 미니어처 증기 기관차 차량 +STR_DESC :부드러운 천으로 된 지붕을 가진 나무 객차와 증기 기관차 모형으로 이루어진 모형 증기 기관차 차량 STR_CPTY :객차당 6명의 승객 [SMONO] @@ -4040,7 +4507,7 @@ STR_CPTY :승객 32명 [GOLF1] STR_NAME :미니 골프 -STR_DESC :미니어처 골프 게임 +STR_DESC :모형 골프 게임 STR_CPTY : [GTC] @@ -4070,7 +4537,7 @@ STR_CPTY :차량당 2명의 승객 [HSKELT] STR_NAME :나선 미끄럼틀 -STR_DESC :Wooden building with an internal staircase and an external spiral slide for use with slide mats +STR_DESC :내부의 계단을 타고 올라가서 외부의 나선형 미끄럼틀을 매트를 타고 내려오는 목재 건물 STR_CPTY : [MGR1] @@ -4080,8 +4547,8 @@ STR_CPTY :승객 16명 [MONBK] STR_NAME :모노레일 자전거 -STR_DESC :Special bicycles run on a steel monorail track, propelled by the pedalling of the riders -STR_CPTY :1 rider per bicycle +STR_DESC :탑승자가 직접 페달을 밟으면 강철 모노레일 트랙 위를 움직이는 특별한 자전거 +STR_CPTY :자전거 당 1명의 탑승객 [OBS1] STR_NAME :전망탑 @@ -4105,18 +4572,18 @@ STR_CPTY :차량당 2명의 승객 [SRINGS] STR_NAME :스페이스 링 -STR_DESC :Concentric pivoting rings allowing the riders free rotation in all directions +STR_DESC :동심원 모양의 고리가 탑승자를 어느 방향이든 회전시킬 수 있는 놀이기구 STR_CPTY :각 1명 [SUBMAR] STR_NAME :잠수함 -STR_DESC :Riders ride in a submerged submarine through an underwater course +STR_DESC :수면 아래 코스를 이동하는 잠수함에 탑승하는 놀이기구 STR_CPTY :잠수함당 4명의 승객 [TRUCK1] STR_NAME :소형 트럭 -STR_DESC :Powered vehicles in the shape of pickup trucks -STR_CPTY :승객 1명 per truck +STR_DESC :소형 트럭 모양의 차량 +STR_CPTY :트럭당 승객 1명 [VCR] STR_NAME :빈티지 차량 @@ -4125,32 +4592,32 @@ STR_CPTY :차량당 2명의 승객 [AMT1] STR_NAME :탄광 열차 코스터 -STR_DESC :Mine train themed roller coaster trains career along steel roller coaster track made to look like old railway track +STR_DESC :오래된 선로 트랙처럼 보이지만 튼튼한 강철로 만든 롤러코스터 트랙을 따라 달리는, 광산 차량을 테마로 한 롤러코스터 차량 STR_CPTY :차량당 2명 또는 4명의 승객 [ARRSW1] STR_NAME :서스펜디드 스윙잉 차량 -STR_DESC :Suspended roller coaster train consisting of cars able to swing freely as the train goes around corners +STR_DESC :차량이 코너를 돌면 자유롭게 흔들거리게 만들어진 서스펜디드 롤러코스터 차량 STR_CPTY :차량당 4명의 승객 [ARRSW2] STR_NAME :서스펜디드 스윙잉 에어로플레인 차량 -STR_DESC :Suspended roller coaster train consisting of aeroplane shaped cars able to swing freely as the train goes around corners +STR_DESC :차량이 코너를 돌면 자유롭게 흔들거리게 만들어진 비행기 모양의 서스펜디드 롤러코스터 차량 STR_CPTY :차량당 4명의 승객 [ARRT1] STR_NAME :코르크스크류 롤러코스터 -STR_DESC :A compact steel-tracked roller coaster where the train travels through corkscrews and loops +STR_DESC :코르크스크류와 루프를 도는 구성을 지닌 강철 트랙의 롤러코스터 STR_CPTY :차량당 4명의 승객 [ARRT2] STR_NAME :하이퍼코스터 -STR_DESC :A tall non-inverting roller coaster with large drops, high speed, and comfortable trains with only lap bar restraints +STR_DESC :무릎 안전바만 채운 채로, 뒤집어지지는 않지만 큰 낙하와 빠른 속도, 편안한 승차감을 자랑하는 롤러코스터 STR_CPTY :차량당 6명의 승객 [ARRX] STR_NAME :멀티 디멘션 코스터 차량 -STR_DESC :Cars with seats capable of pitching the riders head-over-heels +STR_DESC :탑승객의 머리와 발을 뒤집어버리는 등의 회전 좌석을 가진 차량 STR_CPTY :차량당 4명의 승객 [BATFL] @@ -4160,157 +4627,157 @@ STR_CPTY :차량당 2명의 승객 [BMAIR] STR_NAME :플라잉 롤러코스터 -STR_DESC :Riders are held in comfortable seats below the track, travelling through twisted track to give the ultimate flying experience +STR_DESC :탑승객에게 정말로 나는 듯한 경험을 주기 위해, 트랙 밑에 달린 편안한 좌석에 앉아서 꼬여있는 트랙을 따라 움직이는 놀이기구 STR_CPTY :차량당 4명의 승객 [BMFL] STR_NAME :플로어리스 롤러 코스터 -STR_DESC :Wide coaster trains with no floor give the passengers an open-air feeling as they glide through twisted track and multiple inversions +STR_DESC :꼬여있는 트랙과 여러 전이를 미끄러지듯 통과하면서 승객들에게 광활한 허공을 느끼게 해주는, 바닥이 없는 넓은 롤러코스터 차량 STR_CPTY :차량당 4명의 승객 [BMRB] STR_NAME :하이퍼 트위스터 차량 (광폭형) -STR_DESC :Wide 4-across cars with raised seating and simple lap restraints +STR_DESC :향상된 탑승감과 간단한 무릎 안전바를 갖고 있는 넓은 4인승 차량 STR_CPTY :차량당 4명의 승객 [BMSD] STR_NAME :트위스터 롤러코스터 -STR_DESC :Wide roller coaster trains glide along smooth steel track, traveling through a variety of inversions +STR_DESC :여러 종류의 루프를 돌면서 부드러운 강철 트랙을 달리는 넓은 롤러코스터 차량 STR_CPTY :차량당 4명의 승객 [BMSU] STR_NAME :스탠드 업 트위스터 코스터 -STR_DESC :Riders ride in a standing position in wide coaster trains with specially designed restraints as they race down smooth drops and through multiple inversions +STR_DESC :탑승자들이 선 자세로 낙하와 여러 특수 트랙을 즐길 수 있도록 특수하게 디자인된 안전바가 있는 넓은 롤러코스터 차량 STR_CPTY :차량당 4명의 승객 [BMVD] -STR_NAME :버티컬 드롭 롤러코스터 -STR_DESC :Extra-wide cars descend completely vertical sloped track for the ultimate freefall roller coaster experience +STR_NAME :수직 낙하 롤러코스터 +STR_DESC :자유 낙하의 극한 경험을 선사하기 위해 완전히 수직 경사 트랙을 따라 하강하는 아주 폭이 넓은 차량 STR_CPTY :차량당 6명의 승객 [BOB1] STR_NAME :봅슬레이 코스터 -STR_DESC :Riders career down a twisting track in bobsleigh-shaped cars guided only by the curvature and banking of the semi-circular track +STR_DESC :반원형 트랙의 커브와 뱅킹만을 따라 이동하는 봅슬레이 모양의 차량을 타고 이리 저리 꼬여있는 트랙을 따라 내려오는 놀이기구 STR_CPTY :차량당 2명의 승객 [GOLTR] STR_NAME :하이퍼 트위스터 차량 -STR_DESC :Spacious trains with simple lap restraints +STR_DESC :간단한 무릎 안전바를 가진 널찍한 차량 STR_CPTY :차량당 6명의 승객 [INTBOB] STR_NAME :플라잉 턴 -STR_DESC :Riders career down a twisting track in large bobsleigh cars guided only by the curvature and banking of the semi-circular track +STR_DESC :반원형 트랙의 커브와 뱅킹만을 따라 이동하는 봅슬레이 모양의 차량을 타고 이리 저리 꼬여있는 트랙을 따라 내려오는 놀이기구 STR_CPTY :차량당 6명의 승객 [INTINV] STR_NAME :인버티드 임펄스 코스터 -STR_DESC :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_DESC :수직으로 솟은 트랙을 오르기 위해 역에서 급가속한 뒤, 다시 역방향으로 되돌아와 역을 통과해서 뒷쪽의 또다른 수직 트랙을 올라가는 인버티드 롤러코스터 차량 STR_CPTY :차량당 4명의 승객 [INTST] STR_NAME :기가 코스터 -STR_DESC :A giant steel roller coaster capable of smooth drops and hills of over 300ft +STR_DESC :90m 이상의 부드러운 낙하와 상승이 가능한 거대한 강철 롤러코스터 STR_CPTY :차량당 4명의 승객 [IVMC1] STR_NAME :인버티트 헤어핀 코스터 -STR_DESC :Individual cars run beneath a zig-zagging track with hairpin turns and sharp drops +STR_DESC :급회전과 급경사를 가진 지그재그 모양의 트랙 아래를 달리는 개별 차량 STR_CPTY :차량당 4명의 승객 [JSTAR1] -STR_NAME :터보건 차량 -STR_DESC :Toboggan-shaped roller coaster cars with in-line seating +STR_NAME :터보건 썰매 차량 +STR_DESC :한 줄로 탑승하는 터보건 썰매 모양의 롤러코스터 STR_CPTY :차량당 4명의 승객 [MFT] -STR_NAME :굴절 롤러코스터 차량 Roller Coaster Trains -STR_DESC :Roller coaster trains with short single-row cars and open fronts +STR_NAME :연결식 롤러코스터 차량 +STR_DESC :하나의 열로 된 짧은 차량과 개방된 전면부를 가진 롤러코스터 차량 STR_CPTY :차량당 2명의 승객 [NEMT] STR_NAME :인버티드 롤러코스터 -STR_DESC :Riders sit in seats suspended beneath the track as they speed through giant loops, twists, and large swooping drops +STR_DESC :거대한 루프, 트위스트와 급격한 낙하 트랙을 따라 이동하며, 탑승객이 트랙 아래에 매달린 좌석에 앉는 차량 STR_CPTY :차량당 4명의 승객 [PMT1] STR_NAME :탄광 차량 -STR_DESC :Powered mine trains career along a smooth and twisted track layout +STR_DESC :부드럽게 꼬인 트랙 구조를 따라 달리는 탄광 차량 STR_CPTY :차량당 2명 또는 4명의 승객 [PREMT1] -STR_NAME :LIM 런치드 롤러코스터 -STR_DESC :Roller coaster trains are accelerated out of the station by linear induction motors to speed through twisting inversions +STR_NAME :LIM 발진 롤러코스터 +STR_DESC :역에서 선형 유도 모터에 의해 가속되어 꼬여있는 트랙을 빠른 속도로 통과하는 롤러코스터 차량 STR_CPTY :차량당 4명의 승객 [PTCT1] STR_NAME :우든 롤러코스터 차량 -STR_DESC :우든 롤러코스터 차량 with padded seats and lap bar restraints +STR_DESC :푹신한 좌석과 무릎 안전바가 있는 나무 롤러코스터 차량 STR_CPTY :차량당 4명의 승객 [PTCT2] STR_NAME :우든 롤러코스터 차량 (6인승) -STR_DESC :우든 롤러코스터 차량 with padded seats and lap bar restraints +STR_DESC :푹신한 좌석과 무릎 안전바가 있는 나무 롤러코스터 차량 STR_CPTY :차량당 6명의 승객 [PTCT2R] STR_NAME :우든 롤러코스터 차량 (6인승, 역방향) -STR_DESC :우든 롤러코스터 차량 with padded seats and lap bar restraints, running with the seats facing backwards +STR_DESC :푹신한 좌석과 무릎 안전바가 있고, 뒤쪽을 본 채로 앉아서 달리는 나무 롤러코스터 차량 STR_CPTY :차량당 6명의 승객 [RCKC] STR_NAME :로켓 차량 -STR_DESC :Roller coaster cars themed to look like rockets +STR_DESC :로켓처럼 꾸며져 있는 롤러코스터 차량 STR_CPTY :차량당 4명의 승객 [REVCAR] -STR_NAME :리버서 롤러코스터 -STR_DESC :Bogied cars run on wooden tracks, turning around on special reversing sections +STR_NAME :반전 롤러코스터 +STR_DESC :특수한 반전 섹션 위에서 앞뒤가 뒤집히는 나무 트랙 위를 운행하는 불안한 차량 STR_CPTY :차량당 6명의 승객 [REVF1] -STR_NAME :리버스 프리폴 차량 -STR_DESC :Large coaster car for the Reverse Freefall Coaster +STR_NAME :역방향 자유낙하 차량 +STR_DESC :역방향 자유낙하 코스터를 위한 대형 코스터 차량 STR_CPTY :승객 8명 [SBOX] STR_NAME :조립 경주차 경주 레이서 -STR_DESC :Riders ride soap-box car shaped vehicles along a single-rail roller coaster track -STR_CPTY :4 riders per car +STR_DESC :하나의 레일로 이루어진 롤러코스터 트랙을 이동하는 조립 경주차 모양의 차량 +STR_CPTY :차량당 4명의 승객 [SCHT1] STR_NAME :롤러코스터 차량 -STR_DESC :Roller coaster trains with lap bars capable of travelling through vertical loops +STR_DESC :무릎 안전바가 있으며 수직 루프를 돌 수 있는 롤러코스터 차량 STR_CPTY :차량당 4명의 승객 [SFRIC1] STR_NAME :우든 사이드 프릭션 차량 -STR_DESC :Basic cars for the Side-Friction Roller Coaster +STR_DESC :사이드 프릭션 롤러코스터를 위한 기본 차량 STR_CPTY :차량당 4명의 승객 [SKYTR] STR_NAME :미니 서스펜디드 플라잉 코스터 -STR_DESC :Passengers ride face-down in a lying position, suspended in a specially designed car from the single-rail track, swinging freely from side to side around corners +STR_DESC :하나의 레일로 이루어진 트랙에 매달린 특수 차량에 얼굴을 아래로 한 자세로 타고 코너를 돌 때마다 이리 저리 자유롭게 흔들리는 차량 STR_CPTY :차량당 승객 1명 [SLCFO] STR_NAME :인버티드 셔틀 코스터 -STR_DESC :Riders sit in pairs facing either forwards or backwards as they loop and twist through tight inversions +STR_DESC :앞쪽이나 뒤쪽을 보고 2명씩 짝지어 앉아 루프와 트위스트와 급격한 전이 트랙을 지나는 차량 STR_CPTY :차량당 4명의 승객 [SLCT] STR_NAME :컴팩트 인버티드 코스터 -STR_DESC :Riders sit in pairs of seats suspended beneath the track as they loop and twist through tight inversions +STR_DESC :트랙 밑에 매달린 좌석에 2명씩 짝지어 앉아 루프와 트위스트와 급격한 전이 트랙을 지나는 차량 STR_CPTY :차량당 2명의 승객 [SMC1] STR_NAME :쥐 차량 -STR_DESC :Individual cars shaped like mice +STR_DESC :쥐처럼 생긴 개별 차량 STR_CPTY :차량당 4명의 승객 [SMC2] STR_NAME :탄광 차량 -STR_DESC :Individual cars shaped like wooden mine trucks +STR_DESC :나무 탄광 트럭처럼 생긴 개별 차량 STR_CPTY :차량당 4명의 승객 [SPDRCR] @@ -4321,16 +4788,16 @@ STR_CPTY :차량당 6명의 승객 [STEEP1] STR_NAME :스티플체이스 STR_DESC :Riders ride horse-shaped vehicles which run along a single-rail roller coaster track -STR_CPTY :2 riders per horse +STR_CPTY :차량당 2명의 승객 [STEEP2] STR_NAME :모터바이크 레이스 STR_DESC :Riders ride motorbike-shaped roller coaster vehicles along a single-rail track -STR_CPTY :2 riders per bike +STR_CPTY :자전거당 2명의 승객 [THCAR] STR_NAME :에어 파워드 버티컬 코스터 -STR_DESC :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_DESC :아주 짜릿한 공기 압축 방식으로 발진하여 차량이 수직 트랙을 향해 속력을 높인 뒤, 꼭대기에 다다르면 다시 수직으로 하강하며 다시 탑승장에 도착합니다 STR_CPTY :차량당 2명의 승객 [TOGST] @@ -4340,12 +4807,12 @@ STR_CPTY :차량당 4명의 승객 [UTCAR] STR_NAME :트위스터 차량 -STR_DESC :Roller coaster cars capable of heartline twists +STR_DESC :하트라인 트위스트에 적합한 롤러코스터 차량 STR_CPTY :차량당 4명의 승객 [UTCARR] STR_NAME :트위스터 차량 (역방향) -STR_DESC :Roller coaster cars capable of heartline twists +STR_DESC :하트라인 트위스트에 적합한 롤러코스터 차량 STR_CPTY :차량당 4명의 승객 [VEKDV] @@ -4400,7 +4867,7 @@ STR_CPTY :차량당 2명의 승객 [C3D] STR_NAME :3D 영화관 -STR_DESC :Cinema showing 3D films inside a geodesic sphere shaped building +STR_DESC :둥근 구 모양의 건물 안에서 3D 영화를 상영하는 영화관 STR_CPTY :손님 20명 [ENTERP] @@ -4415,8 +4882,8 @@ STR_CPTY :승객 16명 [KART1] STR_NAME :고 카트 -STR_DESC :Self-drive petrol-engined go karts -STR_CPTY :single-seater +STR_DESC :스스로 운전하는 페트롤 엔진의 고 카트 +STR_CPTY :1인승 [MCARPET1] STR_NAME :마법의 양탄자 @@ -4435,7 +4902,7 @@ STR_CPTY :승객 8명 [SWSH1] STR_NAME :바이킹 -STR_DESC :Large swinging pirate ship +STR_DESC :흔들리는 거대한 해적선 STR_CPTY :승객 16명 [SWSH2] @@ -4501,7 +4968,7 @@ STR_CPTY :보트당 2명의 승객 [RFTBOAT] STR_NAME :리버 래프트 STR_DESC :Raft-shaped boats gently meander around a river track -STR_CPTY :raft당 4명의 승객 +STR_CPTY :래프트당 4명의 승객 [SPBOAT] STR_NAME :스플래시 보트 @@ -4599,7 +5066,7 @@ STR_NAME :핫도그 가게 STR_DESC :핫도그를 파는 가게 [ICECR1] -STR_NAME :아이스크림 가게 +STR_NAME :과일 아이스크림 가게 STR_DESC :과일 아이스크림을 파는 가게 [ICECR2] @@ -4707,43 +5174,43 @@ STR_NAME :축구 STR_NAME :테니스 공 [BEANST1] -STR_NAME :Giant Beanstalk +STR_NAME :대형 강낭콩 줄기 [BEANST2] -STR_NAME :Giant Beanstalk +STR_NAME :대형 강낭콩 줄기 [BRBASE] -STR_NAME :Base Block +STR_NAME :기본 블록 [BRBASE2] -STR_NAME :Base Block +STR_NAME :기본 블록 [BRBASE3] -STR_NAME :Base Block +STR_NAME :기본 블록 [BRCRRF1] -STR_NAME :Curved Roof +STR_NAME :곡선형 지붕 [BRCRRF2] -STR_NAME :Curved Roof +STR_NAME :곡선형 지붕 [CARROT] -STR_NAME :Giant Carrot +STR_NAME :대형 당근 [CHBBASE] -STR_NAME :Checkerboard Block +STR_NAME :체스판 블록 [CHEST1] -STR_NAME :Treasure Chest +STR_NAME :보물 상자 [CHEST2] -STR_NAME :Treasure Chest +STR_NAME :보물 상자 [CHOCROOF] -STR_NAME :Chocolate Bar +STR_NAME :초콜릿 바 [CNBALLS] -STR_NAME :Cannon Balls +STR_NAME :대포알 [CNDYRK1] STR_NAME :사탕 스틱 @@ -4752,10 +5219,10 @@ STR_NAME :사탕 스틱 STR_NAME :콜라 사탕 [CORROOF] -STR_NAME :Corrugated Steel Roof +STR_NAME :물결 무늬 강철 지붕 [CORROOF2] -STR_NAME :Corrugated Steel Base +STR_NAME :물결 무늬 강철 기반 [CWBCRV32] STR_NAME :곡선형 벽 @@ -4770,16 +5237,16 @@ STR_NAME :곡선형 벽 STR_NAME :곡선형 블록 [FERN1] -STR_NAME :Giant Fern +STR_NAME :대형 양치식물 [GGRS1] -STR_NAME :Giant Grass +STR_NAME :대형 풀 [HANG1] STR_NAME :교수대 [HELMET1] -STR_NAME :American Football Helmet +STR_NAME :아메리칸 풋볼 헬멧 [ICECUBE] STR_NAME :얼음 큐브 @@ -4794,10 +5261,10 @@ STR_NAME :젤리빈 STR_NAME :젤리빈 [JELDROP1] -STR_NAME :Fruit Drop +STR_NAME :떨어진 젤리 [JELDROP2] -STR_NAME :Fruit Drop +STR_NAME :떨어진 젤리 [JNGROOF1] STR_NAME :천장 @@ -5235,7 +5702,7 @@ STR_NAME :나무 STR_NAME :나무 [TMBJ] -STR_NAME :Meyer's Blue Juniper Tree +STR_NAME :메이어 향나무 [TMC] STR_NAME :왕느릅나무 @@ -5250,13 +5717,13 @@ STR_NAME :잔해 STR_NAME :나무 [TMM1] -STR_NAME :Graveyard Monument +STR_NAME :묘지 기념물 [TMM2] -STR_NAME :Graveyard Monument +STR_NAME :묘지 기념비 [TMM3] -STR_NAME :Graveyard Monument +STR_NAME :묘지 기념비 [TMO1] STR_NAME :화성 물체 @@ -5274,22 +5741,22 @@ STR_NAME :화성 물체 STR_NAME :화성 물체 [TMP] -STR_NAME :Monkey-Puzzle Tree +STR_NAME :칠레삼나무 [TMS1] STR_NAME :독버섯 [TMW] -STR_NAME :Wheels +STR_NAME :바퀴 [TMZP] -STR_NAME :Montezuma Pine Tree +STR_NAME :몬테수마 소나무 [TNS] -STR_NAME :Norway Spruce Tree +STR_NAME :노르웨이 가문비나무 [TNSS] -STR_NAME :Snow-covered Norway Spruce Tree +STR_NAME :눈 덮인 노르웨이 가문비나무 [TNTROOF1] STR_NAME :천막 지붕 @@ -5304,10 +5771,10 @@ STR_NAME :집 STR_NAME :건물 [TORN1] -STR_NAME :Ornamental Tree +STR_NAME :장식용 나무 [TORN2] -STR_NAME :Ornamental Tree +STR_NAME :장식용 나무 [TOS] STR_NAME :동상 @@ -5325,7 +5792,7 @@ STR_NAME :나무 STR_NAME :나무 [TOTEM1] -STR_NAME :Totem Pole +STR_NAME :토템 폴 [TP1] STR_NAME :흰색 폰 @@ -5385,16 +5852,16 @@ STR_NAME :나무 STR_NAME :나무 [TS4] -STR_NAME :Ornamental Tree +STR_NAME :장식용 나무 [TS5] -STR_NAME :Ornamental Tree +STR_NAME :장식용 나무 [TS6] -STR_NAME :Ornamental Tree +STR_NAME :장식용 나무 [TSB] -STR_NAME :Silver Birch Tree +STR_NAME :자작나무 [TSC] STR_NAME :선인장 @@ -5403,22 +5870,22 @@ STR_NAME :선인장 STR_NAME :건물 [TSCP] -STR_NAME :Space Capsule +STR_NAME :우주 캡슐 [TSD] -STR_NAME :Spade Shaped Tree +STR_NAME :스페이드 모양의 나무 [TSF1] -STR_NAME :Giant Snowflake +STR_NAME :대형 눈송이 [TSF2] -STR_NAME :Giant Snowflake +STR_NAME :대형 눈송이 [TSF3] -STR_NAME :Giant Snowflake +STR_NAME :대형 눈송이 [TSH] -STR_NAME :Horse Statue +STR_NAME :말 동상 [TSH0] STR_NAME :수풀 @@ -5445,7 +5912,7 @@ STR_NAME :눈사람 STR_NAME :눈덩이 [TSNC] -STR_NAME :Log Cabin +STR_NAME :통나무 집 [TSP] STR_NAME :스코틀랜드 소나무 @@ -5460,7 +5927,7 @@ STR_NAME :나무 STR_NAME :집 [TSQ] -STR_NAME :Squirrel Shaped Tree +STR_NAME :다람쥐 모양의 나무 [TST1] STR_NAME :독버섯 @@ -5478,7 +5945,7 @@ STR_NAME :독버섯 STR_NAME :독버섯 [TSTD] -STR_NAME :Dolphins Statue +STR_NAME :돌고래 동상 [TT1] STR_NAME :로마 사원 @@ -5490,34 +5957,34 @@ STR_NAME :과녁 STR_NAME :유니콘 동상 [TVL] -STR_NAME :Voss's Laburnam Tree +STR_NAME :나도싸리 [TWH1] STR_NAME :집 [TWH2] -STR_NAME :Pumpkin House +STR_NAME :호박 집 [TWN] -STR_NAME :Walnut Tree +STR_NAME :호두나무 [TWP] -STR_NAME :White Poplar Tree +STR_NAME :사시나무 [TWW] -STR_NAME :Weeping Willow Tree +STR_NAME :수양버들 [WAG1] -STR_NAME :Wagon +STR_NAME :마차 [WAG2] -STR_NAME :Wagon +STR_NAME :마차 [WDBASE] -STR_NAME :Wooden Block +STR_NAME :나무 블록 [TDF] -STR_NAME :Dolphin Fountain +STR_NAME :돌고래 분수 [TEF] STR_NAME :코끼리 분수 @@ -5739,7 +6206,7 @@ STR_NAME :탄광 건물 STR_NAME :갱도 [SOB] -STR_NAME :Office Block +STR_NAME :사무 빌딩 [SOH1] STR_NAME :집 @@ -5751,34 +6218,34 @@ STR_NAME :집 STR_NAME :집 [SPS] -STR_NAME :Petrol station +STR_NAME :주유소 [SSH] -STR_NAME :Space Capsule +STR_NAME :우주 캡슐 [SSK1] -STR_NAME :Skeleton +STR_NAME :해골 [SST] -STR_NAME :Satellite +STR_NAME :위성 [STB1] -STR_NAME :Castle Tower +STR_NAME :성탑 [STB2] -STR_NAME :Castle Tower +STR_NAME :성탑 [STG1] -STR_NAME :Castle Tower +STR_NAME :성탑 [STG2] -STR_NAME :Castle Tower +STR_NAME :성탑 [STH] -STR_NAME :Town Hall +STR_NAME :시청 [TAVERN] -STR_NAME :Tavern +STR_NAME :터번 [WWBANK] STR_NAME :은행 @@ -5805,28 +6272,28 @@ STR_NAME :해적선 STR_NAME :로마 콜로세움 [SIP] -STR_NAME :Ice Palace +STR_NAME :얼음성 [SMB] -STR_NAME :Martian Building +STR_NAME :화성 건물 [SPG] -STR_NAME :Pagoda +STR_NAME :탑 [SPYR] -STR_NAME :Pyramid +STR_NAME :피라미드 [SSPX] -STR_NAME :Sphinx +STR_NAME :스핑크스 [SSR] -STR_NAME :Space Rocket +STR_NAME :우주 로켓 [SVLC] -STR_NAME :Volcano +STR_NAME :화산 [WALLBADM] -STR_NAME :Badminton Racket +STR_NAME :배드민턴 라켓 [WALLBB16] STR_NAME :벽 @@ -5883,7 +6350,7 @@ STR_NAME :벽 아치 STR_NAME :창문 [WALLCO16] -STR_NAME :Corrugated Steel Wall +STR_NAME :물결 무늬 강철 벽 [WALLCW32] STR_NAME :벽 @@ -5910,13 +6377,13 @@ STR_NAME :젤리빈 벽 STR_NAME :벽 [WALLLT32] -STR_NAME :Steel Latticework +STR_NAME :강철 격자 [WALLMM16] -STR_NAME :Railings +STR_NAME :철책 [WALLMM17] -STR_NAME :Railings +STR_NAME :철책 [WALLMN32] STR_NAME :벽 @@ -5961,7 +6428,7 @@ STR_NAME :벽 STR_NAME :벽 [WALLSC16] -STR_NAME :Railings +STR_NAME :철책 [WALLSK16] STR_NAME :벽 @@ -6012,7 +6479,7 @@ STR_NAME :나무 벽 STR_NAME :나무 벽 [WALLWDPS] -STR_NAME :Wooden Post Fence +STR_NAME :나무 울타리 [WBR1] STR_NAME :벽돌 벽 @@ -6063,13 +6530,13 @@ STR_NAME :울타리 STR_NAME :나무 울타리 [WC18] -STR_NAME :Wooden Post Wall +STR_NAME :나무 울타리 [WC2] STR_NAME :성벽 [WC3] -STR_NAME :Roman Column Wall +STR_NAME :로마식 기둥 벽 [WC4] STR_NAME :성벽 @@ -6090,16 +6557,16 @@ STR_NAME :성벽 STR_NAME :성벽 [WCH] -STR_NAME :Conifer Hedge +STR_NAME :침엽수 생울타리 [WCHG] -STR_NAME :Conifer Hedge +STR_NAME :침엽수 생울타리 [WCW1] -STR_NAME :Playing Card Wall +STR_NAME :트럼프 벽 [WCW2] -STR_NAME :Playing Card Wall +STR_NAME :트럼프 벽 [WEW] STR_NAME :이집트 벽 @@ -6117,16 +6584,16 @@ STR_NAME :생울타리 STR_NAME :생울타리 [WJF] -STR_NAME :Jungle Fence +STR_NAME :정글 울타리 [WMF] -STR_NAME :Mesh Fence +STR_NAME :그물 철책 [WMFG] -STR_NAME :Mesh Fence +STR_NAME :그물 철책 [WMW] -STR_NAME :Martian Wall +STR_NAME :화성식 벽 [WMWW] STR_NAME :나무 울타리 @@ -6138,37 +6605,37 @@ STR_NAME :울타리 STR_NAME :울타리 [WPW1] -STR_NAME :Wooden Post Wall +STR_NAME :나무 울타리 [WPW2] -STR_NAME :Wooden Post Wall +STR_NAME :나무 울타리 [WPW3] STR_NAME :나무 울타리 [WRW] -STR_NAME :Roman Wall +STR_NAME :로마식 벽 [WRWA] -STR_NAME :Roman Wall +STR_NAME :로마식 벽 [WSW] -STR_NAME :Railings +STR_NAME :철책 [WSW1] -STR_NAME :Railings +STR_NAME :철책 [WSW2] -STR_NAME :Railings +STR_NAME :철책 [WSWG] -STR_NAME :Railings +STR_NAME :철책 [WWTW] -STR_NAME :Tall Wooden Fence +STR_NAME :키 큰 나무 울타리 [WWTWA] -STR_NAME :나무 울타리 Wall +STR_NAME :나무 울타리 벽 [WALLBRDR] STR_NAME :출입구 @@ -6177,13 +6644,13 @@ STR_NAME :출입구 STR_NAME :출입구 [WALLCBPC] -STR_NAME :Portcullis Door +STR_NAME :성문 [WALLCFDR] STR_NAME :출입구 [WALLCFPC] -STR_NAME :Portcullis Door +STR_NAME :성문 [WALLWF32] STR_NAME :폭포 @@ -6330,7 +6797,7 @@ STR_NAME :정원 STR_NAME :대형 정원 테마 [SCGHALLO] -STR_NAME :으스스한 테마 +STR_NAME :오싹한 테마 [SCGINDUS] STR_NAME :기계 테마 @@ -6402,7 +6869,7 @@ STR_NAME :공원 출입구 STR_NAME :기본 공원 입구 [PKESFH] -STR_NAME :Park Entrance Building +STR_NAME :공원 입구 건물 [WTRCYAN] STR_NAME :기본 물 @@ -6507,7 +6974,7 @@ STR_CPTY :차량당 4명의 승객 [CONDORRD] STR_NAME :콘도르 라이드 STR_DESC :Passengers ride face-down in a lying position, suspended in a Condor-shaped car from the single-rail track, swinging freely from side to side around corners -STR_CPTY :승객 1명 per car +STR_CPTY :차량당 승객 1명 [CONGAEEL] STR_NAME :콩가 뱀장어 코스터 @@ -6551,7 +7018,7 @@ STR_CPTY :차량당 4명의 승객 [MINECART] STR_NAME :탄광 카트 라이드 -STR_DESC :우든 롤러코스터 차량 with padded seats and lap bar restraints +STR_DESC :푹신한 좌석과 무릎 안전바가 있는 나무 롤러코스터 차량 STR_CPTY :차량당 4명의 승객 [OSTRICH] @@ -6597,7 +7064,7 @@ STR_CPTY :차량당 4명의 승객 [SPUTNIKR] STR_NAME :스푸트니크 서스펜디드 플라잉 코스터 STR_DESC :Passengers ride face-down in a lying position, suspended in a specially designed car from the single-rail track, swinging freely from side to side around corners -STR_CPTY :승객 2명 per car +STR_CPTY :차량당 승객 2명 [STGCCSTR] STR_NAME :역마차 롤러코스터 @@ -6616,7 +7083,7 @@ STR_CPTY :차량당 4명의 승객 [TGVTRAIN] STR_NAME :TGV 트레인 롤러코스터 -STR_DESC :Roller coaster trains are accelerated out of the station by linear induction motors to speed through twisting inversions +STR_DESC :역에서 선형 유도 모터에 의해 가속되어 꼬여있는 트랙을 빠른 속도로 통과하는 롤러코스터 차량 STR_CPTY :차량당 4명의 승객 [TIGRTWST] @@ -6677,7 +7144,7 @@ STR_CPTY :보트당 2명의 승객 [DOLPHINR] STR_NAME :돌고래 라이드 STR_DESC :Single-seater Dolphin-shaped vehicles which riders can drive themselves -STR_CPTY :1 rider per vehicle +STR_CPTY :차량당 1명의 탑승객 [MANDARIN] STR_NAME :원앙새 워터 라이드 @@ -6692,13 +7159,16 @@ STR_CPTY :보트당 16명의 승객 [OUTRIGGR] STR_NAME :아웃리거 라이드 STR_DESC :Long canoes which the passengers paddle themselves -STR_CPTY :canoe당 2명의 승객 +STR_CPTY :카누당 2명의 승객 [TUTLBOAT] STR_NAME :거북이 워터 라이드 STR_DESC :Small circular dinghies powered by a centrally-mounted motor controlled by the passengers STR_CPTY :보트당 2명의 승객 +[WILTLP] +STR_NAME :시들지 않는 튤립 + [1X1ATRE2] STR_NAME :덩굴 @@ -6799,64 +7269,64 @@ STR_NAME :파이프 STR_NAME :파이프 [RBRICK01] -STR_NAME :Red Brick Inverted Roof Piece +STR_NAME :Red Brick Inverted 지붕 Piece [RBRICK02] -STR_NAME :Red Brick Corner Roof Piece +STR_NAME :Red Brick Corner 지붕 Piece [RBRICK03] -STR_NAME :Red Brick Flat Roof Edge Piece +STR_NAME :Red Brick Flat 지붕 Edge Piece [RBRICK04] -STR_NAME :Red Brick Flat Roof Corner +STR_NAME :Red Brick Flat 지붕 Corner [RBRICK05] -STR_NAME :Red Brick Roof Piece 2 +STR_NAME :Red Brick 지붕 Piece 2 [RBRICK07] -STR_NAME :Red Brick Roof Piece 3 +STR_NAME :Red Brick 지붕 Piece 3 [RBRICK08] -STR_NAME :Red Brick Roof Piece 1 +STR_NAME :Red Brick 지붕 Piece 1 [RCORR01] -STR_NAME :Corrugated Roof Piece +STR_NAME :Corrugated 지붕 Piece [RCORR02] -STR_NAME :Corrugated Roof Piece +STR_NAME :Corrugated 지붕 Piece [RCORR03] -STR_NAME :Corrugated Roof Piece +STR_NAME :Corrugated 지붕 Piece [RCORR04] -STR_NAME :Corrugated Roof Piece +STR_NAME :Corrugated 지붕 Piece [RCORR05] -STR_NAME :Corrugated Roof Piece +STR_NAME :Corrugated 지붕 Piece [RCORR07] -STR_NAME :Corrugated Roof Piece +STR_NAME :Corrugated 지붕 Piece [RCORR08] -STR_NAME :Corrugated Roof Piece +STR_NAME :Corrugated 지붕 Piece [RCORR09] -STR_NAME :Corrugated Roof Piece +STR_NAME :Corrugated 지붕 Piece [RCORR10] -STR_NAME :Corrugated Roof Piece +STR_NAME :Corrugated 지붕 Piece [RCORR11] -STR_NAME :Corrugated Roof Piece +STR_NAME :Corrugated 지붕 Piece [RDRAB05] -STR_NAME :Drab Small Tower Minaret Base +STR_NAME :Drab Small Tower Minaret 기본 [RDRAB06] STR_NAME :Drab Small Tower Top or Mid-Section [RDRAB07] -STR_NAME :Drab Small Tower Base +STR_NAME :Drab Small Tower 기본 [RDRAB08] STR_NAME :Drab Minaret Piece 1 @@ -6868,52 +7338,52 @@ STR_NAME :Drab Minaret Piece 2 STR_NAME :Drab Minaret Piece 3 [RDRAB11] -STR_NAME :Drab Roof Piece 1 +STR_NAME :Drab 지붕 Piece 1 [RDRAB12] -STR_NAME :Drab Roof Piece 2 +STR_NAME :Drab 지붕 Piece 2 [RDRAB13] -STR_NAME :Drab Roof Piece 3 +STR_NAME :Drab 지붕 Piece 3 [RDRAB14] -STR_NAME :Drab Roof Piece 4 +STR_NAME :Drab 지붕 Piece 4 [RGEORG01] -STR_NAME :Georgian Roof End Piece 1 +STR_NAME :Georgian 지붕 End Piece 1 [RGEORG02] -STR_NAME :Georgian Roof End Piece 2 +STR_NAME :Georgian 지붕 End Piece 2 [RGEORG03] -STR_NAME :Georgian Roof Piece 1 +STR_NAME :Georgian 지붕 Piece 1 [RGEORG04] -STR_NAME :Georgian Roof Piece 2 +STR_NAME :Georgian 지붕 Piece 2 [RGEORG05] -STR_NAME :Georgian Roof Piece 3 +STR_NAME :Georgian 지붕 Piece 3 [RGEORG06] -STR_NAME :Georgian Roof Piece 4 +STR_NAME :Georgian 지붕 Piece 4 [RGEORG07] -STR_NAME :Georgian Roof Piece 5 +STR_NAME :Georgian 지붕 Piece 5 [RGEORG08] STR_NAME :Georgian Ground Floor Wall Piece 7 [RGEORG09] -STR_NAME :Georgian Flat Roof Edge 1 +STR_NAME :Georgian Flat 지붕 Edge 1 [RGEORG10] -STR_NAME :Georgian Flat Roof Edge 2 +STR_NAME :Georgian Flat 지붕 Edge 2 [RGEORG11] -STR_NAME :Georgian Flat Roof Corner +STR_NAME :Georgian Flat 지붕 Corner [RGEORG12] -STR_NAME :Georgian Roof Piece 7 +STR_NAME :Georgian 지붕 Piece 7 [ROOFICE1] STR_NAME :눈 지붕 @@ -6943,25 +7413,25 @@ STR_NAME :Kremlin Minaret Piece 2 STR_NAME :Kremlin Minaret Piece 3 [RKREML04] -STR_NAME :Kremlin Roof Piece 1 +STR_NAME :Kremlin 지붕 Piece 1 [RKREML05] -STR_NAME :Kremlin Roof Piece 2 +STR_NAME :Kremlin 지붕 Piece 2 [RKREML06] STR_NAME :Kremlin Small Tower Mid-Section [RKREML07] -STR_NAME :Kremlin Small Tower Base +STR_NAME :Kremlin Small Tower 기본 [RKREML11] -STR_NAME :Kremlin Small Tower Minaret Base +STR_NAME :Kremlin Small Tower Minaret 기본 [RLOG01] -STR_NAME :Log Cabin Roof Piece +STR_NAME :Log Cabin 지붕 Piece [RLOG02] -STR_NAME :Log Cabin Roof Piece +STR_NAME :Log Cabin 지붕 Piece [RLOG03] STR_NAME :Log Cabin Wall Piece @@ -6970,31 +7440,31 @@ STR_NAME :Log Cabin Wall Piece STR_NAME :Log Cabin Wall Piece [RLOG05] -STR_NAME :Log Cabin Roof Piece +STR_NAME :Log Cabin 지붕 Piece [RMARBLE1] -STR_NAME :Marble Roof +STR_NAME :Marble 지붕 [RMARBLE2] -STR_NAME :Marble Roof +STR_NAME :Marble 지붕 [RMARBLE3] -STR_NAME :Marble Roof +STR_NAME :Marble 지붕 [RMARBLE4] -STR_NAME :Marble Roof +STR_NAME :Marble 지붕 [RMUD01] -STR_NAME :Curved Mud Wall Piece +STR_NAME :곡선형 Mud Wall Piece [RMUD02] -STR_NAME :Curved Mud Wall Piece +STR_NAME :곡선형 Mud Wall Piece [RMUD03] -STR_NAME :Curved Mud Wall Piece +STR_NAME :곡선형 Mud Wall Piece [RMUD05] -STR_NAME :Mud Roof Piece +STR_NAME :Mud 지붕 Piece [ROOFIG01] STR_NAME :이글루 벽 @@ -7039,31 +7509,31 @@ STR_NAME :Iced Barrels STR_NAME :Ice Pipe Vent [PIPEBASE] -STR_NAME :Ice Pipe Base +STR_NAME :Ice Pipe 기본 [RTUDOR01] -STR_NAME :Tudor Roof Piece 1 +STR_NAME :Tudor 지붕 Piece 1 [RTUDOR02] -STR_NAME :Tudor Roof Piece 1 Extender Piece +STR_NAME :Tudor 지붕 Piece 1 Extender Piece [RTUDOR03] -STR_NAME :Tudor Roof Piece 2 +STR_NAME :Tudor 지붕 Piece 2 [RWDAUB01] -STR_NAME :Wattle & Daub Roof +STR_NAME :Wattle & Daub 지붕 [RWDAUB02] -STR_NAME :Wattle & Daub Roof +STR_NAME :Wattle & Daub 지붕 [RWDAUB03] -STR_NAME :Wattle & Daub Roof +STR_NAME :Wattle & Daub 지붕 [SB1HSPB1] -STR_NAME :Suspension Bridge Base Piece +STR_NAME :Suspension Bridge 기본 Piece [SB1HSPB2] -STR_NAME :Suspension Bridge Base Spacer Piece +STR_NAME :Suspension Bridge 기본 Spacer Piece [SB1HSPB3] STR_NAME :Suspension Bridge Mid Section Piece @@ -7072,7 +7542,7 @@ STR_NAME :Suspension Bridge Mid Section Piece STR_NAME :Cabana Porch [SB2SKY01] -STR_NAME :Stone Skyscraper Stairway Base +STR_NAME :Stone Skyscraper Stairway 기본 [SBH1TEPE] STR_NAME :Tee Pee @@ -7144,34 +7614,34 @@ STR_NAME :Skyscaper Metal Set 2 Concave Piece STR_NAME :Skyscaper Concave Piece [SBSKYS11] -STR_NAME :Skyscraper Concave Roof +STR_NAME :Skyscraper Concave 지붕 [SBSKYS12] STR_NAME :Skyscaper Convex Piece [SBSKYS13] -STR_NAME :Skyscaper Convex Roof +STR_NAME :Skyscaper Convex 지붕 [SBSKYS14] -STR_NAME :Sky Scraper Roof Piece +STR_NAME :Sky Scraper 지붕 Piece [SBSKYS15] -STR_NAME :Sky Scraper Roof Piece +STR_NAME :Sky Scraper 지붕 Piece [SBSKYS16] -STR_NAME :Sky Scraper Roof Piece +STR_NAME :Sky Scraper 지붕 Piece [SBSKYS17] -STR_NAME :Sky Scraper Roof Piece +STR_NAME :Sky Scraper 지붕 Piece [SBSKYS18] -STR_NAME :Sky Scraper Roof Piece +STR_NAME :Sky Scraper 지붕 Piece [SBWIND01] STR_NAME :Wind Sculpted Concave Wall Corner [SBWIND02] -STR_NAME :Wind Sculpted Concave Roof Corner +STR_NAME :Wind Sculpted Concave 지붕 Corner [SBWIND03] STR_NAME :Wind Sculpted Concave Wall Corner @@ -7180,16 +7650,16 @@ STR_NAME :Wind Sculpted Concave Wall Corner STR_NAME :Wind Sculpted Convex Wall Corner [SBWIND05] -STR_NAME :Wind Sculpted Convex Roof Corner +STR_NAME :Wind Sculpted Convex 지붕 Corner [SBWIND06] STR_NAME :Wind Sculpted Convex Wall Corner [SBWIND07] -STR_NAME :Wind Sculpted Rock Formation Base +STR_NAME :Wind Sculpted Rock Formation 기본 [SBWIND08] -STR_NAME :Wind Sculpted Rock Formation Base +STR_NAME :Wind Sculpted Rock Formation 기본 [SBWIND09] STR_NAME :Wind Sculpted Rock Formation Mid Section @@ -7210,13 +7680,13 @@ STR_NAME :Wind Sculpted Rock Formation Top STR_NAME :Wind Sculpted Rock Formation Top [SBWIND15] -STR_NAME :Wind Sculpted Roof Flat Roof Piece +STR_NAME :Wind Sculpted 지붕 Flat 지붕 Piece [SBWIND16] -STR_NAME :Wind Sculpted Roof Flat Roof Piece +STR_NAME :Wind Sculpted 지붕 Flat 지붕 Piece [SBWIND17] -STR_NAME :Wind Sculpted Roof Flat Roof Piece +STR_NAME :Wind Sculpted 지붕 Flat 지붕 Piece [SBWIND18] STR_NAME :Wind Sculpted Floor Piece @@ -7225,10 +7695,10 @@ STR_NAME :Wind Sculpted Floor Piece STR_NAME :Wind Sculpted Floor Piece [SBWIND20] -STR_NAME :Wind Sculpted Wall Base +STR_NAME :Wind Sculpted Wall 기본 [SBWIND21] -STR_NAME :Wind Sculpted Wall Base +STR_NAME :Wind Sculpted Wall 기본 [SBWPLM01] STR_NAME :Cabana Top @@ -7237,13 +7707,13 @@ STR_NAME :Cabana Top STR_NAME :Cabana Porch [SBWPLM03] -STR_NAME :Cabana Roof Piece +STR_NAME :Cabana 지붕 Piece [SBWPLM04] -STR_NAME :Cabana Roof Piece +STR_NAME :Cabana 지붕 Piece [SBWPLM05] -STR_NAME :Cabana Roof Piece +STR_NAME :Cabana 지붕 Piece [SBWPLM06] STR_NAME :Cabana Wall Piece @@ -7339,10 +7809,10 @@ STR_NAME :Aboriginal Art Set Piece STR_NAME :Aboriginal Art Set Piece [WAZTEC01] -STR_NAME :Temple Roof Piece +STR_NAME :Temple 지붕 Piece [WAZTEC02] -STR_NAME :Temple Roof Piece +STR_NAME :Temple 지붕 Piece [WAZTEC03] STR_NAME :Temple Wall Piece @@ -7381,19 +7851,19 @@ STR_NAME :Temple Wall Piece STR_NAME :Temple Wall Piece [WAZTEC15] -STR_NAME :Temple Roof Piece +STR_NAME :Temple 지붕 Piece [WAZTEC16] -STR_NAME :Temple Roof Piece +STR_NAME :Temple 지붕 Piece [WAZTEC17] -STR_NAME :Temple Roof Piece +STR_NAME :Temple 지붕 Piece [WAZTEC18] -STR_NAME :Temple Roof Piece +STR_NAME :Temple 지붕 Piece [WAZTEC19] -STR_NAME :Temple Roof Piece +STR_NAME :Temple 지붕 Piece [WAZTEC20] STR_NAME :Temple Stairway Piece @@ -7558,7 +8028,7 @@ STR_NAME :Kremlin Wall Piece 4 STR_NAME :Lost City Wall Piece [WMAYAN02] -STR_NAME :Lost City Flat Roof Piece +STR_NAME :Lost City Flat 지붕 Piece [WMAYAN03] STR_NAME :Lost City Wall Piece @@ -7612,10 +8082,10 @@ STR_NAME :Lost City Column Piece STR_NAME :Lost City Wall Piece [WMAYAN21] -STR_NAME :Lost City Flat Roof Piece +STR_NAME :Lost City Flat 지붕 Piece [WMAYAN22] -STR_NAME :Lost City Flat Roof Piece +STR_NAME :Lost City Flat 지붕 Piece [WMAYAN23] STR_NAME :Lost City Wall Corner Piece @@ -7630,19 +8100,19 @@ STR_NAME :Lost City Wall Corner Piece STR_NAME :Lost City Wall Corner Piece [WNAUTI01] -STR_NAME :Nautical Roof Piece +STR_NAME :Nautical 지붕 Piece [WNAUTI02] -STR_NAME :Nautical Roof Piece +STR_NAME :Nautical 지붕 Piece [WNAUTI03] -STR_NAME :Nautical Roof Piece +STR_NAME :Nautical 지붕 Piece [WNAUTI04] -STR_NAME :Nautical Roof Piece +STR_NAME :Nautical 지붕 Piece [WNAUTI05] -STR_NAME :Nautical Roof Piece +STR_NAME :Nautical 지붕 Piece [WTUDOR12] STR_NAME :Tudor Wall Piece 4 @@ -7756,10 +8226,10 @@ STR_NAME :Animated Balloons STR_NAME :Monumental Fountain [WROPECOR] -STR_NAME :Nautical Corner Roof Railing +STR_NAME :Nautical Corner 지붕 Railing [WROPESWA] -STR_NAME :Nautical Roof Railing +STR_NAME :Nautical 지붕 Railing [1X2ABR01] STR_NAME :Aboriginal Plain Tile @@ -7816,13 +8286,13 @@ STR_NAME :Mangrove Tree STR_NAME :1950's Rocket [BamboRf1] -STR_NAME :Bamboo Roof +STR_NAME :Bamboo 지붕 [BAMBORF2] -STR_NAME :Bamboo Roof +STR_NAME :Bamboo 지붕 [BamboRf3] -STR_NAME :Bamboo Roof +STR_NAME :Bamboo 지붕 [BIGGEOSP] STR_NAME :Big Geosphere @@ -7873,19 +8343,19 @@ STR_NAME :Washington Statue STR_NAME :Drab Large Tower Mid-Section [RDRAB02] -STR_NAME :Drab Large Tower Base +STR_NAME :Drab Large Tower 기본 [RDRAB03] STR_NAME :Drab Large Tower Top [RDRAB04] -STR_NAME :Drab Large Tower Broken Base +STR_NAME :Drab Large Tower Broken 기본 [REDWOOD] STR_NAME :Redwood Tree [RKREML08] -STR_NAME :Kremlin Large Tower Base +STR_NAME :Kremlin Large Tower 기본 [RKREML09] STR_NAME :Kremlin Large Tower Top @@ -7894,10 +8364,10 @@ STR_NAME :Kremlin Large Tower Top STR_NAME :Kremlin Large Tower Mid-Section [RTUDOR05] -STR_NAME :Tudor Roof Piece 3 +STR_NAME :Tudor 지붕 Piece 3 [RTUDOR06] -STR_NAME :Tudor Roof Piece 4 +STR_NAME :Tudor 지붕 Piece 4 [SHIVA] STR_NAME :Shiva @@ -7909,7 +8379,7 @@ STR_NAME :동상 of Liberty STR_NAME :Sputnik [TAJMCBSE] -STR_NAME :Maharaja Palace Tower Base +STR_NAME :Maharaja Palace Tower 기본 [TAJMCOLM] STR_NAME :Maharaja Palace Tower Column @@ -7984,7 +8454,7 @@ STR_NAME :Ice Formation STR_NAME :Ice Formation [MBSKYR01] -STR_NAME :Sky Scraper Roof Piece +STR_NAME :Sky Scraper 지붕 Piece [MBSKYR02] STR_NAME :Sky Scraper Tip @@ -8572,49 +9042,49 @@ STR_NAME :Wind Sculpted Wall Piece STR_NAME :Wind Sculpted Wall Piece [WBamboPC] -STR_NAME :Bamboo Wall +STR_NAME :대나무 벽 [SCGAFRIC] -STR_NAME : Africa Themeing +STR_NAME :아프리카 테마 [SCGARTIC] -STR_NAME : Antarctic Themeing +STR_NAME :남극 테마 [SCGASIA] -STR_NAME : Asia Themeing +STR_NAME :아시아 테마 [SCGAUSTR] -STR_NAME : Australasian Themeing +STR_NAME :오스트레일리아 테마 [SCGEUROP] -STR_NAME : Europe Themeing +STR_NAME :유럽 테마 [SCGNAMRC] -STR_NAME : North America Themeing +STR_NAME :북아메리카 테마 [SCGSAMER] -STR_NAME : South America Themeing +STR_NAME :남아메리카 테마 [AFRICENT] -STR_NAME :Africa Park Entrance +STR_NAME :아프리카식 공원 입구 [EUROENT] -STR_NAME :European Park Entrance +STR_NAME :유럽식 공원 입구 [ICEENT] -STR_NAME :Ice Park Entrance +STR_NAME :얼음 공원 입구 [JAPENT] -STR_NAME :Japanese Park Entrance +STR_NAME :일본식 공원 입구 [NAENT] -STR_NAME :North America Park Entrance +STR_NAME :북아메리카식 공원 입구 [OZENTRAN] -STR_NAME :Australasian Park Entrance +STR_NAME :오스트레일리아식 공원 입구 [SAMERENT] -STR_NAME :South American Park Entrance +STR_NAME :남아메리카식 공원 입구 ############################################################################### ## Time Twister Objects @@ -8641,7 +9111,7 @@ STR_CPTY :승객 20명 [CYCLOPSX] STR_NAME :사이클롭스 라이드 -STR_DESC :Riders drive the Eye of a Giant Cyclops +STR_DESC :Riders drive the Eye of a 대형 Cyclops STR_CPTY :차량당 1명의 손님 [FIGTKNIT] @@ -8695,8 +9165,8 @@ STR_DESC :Riders lock horns with each other in Triceratops dodgem cars STR_CPTY :차량당 1명의 손님 [BARNSTRM] -STR_NAME :선거 유세 코스터 -STR_DESC :Riders sit in seats suspended beneath the track as they speed through giant loops, twists, and large swooping drops +STR_NAME :곡예 비행기 코스터 +STR_DESC :거대한 루프, 트위스트와 급격한 낙하 트랙을 따라 이동하며, 탑승객이 트랙 아래에 매달린 좌석에 앉는 차량 STR_CPTY :차량당 4명의 승객 [BATTRRAM] @@ -8985,16 +9455,16 @@ STR_NAME :Art Deco Wall with Railings STR_NAME :Art Deco Wall with Railings [ARTDEC28] -STR_NAME :Art Deco Roof Section +STR_NAME :Art Deco 지붕 Section [ARTDEC29] STR_NAME :Art Deco Inverted Corner Section [BIGBASSX] -STR_NAME :Giant Bass Guitar +STR_NAME :대형 Bass Guitar [BIGGUTAR] -STR_NAME :Giant Guitar +STR_NAME :대형 Guitar [CHPRBKE1] STR_NAME :Motorcycle @@ -9027,16 +9497,16 @@ STR_NAME :Sandstone Skyscraper Mid Wall Section STR_NAME :Sandstone Skyscraper Inverted Corner Top [FUTSKY29] -STR_NAME :Sandstone Skyscraper Bottom Curved Slope +STR_NAME :Sandstone Skyscraper Bottom 곡선형 Slope [FUTSKY34] -STR_NAME :Sandstone Skyscraper Roof +STR_NAME :Sandstone Skyscraper 지붕 [FUTSKY35] -STR_NAME :Sandstone Skyscraper Mid Curved Slope +STR_NAME :Sandstone Skyscraper Mid 곡선형 Slope [FUTSKY42] -STR_NAME :Sandstone Skyscraper Curved Slope Top +STR_NAME :Sandstone Skyscraper 곡선형 Slope Top [FUTSKY52] STR_NAME :Sandstone Skyscraper Bottom Inverted Corner @@ -9045,7 +9515,7 @@ STR_NAME :Sandstone Skyscraper Bottom Inverted Corner STR_NAME :Sandstone Skyscraper Mid Corner [FUTSKY54] -STR_NAME :Obsidian SkyScraper Roof Piece +STR_NAME :Obsidian SkyScraper 지붕 Piece [GLDCHEST] STR_NAME :Treasure Chest @@ -9090,16 +9560,16 @@ STR_NAME :Heavenly Bath Window STR_NAME :Heavenly Bath Floor [HEVROF01] -STR_NAME :Heavenly Bath Roof +STR_NAME :Heavenly Bath 지붕 [HEVROF02] -STR_NAME :Heavenly Bath Roof +STR_NAME :Heavenly Bath 지붕 [HEVROF03] -STR_NAME :Heavenly Bath Roof +STR_NAME :Heavenly Bath 지붕 [HEVROF04] -STR_NAME :Heavenly Bath Roof +STR_NAME :Heavenly Bath 지붕 [HRBWAL01] STR_NAME :Harbour Wall @@ -9135,10 +9605,10 @@ STR_NAME :Industrial Wall Set STR_NAME :Industrial Wall Set [INDWAL05] -STR_NAME :Industrial Roof Corner Piece +STR_NAME :Industrial 지붕 Corner Piece [INDWAL06] -STR_NAME :Industrial Roof Corner Piece +STR_NAME :Industrial 지붕 Corner Piece [INDWAL07] STR_NAME :Industrial Wall with Doorway @@ -9180,34 +9650,34 @@ STR_NAME :Industrial Wall with Window STR_NAME :Industrial Wall with Window [INDWAL20] -STR_NAME :Industrial Roof Piece +STR_NAME :Industrial 지붕 Piece [INDWAL21] -STR_NAME :Industrial Roof Piece +STR_NAME :Industrial 지붕 Piece [INDWAL22] -STR_NAME :Industrial Roof Piece +STR_NAME :Industrial 지붕 Piece [INDWAL23] -STR_NAME :Industrial Roof Piece +STR_NAME :Industrial 지붕 Piece [INDWAL24] -STR_NAME :Industrial Roof Piece +STR_NAME :Industrial 지붕 Piece [INDWAL25] -STR_NAME :Industrial Roof Piece +STR_NAME :Industrial 지붕 Piece [INDWAL26] -STR_NAME :Industrial Roof Piece +STR_NAME :Industrial 지붕 Piece [INDWAL27] -STR_NAME :Industrial Roof Piece +STR_NAME :Industrial 지붕 Piece [INDWAL28] -STR_NAME :Industrial Roof Piece +STR_NAME :Industrial 지붕 Piece [INDWAL29] -STR_NAME :Industrial Roof Piece +STR_NAME :Industrial 지붕 Piece [INDWAL30] STR_NAME :Industrial Wall with Window @@ -9237,7 +9707,7 @@ STR_NAME :Prison Wall Piece STR_NAME :Prison Wall Piece [JAILXX07] -STR_NAME :Prison Wall Roof +STR_NAME :Prison Wall 지붕 [JAILXX08] STR_NAME :Prison Inverted Piece @@ -9474,22 +9944,22 @@ STR_NAME :Dark Age Village Upper Wall Piece STR_NAME :Dark Age Village Upper Wall Piece [PSNTWL14] -STR_NAME :Dark Age Village Roof Piece +STR_NAME :Dark Age Village 지붕 Piece [PSNTWL15] -STR_NAME :Dark Age Village Inverted Roof Piece +STR_NAME :Dark Age Village Inverted 지붕 Piece [PSNTWL16] -STR_NAME :Dark Age Village Roof Piece +STR_NAME :Dark Age Village 지붕 Piece [PSNTWL17] -STR_NAME :Dark Age Village Roof Piece +STR_NAME :Dark Age Village 지붕 Piece [PSNTWL20] -STR_NAME :Dark Age Village Window Box Roof +STR_NAME :Dark Age Village Window Box 지붕 [PSNTWL21] -STR_NAME :Dark Age Village Window Box Roof +STR_NAME :Dark Age Village Window Box 지붕 [PSNTWL23] STR_NAME :Dark Age Village Upper Corner Piece @@ -9501,13 +9971,13 @@ STR_NAME :Dark Age Village Window Box STR_NAME :Dark Age Village Window Box [PSNTWL29] -STR_NAME :Dark Age Village Window Box Roof +STR_NAME :Dark Age Village Window Box 지붕 [PSNTWL30] -STR_NAME :Dark Age Village Window Box Roof +STR_NAME :Dark Age Village Window Box 지붕 [PSNTWL31] -STR_NAME :Dark Age Village Corner Roof Piece +STR_NAME :Dark Age Village Corner 지붕 Piece [RDMETO03] STR_NAME :Red Meteor Crater Wall @@ -9554,7 +10024,7 @@ STR_NAME :Forest Trees STR_NAME :Smoke Stack Mid [SMOKSK03] -STR_NAME :Smoke Stack Base +STR_NAME :Smoke Stack 기본 [SPCSHP06] STR_NAME :Space Ship Cross Section @@ -9806,13 +10276,13 @@ STR_NAME :Sandstone Skyscraper Filler STR_NAME :Sandstone Skyscraper Bottom Corner [FUTSKY04] -STR_NAME :Sandstone Skyscraper Curved Slope Top +STR_NAME :Sandstone Skyscraper 곡선형 Slope Top [FUTSKY05] STR_NAME :Sandstone Skyscraper Corner Top [FUTSKY06] -STR_NAME :Sandstone Skyscraper Mid Curved Slope +STR_NAME :Sandstone Skyscraper Mid 곡선형 Slope [FUTSKY07] STR_NAME :Sandstone Skyscraper Mid Wall Section @@ -9824,7 +10294,7 @@ STR_NAME :Sandstone Skyscraper Mid Wall Section STR_NAME :Sandstone Skyscraper Mid Wall Section [FUTSKY10] -STR_NAME :Sandstone Skyscraper Bottom Slope Base +STR_NAME :Sandstone Skyscraper Bottom Slope 기본 [FUTSKY11] STR_NAME :Sandstone Skyscraper Mid Corner @@ -9833,10 +10303,10 @@ STR_NAME :Sandstone Skyscraper Mid Corner STR_NAME :Sandstone Skyscraper Mid Wall Section [FUTSKY13] -STR_NAME :Sandstone Skyscraper Roof Spire +STR_NAME :Sandstone Skyscraper 지붕 Spire [FUTSKY14] -STR_NAME :Sandstone Skyscraper Roof Spire +STR_NAME :Sandstone Skyscraper 지붕 Spire [FUTSKY15] STR_NAME :Sandstone Skyscraper Docking Bay @@ -9893,10 +10363,10 @@ STR_NAME :Animatronic Good Alien STR_NAME :Geysers [GGNTOCTO] -STR_NAME :B-Movie Giant Octopus +STR_NAME :B-Movie 대형 Octopus [GGNTSPID] -STR_NAME :B-Movie Giant Spider +STR_NAME :B-Movie 대형 Spider [GSCORPO2] STR_NAME :Animatronic attacking Scorpion @@ -10034,7 +10504,7 @@ STR_NAME :Wood Fence with Man Eating Plant STR_NAME :Wood Fence with Man Eating Plant [PSNTWL01] -STR_NAME :Dark Age Village Roof with Chimney +STR_NAME :Dark Age Village 지붕 with Chimney [RCKNROLR] STR_NAME :Cool Dude @@ -10235,16 +10705,16 @@ STR_NAME :Castle Entrance STR_NAME :Large Elm Tree [OLDNYK24] -STR_NAME :뉴욕 Inverted Corner Roof +STR_NAME :뉴욕 Inverted Corner 지붕 [OLDNYK25] -STR_NAME :뉴욕 Roof Piece +STR_NAME :뉴욕 지붕 Piece [OLDNYK26] STR_NAME :뉴욕 Entrance [OLDNYK32] -STR_NAME :뉴욕 Roof Piece +STR_NAME :뉴욕 지붕 Piece [1950SCAR] STR_NAME :1950s Car @@ -10253,7 +10723,7 @@ STR_NAME :1950s Car STR_NAME :Period Diner [4X4GMANT] -STR_NAME :Giant Mangrove Tree +STR_NAME :대형 Mangrove Tree [4X4STNHN] STR_NAME :Stone Age Temple @@ -10286,7 +10756,7 @@ STR_NAME :Ash Tree with Nymphs STR_NAME :Rock Band Tour Bus [BIGDRUMS] -STR_NAME :Giant Drum Kit +STR_NAME :대형 Drum Kit [CAVENTRA] STR_NAME :Cave Entrance @@ -10316,7 +10786,7 @@ STR_NAME :Cyclops Statue STR_NAME :Feast Table [FOOTPRNT] -STR_NAME :Giant Dinosaur Footprint +STR_NAME :대형 Dinosaur Footprint [FORBIDFT] STR_NAME :Forbidden Fruit Tree @@ -10397,7 +10867,7 @@ STR_NAME :Meteor Crater Corner STR_NAME :Meteor Crater Inverted Corner [OLDNYK20] -STR_NAME :뉴욕 Roof Piece +STR_NAME :뉴욕 지붕 Piece [OLDNYK21] STR_NAME :뉴욕 벽 조각 @@ -10442,13 +10912,13 @@ STR_NAME :Plough STR_NAME :Period Sailing Yacht [PSNTWL26] -STR_NAME :Dark Age Village Roof Piece +STR_NAME :Dark Age Village 지붕 Piece [PSNTWL27] -STR_NAME :Dark Age Village Corner Roof Piece +STR_NAME :Dark Age Village Corner 지붕 Piece [PSNTWL28] -STR_NAME :Dark Age Village Inverted Roof Piece +STR_NAME :Dark Age Village Inverted 지붕 Piece [RDMET2X2] STR_NAME :Small Red Meteor Crater diff --git a/data/title/rct1/script.txt b/data/title/rct1/script.txt new file mode 100644 index 0000000000..6d9ea69198 --- /dev/null +++ b/data/title/rct1/script.txt @@ -0,0 +1,98 @@ +# RollerCoaster Tycoon 1 Title Sequence + +############################## +# RollerCoaster Tycoon 1 # +############################## +# SC_DIAMOND_HEIGHTS +LOADRCT1 3 +ROTATE 2 +LOCATION 47, 99 +WAIT 15 +ROTATE 2 +LOCATION 90, 48 +WAIT 15 +ROTATE 1 +LOCATION 86, 43 +WAIT 15 +ROTATE 3 +LOCATION 57, 50 +WAIT 15 +ROTATE 2 +LOCATION 86, 64 +WAIT 15 + +# SC_KATIES_DREAMLAND +LOADRCT1 7 +LOCATION 48, 44 +WAIT 15 +LOCATION 64, 41 +WAIT 15 + +# SC_POKEY_PARK, +LOADRCT1 8 +ROTATE 2 +LOCATION 56, 64 +WAIT 15 + +# SC_WHITE_WATER_PARK +LOADRCT1 9 +ROTATE 3 +LOCATION 96, 88 +WAIT 15 +LOCATION 84, 95 +WAIT 15 + +# SC_MILLENNIUM_MINES +LOADRCT1 10 +ROTATE 1 +ROTATE 1 +LOCATION 64, 37 +WAIT 15 + +# SC_KARTS_COASTERS +LOADRCT1 11 +LOCATION 84, 56 +WAIT 15 +LOCATION 34, 36 +WAIT 15 +LOCATION 33, 65 +WAIT 15 + +# SC_MELS_WORLD +LOADRCT1 12 +ROTATE 3 +LOCATION 50, 50 +WAIT 15 +LOCATION 35, 39 +WAIT 15 +ROTATE 3 +LOCATION 62, 39 +WAIT 15 + +# SC_CRUMBLY_WOODS +LOADRCT1 15 +ROTATE 3 +LOCATION 57, 94 +WAIT 15 +LOCATION 44, 84 +WAIT 15 +ROTATE 1 +LOCATION 76, 59 +WAIT 15 +LOCATION 76, 48 +WAIT 15 + +# SC_LIGHTNING_PEAKS +LOADRCT1 17 +LOCATION 80, 49 +WAIT 15 +LOCATION 60, 62 +WAIT 15 + +# SC_IVORY_TOWERS +LOADRCT1 18 +ROTATE 3 +LOCATION 50, 77 +WAIT 15 + +RESTART diff --git a/data/title/rct1aa/script.txt b/data/title/rct1aa/script.txt new file mode 100644 index 0000000000..a3dd850a27 --- /dev/null +++ b/data/title/rct1aa/script.txt @@ -0,0 +1,187 @@ +# RollerCoaster Tycoon 1 Title Sequence + +############################## +# Added Attractions # +############################## +# SC_HAUNTED_HARBOR +LOADRCT1 45 +LOCATION 62, 53 +WAIT 11 +ROTATE 3 +LOCATION 78, 45 +WAIT 16 + +# SC_CANARY_MINES +LOADRCT1 42 +LOCATION 52, 28 +WAIT 15 + +# SC_GENTLE_GLEN +LOADRCT1 48 +LOCATION 68, 45 +WAIT 11 + +# SC_FUNTOPIA +LOADRCT1 44 +LOCATION 69, 93 +WAIT 17 + +# SC_SPRIGHTLY_PARK +LOADRCT1 51 +ROTATE 3 +LOCATION 97, 72 +WAIT 12 +ROTATE 2 +LOCATION 74, 71 +WAIT 12 +ROTATE 2 +LOCATION 67, 90 +WAIT 12 + +# SC_GIGGLE_DOWNS +LOADRCT1 65 +LOCATION 94, 64 +WAIT 10 + +# SC_SWAMP_COVE +LOADRCT1 59 +LOCATION 96, 22 +WAIT 10 +ROTATE 3 +LOCATION 90, 29 +WAIT 10 + +# SC_FRUIT_FARM +LOADRCT1 53 +LOCATION 47, 52 +WAIT 12 + +# SC_FUTURE_WORLD +LOADRCT1 47 +LOCATION 67, 59 +WAIT 19 + +# SC_THREE_MONKEYS_PARK +LOADRCT1 41 +ROTATE 2 +LOCATION 72, 61 +WAIT 8 +ROTATE 2 +LOCATION 68, 70 +WAIT 8 +LOCATION 58, 56 +WAIT 8 +ROTATE 1 +LOCATION 44, 70 +WAIT 8 +ROTATE 3 +LOCATION 43, 90 +WAIT 10 + +# SC_ROMAN_VILLAGE +LOADRCT1 58 +LOCATION 49, 46 +WAIT 15 + +# SC_ADRENALINE_HEIGHTS +LOADRCT1 60 +ROTATE 3 +LOCATION 38, 57 +WAIT 15 + +############################## +# RollerCoaster Tycoon 1 # +############################## +# SC_DIAMOND_HEIGHTS +LOADRCT1 3 +ROTATE 2 +LOCATION 47, 99 +WAIT 15 +ROTATE 2 +LOCATION 90, 48 +WAIT 15 +ROTATE 1 +LOCATION 86, 43 +WAIT 15 +ROTATE 3 +LOCATION 57, 50 +WAIT 15 +ROTATE 2 +LOCATION 86, 64 +WAIT 15 + +# SC_KATIES_DREAMLAND +LOADRCT1 7 +LOCATION 48, 44 +WAIT 15 +LOCATION 64, 41 +WAIT 15 + +# SC_POKEY_PARK, +LOADRCT1 8 +ROTATE 2 +LOCATION 56, 64 +WAIT 15 + +# SC_WHITE_WATER_PARK +LOADRCT1 9 +ROTATE 3 +LOCATION 96, 88 +WAIT 15 +LOCATION 84, 95 +WAIT 15 + +# SC_MILLENNIUM_MINES +LOADRCT1 10 +ROTATE 1 +ROTATE 1 +LOCATION 64, 37 +WAIT 15 + +# SC_KARTS_COASTERS +LOADRCT1 11 +LOCATION 84, 56 +WAIT 15 +LOCATION 34, 36 +WAIT 15 +LOCATION 33, 65 +WAIT 15 + +# SC_MELS_WORLD +LOADRCT1 12 +ROTATE 3 +LOCATION 50, 50 +WAIT 15 +LOCATION 35, 39 +WAIT 15 +ROTATE 3 +LOCATION 62, 39 +WAIT 15 + +# SC_CRUMBLY_WOODS +LOADRCT1 15 +ROTATE 3 +LOCATION 57, 94 +WAIT 15 +LOCATION 44, 84 +WAIT 15 +ROTATE 1 +LOCATION 76, 59 +WAIT 15 +LOCATION 76, 48 +WAIT 15 + +# SC_LIGHTNING_PEAKS +LOADRCT1 17 +LOCATION 80, 49 +WAIT 15 +LOCATION 60, 62 +WAIT 15 + +# SC_IVORY_TOWERS +LOADRCT1 18 +ROTATE 3 +LOCATION 50, 77 +WAIT 15 + +RESTART diff --git a/data/title/rct1aall/script.txt b/data/title/rct1aall/script.txt new file mode 100644 index 0000000000..63a64545c7 --- /dev/null +++ b/data/title/rct1aall/script.txt @@ -0,0 +1,233 @@ +# RollerCoaster Tycoon 1 Title Sequence + +############################## +# Added Attractions (part 1) # +############################## +# SC_HAUNTED_HARBOR +LOADRCT1 45 +LOCATION 62, 53 +WAIT 11 +ROTATE 3 +LOCATION 78, 45 +WAIT 16 + +# SC_CANARY_MINES +LOADRCT1 42 +LOCATION 52, 28 +WAIT 15 + +# SC_GENTLE_GLEN +LOADRCT1 48 +LOCATION 68, 45 +WAIT 11 + +# SC_FUNTOPIA +LOADRCT1 44 +LOCATION 69, 93 +WAIT 17 + +############################## +# Loopy Landscapes # +############################## +# SC_FRIGHTMARE_HILLS +LOADRCT1 86 +LOCATION 46, 47 +WAIT 5 + +# SC_GOOD_KNIGHT_PARK +LOADRCT1 30 +ROTATE 2 +LOCATION 60, 62 +WAIT 5 + +# SC_ICEBERG_ISLANDS +LOADRCT1 22 +ROTATE 3 +LOCATION 36, 52 +WAIT 4 + +# SC_SOUTHERN_SANDS +LOADRCT1 91 +ROTATE 2 +LOCATION 51, 47 +WAIT 4 + +# SC_SUNNY_SWAMPS +LOADRCT1 85 +ROTATE 3 +LOCATION 77, 82 +WAIT 4 + +# SC_VERTIGO_VIEWS +LOADRCT1 27 +LOCATION 22, 56 +WAIT 3 + +# SC_WACKY_WARREN +LOADRCT1 31 +ROTATE 3 +LOCATION 72, 80 +WAIT 4 + +############################## +# Added Attractions (part 2) # +############################## +# SC_SPRIGHTLY_PARK +LOADRCT1 51 +ROTATE 3 +LOCATION 97, 72 +WAIT 12 +ROTATE 2 +LOCATION 74, 71 +WAIT 12 +ROTATE 2 +LOCATION 67, 90 +WAIT 12 + +# SC_GIGGLE_DOWNS +LOADRCT1 65 +LOCATION 94, 64 +WAIT 10 + +# SC_SWAMP_COVE +LOADRCT1 59 +LOCATION 96, 22 +WAIT 10 +ROTATE 3 +LOCATION 90, 29 +WAIT 10 + +# SC_FRUIT_FARM +LOADRCT1 53 +LOCATION 47, 52 +WAIT 12 + +# SC_FUTURE_WORLD +LOADRCT1 47 +LOCATION 67, 59 +WAIT 19 + +# SC_THREE_MONKEYS_PARK +LOADRCT1 41 +ROTATE 2 +LOCATION 72, 61 +WAIT 8 +ROTATE 2 +LOCATION 68, 70 +WAIT 8 +LOCATION 58, 56 +WAIT 8 +ROTATE 1 +LOCATION 44, 70 +WAIT 8 +ROTATE 3 +LOCATION 43, 90 +WAIT 10 + +# SC_ROMAN_VILLAGE +LOADRCT1 58 +LOCATION 49, 46 +WAIT 15 + +# SC_ADRENALINE_HEIGHTS +LOADRCT1 60 +ROTATE 3 +LOCATION 38, 57 +WAIT 15 + +############################## +# RollerCoaster Tycoon 1 # +############################## +# SC_DIAMOND_HEIGHTS +LOADRCT1 3 +ROTATE 2 +LOCATION 47, 99 +WAIT 15 +ROTATE 2 +LOCATION 90, 48 +WAIT 15 +ROTATE 1 +LOCATION 86, 43 +WAIT 15 +ROTATE 3 +LOCATION 57, 50 +WAIT 15 +ROTATE 2 +LOCATION 86, 64 +WAIT 15 + +# SC_KATIES_DREAMLAND +LOADRCT1 7 +LOCATION 48, 44 +WAIT 15 +LOCATION 64, 41 +WAIT 15 + +# SC_POKEY_PARK, +LOADRCT1 8 +ROTATE 2 +LOCATION 56, 64 +WAIT 15 + +# SC_WHITE_WATER_PARK +LOADRCT1 9 +ROTATE 3 +LOCATION 96, 88 +WAIT 15 +LOCATION 84, 95 +WAIT 15 + +# SC_MILLENNIUM_MINES +LOADRCT1 10 +ROTATE 1 +ROTATE 1 +LOCATION 64, 37 +WAIT 15 + +# SC_KARTS_COASTERS +LOADRCT1 11 +LOCATION 84, 56 +WAIT 15 +LOCATION 34, 36 +WAIT 15 +LOCATION 33, 65 +WAIT 15 + +# SC_MELS_WORLD +LOADRCT1 12 +ROTATE 3 +LOCATION 50, 50 +WAIT 15 +LOCATION 35, 39 +WAIT 15 +ROTATE 3 +LOCATION 62, 39 +WAIT 15 + +# SC_CRUMBLY_WOODS +LOADRCT1 15 +ROTATE 3 +LOCATION 57, 94 +WAIT 15 +LOCATION 44, 84 +WAIT 15 +ROTATE 1 +LOCATION 76, 59 +WAIT 15 +LOCATION 76, 48 +WAIT 15 + +# SC_LIGHTNING_PEAKS +LOADRCT1 17 +LOCATION 80, 49 +WAIT 15 +LOCATION 60, 62 +WAIT 15 + +# SC_IVORY_TOWERS +LOADRCT1 18 +ROTATE 3 +LOCATION 50, 77 +WAIT 15 + +RESTART diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 6650f90d21..dc24bc75c6 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -5,6 +5,8 @@ - Feature: Add SI units as a new measurement system for distance / speed. - Feature: Update alternative font selection mechanism for all platforms. - Feature: Allow enabling / disabling of different notifications. +- Feature: Improved tile inspector. +- Feature: Integrate RCT1 style scenario select with optional unlock progression. - Fix: [#2126] Ferris Wheels set to "backward rotation" stop working (original bug) - Fix: [#2449] Turning off Day/Night Circle while it is night doesn't reset back to day diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 7fd8ebf384..ba532cfbac 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -120,7 +120,6 @@ - @@ -266,13 +265,13 @@ + - diff --git a/openrct2.vcxproj.filters b/openrct2.vcxproj.filters index 3f772e9f8f..7cff07ad18 100644 --- a/openrct2.vcxproj.filters +++ b/openrct2.vcxproj.filters @@ -270,9 +270,6 @@ Source - - Source - Source\Localisation @@ -564,6 +561,9 @@ Source + + Source + @@ -692,9 +692,6 @@ Source - - Source - Source\Localisation diff --git a/scripts/linux/build.sh b/scripts/linux/build.sh index 8c64ee3283..049059f2fa 100755 --- a/scripts/linux/build.sh +++ b/scripts/linux/build.sh @@ -15,7 +15,7 @@ fi # keep in sync with version in install.sh if [[ $(uname -s) == "Darwin" ]]; then # keep in sync with version in Xcode project - sha256sum=02ebc8e7fd8b9b02b7144721784c5d96202a17398bc8652da163c8c85b66a7db + sha256sum=6562ce9e1f37f125e3345bfd8b961777800436bf607b30dc7c964e0e6991ad2c else sha256sum=31c5e19d9f794bd5f0e75f20c2b4c3c4664d736b0a4d50c8cde14a9a9007b62d fi diff --git a/src/addresses.h b/src/addresses.h index 49ada59c0f..7ab377d187 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -63,6 +63,7 @@ // are implemented in C. Sometimes memory locations are still used even if // they aren't directly referenced, for example when a game is saved and // loaded, large chunks of data is read and written to. +#define RCT2_ADDRESS_SPRITE_ENTRIES 0x00982708 #define RCT2_ADDRESS_EASTEREGG_NAMES 0x00988C20 @@ -191,7 +192,7 @@ #define RCT2_ADDRESS_TICKS_SINCE_DRAG_START 0x009DE540 -#define RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE 0x009DE550 +#define RCT2_ADDRESS_PICKEDUP_PEEP_IMAGE 0x009DE550 #define RCT2_ADDRESS_PICKEDUP_PEEP_X 0x009DE554 #define RCT2_ADDRESS_PICKEDUP_PEEP_Y 0x009DE556 diff --git a/src/config.c b/src/config.c index 031ce02f72..8ff2ccced9 100644 --- a/src/config.c +++ b/src/config.c @@ -203,6 +203,10 @@ config_property_definition _generalDefinitions[] = { { offsetof(general_configuration, show_fps), "show_fps", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, { offsetof(general_configuration, trap_cursor), "trap_cursor", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, { offsetof(general_configuration, auto_open_shops), "auto_open_shops", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, + { offsetof(general_configuration, scenario_select_mode), "scenario_select_mode", CONFIG_VALUE_TYPE_UINT8, SCENARIO_SELECT_MODE_ORIGIN, NULL }, + { offsetof(general_configuration, scenario_unlocking_enabled), "scenario_unlocking_enabled", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, + { offsetof(general_configuration, scenario_hide_mega_park), "scenario_hide_mega_park", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL }, + }; config_property_definition _interfaceDefinitions[] = { @@ -1404,11 +1408,23 @@ void title_sequences_set_default() platform_get_openrct_data_path(dataPath); - // Load OpenRCT2 title sequence + // RCT1 title sequence + sprintf(path, "%s%c%s%c%s%c", dataPath, sep, "title", sep, "rct1", sep); + title_sequence_open(path, language_get_string(5305)); + + // RCT1 (AA) title sequence + sprintf(path, "%s%c%s%c%s%c", dataPath, sep, "title", sep, "rct1aa", sep); + title_sequence_open(path, language_get_string(5306)); + + // RCT1 (AA + LL) title sequence + sprintf(path, "%s%c%s%c%s%c", dataPath, sep, "title", sep, "rct1aall", sep); + title_sequence_open(path, language_get_string(5307)); + + // RCT2 title sequence sprintf(path, "%s%c%s%c%s%c", dataPath, sep, "title", sep, "rct2", sep); title_sequence_open(path, language_get_string(5308)); - // Load OpenRCT2 title sequence + // OpenRCT2 title sequence sprintf(path, "%s%c%s%c%s%c", dataPath, sep, "title", sep, "openrct2", sep); title_sequence_open(path, language_get_string(5309)); } @@ -1429,12 +1445,21 @@ void title_sequences_load_presets() platform_enumerate_directories_end(dirEnumHandle); // Check which title sequence is the current one - if (_stricmp(gConfigInterface.current_title_sequence_preset, "*RCT2") == 0) { + if (_stricmp(gConfigInterface.current_title_sequence_preset, "*RCT1") == 0) { gCurrentTitleSequence = 0; } - else if (_stricmp(gConfigInterface.current_title_sequence_preset, "*OPENRCT2") == 0) { + else if (_stricmp(gConfigInterface.current_title_sequence_preset, "*RCT1AA") == 0) { gCurrentTitleSequence = 1; } + else if (_stricmp(gConfigInterface.current_title_sequence_preset, "*RCT1AALL") == 0) { + gCurrentTitleSequence = 2; + } + else if (_stricmp(gConfigInterface.current_title_sequence_preset, "*RCT2") == 0) { + gCurrentTitleSequence = 3; + } + else if (_stricmp(gConfigInterface.current_title_sequence_preset, "*OPENRCT2") == 0) { + gCurrentTitleSequence = 4; + } else { for (i = TITLE_SEQUENCE_DEFAULT_PRESETS; i < gConfigTitleSequences.num_presets; i++) { if (_stricmp(gConfigInterface.current_title_sequence_preset, gConfigTitleSequences.presets[i].name) == 0) { @@ -1564,6 +1589,9 @@ static void title_sequence_open(const char *path, const char *customName) command.command = TITLE_SCRIPT_END; } else if (_stricmp(token, "LOADMM") == 0) { command.command = TITLE_SCRIPT_LOADMM; + } else if (_stricmp(token, "LOADRCT1") == 0) { + command.command = TITLE_SCRIPT_LOADRCT1; + command.saveIndex = atoi(part1) & 0xFF; } } if (command.command != 0xFF) { diff --git a/src/config.h b/src/config.h index e85c5d66d1..ced0402a6a 100644 --- a/src/config.h +++ b/src/config.h @@ -128,6 +128,11 @@ enum { SORT_DATE_DESCENDING, }; +enum { + SCENARIO_SELECT_MODE_DIFFICULTY, + SCENARIO_SELECT_MODE_ORIGIN, +}; + typedef struct { uint8 play_intro; uint8 confirmation_prompt; @@ -172,6 +177,9 @@ typedef struct { uint8 show_fps; uint8 trap_cursor; uint8 auto_open_shops; + uint8 scenario_select_mode; + uint8 scenario_unlocking_enabled; + uint8 scenario_hide_mega_park; } general_configuration; typedef struct { diff --git a/src/drawing/drawing.c b/src/drawing/drawing.c index cb0743544a..d2f8226595 100644 --- a/src/drawing/drawing.c +++ b/src/drawing/drawing.c @@ -485,7 +485,7 @@ void redraw_rain() void gfx_invalidate_pickedup_peep() { if (RCT2_GLOBAL(0x009ABDF2, uint32) != 0) { - int sprite = RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32); + int sprite = RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_IMAGE, sint32); if (sprite != -1) { sprite = sprite & 0x7FFFF; @@ -506,10 +506,10 @@ void gfx_draw_pickedup_peep() return; // Draw picked-up peep - if (RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, uint32) != 0xFFFFFFFF) { + if (RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_IMAGE, 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_IMAGE, uint32), RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_X, sint16), RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_Y, sint16), 0 ); diff --git a/src/drawing/drawing.h b/src/drawing/drawing.h index 0cd56e2cfb..81bbf2bd8f 100644 --- a/src/drawing/drawing.h +++ b/src/drawing/drawing.h @@ -149,6 +149,7 @@ 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); +void shorten_path(utf8 *buffer, size_t bufferSize, const utf8 *path, int availableWidth); bool ttf_initialise(); void ttf_dispose(); diff --git a/src/drawing/string.c b/src/drawing/string.c index f12f0af0e0..7cfaf346df 100644 --- a/src/drawing/string.c +++ b/src/drawing/string.c @@ -21,9 +21,10 @@ #include "../addresses.h" #include "../interface/colour.h" #include "../localisation/localisation.h" -#include "../sprites.h" -#include "../world/map.h" #include "../platform/platform.h" +#include "../sprites.h" +#include "../util/util.h" +#include "../world/map.h" #include "drawing.h" static int ttf_get_string_width(const utf8 *text); @@ -1355,3 +1356,40 @@ void gfx_draw_string_with_y_offsets(rct_drawpixelinfo *dpi, const utf8 *text, in gLastDrawStringX = info.x; gLastDrawStringY = info.y; } + +void shorten_path(utf8 *buffer, size_t bufferSize, const utf8 *path, int availableWidth) +{ + int length = strlen(path); + + // Return full string if it fits + if (gfx_get_string_width((char*)path) <= availableWidth) { + safe_strncpy(buffer, path, bufferSize); + 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 + safe_strncpy(buffer, "...", bufferSize); + + // 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()); + + safe_strncpy(buffer + 3, path + begin, bufferSize - 3); + if (gfx_get_string_width(buffer) <= availableWidth) { + return; + } + } + + safe_strncpy(buffer, path, bufferSize); +} diff --git a/src/editor.c b/src/editor.c index 7b566001ca..a9fc456a8d 100644 --- a/src/editor.c +++ b/src/editor.c @@ -138,7 +138,7 @@ void editor_convert_save_to_scenario_callback(int result) RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_SCENARIO_EDITOR; s6Info->editor_step = EDITOR_STEP_OBJECTIVE_SELECTION; - s6Info->category = SCENARIO_CATEGORY_BUILDYOUROWN; + s6Info->category = SCENARIO_CATEGORY_OTHER; viewport_init_all(); news_item_init_queue(); window_editor_main_open(); @@ -328,7 +328,7 @@ static int editor_read_s6(const char *path) s6Info->editor_step = EDITOR_STEP_LANDSCAPE_EDITOR; } else { s6Info->editor_step = EDITOR_STEP_LANDSCAPE_EDITOR; - s6Info->category = SCENARIO_CATEGORY_BUILDYOUROWN; + s6Info->category = SCENARIO_CATEGORY_OTHER; format_string(s6Info->details, STR_NO_DETAILS_YET, NULL); } diff --git a/src/game.c b/src/game.c index 1ff9d3cddb..90de03c730 100644 --- a/src/game.c +++ b/src/game.c @@ -46,7 +46,6 @@ #include "ride/track.h" #include "scenario.h" #include "title.h" -#include "tutorial.h" #include "util/sawyercoding.h" #include "util/util.h" #include "windows/error.h" @@ -57,6 +56,9 @@ #include "world/scenery.h" #include "world/sprite.h" #include "world/water.h" +#include + +#define NUMBER_OF_AUTOSAVES_TO_KEEP 9 int gGameSpeed = 1; float gDayNightCycle = 0; @@ -288,11 +290,11 @@ void game_update() 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 (gInputState == INPUT_STATE_RESET || + gInputState == 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; + if (gInputFlags & INPUT_FLAG_VIEWPORT_SCROLLING) { + gInputFlags &= ~INPUT_FLAG_VIEWPORT_SCROLLING; break; } } else { @@ -310,7 +312,7 @@ void game_update() RCT2_GLOBAL(0x009A8C28, uint8) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_VIEWPORT_SCROLLING; + gInputFlags &= ~INPUT_FLAG_VIEWPORT_SCROLLING; // the flickering frequency is reduced by 4, compared to the original // it was done due to inability to reproduce original frequency @@ -770,10 +772,10 @@ int game_load_sv6(SDL_RWops* rw) if (!load_success){ set_load_objects_fail_reason(); - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_5){ + if (gInputFlags & 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; + gInputFlags &= ~INPUT_FLAG_5; } return 0;//This never gets called @@ -864,10 +866,10 @@ int game_load_network(SDL_RWops* rw) if (!load_success){ set_load_objects_fail_reason(); - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_5){ + if (gInputFlags & 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; + gInputFlags &= ~INPUT_FLAG_5; } return 0;//This never gets called @@ -1059,16 +1061,99 @@ void save_game_as() window_loadsave_open(LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME, (char*)path_get_filename(gScenarioSavePath)); } +int compare_autosave_file_paths (const void * a, const void * b ) { + return strcmp(*(char **)a, *(char **)b); +} + +void limit_autosave_count(const size_t numberOfFilesToKeep) +{ + int fileEnumHandle = 0; + + size_t autosavesCount = 0; + size_t numAutosavesToDelete = 0; + + file_info fileInfo; + + utf8 filter[MAX_PATH]; + + utf8 **autosaveFiles = NULL; + + size_t i=0; + + platform_get_user_directory(filter, "save"); + strncat(filter, "autosave_*.sv6", sizeof(filter) - strnlen(filter, MAX_PATH) - 1); + + // At first, count how many autosaves there are + fileEnumHandle = platform_enumerate_files_begin(filter); + while (platform_enumerate_files_next(fileEnumHandle, &fileInfo)) { + autosavesCount++; + } + platform_enumerate_files_end(fileEnumHandle); + + // If there are fewer autosaves than the number of files to keep we don't need to delete anything + if(autosavesCount <= numberOfFilesToKeep) { + return; + } + + autosaveFiles = (utf8**) malloc(sizeof(utf8*) * autosavesCount); + + fileEnumHandle = platform_enumerate_files_begin(filter); + for(i = 0; i < autosavesCount; i++) { + autosaveFiles[i] = (utf8*)malloc(sizeof(utf8) * MAX_PATH); + memset(autosaveFiles[i], 0, sizeof(utf8) * MAX_PATH); + + if(platform_enumerate_files_next(fileEnumHandle, &fileInfo)) { + platform_get_user_directory(autosaveFiles[i], "save"); + strcat(autosaveFiles[i], fileInfo.path); + } + } + platform_enumerate_files_end(fileEnumHandle); + + qsort (autosaveFiles, autosavesCount, sizeof (char*), compare_autosave_file_paths); + + // calculate how many saves we need to delete. + numAutosavesToDelete = autosavesCount - numberOfFilesToKeep; + + i=0; + while (numAutosavesToDelete > 0) { + platform_file_delete(autosaveFiles[i]); + + i++; + numAutosavesToDelete--; + } + + + for(i = 0; i < autosavesCount; i++) { + free(autosaveFiles[i]); + } + + free(autosaveFiles); +} void game_autosave() { utf8 path[MAX_PATH]; utf8 backupPath[MAX_PATH]; + utf8 timeString[21]=""; + + time_t rawtime; + struct tm * timeinfo; + + time ( &rawtime ); + timeinfo = localtime ( &rawtime ); + limit_autosave_count(NUMBER_OF_AUTOSAVES_TO_KEEP); + + snprintf(timeString, 20, "%d-%02d-%02d_%02d-%02d-%02d", 1900+timeinfo->tm_year, 1+timeinfo->tm_mon, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); + + platform_get_user_directory(path, "save"); safe_strncpy(backupPath, path, MAX_PATH); - strcat(path, "autosave.sv6"); + strcat(path, "autosave_"); + strcat(path, timeString); + strcat(path, ".sv6"); + strcat(backupPath, "autosave.sv6.bak"); if (platform_file_exists(path)) { @@ -1129,8 +1214,8 @@ void game_load_or_quit_no_save_prompt() } else if (RCT2_GLOBAL(RCT2_ADDRESS_SAVE_PROMPT_MODE, uint16) == 1) { game_do_command(0, 1, 0, 1, GAME_COMMAND_LOAD_OR_QUIT, 0, 0); tool_cancel(); - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_5) { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_5; + if (gInputFlags & INPUT_FLAG_5) { + gInputFlags &= ~INPUT_FLAG_5; } gGameSpeed = 1; title_load(); diff --git a/src/hook.c b/src/hook.c index c0b9e16b72..ebed9b189c 100644 --- a/src/hook.c +++ b/src/hook.c @@ -30,6 +30,14 @@ void* g_hooktableaddress = 0; int g_hooktableoffset = 0; int g_maxhooks = 1000; +// This macro writes a little-endian 4-byte long value into *data +// It is used to avoid type punning. +#define write_address_strictalias(data, addr) \ + *(data + 0) = ((addr) & 0x000000ff) >> 0; \ + *(data + 1) = ((addr) & 0x0000ff00) >> 8; \ + *(data + 2) = ((addr) & 0x00ff0000) >> 16; \ + *(data + 3) = ((addr) & 0xff000000) >> 24; + void hookfunc(int address, int newaddress, int stacksize, int registerargs[], int registersreturned, int eaxDestinationRegister) { int i = 0; @@ -118,7 +126,9 @@ void hookfunc(int address, int newaddress, int stacksize, int registerargs[], in } data[i++] = 0xE8; // call - *((int *)&data[i]) = (newaddress - address - i - 4); i += 4; + + write_address_strictalias(&data[i], newaddress - address - i - 4); + i += 4; // returnlocation: @@ -220,7 +230,10 @@ void addhook(int address, int newaddress, int stacksize, int registerargs[], int char data[9]; int i = 0; data[i++] = 0xE9; // jmp - *((int *)&data[i]) = hookaddress - address - i - 4; i += 4; + + write_address_strictalias(&data[i], hookaddress - address - i - 4); + i += 4; + data[i++] = 0xC3; // retn #ifdef _WIN32 WriteProcessMemory(GetCurrentProcess(), (LPVOID)address, data, i, 0); diff --git a/src/input.c b/src/input.c index 2f3ca89b54..e4d39e40a9 100644 --- a/src/input.c +++ b/src/input.c @@ -35,7 +35,6 @@ #include "platform/platform.h" #include "ride/ride_data.h" #include "scenario.h" -#include "tutorial.h" #include "windows/tooltip.h" #include "windows/dropdown.h" #include "world/banner.h" @@ -44,11 +43,21 @@ #include "world/scenery.h" #include "openrct2.h" -static int _dragX, _dragY; -static rct_windowclass _dragWindowClass; -static rct_windownumber _dragWindowNumber; -static int _dragWidgetIndex, _dragScrollIndex; -static int _originalWindowWidth, _originalWindowHeight; +static sint32 _dragX; +static sint32 _dragY; +static widget_ref _dragWidget; +static uint8 _dragScrollIndex; +static sint32 _originalWindowWidth; +static sint32 _originalWindowHeight; + +uint8 gInputState; +uint8 gInputFlags; + +uint16 gTooltipNotShownTicks; +uint16 gTooltipTimeout; +widget_ref gTooltipWidget; +sint32 gTooltipCursorX; +sint32 gTooltipCursorY; typedef struct { uint32 x, y; @@ -92,7 +101,6 @@ static void input_scroll_part_update_vthumb(rct_window *w, int widgetIndex, int static void input_scroll_part_update_vtop(rct_window *w, int widgetIndex, int scroll_id); static void input_scroll_part_update_vbottom(rct_window *w, int widgetIndex, int scroll_id); static void input_update_tooltip(rct_window *w, int widgetIndex, int x, int y); -static void update_cursor_position(); #pragma region Mouse input @@ -115,7 +123,6 @@ void game_handle_input() window_event_unknown_07_call(w); sub_6EA73F(); - update_cursor_position(); for (;;) { game_get_next_input(&x, &y, &state); @@ -125,7 +132,7 @@ void game_handle_input() game_handle_input_mouse(x, y, state & 0xFF); } - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_5) { + if (gInputFlags & INPUT_FLAG_5) { game_handle_input_mouse(x, y, state); } else if (x != 0x80000000) { @@ -159,8 +166,6 @@ static void game_get_next_input(int *x, int *y, int *state) *x = eax->x; *y = eax->y; *state = eax->state; - - // NOTE this function lacks tutorial logic } /** @@ -184,12 +189,12 @@ static rct_mouse_data* get_mouse_input() * 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; + gInputState = INPUT_STATE_SCROLL_RIGHT; _dragX = x; _dragY = y; - _dragWindowClass = w->classification; - _dragWindowNumber = w->number; - _dragWidgetIndex = widgetIndex; + _dragWidget.window_classification = w->classification; + _dragWidget.window_number = w->number; + _dragWidget.widget_index = widgetIndex; RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_DRAG_START, sint16) = 0; _dragScrollIndex = window_get_scroll_data_index(w, widgetIndex); @@ -200,8 +205,9 @@ static void input_scroll_drag_begin(int x, int y, rct_window* w, rct_widget* wid * Based on (heavily changed) * rct2: 0x006E9E0E, 0x006E9ED0 */ -static void input_scroll_drag_continue(int x, int y, rct_window* w) { - uint8 widgetIndex = _dragWidgetIndex; +static void input_scroll_drag_continue(int x, int y, rct_window* w) +{ + uint8 widgetIndex = _dragWidget.widget_index; uint8 scrollIndex = _dragScrollIndex; rct_widget* widget = &w->widgets[widgetIndex]; @@ -238,13 +244,13 @@ static void input_scroll_drag_continue(int x, int y, rct_window* w) { */ static void input_scroll_right(int x, int y, int state) { rct_window* w = window_find_by_number( - _dragWindowClass, - _dragWindowNumber - ); + _dragWidget.window_classification, + _dragWidget.window_number + ); if (w == NULL) { platform_show_cursor(); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESET; + gInputState = INPUT_STATE_RESET; return; } @@ -258,7 +264,7 @@ static void input_scroll_right(int x, int y, int state) { input_scroll_drag_continue(x, y, w); break; case 4: - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESET; + gInputState = INPUT_STATE_RESET; platform_show_cursor(); break; } @@ -279,7 +285,7 @@ static void game_handle_input_mouse(int x, int y, int state) widgetIndex = w == NULL ? -1 : window_find_widget_from_point(w, x, y); widget = widgetIndex == -1 ? 0 : &w->widgets[widgetIndex]; - switch (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8)) { + switch (gInputState) { case INPUT_STATE_RESET: window_tooltip_reset(x, y); // fall-through @@ -315,9 +321,9 @@ static void game_handle_input_mouse(int x, int y, int state) input_state_widget_pressed(x, y, state, widgetIndex, w, widget); break; case INPUT_STATE_POSITIONING_WINDOW: - w = window_find_by_number(_dragWindowClass, _dragWindowNumber); + w = window_find_by_number(_dragWidget.window_classification, _dragWidget.window_number); if (w == NULL) { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESET; + gInputState = INPUT_STATE_RESET; } else { input_window_position_continue(w, _dragX, _dragY, x, y); @@ -346,19 +352,19 @@ static void game_handle_input_mouse(int x, int y, int state) RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber) ); if (!w){ - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 0; + gInputState = INPUT_STATE_RESET; break; } if (state == 0){ if (!w->viewport){ - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 0; + gInputState = INPUT_STATE_RESET; break; } if (w->classification != RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS, rct_windowclass) || w->number != RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber) || - !(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) break; + !(gInputFlags & INPUT_FLAG_TOOL_ACTIVE)) break; w = window_find_by_number( RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), @@ -371,9 +377,9 @@ static void game_handle_input_mouse(int x, int y, int state) } else if (state == 2){ - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 0; + gInputState = INPUT_STATE_RESET; if (RCT2_GLOBAL(0x9DE52E, rct_windownumber) != w->number)break; - if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)){ + if ((gInputFlags & INPUT_FLAG_TOOL_ACTIVE)){ w = window_find_by_number( RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) @@ -383,7 +389,7 @@ static void game_handle_input_mouse(int x, int y, int state) window_event_tool_up_call(w, RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16), x, y); } else{ - if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_4)) + if ((gInputFlags & INPUT_FLAG_4)) break; viewport_interaction_left_click(x, y); @@ -397,9 +403,9 @@ static void game_handle_input_mouse(int x, int y, int state) input_scroll_end(); break; case INPUT_STATE_RESIZING: - w = window_find_by_number(_dragWindowClass, _dragWindowNumber); + w = window_find_by_number(_dragWidget.window_classification, _dragWidget.window_number); if (w == NULL) { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESET; + gInputState = INPUT_STATE_RESET; } else { if (state == 2) @@ -419,12 +425,12 @@ static void game_handle_input_mouse(int x, int y, int state) void input_window_position_begin(rct_window *w, int widgetIndex, int x, int y) { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_POSITIONING_WINDOW; + gInputState = INPUT_STATE_POSITIONING_WINDOW; _dragX = x - w->x; _dragY = y - w->y; - _dragWindowClass = w->classification; - _dragWindowNumber = w->number; - _dragWidgetIndex = widgetIndex; + _dragWidget.window_classification = w->classification; + _dragWidget.window_number = w->number; + _dragWidget.widget_index = widgetIndex; } static void input_window_position_continue(rct_window *w, int wdx, int wdy, int x, int y) @@ -437,22 +443,20 @@ static void input_window_position_continue(rct_window *w, int wdx, int wdy, int static void input_window_position_end(rct_window *w, int x, int y) { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_NORMAL; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint8) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) = _dragWindowClass; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) = _dragWindowNumber; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = _dragWidgetIndex; + gInputState = INPUT_STATE_NORMAL; + gTooltipTimeout = 0; + gTooltipWidget = _dragWidget; window_event_moved_call(w, x, y); } static void input_window_resize_begin(rct_window *w, int widgetIndex, int x, int y) { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESIZING; + gInputState = INPUT_STATE_RESIZING; _dragX = x; _dragY = y; - _dragWindowClass = w->classification; - _dragWindowNumber = w->number; - _dragWidgetIndex = widgetIndex; + _dragWidget.window_classification = w->classification; + _dragWidget.window_number = w->number; + _dragWidget.widget_index = widgetIndex; _originalWindowWidth = w->width; _originalWindowHeight = w->height; } @@ -477,11 +481,9 @@ static void input_window_resize_continue(rct_window *w, int x, int y) static void input_window_resize_end() { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_NORMAL; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint8) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) = _dragWindowClass; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) = _dragWindowNumber; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = _dragWidgetIndex; + gInputState = INPUT_STATE_NORMAL; + gTooltipTimeout = 0; + gTooltipWidget = _dragWidget; } #pragma endregion @@ -491,14 +493,14 @@ static void input_window_resize_end() static void input_viewport_drag_begin(rct_window *w, int x, int y) { w->flags &= ~WF_SCROLLING_TO_LOCATION; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_VIEWPORT_RIGHT; - _dragWindowClass = w->classification; - _dragWindowNumber = w->number; + gInputState = INPUT_STATE_VIEWPORT_RIGHT; + _dragWidget.window_classification = w->classification; + _dragWidget.window_number = w->number; RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_DRAG_START, sint16) = 0; platform_get_cursor_position(&_dragX, &_dragY); platform_hide_cursor(); - // RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_5; + // gInputFlags |= INPUT_FLAG_5; } static void input_viewport_drag_continue() @@ -511,14 +513,14 @@ static void input_viewport_drag_continue() dx = newDragX - _dragX; dy = newDragY - _dragY; - w = window_find_by_number(_dragWindowClass, _dragWindowNumber); + w = window_find_by_number(_dragWidget.window_classification, _dragWidget.window_number); assert(w != NULL); viewport = w->viewport; 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; + gInputState = INPUT_STATE_RESET; } else if (dx != 0 || dy != 0) { if (!(w->flags & WF_NO_SCROLLING)) { // User dragged a scrollable viewport @@ -544,7 +546,7 @@ static void input_viewport_drag_continue() static void input_viewport_drag_end() { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESET; + gInputState = INPUT_STATE_RESET; platform_show_cursor(); } @@ -558,12 +560,12 @@ static void input_scroll_begin(rct_window *w, int widgetIndex, int x, int y) widget = &w->widgets[widgetIndex]; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_SCROLL_LEFT; + gInputState = INPUT_STATE_SCROLL_LEFT; RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint16) = widgetIndex; RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, rct_windowclass) = w->classification; RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWNUMBER, rct_windownumber) = w->number; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, uint16) = x; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, uint16) = y; + gTooltipCursorX = x; + gTooltipCursorY = y; int eax, ebx, scroll_area, scroll_id; scroll_id = 0; // safety @@ -647,9 +649,7 @@ static void input_scroll_continue(rct_window *w, int widgetIndex, int state, int 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); - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, uint16) = temp_x; + gTooltipCursorX = x - gTooltipCursorX; input_scroll_part_update_hthumb(w, widgetIndex, x, scroll_id); return; } @@ -702,7 +702,7 @@ static void input_scroll_continue(rct_window *w, int widgetIndex, int state, int static void input_scroll_end() { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_RESET; + gInputState = INPUT_STATE_RESET; invalidate_scroll(); } @@ -904,9 +904,9 @@ static void input_widget_over(int x, int y, rct_window *w, int widgetIndex) input_update_tooltip(w, widgetIndex, x, y); } - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, sint16) = x; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, sint16) = y; + gTooltipTimeout = 0; + gTooltipCursorX = x; + gTooltipCursorY = y; } /** @@ -1004,19 +1004,19 @@ static void input_widget_left(int x, int y, rct_window *w, int widgetIndex) input_window_resize_begin(w, widgetIndex, x, y); break; case WWT_VIEWPORT: - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_VIEWPORT_LEFT; + gInputState = INPUT_STATE_VIEWPORT_LEFT; RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_X, uint16) = x; RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_LAST_Y, uint16) = y; RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS, rct_windowclass) = windowClass; RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber) = windowNumber; - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) { + if (gInputFlags & INPUT_FLAG_TOOL_ACTIVE) { w = window_find_by_number( RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) ); if (w != NULL) { window_event_tool_down_call(w, RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16), x, y); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_4; + gInputFlags |= INPUT_FLAG_4; } } break; @@ -1034,8 +1034,8 @@ static void input_widget_left(int x, int y, rct_window *w, int widgetIndex) RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, rct_windowclass) = windowClass; RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWNUMBER, rct_windownumber) = windowNumber; RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint16) = widgetIndex; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_WIDGET_PRESSED; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = INPUT_STATE_WIDGET_PRESSED; + gInputFlags |= INPUT_FLAG_WIDGET_PRESSED; + gInputState = INPUT_STATE_WIDGET_PRESSED; RCT2_GLOBAL(0x009DE528, uint16) = 1; widget_invalidate_by_number(windowClass, windowNumber, widgetIndex); @@ -1071,7 +1071,7 @@ void process_mouse_over(int x, int y) switch (window->widgets[widgetId].type){ case WWT_VIEWPORT: - if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, int) & INPUT_FLAG_TOOL_ACTIVE) == 0) { + if (!(gInputFlags & INPUT_FLAG_TOOL_ACTIVE)) { if (viewport_interaction_left_over(x, y)) { sub_6ED990(CURSOR_HAND_POINT); return; @@ -1153,7 +1153,7 @@ void process_mouse_over(int x, int y) */ void process_mouse_tool(int x, int y) { - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) + if (gInputFlags & INPUT_FLAG_TOOL_ACTIVE) { rct_window* w = window_find_by_number( RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), @@ -1185,7 +1185,7 @@ void input_state_widget_pressed(int x, int y, int state, int widgetIndex, rct_wi rct_window *cursor_w = window_find_by_number(cursor_w_class, cursor_w_number); if (cursor_w == NULL) { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 0; + gInputState = INPUT_STATE_RESET; return; } @@ -1207,14 +1207,14 @@ void input_state_widget_pressed(int x, int y, int state, int widgetIndex, rct_wi window_event_mouse_down_call(w, widgetIndex); } - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_WIDGET_PRESSED) return; + if (gInputFlags & INPUT_FLAG_WIDGET_PRESSED) return; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_WIDGET_PRESSED; + gInputFlags |= INPUT_FLAG_WIDGET_PRESSED; widget_invalidate_by_number(cursor_w_class, cursor_w_number, widgetIndex); return; case 3: case 2: - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) == 5) { + if (gInputState == INPUT_STATE_DROPDOWN_ACTIVE) { if (w) { int dropdown_index = 0; @@ -1236,9 +1236,9 @@ void input_state_widget_pressed(int x, int y, int state, int widgetIndex, rct_wi if (cursor_w_class != w->classification || cursor_w_number != w->number || widgetIndex != cursor_widgetIndex) goto dropdown_cleanup; dropdown_index = -1; - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_DROPDOWN_STAY_OPEN){ - if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_DROPDOWN_MOUSE_UP)){ - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_DROPDOWN_MOUSE_UP; + if (gInputFlags & INPUT_FLAG_DROPDOWN_STAY_OPEN){ + if (!(gInputFlags & INPUT_FLAG_DROPDOWN_MOUSE_UP)){ + gInputFlags |= INPUT_FLAG_DROPDOWN_MOUSE_UP; return; } } @@ -1246,16 +1246,16 @@ void input_state_widget_pressed(int x, int y, int state, int widgetIndex, rct_wi window_close_by_class(WC_DROPDOWN); cursor_w = window_find_by_number(cursor_w_class, cursor_w_number); - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_WIDGET_PRESSED) { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= 0xFFFE; + if (gInputFlags & INPUT_FLAG_WIDGET_PRESSED) { + gInputFlags &= ~INPUT_FLAG_WIDGET_PRESSED; widget_invalidate_by_number(cursor_w_class, cursor_w_number, cursor_widgetIndex); } - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 1; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = cursor_widgetIndex; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) = cursor_w_class; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) = cursor_w_number; + gInputState = INPUT_STATE_NORMAL; + gTooltipTimeout = 0; + gTooltipWidget.widget_index = cursor_widgetIndex; + gTooltipWidget.window_classification = cursor_w_class; + gTooltipWidget.window_number = cursor_w_number; window_event_dropdown_call(cursor_w, cursor_widgetIndex, dropdown_index); } dropdown_cleanup: @@ -1263,9 +1263,9 @@ void input_state_widget_pressed(int x, int y, int state, int widgetIndex, rct_wi } if (state == 3) return; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 1; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = cursor_widgetIndex; + gInputState = INPUT_STATE_NORMAL; + gTooltipTimeout = 0; + gTooltipWidget.widget_index = cursor_widgetIndex; if (!w) break; @@ -1288,10 +1288,10 @@ void input_state_widget_pressed(int x, int y, int state, int widgetIndex, rct_wi } RCT2_GLOBAL(0x9DE528, uint16) = 0; - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) != 5){ + if (gInputState != INPUT_STATE_DROPDOWN_ACTIVE){ // Hold down widget and drag outside of area?? - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_WIDGET_PRESSED){ - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= 0xFFFE; + if (gInputFlags & INPUT_FLAG_WIDGET_PRESSED){ + gInputFlags &= ~INPUT_FLAG_WIDGET_PRESSED; widget_invalidate_by_number(cursor_w_class, cursor_w_number, cursor_widgetIndex); } return; @@ -1328,36 +1328,34 @@ void input_state_widget_pressed(int x, int y, int state, int widgetIndex, rct_wi static void input_update_tooltip(rct_window *w, int widgetIndex, int x, int y) { - if (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) == 255) { - if (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, uint16) < 500 || - (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, sint16) == x && - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, sint16) == y) - ) { - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_LAST_UPDATE, uint16); + if (gTooltipWidget.window_classification == 255) { + if (gTooltipNotShownTicks < 500 || (gTooltipCursorX == x && gTooltipCursorY == y)) { + gTooltipTimeout = RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_LAST_UPDATE, uint16); - int bp = 2000; - if (RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, uint16) >= 1) - bp = 0; - if (bp > RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16)) { - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, sint16)++; + int time = 2000; + if (gTooltipNotShownTicks >= 1) { + time = 0; + } + if (time > gTooltipTimeout) { + gTooltipNotShownTicks++; return; } window_tooltip_open(w, widgetIndex, x, y); } - } - else { - 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 - ) { + } else { + if (( + (w != NULL) && + (gTooltipWidget.window_classification != w->classification || gTooltipWidget.window_number != w->number) + ) || + gTooltipWidget.widget_index != widgetIndex + ) { window_tooltip_close(); } - 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); + gTooltipTimeout += RCT2_GLOBAL(RCT2_ADDRESS_TICKS_SINCE_LAST_UPDATE, uint16); + if (gTooltipTimeout >= 8000) { + window_close_by_class(WC_TOOLTIP); + } } } @@ -1432,11 +1430,10 @@ void game_handle_keyboard_input() if (!gConsoleOpen) { // Handle mouse scrolling - if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) == 0) - if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_EDGE_SCROLLING, uint8) != 0) - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) == 1) - if (!(RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & 3)) - game_handle_edge_scroll(); + if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_EDGE_SCROLLING, uint8) != 0) + if (gInputState == INPUT_STATE_NORMAL) + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & 3)) + game_handle_edge_scroll(); // Handle modifier keys and key scrolling RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) = 0; @@ -1447,8 +1444,7 @@ void game_handle_keyboard_input() RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) |= 2; if (gKeysState[SDL_SCANCODE_LALT] || gKeysState[SDL_SCANCODE_RALT]) RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) |= 4; - if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) == 0) - game_handle_key_scroll(); + game_handle_key_scroll(); } } @@ -1478,8 +1474,6 @@ void game_handle_keyboard_input() w = window_find_by_class(WC_CHANGE_KEYBOARD_SHORTCUT); if (w != NULL) { keyboard_shortcut_set(key); - } else if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) == 1) { - tutorial_stop(); } else { w = window_find_by_class(WC_TEXTINPUT); if (w != NULL) { @@ -1489,10 +1483,6 @@ void game_handle_keyboard_input() } } } - - if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) != 0) { - game_handle_keyboard_input_for_tutorial(); - } } /** @@ -1519,7 +1509,7 @@ int get_next_key() * rct2: 0x006ED990 */ void sub_6ED990(char cursor_id){ - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) == INPUT_STATE_RESIZING) + if (gInputState == INPUT_STATE_RESIZING) { cursor_id = CURSOR_DIAGONAL_ARROWS; //resize icon } @@ -1613,11 +1603,11 @@ void game_handle_edge_scroll() // Scroll viewport if (scrollX != 0) { mainWindow->saved_view_x += scrollX * (12 << mainWindow->viewport->zoom); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_VIEWPORT_SCROLLING; + gInputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; } if (scrollY != 0) { mainWindow->saved_view_y += scrollY * (12 << mainWindow->viewport->zoom); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_VIEWPORT_SCROLLING; + gInputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; } } @@ -1682,30 +1672,10 @@ void game_handle_key_scroll() // Scroll viewport if (scrollX != 0) { mainWindow->saved_view_x += scrollX * (12 << mainWindow->viewport->zoom); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_VIEWPORT_SCROLLING; + gInputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; } if (scrollY != 0) { mainWindow->saved_view_y += scrollY * (12 << mainWindow->viewport->zoom); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_VIEWPORT_SCROLLING; - } -} - -/** - * - * rct2: 0x006E8346 - */ -static void update_cursor_position() -{ - switch (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8)) { - case 0: - // RCT2_GLOBAL(0x0142004C, sint32) = RCT2_GLOBAL(0x0142406C, sint32); - // RCT2_GLOBAL(0x01420050, sint32) = RCT2_GLOBAL(0x01424070, sint32); - break; - case 1: - // read tutorial cursor position - break; - case 2: - // write tutorial cursor position - break; + gInputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; } } diff --git a/src/input.h b/src/input.h index e6322a68e8..3caa9d8584 100644 --- a/src/input.h +++ b/src/input.h @@ -23,6 +23,19 @@ #include "interface/window.h" +enum { + INPUT_STATE_RESET, + INPUT_STATE_NORMAL, + INPUT_STATE_WIDGET_PRESSED, + INPUT_STATE_POSITIONING_WINDOW, + INPUT_STATE_VIEWPORT_RIGHT, + INPUT_STATE_DROPDOWN_ACTIVE, + INPUT_STATE_VIEWPORT_LEFT, + INPUT_STATE_SCROLL_LEFT, + INPUT_STATE_RESIZING, + INPUT_STATE_SCROLL_RIGHT +}; + enum { INPUT_FLAG_WIDGET_PRESSED = (1 << 0), @@ -47,10 +60,24 @@ enum { INPUT_FLAG_VIEWPORT_SCROLLING = (1 << 7) }; +typedef struct { + rct_windowclass window_classification; + rct_windownumber window_number; + uint8 widget_index; +} widget_ref; + +extern uint8 gInputState; +extern uint8 gInputFlags; + +extern uint16 gTooltipNotShownTicks; +extern uint16 gTooltipTimeout; +extern widget_ref gTooltipWidget; +extern sint32 gTooltipCursorX; +extern sint32 gTooltipCursorY; + void title_handle_keyboard_input(); void game_handle_input(); void game_handle_keyboard_input(); -void game_handle_keyboard_input_for_tutorial(); void store_mouse_input(int state); diff --git a/src/interface/keyboard_shortcut.c b/src/interface/keyboard_shortcut.c index 606b45a181..7308fac0eb 100644 --- a/src/interface/keyboard_shortcut.c +++ b/src/interface/keyboard_shortcut.c @@ -136,7 +136,7 @@ static void shortcut_cancel_construction_mode() window = window_find_by_class(WC_ERROR); if (window != NULL) window_close(window); - else if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) + else if (gInputFlags & INPUT_FLAG_TOOL_ACTIVE) tool_cancel(); } @@ -472,12 +472,14 @@ static void shortcut_screenshot() static void shortcut_reduce_game_speed() { - game_reduce_game_speed(); + if (network_get_mode() == NETWORK_MODE_NONE) + game_reduce_game_speed(); } static void shortcut_increase_game_speed() { - game_increase_game_speed(); + if (network_get_mode() == NETWORK_MODE_NONE) + game_increase_game_speed(); } static void shortcut_open_cheat_window() diff --git a/src/interface/title_sequences.c b/src/interface/title_sequences.c index 5d3b05cbb3..af66f7e731 100644 --- a/src/interface/title_sequences.c +++ b/src/interface/title_sequences.c @@ -63,9 +63,18 @@ void title_sequence_change_preset(int preset) if (preset >= 0 && preset < gConfigTitleSequences.num_presets) { switch (preset) { case 0: - gConfigInterface.current_title_sequence_preset = "*RCT2"; + gConfigInterface.current_title_sequence_preset = "*RCT1"; break; case 1: + gConfigInterface.current_title_sequence_preset = "*RCT1AA"; + break; + case 2: + gConfigInterface.current_title_sequence_preset = "*RCT1AALL"; + break; + case 3: + gConfigInterface.current_title_sequence_preset = "*RCT2"; + break; + case 4: gConfigInterface.current_title_sequence_preset = "*OPENRCT2"; break; default: diff --git a/src/interface/viewport.c b/src/interface/viewport.c index 91e9e21707..80f52a9439 100644 --- a/src/interface/viewport.c +++ b/src/interface/viewport.c @@ -22,6 +22,7 @@ #include "../config.h" #include "../drawing/drawing.h" #include "../drawing/supports.h" +#include "../input.h" #include "../localisation/localisation.h" #include "../ride/ride_data.h" #include "../ride/track_data.h" @@ -101,11 +102,11 @@ void viewport_init_all() RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_VIEWPORT_PTR_ARRAY, rct_viewport*) = NULL; // ? - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, sint8) = INPUT_STATE_RESET; + gInputFlags = 0; + gInputState = INPUT_STATE_RESET; RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWCLASS, rct_windowclass) = -1; - RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32) = -1; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, sint16) = -1; + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_IMAGE, sint32) = -1; + gTooltipNotShownTicks = -1; RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, sint16) = 0; RCT2_GLOBAL(0x009DEA50, sint16) = -1; textinput_cancel(); diff --git a/src/interface/viewport_interaction.c b/src/interface/viewport_interaction.c index b8ef2602e1..c9f96379a4 100644 --- a/src/interface/viewport_interaction.c +++ b/src/interface/viewport_interaction.c @@ -272,7 +272,7 @@ int viewport_interaction_get_item_right(int x, int y, viewport_interaction_info return info->type; } - if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & (INPUT_FLAG_6 | INPUT_FLAG_TOOL_ACTIVE)) != (INPUT_FLAG_6 | INPUT_FLAG_TOOL_ACTIVE)) + if ((gInputFlags & INPUT_FLAG_6) && (gInputFlags & INPUT_FLAG_TOOL_ACTIVE)) if (window_find_by_class(WC_RIDE_CONSTRUCTION) == NULL && window_find_by_class(WC_FOOTPATH) == NULL) return info->type = VIEWPORT_INTERACTION_ITEM_NONE; @@ -291,7 +291,7 @@ int viewport_interaction_get_item_right(int x, int y, viewport_interaction_info return info->type; case VIEWPORT_INTERACTION_ITEM_FOOTPATH_ITEM: - sceneryEntry = g_pathBitSceneryEntries[(mapElement->properties.path.additions & 0x0F) - 1]; + sceneryEntry = g_pathBitSceneryEntries[footpath_element_get_path_scenery_index(mapElement)]; RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 0, uint16) = 1164; if (mapElement->flags & 0x20) { RCT2_GLOBAL(RCT2_ADDRESS_MAP_TOOLTIP_ARGS + 2, uint16) = 3124; diff --git a/src/interface/widget.c b/src/interface/widget.c index a07bba487e..6175540dee 100644 --- a/src/interface/widget.c +++ b/src/interface/widget.c @@ -978,7 +978,7 @@ int widget_is_disabled(rct_window *w, int widgetIndex) int widget_is_pressed(rct_window *w, int widgetIndex) { - int inputState = RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8); + int inputState = gInputState; if (w->pressed_widgets & (1LL << widgetIndex)) return 1; @@ -987,7 +987,7 @@ int widget_is_pressed(rct_window *w, int widgetIndex) return 0; if (RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WINDOWNUMBER, rct_windownumber) != w->number) return 0; - if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_WIDGET_PRESSED)) + if (!(gInputFlags & INPUT_FLAG_WIDGET_PRESSED)) return 0; if (RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, sint32) == widgetIndex) return 1; @@ -1008,7 +1008,7 @@ int widget_is_highlighted(rct_window *w, int widgetIndex) int widget_is_active_tool(rct_window *w, int widgetIndex) { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) + if (!(gInputFlags & INPUT_FLAG_TOOL_ACTIVE)) return 0; if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != w->classification) return 0; diff --git a/src/interface/window.c b/src/interface/window.c index 54d69c2cad..bb38986147 100644 --- a/src/interface/window.c +++ b/src/interface/window.c @@ -41,7 +41,7 @@ rct_window* g_window_list = RCT2_ADDRESS(RCT2_ADDRESS_WINDOW_LIST, rct_window); -uint8 TextInputDescriptionArgs[8]; +uint16 TextInputDescriptionArgs[4]; widget_identifier gCurrentTextBox = { { 255, 0 }, 0 }; char gTextBoxInput[512] = { 0 }; int gMaxTextBoxInputLength = 0; @@ -150,7 +150,7 @@ void window_dispatch_update_all() rct_window *w; RCT2_GLOBAL(0x01423604, sint32)++; - //RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, sint16)++; + // gTooltipNotShownTicks++; for (w = RCT2_LAST_WINDOW; w >= g_window_list; w--) window_event_update_call(w); } @@ -306,7 +306,7 @@ static void window_all_wheel_input() return; // Check window cursor is over - if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_5)) { + if (!(gInputFlags & INPUT_FLAG_5)) { w = window_find_from_point(gCursorState.x, gCursorState.y); if (w != NULL) { // Check if main window @@ -1727,7 +1727,7 @@ void window_set_resize(rct_window *w, int minWidth, int minHeight, int maxWidth, */ int tool_set(rct_window *w, int widgetIndex, int tool) { - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) { + if (gInputFlags & 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) && @@ -1740,8 +1740,8 @@ int tool_set(rct_window *w, int widgetIndex, int tool) } } - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_TOOL_ACTIVE; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_TOOL_ACTIVE; + gInputFlags &= ~INPUT_FLAG_6; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = tool; RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) = w->classification; RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) = w->number; @@ -1757,8 +1757,8 @@ void tool_cancel() { rct_window *w; - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_TOOL_ACTIVE; + if (gInputFlags & INPUT_FLAG_TOOL_ACTIVE) { + gInputFlags &= ~INPUT_FLAG_TOOL_ACTIVE; map_invalidate_selection_rect(); map_invalidate_map_selection_tiles(); diff --git a/src/interface/window.h b/src/interface/window.h index e538d69091..b8a44147a1 100644 --- a/src/interface/window.h +++ b/src/interface/window.h @@ -27,11 +27,13 @@ #include "../ride/ride.h" #include "../ride/vehicle.h" #include "../world/park.h" +#include "../management/research.h" +#include "../scenario.h" #include "colour.h" struct rct_window; union rct_window_event; -extern uint8 TextInputDescriptionArgs[8]; +extern uint16 TextInputDescriptionArgs[4]; extern char gTextBoxInput[512]; extern int gMaxTextBoxInputLength; extern int gTextBoxFrameNo; @@ -260,11 +262,23 @@ typedef struct rct_window { error_variables error; }; sint16 page; // 0x48A - sint16 var_48C; + union { + sint16 picked_peep_old_x; // 0x48C staff/guest window: peep x gets set to 0x8000 on pickup, this is the old value + sint16 var_48C; + }; uint16 frame_no; // 0x48E updated every tic for motion in windows sprites uint16 list_information_type; // 0x490 0 for none, Used as current position of marquee in window_peep - sint16 var_492; - uint32 highlighted_item; // 0x494 + union { + sint16 picked_peep_frame; // 0x492 Animation frame of picked peep in staff window and guest window + sint16 var_492; + }; + union { // 0x494 + uint32 highlighted_item; + uint16 ride_colour; + rct_research_item* research_item; + rct_object_entry* object_entry; + scenario_index_entry* highlighted_scenario; + }; uint8 var_498[0x14]; sint16 selected_tab; // 0x4AC sint16 var_4AE; @@ -372,19 +386,6 @@ enum { SCROLL_PART_VSCROLLBAR_THUMB = 10, }; -enum { - INPUT_STATE_RESET = 0, - INPUT_STATE_NORMAL = 1, - INPUT_STATE_WIDGET_PRESSED = 2, - INPUT_STATE_POSITIONING_WINDOW = 3, - INPUT_STATE_VIEWPORT_RIGHT = 4, - INPUT_STATE_DROPDOWN_ACTIVE = 5, - INPUT_STATE_VIEWPORT_LEFT = 6, - INPUT_STATE_SCROLL_LEFT = 7, - INPUT_STATE_RESIZING = 8, - INPUT_STATE_SCROLL_RIGHT = 9 -}; - enum { WC_MAIN_WINDOW = 0, WC_TOP_TOOLBAR = 1, diff --git a/src/localisation/language.cpp b/src/localisation/language.cpp index f9d36eb779..dc70f285cd 100644 --- a/src/localisation/language.cpp +++ b/src/localisation/language.cpp @@ -47,6 +47,13 @@ enum { RCT2_LANGUAGE_ID_END = 255 }; +static TTFFontSetDescriptor TTFFontMSGothic = {{ + { "msgothic_02.ttf", "MS PGothic", 9, 1, 0, 15, nullptr }, + { "msgothic_02.ttf", "MS PGothic", 12, 1, 0, 17, nullptr }, + { "msgothic_02.ttf", "MS PGothic", 12, 1, 0, 17, nullptr }, + { "msgothic_02.ttf", "MS PGothic", 13, 1, 0, 20, nullptr }, +}}; + static TTFFontSetDescriptor TTFFontMingLiu = {{ { "msjh.ttc", "JhengHei", 9, -1, -3, 6, nullptr }, { "mingliu.ttc", "MingLiU", 11, 1, 1, 12, nullptr }, @@ -94,6 +101,7 @@ const language_descriptor LanguagesDescriptors[LANGUAGE_COUNT] = { { "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 + { "jp-JP", "Japanese", "Japanese", "japanese", &TTFFontMSGothic, RCT2_LANGUAGE_ID_ENGLISH_UK }, // LANGUAGE_JAPANESE }; int gCurrentLanguage = LANGUAGE_UNDEFINED; diff --git a/src/localisation/language.h b/src/localisation/language.h index 3adf76de0f..deb19f23a3 100644 --- a/src/localisation/language.h +++ b/src/localisation/language.h @@ -43,6 +43,7 @@ enum { LANGUAGE_KOREAN, LANGUAGE_RUSSIAN, LANGUAGE_CZECH, + LANGUAGE_JAPANESE, LANGUAGE_COUNT }; diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h index ba7d04c483..9e24822c28 100644 --- a/src/localisation/string_ids.h +++ b/src/localisation/string_ids.h @@ -1527,8 +1527,6 @@ enum { STR_ENTRANCE_NOT_CONNECTED = 2854, STR_EXIT_NOT_CONNECTED = 2855, - STR_TUTORIAL = 2856, - STR_PRESS_KEY_OR_MOUSE_BUTTON_FOR_CONTROL = 2857, STR_CANT_START_MARKETING_CAMPAIGN = 2858, STR_INFOGRAMES_INTERACTIVE_CREDITS = 2860, @@ -1878,10 +1876,6 @@ enum { STR_INSTALL_NEW_TRACK_DESIGN = 3376, STR_INSTALL_NEW_TRACK_DESIGN_TIP = 3377, - STR_TUTORIAL_BEGINNERS = 3385, - STR_TUTORIAL_CUSTOM_RIDES = 3386, - STR_TUTORIAL_ROLLER_COASTER = 3387, - STR_SAVE_TRACK_SCENERY_UNABLE_TO_SELECT_ADDITIONAL_ITEM_OF_SCENERY = 3389, STR_SAVE_TRACK_SCENERY_TOO_MANY_ITEMS_SELECTED = 3390, @@ -2004,9 +1998,17 @@ enum { 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_BASE_HEIGHT_SHORT = 5608, + STR_TILE_INSPECTOR_CLEARANCE_HEIGHT = 5340, + STR_TILE_INSPECTOR_CLEARANGE_HEIGHT_SHORT = 5609, STR_TILE_INSPECTOR_FLAGS = 5341, STR_TILE_INSPECTOR_CHOOSE_MSG = 5342, + STR_TILE_INSPECTOR_FLAG_GHOST_SHORT = 5611, + STR_TILE_INSPECTOR_FLAG_GHOST = 5612, + STR_TILE_INSPECTOR_FLAG_BROKEN_SHORT = 5613, + STR_TILE_INSPECTOR_FLAG_BROKEN = 5614, + STR_TILE_INSPECTOR_FLAG_LAST_SHORT = 5615, + STR_TILE_INSPECTOR_FLAG_LAST = 5616, STR_AUTO_STAFF_PLACEMENT = 5343, @@ -2232,6 +2234,23 @@ enum { STR_NOTIFICATION_GUEST_USED_FACILITY = 5605, STR_NOTIFICATION_GUEST_DIED = 5606, + STR_SCENARIO_CATEGORY_RCT1 = 5619, + STR_SCENARIO_CATEGORY_RCT1_AA = 5620, + STR_SCENARIO_CATEGORY_RCT1_LL = 5621, + STR_SCENARIO_CATEGORY_RCT2 = 5622, + STR_SCENARIO_CATEGORY_RCT2_WW = 5623, + STR_SCENARIO_CATEGORY_RCT2_TT = 5624, + STR_SCENARIO_CATEGORY_REAL_PARKS = 5625, + STR_SCENARIO_CATEGORY_OTHER_PARKS = 5626, + + STR_OPTIONS_SCENARIO_GROUPING = 5627, + STR_OPTIONS_SCENARIO_ORIGIN = 5628, + STR_OPTIONS_SCENARIO_DIFFICULTY = 5629, + STR_OPTIONS_SCENARIO_UNLOCKING = 5630, + + STR_DLC_PARKS = 5631, + STR_BUILD_YOUR_OWN_PARKS = 5632, + // 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/management/marketing.c b/src/management/marketing.c index 7e3a4a16be..55cf24c521 100644 --- a/src/management/marketing.c +++ b/src/management/marketing.c @@ -155,6 +155,13 @@ void game_command_start_campaign(int* eax, int* ebx, int* ecx, int* edx, int* es int rideOrItem = (*edx >> 8) & 0xFF; int numWeeks = (*ebx >> 8) & 0xFF; + if (type < 0 || type >= countof(AdvertisingCampaignPricePerWeek)) + { + log_warning("Invalid game command, type = %d", type); + *ebx = MONEY32_UNDEFINED; + return; + } + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_MARKETING * 4; if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_FORBID_MARKETING_CAMPAIGN) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 3048; diff --git a/src/management/news_item.c b/src/management/news_item.c index a855bcbdf2..df7b1de3e9 100644 --- a/src/management/news_item.c +++ b/src/management/news_item.c @@ -379,7 +379,7 @@ void news_item_open_subject(int type, int subject) if (window != NULL) { window_invalidate(window); if (!tool_set(window, 9, 0)) { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_6; window_scenery_open(); } } diff --git a/src/object.c b/src/object.c index c091a2ec42..4025d56768 100644 --- a/src/object.c +++ b/src/object.c @@ -358,17 +358,15 @@ int object_entry_compare(const rct_object_entry *a, const rct_object_entry *b) if (a->flags & 0xF0) { if ((a->flags & 0x0F) != (b->flags & 0x0F)) return 0; - if (*((uint32*)a->name) != *((uint32*)b->name)) - return 0; - if (*((uint32*)(&a->name[4])) != *((uint32*)(&b->name[4]))) + int match = memcmp(a->name, b->name, 8); + if (match) return 0; } else { if (a->flags != b->flags) return 0; - if (*((uint32*)a->name) != *((uint32*)b->name)) - return 0; - if (*((uint32*)(&a->name[4])) != *((uint32*)(&b->name[4]))) + int match = memcmp(a->name, b->name, 8); + if (match) return 0; if (a->checksum != b->checksum) return 0; diff --git a/src/openrct2.c b/src/openrct2.c index eb41a4457f..469a610c29 100644 --- a/src/openrct2.c +++ b/src/openrct2.c @@ -203,7 +203,7 @@ bool openrct2_initialise() gOpenRCT2ShowChangelog = true; if (gConfigGeneral.last_run_version != NULL && (strcmp(gConfigGeneral.last_run_version, OPENRCT2_VERSION) == 0)) gOpenRCT2ShowChangelog = false; - gConfigGeneral.last_run_version = OPENRCT2_VERSION; + gConfigGeneral.last_run_version = strndup(OPENRCT2_VERSION, strlen(OPENRCT2_VERSION)); config_save_default(); // TODO add configuration option to allow multiple instances diff --git a/src/peep/peep.c b/src/peep/peep.c index 3828a234d0..1a985b1f54 100644 --- a/src/peep/peep.c +++ b/src/peep/peep.c @@ -200,11 +200,11 @@ static uint8 peep_assess_surroundings(sint16 center_x, sint16 center_y, sint16 c switch (map_element_get_type(mapElement)){ case MAP_ELEMENT_TYPE_PATH: - if ((mapElement->properties.path.additions & 0xF) == 0) + if (!footpath_element_has_path_scenery(mapElement)) break; - scenery = g_pathBitSceneryEntries[(mapElement->properties.path.additions & 0x0F) - 1]; - if (mapElement->properties.path.additions & (1 << 7)) + scenery = g_pathBitSceneryEntries[footpath_element_get_path_scenery_index(mapElement)]; + if (footpath_element_path_scenery_is_ghost(mapElement)) break; if (scenery->path_bit.var_06 & @@ -620,9 +620,10 @@ static void sub_68F41A(rct_peep *peep, int index) 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]; + // Check if the footpath has ghost path scenery on it + if (footpath_element_has_path_scenery(mapElement) && footpath_element_path_scenery_is_ghost(mapElement)){ + uint8 pathSceneryIndex = footpath_element_get_path_scenery_index(mapElement); + rct_scenery_entry *sceneryEntry = g_pathBitSceneryEntries[pathSceneryIndex]; if (sceneryEntry->path_bit.var_06 & (1 << 8)){ found = 1; } @@ -803,10 +804,17 @@ static void sub_68F41A(rct_peep *peep, int index) } } -/* some sort of check to see if peep is connected to the ground?? */ -int sub_68F3AE(rct_peep* peep){ +/* + * rct2: 0x68F3AE + * Set peep state to falling if path below has gone missing, return 1 if current path is valid, 0 if peep starts falling + */ +int checkForPath(rct_peep *peep){ peep->var_C4++; - if ((peep->var_C4 & 0xF) != (peep->sprite_index & 0xF))return 1; + if ((peep->var_C4 & 0xF) != (peep->sprite_index & 0xF)){ + // This condition makes the check happen less often so the peeps hover for a short, + // random time when a path below them has been deleted + return 1; + } rct_map_element* map_element = map_get_first_element_at(peep->next_x / 32, peep->next_y / 32); @@ -819,10 +827,14 @@ int sub_68F3AE(rct_peep* peep){ do { if (map_element_get_type(map_element) == map_type){ - if (z == map_element->base_height)return 1; + if (z == map_element->base_height) { + // Found a suitable path + return 1; + } } } while (!map_element_is_last_for_tile(map_element++)); + // Found no suitable path peep_decrement_num_riders(peep); peep->state = PEEP_STATE_FALLING; peep_window_state_update(peep); @@ -830,31 +842,31 @@ int sub_68F3AE(rct_peep* peep){ } void sub_693B58(rct_peep* peep){ - int ebx; - if (peep->action >= 0xFE){ - ebx = RCT2_ADDRESS(0x981D8C, uint8)[peep->var_6D]; + uint8 action_sprite_type; + if (peep->action >= PEEP_ACTION_NONE_1){ // PEEP_ACTION_NONE_1 or PEEP_ACTION_NONE_2 + action_sprite_type = RCT2_ADDRESS(0x981D8C, uint8)[peep->special_sprite]; } else{ - ebx = RCT2_ADDRESS(0x981D8F, uint8)[peep->action]; + action_sprite_type = RCT2_ADDRESS(0x981D8F, uint8)[peep->action]; } - if (ebx == peep->action_sprite_type)return; + if (action_sprite_type == peep->action_sprite_type)return; invalidate_sprite_2((rct_sprite*)peep); - peep->action_sprite_type = ebx; + peep->action_sprite_type = action_sprite_type; - uint8* edx = RCT2_ADDRESS(0x98270C, uint8*)[peep->sprite_type * 2]; - peep->sprite_width = edx[ebx * 4]; - peep->sprite_height_negative = edx[ebx * 4 + 1]; - peep->sprite_height_positive = edx[ebx * 4 + 2]; + rct_sprite_bounds* spriteBounds = g_sprite_entries[peep->sprite_type].sprite_bounds; + peep->sprite_width = spriteBounds[action_sprite_type].sprite_width; + peep->sprite_height_negative = spriteBounds[action_sprite_type].sprite_height_negative; + peep->sprite_height_positive = spriteBounds[action_sprite_type].sprite_height_positive; // This is pointless as nothing will have changed. invalidate_sprite_2((rct_sprite*)peep); } /* 0x00693BE5 */ void sub_693BE5(rct_peep* peep, uint8 al){ - if (al == peep->var_6D)return; + if (al == peep->special_sprite)return; - peep->var_6D = al; + peep->special_sprite = al; // If NONE_1 or NONE_2 if (peep->action >= PEEP_ACTION_NONE_1){ @@ -998,8 +1010,8 @@ int peep_update_action(sint16* x, sint16* y, sint16* xy_distance, rct_peep* peep *x = peep->x + RCT2_ADDRESS(0x981D7C, uint16)[direction / 4]; *y = peep->y + RCT2_ADDRESS(0x981D7E, uint16)[direction / 4]; peep->no_action_frame_no++; - uint32* edi = RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2]; - uint8* _edi = (uint8*)(edi[peep->action_sprite_type * 2 + 1]); + rct_sprite_image * edi = g_sprite_entries[peep->sprite_type].sprite_image; + uint8* _edi = (edi[peep->action_sprite_type]).unkn_04; if (peep->no_action_frame_no >= *_edi){ peep->no_action_frame_no = 0; } @@ -1007,8 +1019,8 @@ int peep_update_action(sint16* x, sint16* y, sint16* xy_distance, rct_peep* peep return 1; } - uint32* edi = RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2]; - uint8* _edi = (uint8*)(edi[peep->action_sprite_type * 2 + 1]); + rct_sprite_image * edi = g_sprite_entries[peep->sprite_type].sprite_image; + uint8* _edi = (edi[peep->action_sprite_type]).unkn_04; peep->action_frame++; int ebx = _edi[peep->action_frame + 1]; @@ -1090,12 +1102,12 @@ void set_sprite_type(rct_peep* peep, uint8 type){ if (peep->state == PEEP_STATE_SITTING){ peep->action = PEEP_ACTION_NONE_1; - peep->var_6F = 7; + peep->next_action_sprite_type = 7; sub_693BAB(peep); } if (peep->state == PEEP_STATE_WATCHING){ peep->action = PEEP_ACTION_NONE_1; - peep->var_6F = 2; + peep->next_action_sprite_type = 2; sub_693BAB(peep); } } @@ -1458,7 +1470,7 @@ void peep_try_get_up_from_sitting(rct_peep* peep){ */ void peep_update_sitting(rct_peep* peep){ if (peep->sub_state == 0){ - if (!sub_68F3AE(peep))return; + if (!checkForPath(peep))return; //691541 sub_693C9E(peep); @@ -1475,7 +1487,7 @@ void peep_update_sitting(rct_peep* peep){ peep->sprite_direction = ((peep->var_37 + 2) & 3) * 8; invalidate_sprite_2((rct_sprite*)peep); peep->action = 254; - peep->var_6F = 7; + peep->next_action_sprite_type = 7; sub_693BAB(peep); peep->sub_state++; @@ -3414,7 +3426,7 @@ static void peep_update_fixing(int steps, rct_peep* peep){ * rct2: 0x69185D */ static void peep_update_queuing(rct_peep* peep){ - if (!sub_68F3AE(peep)){ + if (!checkForPath(peep)){ remove_peep_from_queue(peep); return; } @@ -3465,7 +3477,7 @@ static void peep_update_queuing(rct_peep* peep){ } } else{ - if (!(peep->time_in_queue & 0x3F) && peep->action == 0xFE && peep->var_6F == 2){ + if (!(peep->time_in_queue & 0x3F) && peep->action == 0xFE && peep->next_action_sprite_type == 2){ switch (peep->sprite_type){ case 0xF: case 0x10: @@ -3518,7 +3530,7 @@ static void peep_update_queuing(rct_peep* peep){ */ static void peep_update_mowing(rct_peep* peep){ peep->var_E2 = 0; - if (!sub_68F3AE(peep))return; + if (!checkForPath(peep))return; invalidate_sprite_2((rct_sprite*)peep); while (1){ @@ -3566,7 +3578,7 @@ static void peep_update_mowing(rct_peep* peep){ static void peep_update_watering(rct_peep* peep){ peep->var_E2 = 0; if (peep->sub_state == 0){ - if (!sub_68F3AE(peep))return; + if (!checkForPath(peep))return; sub_693C9E(peep); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return; @@ -3622,7 +3634,7 @@ static void peep_update_emptying_bin(rct_peep* peep){ peep->var_E2 = 0; if (peep->sub_state == 0){ - if (!sub_68F3AE(peep))return; + if (!checkForPath(peep))return; sub_693C9E(peep); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return; @@ -3661,16 +3673,16 @@ static void peep_update_emptying_bin(rct_peep* peep){ } } - if ((map_element->properties.path.additions & 0x0F) == 0) { + if (!footpath_element_has_path_scenery(map_element)) { peep_state_reset(peep); return; } - rct_scenery_entry* scenery_entry = g_pathBitSceneryEntries[(map_element->properties.path.additions & 0xF) - 1]; + rct_scenery_entry* scenery_entry = g_pathBitSceneryEntries[footpath_element_get_path_scenery_index(map_element)]; if ( !(scenery_entry->path_bit.var_06 & 1) || map_element->flags & (1 << 5) - || map_element->properties.path.additions & (1 << 7) + || footpath_element_path_scenery_is_ghost(map_element) ) { peep_state_reset(peep); return; @@ -3691,7 +3703,7 @@ 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; + if (!checkForPath(peep))return; invalidate_sprite_2((rct_sprite*)peep); @@ -3726,7 +3738,7 @@ static void peep_update_sweeping(rct_peep* peep){ * rct2: 0x6902A2 */ static void peep_update_1(rct_peep* peep){ - if (!sub_68F3AE(peep))return; + if (!checkForPath(peep))return; peep_decrement_num_riders(peep); @@ -3795,7 +3807,7 @@ static void peep_update_leaving_park(rct_peep* peep){ */ static void peep_update_watching(rct_peep* peep){ if (peep->sub_state == 0){ - if (!sub_68F3AE(peep))return; + if (!checkForPath(peep))return; sub_693C9E(peep); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return; @@ -3807,7 +3819,7 @@ static void peep_update_watching(rct_peep* peep){ invalidate_sprite_2((rct_sprite*)peep); peep->action = 0xFE; - peep->var_6F = 2; + peep->next_action_sprite_type = 2; sub_693BAB(peep); @@ -3925,16 +3937,14 @@ static int peep_update_walking_find_bench(rct_peep* peep){ } } - uint8 additions = map_element->properties.path.additions & 0xF; - - if (!additions) return 0; - rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + if (!footpath_element_has_path_scenery(map_element)) return 0; + rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[footpath_element_get_path_scenery_index(map_element)]; if (!(sceneryEntry->path_bit.var_06 & 0x2))return 0; if (map_element->flags & MAP_ELEMENT_FLAG_BROKEN)return 0; - if (map_element->properties.path.additions & 0x80)return 0; + if (footpath_element_path_scenery_is_ghost(map_element)) return 0; int edges = (map_element->properties.path.edges & 0xF) ^ 0xF; if (edges == 0) return 0; @@ -4002,16 +4012,14 @@ static int peep_update_walking_find_bin(rct_peep* peep){ } } - uint8 additions = map_element->properties.path.additions & 0xF; - - if (!additions) return 0; - rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + if (!footpath_element_has_path_scenery(map_element)) return 0; + rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[footpath_element_get_path_scenery_index(map_element)]; if (!(sceneryEntry->path_bit.var_06 & 0x1))return 0; if (map_element->flags & MAP_ELEMENT_FLAG_BROKEN)return 0; - if (map_element->properties.path.additions & 0x80)return 0; + if (footpath_element_path_scenery_is_ghost(map_element)) return 0; int edges = (map_element->properties.path.edges & 0xF) ^ 0xF; if (edges == 0) return 0; @@ -4085,16 +4093,14 @@ static void peep_update_walking_break_scenery(rct_peep* peep){ } } - uint8 additions = map_element->properties.path.additions & 0xF; - - if (!additions) return; - rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + if (!footpath_element_has_path_scenery(map_element)) return; + rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[footpath_element_get_path_scenery_index(map_element)]; if (!(sceneryEntry->path_bit.var_06 & 0x4))return; if (map_element->flags & MAP_ELEMENT_FLAG_BROKEN)return; - if (map_element->properties.path.additions & 0x80)return; + if (footpath_element_path_scenery_is_ghost(map_element))return; int edges = map_element->properties.path.edges & 0xF; if (edges == 0xF) return; @@ -4132,7 +4138,7 @@ static void peep_update_walking_break_scenery(rct_peep* peep){ */ static void peep_update_buying(rct_peep* peep) { - if (!sub_68F3AE(peep))return; + if (!checkForPath(peep))return; rct_ride* ride = GET_RIDE(peep->current_ride); if (ride->type == RIDE_TYPE_NULL || ride->status != RIDE_STATUS_OPEN){ @@ -4225,7 +4231,7 @@ static void peep_update_buying(rct_peep* peep) */ static void peep_update_using_bin(rct_peep* peep){ if (peep->sub_state == 0){ - if (!sub_68F3AE(peep))return; + if (!checkForPath(peep))return; sub_693C9E(peep); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return; @@ -4255,13 +4261,12 @@ static void peep_update_using_bin(rct_peep* peep){ } } - uint8 additions = map_element->properties.path.additions & 0x0F; - if (!additions){ + if (!footpath_element_has_path_scenery(map_element)){ peep_state_reset(peep); return; } - rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[footpath_element_get_path_scenery_index(map_element)]; if (!(sceneryEntry->path_bit.var_06 & 1)){ peep_state_reset(peep); return; @@ -4272,7 +4277,7 @@ static void peep_update_using_bin(rct_peep* peep){ return; } - if (map_element->properties.path.additions & 0x80){ + if (footpath_element_path_scenery_is_ghost(map_element)){ peep_state_reset(peep); return; } @@ -4400,7 +4405,7 @@ static void peep_update_heading_to_inspect(rct_peep* peep){ return; } - if (!sub_68F3AE(peep))return; + if (!checkForPath(peep))return; sub_693C9E(peep); @@ -4513,7 +4518,7 @@ static void peep_update_answering(rct_peep* peep){ return; } - if (!sub_68F3AE(peep))return; + if (!checkForPath(peep))return; sub_693C9E(peep); @@ -4656,11 +4661,8 @@ static int peep_update_patrolling_find_bin(rct_peep* peep){ return 0; } - uint8 additions = map_element->properties.path.additions & 0xF; - - if (additions == 0)return 0; - - rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + if (!footpath_element_has_path_scenery(map_element)) return 0; + rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[footpath_element_get_path_scenery_index(map_element)]; if (!(sceneryEntry->path_bit.var_06 & 1)) return 0; @@ -4668,7 +4670,7 @@ static int peep_update_patrolling_find_bin(rct_peep* peep){ if (map_element->flags & MAP_ELEMENT_FLAG_BROKEN) return 0; - if (map_element->properties.path.additions & 0x80) + if (footpath_element_path_scenery_is_ghost(map_element)) return 0; uint8 bin_positions = map_element->properties.path.edges & 0xF; @@ -4768,7 +4770,7 @@ static int peep_update_patrolling_find_sweeping(rct_peep* peep){ */ static void peep_update_patrolling(rct_peep* peep){ - if (!sub_68F3AE(peep))return; + if (!checkForPath(peep))return; sub_693C9E(peep); if (!(RCT2_GLOBAL(0xF1EE18, uint16) & 1))return; @@ -4808,7 +4810,7 @@ static void peep_update_patrolling(rct_peep* peep){ * rct2: 0x0069030A */ static void peep_update_walking(rct_peep* peep){ - if (!sub_68F3AE(peep))return; + if (!checkForPath(peep))return; if (peep->flags & PEEP_FLAGS_WAVING){ if (peep->action >= PEEP_ACTION_NONE_1){ @@ -4958,13 +4960,11 @@ static void peep_update_walking(rct_peep* peep){ } } - uint8 additions = map_element->properties.path.additions & 0xF; - int ebp = 15; - if (additions){ - if (!(map_element->properties.path.additions & 0x80)){ - rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + if (footpath_element_has_path_scenery(map_element)) { + if (!footpath_element_path_scenery_is_ghost(map_element)) { + rct_scenery_entry* sceneryEntry = g_pathBitSceneryEntries[footpath_element_get_path_scenery_index(map_element)]; if (!(sceneryEntry->path_bit.var_06 & 0x2)) ebp = 9; } @@ -5484,7 +5484,7 @@ rct_peep *peep_generate(int x, int y, int z) peep->outside_of_park = 1; peep->state = PEEP_STATE_FALLING; peep->action = PEEP_ACTION_NONE_2; - peep->var_6D = 0; + peep->special_sprite = 0; peep->action_sprite_image_offset = 0; peep->no_action_frame_no = 0; peep->action_sprite_type = 0; @@ -5492,10 +5492,10 @@ rct_peep *peep_generate(int x, int y, int z) peep->favourite_ride = 0xFF; peep->favourite_ride_rating = 0; - uint8* edx = RCT2_ADDRESS(0x98270C, uint8*)[peep->sprite_type * 2]; - peep->sprite_width = edx[peep->action_sprite_type * 4]; - peep->sprite_height_negative = edx[peep->action_sprite_type * 4 + 1]; - peep->sprite_height_positive = edx[peep->action_sprite_type * 4 + 2]; + rct_sprite_bounds* spriteBounds = g_sprite_entries[peep->sprite_type].sprite_bounds; + peep->sprite_width = spriteBounds[peep->action_sprite_type].sprite_width; + peep->sprite_height_negative = spriteBounds[peep->action_sprite_type].sprite_height_negative; + peep->sprite_height_positive = spriteBounds[peep->action_sprite_type].sprite_height_positive; peep->sprite_direction = 0; @@ -6160,14 +6160,15 @@ 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) { + // TBD: Add nextActionSpriteType as function parameter and make peep->next_action_sprite_type obsolete? + uint8 nextActionSpriteType = peep->next_action_sprite_type; + if (nextActionSpriteType != peep->action_sprite_type) { 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]; + peep->action_sprite_type = nextActionSpriteType; + rct_sprite_bounds* spriteBounds = g_sprite_entries[peep->sprite_type].sprite_bounds; + peep->sprite_width = spriteBounds[nextActionSpriteType].sprite_width; + peep->sprite_height_negative = spriteBounds[nextActionSpriteType].sprite_height_negative; + peep->sprite_height_positive = spriteBounds[nextActionSpriteType].sprite_height_positive; invalidate_sprite_2((rct_sprite*)peep); } } @@ -6235,7 +6236,7 @@ static int peep_update_queue_position(rct_peep* peep){ return 1; peep->action = PEEP_ACTION_NONE_1; - peep->var_6F = 2; + peep->next_action_sprite_type = 2; if (RCT2_GLOBAL(0x00F1AEF1, uint8) != 0xFE) invalidate_sprite_2((rct_sprite*)peep); return 1; @@ -6629,7 +6630,7 @@ static int peep_interact_with_path(rct_peep* peep, sint16 x, sint16 y, rct_map_e // 0x00F1AEE2 bool vandalism_present = false; - if ((map_element->properties.path.additions & 0xF) != 0 && + if (footpath_element_has_path_scenery(map_element) && (map_element->flags & MAP_ELEMENT_FLAG_BROKEN) && (map_element->properties.path.edges & 0xF) != 0xF){ vandalism_present = 1; diff --git a/src/peep/peep.h b/src/peep/peep.h index 3ccd25f3f8..a1cb664d00 100644 --- a/src/peep/peep.h +++ b/src/peep/peep.h @@ -372,6 +372,12 @@ enum { PEEP_RIDE_DECISION_THINKING = 1 << 2 }; +// Flags used by peep->list_flags +enum { + PEEP_LIST_FLAGS_VISIBLE = 1 << 8, // Peep is eligible to show in summarized guest list window (is inside park?) + PEEP_LIST_FLAGS_FLASHING = 1 << 9, // Peep belongs to highlighted group (flashes red on map) +}; + typedef struct { uint8 type; //0 uint8 item; //1 @@ -389,7 +395,7 @@ typedef struct { // Height from center of sprite to bottom uint8 sprite_height_negative; // 0x09 uint16 sprite_index; // 0x0A - uint16 var_0C; + uint16 list_flags; // 0x0C Used for highlighting peeps on map with staff list or guest list open sint16 x; // 0x0E sint16 y; // 0x10 sint16 z; // 0x12 @@ -458,9 +464,11 @@ typedef struct { uint8 standing_flags; //0x6C }; }; - uint8 var_6D; // 0x6D + // Normally 0, 1 for carrying sliding board on spiral slide ride, 2 for carrying lawn mower + uint8 special_sprite; // 0x6D uint8 action_sprite_type; // 0x6E - uint8 var_6F; + // Seems to be used like a local variable, as it's always set before calling sub_693BAB, which reads this again + uint8 next_action_sprite_type; // 0x6F uint8 action_sprite_image_offset; // 0x70 uint8 action; // 0x71 uint8 action_frame; // 0x72 @@ -488,7 +496,7 @@ typedef struct { uint8 previous_ride; // 0xAD uint16 previous_ride_time_out; // 0xAE rct_peep_thought thoughts[PEEP_MAX_THOUGHTS]; // 0xB0 - uint8 var_C4; // 0xC4 + uint8 var_C4; // 0xC4 has something to do with peep falling, see peep.checkForPath union { uint8 staff_id; // 0xC5 uint8 guest_heading_to_ride_id; // 0xC5 diff --git a/src/peep/staff.c b/src/peep/staff.c index 60348ac860..f1adf05318 100644 --- a/src/peep/staff.c +++ b/src/peep/staff.c @@ -109,7 +109,8 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, int newStaffId = i; - int _eax, _ebx, _ecx = _cx, _edx; + int _eax, _ebx, _ecx = _cx; + rct_sprite_bounds *spriteBounds; _ebx = _bl; rct_peep* newPeep = &(create_sprite(_bl)->peep); @@ -129,7 +130,7 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, newPeep->sprite_identifier = 1; newPeep->window_invalidate_flags = 0; newPeep->action = PEEP_ACTION_NONE_2; - newPeep->var_6D = 0; + newPeep->special_sprite = 0; newPeep->action_sprite_image_offset = 0; newPeep->no_action_frame_no = 0; newPeep->action_sprite_type = 0; @@ -181,10 +182,10 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx, newPeep->name_string_idx = staff_type + 0x300; newPeep->sprite_type = _eax; - _edx = RCT2_ADDRESS(0x0098270C, uint32)[_eax * 2]; - newPeep->sprite_width = *((uint8*)_edx); - newPeep->sprite_height_negative = *((uint8*)(_edx + 1)); - newPeep->sprite_height_positive = *((uint8*)(_edx + 2)); + spriteBounds = g_sprite_entries[_eax].sprite_bounds; + newPeep->sprite_width = spriteBounds->sprite_width; + newPeep->sprite_height_negative = spriteBounds->sprite_height_negative; + newPeep->sprite_height_positive = spriteBounds->sprite_height_positive; if ((gConfigGeneral.auto_staff_placement != 0) != ((SDL_GetModState() & KMOD_SHIFT) != 0)) { newPeep->state = PEEP_STATE_FALLING; @@ -292,7 +293,13 @@ void game_command_set_staff_order(int *eax, int *ebx, int *ecx, int *edx, int *e 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){ + if (sprite_id >= MAX_SPRITES) + { + log_warning("Invalid game command, sprite_id = %u", sprite_id); + *ebx = MONEY32_UNDEFINED; + return; + } + if (*ebx & GAME_COMMAND_FLAG_APPLY) { rct_peep *peep = &g_sprite_list[sprite_id].peep; if(order_id & 0x80){ // change costume uint8 sprite_type = order_id & ~0x80; @@ -365,7 +372,19 @@ void game_command_fire_staff_member(int *eax, int *ebx, int *ecx, int *edx, int if(*ebx & GAME_COMMAND_FLAG_APPLY){ window_close_by_class(WC_FIRE_PROMPT); uint16 sprite_id = *edx; + if (sprite_id >= MAX_SPRITES) + { + log_warning("Invalid game command, sprite_id = %u", sprite_id); + *ebx = MONEY32_UNDEFINED; + return; + } rct_peep *peep = &g_sprite_list[sprite_id].peep; + if (peep->sprite_identifier != SPRITE_IDENTIFIER_PEEP || peep->type != PEEP_TYPE_STAFF) + { + log_warning("Invalid game command, peep->sprite_identifier = %u, peep->type = %u", peep->sprite_identifier, peep->type); + *ebx = MONEY32_UNDEFINED; + return; + } remove_peep_from_ride(peep); peep_sprite_remove(peep); } diff --git a/src/platform/platform.h b/src/platform/platform.h index c9e3eb23ad..026e6df020 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -166,6 +166,8 @@ bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer); bool platform_check_steam_overlay_attached(); +datetime64 platform_get_datetime_now_utc(); + // BSD and OS X has MAP_ANON instead of MAP_ANONYMOUS #ifndef MAP_ANONYMOUS #define MAP_ANONYMOUS MAP_ANON diff --git a/src/platform/posix.c b/src/platform/posix.c index 36d9844c15..04c74fb054 100644 --- a/src/platform/posix.c +++ b/src/platform/posix.c @@ -36,6 +36,7 @@ #include #include #include +#include #include // The name of the mutex used to prevent multiple instances of the game from running @@ -499,8 +500,8 @@ bool platform_file_move(const utf8 *srcPath, const utf8 *dstPath) bool platform_file_delete(const utf8 *path) { - STUB(); - return 0; + int ret = unlink(path); + return ret == 0; } wchar_t *regular_to_wchar(const char* src) @@ -753,4 +754,20 @@ uint8 platform_get_locale_temperature_format(){ return TEMPERATURE_FORMAT_C; } +datetime64 platform_get_datetime_now_utc() +{ + const datetime64 epochAsTicks = 621355968000000000; + + struct timeval tv; + gettimeofday(&tv, NULL); + + uint64 utcEpoch = tv.tv_sec; + + // Epoch starts from: 1970-01-01T00:00:00Z + // Convert to ticks from 0001-01-01T00:00:00Z + uint64 utcEpochTicks = (uint64)tv.tv_sec * 10000000ULL + tv.tv_usec * 10; + datetime64 utcNow = epochAsTicks + utcEpochTicks; + return utcNow; +} + #endif diff --git a/src/platform/shared.c b/src/platform/shared.c index 362cf2e84f..31436bae6a 100644 --- a/src/platform/shared.c +++ b/src/platform/shared.c @@ -242,7 +242,11 @@ void platform_draw() 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++]); } + for (int x = width; x > 0; x--) { + const uint8 lower = *(uint8 *)(&gPaletteHWMapped[*src++]); + const uint8 upper = *(uint8 *)(&gPaletteHWMapped[*src++]); + *dst++ = (lower << 8) | upper; + } dst = (uint16*)(((uint8 *)dst) + padding); } } diff --git a/src/platform/windows.c b/src/platform/windows.c index d1443b762a..7069950c18 100644 --- a/src/platform/windows.c +++ b/src/platform/windows.c @@ -262,6 +262,48 @@ int platform_enumerate_files_begin(const utf8 *pattern) return INVALID_HANDLE; } +/** + * Due to FindFirstFile / FindNextFile searching for DOS names as well, *.doc also matches *.docx which isn't what the pattern + * specified. This will verify if a filename does indeed match the pattern we asked for. + * @remarks Based on algorithm (http://xoomer.virgilio.it/acantato/dev/wildcard/wildmatch.html) + */ +static bool match_wildcard(const wchar_t *fileName, const wchar_t *pattern) +{ + while (*fileName != '\0') { + switch (*pattern) { + case '?': + if (*fileName == '.') { + return false; + } + break; + case '*': + do { + pattern++; + } while (*pattern == '*'); + if (*pattern == '\0') { + return false; + } + while (*fileName != '\0') { + if (match_wildcard(fileName++, pattern)) { + return true; + } + } + return false; + default: + if (toupper(*fileName) != toupper(*pattern)) { + return false; + } + break; + } + pattern++; + fileName++; + } + while (*pattern == '*') { + ++fileName; + } + return *pattern == '\0'; +} + bool platform_enumerate_files_next(int handle, file_info *outFileInfo) { bool result; @@ -270,18 +312,28 @@ bool platform_enumerate_files_next(int handle, file_info *outFileInfo) enumFileInfo = &_enumerateFileInfoList[handle]; - if (enumFileInfo->handle == NULL) { - findFileHandle = FindFirstFileW(enumFileInfo->pattern, &enumFileInfo->data); - if (findFileHandle != INVALID_HANDLE_VALUE) { - enumFileInfo->handle = findFileHandle; - result = true; - } else { - result = false; - } + // Get pattern (just filename part) + const wchar_t *patternWithoutDirectory = wcsrchr(enumFileInfo->pattern, '\\'); + if (patternWithoutDirectory == NULL) { + patternWithoutDirectory = enumFileInfo->pattern; } else { - result = FindNextFileW(enumFileInfo->handle, &enumFileInfo->data); + patternWithoutDirectory++; } + do { + if (enumFileInfo->handle == NULL) { + findFileHandle = FindFirstFileW(enumFileInfo->pattern, &enumFileInfo->data); + if (findFileHandle != INVALID_HANDLE_VALUE) { + enumFileInfo->handle = findFileHandle; + result = true; + } else { + result = false; + } + } else { + result = FindNextFileW(enumFileInfo->handle, &enumFileInfo->data); + } + } while (result && !match_wildcard(enumFileInfo->data.cFileName, patternWithoutDirectory)); + if (result) { outFileInfo->path = enumFileInfo->outFilename = widechar_to_utf8(enumFileInfo->data.cFileName); outFileInfo->size = ((uint64)enumFileInfo->data.nFileSizeHigh << 32ULL) | (uint64)enumFileInfo->data.nFileSizeLow; @@ -935,4 +987,17 @@ bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer) #endif } +datetime64 platform_get_datetime_now_utc() +{ + // Get file time + FILETIME fileTime; + GetSystemTimeAsFileTime(&fileTime); + uint64 fileTime64 = ((uint64)fileTime.dwHighDateTime << 32ULL) | ((uint64)fileTime.dwLowDateTime); + + // File time starts from: 1601-01-01T00:00:00Z + // Convert to start from: 0001-01-01T00:00:00Z + datetime64 utcNow = fileTime64 - 504911232000000000ULL; + return utcNow; +} + #endif diff --git a/src/rct1.c b/src/rct1.c index 4c590c94dd..9759287cbd 100644 --- a/src/rct1.c +++ b/src/rct1.c @@ -776,23 +776,22 @@ static void rct1_fix_paths() mapElement->type &= 0xFC; mapElement->flags &= ~0x60; mapElement->properties.path.type &= 0x0F; - mapElement->properties.path.additions &= 0x7F; + footpath_scenery_set_is_ghost(mapElement, false); 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; + additions = RCT1PathAdditionConversionTable[footpath_element_get_path_scenery(mapElement)]; + if (footpath_element_path_scenery_is_ghost(mapElement)) { + footpath_scenery_set_is_ghost(mapElement, false); mapElement->flags |= MAP_ELEMENT_FLAG_BROKEN; } else { mapElement->flags &= ~MAP_ELEMENT_FLAG_BROKEN; } - mapElement->properties.path.additions &= 0xF0; - mapElement->properties.path.additions |= additions; + + footpath_element_set_path_scenery(mapElement, additions); break; case MAP_ELEMENT_TYPE_ENTRANCE: if (mapElement->properties.entrance.type == ENTRANCE_TYPE_PARK_ENTRANCE) { diff --git a/src/rct2.c b/src/rct2.c index db15b17542..aa36ae4a30 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -438,9 +438,6 @@ void rct2_update_2() 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(RCT2_ADDRESS_TICKS_SINCE_LAST_UPDATE, sint16) = 31; - // TODO: screenshot countdown process network_update(); diff --git a/src/rct2.h b/src/rct2.h index 8885921a74..07bc633de7 100644 --- a/src/rct2.h +++ b/src/rct2.h @@ -115,6 +115,11 @@ typedef utf16* utf16string; #define OPENRCT2_MASTER_SERVER_URL "https://servers.openrct2.website" +// Time (represented as number of 100-nanosecond intervals since 0001-01-01T00:00:00Z) +typedef uint64 datetime64; + +#define DATETIME64_MIN ((datetime64)0) + // Represent fixed point numbers. dp = decimal point typedef uint8 fixed8_1dp; typedef uint8 fixed8_2dp; diff --git a/src/ride/ride.c b/src/ride/ride.c index 0fe59765e6..400973babc 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -1592,7 +1592,7 @@ static int ride_modify_entrance_or_exit(rct_map_element *mapElement, int x, int sub_6C9627(); if ( _rideConstructionState != RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT || - !(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) || + !(gInputFlags & INPUT_FLAG_TOOL_ACTIVE) || RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_RIDE_CONSTRUCTION ) { // Replace entrance / exit @@ -1600,7 +1600,7 @@ static int ride_modify_entrance_or_exit(rct_map_element *mapElement, int x, int RCT2_GLOBAL(0x00F44191, uint8) = entranceType; RCT2_GLOBAL(0x00F44192, uint8) = rideIndex; RCT2_GLOBAL(0x00F44193, uint8) = bl; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_6; if (_rideConstructionState != RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT) { RCT2_GLOBAL(0x00F440CC, uint8) = _rideConstructionState; _rideConstructionState = RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT; @@ -1755,7 +1755,7 @@ int sub_6CC3FB(int rideIndex) w = ride_create_or_find_construction_window(rideIndex); tool_set(w, 23, 12); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_6; ride = GET_RIDE(_currentRideIndex); @@ -2467,7 +2467,7 @@ rct_peep *find_closest_mechanic(int x, int y, int forInspection) uint16 spriteIndex; rct_peep *peep, *closestMechanic = NULL; - closestDistance = -1; + closestDistance = UINT_MAX; FOR_ALL_STAFF(spriteIndex, peep) { if (peep->staff_type != STAFF_TYPE_MECHANIC) continue; @@ -2494,15 +2494,15 @@ rct_peep *find_closest_mechanic(int x, int y, int forInspection) if (peep->x == (sint16)0x8000) continue; - // Should probably be euclidean or manhattan distance, this seems a bit naive - distance = max(abs(peep->x - x), abs(peep->y - y)); + // manhattan distance + distance = abs(peep->x - x) + abs(peep->y - y); if (distance < closestDistance) { closestDistance = distance; closestMechanic = peep; } } - return closestDistance == -1 ? NULL : closestMechanic; + return closestMechanic; } rct_peep *ride_get_assigned_mechanic(rct_ride *ride) @@ -2920,7 +2920,15 @@ static bool ride_does_vehicle_colour_exist(uint8 ride_sub_type, vehicle_colour * static int ride_get_unused_preset_vehicle_colour(uint8 ride_type, uint8 ride_sub_type) { + if (ride_sub_type >= 128) + { + return 0; + } rct_ride_type *rideEntry = GET_RIDE_ENTRY(ride_sub_type); + if (rideEntry == (rct_ride_type *)0xFFFFFFFF) + { + return 0; + } vehicle_colour_preset_list *presetList = rideEntry->vehicle_preset_list; if (presetList->count == 255) return 255; @@ -3594,6 +3602,12 @@ void game_command_set_ride_setting(int *eax, int *ebx, int *ecx, int *edx, int * uint8 ride_id = *edx & 0xFF; rct_ride* ride = GET_RIDE(ride_id); + if (ride->type == RIDE_TYPE_NULL) + { + log_warning("Invalid game command."); + *ebx = MONEY32_UNDEFINED; + return; + } uint8 flags = *ebx & 0xFF; uint8 new_value = (*ebx >> 8) & 0xFF; @@ -4612,6 +4626,11 @@ int ride_is_valid_for_test(int rideIndex, int goingToBeOpen, int isApplying) rct_xy_element trackElement, problematicTrackElement; ride = GET_RIDE(rideIndex); + if (ride->type == RIDE_TYPE_NULL) + { + log_warning("Invalid ride type for ride %u", rideIndex); + return 0; + } window_close_by_number(WC_RIDE_CONSTRUCTION, rideIndex); @@ -4870,6 +4889,12 @@ void game_command_set_ride_status(int *eax, int *ebx, int *ecx, int *edx, int *e RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_RUNNING_COSTS * 4; ride = GET_RIDE(rideIndex); + if (ride->type == RIDE_TYPE_NULL) + { + log_warning("Invalid game command for ride %u", rideIndex); + *ebx = MONEY32_UNDEFINED; + return; + } RCT2_GLOBAL(0x00F43484, uint32) = RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32); switch (targetStatus) { @@ -4950,6 +4975,7 @@ void game_command_set_ride_name(int *eax, int *ebx, int *ecx, int *edx, int *esi if (nameChunkOffset < 0) nameChunkOffset = 2; nameChunkOffset *= 12; + nameChunkOffset = min(nameChunkOffset, countof(newName) - 12); RCT2_GLOBAL(newName + nameChunkOffset + 0, uint32) = *edx; RCT2_GLOBAL(newName + nameChunkOffset + 4, uint32) = *ebp; RCT2_GLOBAL(newName + nameChunkOffset + 8, uint32) = *edi; @@ -5168,6 +5194,10 @@ static int ride_get_random_colour_preset_index(uint8 ride_type) { const track_colour_preset_list *colourPresets; const track_colour *colours; + if (ride_type >= 128) + { + return 0; + } colourPresets = RCT2_ADDRESS(0x0097D934, track_colour_preset_list*)[ride_type]; @@ -5271,6 +5301,11 @@ money32 ride_create(int type, int subType, int flags, int *outRideIndex, int *ou foundRideEntry: rideEntryIndex = subType; rideIndex = ride_get_empty_slot(); + if (subType >= 128) + { + log_warning("Invalid request for ride type %u", subType); + return MONEY32_UNDEFINED; + } if (rideIndex == -1) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_TOO_MANY_RIDES; return MONEY32_UNDEFINED; @@ -5293,6 +5328,11 @@ foundRideEntry: ride = GET_RIDE(rideIndex); rideEntry = GET_RIDE_ENTRY(rideEntryIndex); + if (rideEntry == (rct_ride_type *)0xFFFFFFFF) + { + log_warning("Invalid request for ride %u", rideIndex); + return MONEY32_UNDEFINED; + } ride->type = type; ride->subtype = rideEntryIndex; ride_set_colour_preset(ride, *outRideColour & 0xFF); @@ -5602,7 +5642,13 @@ void game_command_demolish_ride(int *eax, int *ebx, int *ecx, int *edx, int *esi 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]; + rct_ride *ride = GET_RIDE(ride_id); + if (ride->type == RIDE_TYPE_NULL) + { + log_warning("Invalid game command for ride %u", ride_id); + *ebx = MONEY32_UNDEFINED; + return; + } int x = 0, y = 0, z = 0; if(ride->overall_view != (uint16)-1){ x = ((ride->overall_view & 0xFF) * 32) + 16; @@ -5730,25 +5776,61 @@ void game_command_set_ride_appearance(int *eax, int *ebx, int *ecx, int *edx, in uint8 type = *ebx >> 8; uint8 value = *edx >> 8; int index = *edi; - rct_ride *ride = &g_ride_list[ride_id]; + if (index < 0) { + log_warning("Invalid game command, index %d out of bounds", index); + *ebx = MONEY32_UNDEFINED; + return; + } + rct_ride *ride = GET_RIDE(ride_id); + if (ride->type == RIDE_TYPE_NULL) { + log_warning("Invalid game command, ride_id = %u", ride_id); + *ebx = MONEY32_UNDEFINED; + return; + } + *ebx = 0; switch(type){ case 0: + if (index >= countof(ride->track_colour_main)) { + log_warning("Invalid game command, index %d out of bounds", index); + *ebx = MONEY32_UNDEFINED; + break; + } ride->track_colour_main[index] = value; gfx_invalidate_screen(); break; case 1: + if (index >= countof(ride->track_colour_additional)) { + log_warning("Invalid game command, index %d out of bounds", index); + *ebx = MONEY32_UNDEFINED; + break; + } ride->track_colour_additional[index] = value; gfx_invalidate_screen(); break; case 2: + if (index >= countof(ride->vehicle_colours)) { + log_warning("Invalid game command, index %d out of bounds", index); + *ebx = MONEY32_UNDEFINED; + break; + } *((uint8*)(&ride->vehicle_colours[index])) = value; ride_update_vehicle_colours(ride_id); break; case 3: + if (index >= countof(ride->vehicle_colours)) { + log_warning("Invalid game command, index %d out of bounds", index); + *ebx = MONEY32_UNDEFINED; + break; + } *((uint8*)(&ride->vehicle_colours[index]) + 1) = value; ride_update_vehicle_colours(ride_id); break; case 4: + if (index >= countof(ride->track_colour_supports)) { + log_warning("Invalid game command, index %d out of bounds", index); + *ebx = MONEY32_UNDEFINED; + break; + } ride->track_colour_supports[index] = value; gfx_invalidate_screen(); break; @@ -5767,13 +5849,17 @@ void game_command_set_ride_appearance(int *eax, int *ebx, int *ecx, int *edx, in gfx_invalidate_screen(); break; case 7: + if (index >= countof(ride->vehicle_colours_extended)) { + log_warning("Invalid game command, index %d out of bounds", index); + *ebx = MONEY32_UNDEFINED; + break; + } ride->vehicle_colours_extended[index] = value; ride_update_vehicle_colours(ride_id); break; } window_invalidate_by_number(WC_RIDE, ride_id); } - *ebx = 0; } /** @@ -5786,21 +5872,28 @@ void game_command_set_ride_price(int *eax, int *ebx, int *ecx, int *edx, int *es uint8 ride_number; money16 price; rct_ride *ride; - rct_ride_type *ride_type; + rct_ride_type *rideEntry; bool secondary_price; flags = *ebx; ride_number = (*edx & 0xFF); ride = GET_RIDE(ride_number); - ride_type = gRideTypeList[ride->subtype]; + rideEntry = GET_RIDE_ENTRY(ride->subtype); price = *edi; secondary_price = (*edx >> 8); + if (rideEntry == (rct_ride_type *)0xFFFFFFFF) + { + log_warning("Invalid game command for ride %u", ride_number); + *ebx = MONEY32_UNDEFINED; + return; + } + //eax //ebx flags //ecx ecx //edx ride_number - //ebp ride_type + //ebp rideEntry *ebx = 0; // for cost check - changing ride price does not cost anything @@ -5809,7 +5902,7 @@ void game_command_set_ride_price(int *eax, int *ebx, int *ecx, int *edx, int *es if (!secondary_price) { shop_item = 0x1F; if (ride->type != RIDE_TYPE_TOILETS) { - shop_item = ride_type->shop_item; + shop_item = rideEntry->shop_item; if (shop_item == 0xFF) { ride->price = price; window_invalidate_by_class(WC_RIDE); @@ -5824,7 +5917,7 @@ void game_command_set_ride_price(int *eax, int *ebx, int *ecx, int *edx, int *es } } else { - shop_item = ride_type->shop_item_secondary; + shop_item = rideEntry->shop_item_secondary; if (shop_item == 0xFF) { shop_item = RCT2_GLOBAL(0x0097D7CB + (ride->type * 4), uint8); if ((ride->lifecycle_flags & RIDE_LIFECYCLE_ON_RIDE_PHOTO) == 0) { @@ -5841,12 +5934,12 @@ void game_command_set_ride_price(int *eax, int *ebx, int *ecx, int *edx, int *es } } ride = GET_RIDE(0); - ride_type = gRideTypeList[ride->subtype]; + rideEntry = GET_RIDE_ENTRY(ride->subtype); uint8 count = 0; while (count < 0xFF) { if (ride->type != 0xFF) { if (ride->type != RIDE_TYPE_TOILETS || shop_item != 0x1F) { - if (ride_type->shop_item == shop_item) { + if (rideEntry->shop_item == shop_item) { ride->price = price; window_invalidate_by_number(WC_RIDE, count); } @@ -5856,8 +5949,8 @@ void game_command_set_ride_price(int *eax, int *ebx, int *ecx, int *edx, int *es window_invalidate_by_number(WC_RIDE, count); } // If the shop item is the same or an on-ride photo - if (ride_type->shop_item_secondary == shop_item || - (ride_type->shop_item_secondary == 0xFF && + if (rideEntry->shop_item_secondary == shop_item || + (rideEntry->shop_item_secondary == 0xFF && (shop_item == 0x3 || shop_item == 0x20 || shop_item == 0x21 || shop_item == 0x22))) { ride->price_secondary = price; @@ -5866,7 +5959,7 @@ void game_command_set_ride_price(int *eax, int *ebx, int *ecx, int *edx, int *es } count++; ride++; - ride_type = gRideTypeList[ride->subtype]; + rideEntry = GET_RIDE_ENTRY(ride->subtype); } } } @@ -6884,6 +6977,12 @@ void game_command_set_ride_vehicles(int *eax, int *ebx, int *ecx, int *edx, int value = (*edx >> 8) & 0xFF; ride = GET_RIDE(rideIndex); + if (ride->type == RIDE_TYPE_NULL) + { + log_warning("Invalid game command for ride %u", rideIndex); + *ebx = MONEY32_UNDEFINED; + return; + } RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_RIDE_RUNNING_COSTS * 4; @@ -7225,6 +7324,11 @@ void game_command_place_ride_entrance_or_exit(int *eax, int *ebx, int *ecx, int money32 remove_ride_entrance_or_exit(sint16 x, sint16 y, uint8 rideIndex, uint8 station_num, uint8 flags){ rct_ride* ride = GET_RIDE(rideIndex); + if (ride->type == RIDE_TYPE_NULL) + { + log_warning("Invalide ride id %u for entrance/exit removal", rideIndex); + return MONEY32_UNDEFINED; + } 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){ @@ -7245,6 +7349,11 @@ money32 remove_ride_entrance_or_exit(sint16 x, sint16 y, uint8 rideIndex, uint8 uint8 found = 0; rct_map_element* mapElement = map_get_first_element_at(x / 32, y / 32); + if (mapElement == NULL) + { + log_warning("Invalid coordinates for entrance/exit removal x = %d, y = %d", x, y); + return MONEY32_UNDEFINED; + } do{ if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_ENTRANCE) continue; diff --git a/src/ride/track.c b/src/ride/track.c index c9c45907ae..1f29c89c1f 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -3099,7 +3099,7 @@ int save_track_design(uint8 rideIndex){ return 1; } - path_set_extension(path, "TD6"); + path_append_extension(path, "TD6"); save_track_to_file(RCT2_ADDRESS(0x009D8178, rct_track_td6), path); @@ -3292,6 +3292,14 @@ void game_command_place_track_design(int* eax, int* ebx, int* ecx, int* edx, int rideIndex = _edi & 0xFF; } + rct_ride* ride = GET_RIDE(rideIndex); + if (ride->type == RIDE_TYPE_NULL) + { + log_warning("Invalid game command for track placement, ride id = %d", rideIndex); + *ebx = MONEY32_UNDEFINED; + return; + } + money32 cost = 0; if (!(flags & GAME_COMMAND_FLAG_APPLY)){ RCT2_GLOBAL(0x00F44150, uint8) = 0; @@ -3348,7 +3356,6 @@ void game_command_place_track_design(int* eax, int* ebx, int* ecx, int* edx, int if (num_circuits == 0) num_circuits = 1; game_do_command(0, GAME_COMMAND_FLAG_APPLY | (num_circuits << 8), 0, rideIndex | (9 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); - rct_ride* ride = GET_RIDE(rideIndex); ride->lifecycle_flags |= RIDE_LIFECYCLE_NOT_CUSTOM_DESIGN; @@ -4494,6 +4501,11 @@ money32 track_remove(uint8 type, uint8 sequence, sint16 originX, sint16 originY, uint8 found = 0; rct_map_element* mapElement = map_get_first_element_at(originX / 32, originY / 32); + if (mapElement == NULL) + { + log_warning("Invalid coordinates for track removal. x = %d, y = %d", originX, originY); + return MONEY32_UNDEFINED; + } do{ if (mapElement->base_height * 8 != originZ) continue; @@ -4781,6 +4793,12 @@ void game_command_set_brakes_speed(int *eax, int *ebx, int *ecx, int *edx, int * } mapElement = map_get_first_element_at(x >> 5, y >> 5); + if (mapElement == NULL) + { + log_warning("Invalid game command for setting brakes speed. x = %d, y = %d", x, y); + *ebx = MONEY32_UNDEFINED; + return; + } do { if (mapElement->base_height * 8 != z) continue; diff --git a/src/scenario.c b/src/scenario.c index 9bc0f7e262..c7bcdcafb0 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -45,6 +45,17 @@ #include "world/sprite.h" #include "world/water.h" +const rct_string_id ScenarioCategoryStringIds[SCENARIO_CATEGORY_COUNT] = { + STR_BEGINNER_PARKS, + STR_CHALLENGING_PARKS, + STR_EXPERT_PARKS, + STR_REAL_PARKS, + STR_OTHER_PARKS, + + STR_DLC_PARKS, + STR_BUILD_YOUR_OWN_PARKS, +}; + static char _scenarioPath[MAX_PATH]; static const char *_scenarioFileName = ""; @@ -58,13 +69,11 @@ static void scenario_objective_check(); * Loads only the basic information from a scenario. * rct2: 0x006761D6 */ -int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *info) +bool scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *info) { - SDL_RWops* rw; - log_verbose("loading scenario details, %s", path); - rw = SDL_RWFromFile(path, "rb"); + SDL_RWops* rw = SDL_RWFromFile(path, "rb"); if (rw != NULL) { // Read first chunk sawyercoding_read_chunk(rw, (uint8*)header); @@ -72,49 +81,16 @@ int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *in // Read second chunk sawyercoding_read_chunk(rw, (uint8*)info); SDL_RWclose(rw); - RCT2_GLOBAL(0x009AA00C, uint8) = 0; - - // 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; + return true; + } else { + log_error("invalid scenario, %s", path); + SDL_RWclose(rw); + return false; } - SDL_RWclose(rw); } - log_error("invalid scenario, %s", path); - // RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, sint8) = -1; - // RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, sint16) = 3011; - return 0; + log_error("unable to open scenario, %s", path); + return false; } /** @@ -219,19 +195,6 @@ int scenario_load(const char *path) return 0; } -/** - * - * rct2: 0x00678282 - * scenario (ebx) - */ -int scenario_load_and_play(const rct_scenario_basic *scenario) -{ - char path[MAX_PATH]; - - substitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), scenario->path); - return scenario_load_and_play_from_path(path); -} - int scenario_load_and_play_from_path(const char *path) { window_close_construction_windows(); @@ -316,13 +279,12 @@ void scenario_begin() safe_strncpy((char*)RCT2_ADDRESS_SCENARIO_NAME, s6Info->name, 64); { - // Get filename - utf8 filename[MAX_PATH]; - safe_strncpy(filename, _scenarioFileName, sizeof(filename)); - path_remove_extension(filename); + utf8 normalisedName[64]; + safe_strncpy(normalisedName, s6Info->name, sizeof(normalisedName)); + scenario_normalise_name(normalisedName); rct_string_id localisedStringIds[3]; - if (language_get_localised_scenario_strings(filename, localisedStringIds)) { + if (language_get_localised_scenario_strings(normalisedName, localisedStringIds)) { if (localisedStringIds[0] != (rct_string_id)STR_NONE) { safe_strncpy((char*)RCT2_ADDRESS_SCENARIO_NAME, language_get_string(localisedStringIds[0]), 32); } @@ -437,29 +399,29 @@ void scenario_failure() */ void scenario_success() { - int i; - rct_scenario_basic* scenario; - uint32 current_val = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_COMPANY_VALUE, uint32); + const money32 companyValue = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_COMPANY_VALUE, money32); - RCT2_GLOBAL(RCT2_ADDRESS_COMPLETED_COMPANY_VALUE, uint32) = current_val; + RCT2_GLOBAL(RCT2_ADDRESS_COMPLETED_COMPANY_VALUE, uint32) = companyValue; peep_applause(); - for (i = 0; i < gScenarioListCount; i++) { - scenario = &gScenarioList[i]; - - if (strequals(scenario->path, _scenarioFileName, 256, true)) { - // Check if record company value has been broken - if ((scenario->flags & SCENARIO_FLAGS_COMPLETED) && scenario->company_value >= current_val) - break; + scenario_index_entry *scenario = scenario_list_find_by_filename(_scenarioFileName); + if (scenario != NULL) { + // Check if record company value has been broken + if (scenario->highscore == NULL || scenario->highscore->company_value < companyValue) { + if (scenario->highscore == NULL) { + scenario->highscore = scenario_highscore_insert(); + } else { + scenario_highscore_free(scenario->highscore); + } + scenario->highscore->fileName = _strdup(path_get_filename(scenario->path)); + scenario->highscore->name = NULL; + scenario->highscore->company_value = companyValue; + scenario->highscore->timestamp = platform_get_datetime_now_utc(); // Allow name entry RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_SCENARIO_COMPLETE_NAME_INPUT; - scenario->company_value = current_val; - scenario->flags |= SCENARIO_FLAGS_COMPLETED; - scenario->completed_by[0] = 0; - RCT2_GLOBAL(0x013587C0, uint32) = current_val; + RCT2_GLOBAL(0x013587C0, money32) = companyValue; scenario_scores_save(); - break; } } scenario_end(); @@ -471,21 +433,13 @@ void scenario_success() */ 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) { - safe_strncpy(scenario->completed_by, name, 64); - safe_strncpy((char*)0x013587D8, name, 32); - scenario_scores_save(); - } - break; + scenario_index_entry *scenario = scenario_list_find_by_filename(_scenarioFileName); + if (scenario != NULL) { + money32 scenarioWinCompanyValue = RCT2_GLOBAL(0x013587C0, money32); + if (scenario->highscore->company_value == scenarioWinCompanyValue) { + scenario->highscore->name = _strdup(name); + safe_strncpy((char*)0x013587D8, name, 32); + scenario_scores_save(); } } diff --git a/src/scenario.h b/src/scenario.h index 6f34f904a6..6368292d79 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -72,6 +72,17 @@ typedef struct { uint32 scenario_count; // 0x0C } rct_scenario_scores_header; +typedef enum { + SCENARIO_SOURCE_RCT1, + SCENARIO_SOURCE_RCT1_AA, + SCENARIO_SOURCE_RCT1_LL, + SCENARIO_SOURCE_RCT2, + SCENARIO_SOURCE_RCT2_WW, + SCENARIO_SOURCE_RCT2_TT, + SCENARIO_SOURCE_REAL, + SCENARIO_SOURCE_OTHER +} scenario_source; + /** * Scenario basic structure, mainly for scenario select * size: 0x02B0 @@ -89,6 +100,8 @@ typedef struct { sint32 flags; // 0x0268 uint32 company_value; // 0x026C char completed_by[64]; // 0x0270 + // uint8 source_game; // new in OpenRCT2 + // sint16 source_index; // new in OpenRCT2 } rct_scenario_basic; typedef struct { @@ -385,11 +398,18 @@ enum { #define S6_MAGIC_NUMBER 0x00031144 enum { + // RCT2 categories (keep order) SCENARIO_CATEGORY_BEGINNER, SCENARIO_CATEGORY_CHALLENGING, SCENARIO_CATEGORY_EXPERT, SCENARIO_CATEGORY_REAL, - SCENARIO_CATEGORY_BUILDYOUROWN + SCENARIO_CATEGORY_OTHER, + + // OpenRCT2 categories + SCENARIO_CATEGORY_DLC, + SCENARIO_CATEGORY_BUILD_YOUR_OWN, + + SCENARIO_CATEGORY_COUNT }; enum { @@ -407,20 +427,61 @@ enum { OBJECTIVE_MONTHLY_FOOD_INCOME }; +typedef struct { + utf8 *fileName; + utf8 *name; + money32 company_value; + datetime64 timestamp; +} scenario_highscore_entry; + +typedef struct { + utf8 path[MAX_PATH]; + uint64 timestamp; + + // Category / sequence + uint8 category; + uint8 source_game; + sint16 source_index; + uint16 sc_id; + + // Objective + uint8 objective_type; + uint8 objective_arg_1; + sint32 objective_arg_2; + sint16 objective_arg_3; + scenario_highscore_entry *highscore; + + utf8 name[64]; + utf8 details[256]; +} scenario_index_entry; + +typedef struct { + const utf8 *title; + uint8 id; + uint8 source; + sint32 index; + uint8 category; +} source_desc; + +extern const rct_string_id ScenarioCategoryStringIds[SCENARIO_CATEGORY_COUNT]; + // Scenario list extern int gScenarioListCount; extern int gScenarioListCapacity; -extern rct_scenario_basic *gScenarioList; +extern scenario_index_entry *gScenarioList; extern char gScenarioSavePath[MAX_PATH]; extern int gFirstTimeSave; -int scenario_scores_save(); +bool scenario_scores_save(); void scenario_load_list(); -rct_scenario_basic *get_scenario_by_filename(const char *filename); -int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *info); +void scenario_list_dispose(); +scenario_index_entry *scenario_list_find_by_filename(const utf8 *filename); +scenario_index_entry *scenario_list_find_by_path(const utf8 *path); +scenario_highscore_entry *scenario_highscore_insert(); +void scenario_highscore_free(scenario_highscore_entry *highscore); +bool scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *info); int scenario_load(const char *path); -int scenario_load_and_play(const rct_scenario_basic *scenario); int scenario_load_and_play_from_path(const char *path); void scenario_begin(); void scenario_update(); @@ -436,4 +497,114 @@ void scenario_success(); void scenario_success_submit_name(const char *name); void scenario_autosave_check(); +bool scenario_get_source_desc(const utf8 *name, source_desc *outDesc); +bool scenario_get_source_desc_by_id(uint8 id, source_desc *outDesc); +void scenario_normalise_name(utf8 *name); + +// RCT1 scenario index map +enum { + SC_UNIDENTIFIED = 255, + + // RCT + SC_FOREST_FRONTIERS = 0, + SC_DYNAMITE_DUNES, + SC_LEAFY_LAKES, + SC_DIAMOND_HEIGHTS, + SC_EVERGREEN_GARDENS, + SC_BUMBLY_BEACH, + SC_TRINITY_ISLANDS, + SC_KATIES_DREAMLAND, + SC_POKEY_PARK, + SC_WHITE_WATER_PARK, + SC_MILLENNIUM_MINES, + SC_KARTS_COASTERS, + SC_MELS_WORLD, + SC_MYSTIC_MOUNTAIN, + SC_PACIFIC_PYRAMIDS, + SC_CRUMBLY_WOODS, + SC_PARADISE_PIER, + SC_LIGHTNING_PEAKS, + SC_IVORY_TOWERS, + SC_RAINBOW_VALLEY, + SC_THUNDER_ROCK, + SC_MEGA_PARK, + + // Loopy Landscapes + SC_ICEBERG_ISLANDS, + SC_VOLCANIA, + SC_ARID_HEIGHTS, + SC_RAZOR_ROCKS, + SC_CRATER_LAKE, + SC_VERTIGO_VIEWS, + SC_PARADISE_PIER_2, + SC_DRAGONS_COVE, + SC_GOOD_KNIGHT_PARK, + SC_WACKY_WARREN, + + // Special + ALTON_TOWERS, + FORT_ANACHRONISM, + + // Added Attractions + SC_WHISPERING_CLIFFS = 40, + SC_THREE_MONKEYS_PARK, + SC_CANARY_MINES, + SC_BARONY_BRIDGE, + SC_FUNTOPIA, + SC_HAUNTED_HARBOR, + SC_FUN_FORTRESS, + SC_FUTURE_WORLD, + SC_GENTLE_GLEN, + SC_JOLLY_JUNGLE, + SC_HYDRO_HILLS, + SC_SPRIGHTLY_PARK, + SC_MAGIC_QUARTERS, + SC_FRUIT_FARM, + SC_BUTTERFLY_DAM, + SC_COASTER_CANYON, + SC_THUNDERSTORM_PARK, + SC_HARMONIC_HILLS, + SC_ROMAN_VILLAGE, + SC_SWAMP_COVE, + SC_ADRENALINE_HEIGHTS, + SC_UTOPIA, + SC_ROTTING_HEIGHTS, + SC_FIASCO_FOREST, + SC_PICKLE_PARK, + SC_GIGGLE_DOWNS, + SC_MINERAL_PARK, + SC_COASTER_CRAZY, + SC_URBAN_PARK, + SC_GEOFFREY_GARDENS, + + // Special + SC_HEIDE_PARK, + SC_PCPLAYER, + SC_PCGW, + SC_GAMEPLAY, + SC_BLACKPOOL_PLEASURE_BEACH, + + // Loopy Landscapes + SC_GRAND_GLACIER = 80, + SC_CRAZY_CRATERS, + SC_DUSTY_DESERT, + SC_WOODWORM_PARK, + SC_ICARUS_PARK, + SC_SUNNY_SWAMPS, + SC_FRIGHTMARE_HILLS, + SC_THUNDER_ROCKS, + SC_OCTAGON_PARK, + SC_PLEASURE_ISLAND, + SC_ICICLE_WORLDS, + SC_SOUTHERN_SANDS, + SC_TINY_TOWERS, + SC_NEVERMORE_PARK, + SC_PACIFICA, + SC_URBAN_JUNGLE, + SC_TERROR_TOWN, + SC_MEGAWORLD_PARK, + SC_VENUS_PONDS, + SC_MICRO_PARK, +}; + #endif diff --git a/src/scenario_list.c b/src/scenario_list.c index f69f4b59c2..d62c906946 100644 --- a/src/scenario_list.c +++ b/src/scenario_list.c @@ -19,228 +19,535 @@ *****************************************************************************/ #include "addresses.h" +#include "config.h" +#include "localisation/localisation.h" #include "platform/platform.h" -#include "util/util.h" #include "scenario.h" +#include "util/util.h" // Scenario list int gScenarioListCount = 0; int gScenarioListCapacity = 0; -rct_scenario_basic *gScenarioList = NULL; +scenario_index_entry *gScenarioList = NULL; -static void scenario_list_add(const char *path); +int gScenarioHighscoreListCount = 0; +int gScenarioHighscoreListCapacity = 0; +scenario_highscore_entry *gScenarioHighscoreList = NULL; + +static void scenario_list_include(const utf8 *directory); +static void scenario_list_add(const utf8 *path, uint64 timestamp); static void scenario_list_sort(); -static int scenario_list_sort_compare(const void *a, const void *b); -static int scenario_scores_load(); +static int scenario_list_sort_by_category(const void *a, const void *b); +static int scenario_list_sort_by_index(const void *a, const void *b); +static void scenario_translate(scenario_index_entry *scenarioEntry, const rct_object_entry *stexObjectEntry); -rct_scenario_basic *get_scenario_by_filename(const char *filename) -{ - int i; - for (i = 0; i < gScenarioListCount; i++) - if (strcmp(gScenarioList[i].path, filename) == 0) - return &gScenarioList[i]; - - return NULL; -} +static bool scenario_scores_load(); +static void scenario_scores_legacy_get_path(utf8 *outPath); +static bool scenario_scores_legacy_load(const utf8 *path); +static void scenario_highscore_remove(scenario_highscore_entry *higscore); +static void scenario_highscore_list_dispose(); +static utf8 *io_read_string(SDL_RWops *file); +static void io_write_string(SDL_RWops *file, utf8 *source); /** - * - * rct2: 0x006775A8 + * Searches and grabs the metadata for all the scenarios. */ void scenario_load_list() { - int i, enumFileHandle; - file_info enumFileInfo; + utf8 directory[MAX_PATH]; - // Load scores + // Clear scenario list + gScenarioListCount = 0; + + // Get scenario directory from RCT2 + safe_strncpy(directory, gConfigGeneral.game_path, sizeof(directory)); + safe_strcat_path(directory, "Scenarios", sizeof(directory)); + scenario_list_include(directory); + + // Get scenario directory from user directory + platform_get_user_directory(directory, "scenario"); + scenario_list_include(directory); + + scenario_list_sort(); scenario_scores_load(); - // Set all scenarios to be invisible - for (i = 0; i < gScenarioListCount; i++) - gScenarioList[i].flags &= ~SCENARIO_FLAGS_VISIBLE; - - // Enumerate through each scenario in the directory - enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char)); - if (enumFileHandle != INVALID_HANDLE) { - while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { - scenario_list_add(enumFileInfo.path); - } - platform_enumerate_files_end(enumFileHandle); - } - - // Sort alphabetically - scenario_list_sort(); - - // Save the scores - scenario_scores_save(); + utf8 scoresPath[MAX_PATH]; + scenario_scores_legacy_get_path(scoresPath); + scenario_scores_legacy_load(scoresPath); + scenario_scores_legacy_load(get_file_path(PATH_ID_SCORES)); } -static void scenario_list_add(const char *path) +static void scenario_list_include(const utf8 *directory) { - char scenarioPath[MAX_PATH]; - rct_scenario_basic *scenario; + int handle; + file_info fileInfo; + + // Scenarios in this directory + utf8 pattern[MAX_PATH]; + safe_strncpy(pattern, directory, sizeof(pattern)); + safe_strcat_path(pattern, "*.sc6", sizeof(pattern)); + + handle = platform_enumerate_files_begin(pattern); + while (platform_enumerate_files_next(handle, &fileInfo)) { + utf8 path[MAX_PATH]; + safe_strncpy(path, directory, sizeof(pattern)); + safe_strcat_path(path, fileInfo.path, sizeof(pattern)); + scenario_list_add(path, fileInfo.last_modified); + } + platform_enumerate_files_end(handle); + + // Include sub-directories + utf8 subDirectory[MAX_PATH]; + handle = platform_enumerate_directories_begin(directory); + while (platform_enumerate_directories_next(handle, subDirectory)) { + utf8 path[MAX_PATH]; + safe_strncpy(path, directory, sizeof(pattern)); + safe_strcat_path(path, subDirectory, sizeof(pattern)); + scenario_list_include(path); + } + platform_enumerate_directories_end(handle); +} + +static void scenario_list_add(const utf8 *path, uint64 timestamp) +{ + // Load the basic scenario information rct_s6_header s6Header; rct_s6_info s6Info; - - // Get absolute path - substitute_path(scenarioPath, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), path); - - // Load the basic scenario information - if (!scenario_load_basic(scenarioPath, &s6Header, &s6Info)) + if (!scenario_load_basic(path, &s6Header, &s6Info)) { return; + } - // Ignore scenarios where first header byte is not 255 - if (s6Info.editor_step != 255) - return; + scenario_index_entry *newEntry = NULL; - // Check if scenario already exists in list, likely if in scores - scenario = get_scenario_by_filename(path); - if (scenario != NULL) { - // Update the scenario information - scenario->flags |= SCENARIO_FLAGS_VISIBLE; - scenario->category = s6Info.category; - scenario->objective_type = s6Info.objective_type; - scenario->objective_arg_1 = s6Info.objective_arg_1; - scenario->objective_arg_2 = s6Info.objective_arg_2; - scenario->objective_arg_3 = s6Info.objective_arg_3; - 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) { - // Allocate more room - gScenarioListCapacity += 16; - gScenarioList = realloc(gScenarioList, gScenarioListCapacity * sizeof(rct_scenario_basic)); + const utf8 *filename = path_get_filename(path); + scenario_index_entry *existingEntry = scenario_list_find_by_filename(filename); + if (existingEntry != NULL) { + bool bail = false; + const utf8 *conflictPath; + if (existingEntry->timestamp > timestamp) { + // Existing entry is more recent + conflictPath = existingEntry->path; + + // Overwrite existing entry with this one + newEntry = existingEntry; + } else { + // This entry is more recent + conflictPath = path; + bail = true; } + printf("Scenario conflict: '%s' ignored because it is newer.\n", conflictPath); + if (bail) { + return; + } + } - // Increment the number of scenarios - scenario = &gScenarioList[gScenarioListCount]; + if (newEntry == NULL) { + // Increase list size + if (gScenarioListCount == gScenarioListCapacity) { + gScenarioListCapacity = max(8, gScenarioListCapacity * 2); + gScenarioList = (scenario_index_entry*)realloc(gScenarioList, gScenarioListCapacity * sizeof(scenario_index_entry)); + } + newEntry = &gScenarioList[gScenarioListCount]; gScenarioListCount++; + } - // Add this new scenario to the list - safe_strncpy(scenario->path, path, 256); - scenario->flags = SCENARIO_FLAGS_VISIBLE; - if (RCT2_GLOBAL(0x009AA00C, uint8) & 1) - scenario->flags |= SCENARIO_FLAGS_SIXFLAGS; - scenario->category = s6Info.category; - scenario->objective_type = s6Info.objective_type; - scenario->objective_arg_1 = s6Info.objective_arg_1; - scenario->objective_arg_2 = s6Info.objective_arg_2; - scenario->objective_arg_3 = s6Info.objective_arg_3; - safe_strncpy(scenario->name, s6Info.name, 64); - safe_strncpy(scenario->details, s6Info.details, 256); + // Set new entry + safe_strncpy(newEntry->path, path, sizeof(newEntry->path)); + newEntry->timestamp = timestamp; + newEntry->category = s6Info.category; + newEntry->objective_type = s6Info.objective_type; + newEntry->objective_arg_1 = s6Info.objective_arg_1; + newEntry->objective_arg_2 = s6Info.objective_arg_2; + newEntry->objective_arg_3 = s6Info.objective_arg_3; + newEntry->highscore = NULL; + safe_strncpy(newEntry->name, s6Info.name, sizeof(newEntry->name)); + safe_strncpy(newEntry->details, s6Info.details, sizeof(newEntry->details)); + + // Normalise the name to make the scenario as recognisable as possible. + scenario_normalise_name(newEntry->name); + + // Look up and store information regarding the origins of this scenario. + source_desc desc; + if (scenario_get_source_desc(newEntry->name, &desc)) { + newEntry->sc_id = desc.id; + newEntry->source_index = desc.index; + newEntry->source_game = desc.source; + newEntry->category = desc.category; + } else { + newEntry->sc_id = SC_UNIDENTIFIED; + newEntry->source_index = -1; + if (newEntry->category == SCENARIO_CATEGORY_REAL) { + newEntry->source_game = SCENARIO_SOURCE_REAL; + } else { + newEntry->source_game = SCENARIO_SOURCE_OTHER; + } + } + + scenario_translate(newEntry, &s6Info.entry); +} + +static void scenario_translate(scenario_index_entry *scenarioEntry, const rct_object_entry *stexObjectEntry) +{ + rct_string_id localisedStringIds[3]; + if (language_get_localised_scenario_strings(scenarioEntry->name, localisedStringIds)) { + if (localisedStringIds[0] != (rct_string_id)STR_NONE) { + safe_strncpy(scenarioEntry->name, language_get_string(localisedStringIds[0]), 64); + } + if (localisedStringIds[2] != (rct_string_id)STR_NONE) { + safe_strncpy(scenarioEntry->details, language_get_string(localisedStringIds[2]), 256); + } + } else { + // Checks for a scenario string object (possibly for localisation) + if ((stexObjectEntry->flags & 0xFF) != 255) { + if (object_get_scenario_text((rct_object_entry*)stexObjectEntry)) { + rct_stex_entry* stex_entry = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_CHUNK, rct_stex_entry*); + format_string(scenarioEntry->name, stex_entry->scenario_name, NULL); + format_string(scenarioEntry->details, stex_entry->details, NULL); + object_free_scenario_text(); + } + } } } -/** -* Sort the list of scenarios. This used to be an insertion sort which took -* place as each scenario loaded. It has now been changed to a quicksort which -* takes place after all the scenarios have been loaded in. -* rct2: 0x00677C3B -*/ -static void scenario_list_sort() +void scenario_list_dispose() { - qsort(gScenarioList, gScenarioListCount, sizeof(rct_scenario_basic), scenario_list_sort_compare); + gScenarioListCapacity = 0; + gScenarioListCount = 0; + SafeFree(gScenarioList); } -/** - * Basic scenario information compare function for sorting. - * rct2: 0x00677C08 - */ -static int scenario_list_sort_compare(const void *a, const void *b) +static void scenario_list_sort() { - return strcmp(((rct_scenario_basic*)a)->name, ((rct_scenario_basic*)b)->name); + int(*compareFunc)(void const*, void const*); + + compareFunc = gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_ORIGIN ? + scenario_list_sort_by_index : + scenario_list_sort_by_category; + + qsort(gScenarioList, gScenarioListCount, sizeof(scenario_index_entry), compareFunc); +} + +static int scenario_list_category_compare(int categoryA, int categoryB) +{ + if (categoryA == categoryB) return 0; + if (categoryA == SCENARIO_CATEGORY_DLC) return -1; + if (categoryB == SCENARIO_CATEGORY_DLC) return 1; + if (categoryA == SCENARIO_CATEGORY_BUILD_YOUR_OWN) return -1; + if (categoryB == SCENARIO_CATEGORY_BUILD_YOUR_OWN) return 1; + return sgn(categoryA - categoryB); +} + +static int scenario_list_sort_by_category(const void *a, const void *b) +{ + const scenario_index_entry *entryA = (const scenario_index_entry*)a; + const scenario_index_entry *entryB = (const scenario_index_entry*)b; + + // Order by category + if (entryA->category != entryB->category) { + return scenario_list_category_compare(entryA->category, entryB->category); + } + + // Then by source game / name + switch (entryA->category) { + default: + if (entryA->source_game != entryB->source_game) { + return entryA->source_game - entryB->source_game; + } + return strcmp(entryA->name, entryB->name); + case SCENARIO_CATEGORY_REAL: + case SCENARIO_CATEGORY_OTHER: + return strcmp(entryA->name, entryB->name); + } +} + +static int scenario_list_sort_by_index(const void *a, const void *b) +{ + const scenario_index_entry *entryA = (const scenario_index_entry*)a; + const scenario_index_entry *entryB = (const scenario_index_entry*)b; + + // Order by source game + if (entryA->source_game != entryB->source_game) { + return entryA->source_game - entryB->source_game; + } + + // Then by index / category / name + uint8 sourceGame = entryA->source_game; + switch (sourceGame) { + default: + if (entryA->source_index == -1 && entryB->source_index == -1) { + if (entryA->category == entryB->category) { + return scenario_list_sort_by_category(a, b); + } else { + return scenario_list_category_compare(entryA->category, entryB->category); + } + } else if (entryA->source_index == -1) { + return 1; + } else if (entryB->source_index == -1) { + return -1; + } else { + return entryA->source_index - entryB->source_index; + } + case SCENARIO_SOURCE_REAL: + return scenario_list_sort_by_category(a, b); + } +} + +scenario_index_entry *scenario_list_find_by_filename(const utf8 *filename) +{ + for (int i = 0; i < gScenarioListCount; i++) { + const utf8 *scenarioFilename = path_get_filename(gScenarioList[i].path); + if (_strcmpi(filename, scenarioFilename) == 0) { + return &gScenarioList[i]; + } + } + return NULL; +} + +scenario_index_entry *scenario_list_find_by_path(const utf8 *path) +{ + for (int i = 0; i < gScenarioListCount; i++) { + if (_strcmpi(path, gScenarioList[i].path) == 0) { + return &gScenarioList[i]; + } + } + return NULL; } /** * Gets the path for the scenario scores path. */ static void scenario_scores_get_path(utf8 *outPath) +{ + platform_get_user_directory(outPath, NULL); + strcat(outPath, "highscores.dat"); +} + +/** + * Gets the path for the scenario scores path. + */ +static void scenario_scores_legacy_get_path(utf8 *outPath) { platform_get_user_directory(outPath, NULL); strcat(outPath, "scores.dat"); } /** - * - * rct2: 0x006775A8 + * Loads the original scores.dat file and replaces any highscores that + * are better for matching scenarios. */ -static int scenario_scores_load() +static bool scenario_scores_legacy_load(const utf8 *path) { - SDL_RWops *file; - char scoresPath[MAX_PATH]; - - scenario_scores_get_path(scoresPath); - - // Free scenario list if already allocated - if (gScenarioList != NULL) { - free(gScenarioList); - gScenarioList = NULL; - } - - // Try and load the scores file - // First check user folder and then fallback to install directory - file = SDL_RWFromFile(scoresPath, "rb"); + SDL_RWops *file = SDL_RWFromFile(path, "rb"); if (file == NULL) { - file = SDL_RWFromFile(get_file_path(PATH_ID_SCORES), "rb"); - if (file == NULL) { - log_error("Unable to load scenario scores."); - return 0; - } + return false; } // Load header rct_scenario_scores_header header; if (SDL_RWread(file, &header, 16, 1) != 1) { SDL_RWclose(file); - log_error("Invalid header in scenario scores file."); - return 0; - } - gScenarioListCount = header.scenario_count; - - // Load scenario information with scores - int scenarioListBufferSize = gScenarioListCount * sizeof(rct_scenario_basic); - gScenarioListCapacity = gScenarioListCount; - gScenarioList = malloc(scenarioListBufferSize); - if (SDL_RWread(file, gScenarioList, scenarioListBufferSize, 1) == 1) { - SDL_RWclose(file); - return 1; + log_error("Invalid header in legacy scenario scores file."); + return false; } - // Unable to load scores, free scenario list + // Read scenarios + bool highscoresDirty = false; + for (uint32 i = 0; i < header.scenario_count; i++) { + // Read legacy entry + rct_scenario_basic scBasic; + if (SDL_RWread(file, &scBasic, sizeof(rct_scenario_basic), 1) != 1) { + break; + } + + // Ignore non-completed scenarios + if (!(scBasic.flags & SCENARIO_FLAGS_COMPLETED)) { + continue; + } + + // Find matching scenario entry + scenario_index_entry *scenarioIndexEntry = scenario_list_find_by_filename(scBasic.path); + if (scenarioIndexEntry != NULL) { + // Check if legacy highscore is better + scenario_highscore_entry *highscore = scenarioIndexEntry->highscore; + if (highscore == NULL) { + highscore = scenario_highscore_insert(); + scenarioIndexEntry->highscore = highscore; + } else if (highscore->company_value < (money32)scBasic.company_value) { + scenario_highscore_free(highscore); + // Re-use highscore entry + } else { + highscore = NULL; + } + + // Set new highscore + if (highscore != NULL) { + highscore->fileName = _strdup(scBasic.path); + highscore->name = _strdup(scBasic.completed_by); + highscore->company_value = (money32)scBasic.company_value; + highscore->timestamp = DATETIME64_MIN; + highscoresDirty = true; + } + + // Exit loop + break; + } + } SDL_RWclose(file); - gScenarioListCount = 0; - gScenarioListCapacity = 0; - free(gScenarioList); - gScenarioList = NULL; - return 0; + + if (highscoresDirty) { + scenario_scores_save(); + } + return true; +} + +static bool scenario_scores_load() +{ + utf8 scoresPath[MAX_PATH]; + scenario_scores_get_path(scoresPath); + + // Load scores file + SDL_RWops *file = SDL_RWFromFile(scoresPath, "rb"); + if (file == NULL) { + return false; + } + + // Check file version + uint32 fileVersion; + SDL_RWread(file, &fileVersion, sizeof(fileVersion), 1); + if (fileVersion != 1) { + log_error("Invalid or incompatible highscores file."); + return false; + } + + // Read and allocate the highscore list + scenario_highscore_list_dispose(); + SDL_RWread(file, &gScenarioHighscoreListCount, sizeof(gScenarioHighscoreListCount), 1); + gScenarioHighscoreListCapacity = gScenarioHighscoreListCount; + gScenarioHighscoreList = malloc(gScenarioHighscoreListCapacity * sizeof(scenario_highscore_entry)); + + // Read highscores + for (int i = 0; i < gScenarioHighscoreListCount; i++) { + scenario_highscore_entry *highscore = &gScenarioHighscoreList[i]; + highscore->fileName = io_read_string(file); + highscore->name = io_read_string(file); + SDL_RWread(file, &highscore->company_value, sizeof(highscore->company_value), 1); + SDL_RWread(file, &highscore->timestamp, sizeof(highscore->timestamp), 1); + + // Attach highscore to correct scenario entry + scenario_index_entry *scenarioIndexEntry = scenario_list_find_by_filename(highscore->fileName); + if (scenarioIndexEntry != NULL) { + scenarioIndexEntry->highscore = highscore; + } + } + + SDL_RWclose(file); + return true; } /** * * rct2: 0x00677B50 */ -int scenario_scores_save() +bool scenario_scores_save() { - SDL_RWops *file; utf8 scoresPath[MAX_PATH]; - scenario_scores_get_path(scoresPath); - file = SDL_RWFromFile(scoresPath, "wb"); + SDL_RWops *file = SDL_RWFromFile(scoresPath, "wb"); if (file == NULL) { log_error("Unable to save scenario scores."); - return 0; + return false; } - rct_scenario_scores_header header; - header.scenario_count = gScenarioListCount; - - SDL_RWwrite(file, &header, sizeof(header), 1); - if (gScenarioListCount > 0) - SDL_RWwrite(file, gScenarioList, gScenarioListCount * sizeof(rct_scenario_basic), 1); + const uint32 fileVersion = 1; + SDL_RWwrite(file, &fileVersion, sizeof(fileVersion), 1); + SDL_RWwrite(file, &gScenarioHighscoreListCount, sizeof(gScenarioHighscoreListCount), 1); + for (int i = 0; i < gScenarioHighscoreListCount; i++) { + scenario_highscore_entry *highscore = &gScenarioHighscoreList[i]; + io_write_string(file, highscore->fileName); + io_write_string(file, highscore->name); + SDL_RWwrite(file, &highscore->company_value, sizeof(highscore->company_value), 1); + SDL_RWwrite(file, &highscore->timestamp, sizeof(highscore->timestamp), 1); + } SDL_RWclose(file); - return 1; + + return true; +} + +scenario_highscore_entry *scenario_highscore_insert() +{ + if (gScenarioHighscoreListCount >= gScenarioHighscoreListCapacity) { + gScenarioHighscoreListCapacity = max(8, gScenarioHighscoreListCapacity * 2); + gScenarioHighscoreList = realloc(gScenarioHighscoreList, gScenarioHighscoreListCapacity * sizeof(scenario_highscore_entry)); + } + return &gScenarioHighscoreList[gScenarioHighscoreListCount++]; +} + +static void scenario_highscore_remove(scenario_highscore_entry *highscore) +{ + for (int i = 0; i < gScenarioHighscoreListCount; i++) { + if (&gScenarioHighscoreList[i] == highscore) { + size_t moveSize = (gScenarioHighscoreListCount - i - 1) * sizeof(scenario_highscore_entry); + if (moveSize > 0) { + memmove(&gScenarioHighscoreList[i], &gScenarioHighscoreList[i + 1], moveSize); + } + return; + } + } +} + +void scenario_highscore_free(scenario_highscore_entry *highscore) +{ + SafeFree(highscore->fileName); + SafeFree(highscore->name); +} + +static void scenario_highscore_list_dispose() +{ + for (int i = 0; i < gScenarioHighscoreListCount; i++) { + scenario_highscore_free(&gScenarioHighscoreList[i]); + } + gScenarioHighscoreListCapacity = 0; + gScenarioHighscoreListCount = 0; + SafeFree(gScenarioHighscoreList); +} + +static utf8 *io_read_string(SDL_RWops *file) +{ + size_t bufferCount = 0; + size_t bufferCapacity = 0; + utf8 *buffer = NULL; + + utf8 ch; + do { + SDL_RWread(file, &ch, sizeof(ch), 1); + if (ch == '\0' && buffer == NULL) { + break; + } + + if (bufferCount >= bufferCapacity) { + bufferCapacity = max(32, bufferCapacity * 2); + buffer = realloc(buffer, bufferCapacity * sizeof(uint8)); + } + + buffer[bufferCount] = ch; + bufferCount++; + } while (ch != '\0'); + + if (bufferCount < bufferCapacity) { + buffer = realloc(buffer, bufferCount); + } + return buffer; +} + +static void io_write_string(SDL_RWops *file, utf8 *source) +{ + if (source == NULL) { + utf8 empty = 0; + SDL_RWwrite(file, &empty, sizeof(utf8), 1); + } else { + SDL_RWwrite(file, source, strlen(source) + 1, 1); + } } diff --git a/src/scenario_sources.c b/src/scenario_sources.c new file mode 100644 index 0000000000..1ca3c957cb --- /dev/null +++ b/src/scenario_sources.c @@ -0,0 +1,306 @@ +#include "scenario.h" +#include "util/util.h" + +typedef struct { + const utf8 *original; + const utf8 *alternative; +} scenario_alias; + +const scenario_alias ScenarioAliases[] = { + // UK - US differences: + { "Katie's Dreamland", "Katie's World" }, + { "Pokey Park", "Dinky Park" }, + { "White Water Park", "Aqua Park" }, + { "Mystic Mountain", "Mothball Mountain" }, + { "Paradise Pier", "Big Pier" }, + { "Paradise Pier 2", "Big Pier 2" }, + { "Mythological - Cradle of Civilisation", "Mythological - Cradle of Civilization" }, + + // RCT1 pack by RCTScenarioLover has a mistake: + { "Geoffrey Gardens", "Geoffery Gardens" }, +}; + +typedef struct { + const uint8 id; + const utf8 *title; + const uint8 category; +} scenario_title_desc; + +// RCT +const scenario_title_desc ScenarioTitlesRCT1[] = { + { SC_FOREST_FRONTIERS, "Forest Frontiers", SCENARIO_CATEGORY_BEGINNER }, + { SC_DYNAMITE_DUNES, "Dynamite Dunes", SCENARIO_CATEGORY_BEGINNER }, + { SC_LEAFY_LAKES, "Leafy Lake", SCENARIO_CATEGORY_BEGINNER }, + { SC_DIAMOND_HEIGHTS, "Diamond Heights", SCENARIO_CATEGORY_BEGINNER }, + { SC_EVERGREEN_GARDENS, "Evergreen Gardens", SCENARIO_CATEGORY_BEGINNER }, + { SC_BUMBLY_BEACH, "Bumbly Beach", SCENARIO_CATEGORY_BEGINNER }, + { SC_TRINITY_ISLANDS, "Trinity Islands", SCENARIO_CATEGORY_CHALLENGING }, + { SC_KATIES_DREAMLAND, "Katie's Dreamland", SCENARIO_CATEGORY_CHALLENGING }, + { SC_POKEY_PARK, "Pokey Park", SCENARIO_CATEGORY_CHALLENGING }, + { SC_WHITE_WATER_PARK, "White Water Park", SCENARIO_CATEGORY_CHALLENGING }, + { SC_MILLENNIUM_MINES, "Millennium Mines", SCENARIO_CATEGORY_CHALLENGING }, + { SC_KARTS_COASTERS, "Karts & Coasters", SCENARIO_CATEGORY_CHALLENGING }, + { SC_MELS_WORLD, "Mel's World", SCENARIO_CATEGORY_CHALLENGING }, + { SC_MYSTIC_MOUNTAIN, "Mystic Mountain", SCENARIO_CATEGORY_CHALLENGING }, + { SC_PACIFIC_PYRAMIDS, "Pacific Pyramids", SCENARIO_CATEGORY_CHALLENGING }, + { SC_CRUMBLY_WOODS, "Crumbly Woods", SCENARIO_CATEGORY_CHALLENGING }, + { SC_PARADISE_PIER, "Paradise Pier", SCENARIO_CATEGORY_CHALLENGING }, + { SC_LIGHTNING_PEAKS, "Lightning Peaks", SCENARIO_CATEGORY_EXPERT }, + { SC_IVORY_TOWERS, "Ivory Towers", SCENARIO_CATEGORY_EXPERT }, + { SC_RAINBOW_VALLEY, "Rainbow Valley", SCENARIO_CATEGORY_EXPERT }, + { SC_THUNDER_ROCK, "Thunder Rock", SCENARIO_CATEGORY_EXPERT }, + { SC_MEGA_PARK, "Mega Park", SCENARIO_CATEGORY_OTHER }, +}; + +// RCT: Added Attractions +const scenario_title_desc ScenarioTitlesRCT1AA[] = { + { SC_WHISPERING_CLIFFS, "Whispering Cliffs", SCENARIO_CATEGORY_BEGINNER }, + { SC_THREE_MONKEYS_PARK, "Three Monkeys Park", SCENARIO_CATEGORY_BEGINNER }, + { SC_CANARY_MINES, "Canary Mines", SCENARIO_CATEGORY_BEGINNER }, + { SC_BARONY_BRIDGE, "Barony Bridge", SCENARIO_CATEGORY_BEGINNER }, + { SC_FUNTOPIA, "Funtopia", SCENARIO_CATEGORY_BEGINNER }, + { SC_HAUNTED_HARBOR, "Haunted Harbor", SCENARIO_CATEGORY_BEGINNER }, + { SC_FUN_FORTRESS, "Fun Fortress", SCENARIO_CATEGORY_BEGINNER }, + { SC_FUTURE_WORLD, "Future World", SCENARIO_CATEGORY_BEGINNER }, + { SC_GENTLE_GLEN, "Gentle Glen", SCENARIO_CATEGORY_BEGINNER }, + { SC_JOLLY_JUNGLE, "Jolly Jungle", SCENARIO_CATEGORY_CHALLENGING }, + { SC_HYDRO_HILLS, "Hydro Hills", SCENARIO_CATEGORY_CHALLENGING }, + { SC_SPRIGHTLY_PARK, "Sprightly Park", SCENARIO_CATEGORY_CHALLENGING }, + { SC_MAGIC_QUARTERS, "Magic Quarters", SCENARIO_CATEGORY_CHALLENGING }, + { SC_FRUIT_FARM, "Fruit Farm", SCENARIO_CATEGORY_CHALLENGING }, + { SC_BUTTERFLY_DAM, "Butterfly Dam", SCENARIO_CATEGORY_CHALLENGING }, + { SC_COASTER_CANYON, "Coaster Canyon", SCENARIO_CATEGORY_CHALLENGING }, + { SC_THUNDERSTORM_PARK, "Thunderstorm Park", SCENARIO_CATEGORY_CHALLENGING }, + { SC_HARMONIC_HILLS, "Harmonic Hills", SCENARIO_CATEGORY_CHALLENGING }, + { SC_ROMAN_VILLAGE, "Roman Village", SCENARIO_CATEGORY_CHALLENGING }, + { SC_SWAMP_COVE, "Swamp Cove", SCENARIO_CATEGORY_CHALLENGING }, + { SC_ADRENALINE_HEIGHTS, "Adrenaline Heights", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UTOPIA, "Utopia", SCENARIO_CATEGORY_CHALLENGING }, + { SC_ROTTING_HEIGHTS, "Rotting Heights", SCENARIO_CATEGORY_EXPERT }, + { SC_FIASCO_FOREST, "Fiasco Forest", SCENARIO_CATEGORY_EXPERT }, + { SC_PICKLE_PARK, "Pickle Park", SCENARIO_CATEGORY_EXPERT }, + { SC_GIGGLE_DOWNS, "Giggle Downs", SCENARIO_CATEGORY_EXPERT }, + { SC_MINERAL_PARK, "Mineral Park", SCENARIO_CATEGORY_EXPERT }, + { SC_COASTER_CRAZY, "Coaster Crazy", SCENARIO_CATEGORY_EXPERT }, + { SC_URBAN_PARK, "Urban Park", SCENARIO_CATEGORY_EXPERT }, + { SC_GEOFFREY_GARDENS, "Geoffrey Gardens", SCENARIO_CATEGORY_EXPERT }, +}; + +// RCT: Loopy Landscapes +const scenario_title_desc ScenarioTitlesRCT1LL[] = { + { SC_ICEBERG_ISLANDS, "Iceberg Islands", SCENARIO_CATEGORY_BEGINNER }, + { SC_VOLCANIA, "Volcania", SCENARIO_CATEGORY_BEGINNER }, + { SC_ARID_HEIGHTS, "Arid Heights", SCENARIO_CATEGORY_BEGINNER }, + { SC_RAZOR_ROCKS, "Razor Rocks", SCENARIO_CATEGORY_BEGINNER }, + { SC_CRATER_LAKE, "Crater Lake", SCENARIO_CATEGORY_BEGINNER }, + { SC_VERTIGO_VIEWS, "Vertigo Views", SCENARIO_CATEGORY_BEGINNER }, + { SC_PARADISE_PIER_2, "Paradise Pier 2", SCENARIO_CATEGORY_CHALLENGING }, + { SC_DRAGONS_COVE, "Dragon's Cove", SCENARIO_CATEGORY_CHALLENGING }, + { SC_GOOD_KNIGHT_PARK, "Good Knight Park", SCENARIO_CATEGORY_CHALLENGING }, + { SC_WACKY_WARREN, "Wacky Warren", SCENARIO_CATEGORY_CHALLENGING }, + { SC_GRAND_GLACIER, "Grand Glacier", SCENARIO_CATEGORY_CHALLENGING }, + { SC_CRAZY_CRATERS, "Crazy Craters", SCENARIO_CATEGORY_CHALLENGING }, + { SC_DUSTY_DESERT, "Dusty Desert", SCENARIO_CATEGORY_CHALLENGING }, + { SC_WOODWORM_PARK, "Woodworm Park", SCENARIO_CATEGORY_CHALLENGING }, + { SC_ICARUS_PARK, "Icarus Park", SCENARIO_CATEGORY_CHALLENGING }, + { SC_SUNNY_SWAMPS, "Sunny Swamps", SCENARIO_CATEGORY_CHALLENGING }, + { SC_FRIGHTMARE_HILLS, "Frightmare Hills", SCENARIO_CATEGORY_CHALLENGING }, + { SC_THUNDER_ROCKS, "Thunder Rocks", SCENARIO_CATEGORY_CHALLENGING }, + { SC_OCTAGON_PARK, "Octagon Park", SCENARIO_CATEGORY_CHALLENGING }, + { SC_PLEASURE_ISLAND, "Pleasure Island", SCENARIO_CATEGORY_CHALLENGING }, + { SC_ICICLE_WORLDS, "Icicle Worlds", SCENARIO_CATEGORY_CHALLENGING }, + { SC_SOUTHERN_SANDS, "Southern Sands", SCENARIO_CATEGORY_CHALLENGING }, + { SC_TINY_TOWERS, "Tiny Towers", SCENARIO_CATEGORY_CHALLENGING }, + { SC_NEVERMORE_PARK, "Nevermore Park", SCENARIO_CATEGORY_CHALLENGING }, + { SC_PACIFICA, "Pacifica", SCENARIO_CATEGORY_CHALLENGING }, + { SC_URBAN_JUNGLE, "Urban Jungle", SCENARIO_CATEGORY_EXPERT }, + { SC_TERROR_TOWN, "Terror Town", SCENARIO_CATEGORY_EXPERT }, + { SC_MEGAWORLD_PARK, "Megaworld Park", SCENARIO_CATEGORY_EXPERT }, + { SC_VENUS_PONDS, "Venus Ponds", SCENARIO_CATEGORY_EXPERT }, + { SC_MICRO_PARK, "Micro Park", SCENARIO_CATEGORY_EXPERT }, +}; + +// RCT2 +const scenario_title_desc ScenarioTitlesRCT2[] = { + { SC_UNIDENTIFIED, "Crazy Castle", SCENARIO_CATEGORY_BEGINNER }, + { SC_UNIDENTIFIED, "Electric Fields", SCENARIO_CATEGORY_BEGINNER }, + { SC_UNIDENTIFIED, "Factory Capers", SCENARIO_CATEGORY_BEGINNER }, + { SC_UNIDENTIFIED, "Amity Airfield", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Botany Breakers", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Bumbly Bazaar", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Dusty Greens", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Fungus Woods", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Gravity Gardens", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Infernal Views", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Alpine Adventures", SCENARIO_CATEGORY_EXPERT }, + { SC_UNIDENTIFIED, "Extreme Heights", SCENARIO_CATEGORY_EXPERT }, + { SC_UNIDENTIFIED, "Ghost Town", SCENARIO_CATEGORY_EXPERT }, + { SC_UNIDENTIFIED, "Lucky Lake", SCENARIO_CATEGORY_EXPERT }, + { SC_UNIDENTIFIED, "Rainbow Summit", SCENARIO_CATEGORY_EXPERT }, +}; + +// RCT2: Wacky Worlds +const scenario_title_desc ScenarioTitlesRCT2WW[] = { + { SC_UNIDENTIFIED, "Africa - Victoria Falls", SCENARIO_CATEGORY_BEGINNER }, + { SC_UNIDENTIFIED, "Asia - Great Wall of China Tourism Enhancement", SCENARIO_CATEGORY_BEGINNER }, + { SC_UNIDENTIFIED, "North America - Grand Canyon", SCENARIO_CATEGORY_BEGINNER }, + { SC_UNIDENTIFIED, "South America - Rio Carnival", SCENARIO_CATEGORY_BEGINNER }, + { SC_UNIDENTIFIED, "Africa - African Diamond Mine", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Asia - Maharaja Palace", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Australasia - Ayers Rock", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Europe - European Cultural Festival", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "North America - Rollercoaster Heaven", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "South America - Inca Lost City", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Africa - Oasis", SCENARIO_CATEGORY_EXPERT }, + { SC_UNIDENTIFIED, "Antarctic - Ecological Salvage", SCENARIO_CATEGORY_EXPERT }, + { SC_UNIDENTIFIED, "Asia - Japanese Coastal Reclaim", SCENARIO_CATEGORY_EXPERT }, + { SC_UNIDENTIFIED, "Australasia - Fun at the Beach", SCENARIO_CATEGORY_EXPERT }, + { SC_UNIDENTIFIED, "Europe - Renovation", SCENARIO_CATEGORY_EXPERT }, + { SC_UNIDENTIFIED, "N. America - Extreme Hawaiian Island", SCENARIO_CATEGORY_EXPERT }, + { SC_UNIDENTIFIED, "South America - Rain Forest Plateau", SCENARIO_CATEGORY_EXPERT }, +}; + +// RCT2: Time Twister +const scenario_title_desc ScenarioTitlesRCT2TT[] = { + { SC_UNIDENTIFIED, "Dark Age - Robin Hood", SCENARIO_CATEGORY_BEGINNER }, + { SC_UNIDENTIFIED, "Prehistoric - After the Asteroid", SCENARIO_CATEGORY_BEGINNER }, + { SC_UNIDENTIFIED, "Roaring Twenties - Prison Island", SCENARIO_CATEGORY_BEGINNER }, + { SC_UNIDENTIFIED, "Rock 'n' Roll - Flower Power", SCENARIO_CATEGORY_BEGINNER }, + { SC_UNIDENTIFIED, "Dark Age - Castle", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Future - First Encounters", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Mythological - Animatronic Film Set", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Prehistoric - Jurassic Safari", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Roaring Twenties - Schneider Cup", SCENARIO_CATEGORY_CHALLENGING }, + { SC_UNIDENTIFIED, "Future - Future World", SCENARIO_CATEGORY_EXPERT }, + { SC_UNIDENTIFIED, "Mythological - Cradle of Civilisation", SCENARIO_CATEGORY_EXPERT }, + { SC_UNIDENTIFIED, "Prehistoric - Stone Age", SCENARIO_CATEGORY_EXPERT }, + { SC_UNIDENTIFIED, "Roaring Twenties - Skyscrapers", SCENARIO_CATEGORY_EXPERT }, + { SC_UNIDENTIFIED, "Rock 'n' Roll - Rock 'n' Roll", SCENARIO_CATEGORY_EXPERT }, +}; + +// Real parks +const scenario_title_desc ScenarioTitlesRealParks[] = { + { SC_UNIDENTIFIED, "Alton Towers", SCENARIO_CATEGORY_REAL }, + { SC_UNIDENTIFIED, "Heide-Park", SCENARIO_CATEGORY_REAL }, + { SC_UNIDENTIFIED, "Blackpool Pleasure Beach", SCENARIO_CATEGORY_REAL }, + { SC_UNIDENTIFIED, "Six Flags Belgium", SCENARIO_CATEGORY_REAL }, + { SC_UNIDENTIFIED, "Six Flags Great Adventure", SCENARIO_CATEGORY_REAL }, + { SC_UNIDENTIFIED, "Six Flags Holland", SCENARIO_CATEGORY_REAL }, + { SC_UNIDENTIFIED, "Six Flags Magic Mountain", SCENARIO_CATEGORY_REAL }, + { SC_UNIDENTIFIED, "Six Flags over Texas", SCENARIO_CATEGORY_REAL }, +}; + +// Other parks +const scenario_title_desc ScenarioTitlesOtherParks[] = { + { SC_UNIDENTIFIED, "Fort Anachronism", SCENARIO_CATEGORY_DLC }, + { SC_UNIDENTIFIED, "PC Player", SCENARIO_CATEGORY_DLC }, + { SC_UNIDENTIFIED, "PC Gaming World", SCENARIO_CATEGORY_DLC }, + { SC_UNIDENTIFIED, "gameplay", SCENARIO_CATEGORY_DLC }, + { SC_UNIDENTIFIED, "Panda World", SCENARIO_CATEGORY_DLC }, + { SC_UNIDENTIFIED, "Competition Land 1", SCENARIO_CATEGORY_DLC }, + { SC_UNIDENTIFIED, "Competition Land 2", SCENARIO_CATEGORY_DLC }, + { SC_UNIDENTIFIED, "Build your own Six Flags Belgium", SCENARIO_CATEGORY_BUILD_YOUR_OWN }, + { SC_UNIDENTIFIED, "Build your own Six Flags Great Adventure", SCENARIO_CATEGORY_BUILD_YOUR_OWN }, + { SC_UNIDENTIFIED, "Build your own Six Flags Holland", SCENARIO_CATEGORY_BUILD_YOUR_OWN }, + { SC_UNIDENTIFIED, "Build your own Six Flags Magic Mountain", SCENARIO_CATEGORY_BUILD_YOUR_OWN }, + { SC_UNIDENTIFIED, "Build your own Six Flags Park", SCENARIO_CATEGORY_BUILD_YOUR_OWN }, + { SC_UNIDENTIFIED, "Build your own Six Flags over Texas", SCENARIO_CATEGORY_BUILD_YOUR_OWN }, +}; + +#define DEFINE_SCENARIO_TITLE_DESC_GROUP(x) { countof(x), x } +const struct { + int count; + const scenario_title_desc * const titles; +} ScenarioTitlesBySource[] = { + DEFINE_SCENARIO_TITLE_DESC_GROUP(ScenarioTitlesRCT1), + DEFINE_SCENARIO_TITLE_DESC_GROUP(ScenarioTitlesRCT1AA), + DEFINE_SCENARIO_TITLE_DESC_GROUP(ScenarioTitlesRCT1LL), + DEFINE_SCENARIO_TITLE_DESC_GROUP(ScenarioTitlesRCT2), + DEFINE_SCENARIO_TITLE_DESC_GROUP(ScenarioTitlesRCT2WW), + DEFINE_SCENARIO_TITLE_DESC_GROUP(ScenarioTitlesRCT2TT), + DEFINE_SCENARIO_TITLE_DESC_GROUP(ScenarioTitlesRealParks), + DEFINE_SCENARIO_TITLE_DESC_GROUP(ScenarioTitlesOtherParks), +}; + +bool scenario_get_source_desc(const utf8 *name, source_desc *outDesc) +{ + assert(outDesc != NULL); + + sint32 currentIndex = 0; + for (int i = 0; i < countof(ScenarioTitlesBySource); i++) { + for (int j = 0; j < ScenarioTitlesBySource[i].count; j++) { + const scenario_title_desc *desc = &ScenarioTitlesBySource[i].titles[j]; + if (_strcmpi(name, desc->title) == 0) { + outDesc->title = desc->title; + outDesc->id = desc->id; + outDesc->source = i; + outDesc->index = currentIndex; + outDesc->category = desc->category; + return true; + } + currentIndex++; + } + } + + outDesc->title = NULL; + outDesc->id = SC_UNIDENTIFIED; + outDesc->source = SCENARIO_SOURCE_OTHER; + outDesc->index = -1; + outDesc->category = SCENARIO_CATEGORY_OTHER; + return false; +} + +bool scenario_get_source_desc_by_id(uint8 id, source_desc *outDesc) +{ + assert(outDesc != NULL); + + sint32 currentIndex = 0; + for (int i = 0; i < countof(ScenarioTitlesBySource); i++) { + for (int j = 0; j < ScenarioTitlesBySource[i].count; j++) { + const scenario_title_desc *desc = &ScenarioTitlesBySource[i].titles[j]; + if (id == desc->id) { + outDesc->title = desc->title; + outDesc->id = desc->id; + outDesc->source = i; + outDesc->index = currentIndex; + outDesc->category = desc->category; + return true; + } + currentIndex++; + } + } + + outDesc->title = NULL; + outDesc->id = SC_UNIDENTIFIED; + outDesc->source = SCENARIO_SOURCE_OTHER; + outDesc->index = -1; + outDesc->category = SCENARIO_CATEGORY_OTHER; + return false; +} + +void scenario_normalise_name(utf8 *name) +{ + size_t nameLength = strlen(name); + + // Strip "RCT(1|2)?" prefix off scenario names. + if (nameLength >= 3 && (name[0] == 'R' && name[1] == 'C' && name[2] == 'T')) { + if (nameLength >= 4 && (name[3] == '1' || name[3] == '2')) { + log_verbose("Stripping RCT/1/2 from name: %s", name); + safe_strncpy(name, name + 4, 64); + } else { + safe_strncpy(name, name + 3, 64); + } + } + + // Trim (for the sake of the above and WW / TT scenarios + safe_strtrimleft(name, name, 64); + + // American scenario titles should be converted to British name + // Don't worry, names will be translated using language packs later + for (int i = 0; i < countof(ScenarioAliases); i++) { + if (strcmp(ScenarioAliases[i].alternative, name) == 0) { + log_verbose("Found alias: %s; will treat as: %s", name, ScenarioAliases[i].original); + safe_strncpy(name, ScenarioAliases[i].original, 64); + } + } +} diff --git a/src/title.c b/src/title.c index 33d6007ffe..3d636ef60d 100644 --- a/src/title.c +++ b/src/title.c @@ -64,6 +64,7 @@ rct_xy16 _titleScriptCurrentCentralPosition = { -1, -1 }; #define ZOOM(d) TITLE_SCRIPT_ZOOM, d #define RESTART() TITLE_SCRIPT_RESTART #define LOAD(i) TITLE_SCRIPT_LOAD, i +#define LOADRCT1(i) TITLE_SCRIPT_LOADRCT1, i static const uint8 _magicMountainScript[] = { LOADMM(), @@ -298,10 +299,7 @@ static void title_do_next_script_opcode() uint8 script_opcode, script_operand; rct_window* w; gTitleScriptCommand++; - if (gTitleScriptCommand <= 1 || *(_currentScript - 1) != TITLE_SCRIPT_END) - script_opcode = *_currentScript++; - else - script_opcode = *_currentScript; + script_opcode = *_currentScript++; if (gTitleScriptSkipTo != -1) { if (gTitleScriptSkipTo == gTitleScriptCommand) { gTitleScriptSkipTo = -1; @@ -422,6 +420,38 @@ static void title_do_next_script_opcode() } } break; + case TITLE_SCRIPT_LOADRCT1: + script_operand = (*_currentScript++); + + source_desc sourceDesc; + if (!scenario_get_source_desc_by_id(script_operand, &sourceDesc) || sourceDesc.index == -1) { + log_fatal("Invalid scenario id."); + exit(-1); + } + + const utf8 *path = NULL; + for (int i = 0; i < gScenarioListCount; i++) { + if (gScenarioList[i].source_index == sourceDesc.index) { + path = gScenarioList[i].path; + break; + } + } + + if (path == NULL || !title_load_park(path)) { + script_opcode = *_currentScript; + while (script_opcode != TITLE_SCRIPT_LOADRCT1 && script_opcode != TITLE_SCRIPT_RESTART && script_opcode != TITLE_SCRIPT_END) { + title_skip_opcode(); + script_opcode = *_currentScript; + } + if (script_opcode == TITLE_SCRIPT_RESTART) { + title_sequence_change_preset(4); + title_refresh_sequence(); + config_save_default(); + return; + } + } + gTitleScriptSave = 0xFF; + break; } window_invalidate_by_class(WC_TITLE_EDITOR); } @@ -508,7 +538,7 @@ void title_update() audio_start_title_music(); } - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~0x80; + gInputFlags &= ~INPUT_FLAG_VIEWPORT_SCROLLING; window_map_tooltip_update_visibility(); window_dispatch_update_all(); @@ -688,6 +718,9 @@ bool title_refresh_sequence() hasInvalidSave = true; hasLoad = true; } + else if (title->commands[i].command == TITLE_SCRIPT_LOADRCT1) { + hasLoad = true; + } else if (title->commands[i].command == TITLE_SCRIPT_LOADMM) { hasLoad = true; } @@ -711,6 +744,9 @@ bool title_refresh_sequence() for (int i = 0; i < title->num_commands; i++) { *scriptPtr++ = title->commands[i].command; switch (title->commands[i].command) { + case TITLE_SCRIPT_LOADRCT1: + *scriptPtr++ = title->commands[i].saveIndex; + break; case TITLE_SCRIPT_LOAD: src = title->saves[title->commands[i].saveIndex]; do { diff --git a/src/title.h b/src/title.h index 924bb738eb..88270393ee 100644 --- a/src/title.h +++ b/src/title.h @@ -34,7 +34,8 @@ enum { TITLE_SCRIPT_END, TITLE_SCRIPT_SPEED, TITLE_SCRIPT_LOOP, - TITLE_SCRIPT_ENDLOOP + TITLE_SCRIPT_ENDLOOP, + TITLE_SCRIPT_LOADRCT1, }; extern sint32 gTitleScriptCommand; diff --git a/src/tutorial.c b/src/tutorial.c deleted file mode 100644 index 56c2655872..0000000000 --- a/src/tutorial.c +++ /dev/null @@ -1,132 +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 "interface/window.h" -#include "localisation/localisation.h" -#include "tutorial.h" -#include "windows/error.h" -#include "windows/tooltip.h" - -static void sub_6EA2AA(rct_window *w, int widgetIndex, int x, int y, int edi); - -/** - * - * rct2: 0x0066ECC1 - */ -void tutorial_start(int type) -{ - strcpy((char*)0x009BC677, "Tutorial not implemented."); - window_error_open(3165, STR_NONE); -} - -/** - * - * rct2: 0x0066EE25 - */ -void tutorial_stop() -{ - // RCT2_CALLPROC_EBPSAFE(0x0066EE25); -} - -void game_handle_keyboard_input_for_tutorial() -{ -#ifdef ENABLE_TUTORIAL - rct_window *w; - - if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) == 1) { - int eax, ebx, ecx, edx, esi, edi, ebp; - RCT2_CALLFUNC_X(0x0066EEB4, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - eax &= 0xFF; - RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) = eax; - if (RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & 4) { - window_tooltip_close(); - if ((w = window_get_main()) != NULL) { - RCT2_CALLPROC_X(0x006EA2AA, 0, 0, 0, 0, (int)w, RCT2_GLOBAL(0x009DEA72, uint16), 0); - RCT2_GLOBAL(0x009DEA72, uint16)++; - } - } - } else { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & 4)) { - window_tooltip_close(); - if ((w = window_get_main()) != NULL) { - sub_6EA2AA(w, 0, 0, 0, RCT2_GLOBAL(0x009DEA72, uint16)); - RCT2_GLOBAL(0x009DEA72, uint16)++; - } - } - - // Write tutorial input - RCT2_CALLPROC_X(0x0066EEE1, RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8), 0, 0, 0, 0, 0, 0); - } -#endif -} - -static void sub_6EA2AA(rct_window *w, int widgetIndex, int x, int y, int edi) -{ -#ifdef ENABLE_TUTORIAL - RCT2_CALLPROC_X(0x006EA2AA, 0, 0, 0, 0, (int)w, RCT2_GLOBAL(0x009DEA72, uint16), 0); - return; - - rct_window *tooltipWindow; - - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) = w->classification; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_NUMBER, rct_windownumber) = w->number; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WIDGET_INDEX, uint16) = widgetIndex; - - rct_string_id stringId = window_event_tooltip_call(w, widgetIndex); - if (stringId == (rct_string_id)STR_NONE) - return; - - tooltipWindow = window_find_by_class(WC_TOOLTIP); - if (tooltipWindow == NULL) - return; - - char *buffer = (char*)RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER; - - RCT2_GLOBAL(0x0142006C, uint32) = edi; - format_string(buffer, edi, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS); - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; - int width = gfx_get_string_width_new_lined(buffer); - width = min(width, 196); - - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = 224; - - int numLines, fontHeight; - gfx_wrap_string(buffer, width + 1, &numLines, &fontHeight); - - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TEXT_HEIGHT, uint16) = numLines; - tooltipWindow->widgets[0].right = width + 3; - tooltipWindow->widgets[0].bottom = ((numLines + 1) * 10) + 4; - - char *tooltipBuffer = (char*)RCT2_ADDRESS_TOOLTIP_TEXT_BUFFER; - memcpy(tooltipBuffer, buffer, 512); - - window_tooltip_open(w, widgetIndex, x, y); -#endif -} - -/** - * - * rct2: 0x0066EE54 - */ -void sub_66EE54() -{ - // RCT2_CALLPROC_EBPSAFE(0x0066EE54); -} diff --git a/src/tutorial.h b/src/tutorial.h deleted file mode 100644 index a3de1993a3..0000000000 --- a/src/tutorial.h +++ /dev/null @@ -1,28 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014 Ted John - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * This file is part of OpenRCT2. - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#ifndef _TUTORIAL_H_ -#define _TUTORIAL_H_ - -void tutorial_start(int type); -void tutorial_stop(); -void sub_66EE54(); - -#endif diff --git a/src/util/util.c b/src/util/util.c index cfd0566eb7..bc18de7d65 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -67,7 +67,6 @@ const char *path_get_filename(const utf8 *path) // Checks if the path is valid (e.g. not just a file name) if (filename == NULL) { - log_warning("Invalid path given: %s", path); // Return the input string to keep things working return path; } @@ -78,6 +77,8 @@ const char *path_get_filename(const utf8 *path) return filename; } +// Returns the extension (dot inclusive) from the given path, or the end of the +// string when no extension was found. const char *path_get_extension(const utf8 *path) { // Get the filename from the path @@ -94,6 +95,15 @@ const char *path_get_extension(const utf8 *path) } void path_set_extension(utf8 *path, const utf8 *newExtension) +{ + // Remove existing extension (check first if there is one) + if (path_get_extension(path) < strrchr(path, '\0')) + path_remove_extension(path); + // Append new extension + path_append_extension(path, newExtension); +} + +void path_append_extension(utf8 *path, const utf8 *newExtension) { // Append a dot to the filename if the new extension doesn't start with it char *endOfString = strrchr(path, '\0'); @@ -101,15 +111,17 @@ void path_set_extension(utf8 *path, const utf8 *newExtension) *endOfString++ = '.'; // Append the extension to the path - // No existing extensions should be removed ("ride.TD6" -> "ride.TD6.TD6") safe_strncpy(endOfString, newExtension, MAX_PATH - (endOfString - path) - 1); } void path_remove_extension(utf8 *path) { // Find last dot in filename, and replace it with a null-terminator - char *lastDot = strrchr(path, '.'); - if (*lastDot) *lastDot = '\0'; + char *lastDot = strrchr(path_get_filename(path), '.'); + if (lastDot != NULL) + *lastDot = '\0'; + else + log_warning("No extension found. (path = %s)", path); } bool readentirefile(const utf8 *path, void **outBuffer, int *outLength) @@ -210,6 +222,70 @@ char *safe_strncpy(char * destination, const char * source, size_t size) return result; } +char *safe_strcat(char *destination, const char *source, size_t size) +{ + assert(destination != NULL); + assert(source != NULL); + + if (size == 0) { + return destination; + } + + char *result = destination; + + size_t i; + for (i = 0; i < size; i++) { + if (*destination == '\0') { + break; + } else { + destination++; + } + } + + bool terminated = false; + for (; 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.", result, size); + } + + return result; +} + +char *safe_strcat_path(char *destination, const char *source, size_t size) +{ + const char pathSeparator = platform_get_path_separator(); + + size_t length = strlen(destination); + if (length >= size - 1) { + return destination; + } + + if (destination[length - 1] != pathSeparator) { + destination[length] = pathSeparator; + destination[length + 1] = '\0'; + } + + return safe_strcat(destination, source, size); +} + +char *safe_strtrimleft(char *destination, const char *source, size_t size) +{ + while (*source == ' ' && *source != '\0') { + source++; + } + return safe_strncpy(destination, source, size); +} + bool utf8_is_bom(const char *str) { return str[0] == (char)0xEF && str[1] == (char)0xBB && str[2] == (char)0xBF; diff --git a/src/util/util.h b/src/util/util.h index 9dff48bc3d..6cef39d0c5 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -33,6 +33,7 @@ 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_append_extension(utf8 *path, const utf8 *newExtension); void path_remove_extension(utf8 *path); bool readentirefile(const utf8 *path, void **outBuffer, int *outLength); @@ -41,6 +42,9 @@ 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); +char *safe_strcat(char *destination, const char *source, size_t size); +char *safe_strcat_path(char *destination, const char *source, size_t size); +char *safe_strtrimleft(char *destination, const char *source, size_t size); bool utf8_is_bom(const char *str); bool str_is_null_or_empty(const char *str); diff --git a/src/windows/cheats.c b/src/windows/cheats.c index 9713ca8ba3..5a9a635b85 100644 --- a/src/windows/cheats.c +++ b/src/windows/cheats.c @@ -483,7 +483,7 @@ static void cheat_fix_vandalism() if (map_element_get_type(it.element) != MAP_ELEMENT_TYPE_PATH) continue; - if ((it.element->properties.path.additions & 0x0F) == 0) + if (!footpath_element_has_path_scenery(it.element)) continue; it.element->flags &= ~MAP_ELEMENT_FLAG_BROKEN; @@ -511,10 +511,10 @@ static void cheat_remove_litter() if (map_element_get_type(it.element) != MAP_ELEMENT_TYPE_PATH) continue; - if ((it.element->properties.path.additions & 0x0F) == 0) + if (!footpath_element_has_path_scenery(it.element)) continue; - sceneryEntry = g_pathBitSceneryEntries[(it.element->properties.path.additions & 0xF) - 1]; + sceneryEntry = g_pathBitSceneryEntries[footpath_element_get_path_scenery_index(it.element)]; if(sceneryEntry->path_bit.var_06 & (1 << 0)) it.element->properties.path.addition_status = 0xFF; diff --git a/src/windows/clear_scenery.c b/src/windows/clear_scenery.c index e6ef342c3d..ebc5251efb 100644 --- a/src/windows/clear_scenery.c +++ b/src/windows/clear_scenery.c @@ -194,8 +194,8 @@ static void window_clear_scenery_textinput(rct_window *w, int widgetIndex, char static void window_clear_scenery_inputsize(rct_window *w) { - ((uint16*)TextInputDescriptionArgs)[0] = MINIMUM_TOOL_SIZE; - ((uint16*)TextInputDescriptionArgs)[1] = MAXIMUM_TOOL_SIZE; + TextInputDescriptionArgs[0] = MINIMUM_TOOL_SIZE; + TextInputDescriptionArgs[1] = MAXIMUM_TOOL_SIZE; window_text_input_open(w, WIDX_PREVIEW, 5128, 5129, STR_NONE, STR_NONE, 3); } @@ -259,7 +259,7 @@ static void window_clear_scenery_paint(rct_window *w, rct_drawpixelinfo *dpi) */ static int window_clear_scenery_should_close() { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) + if (!(gInputFlags & INPUT_FLAG_TOOL_ACTIVE)) return 1; if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_TOP_TOOLBAR) return 1; diff --git a/src/windows/dropdown.c b/src/windows/dropdown.c index 43e92b9592..37bc26d370 100644 --- a/src/windows/dropdown.c +++ b/src/windows/dropdown.c @@ -160,9 +160,9 @@ void window_dropdown_show_text_custom_width(int x, int y, int extray, uint8 colo memcpy((void*)0x009DEBA4, gDropdownItemsFormat, 40 * 2); memcpy((void*)0x009DEBF4, gDropdownItemsArgs, 40 * 8); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~(INPUT_FLAG_DROPDOWN_STAY_OPEN | INPUT_FLAG_DROPDOWN_MOUSE_UP); + gInputFlags &= ~(INPUT_FLAG_DROPDOWN_STAY_OPEN | INPUT_FLAG_DROPDOWN_MOUSE_UP); if (flags & DROPDOWN_FLAG_STAY_OPEN) - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_DROPDOWN_STAY_OPEN; + gInputFlags |= INPUT_FLAG_DROPDOWN_STAY_OPEN; window_dropdown_close(); _dropdown_num_columns = 1; @@ -204,7 +204,7 @@ void window_dropdown_show_text_custom_width(int x, int y, int extray, uint8 colo gDropdownItemsDisabled = 0; gDropdownItemsChecked = 0; gDropdownIsColour = false; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, sint8) = INPUT_STATE_DROPDOWN_ACTIVE; + gInputState = INPUT_STATE_DROPDOWN_ACTIVE; } /** @@ -230,9 +230,9 @@ void window_dropdown_show_image(int x, int y, int extray, uint8 colour, uint8 fl memcpy((void*)0x009DEBA4, gDropdownItemsFormat, 40 * 2); memcpy((void*)0x009DEBF4, gDropdownItemsArgs, 40 * 8); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~(INPUT_FLAG_DROPDOWN_STAY_OPEN | INPUT_FLAG_DROPDOWN_MOUSE_UP); + gInputFlags &= ~(INPUT_FLAG_DROPDOWN_STAY_OPEN | INPUT_FLAG_DROPDOWN_MOUSE_UP); if (flags & DROPDOWN_FLAG_STAY_OPEN) - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_DROPDOWN_STAY_OPEN; + gInputFlags |= INPUT_FLAG_DROPDOWN_STAY_OPEN; // Close existing dropdown window_dropdown_close(); @@ -274,7 +274,7 @@ void window_dropdown_show_image(int x, int y, int extray, uint8 colour, uint8 fl gDropdownHighlightedIndex = -1; gDropdownItemsDisabled = 0; gDropdownItemsChecked = 0; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, sint8) = INPUT_STATE_DROPDOWN_ACTIVE; + gInputState = INPUT_STATE_DROPDOWN_ACTIVE; // Copy the following properties until all use of it is decompiled gDropdownHighlightedIndex = gDropdownHighlightedIndex; @@ -324,7 +324,7 @@ static void window_dropdown_paint(rct_window *w, rct_drawpixelinfo *dpi) item = gDropdownItemsFormat[i]; if (item == (uint16)-1 || item == (uint16)-2) { // Image item - image = *((uint32*)&gDropdownItemsArgs[i]); + image = (uint32)gDropdownItemsArgs[i]; if (item == (uint16)-2 && gDropdownHighlightedIndex == i) image++; diff --git a/src/windows/editor_bottom_toolbar.c b/src/windows/editor_bottom_toolbar.c index b03d98acb0..f0e6f15499 100644 --- a/src/windows/editor_bottom_toolbar.c +++ b/src/windows/editor_bottom_toolbar.c @@ -375,7 +375,7 @@ void window_editor_bottom_toolbar_jump_forward_to_save_scenario() s6Info->editor_step = 255; // Ensure path has .SC6 extension - path_set_extension(path, ".SC6"); + path_append_extension(path, ".SC6"); // Save the scenario parkFlagsBackup = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32); diff --git a/src/windows/editor_inventions_list.c b/src/windows/editor_inventions_list.c index 6fdab5406a..1afcad62e4 100644 --- a/src/windows/editor_inventions_list.c +++ b/src/windows/editor_inventions_list.c @@ -155,8 +155,6 @@ static rct_window_event_list window_editor_inventions_list_drag_events = { rct_research_item *_editorInventionsListDraggedItem; -#define WindowHighlightedItem(w) *((rct_research_item**)&(w->highlighted_item)) - static void window_editor_inventions_list_drag_open(rct_research_item *researchItem); static void move_research_item(rct_research_item *beforeItem); @@ -437,7 +435,7 @@ static void move_research_item(rct_research_item *beforeItem) w = window_find_by_class(WC_EDITOR_INVENTION_LIST); if (w != NULL) { - WindowHighlightedItem(w) = NULL; + w->research_item = NULL; window_invalidate(w); } } @@ -549,7 +547,7 @@ void window_editor_inventions_list_open() window_init_scroll_widgets(w); w->var_4AE = 0; w->selected_tab = 0; - WindowHighlightedItem(w) = NULL; + w->research_item = NULL; _editorInventionsListDraggedItem = NULL; } @@ -668,8 +666,8 @@ static void window_editor_inventions_list_scrollmouseover(rct_window *w, int scr rct_research_item *researchItem; researchItem = window_editor_inventions_list_get_item_from_scroll_y(scrollIndex, y); - if (researchItem != WindowHighlightedItem(w)) { - WindowHighlightedItem(w) = researchItem; + if (researchItem != w->research_item) { + w->research_item = researchItem; window_invalidate(w); } } @@ -770,7 +768,7 @@ static void window_editor_inventions_list_paint(rct_window *w, rct_drawpixelinfo researchItem = _editorInventionsListDraggedItem; if (researchItem == NULL) - researchItem = WindowHighlightedItem(w); + researchItem = w->research_item; // If the research item is null or a list separator. if (researchItem == NULL || researchItem->entryIndex < 0) return; @@ -842,7 +840,7 @@ static void window_editor_inventions_list_scrollpaint(rct_window *w, rct_drawpix continue; colour = 142; - if (WindowHighlightedItem(w) == researchItem) { + if (w->research_item == researchItem) { if (_editorInventionsListDraggedItem == NULL) { // Highlight top = itemY; @@ -912,8 +910,8 @@ static void window_editor_inventions_list_drag_open(rct_research_item *researchI window_editor_inventions_list_drag_widgets[0].right = stringWidth; w = window_create( - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, uint16) - (stringWidth / 2), - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, uint16) - 7, + gTooltipCursorX - (stringWidth / 2), + gTooltipCursorY - 7, stringWidth, 14, &window_editor_inventions_list_drag_events, @@ -922,9 +920,7 @@ static void window_editor_inventions_list_drag_open(rct_research_item *researchI ); w->widgets = window_editor_inventions_list_drag_widgets; w->colours[1] = 2; - input_window_position_begin( - w, 0, RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, uint16), RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, uint16) - ); + input_window_position_begin(w, 0, gTooltipCursorX, gTooltipCursorY); } /** @@ -939,8 +935,8 @@ static void window_editor_inventions_list_drag_cursor(rct_window *w, int widgetI inventionListWindow = window_find_by_class(WC_EDITOR_INVENTION_LIST); if (inventionListWindow != NULL) { researchItem = get_research_item_at(x, y); - if (researchItem != WindowHighlightedItem(inventionListWindow)) { - WindowHighlightedItem(inventionListWindow) = researchItem; + if (researchItem != inventionListWindow->research_item) { + inventionListWindow = (rct_window *)researchItem; window_invalidate(inventionListWindow); } } diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index ba322044fb..63ed78a400 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -36,6 +36,7 @@ #include "dropdown.h" #include "error.h" #include "../util/util.h" +#include "../world/footpath.h" enum { @@ -419,7 +420,7 @@ void window_editor_object_selection_open() window->var_4AE = 0; window->selected_tab = 0; window->selected_list_item = -1; - window->highlighted_item = 0xFFFFFFFF; + window->object_entry = (rct_object_entry *) 0xFFFFFFFF; window->min_width = 600; window->min_height = 400; window->max_width = 1200; @@ -577,7 +578,6 @@ static void setup_in_use_selection_flags(){ map_element_iterator_begin(&iter); do { uint16 type; - uint8 path_additions; rct_banner* banner; switch (map_element_get_type(iter.element)) { @@ -591,10 +591,9 @@ static void setup_in_use_selection_flags(){ 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); + if (footpath_element_has_path_scenery(iter.element)) { + uint8 path_additions = footpath_element_get_path_scenery_index(iter.element); + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_PATH_BITS][path_additions] |= 1; } break; case MAP_ELEMENT_TYPE_SCENERY: @@ -836,7 +835,7 @@ static void window_editor_object_selection_mouseup(rct_window *w, int widgetInde visible_list_refresh(w); w->selected_list_item = -1; - w->highlighted_item = 0xFFFFFFFF; + w->object_entry = (rct_object_entry *) 0xFFFFFFFF; w->scrolls[0].v_top = 0; object_free_scenario_text(); window_invalidate(w); @@ -856,7 +855,7 @@ static void window_editor_object_selection_mouseup(rct_window *w, int widgetInde visible_list_refresh(w); w->selected_list_item = -1; - w->highlighted_item = 0xFFFFFFFF; + w->object_entry = (rct_object_entry *) 0xFFFFFFFF; w->scrolls[0].v_top = 0; object_free_scenario_text(); window_invalidate(w); @@ -1051,7 +1050,7 @@ static void window_editor_object_selection_scroll_mouseover(rct_window *w, int s return; w->selected_list_item = selectedObject; - w->highlighted_item = (uint32)installedEntry; + w->object_entry = installedEntry; object_free_scenario_text(); if (selectedObject != -1) object_get_scenario_text(installedEntry); @@ -1342,7 +1341,7 @@ static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinf if (w->selected_list_item == -1 || stex_entry == NULL) return; - highlightedEntry = (rct_object_entry*)w->highlighted_item; + highlightedEntry = w->object_entry; type = highlightedEntry->flags & 0x0F; // Draw preview @@ -1458,7 +1457,7 @@ static void window_editor_object_selection_scrollpaint(rct_window *w, rct_drawpi // Highlight background colour = 142; - if (listItem->entry == (rct_object_entry*)w->highlighted_item && !(*listItem->flags & OBJECT_SELECTION_FLAG_6)) { + if (listItem->entry == w->object_entry && !(*listItem->flags & OBJECT_SELECTION_FLAG_6)) { gfx_fill_rect(dpi, 0, y, w->width, y + 11, 0x2000031); colour = 14; } @@ -1515,7 +1514,7 @@ static void window_editor_object_set_page(rct_window *w, int page) w->selected_tab = page; w->selected_list_item = -1; - w->highlighted_item = 0xFFFFFFFF; + w->object_entry = (rct_object_entry *)0xFFFFFFFF; w->scrolls[0].v_top = 0; object_free_scenario_text(); diff --git a/src/windows/editor_objective_options.c b/src/windows/editor_objective_options.c index 04bdad6fd1..aa7861c59e 100644 --- a/src/windows/editor_objective_options.c +++ b/src/windows/editor_objective_options.c @@ -534,9 +534,9 @@ static void window_editor_objective_options_show_category_dropdown(rct_window *w dropdownWidget = &w->widgets[WIDX_CATEGORY]; - for (i = 0; i < 5; i++) { + for (i = SCENARIO_CATEGORY_BEGINNER; i <= SCENARIO_CATEGORY_OTHER; i++) { gDropdownItemsFormat[i] = 1142; - gDropdownItemsArgs[i] = STR_BEGINNER_PARKS + i; + gDropdownItemsArgs[i] = ScenarioCategoryStringIds[i]; } window_dropdown_show_text_custom_width( w->x + dropdownWidget->left, @@ -1036,7 +1036,7 @@ static void window_editor_objective_options_main_paint(rct_window *w, rct_drawpi // Scenario category value x = w->x + w->widgets[WIDX_CATEGORY].left + 1; y = w->y + w->widgets[WIDX_CATEGORY].top; - stringId = STR_BEGINNER_PARKS + s6Info->category; + stringId = ScenarioCategoryStringIds[s6Info->category]; gfx_draw_string_left(dpi, 1193, &stringId, 0, x, y); } diff --git a/src/windows/footpath.c b/src/windows/footpath.c index d815f41985..46564f0de5 100644 --- a/src/windows/footpath.c +++ b/src/windows/footpath.c @@ -217,7 +217,7 @@ void window_footpath_open() tool_cancel(); RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) = PATH_CONSTRUCTION_MODE_LAND; tool_set(window, WIDX_CONSTRUCT_ON_LAND, 17); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_6; RCT2_GLOBAL(RCT2_ADDRESS_PATH_ERROR_OCCURED, uint8) = 0; window_footpath_set_enabled_and_pressed_widgets(); } @@ -263,7 +263,7 @@ static void window_footpath_mouseup(rct_window *w, int widgetIndex) RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~2; RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) = PATH_CONSTRUCTION_MODE_LAND; tool_set(w, WIDX_CONSTRUCT_ON_LAND, 17); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_6; RCT2_GLOBAL(RCT2_ADDRESS_PATH_ERROR_OCCURED, uint8) = 0; window_footpath_set_enabled_and_pressed_widgets(); break; @@ -278,7 +278,7 @@ static void window_footpath_mouseup(rct_window *w, int widgetIndex) RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~2; RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) = PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL_TOOL; tool_set(w, WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL, 12); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_6; RCT2_GLOBAL(RCT2_ADDRESS_PATH_ERROR_OCCURED, uint8) = 0; window_footpath_set_enabled_and_pressed_widgets(); break; @@ -479,14 +479,14 @@ static void window_footpath_update(rct_window *w) // Check tool if (RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) == PATH_CONSTRUCTION_MODE_LAND) { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) + if (!(gInputFlags & INPUT_FLAG_TOOL_ACTIVE)) window_close(w); else if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_FOOTPATH) window_close(w); else if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) != WIDX_CONSTRUCT_ON_LAND) window_close(w); } else if (RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL_TOOL) { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) + if (!(gInputFlags & INPUT_FLAG_TOOL_ACTIVE)) window_close(w); else if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_FOOTPATH) window_close(w); diff --git a/src/windows/game_bottom_toolbar.c b/src/windows/game_bottom_toolbar.c index 9dbc2aebf4..1fbe55c2d7 100644 --- a/src/windows/game_bottom_toolbar.c +++ b/src/windows/game_bottom_toolbar.c @@ -20,10 +20,12 @@ #include "../addresses.h" #include "../config.h" -#include "../localisation/date.h" -#include "../localisation/localisation.h" +#include "../input.h" +#include "../interface/themes.h" #include "../interface/widget.h" #include "../interface/window.h" +#include "../localisation/date.h" +#include "../localisation/localisation.h" #include "../management/news_item.h" #include "../peep/peep.h" #include "../peep/staff.h" @@ -31,7 +33,6 @@ #include "../world/climate.h" #include "../world/park.h" #include "../world/sprite.h" -#include "../interface/themes.h" enum WINDOW_GAME_BOTTOM_TOOLBAR_WIDGET_IDX { WIDX_LEFT_OUTSET, @@ -85,7 +86,6 @@ static void window_game_bottom_toolbar_draw_left_panel(rct_drawpixelinfo *dpi, r static void window_game_bottom_toolbar_draw_park_rating(rct_drawpixelinfo *dpi, rct_window *w, int colour, int x, int y, uint8 factor); static void window_game_bottom_toolbar_draw_right_panel(rct_drawpixelinfo *dpi, rct_window *w); static void window_game_bottom_toolbar_draw_news_item(rct_drawpixelinfo *dpi, rct_window *w); -static void window_game_bottom_toolbar_draw_tutorial_text(rct_drawpixelinfo *dpi, rct_window *w); /** * @@ -358,8 +358,6 @@ static void window_game_bottom_toolbar_paint(rct_window *w, rct_drawpixelinfo *d 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); } static void window_game_bottom_toolbar_draw_left_panel(rct_drawpixelinfo *dpi, rct_window *w) @@ -551,7 +549,7 @@ static void window_game_bottom_toolbar_draw_news_item(rct_drawpixelinfo *dpi, rc } } - uint32 image_id_base = *RCT2_ADDRESS(0x00982708, uint32*)[peep->sprite_type * 2]; + uint32 image_id_base = g_sprite_entries[peep->sprite_type].sprite_image->base_image; image_id_base += w->frame_no & 0xFFFFFFFC; image_id_base++; @@ -599,16 +597,6 @@ 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) -{ - int x, y; - - x = (window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].left + window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].right) / 2 + w->x; - y = window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].top + w->y + 2; - gfx_draw_string_centred(dpi, STR_TUTORIAL, x, y, 32, 0); - gfx_draw_string_centred(dpi, STR_PRESS_KEY_OR_MOUSE_BUTTON_FOR_CONTROL, x, y + 10, 32, 0); -} - /** * * rct2: 0x0066C6D8 @@ -633,7 +621,7 @@ static void window_game_bottom_toolbar_cursor(rct_window *w, int widgetIndex, in case WIDX_GUESTS: case WIDX_PARK_RATING: case WIDX_DATE: - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = 2000; + gTooltipTimeout = 2000; break; } } diff --git a/src/windows/guest.c b/src/windows/guest.c index 58f808db5c..cc1782d4c2 100644 --- a/src/windows/guest.c +++ b/src/windows/guest.c @@ -503,7 +503,7 @@ void window_guest_open(rct_peep* peep){ window->viewport_focus_coordinates.y = 0; window->frame_no = 0; window->list_information_type = 0; - window->var_492 = 0; + window->picked_peep_frame = 0; window->highlighted_item = 0; window_guest_disable_widgets(window); window->min_width = 192; @@ -560,7 +560,7 @@ void window_guest_disable_widgets(rct_window* w){ */ void window_guest_overview_close(rct_window *w) { - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE){ + if (gInputFlags & 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(); @@ -625,7 +625,7 @@ void window_guest_overview_mouse_up(rct_window *w, int widgetIndex) return; } - w->var_48C = peep->x; + w->picked_peep_old_x = peep->x; remove_peep_from_ride(peep); invalidate_sprite_2((rct_sprite*)peep); @@ -653,7 +653,7 @@ void window_guest_overview_mouse_up(rct_window *w, int widgetIndex) * rct2: 0x696AA0 */ void window_guest_set_page(rct_window* w, int page){ - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) + if (gInputFlags & INPUT_FLAG_TOOL_ACTIVE) { if(w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) && w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass)) @@ -830,7 +830,7 @@ void window_guest_overview_tab_paint(rct_window* w, rct_drawpixelinfo* dpi){ 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 ebx = g_sprite_entries[peep->sprite_type].sprite_image->base_image + 1; int eax = 0; @@ -1182,7 +1182,7 @@ void window_guest_overview_tool_update(rct_window* w, int widgetIndex, int x, in map_invalidate_selection_rect(); } - RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32) = -1; + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_IMAGE, sint32) = -1; int interactionType; get_map_coordinates_from_pos(x, y, VIEWPORT_INTERACTION_MASK_NONE, NULL, NULL, &interactionType, NULL, NULL); @@ -1193,19 +1193,21 @@ void window_guest_overview_tool_update(rct_window* w, int widgetIndex, int x, in y += 16; RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_X, uint16) = x; RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_Y, uint16) = y; - w->var_492++; - if (w->var_492 >= 48)w->var_492 = 0; + w->picked_peep_frame++; + if (w->picked_peep_frame >= 48) { + w->picked_peep_frame = 0; + } rct_peep* peep; peep = GET_PEEP(w->number); - int ebx = (RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2])[22]; - ebx += w->var_492 >> 2; + uint32 imageId = g_sprite_entries[peep->sprite_type].sprite_image[11].base_image; + imageId += w->picked_peep_frame >> 2; int ebp = peep->tshirt_colour << 19; int ecx = peep->trousers_colour << 24; - ebx |= ebp | ecx | 0xA0000000; - RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, uint32) = ebx; + imageId |= ebp | ecx | 0xA0000000; + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_IMAGE, uint32) = imageId; } /** @@ -1254,7 +1256,7 @@ void window_guest_overview_tool_down(rct_window* w, int widgetIndex, int x, int peep->state = 0; peep_window_state_update(peep); peep->action = 0xFF; - peep->var_6D = 0; + peep->special_sprite = 0; peep->action_sprite_image_offset = 0; peep->action_sprite_type = 0xFF; peep->var_C4 = 0; @@ -1279,7 +1281,7 @@ void window_guest_overview_tool_abort(rct_window *w, int widgetIndex) if (peep->state != PEEP_STATE_PICKED) return; - sprite_move( w->var_48C, peep->y, peep->z + 8, (rct_sprite*)peep); + sprite_move(w->picked_peep_old_x, peep->y, peep->z + 8, (rct_sprite*)peep); invalidate_sprite_2((rct_sprite*)peep); if (peep->x != (sint16)0x8000){ @@ -1287,13 +1289,13 @@ void window_guest_overview_tool_abort(rct_window *w, int widgetIndex) peep->state = 0; peep_window_state_update(peep); peep->action = 0xFF; - peep->var_6D = 0; + peep->special_sprite = 0; peep->action_sprite_image_offset = 0; peep->action_sprite_type = 0; peep->var_C4 = 0; } - RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32) = -1; + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_IMAGE, sint32) = -1; } /** diff --git a/src/windows/guest_list.c b/src/windows/guest_list.c index b1079bda40..f4989979c0 100644 --- a/src/windows/guest_list.c +++ b/src/windows/guest_list.c @@ -590,7 +590,7 @@ static void window_guest_list_paint(rct_window *w, rct_drawpixelinfo *dpi) window_draw_widgets(w, dpi); // Tab 1 image i = (_window_guest_list_selected_tab == 0 ? w->list_information_type & 0x0FFFFFFFC : 0); - i += RCT2_ADDRESS(RCT2_GLOBAL(0x00982708, int), int)[0] + 1; + i += g_sprite_entries[0].sprite_image->base_image + 1; i |= 0xA1600000; gfx_draw_sprite( dpi, @@ -655,14 +655,14 @@ static void window_guest_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, // For each guest FOR_ALL_GUESTS(spriteIndex, peep) { - peep->var_0C &= ~0x200; + peep->list_flags &= ~(PEEP_LIST_FLAGS_FLASHING); if (peep->outside_of_park != 0) continue; if (_window_guest_list_selected_filter != -1) { if (window_guest_list_is_peep_in_filter(peep)) continue; RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) |= (1 << 0); - peep->var_0C |= 0x200; + peep->list_flags |= PEEP_LIST_FLAGS_FLASHING; } if (_window_guest_list_tracking_only && !(peep->flags & PEEP_FLAGS_TRACKING)) continue; @@ -841,11 +841,11 @@ static void window_guest_list_find_groups() // Set all guests to unassigned FOR_ALL_GUESTS(spriteIndex, peep) if (peep->outside_of_park == 0) - peep->var_0C |= (1 << 8); + peep->list_flags |= PEEP_LIST_FLAGS_VISIBLE; // For each guest / group FOR_ALL_GUESTS(spriteIndex, peep) { - if (peep->outside_of_park != 0 || !(peep->var_0C & (1 << 8))) + if (peep->outside_of_park != 0 || !(peep->list_flags & PEEP_LIST_FLAGS_VISIBLE)) continue; // New group, cap at 240 though @@ -856,7 +856,7 @@ static void window_guest_list_find_groups() int ax = peep->sprite_index; _window_guest_list_num_groups++; _window_guest_list_groups_num_guests[groupIndex] = 1; - peep->var_0C &= ~(1 << 8); + peep->list_flags &= ~(PEEP_LIST_FLAGS_VISIBLE); 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]; @@ -868,7 +868,7 @@ static void window_guest_list_find_groups() // Find more peeps that belong to same group FOR_ALL_GUESTS(spriteIndex2, peep2) { - if (peep2->outside_of_park != 0 || !(peep2->var_0C & (1 << 8))) + if (peep2->outside_of_park != 0 || !(peep2->list_flags & PEEP_LIST_FLAGS_VISIBLE)) continue; uint32 argument1, argument2; @@ -879,7 +879,7 @@ static void window_guest_list_find_groups() // Assign guest _window_guest_list_groups_num_guests[groupIndex]++; - peep2->var_0C &= ~(1 << 8); + peep2->list_flags &= ~(PEEP_LIST_FLAGS_VISIBLE); // Add face sprite, cap at 56 though if (_window_guest_list_groups_num_guests[groupIndex] >= 56) diff --git a/src/windows/land.c b/src/windows/land.c index 97b5a85f1b..c98a6ffedb 100644 --- a/src/windows/land.c +++ b/src/windows/land.c @@ -272,7 +272,7 @@ static void window_land_dropdown(rct_window *w, int widgetIndex, int dropdownInd type = (dropdownIndex == -1) ? _selectedFloorTexture : - *((uint32*)&gDropdownItemsArgs[dropdownIndex]) - SPR_FLOOR_TEXTURE_GRASS; + (uint32)gDropdownItemsArgs[dropdownIndex] - SPR_FLOOR_TEXTURE_GRASS; if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) == type) { RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) = 255; @@ -288,7 +288,7 @@ static void window_land_dropdown(rct_window *w, int widgetIndex, int dropdownInd type = (dropdownIndex == -1) ? _selectedWallTexture : - *((uint32*)&gDropdownItemsArgs[dropdownIndex]) - SPR_WALL_TEXTURE_ROCK; + (uint32)gDropdownItemsArgs[dropdownIndex] - SPR_WALL_TEXTURE_ROCK; if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) == type) { RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) = 255; @@ -321,8 +321,8 @@ static void window_land_textinput(rct_window *w, int widgetIndex, char *text) static void window_land_inputsize(rct_window *w) { - ((uint16*)TextInputDescriptionArgs)[0] = MINIMUM_TOOL_SIZE; - ((uint16*)TextInputDescriptionArgs)[1] = MAXIMUM_TOOL_SIZE; + TextInputDescriptionArgs[0] = MINIMUM_TOOL_SIZE; + TextInputDescriptionArgs[1] = MAXIMUM_TOOL_SIZE; window_text_input_open(w, WIDX_PREVIEW, 5128, 5129, STR_NONE, STR_NONE, 3); } diff --git a/src/windows/land_rights.c b/src/windows/land_rights.c index b59432fee9..6d5b6723f0 100644 --- a/src/windows/land_rights.c +++ b/src/windows/land_rights.c @@ -188,8 +188,8 @@ static void window_land_rights_textinput(rct_window *w, int widgetIndex, char *t static void window_land_rights_inputsize(rct_window *w) { - ((uint16*)TextInputDescriptionArgs)[0] = MINIMUM_TOOL_SIZE; - ((uint16*)TextInputDescriptionArgs)[1] = MAXIMUM_TOOL_SIZE; + TextInputDescriptionArgs[0] = MINIMUM_TOOL_SIZE; + TextInputDescriptionArgs[1] = MAXIMUM_TOOL_SIZE; window_text_input_open(w, WIDX_PREVIEW, 5128, 5129, STR_NONE, STR_NONE, 3); } @@ -237,7 +237,7 @@ static void window_land_rights_paint(rct_window *w, rct_drawpixelinfo *dpi) static int window_land_rights_should_close() { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) + if (!(gInputFlags & INPUT_FLAG_TOOL_ACTIVE)) return 1; if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_PARK_INFORMATION) return 1; diff --git a/src/windows/loadsave.c b/src/windows/loadsave.c index 227483cce9..42842a8723 100644 --- a/src/windows/loadsave.c +++ b/src/windows/loadsave.c @@ -144,8 +144,6 @@ 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) @@ -160,7 +158,6 @@ rct_window *window_loadsave_open(int type, char *defaultName) if (!str_is_null_or_empty(defaultName)) { safe_strncpy(_defaultName, defaultName, sizeof(_defaultName)); - path_remove_extension(_defaultName); } w = window_bring_to_front_by_class(WC_LOADSAVE); @@ -221,21 +218,12 @@ rct_window *window_loadsave_open(int type, char *defaultName) window_loadsave_populate_list(w, includeNewItem, path, ".sc6"); break; case LOADSAVETYPE_SCENARIO: - /* - Uncomment when user scenarios are separated - platform_get_user_directory(path, "scenario"); if (!platform_ensure_directory_exists(path)) { - log_error("Unable to create scenarios directory."); - window_close(w); - return NULL; + log_error("Unable to create scenarios directory."); + window_close(w); + return NULL; } - */ - - safe_strncpy(path, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), MAX_PATH); - ch = strchr(path, '*'); - if (ch != NULL) - *ch = 0; window_loadsave_populate_list(w, includeNewItem, path, ".sc6"); break; @@ -306,12 +294,13 @@ static void window_loadsave_mouseup(rct_window *w, int widgetIndex) } case WIDX_BROWSE: safe_strncpy(path, _directory, MAX_PATH); - if (_type & LOADSAVETYPE_SAVE) - strcat(path, (char*)RCT2_ADDRESS_SCENARIO_NAME); + if (_type & LOADSAVETYPE_SAVE) { + strcat(path, _defaultName); + } memset(filter, '\0', MAX_PATH); safe_strncpy(filter, "*", MAX_PATH); - strncat(filter, _extension, MAX_PATH); + strncat(filter, _extension, MAX_PATH - strnlen(filter, MAX_PATH) - 1); switch (_type) { case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME) : @@ -336,7 +325,7 @@ static void window_loadsave_mouseup(rct_window *w, int widgetIndex) if (result) { if (!has_extension(path, _extension)) { - strncat(path, _extension, MAX_PATH); + strncat(path, _extension, sizeof(path) - strnlen(path, sizeof(path)) - 1); } window_loadsave_select(w, path); } @@ -480,8 +469,9 @@ static void window_loadsave_paint(rct_window *w, rct_drawpixelinfo *dpi) { window_draw_widgets(w, dpi); - if (_shortenedDirectory[0] == '\0') - shorten_path(_directory, _shortenedDirectory, w->width - 8); + if (_shortenedDirectory[0] == '\0') { + shorten_path(_shortenedDirectory, sizeof(_shortenedDirectory), _directory, w->width - 8); + } utf8 buffer[256]; @@ -510,41 +500,6 @@ static void window_loadsave_paint(rct_window *w, rct_drawpixelinfo *dpi) 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 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; @@ -684,7 +639,7 @@ static void window_loadsave_populate_list(rct_window *w, int includeNewItem, con listItem = &_listItems[_listItemsCount]; memset(listItem->path, '\0', MAX_PATH); safe_strncpy(listItem->path, directory, MAX_PATH); - strncat(listItem->path, subDir, MAX_PATH); + strncat(listItem->path, subDir, MAX_PATH - strnlen(listItem->path, MAX_PATH) - 1); safe_strncpy(listItem->name, subDir, sizeof(listItem->name)); listItem->type = TYPE_DIRECTORY; _listItemsCount++; @@ -700,7 +655,7 @@ static void window_loadsave_populate_list(rct_window *w, int includeNewItem, con listItem = &_listItems[_listItemsCount]; safe_strncpy(listItem->path, directory, sizeof(listItem->path)); - strncat(listItem->path, fileInfo.path, sizeof(listItem->path)); + strncat(listItem->path, fileInfo.path, sizeof(listItem->path) - strnlen(listItem->path, MAX_PATH) - 1); listItem->type = TYPE_FILE; listItem->date_modified = platform_file_get_modified_time(listItem->path); diff --git a/src/windows/map.c b/src/windows/map.c index 8e6b06b766..ffc74fa61b 100644 --- a/src/windows/map.c +++ b/src/windows/map.c @@ -241,7 +241,7 @@ void window_map_open() static void window_map_close(rct_window *w) { free(RCT2_GLOBAL(RCT2_ADDRESS_MAP_IMAGE_DATA, uint32*)); - if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && + if ((gInputFlags & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == w->classification && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, uint16) == w->number) { tool_cancel(); @@ -319,7 +319,7 @@ static void window_map_mouseup(rct_window *w, int widgetIndex) break; RCT2_GLOBAL(0x9E32D2, sint8) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_6; show_gridlines(); show_land_rights(); @@ -740,7 +740,7 @@ static void window_map_invalidate(rct_window *w) 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) && + (gInputFlags & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) == WC_MAP && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == WIDX_BUILD_PARK_ENTRANCE ) { @@ -752,7 +752,7 @@ static void window_map_invalidate(rct_window *w) // If any tool is active if ( - (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && + (gInputFlags & 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 @@ -935,15 +935,15 @@ static void window_map_show_default_scenario_editor_buttons(rct_window *w) { static void window_map_inputsize_land(rct_window *w) { - ((uint16*)TextInputDescriptionArgs)[0] = MINIMUM_TOOL_SIZE; - ((uint16*)TextInputDescriptionArgs)[1] = MAXIMUM_TOOL_SIZE; + TextInputDescriptionArgs[0] = MINIMUM_TOOL_SIZE; + 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; + TextInputDescriptionArgs[0] = MINIMUM_MAP_SIZE_PRACTICAL; + TextInputDescriptionArgs[1] = MAXIMUM_MAP_SIZE_PRACTICAL; window_text_input_open(w, WIDX_MAP_SIZE_SPINNER, 5130, 5131, STR_NONE, STR_NONE, 4); } @@ -1028,7 +1028,7 @@ static void window_map_paint_peep_overlay(rct_drawpixelinfo *dpi) color = 0x14; - if ((peep->var_0C & 0x200) != 0) { + if ((peep->list_flags & PEEP_LIST_FLAGS_FLASHING) != 0) { if (peep->type == PEEP_TYPE_STAFF) { if ((RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) & (1 << 3)) != 0) { color = 0x8A; diff --git a/src/windows/map_tooltip.c b/src/windows/map_tooltip.c index 180a3f9709..eb5b2179f1 100644 --- a/src/windows/map_tooltip.c +++ b/src/windows/map_tooltip.c @@ -81,7 +81,7 @@ void window_map_tooltip_update_visibility() cursorX = RCT2_GLOBAL(0x0142406C, sint32); cursorY = RCT2_GLOBAL(0x01424070, sint32); - inputFlags = RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32); + inputFlags = gInputFlags; // Check for cursor movement _cursorHoldDuration++; diff --git a/src/windows/mapgen.c b/src/windows/mapgen.c index f95f875ad9..9a48fc074d 100644 --- a/src/windows/mapgen.c +++ b/src/windows/mapgen.c @@ -488,19 +488,19 @@ static void window_mapgen_base_mouseup(rct_window *w, int widgetIndex) gfx_invalidate_screen(); break; case WIDX_MAP_SIZE: - ((uint16*)TextInputDescriptionArgs)[0] = MINIMUM_MAP_SIZE_PRACTICAL; - ((uint16*)TextInputDescriptionArgs)[1] = MAXIMUM_MAP_SIZE_PRACTICAL; + TextInputDescriptionArgs[0] = MINIMUM_MAP_SIZE_PRACTICAL; + 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; - ((uint16*)TextInputDescriptionArgs)[1] = (BASESIZE_MAX - 12) / 2; + TextInputDescriptionArgs[0] = (BASESIZE_MIN - 12) / 2; + TextInputDescriptionArgs[1] = (BASESIZE_MAX - 12) / 2; window_text_input_open(w, WIDX_BASE_HEIGHT, 5183, 5184, 5182, (_baseHeight - 12) / 2, 3); break; case WIDX_WATER_LEVEL: - ((uint16*)TextInputDescriptionArgs)[0] = (WATERLEVEL_MIN - 12) / 2; - ((uint16*)TextInputDescriptionArgs)[1] = (WATERLEVEL_MAX - 12) / 2; + TextInputDescriptionArgs[0] = (WATERLEVEL_MIN - 12) / 2; + TextInputDescriptionArgs[1] = (WATERLEVEL_MAX - 12) / 2; window_text_input_open(w, WIDX_WATER_LEVEL, 5185, 5186, 5182, (_waterLevel - 12) / 2, 3); break; } @@ -583,7 +583,7 @@ static void window_mapgen_base_dropdown(rct_window *w, int widgetIndex, int drop type = (dropdownIndex == -1) ? _floorTexture : - *((uint32*)&gDropdownItemsArgs[dropdownIndex]) - SPR_FLOOR_TEXTURE_GRASS; + (uint32)gDropdownItemsArgs[dropdownIndex] - SPR_FLOOR_TEXTURE_GRASS; if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) == type) { RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) = 255; @@ -599,7 +599,7 @@ static void window_mapgen_base_dropdown(rct_window *w, int widgetIndex, int drop type = (dropdownIndex == -1) ? _wallTexture : - *((uint32*)&gDropdownItemsArgs[dropdownIndex]) - SPR_WALL_TEXTURE_ROCK; + (uint32)gDropdownItemsArgs[dropdownIndex] - SPR_WALL_TEXTURE_ROCK; if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) == type) { RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) = 255; @@ -790,8 +790,8 @@ static void window_mapgen_simplex_mouseup(rct_window *w, int widgetIndex) 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; + TextInputDescriptionArgs[0] = MINIMUM_MAP_SIZE_PRACTICAL; + 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; @@ -916,7 +916,7 @@ static void window_mapgen_simplex_dropdown(rct_window *w, int widgetIndex, int d type = (dropdownIndex == -1) ? _floorTexture : - *((uint32*)&gDropdownItemsArgs[dropdownIndex]) - SPR_FLOOR_TEXTURE_GRASS; + (uint32)gDropdownItemsArgs[dropdownIndex] - SPR_FLOOR_TEXTURE_GRASS; if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) == type) { RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_SURFACE, uint8) = 255; @@ -933,7 +933,7 @@ static void window_mapgen_simplex_dropdown(rct_window *w, int widgetIndex, int d type = (dropdownIndex == -1) ? _wallTexture : - *((uint32*)&gDropdownItemsArgs[dropdownIndex]) - SPR_WALL_TEXTURE_ROCK; + (uint32)gDropdownItemsArgs[dropdownIndex] - SPR_WALL_TEXTURE_ROCK; if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) == type) { RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) = 255; diff --git a/src/windows/maze_construction.c b/src/windows/maze_construction.c index 7ca6166205..992eea20b0 100644 --- a/src/windows/maze_construction.c +++ b/src/windows/maze_construction.c @@ -194,7 +194,7 @@ static void window_maze_construction_entrance_mouseup(rct_window *w, int widgetI 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; + gInputFlags |= INPUT_FLAG_6; sub_6C9627(); @@ -311,7 +311,7 @@ static void window_maze_construction_update(rct_window *w) case RIDE_CONSTRUCTION_STATE_BACK: case RIDE_CONSTRUCTION_STATE_SELECTED: if ( - (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && + (gInputFlags & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) == WC_RIDE_CONSTRUCTION ) { tool_cancel(); diff --git a/src/windows/news.c b/src/windows/news.c index 5885811365..77a0760e01 100644 --- a/src/windows/news.c +++ b/src/windows/news.c @@ -344,7 +344,7 @@ static void window_news_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int s } } - uint32 image_id = *RCT2_ADDRESS(0x00982708, uint32*)[sprite_type * 2]; + uint32 image_id = g_sprite_entries[sprite_type].sprite_image->base_image; image_id += 0xA0000001; image_id |= (peep->tshirt_colour << 19) | (peep->trousers_colour << 24); diff --git a/src/windows/options.c b/src/windows/options.c index 1609ec8b27..40b19f12c1 100644 --- a/src/windows/options.c +++ b/src/windows/options.c @@ -135,6 +135,9 @@ enum WINDOW_OPTIONS_WIDGET_IDX { WIDX_TOOLBAR_SHOW_CHEATS, WIDX_TOOLBAR_SHOW_NEWS, WIDX_SELECT_BY_TRACK_TYPE, + WIDX_SCENARIO_GROUPING, + WIDX_SCENARIO_GROUPING_DROPDOWN, + WIDX_SCENARIO_UNLOCKING, // Misc WIDX_REAL_NAME_CHECKBOX = WIDX_PAGE_START, @@ -162,7 +165,7 @@ enum WINDOW_OPTIONS_WIDGET_IDX { }; #define WW 310 -#define WH 280 +#define WH 302 #define MAIN_OPTIONS_WIDGETS \ { WWT_FRAME, 0, 0, WW-1, 0, WH-1, STR_NONE, STR_NONE }, \ @@ -253,6 +256,9 @@ static rct_widget window_options_controls_and_interface_widgets[] = { { WWT_CHECKBOX, 2, 155, 299, 229, 240, STR_SHOW_RECENT_MESSAGES_ON_TOOLBAR, STR_NONE }, // Recent messages { WWT_CHECKBOX, 2, 10, 299, 254, 265, STR_SELECT_BY_TRACK_TYPE, STR_SELECT_BY_TRACK_TYPE_TIP }, // Select by track type + { WWT_DROPDOWN, 2, 155, 299, 269, 280, STR_NONE, STR_NONE }, // Scenario select mode + { WWT_DROPDOWN_BUTTON, 2, 288, 298, 270, 279, STR_DROPDOWN_GLYPH, STR_NONE }, + { WWT_CHECKBOX, 2, 18, 299, 284, 295, STR_OPTIONS_SCENARIO_UNLOCKING, STR_NONE }, // Unlocking of scenarios { WIDGETS_END }, }; @@ -418,7 +424,10 @@ static uint32 window_options_page_enabled_widgets[] = { (1 << WIDX_THEMES) | (1 << WIDX_THEMES_DROPDOWN) | (1 << WIDX_THEMES_BUTTON) | - (1 << WIDX_SELECT_BY_TRACK_TYPE), + (1 << WIDX_SELECT_BY_TRACK_TYPE) | + (1 << WIDX_SCENARIO_GROUPING) | + (1 << WIDX_SCENARIO_GROUPING_DROPDOWN) | + (1 << WIDX_SCENARIO_UNLOCKING), MAIN_OPTIONS_ENABLED_WIDGETS | (1 << WIDX_REAL_NAME_CHECKBOX) | @@ -642,6 +651,11 @@ static void window_options_mouseup(rct_window *w, int widgetIndex) window_invalidate_by_class(WC_RIDE); window_invalidate_by_class(WC_CONSTRUCT_RIDE); break; + case WIDX_SCENARIO_UNLOCKING: + gConfigGeneral.scenario_unlocking_enabled ^= 1; + config_save_default(); + window_close_by_class(WC_SCENARIO_SELECT); + break; } break; @@ -650,8 +664,7 @@ static void window_options_mouseup(rct_window *w, int widgetIndex) case WIDX_DEBUGGING_TOOLS: gConfigGeneral.debugging_tools ^= 1; config_save_default(); - window_invalidate(w); - window_invalidate_by_class(WC_TOP_TOOLBAR); + gfx_invalidate_screen(); break; case WIDX_TEST_UNFINISHED_TRACKS: gConfigGeneral.test_unfinished_tracks ^= 1; @@ -940,6 +953,27 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* dropdown_set_checked(gCurrentTheme, true); } break; + + case WIDX_SCENARIO_GROUPING_DROPDOWN: + num_items = 2; + + gDropdownItemsFormat[0] = 1142; + gDropdownItemsArgs[0] = STR_OPTIONS_SCENARIO_DIFFICULTY; + gDropdownItemsFormat[1] = 1142; + gDropdownItemsArgs[1] = STR_OPTIONS_SCENARIO_ORIGIN; + + 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(gConfigGeneral.scenario_select_mode, true); + break; } break; @@ -962,15 +996,14 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* gDropdownItemsArgs[i] = (uint32)&gConfigTitleSequences.presets[i].name; } - window_dropdown_show_text_custom_width( + window_dropdown_show_text( 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 - ); + num_items + ); dropdown_set_checked(gCurrentPreviewTitleSequence, true); break; @@ -1139,6 +1172,14 @@ static void window_options_dropdown(rct_window *w, int widgetIndex, int dropdown } config_save_default(); break; + case WIDX_SCENARIO_GROUPING_DROPDOWN: + if (dropdownIndex != gConfigGeneral.scenario_select_mode) { + gConfigGeneral.scenario_select_mode = dropdownIndex; + config_save_default(); + window_invalidate(w); + window_close_by_class(WC_SCENARIO_SELECT); + } + break; } break; @@ -1320,6 +1361,13 @@ static void window_options_invalidate(rct_window *w) 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); + widget_set_checkbox_value(w, WIDX_SCENARIO_UNLOCKING, gConfigGeneral.scenario_unlocking_enabled); + + if (gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_ORIGIN) { + w->disabled_widgets &= ~(1ULL << WIDX_SCENARIO_UNLOCKING); + } else { + w->disabled_widgets |= (1ULL << WIDX_SCENARIO_UNLOCKING); + } window_options_controls_and_interface_widgets[WIDX_THEMES].type = WWT_DROPDOWN; window_options_controls_and_interface_widgets[WIDX_THEMES_DROPDOWN].type = WWT_DROPDOWN_BUTTON; @@ -1332,6 +1380,8 @@ static void window_options_invalidate(rct_window *w) 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; + window_options_controls_and_interface_widgets[WIDX_SCENARIO_GROUPING].type = WWT_DROPDOWN; + window_options_controls_and_interface_widgets[WIDX_SCENARIO_UNLOCKING].type = WWT_CHECKBOX; break; case WINDOW_OPTIONS_PAGE_MISC: @@ -1386,6 +1436,15 @@ static void window_options_invalidate(rct_window *w) window_options_twitch_widgets[WIDX_NEWS_CHECKBOX].type = WWT_CHECKBOX; break; } + + // Automatically adjust window height to fit widgets + int y = 0; + for (widget = &w->widgets[WIDX_PAGE_START]; widget->type != WWT_LAST; widget++) { + y = max(y, widget->bottom); + } + w->height = y + 6; + w->widgets[WIDX_BACKGROUND].bottom = w->height - 1; + w->widgets[WIDX_PAGE_BACKGROUND].bottom = w->height - 1; } static void window_options_update(rct_window *w) @@ -1481,7 +1540,19 @@ static void window_options_paint(rct_window *w, rct_drawpixelinfo *dpi) 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 - ); + ); + gfx_draw_string_left(dpi, STR_OPTIONS_SCENARIO_GROUPING, NULL, w->colours[1], w->x + 10, w->y + window_options_controls_and_interface_widgets[WIDX_SCENARIO_GROUPING].top + 1); + gfx_draw_string_left_clipped( + dpi, + gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_DIFFICULTY ? + STR_OPTIONS_SCENARIO_DIFFICULTY : + STR_OPTIONS_SCENARIO_ORIGIN, + NULL, + w->colours[1], + w->x + window_options_controls_and_interface_widgets[WIDX_SCENARIO_GROUPING].left + 1, + w->y + window_options_controls_and_interface_widgets[WIDX_SCENARIO_GROUPING].top, + window_options_controls_and_interface_widgets[WIDX_SCENARIO_GROUPING_DROPDOWN].left - window_options_controls_and_interface_widgets[WIDX_SCENARIO_GROUPING].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); diff --git a/src/windows/park.c b/src/windows/park.c index 15f419ede7..51ad8cb281 100644 --- a/src/windows/park.c +++ b/src/windows/park.c @@ -612,7 +612,7 @@ void window_park_entrance_open() */ static void window_park_entrance_close(rct_window *w) { - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) + if (gInputFlags & 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(); } @@ -1124,14 +1124,14 @@ 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) == WC_PARK_INFORMATION && + if ((gInputFlags & 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 { show_gridlines(); tool_set(parkWindow, widgetIndex, 2); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_6; RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; window_land_rights_open(); } @@ -1156,7 +1156,7 @@ void window_park_rating_open() window->viewport_focus_coordinates.y = -1; } - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) + if (gInputFlags & INPUT_FLAG_TOOL_ACTIVE) if (window->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) && window->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber)) tool_cancel(); @@ -1272,7 +1272,7 @@ void window_park_guests_open() window->viewport_focus_coordinates.y = -1; } - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) + if (gInputFlags & INPUT_FLAG_TOOL_ACTIVE) if (window->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) && window->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber)) tool_cancel(); @@ -1630,7 +1630,7 @@ void window_park_objective_open() window->viewport_focus_coordinates.y = -1; } - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) + if (gInputFlags & INPUT_FLAG_TOOL_ACTIVE) if (window->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) && window->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber)) tool_cancel(); @@ -1795,7 +1795,7 @@ void window_park_awards_open() window->viewport_focus_coordinates.y = -1; } - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) + if (gInputFlags & INPUT_FLAG_TOOL_ACTIVE) if (window->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) && window->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber)) tool_cancel(); @@ -1907,7 +1907,7 @@ static void window_park_set_page(rct_window *w, int page) { int listen; - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) + if (gInputFlags & 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(); @@ -1982,7 +1982,7 @@ static void window_park_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w) 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; + sprite_idx = g_sprite_entries[0].sprite_image->base_image + 1; if (w->page == WINDOW_PARK_PAGE_GUESTS) sprite_idx += w->var_492 & 0xFFFFFFFC; diff --git a/src/windows/ride.c b/src/windows/ride.c index 20d1df837e..940d1eccdc 100644 --- a/src/windows/ride.c +++ b/src/windows/ride.c @@ -1086,7 +1086,7 @@ static void window_ride_draw_tab_customer(rct_drawpixelinfo *dpi, rct_window *w) if (w->page == WINDOW_RIDE_PAGE_CUSTOMER) spriteIndex = w->var_492 & ~3; - spriteIndex += RCT2_GLOBAL(RCT2_GLOBAL(0x00982708, uint32), uint32); + spriteIndex += g_sprite_entries[0].sprite_image->base_image; spriteIndex += 1; spriteIndex |= 0xA9E00000; @@ -1183,7 +1183,7 @@ rct_window *window_ride_open(int rideIndex) w->frame_no = 0; w->list_information_type = 0; w->var_492 = 0; - w->highlighted_item = 0; + w->ride_colour = 0; window_ride_disable_tabs(w); w->min_width = 316; w->min_height = 180; @@ -1219,7 +1219,7 @@ rct_window *window_ride_main_open(int rideIndex) w->ride.var_482 = -1; } - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) { + if (gInputFlags & 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) ) { @@ -1266,7 +1266,7 @@ rct_window *window_ride_open_station(int rideIndex, int stationIndex) } if ( - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE && + gInputFlags & INPUT_FLAG_TOOL_ACTIVE && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) == w->classification && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) == w->number ) { @@ -1345,7 +1345,7 @@ rct_window *window_ride_open_vehicle(rct_vehicle *vehicle) window_invalidate(w); if ( - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE && + gInputFlags & INPUT_FLAG_TOOL_ACTIVE && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) == w->classification && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) == w->number ) { @@ -1410,7 +1410,7 @@ static void window_ride_set_page(rct_window *w, int page) { int listen; - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) + if (gInputFlags & 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(); @@ -3727,7 +3727,7 @@ static void window_ride_set_track_colour_scheme(rct_window *w, int x, int y) uint8 newColourScheme; int interactionType, z, direction; - newColourScheme = (uint8)(*((uint16*)&w->highlighted_item)); + newColourScheme = (uint8)w->ride_colour; rct_xy16 mapCoord = { 0 }; get_map_coordinates_from_pos(x, y, VIEWPORT_INTERACTION_MASK_RIDE, &mapCoord.x, &mapCoord.y, &interactionType, &mapElement, NULL); @@ -3752,7 +3752,7 @@ static void window_ride_set_track_colour_scheme(rct_window *w, int x, int y) */ static void window_ride_colour_close(rct_window *w) { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) + if (!(gInputFlags & INPUT_FLAG_TOOL_ACTIVE)) return; if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != w->classification) @@ -3817,7 +3817,7 @@ static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_wid ride = GET_RIDE(w->number); rideEntry = ride_get_entry(ride); - colourSchemeIndex = *((uint16*)&w->highlighted_item); + colourSchemeIndex = w->ride_colour; dropdownWidget = widget - 1; switch (widgetIndex) { @@ -3957,20 +3957,20 @@ static void window_ride_colour_dropdown(rct_window *w, int widgetIndex, int drop switch (widgetIndex) { case WIDX_TRACK_COLOUR_SCHEME_DROPDOWN: - *((uint16*)&w->highlighted_item) = dropdownIndex; + w->ride_colour = (uint16)dropdownIndex; window_invalidate(w); break; case WIDX_TRACK_MAIN_COLOUR: - game_do_command(0, (0 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, *((uint16*)&w->highlighted_item), 0); + game_do_command(0, (0 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, w->ride_colour, 0); break; case WIDX_TRACK_ADDITIONAL_COLOUR: - game_do_command(0, (1 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, *((uint16*)&w->highlighted_item), 0); + game_do_command(0, (1 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, w->ride_colour, 0); break; case WIDX_TRACK_SUPPORT_COLOUR: - game_do_command(0, (4 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, *((uint16*)&w->highlighted_item), 0); + game_do_command(0, (4 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, w->ride_colour, 0); break; case WIDX_MAZE_STYLE_DROPDOWN: - game_do_command(0, (4 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, *((uint16*)&w->highlighted_item), 0); + game_do_command(0, (4 << 8) | 1, 0, (dropdownIndex << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, w->ride_colour, 0); break; case WIDX_ENTRANCE_STYLE_DROPDOWN: game_do_command(0, (6 << 8) | 1, 0, (window_ride_entrance_style_list[dropdownIndex] << 8) | w->number, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0); @@ -4057,7 +4057,7 @@ static void window_ride_colour_invalidate(rct_window *w) RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 2, uint32) = ride->name_arguments; // Track colours - int colourScheme = *((uint16*)&w->highlighted_item); + int colourScheme = w->ride_colour; trackColour = ride_get_track_colour(ride, colourScheme); // Maze style @@ -4226,7 +4226,7 @@ static void window_ride_colour_paint(rct_window *w, rct_drawpixelinfo *dpi) 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->highlighted_item)); + trackColour = ride_get_track_colour(ride, w->ride_colour); // if (rideEntry->shop_item == 0xFF) { diff --git a/src/windows/ride_construction.c b/src/windows/ride_construction.c index e43d2083ec..f344fe18d6 100644 --- a/src/windows/ride_construction.c +++ b/src/windows/ride_construction.c @@ -1873,7 +1873,7 @@ static void window_ride_construction_entrance_click(rct_window *w) RCT2_GLOBAL(0x00F44191, uint8) = 0; RCT2_GLOBAL(0x00F44192, uint8) = w->number & 0xFF; RCT2_GLOBAL(0x00F44193, uint8) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_6; sub_6C9627(); if (_rideConstructionState != RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT) { RCT2_GLOBAL(0x00F440CC, uint8) = _rideConstructionState; @@ -1897,7 +1897,7 @@ static void window_ride_construction_exit_click(rct_window *w) RCT2_GLOBAL(0x00F44191, uint8) = 1; RCT2_GLOBAL(0x00F44192, uint8) = w->number & 0xFF; RCT2_GLOBAL(0x00F44193, uint8) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_6; sub_6C9627(); if (_rideConstructionState != RIDE_CONSTRUCTION_STATE_ENTRANCE_EXIT) { RCT2_GLOBAL(0x00F440CC, uint8) = _rideConstructionState; @@ -1941,7 +1941,7 @@ static void window_ride_construction_update(rct_window *w) case RIDE_CONSTRUCTION_STATE_BACK: case RIDE_CONSTRUCTION_STATE_SELECTED: if ( - (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && + (gInputFlags & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) == WC_RIDE_CONSTRUCTION ) { tool_cancel(); @@ -3569,7 +3569,7 @@ void ride_construction_tooldown_construct(int screenX, int screenY) 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); + gInputFlags |= INPUT_FLAG_6; RCT2_GLOBAL(0x00F44159, uint8) = 0; RCT2_GLOBAL(0x00F4415C, uint8) = 0; } diff --git a/src/windows/ride_list.c b/src/windows/ride_list.c index e42f8f7eb5..8592edd2c5 100644 --- a/src/windows/ride_list.c +++ b/src/windows/ride_list.c @@ -286,7 +286,7 @@ static void window_ride_list_dropdown(rct_window *w, int widgetIndex, int dropdo if (dropdownIndex == -1) return; - _window_ride_list_information_type = *((uint32*)&gDropdownItemsArgs[dropdownIndex]) - STR_STATUS; + _window_ride_list_information_type = (uint32)gDropdownItemsArgs[dropdownIndex] - STR_STATUS; window_invalidate(w); } } diff --git a/src/windows/save_prompt.c b/src/windows/save_prompt.c index 60058185e7..68f84e85db 100644 --- a/src/windows/save_prompt.c +++ b/src/windows/save_prompt.c @@ -28,7 +28,6 @@ #include "../interface/window.h" #include "../openrct2.h" #include "../sprites.h" -#include "../tutorial.h" enum WINDOW_SAVE_PROMPT_WIDGET_IDX { WIDX_BACKGROUND, @@ -134,19 +133,6 @@ void window_save_prompt_open() * and game_load_or_quit() are not called by the original binary anymore. */ - if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) != 0) { - if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) != 1) { - sub_66EE54(); - game_load_or_quit_no_save_prompt(); - return; - } - else { - tutorial_stop(); - game_load_or_quit_no_save_prompt(); - return; - } - } - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_AGE, uint16) < 3840) { game_load_or_quit_no_save_prompt(); return; @@ -249,18 +235,6 @@ static void window_save_prompt_mouseup(rct_window *w, int widgetIndex) return; } } - - if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) != 0) { - if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) != 1) { - sub_66EE54(); - game_load_or_quit_no_save_prompt(); - return; - } else { - tutorial_stop(); - game_load_or_quit_no_save_prompt(); - return; - } - } } static void window_save_prompt_invalidate(rct_window *w) diff --git a/src/windows/scenery.c b/src/windows/scenery.c index 3c8e57278b..87331be5ae 100644 --- a/src/windows/scenery.c +++ b/src/windows/scenery.c @@ -490,7 +490,7 @@ bool window_scenery_is_scenery_tool_active() { int toolWindowClassification = RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass); int toolWidgetIndex = RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16); - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) + if (gInputFlags & INPUT_FLAG_TOOL_ACTIVE) if (toolWindowClassification == WC_TOP_TOOLBAR && toolWidgetIndex == 9) // 9 is WIDX_SCENERY return true; @@ -693,7 +693,7 @@ static void window_scenery_update(rct_window *w) if (widgetIndex >= WIDX_SCENERY_TAB_CONTENT_PANEL) { w->scenery.hover_counter++; if (w->scenery.hover_counter < 8) { - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, sint8) != INPUT_STATE_SCROLL_LEFT) { + if (gInputState != INPUT_STATE_SCROLL_LEFT) { w->min_width = WINDOW_SCENERY_WIDTH; w->max_width = WINDOW_SCENERY_WIDTH; w->min_height = WINDOW_SCENERY_HEIGHT; @@ -713,7 +713,7 @@ static void window_scenery_update(rct_window *w) } } else { w->scenery.hover_counter = 0; - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, sint8) != INPUT_STATE_SCROLL_LEFT) { + if (gInputState != INPUT_STATE_SCROLL_LEFT) { w->min_width = WINDOW_SCENERY_WIDTH; w->max_width = WINDOW_SCENERY_WIDTH; w->min_height = WINDOW_SCENERY_HEIGHT; diff --git a/src/windows/staff.c b/src/windows/staff.c index 0d3833830f..9bf5e7c81a 100644 --- a/src/windows/staff.c +++ b/src/windows/staff.c @@ -369,7 +369,7 @@ void window_staff_disable_widgets(rct_window* w) */ void window_staff_overview_close(rct_window *w) { - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE){ + if (gInputFlags & 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(); @@ -382,7 +382,7 @@ void window_staff_overview_close(rct_window *w) */ void window_staff_set_page(rct_window* w, int page) { - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) + if (gInputFlags & INPUT_FLAG_TOOL_ACTIVE) { if(w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) && w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass)) @@ -449,7 +449,7 @@ void window_staff_overview_mouseup(rct_window *w, int widgetIndex) return; } - w->var_48C = peep->x; + w->picked_peep_old_x = peep->x; remove_peep_from_ride(peep); invalidate_sprite_2((rct_sprite*)peep); @@ -987,7 +987,7 @@ void window_staff_overview_tab_paint(rct_window* w, rct_drawpixelinfo* dpi) 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 ebx = g_sprite_entries[peep->sprite_type].sprite_image->base_image + 1; int eax = 0; @@ -1096,7 +1096,7 @@ void window_staff_overview_tool_update(rct_window* w, int widgetIndex, int x, in if (widgetIndex != WIDX_PICKUP) return; - RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32) = -1; + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_IMAGE, sint32) = -1; int interactionType; get_map_coordinates_from_pos(x, y, VIEWPORT_INTERACTION_MASK_NONE, NULL, NULL, &interactionType, NULL, NULL); @@ -1107,16 +1107,19 @@ void window_staff_overview_tool_update(rct_window* w, int widgetIndex, int x, in y += 16; RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_X, uint16) = x; RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_Y, uint16) = y; - w->var_492++; - if (w->var_492 >= 48)w->var_492 = 0; + w->picked_peep_frame++; + if (w->picked_peep_frame >= 48) { + w->picked_peep_frame = 0; + } rct_peep* peep; peep = GET_PEEP(w->number); - int sprite_idx = (RCT2_ADDRESS(0x982708, uint32*)[peep->sprite_type * 2])[22]; - sprite_idx += w->var_492 >> 2; - sprite_idx |= (peep->tshirt_colour << 19) | (peep->trousers_colour << 24) | 0xA0000000; - RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, uint32) = sprite_idx; + uint32 imageId = g_sprite_entries[peep->sprite_type].sprite_image[11].base_image; + imageId += w->picked_peep_frame >> 2; + + imageId |= (peep->tshirt_colour << 19) | (peep->trousers_colour << 24) | 0xA0000000; + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_IMAGE, uint32) = imageId; } /** @@ -1163,7 +1166,7 @@ void window_staff_overview_tool_down(rct_window* w, int widgetIndex, int x, int peep->state = PEEP_STATE_FALLING; peep_window_state_update(peep); peep->action = 0xFF; - peep->var_6D = 0; + peep->special_sprite = 0; peep->action_sprite_image_offset = 0; peep->action_sprite_type = 0; peep->var_C4 = 0; @@ -1191,7 +1194,7 @@ void window_staff_overview_tool_abort(rct_window *w, int widgetIndex) 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); + sprite_move(w->picked_peep_old_x, peep->y, peep->z + 8, (rct_sprite*)peep); invalidate_sprite_2((rct_sprite*)peep); if (peep->x != (sint16)0x8000){ @@ -1199,13 +1202,13 @@ void window_staff_overview_tool_abort(rct_window *w, int widgetIndex) peep->state = PEEP_STATE_FALLING; peep_window_state_update(peep); peep->action = 0xFF; - peep->var_6D = 0; + peep->special_sprite = 0; peep->action_sprite_image_offset = 0; peep->action_sprite_type = 0; peep->var_C4 = 0; } - RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_SPRITE, sint32) = -1; + RCT2_GLOBAL(RCT2_ADDRESS_PICKEDUP_PEEP_IMAGE, sint32) = -1; } else if (widgetIndex == WIDX_PATROL){ hide_gridlines(); diff --git a/src/windows/staff_list.c b/src/windows/staff_list.c index 76595b00da..d1c9fc1825 100644 --- a/src/windows/staff_list.c +++ b/src/windows/staff_list.c @@ -181,7 +181,7 @@ void window_staff_list_open() void window_staff_list_cancel_tools(rct_window *w) { int toolWindowClassification = RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass); int toolWindowNumber = RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber); - if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) + if (gInputFlags & 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(); } @@ -310,10 +310,10 @@ void window_staff_list_update(rct_window *w) RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) |= (1 << 2); FOR_ALL_PEEPS(spriteIndex, peep) { if (peep->type == PEEP_TYPE_STAFF) { - peep->var_0C &= ~0x200; + peep->list_flags &= ~(PEEP_LIST_FLAGS_FLASHING); if (peep->staff_type == RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8)) { - peep->var_0C |= 0x200; + peep->list_flags |= PEEP_LIST_FLAGS_FLASHING; } } } diff --git a/src/windows/tile_inspector.c b/src/windows/tile_inspector.c index c3425d6d77..c0dde9e3ea 100644 --- a/src/windows/tile_inspector.c +++ b/src/windows/tile_inspector.c @@ -26,31 +26,76 @@ #include "../world/scenery.h" #include "../world/map.h" #include "../world/footpath.h" +#include "../sprites.h" enum WINDOW_TILE_INSPECTOR_WIDGET_IDX { WIDX_BACKGROUND, WIDX_TITLE, WIDX_CLOSE, + WIDX_LIST, WIDX_CORRUPT, - WIDX_CONTENT_PANEL, - WIDX_SCROLL + WIDX_REMOVE, + WIDX_MOVE_DOWN, + WIDX_MOVE_UP, + WIDX_COLUMN_TYPE, + WIDX_COLUMN_BASEHEIGHT, + WIDX_COLUMN_CLEARANCEHEIGHT, + WIDX_COLUMN_GHOSTFLAG, + WIDX_COLUMN_BROKENFLAG, + WIDX_COLUMN_LASTFLAG, }; -#define WW 500 -#define WH 400 +#define WW 400 +#define WH 200 +#define MIN_WW WW +#define MAX_WW WW #define MIN_WH 150 #define MAX_WH 800 +#define BW (WW - 5) // Button's right side +#define BX (BW - 23) // Button's left side +#define BY 17 // Button's Top +#define BH (BY + 23) // Button's Bottom +#define BS 24 + +#define SCROLL_BOTTOM_OFFSET 15 +#define LIST_ITEM_HEIGHT 11 + +// Column offsets +#define COL_X_TYPE 3 // Type +#define COL_X_BH (COL_X_TYPE + 300) // Base height +#define COL_X_CH (COL_X_BH + 20) // Clearance height +#define COL_X_GF (COL_X_CH + 20) // Ghost flag +#define COL_X_BF (COL_X_GF + 12) // Broken flag +#define COL_X_LF (COL_X_BF + 12) // Last for tile flag + 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 + { 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 + + // Map element list + { WWT_SCROLL, 1, 3, WW - 4, 57, WH - SCROLL_BOTTOM_OFFSET, 2, STR_NONE }, // scroll area + + // Buttons + { WWT_FLATBTN, 1, BX, BW, BY, BH, SPR_MAP, STR_INSERT_CORRUPT_TIP }, // Insert corrupt button + { WWT_FLATBTN, 1, BX - BS * 1, BW - BS * 1, BY, BH, SPR_DEMOLISH, 5607 }, // Remove button + { WWT_CLOSEBOX, 1, BX - BS * 2, BW - BS * 2, BY, BY + 11, 5375, 5617 }, // Move down + { WWT_CLOSEBOX, 1, BX - BS * 2, BW - BS * 2, BH - 11, BH, 5376, 5618 }, // Move up + + // Column headers + { WWT_13, 1, COL_X_TYPE, COL_X_BH - 1, 42, 42 + 13, STR_NONE, STR_NONE }, // Type + { WWT_13, 1, COL_X_BH, COL_X_CH - 1, 42, 42 + 13, STR_NONE, STR_TILE_INSPECTOR_BASE_HEIGHT }, // Base height + { WWT_13, 1, COL_X_CH, COL_X_GF - 1, 42, 42 + 13, STR_NONE, STR_TILE_INSPECTOR_CLEARANCE_HEIGHT }, // Clearance height + { WWT_13, 1, COL_X_GF, COL_X_BF - 1, 42, 42 + 13, STR_NONE, STR_TILE_INSPECTOR_FLAG_GHOST }, // Ghost flag + { WWT_13, 1, COL_X_BF, COL_X_LF - 1, 42, 42 + 13, STR_NONE, STR_TILE_INSPECTOR_FLAG_BROKEN }, // Broken flag + { WWT_13, 1, COL_X_LF, WW - 3, 42, 42 + 13, STR_NONE, STR_TILE_INSPECTOR_FLAG_LAST }, // Last of tile flag + { WIDGETS_END }, }; +static sint16 window_tile_inspector_highlighted_index = -1; + static int window_tile_inspector_tile_x; static int window_tile_inspector_tile_y; static int window_tile_inspector_item_count; @@ -58,15 +103,19 @@ static int window_tile_inspector_item_count; 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_title_editor_update(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_scrollmousedown(rct_window *w, int scrollIndex, int x, int y); 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_auto_set_buttons(rct_window *w); + static rct_window_event_list window_tile_inspector_events = { window_tile_inspector_close, window_tile_inspector_mouseup, @@ -74,7 +123,7 @@ static rct_window_event_list window_tile_inspector_events = { NULL, NULL, NULL, - NULL, + window_title_editor_update, NULL, NULL, window_tile_inspector_tool_update, @@ -84,7 +133,7 @@ static rct_window_event_list window_tile_inspector_events = { window_tile_inspector_tool_abort, NULL, window_tile_inspector_scrollgetsize, - NULL, + window_tile_inspector_scrollmousedown, NULL, window_tile_inspector_scrollmouseover, NULL, @@ -118,16 +167,17 @@ void window_tile_inspector_open() ); window->widgets = window_tile_inspector_widgets; window->enabled_widgets = (1 << WIDX_CLOSE); - window->disabled_widgets = (1 << WIDX_CORRUPT); + window->disabled_widgets = (1 << WIDX_CORRUPT) | (1 << WIDX_MOVE_UP) | (1 << WIDX_MOVE_DOWN) | (1 << WIDX_REMOVE); window_init_scroll_widgets(window); window->colours[0] = 7; window->colours[1] = 7; window->colours[2] = 7; - window->min_width = WW; + window->min_width = MIN_WW; window->min_height = MIN_WH; - window->max_width = WW; + window->max_width = MAX_WW; window->max_height = MAX_WH; + window->selected_list_item = -1; window_tile_inspector_tile_x = -1; window_tile_inspector_tile_y = -1; @@ -151,6 +201,50 @@ void corrupt_element(int x, int y) { mapElement->type = (8 << 2); } +void remove_element(int index) +{ + assert(index < window_tile_inspector_item_count); + rct_map_element *mapElement = map_get_first_element_at(window_tile_inspector_tile_x, window_tile_inspector_tile_y); + mapElement += index; + map_element_remove(mapElement); + window_tile_inspector_item_count--; +} + +// Swap element with its parent +void swap_elements(sint16 first, sint16 second) +{ + rct_map_element *mapElement; + rct_map_element *firstElement = NULL; + rct_map_element *secondElement = NULL; + mapElement = map_get_first_element_at(window_tile_inspector_tile_x, window_tile_inspector_tile_y); + + // swap_elements shouldn't be called when there is only one element on the tile + assert(!map_element_is_last_for_tile(mapElement)); + + // Search for the elements + sint16 i = 0; + do { + if (i == first) firstElement = mapElement; + if (i == second) secondElement = mapElement; + i++; + + // Check if both elements have been found + if (firstElement != NULL && secondElement != NULL) + break; + } while (!map_element_is_last_for_tile(mapElement++)); + + // Swap their memory + rct_map_element temp = *firstElement; + *firstElement = *secondElement; + *secondElement = temp; + + // Swap the 'last map element for tile' flag if either one of them was last + if (map_element_is_last_for_tile(firstElement) || map_element_is_last_for_tile(secondElement)) { + firstElement->flags ^= MAP_ELEMENT_FLAG_LAST_TILE; + secondElement->flags ^= MAP_ELEMENT_FLAG_LAST_TILE; + } +} + static void window_tile_inspector_mouseup(rct_window *w, int widgetIndex) { switch (widgetIndex) { @@ -159,9 +253,28 @@ static void window_tile_inspector_mouseup(rct_window *w, int widgetIndex) 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); + w->selected_list_item = window_tile_inspector_item_count++; + window_tile_inspector_auto_set_buttons(w); + widget_invalidate(w, WIDX_LIST); + break; + case WIDX_REMOVE: + remove_element(w->selected_list_item); + w->selected_list_item = -1; + window_tile_inspector_auto_set_buttons(w); + widget_invalidate(w, WIDX_LIST); + break; + case WIDX_MOVE_DOWN: + swap_elements(w->selected_list_item, w->selected_list_item + 1); + w->selected_list_item++; + window_tile_inspector_auto_set_buttons(w); + widget_invalidate(w, WIDX_LIST); + break; + case WIDX_MOVE_UP: + swap_elements(w->selected_list_item - 1, w->selected_list_item); + w->selected_list_item--; + window_tile_inspector_auto_set_buttons(w); + widget_invalidate(w, WIDX_LIST); break; } } @@ -180,6 +293,16 @@ static void window_tile_inspector_resize(rct_window *w) } } +static void window_title_editor_update(rct_window *w) +{ + // Check if the mouse is hovering over the list + if (!widget_is_highlighted(w, WIDX_LIST)) + { + window_tile_inspector_highlighted_index = -1; + widget_invalidate(w, WIDX_LIST); + } +} + static void window_tile_inspector_tool_update(rct_window* w, int widgetIndex, int x, int y) { int direction; @@ -229,8 +352,13 @@ static void window_tile_inspector_tool_down(rct_window* w, int widgetIndex, int window_tile_inspector_item_count = numItems; + // Enable 'insert corrupt element' button w->enabled_widgets |= (1 << WIDX_CORRUPT); w->disabled_widgets &= ~(1ULL << WIDX_CORRUPT); + // undo selection and buttons affecting it + w->selected_list_item = -1; + w->disabled_widgets |= (1ULL << WIDX_MOVE_UP) | (1ULL << WIDX_MOVE_DOWN) | (1ULL << WIDX_REMOVE); + w->enabled_widgets &= ~((1ULL << WIDX_MOVE_UP) | (1ULL << WIDX_MOVE_DOWN) | (1ULL << WIDX_REMOVE)); w->scrolls[0].v_top = 0; window_invalidate(w); @@ -244,12 +372,63 @@ 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) { *width = WW - 30; - *height = window_tile_inspector_item_count * 11; + *height = window_tile_inspector_item_count * LIST_ITEM_HEIGHT; +} + +static void window_tile_inspector_auto_set_buttons(rct_window *w) +{ + // Remove button + if (w->selected_list_item == -1) { // Check if anything is selected + w->disabled_widgets |= (1ULL << WIDX_REMOVE); + w->enabled_widgets &= ~(1ULL << WIDX_REMOVE); + } else { // Nothing is selected + w->disabled_widgets &= ~(1ULL << WIDX_REMOVE); + w->enabled_widgets |= (1ULL << WIDX_REMOVE); + } + widget_invalidate(w, WIDX_REMOVE); + + // Move Up button + if (w->selected_list_item <= 0) { // Top element in list, or -1 + w->disabled_widgets |= (1ULL << WIDX_MOVE_UP); + w->enabled_widgets &= ~(1ULL << WIDX_MOVE_UP); + } else { // Not the top element in the list + w->enabled_widgets |= (1ULL << WIDX_MOVE_UP); + w->disabled_widgets &= ~(1ULL << WIDX_MOVE_UP); + } + widget_invalidate(w, WIDX_MOVE_UP); + + // Move Down button + if (w->selected_list_item == window_tile_inspector_item_count - 1 || w->selected_list_item == -1) { // Bottom element in list, or -1 + w->disabled_widgets |= (1ULL << WIDX_MOVE_DOWN); + w->enabled_widgets &= ~(1ULL << WIDX_MOVE_DOWN); + } else { // Not the bottom element in the list + w->enabled_widgets |= (1ULL << WIDX_MOVE_DOWN); + w->disabled_widgets &= ~(1ULL << WIDX_MOVE_DOWN); + } + widget_invalidate(w, WIDX_MOVE_DOWN); +} + +static void window_tile_inspector_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) +{ + // Because the list items are displayed in reverse order, subtract the number from the amount of elements + sint16 index = window_tile_inspector_item_count - (y - 1) / LIST_ITEM_HEIGHT - 1; + if (index < 0 || index >= window_tile_inspector_item_count) + return; + w->selected_list_item = index; + + // Enable/disable buttons + window_tile_inspector_auto_set_buttons(w); } static void window_tile_inspector_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) { - window_invalidate(w); + sint16 index = window_tile_inspector_item_count - (y - 1) / LIST_ITEM_HEIGHT - 1; + if (index < 0 || index >= window_tile_inspector_item_count) + window_tile_inspector_highlighted_index = -1; + else + window_tile_inspector_highlighted_index = index; + + widget_invalidate(w, WIDX_LIST); } static void window_tile_inspector_invalidate(rct_window *w) @@ -258,28 +437,53 @@ static void window_tile_inspector_invalidate(rct_window *w) window_tile_inspector_widgets[WIDX_BACKGROUND].bottom = w->height - 1; window_tile_inspector_widgets[WIDX_CLOSE].left = w->width - 13; window_tile_inspector_widgets[WIDX_CLOSE].right = w->width - 3; - window_tile_inspector_widgets[WIDX_CONTENT_PANEL].right = w->width - 1; - window_tile_inspector_widgets[WIDX_CONTENT_PANEL].bottom = w->height - 1; - window_tile_inspector_widgets[WIDX_SCROLL].bottom = w->height - 30; + window_tile_inspector_widgets[WIDX_TITLE].right = w->width - 2; + window_tile_inspector_widgets[WIDX_LIST].right = w->width - 4; + window_tile_inspector_widgets[WIDX_LIST].bottom = w->height - SCROLL_BOTTOM_OFFSET; + window_tile_inspector_widgets[WIDX_COLUMN_LASTFLAG].right = w->width - 3; } static void window_tile_inspector_paint(rct_window *w, rct_drawpixelinfo *dpi) { - int x, y; - char buffer[256]; - window_draw_widgets(w, dpi); - x = w->x + 20; - y = w->y + 25; + char buffer[256]; + int x = w->x /*+ w->widgets[WIDX_LIST].left*/ + 3; + int y = w->y + w->height - 13; - if (window_tile_inspector_tile_x == -1) { + // Set medium font size + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = FONT_SPRITE_BASE_MEDIUM; - // No tile selected + // Draw column headers + rct_widget *widget; + if ((widget= &w->widgets[WIDX_COLUMN_TYPE])->type != WWT_EMPTY) { + gfx_draw_string_left_clipped(dpi, STR_TILE_INSPECTOR_ELEMENT_TYPE, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, w->colours[1], w->x + widget->left + 1, w->y + widget->top + 1, widget->right - widget->left); + } + if ((widget = &w->widgets[WIDX_COLUMN_BASEHEIGHT])->type != WWT_EMPTY) + { + gfx_draw_string_left_clipped(dpi, STR_TILE_INSPECTOR_BASE_HEIGHT_SHORT, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, w->colours[1], w->x + widget->left + 1, w->y + widget->top + 1, widget->right - widget->left); + } + if ((widget = &w->widgets[WIDX_COLUMN_CLEARANCEHEIGHT])->type != WWT_EMPTY) + { + gfx_draw_string_left_clipped(dpi, STR_TILE_INSPECTOR_CLEARANGE_HEIGHT_SHORT, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, w->colours[1], w->x + widget->left + 1, w->y + widget->top + 1, widget->right - widget->left); + } + if ((widget = &w->widgets[WIDX_COLUMN_GHOSTFLAG])->type != WWT_EMPTY) + { + gfx_draw_string_left_clipped(dpi, STR_TILE_INSPECTOR_FLAG_GHOST_SHORT, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, w->colours[1], w->x + widget->left + 1, w->y + widget->top + 1, widget->right - widget->left); + } + if ((widget = &w->widgets[WIDX_COLUMN_BROKENFLAG])->type != WWT_EMPTY) + { + gfx_draw_string_left_clipped(dpi, STR_TILE_INSPECTOR_FLAG_BROKEN_SHORT, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, w->colours[1], w->x + widget->left + 1, w->y + widget->top + 1, widget->right - widget->left); + } + if ((widget = &w->widgets[WIDX_COLUMN_LASTFLAG])->type != WWT_EMPTY) + { + gfx_draw_string_left_clipped(dpi, STR_TILE_INSPECTOR_FLAG_LAST_SHORT, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, w->colours[1], w->x + widget->left + 1, w->y + widget->top + 1, widget->right - widget->left); + } + + // Draw coordinates + if (window_tile_inspector_tile_x == -1) { // No tile selected gfx_draw_string_left(dpi, STR_TILE_INSPECTOR_CHOOSE_MSG, NULL, 12, x, y); - } else { - sprintf( buffer, "X: %d, Y: %d", @@ -288,21 +492,14 @@ static void window_tile_inspector_paint(rct_window *w, rct_drawpixelinfo *dpi) ); gfx_draw_string(dpi, buffer, 12, x, y); - } - - y += 25; - - draw_string_left_underline(dpi, STR_TILE_INSPECTOR_ELEMENT_TYPE, NULL, 12, x, y); - draw_string_left_underline(dpi, STR_TILE_INSPECTOR_BASE_HEIGHT, NULL, 12, x + 200, y); - draw_string_left_underline(dpi, STR_TILE_INSPECTOR_CLEARANGE_HEIGHT, NULL, 12, x + 280, y); - draw_string_left_underline(dpi, STR_TILE_INSPECTOR_FLAGS, NULL, 12, x + 390, y); - } static void window_tile_inspector_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { - int x = 15, y = 11 * (window_tile_inspector_item_count - 1), i = 0; + int x = 3; + int y = LIST_ITEM_HEIGHT * (window_tile_inspector_item_count - 1); + int i = 0; char buffer[256]; if (window_tile_inspector_tile_x == -1) @@ -310,15 +507,21 @@ static void window_tile_inspector_scrollpaint(rct_window *w, rct_drawpixelinfo * rct_map_element *element = map_get_first_element_at(window_tile_inspector_tile_x, window_tile_inspector_tile_y); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16) = FONT_SPRITE_BASE_MEDIUM; do { - int type = map_element_get_type(element); char *type_name; int base_height = element->base_height; int clearance_height = element->clearance_height; - if ((i & 1) != 0) - gfx_fill_rect(dpi, x - 15, y, x + WW - 20, y + 11, ColourMapA[w->colours[1]].lighter | 0x1000000); + // Fill colour for current list element + const int list_width = w->widgets[WIDX_LIST].right - w->widgets[WIDX_LIST].left; + if (i == w->selected_list_item) // Currently selected element + gfx_fill_rect(dpi, 0, y, list_width, y + LIST_ITEM_HEIGHT - 1, ColourMapA[w->colours[1]].darker | 0x1000000); + else if (i == window_tile_inspector_highlighted_index) // Hovering + gfx_fill_rect(dpi, 0, y, list_width, y + LIST_ITEM_HEIGHT - 1, ColourMapA[w->colours[1]].mid_dark | 0x1000000); + else if ((i & 1) != 0) // odd / even check + gfx_fill_rect(dpi, 0, y, list_width, y + LIST_ITEM_HEIGHT - 1, ColourMapA[w->colours[1]].lighter | 0x1000000); switch (type) { case MAP_ELEMENT_TYPE_SURFACE: @@ -332,28 +535,35 @@ static void window_tile_inspector_scrollpaint(rct_window *w, rct_drawpixelinfo * break; case MAP_ELEMENT_TYPE_PATH: { - // TODO: use these - uint8 pathType, pathDirection; - pathType = element->properties.path.type >> 2; - pathDirection = element->properties.path.type & 3; + const uint8 pathType = footpath_element_get_type(element); + const uint8 pathHasScenery = footpath_element_has_path_scenery(element); + const uint8 pathAdditionType = footpath_element_get_path_scenery_index(element); if (footpath_element_is_queue(element)) { sprintf( - buffer, - "Queue for (%d)", - element->properties.path.ride_index + buffer, "Queue (%s)%s%s for (%d)", + language_get_string(g_pathSceneryEntries[pathType]->name), // Path name + pathHasScenery ? " with " : "", // Adds " with " when there is something on the path + pathHasScenery ? language_get_string(g_pathBitSceneryEntries[pathAdditionType]->name) : "", // Path addition name + element->properties.path.ride_index // Ride index for queue ); } else { sprintf( - buffer, - "Path (%s)", - "" // TODO: queue? has bins? has benches? e.t.c. + buffer, "Path (%s)%s%s", + language_get_string(g_pathSceneryEntries[pathType]->name), // Path name + pathHasScenery ? " with " : "", // Adds " with " when there is something on the path + pathHasScenery ? language_get_string(g_pathBitSceneryEntries[pathAdditionType]->name) : "" // Path addition name ); } } type_name = buffer; break; case MAP_ELEMENT_TYPE_TRACK: - type_name = "Track"; // TODO: show type? + sprintf( + buffer, + "Track (%s)", + language_get_string(2 + GET_RIDE(element->properties.track.ride_index)->type) + ); + type_name = buffer; break; case MAP_ELEMENT_TYPE_SCENERY: sprintf( @@ -397,24 +607,19 @@ static void window_tile_inspector_scrollpaint(rct_window *w, rct_drawpixelinfo * type_name = buffer; } - gfx_draw_string(dpi, type_name, 12, x, y); - gfx_draw_string_left(dpi, 5182, &base_height, 12, x + 200, y); - gfx_draw_string_left(dpi, 5182, &clearance_height, 12, x + 280, y); + // Undo relative scroll offset, but keep the 3 pixel padding + x = -w->widgets[WIDX_LIST].left; + const bool ghost = (element->flags & MAP_ELEMENT_FLAG_GHOST) != 0; + const bool broken = (element->flags & MAP_ELEMENT_FLAG_BROKEN) != 0; + const bool last = (element->flags & MAP_ELEMENT_FLAG_LAST_TILE) != 0; + gfx_draw_string(dpi, type_name, 12, x + COL_X_TYPE + 3, y); // 3px padding + gfx_draw_string_left(dpi, 5182, &base_height, 12, x + COL_X_BH, y); + gfx_draw_string_left(dpi, 5182, &clearance_height, 12, x + COL_X_CH, y); + if (ghost) gfx_draw_string(dpi, (char*)CheckBoxMarkString, w->colours[1], x + COL_X_GF, y); + if (broken) gfx_draw_string(dpi, (char*)CheckBoxMarkString, w->colours[1], x + COL_X_BF, y); + if (last) gfx_draw_string(dpi, (char*)CheckBoxMarkString, w->colours[1], x + COL_X_LF, y); - uint8 flags = element->flags; - char j; - - buffer[8] = '\0'; - - for (j = 7; j >= 0; j--, flags >>= 1) { - buffer[j] = flags & 1 ? '1' : '0'; - } - - gfx_draw_string(dpi, buffer, 12, x + 390, y); - - y -= 11; + y -= LIST_ITEM_HEIGHT; i++; - } while (!map_element_is_last_for_tile(element++)); - } diff --git a/src/windows/title_menu.c b/src/windows/title_menu.c index 1709c74273..246128a264 100644 --- a/src/windows/title_menu.c +++ b/src/windows/title_menu.c @@ -22,13 +22,13 @@ #include "../config.h" #include "../editor.h" #include "../game.h" +#include "../input.h" +#include "../interface/themes.h" #include "../interface/widget.h" #include "../interface/window.h" #include "../localisation/localisation.h" #include "../sprites.h" -#include "../tutorial.h" #include "dropdown.h" -#include "../interface/themes.h" enum { WIDX_START_NEW_GAME, @@ -148,19 +148,7 @@ 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) { - if (widgetIndex == WIDX_SHOW_TUTORIAL) { - gDropdownItemsFormat[0] = STR_TUTORIAL_BEGINNERS; - gDropdownItemsFormat[1] = STR_TUTORIAL_CUSTOM_RIDES; - gDropdownItemsFormat[2] = STR_TUTORIAL_ROLLER_COASTER; - window_dropdown_show_text( - w->x + widget->left, - w->y + widget->top, - widget->bottom - widget->top + 1, - w->colours[0] | 0x80, - DROPDOWN_FLAG_STAY_OPEN, - 3 - ); - } else if (widgetIndex == WIDX_GAME_TOOLS) { + if (widgetIndex == WIDX_GAME_TOOLS) { gDropdownItemsFormat[0] = STR_SCENARIO_EDITOR; gDropdownItemsFormat[1] = STR_CONVERT_SAVED_GAME_TO_SCENARIO; gDropdownItemsFormat[2] = STR_ROLLER_COASTER_DESIGNER; @@ -178,9 +166,7 @@ static void window_title_menu_mousedown(int widgetIndex, rct_window*w, rct_widge static void window_title_menu_dropdown(rct_window *w, int widgetIndex, int dropdownIndex) { - if (widgetIndex == WIDX_SHOW_TUTORIAL) { - tutorial_start(dropdownIndex); - } else if (widgetIndex == WIDX_GAME_TOOLS) { + if (widgetIndex == WIDX_GAME_TOOLS) { switch (dropdownIndex) { case 0: editor_load(); @@ -200,7 +186,7 @@ static void window_title_menu_dropdown(rct_window *w, int widgetIndex, int dropd 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; + gTooltipTimeout = 2000; } static void window_title_menu_paint(rct_window *w, rct_drawpixelinfo *dpi) diff --git a/src/windows/title_scenarioselect.c b/src/windows/title_scenarioselect.c index 18d3511fe3..20e358ceed 100644 --- a/src/windows/title_scenarioselect.c +++ b/src/windows/title_scenarioselect.c @@ -30,6 +30,29 @@ #include "../interface/themes.h" #include "../util/util.h" +#define INITIAL_NUM_UNLOCKED_SCENARIOS 5 + +enum { + LIST_ITEM_TYPE_HEADING, + LIST_ITEM_TYPE_SCENARIO, + LIST_ITEM_TYPE_END, +}; + +typedef struct { + uint8 type; + union { + struct { + rct_string_id string_id; + } heading; + struct { + scenario_index_entry *scenario; + bool is_locked; + } scenario; + }; +} sc_list_item; + +static sc_list_item *_listItems = NULL; + enum { WIDX_BACKGROUND, WIDX_TITLEBAR, @@ -40,25 +63,32 @@ enum { WIDX_TAB3, WIDX_TAB4, WIDX_TAB5, + WIDX_TAB6, + WIDX_TAB7, + WIDX_TAB8, WIDX_SCENARIOLIST }; static rct_widget window_scenarioselect_widgets[] = { - { WWT_FRAME, 0, 0, 609, 0, 333, -1, STR_NONE }, // panel / background - { WWT_CAPTION, 0, 1, 608, 1, 14, STR_SELECT_SCENARIO, STR_WINDOW_TITLE_TIP }, // title bar - { WWT_CLOSEBOX, 0, 597, 607, 2, 13, 824, STR_CLOSE_WINDOW_TIP }, // close x button - { WWT_IMGBTN, 1, 0, 609, 50, 333, -1, STR_NONE }, // tab content panel + { WWT_FRAME, 0, 0, 733, 0, 333, -1, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, 732, 1, 14, STR_SELECT_SCENARIO, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, 721, 731, 2, 13, 824, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_IMGBTN, 1, 0, 733, 50, 333, -1, STR_NONE }, // tab content panel { WWT_TAB, 1, 3, 93, 17, 50, 0x200015BC, STR_NONE }, // tab 1 { WWT_TAB, 1, 94, 184, 17, 50, 0x200015BC, STR_NONE }, // tab 2 { WWT_TAB, 1, 185, 275, 17, 50, 0x200015BC, STR_NONE }, // tab 3 { WWT_TAB, 1, 276, 366, 17, 50, 0x200015BC, STR_NONE }, // tab 4 { WWT_TAB, 1, 367, 457, 17, 50, 0x200015BC, STR_NONE }, // tab 5 - { WWT_SCROLL, 1, 3, 433, 54, 329, 2, STR_NONE }, // level list + { WWT_TAB, 1, 458, 593, 17, 50, 0x200015BC, STR_NONE }, // tab 6 + { WWT_TAB, 1, 594, 684, 17, 50, 0x200015BC, STR_NONE }, // tab 7 + { WWT_TAB, 1, 685, 775, 17, 50, 0x200015BC, STR_NONE }, // tab 8 + { WWT_SCROLL, 1, 3, 555, 54, 329, 2, STR_NONE }, // level list { WIDGETS_END }, }; -static void window_scenarioselect_init_tabs(); +static void window_scenarioselect_init_tabs(rct_window *w); +static void window_scenarioselect_close(rct_window *w); 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(rct_window *w, int scrollIndex, int *width, int *height); @@ -69,7 +99,7 @@ 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 rct_window_event_list window_scenarioselect_events = { - NULL, + window_scenarioselect_close, window_scenarioselect_mouseup, NULL, window_scenarioselect_mousedown, @@ -99,6 +129,11 @@ static rct_window_event_list window_scenarioselect_events = { window_scenarioselect_scrollpaint }; +static void draw_category_heading(rct_window *w, rct_drawpixelinfo *dpi, int left, int right, int y, rct_string_id stringId); +static void initialise_list_items(rct_window *w); +static bool is_scenario_visible(rct_window *w, scenario_index_entry *scenario); +static bool is_locking_enabled(rct_window *w); + /** * * rct2: 0x006781B5 @@ -106,6 +141,8 @@ static rct_window_event_list window_scenarioselect_events = { void window_scenarioselect_open() { rct_window* window; + int windowWidth; + int windowHeight = 334; if (window_bring_to_front_by_class(WC_SCENARIO_SELECT) != NULL) return; @@ -113,48 +150,62 @@ void window_scenarioselect_open() // Load scenario list scenario_load_list(); + // Shrink the window if we're showing scenarios by difficulty level. + if (gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_DIFFICULTY) { + windowWidth = 610; + } else { + windowWidth = 733; + } + window = window_create_centred( - 610, - 334, + windowWidth, + windowHeight, &window_scenarioselect_events, WC_SCENARIO_SELECT, WF_10 ); window->widgets = window_scenarioselect_widgets; - window->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_TAB1) | (1 << WIDX_TAB2) - | (1 << WIDX_TAB3) | (1 << WIDX_TAB4) | (1 << WIDX_TAB5); + | (1 << WIDX_TAB3) | (1 << WIDX_TAB4) | (1 << WIDX_TAB5) + | (1 << WIDX_TAB6) | (1 << WIDX_TAB7) | (1 << WIDX_TAB8); + + window_scenarioselect_init_tabs(window); + initialise_list_items(window); window_init_scroll_widgets(window); window->viewport_focus_coordinates.var_480 = -1; - window->highlighted_item = 0; - - window_scenarioselect_init_tabs(); - - window->selected_tab = 0; + window->highlighted_scenario = NULL; } /** * * rct2: 0x00677C8A */ -static void window_scenarioselect_init_tabs() +static void window_scenarioselect_init_tabs(rct_window *w) { - int i, x, show_pages; - rct_widget* widget; - rct_scenario_basic* scenario; + int showPages = 0; + for (int i = 0; i < gScenarioListCount; i++) { + scenario_index_entry *scenario = &gScenarioList[i]; + if (gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_ORIGIN) { + showPages |= 1 << scenario->source_game; + } else { + int category = scenario->category; + if (category > SCENARIO_CATEGORY_OTHER) { + category = SCENARIO_CATEGORY_OTHER; + } + showPages |= 1 << category; + } + } - show_pages = 0; - for (i = 0; i < gScenarioListCount; i++) { - scenario = &gScenarioList[i]; - if (scenario->flags & SCENARIO_FLAGS_VISIBLE) - show_pages |= 1 << scenario->category; + int firstPage = bitscanforward(showPages); + if (firstPage != -1) { + w->selected_tab = firstPage; } - x = 3; - for (i = 0; i < 5; i++) { - widget = &window_scenarioselect_widgets[i + 4]; - if (!(show_pages & (1 << i))) { + int x = 3; + for (int i = 0; i < 8; i++) { + rct_widget* widget = &w->widgets[i + 4]; + if (!(showPages & (1 << i))) { widget->type = WWT_EMPTY; continue; } @@ -166,17 +217,24 @@ static void window_scenarioselect_init_tabs() } } +static void window_scenarioselect_close(rct_window *w) +{ + SafeFree(_listItems); +} + static void window_scenarioselect_mouseup(rct_window *w, int widgetIndex) { - if (widgetIndex == WIDX_CLOSE) + if (widgetIndex == WIDX_CLOSE) { window_close(w); + } } static void window_scenarioselect_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) { - if (widgetIndex >= WIDX_TAB1 && widgetIndex <= WIDX_TAB5) { + if (widgetIndex >= WIDX_TAB1 && widgetIndex <= WIDX_TAB8) { w->selected_tab = widgetIndex - 4; - w->highlighted_item = 0; + w->highlighted_scenario = NULL; + initialise_list_items(w); window_invalidate(w); window_event_resize_call(w); window_event_invalidate_call(w); @@ -187,17 +245,18 @@ static void window_scenarioselect_mousedown(int widgetIndex, rct_window*w, rct_w static void window_scenarioselect_scrollgetsize(rct_window *w, int scrollIndex, int *width, int *height) { - int i; - rct_scenario_basic *scenario; - - *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; + int y = 0; + for (sc_list_item *listItem = _listItems; listItem->type != LIST_ITEM_TYPE_END; listItem++) { + switch (listItem->type) { + case LIST_ITEM_TYPE_HEADING: + y += 18; + break; + case LIST_ITEM_TYPE_SCENARIO: + y += 24; + break; + } } + *height = y; } /** @@ -206,23 +265,22 @@ static void window_scenarioselect_scrollgetsize(rct_window *w, int scrollIndex, */ static void window_scenarioselect_scrollmousedown(rct_window *w, int scrollIndex, int x, int y) { - int i; - rct_scenario_basic *scenario; - - for (i = 0; i < gScenarioListCount; i++) { - scenario = &gScenarioList[i]; - if (scenario->category != w->selected_tab) - continue; - if (!(scenario->flags & SCENARIO_FLAGS_VISIBLE)) - continue; - - y -= 24; - if (y >= 0) - continue; - - audio_play_sound_panned(SOUND_CLICK_1, w->width / 2 + w->x, 0, 0, 0); - scenario_load_and_play(scenario); - break; + for (sc_list_item *listItem = _listItems; listItem->type != LIST_ITEM_TYPE_END; listItem++) { + switch (listItem->type) { + case LIST_ITEM_TYPE_HEADING: + y -= 18; + break; + case LIST_ITEM_TYPE_SCENARIO: + y -= 24; + if (y < 0 && !listItem->scenario.is_locked) { + audio_play_sound_panned(SOUND_CLICK_1, w->width / 2 + w->x, 0, 0, 0); + scenario_load_and_play_from_path(listItem->scenario.scenario->path); + } + break; + } + if (y < 0) { + break; + } } } @@ -232,26 +290,26 @@ static void window_scenarioselect_scrollmousedown(rct_window *w, int scrollIndex */ static void window_scenarioselect_scrollmouseover(rct_window *w, int scrollIndex, int x, int y) { - int i; - rct_scenario_basic *scenario, *selected; - - selected = NULL; - for (i = 0; i < gScenarioListCount; i++) { - scenario = &gScenarioList[i]; - if (scenario->category != w->selected_tab) - continue; - if (!(scenario->flags & SCENARIO_FLAGS_VISIBLE)) - continue; - - y -= 24; - if (y >= 0) - continue; - - selected = scenario; - break; + scenario_index_entry *selected = NULL; + for (sc_list_item *listItem = _listItems; listItem->type != LIST_ITEM_TYPE_END; listItem++) { + switch (listItem->type) { + case LIST_ITEM_TYPE_HEADING: + y -= 18; + break; + case LIST_ITEM_TYPE_SCENARIO: + y -= 24; + if (y < 0 && !listItem->scenario.is_locked) { + selected = listItem->scenario.scenario; + } + break; + } + if (y < 0) { + break; + } } - if (w->highlighted_item != (uint32)selected) { - w->highlighted_item = (uint32)selected; + + if (w->highlighted_scenario != selected) { + w->highlighted_scenario = selected; window_invalidate(w); } } @@ -261,113 +319,341 @@ static void window_scenarioselect_invalidate(rct_window *w) colour_scheme_update(w); w->pressed_widgets &= ~( (1 << WIDX_CLOSE) | (1 << WIDX_TAB1) | (1 << WIDX_TAB2) - | (1 << WIDX_TAB3) | (1 << WIDX_TAB4) | (1 << WIDX_TAB5) ); + | (1 << WIDX_TAB3) | (1 << WIDX_TAB4) | (1 << WIDX_TAB5) + | (1 << WIDX_TAB6) | (1 << WIDX_TAB7) | (1 << WIDX_TAB8) ); w->pressed_widgets |= 1LL << (w->selected_tab + 4); + + int windowWidth = w->width; + window_scenarioselect_widgets[WIDX_BACKGROUND].right = windowWidth - 1; + window_scenarioselect_widgets[WIDX_TITLEBAR].right = windowWidth - 2; + window_scenarioselect_widgets[WIDX_CLOSE].left = windowWidth - 13; + window_scenarioselect_widgets[WIDX_CLOSE].right = windowWidth - 3; + window_scenarioselect_widgets[WIDX_TABCONTENT].right = windowWidth - 1; + window_scenarioselect_widgets[WIDX_SCENARIOLIST].right = windowWidth - 179; + + int windowHeight = w->height; + window_scenarioselect_widgets[WIDX_BACKGROUND].bottom = windowHeight - 1; + window_scenarioselect_widgets[WIDX_TABCONTENT].bottom = windowHeight - 1; + + const int bottomMargin = gConfigGeneral.debugging_tools ? 17 : 5; + window_scenarioselect_widgets[WIDX_SCENARIOLIST].bottom = windowHeight - bottomMargin; } static void window_scenarioselect_paint(rct_window *w, rct_drawpixelinfo *dpi) { int i, x, y, format; rct_widget *widget; - rct_scenario_basic *scenario; + scenario_index_entry *scenario; window_draw_widgets(w, dpi); format = (theme_get_preset()->features.rct1_scenario_font) ? 5138 : 1193; // Text for each tab - for (i = 0; i < 5; i++) { + for (i = 0; i < 8; i++) { widget = &window_scenarioselect_widgets[WIDX_TAB1 + i]; if (widget->type == WWT_EMPTY) continue; x = (widget->left + widget->right) / 2 + w->x; y = (widget->top + widget->bottom) / 2 + w->y - 3; - RCT2_GLOBAL(0x013CE952 + 0, short) = STR_BEGINNER_PARKS + i; - gfx_draw_string_centred_wrapped(dpi, (void*)0x013CE952, x, y, 87, format, 10); + + if (gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_ORIGIN) { + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, short) = STR_SCENARIO_CATEGORY_RCT1 + i; + } else { // old-style + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, short) = ScenarioCategoryStringIds[i]; + } + gfx_draw_string_centred_wrapped(dpi, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, x, y, 87, format, 10); } // Return if no scenario highlighted - scenario = (rct_scenario_basic*)w->highlighted_item; - if (scenario == NULL) + scenario = w->highlighted_scenario; + if (scenario == NULL) { return; + } + + // Scenario path + if (gConfigGeneral.debugging_tools) { + utf8 path[MAX_PATH]; + shorten_path(path, sizeof(path), scenario->path, w->width - 6); + + const utf8 *pathPtr = path; + gfx_draw_string_left(dpi, 1170, (void*)&pathPtr, w->colours[1], w->x + 3, w->y + w->height - 3 - 11); + } // Scenario name x = w->x + window_scenarioselect_widgets[WIDX_SCENARIOLIST].right + 4; y = w->y + window_scenarioselect_widgets[WIDX_TABCONTENT].top + 5; 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); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, short) = 3165; // empty string + gfx_draw_string_centred_clipped(dpi, 1193, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, 0, x + 85, y, 170); y += 15; // 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; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, short) = 3165; // empty string + y += gfx_draw_string_left_wrapped(dpi, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, x, y, 170, 1191, 0) + 5; // Scenario objective - RCT2_GLOBAL(0x013CE952 + 0, short) = scenario->objective_type + STR_OBJECTIVE_NONE; - RCT2_GLOBAL(0x013CE952 + 2, short) = scenario->objective_arg_3; - RCT2_GLOBAL(0x013CE952 + 4, short) = date_get_total_months(MONTH_OCTOBER, scenario->objective_arg_1); - RCT2_GLOBAL(0x013CE952 + 6, int) = scenario->objective_arg_2; - y += gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x, y, 170, STR_OBJECTIVE, 0) + 5; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, short) = scenario->objective_type + STR_OBJECTIVE_NONE; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 2, short) = scenario->objective_arg_3; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 4, short) = date_get_total_months(MONTH_OCTOBER, scenario->objective_arg_1); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 6, int) = scenario->objective_arg_2; + y += gfx_draw_string_left_wrapped(dpi, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, x, y, 170, STR_OBJECTIVE, 0) + 5; // Scenario score - if (scenario->flags & SCENARIO_FLAGS_COMPLETED) { - 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); + if (scenario->highscore != NULL) { + const utf8 *completedByName = "???"; + if (!str_is_null_or_empty(scenario->highscore->name)) { + completedByName = scenario->highscore->name; + } + safe_strncpy((char*)0x009BC677, completedByName, 64); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, short) = 3165; // empty string + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 2, int) = scenario->highscore->company_value; + y += gfx_draw_string_left_wrapped(dpi, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, x, y, 170, STR_COMPLETED_BY_WITH_COMPANY_VALUE, 0); } } static void window_scenarioselect_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex) { - int i, y, colour, highlighted, highlighted_format, unhighlighted_format; - rct_scenario_basic *scenario; - - colour = ColourMapA[w->colours[1]].mid_light; + int colour = ColourMapA[w->colours[1]].mid_light; colour = (colour << 24) | (colour << 16) | (colour << 8) | colour; gfx_clear(dpi, colour); - highlighted_format = (theme_get_preset()->features.rct1_scenario_font) ? 5139 : 1193; - unhighlighted_format = (theme_get_preset()->features.rct1_scenario_font) ? 5139 : 1191; + int highlighted_format = (theme_get_preset()->features.rct1_scenario_font) ? 5139 : 1193; + int unhighlighted_format = (theme_get_preset()->features.rct1_scenario_font) ? 5139 : 1191; - y = 0; - for (i = 0; i < gScenarioListCount; i++) { - scenario = &gScenarioList[i]; - if (scenario->category != w->selected_tab) + bool wide = gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_ORIGIN; + + rct_widget *listWidget = &w->widgets[WIDX_SCENARIOLIST]; + int listWidth = listWidget->right - listWidget->left - 12; + + int y = 0; + for (sc_list_item *listItem = _listItems; listItem->type != LIST_ITEM_TYPE_END; listItem++) { + if (y > dpi->y + dpi->height) { continue; - if (!(scenario->flags & SCENARIO_FLAGS_VISIBLE)) - continue; - - if (y > dpi->y + dpi->height) - continue; - - highlighted = w->highlighted_item == (int)scenario; - - // Draw hover highlight - if (highlighted) - gfx_fill_rect(dpi, 0, y, w->width, y + 23, 0x02000031); - - // Draw scenario name - 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 - if (scenario->flags & SCENARIO_FLAGS_COMPLETED) { - // Draw completion tick - gfx_draw_sprite(dpi, 0x5A9F, 395, y + 1, 0); - - // Draw completion score - 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); } - y += 24; + switch (listItem->type) { + case LIST_ITEM_TYPE_HEADING:; + const int horizontalRuleMargin = 4; + draw_category_heading(w, dpi, horizontalRuleMargin, listWidth - horizontalRuleMargin, y + 2, listItem->heading.string_id); + y += 18; + break; + case LIST_ITEM_TYPE_SCENARIO:; + // Draw hover highlight + scenario_index_entry *scenario = listItem->scenario.scenario; + bool isHighlighted = w->highlighted_scenario == scenario; + if (isHighlighted) { + gfx_fill_rect(dpi, 0, y, w->width, y + 23, 0x02000031); + } + + bool isCompleted = scenario->highscore != NULL; + bool isDisabled = listItem->scenario.is_locked; + + // Draw scenario name + rct_string_id placeholderStringId = 3165; + safe_strncpy((char*)language_get_string(placeholderStringId), scenario->name, 64); + int format = isDisabled ? 865 : (isHighlighted ? highlighted_format : unhighlighted_format); + colour = isDisabled ? w->colours[1] | 0x40 : COLOUR_BLACK; + gfx_draw_string_centred(dpi, format, wide ? 270 : 210, y + 1, colour, &placeholderStringId); + + // Check if scenario is completed + if (isCompleted) { + // Draw completion tick + gfx_draw_sprite(dpi, 0x5A9F, wide ? 500 : 395, y + 1, 0); + + // Draw completion score + const utf8 *completedByName = "???"; + if (!str_is_null_or_empty(scenario->highscore->name)) { + completedByName = scenario->highscore->name; + } + safe_strncpy((char*)language_get_string(placeholderStringId), completedByName, 64); + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, rct_string_id) = 2793; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 2, rct_string_id) = placeholderStringId; + gfx_draw_string_centred(dpi, format, wide ? 270 : 210, y + 11, 0, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS); + } + + y += 24; + break; + } } } + +static void draw_category_heading(rct_window *w, rct_drawpixelinfo *dpi, int left, int right, int y, rct_string_id stringId) +{ + uint8 baseColour = w->colours[1]; + uint8 lightColour = ColourMapA[baseColour].lighter; + uint8 darkColour = ColourMapA[baseColour].mid_dark; + + // Draw string + int centreX = (left + right) / 2; + gfx_draw_string_centred(dpi, stringId, centreX, y, baseColour, NULL); + + // Get string dimensions + utf8 *buffer = RCT2_ADDRESS(RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER, utf8); + format_string(buffer, stringId, NULL); + int categoryStringHalfWidth = (gfx_get_string_width(buffer) / 2) + 4; + int strLeft = centreX - categoryStringHalfWidth; + int strRight = centreX + categoryStringHalfWidth; + + // Draw light horizontal rule + int lineY = y + 4; + gfx_draw_line(dpi, left, lineY, strLeft, lineY, lightColour); + gfx_draw_line(dpi, strRight, lineY, right, lineY, lightColour); + + // Draw dark horizontal rule + lineY++; + gfx_draw_line(dpi, left, lineY, strLeft, lineY, darkColour); + gfx_draw_line(dpi, strRight, lineY, right, lineY, darkColour); +} + +static void initialise_list_items(rct_window *w) +{ + SafeFree(_listItems); + + int capacity = gScenarioListCount + 16; + int length = 0; + _listItems = malloc(capacity * sizeof(sc_list_item)); + + // Mega park unlock + const uint32 rct1RequiredCompletedScenarios = (1 << SC_MEGA_PARK) - 1; + uint32 rct1CompletedScenarios = 0; + int megaParkListItemIndex = -1; + + int numUnlocks = INITIAL_NUM_UNLOCKED_SCENARIOS; + uint8 currentHeading = UINT8_MAX; + for (int i = 0; i < gScenarioListCount; i++) { + scenario_index_entry *scenario = &gScenarioList[i]; + if (!is_scenario_visible(w, scenario)) { + continue; + } + + sc_list_item *listItem; + + // Category heading + rct_string_id headingStringId = STR_NONE; + if (gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_ORIGIN) { + if (w->selected_tab != SCENARIO_SOURCE_REAL && currentHeading != scenario->category) { + currentHeading = scenario->category; + headingStringId = ScenarioCategoryStringIds[currentHeading]; + } + } else { + if (w->selected_tab <= SCENARIO_CATEGORY_EXPERT) { + if (currentHeading != scenario->source_game) { + currentHeading = scenario->source_game; + headingStringId = STR_SCENARIO_CATEGORY_RCT1 + currentHeading; + } + } else if (w->selected_tab == SCENARIO_CATEGORY_OTHER) { + int category = scenario->category; + if (category <= SCENARIO_CATEGORY_REAL) { + category = SCENARIO_CATEGORY_OTHER; + } + if (currentHeading != category) { + currentHeading = category; + headingStringId = ScenarioCategoryStringIds[category]; + } + } + } + if (headingStringId != (rct_string_id)STR_NONE) { + // Ensure list capacity + if (length == capacity) { + capacity += 32; + _listItems = realloc(_listItems, capacity * sizeof(sc_list_item)); + } + listItem = &_listItems[length++]; + + listItem->type = LIST_ITEM_TYPE_HEADING; + listItem->heading.string_id = headingStringId; + } + + // Ensure list capacity + if (length == capacity) { + capacity += 32; + _listItems = realloc(_listItems, capacity * sizeof(sc_list_item)); + } + listItem = &_listItems[length++]; + + // Scenario + listItem->type = LIST_ITEM_TYPE_SCENARIO; + listItem->scenario.scenario = scenario; + if (is_locking_enabled(w)) { + listItem->scenario.is_locked = numUnlocks <= 0; + if (scenario->highscore == NULL) { + numUnlocks--; + } else { + // Mark RCT1 scenario as completed + if (scenario->sc_id < SC_MEGA_PARK) { + rct1CompletedScenarios |= 1 << scenario->sc_id; + } + } + + // If scenario is Mega Park, keep a reference to it + if (scenario->sc_id == SC_MEGA_PARK) { + megaParkListItemIndex = length - 1; + } + } else { + listItem->scenario.is_locked = false; + } + } + + length++; + _listItems = realloc(_listItems, length * sizeof(sc_list_item)); + _listItems[length - 1].type = LIST_ITEM_TYPE_END; + + // Mega park handling + if (megaParkListItemIndex != -1) { + bool megaParkLocked = (rct1CompletedScenarios & rct1RequiredCompletedScenarios) != rct1RequiredCompletedScenarios; + _listItems[megaParkListItemIndex].scenario.is_locked = megaParkLocked; + if (megaParkLocked && gConfigGeneral.scenario_hide_mega_park) { + // Remove mega park + int remainingItems = length - megaParkListItemIndex - 1; + memmove(&_listItems[megaParkListItemIndex], &_listItems[megaParkListItemIndex + 1], remainingItems); + + // Remove empty headings + int i = 0; + for (sc_list_item *listItem = _listItems; listItem->type != LIST_ITEM_TYPE_END; listItem++) { + if (listItem->type == LIST_ITEM_TYPE_HEADING && (listItem + 1)->type != LIST_ITEM_TYPE_SCENARIO) { + remainingItems = length - i - 1; + memmove(&_listItems[i], &_listItems[i + 1], remainingItems); + listItem--; + } else { + i++; + } + } + } + } +} + +static bool is_scenario_visible(rct_window *w, scenario_index_entry *scenario) +{ + if (gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_ORIGIN) { + if (scenario->source_game != w->selected_tab) { + return false; + } + } else { + int category = scenario->category; + if (category > SCENARIO_CATEGORY_OTHER) { + category = SCENARIO_CATEGORY_OTHER; + } + if (category != w->selected_tab) { + return false; + } + } + return true; +} + +static bool is_locking_enabled(rct_window *w) +{ + if (gConfigGeneral.scenario_select_mode != SCENARIO_SELECT_MODE_ORIGIN) { + return false; + } + if (!gConfigGeneral.scenario_unlocking_enabled) { + return false; + } + if (w->selected_tab >= 6) { + return false; + } + return true; +} diff --git a/src/windows/tooltip.c b/src/windows/tooltip.c index f2bf9b6e7b..8ba29917ef 100644 --- a/src/windows/tooltip.c +++ b/src/windows/tooltip.c @@ -21,6 +21,7 @@ #include "../addresses.h" #include "../drawing/drawing.h" #include "../localisation/localisation.h" +#include "../input.h" #include "../interface/widget.h" #include "../interface/window.h" @@ -70,12 +71,12 @@ static rct_window_event_list window_tooltip_events = { void window_tooltip_reset(int x, int y) { - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_X, uint16) = x; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_CURSOR_Y, uint16) = y; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, uint8) = 255; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 1; - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~(1 << 4); + gTooltipCursorX = x; + gTooltipCursorY = y; + gTooltipTimeout = 0; + gTooltipWidget.window_classification = 255; + gInputState = INPUT_STATE_NORMAL; + gInputFlags &= ~INPUT_FLAG_4; } uint8* gTooltip_text_buffer = RCT2_ADDRESS(RCT2_ADDRESS_TOOLTIP_TEXT_BUFFER, uint8); @@ -134,7 +135,7 @@ void window_tooltip_show(rct_string_id id, int x, int y) ); w->widgets = window_tooltip_widgets; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, uint16) = 0; + gTooltipNotShownTicks = 0; } /** @@ -153,9 +154,9 @@ void window_tooltip_open(rct_window *widgetWindow, int widgetIndex, int x, int y 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; + gTooltipWidget.window_classification = widgetWindow->classification; + gTooltipWidget.window_number = widgetWindow->number; + gTooltipWidget.widget_index = widgetIndex; if (window_event_tooltip_call(widgetWindow, widgetIndex) == (rct_string_id)STR_NONE) return; @@ -170,8 +171,8 @@ void window_tooltip_open(rct_window *widgetWindow, int widgetIndex, int x, int y void window_tooltip_close() { window_close_by_class(WC_TOOLTIP); - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_TIMEOUT, uint16) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_WINDOW_CLASS, rct_windowclass) = 255; + gTooltipTimeout = 0; + gTooltipWidget.window_classification = 255; RCT2_GLOBAL(0x0142006C, sint32) = -1; RCT2_GLOBAL(0x009DE51E, uint8) = 0; } @@ -192,7 +193,7 @@ static void window_tooltip_onclose(rct_window *w) static void window_tooltip_update(rct_window *w) { if (RCT2_GLOBAL(0x009DE51E, uint8) == 0) - RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, uint16) = 0; + gTooltipNotShownTicks = 0; } /** diff --git a/src/windows/top_toolbar.c b/src/windows/top_toolbar.c index 390f4501d4..7c2e2b5e1c 100644 --- a/src/windows/top_toolbar.c +++ b/src/windows/top_toolbar.c @@ -310,7 +310,7 @@ static void window_top_toolbar_mouseup(rct_window *w, int widgetIndex) break; case WIDX_SCENERY: if (!tool_set(w, WIDX_SCENERY, 0)) { - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_6; window_scenery_open(); } break; @@ -3117,12 +3117,12 @@ void toggle_footpath_window() */ void toggle_land_window(rct_window *topToolbar, int widgetIndex) { - if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) == 1 && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 7) { + if ((gInputFlags & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) == WC_TOP_TOOLBAR && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 7) { tool_cancel(); } else { show_gridlines(); tool_set(topToolbar, widgetIndex, 18); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_6; RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; window_land_open(); } @@ -3134,12 +3134,12 @@ void toggle_land_window(rct_window *topToolbar, int widgetIndex) */ void toggle_clear_scenery_window(rct_window *topToolbar, int widgetIndex) { - if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) == 1 && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 16) { + if ((gInputFlags & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) == WC_TOP_TOOLBAR && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 16) { tool_cancel(); } else { show_gridlines(); tool_set(topToolbar, widgetIndex, 12); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_6; RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 2; window_clear_scenery_open(); } @@ -3151,12 +3151,12 @@ void toggle_clear_scenery_window(rct_window *topToolbar, int widgetIndex) */ void toggle_water_window(rct_window *topToolbar, int widgetIndex) { - if ((RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) == 1 && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 8) { + if ((gInputFlags & INPUT_FLAG_TOOL_ACTIVE) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) == WC_TOP_TOOLBAR && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 8) { tool_cancel(); } else { show_gridlines(); tool_set(topToolbar, widgetIndex, 19); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_6; RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; window_water_open(); } @@ -3168,7 +3168,7 @@ void toggle_water_window(rct_window *topToolbar, int widgetIndex) */ bool land_tool_is_active() { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) + if (!(gInputFlags & INPUT_FLAG_TOOL_ACTIVE)) return false; if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_TOP_TOOLBAR) return false; diff --git a/src/windows/track_place.c b/src/windows/track_place.c index 8232abba53..4fe5fb149d 100644 --- a/src/windows/track_place.c +++ b/src/windows/track_place.c @@ -389,7 +389,7 @@ void window_track_place_open() w->enabled_widgets = 4 | 8 | 0x10 | 0x20; window_init_scroll_widgets(w); tool_set(w, 6, 12); - RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_6; + gInputFlags |= INPUT_FLAG_6; window_push_others_right(w); show_gridlines(); _window_track_place_last_cost = MONEY32_UNDEFINED; @@ -449,7 +449,7 @@ static void window_track_place_mouseup(rct_window *w, int widgetIndex) */ static void window_track_place_update(rct_window *w) { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) + if (!(gInputFlags & INPUT_FLAG_TOOL_ACTIVE)) if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_TRACK_DESIGN_PLACE) window_close(w); } diff --git a/src/windows/water.c b/src/windows/water.c index 85ccc87f36..8a8b98dd08 100644 --- a/src/windows/water.c +++ b/src/windows/water.c @@ -181,8 +181,8 @@ static void window_water_textinput(rct_window *w, int widgetIndex, char *text) static void window_water_inputsize(rct_window *w) { - ((uint16*)TextInputDescriptionArgs)[0] = MINIMUM_TOOL_SIZE; - ((uint16*)TextInputDescriptionArgs)[1] = MAXIMUM_TOOL_SIZE; + TextInputDescriptionArgs[0] = MINIMUM_TOOL_SIZE; + TextInputDescriptionArgs[1] = MAXIMUM_TOOL_SIZE; window_text_input_open(w, WIDX_PREVIEW, 5128, 5129, STR_NONE, STR_NONE, 3); } @@ -256,7 +256,7 @@ static void window_water_paint(rct_window *w, rct_drawpixelinfo *dpi) */ static int window_water_should_close() { - if (!(RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_TOOL_ACTIVE)) + if (!(gInputFlags & INPUT_FLAG_TOOL_ACTIVE)) return 1; if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_TOP_TOOLBAR) return 1; diff --git a/src/world/footpath.c b/src/world/footpath.c index 298f239354..57b7fd3b1a 100644 --- a/src/world/footpath.c +++ b/src/world/footpath.c @@ -210,7 +210,7 @@ static money32 footpath_element_update(int x, int y, rct_map_element *mapElement } else if (pathItemType != 0) { if ( !(flags & GAME_COMMAND_FLAG_GHOST) && - (mapElement->properties.path.additions & 0x0F) == pathItemType && + footpath_element_get_path_scenery(mapElement) == pathItemType && !(mapElement->flags & MAP_ELEMENT_FLAG_BROKEN) ) { if (flags & GAME_COMMAND_FLAG_4) @@ -249,14 +249,17 @@ static money32 footpath_element_update(int x, int y, rct_map_element *mapElement if (flags & GAME_COMMAND_FLAG_4) return MONEY32_UNDEFINED; + // Should place a ghost? if (flags & GAME_COMMAND_FLAG_GHOST) { - if (mapElement->properties.path.additions & 0x0F) { + // Check if there is something on the path already + if (footpath_element_has_path_scenery(mapElement)) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, rct_string_id) = STR_NONE; return MONEY32_UNDEFINED; } + // There is nothing yet - check if we should place a ghost if (flags & GAME_COMMAND_FLAG_APPLY) - mapElement->properties.path.additions |= 0x80; + footpath_scenery_set_is_ghost(mapElement, true); } if (!(flags & GAME_COMMAND_FLAG_APPLY)) @@ -264,12 +267,12 @@ static money32 footpath_element_update(int x, int y, rct_map_element *mapElement if ( (pathItemType != 0 && !(flags & GAME_COMMAND_FLAG_GHOST)) || - (pathItemType == 0 && (mapElement->properties.path.additions & 0x80)) + (pathItemType == 0 && footpath_element_path_scenery_is_ghost(mapElement)) ) { - mapElement->properties.path.additions &= ~0x80; + footpath_scenery_set_is_ghost(mapElement, false); } - mapElement->properties.path.additions = (mapElement->properties.path.additions & 0xF0) | pathItemType; + footpath_element_set_path_scenery(mapElement, pathItemType); mapElement->flags &= ~MAP_ELEMENT_FLAG_BROKEN; if (pathItemType != 0) { rct_scenery_entry* scenery_entry = g_pathBitSceneryEntries[pathItemType - 1]; @@ -292,7 +295,7 @@ static money32 footpath_element_update(int x, int y, rct_map_element *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) | pathItemType; + footpath_element_set_path_scenery(mapElement, pathItemType); mapElement->flags &= ~MAP_ELEMENT_FLAG_BROKEN; loc_6A6620(flags, x, y, mapElement); @@ -1579,7 +1582,7 @@ 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) +uint8 footpath_element_get_slope_direction(rct_map_element *mapElement) { return mapElement->properties.path.type & 3; } @@ -1594,6 +1597,45 @@ bool footpath_element_is_wide(rct_map_element *mapElement) return mapElement->type & 2; } +bool footpath_element_has_path_scenery(rct_map_element *mapElement) +{ + return (mapElement->properties.path.additions & 0xF) > 0; +} + +uint8 footpath_element_get_path_scenery(rct_map_element *mapElement) +{ + return mapElement->properties.path.additions & 0xF; +} + +void footpath_element_set_path_scenery(rct_map_element *mapElement, uint8 pathSceneryType) +{ + mapElement->properties.path.additions = (mapElement->properties.path.additions & 0xF0) | pathSceneryType; +} + +uint8 footpath_element_get_path_scenery_index(rct_map_element *mapElement) +{ + return footpath_element_get_path_scenery(mapElement) - 1; +} + +bool footpath_element_path_scenery_is_ghost(rct_map_element *mapElement) +{ + return (mapElement->properties.path.additions & 0x80) == 0x80; +} + +void footpath_scenery_set_is_ghost(rct_map_element *mapElement, bool isGhost) +{ + // Remove ghost flag + mapElement->properties.path.additions &= ~0x80; + // Set flag if it should be a ghost + if (isGhost) + mapElement->properties.path.additions |= 0x80; +} + +uint8 footpath_element_get_type(rct_map_element *mapElement) +{ + return mapElement->properties.path.type >> 4; +} + /** * * rct2: 0x006A8B12 diff --git a/src/world/footpath.h b/src/world/footpath.h index 05c5ad43ad..7f67b982af 100644 --- a/src/world/footpath.h +++ b/src/world/footpath.h @@ -70,9 +70,16 @@ void footpath_bridge_get_info_from_pos(int screenX, int screenY, int *x, int *y, 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); +uint8 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); +uint8 footpath_element_get_type(rct_map_element *mapElement); +bool footpath_element_has_path_scenery(rct_map_element *mapElement); +uint8 footpath_element_get_path_scenery(rct_map_element *mapElement); +void footpath_element_set_path_scenery(rct_map_element *mapElement, uint8 pathSceneryType); +uint8 footpath_element_get_path_scenery_index(rct_map_element *mapElement); +bool footpath_element_path_scenery_is_ghost(rct_map_element *mapElement); +void footpath_scenery_set_is_ghost(rct_map_element *mapElement, bool isGhost); 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 b043fcfe69..38cb1811b2 100644 --- a/src/world/fountain.c +++ b/src/world/fountain.c @@ -24,6 +24,7 @@ #include "map.h" #include "scenery.h" #include "sprite.h" +#include "footpath.h" enum { PATTERN_CYCLIC_SQUARES, @@ -297,14 +298,14 @@ static bool is_jumping_fountain(int type, int x, int y, int z) continue; if (mapElement->base_height != z) continue; - if (mapElement->properties.path.additions & 0x80) + if (footpath_element_path_scenery_is_ghost(mapElement)) continue; - int additions = mapElement->properties.path.additions & 0x0F; - if (additions == 0) + if (!footpath_element_has_path_scenery(mapElement)) continue; - rct_scenery_entry *sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + uint8 additionIndex = footpath_element_get_path_scenery_index(mapElement); + rct_scenery_entry *sceneryEntry = g_pathBitSceneryEntries[additionIndex]; if (!(sceneryEntry->path_bit.var_06 & pathBitFlagMask)) continue; diff --git a/src/world/map.c b/src/world/map.c index 4228bc709d..6d75247f9c 100644 --- a/src/world/map.c +++ b/src/world/map.c @@ -645,15 +645,18 @@ int map_is_location_owned(int x, int y, int z) { rct_map_element *mapElement; + // This check is to avoid throwing lots of messages in logs. 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 1; - - if (mapElement->properties.surface.ownership & OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED) { - z /= 8; - if (z < mapElement->base_height || z - 2 > mapElement->base_height) + if (mapElement != NULL) { + if (mapElement->properties.surface.ownership & OWNERSHIP_OWNED) return 1; + + if (mapElement->properties.surface.ownership & OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED) { + z /= 8; + if (z < mapElement->base_height || z - 2 > mapElement->base_height) + return 1; + } } } @@ -708,6 +711,12 @@ void game_command_remove_scenery(int* eax, int* ebx, int* ecx, int* edx, int* es money32 cost; rct_scenery_entry *entry = g_smallSceneryEntries[scenery_type]; + if (entry == (rct_scenery_entry *)0xFFFFFFFF) + { + log_warning("Invalid game command for scenery removal, scenery_type = %u", scenery_type); + *ebx = MONEY32_UNDEFINED; + return; + } cost = entry->small_scenery.removal_price * 10; RCT2_GLOBAL(RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE, uint8) = RCT_EXPENDITURE_TYPE_LANDSCAPING * 4; @@ -793,6 +802,12 @@ void game_command_remove_large_scenery(int* eax, int* ebx, int* ecx, int* edx, i bool element_found = false; rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + if (map_element == NULL) + { + log_warning("Invalid game command for scenery removal, x = %d, y = %d", x, y); + *ebx = MONEY32_UNDEFINED; + return; + } do { if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) continue; @@ -2128,6 +2143,11 @@ static money32 smooth_land_tile(int direction, uint8 flags, int x, int y, int ta // Get height of tile rct_map_element *mapElement = map_get_surface_element_at(x >> 5, y >> 5); + if (mapElement == NULL) + { + log_warning("Invalid coordinates for land smoothing, x = %d, y = %d", x, y); + return MONEY32_UNDEFINED; + } int baseZ = map_get_corner_height(mapElement, direction); // Check if tile is same height as target tile @@ -2200,6 +2220,11 @@ money32 smooth_land(int flags, int centreX, int centreY, int mapLeft, int mapTop x = mapLeft; y = mapTop; mapElement = map_get_surface_element_at(x >> 5, y >> 5); + if (mapElement == NULL) + { + log_warning("Invalid coordinates for land smoothing, x = %d, y = %d", x, y); + return MONEY32_UNDEFINED; + } int slope = mapElement->properties.surface.slope & MAP_ELEMENT_SLOPE_MASK; if (slope != 0) { commandType = command == 0xFFFF ? GAME_COMMAND_RAISE_LAND : GAME_COMMAND_LOWER_LAND; @@ -3294,12 +3319,25 @@ void game_command_place_large_scenery(int* eax, int* ebx, int* ecx, int* edx, in return; } + if (entry_index >= 128) + { + log_warning("Invalid game command for scenery placement, entry_index = %u", entry_index); + *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 == (rct_scenery_entry *)0xFFFFFFFF) + { + log_warning("Invalid game command for scenery placement, entry_index = %u", entry_index); + *ebx = MONEY32_UNDEFINED; + return; + } if(scenery_entry->large_scenery.var_11 != 0xFF){ banner_id = create_new_banner(flags); @@ -4284,6 +4322,10 @@ bool map_element_is_underground(rct_map_element *mapElement) 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); + if (mapElement == NULL) + { + return NULL; + } do { if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_SCENERY_MULTIPLE) continue; @@ -4767,6 +4809,12 @@ void game_command_place_park_entrance(int* eax, int* ebx, int* ecx, int* edx, in void game_command_set_banner_name(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) { static char newName[128]; + if ((*ecx >= MAX_BANNERS) || (*ecx < 0)) + { + log_warning("Invalid game command for setting banner name, banner id = %d", *ecx); + *ebx = MONEY32_UNDEFINED; + return; + } rct_banner* banner = &gBanners[*ecx]; int nameChunkIndex = *eax & 0xFFFF; @@ -4776,6 +4824,7 @@ void game_command_set_banner_name(int* eax, int* ebx, int* ecx, int* edx, int* e if (nameChunkOffset < 0) nameChunkOffset = 2; nameChunkOffset *= 12; + nameChunkOffset = min(nameChunkOffset, countof(newName) - 12); RCT2_GLOBAL(newName + nameChunkOffset + 0, uint32) = *edx; RCT2_GLOBAL(newName + nameChunkOffset + 4, uint32) = *ebp; RCT2_GLOBAL(newName + nameChunkOffset + 8, uint32) = *edi; @@ -4811,6 +4860,12 @@ void game_command_set_banner_name(int* eax, int* ebx, int* ecx, int* edx, int* e void game_command_set_sign_name(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) { static char newName[128]; + if ((*ecx >= MAX_BANNERS) || (*ecx < 0)) + { + log_warning("Invalid game command for setting sign name, banner id = %d", *ecx); + *ebx = MONEY32_UNDEFINED; + return; + } rct_banner* banner = &gBanners[*ecx]; int x = banner->x << 5; int y = banner->y << 5; @@ -4822,6 +4877,7 @@ void game_command_set_sign_name(int* eax, int* ebx, int* ecx, int* edx, int* esi if (nameChunkOffset < 0) nameChunkOffset = 2; nameChunkOffset *= 12; + nameChunkOffset = min(nameChunkOffset, countof(newName) - 12); RCT2_GLOBAL(newName + nameChunkOffset + 0, uint32) = *edx; RCT2_GLOBAL(newName + nameChunkOffset + 4, uint32) = *ebp; RCT2_GLOBAL(newName + nameChunkOffset + 8, uint32) = *edi; @@ -4866,6 +4922,12 @@ void game_command_set_sign_name(int* eax, int* ebx, int* ecx, int* edx, int* esi } void game_command_set_banner_style(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp) { + if ((*ecx >= MAX_BANNERS) || (*ecx < 0)) + { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_INVALID_SELECTION_OF_OBJECTS; + *ebx = MONEY32_UNDEFINED; + return; + } rct_banner* banner = &gBanners[*ecx]; banner->colour = (uint8)*edx; diff --git a/src/world/map.h b/src/world/map.h index d96fc9fdd8..ae00c163d6 100644 --- a/src/world/map.h +++ b/src/world/map.h @@ -31,7 +31,7 @@ typedef struct { } rct_map_element_surface_properties; typedef struct { - uint8 type; //4 + uint8 type; //4 0xF0 Path type, 0x08 Unknown/Unused, 0x04 Set when path is diagonal, 0x03 Rotation uint8 additions; //5 uint8 edges; //6 union { diff --git a/src/world/park.c b/src/world/park.c index 6512d2a9a4..e17e053359 100644 --- a/src/world/park.c +++ b/src/world/park.c @@ -871,6 +871,7 @@ void game_command_set_park_name(int *eax, int *ebx, int *ecx, int *edx, int *esi if (nameChunkOffset < 0) nameChunkOffset = 2; nameChunkOffset *= 12; + nameChunkOffset = min(nameChunkOffset, countof(newName) - 12); RCT2_GLOBAL(newName + nameChunkOffset + 0, uint32) = *edx; RCT2_GLOBAL(newName + nameChunkOffset + 4, uint32) = *ebp; RCT2_GLOBAL(newName + nameChunkOffset + 8, uint32) = *edi; diff --git a/src/world/scenery.c b/src/world/scenery.c index 84a3833496..21c19b2dde 100644 --- a/src/world/scenery.c +++ b/src/world/scenery.c @@ -28,6 +28,7 @@ #include "map.h" #include "park.h" #include "scenery.h" +#include "footpath.h" void scenery_increase_age(int x, int y, rct_map_element *mapElement); @@ -40,10 +41,9 @@ void scenery_update_tile(int x, int y) if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_SCENERY) { scenery_update_age(x, y, mapElement); } else if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH) { - int additions = mapElement->properties.path.additions & 0x0F; - if (additions != 0 && !(mapElement->properties.path.additions & 0x80)) { + if (footpath_element_has_path_scenery(mapElement) && !footpath_element_path_scenery_is_ghost(mapElement)) { rct_scenery_entry *sceneryEntry; - sceneryEntry = g_pathBitSceneryEntries[additions - 1]; + sceneryEntry = g_pathBitSceneryEntries[footpath_element_get_path_scenery_index(mapElement)]; if (sceneryEntry->path_bit.var_06 & PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER) { jumping_fountain_begin(JUMPING_FOUNTAIN_TYPE_WATER, x, y, mapElement); } else if (sceneryEntry->path_bit.var_06 & PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW) { diff --git a/src/world/scenery.h b/src/world/scenery.h index a98578eb04..1869069998 100644 --- a/src/world/scenery.h +++ b/src/world/scenery.h @@ -163,6 +163,7 @@ enum { #define g_largeSceneryEntries ((rct_scenery_entry**)object_entry_groups[OBJECT_TYPE_LARGE_SCENERY].chunks) #define g_wallSceneryEntries ((rct_scenery_entry**)object_entry_groups[OBJECT_TYPE_WALLS].chunks) #define g_bannerSceneryEntries ((rct_scenery_entry**)object_entry_groups[OBJECT_TYPE_BANNERS].chunks) +#define g_pathSceneryEntries ((rct_scenery_entry**)object_entry_groups[OBJECT_TYPE_PATHS].chunks) // Often 0x009ADA50 is used for pathBits this is 1 entry before g_pathBitSceneryEntries and is used // because 0 represents no path bits on a path. So remember to remove 1 when using it for 0x009ADA50 diff --git a/src/world/sprite.c b/src/world/sprite.c index cb9f5bdac9..7758041618 100644 --- a/src/world/sprite.c +++ b/src/world/sprite.c @@ -29,6 +29,8 @@ rct_sprite* g_sprite_list = RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_LIST, rct_sprite); +rct_sprite_entry* g_sprite_entries = RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_ENTRIES, rct_sprite_entry); + static uint16 sprite_get_first_in_quadrant(int x, int y) { int offset = ((x & 0x1FE0) << 3) | (y >> 5); diff --git a/src/world/sprite.h b/src/world/sprite.h index db1a20dce5..fd32231273 100644 --- a/src/world/sprite.h +++ b/src/world/sprite.h @@ -330,6 +330,23 @@ typedef union { rct_steam_particle steam_particle; } rct_sprite; +typedef struct { + uint8 sprite_width; // 0x00 + uint8 sprite_height_negative; // 0x01 + uint8 sprite_height_positive; // 0x02 + uint8 unused; // 0x03 +} rct_sprite_bounds; + +typedef struct { + uint32 base_image; // 0x00 + uint8* unkn_04; // 0x04 +} rct_sprite_image; + +typedef struct { + rct_sprite_image *sprite_image; // 0x00 + rct_sprite_bounds *sprite_bounds; // 0x04 +} rct_sprite_entry; + enum { SPRITE_MISC_STEAM_PARTICLE, SPRITE_MISC_MONEY_EFFECT, @@ -346,6 +363,10 @@ enum { // rct2: 0x010E63BC extern rct_sprite* g_sprite_list; +// rct2: 0x00982708 +extern rct_sprite_entry* g_sprite_entries; + + rct_sprite *create_sprite(uint8 bl); void reset_sprite_list(); void reset_0x69EBE4(); diff --git a/test/tests.h b/test/tests.h index 7691a3dd88..06619ec167 100644 --- a/test/tests.h +++ b/test/tests.h @@ -33,11 +33,11 @@ int run_all_tests(); #include "../src/scenario.h" static void test_load_scenario(CuTest* tc, const char* file_name) { - const rct_scenario_basic* scenario = get_scenario_by_filename(file_name); + const scenario_index_entry* scenario = scenario_list_find_by_path(file_name); if (scenario == NULL) { CuFail(tc, "Could not load scenario"); } - scenario_load_and_play(scenario); + scenario_load_and_play_from_path(scenario->name); } #endif