diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 854488efb8..0e84ff1e7d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,8 @@ name: CI on: [push, pull_request] +defaults: + run: + shell: bash env: OPENRCT2_BUILD_SERVER: GitHub OPENRCT2_ORG_TOKEN: ${{ secrets.OPENRCT2_ORG_TOKEN }} @@ -18,7 +21,7 @@ jobs: with: fetch-depth: 0 - name: Lint Commit Messages - uses: wagoid/commitlint-github-action@v1 + uses: wagoid/commitlint-github-action@v3 with: configFile: .commitlint.json check-code-formatting: @@ -28,14 +31,14 @@ jobs: image: openrct2/openrct2-build:0.3.1-format steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Run clang-format shell: sh run: scripts/check-code-formatting windows: name: Windows runs-on: windows-latest - needs: [check-code-formatting] + needs: check-code-formatting strategy: fail-fast: false matrix: @@ -45,27 +48,24 @@ jobs: PLATFORM: ${{ matrix.platform }} steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Build OpenRCT2 - shell: bash run: . scripts/setenv && build - name: Build artifacts - shell: bash run: | . scripts/setenv -q build-portable build-symbols build-installer -i - name: Upload artifacts (CI) - uses: actions/upload-artifact@v2-preview + uses: actions/upload-artifact@v2 with: - name: "OpenRCT2-Windows-${{ matrix.platform }}" - path: artifacts/* + name: OpenRCT2-${{ runner.os }}-${{ matrix.platform }} + path: artifacts + if-no-files-found: error - name: Run Tests - shell: bash run: . scripts/setenv -q && run-tests - name: Upload artifacts (openrct2.org) - shell: bash run: | . scripts/setenv -q if [[ "$OPENRCT2_PUSH" == "true" ]]; then @@ -77,55 +77,51 @@ jobs: echo 'Not going to push build' fi windows-mingw: - name: Windows (win32) using mingw + name: Windows (${{ matrix.platform_name }}) using mingw runs-on: ubuntu-latest - needs: [check-code-formatting] + needs: check-code-formatting container: image: openrct2/openrct2-build:0.3.1-mingw + strategy: + fail-fast: false + matrix: + platform: [win32, NT5.1] + include: + - platform: win32 + platform_name: win32 + cache_key: windows-mingw + build_flags: -DBUILD_SHARED_LIBS=ON -DENABLE_SCRIPTING=OFF + - platform: NT5.1 + platform_name: win32, NT5.1 + cache_key: windows-mingw-nt51 + build_flags: -DDISABLE_HTTP=Off -DENABLE_SCRIPTING=ON -DCMAKE_CXX_FLAGS="-Wno-error=cast-function-type -Wno-error=unused-function" -DSTATIC=on -DMINGW_TARGET_NT5_1=ON steps: - name: Checkout uses: actions/checkout@v2 - name: ccache uses: hendrikmuhs/ccache-action@v1 with: - key: windows-mingw + key: ${{ matrix.cache_key }} - name: Build OpenRCT2 run: | sudo su mkdir bin && cd bin - cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE=../CMakeLists_mingw.txt -DCMAKE_BUILD_TYPE=MinSizeRel -DDISABLE_IPO=on -DFORCE32=on -DBUILD_SHARED_LIBS=ON -DENABLE_SCRIPTING=OFF - ninja -k0 - windows-mingw-nt51: - name: Windows (win32, WinNT5.1) using mingw - runs-on: ubuntu-latest - needs: [check-code-formatting] - container: - image: openrct2/openrct2-build:0.3.1-mingw - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: ccache - uses: hendrikmuhs/ccache-action@v1 - with: - key: windows-mingw-nt51 - - name: Build OpenRCT2 - run: | - sudo su - mkdir bin && cd bin - cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE=../CMakeLists_mingw.txt -DCMAKE_BUILD_TYPE=MinSizeRel -DDISABLE_IPO=on -DDISABLE_HTTP=Off -DFORCE32=on -DENABLE_SCRIPTING=ON -DCMAKE_CXX_FLAGS="-Wno-error=cast-function-type -Wno-error=unused-function" -DSTATIC=on -DMINGW_TARGET_NT5_1=ON + cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE=../CMakeLists_mingw.txt -DCMAKE_BUILD_TYPE=Release -DDISABLE_IPO=on -DFORCE32=on ${{ matrix.build_flags }} ninja -k0 - name: Upload artifacts (CI) - uses: actions/upload-artifact@v2-preview + if: matrix.platform == 'NT5.1' + uses: actions/upload-artifact@v2 with: - name: "OpenRCT2-NT5.1" + name: OpenRCT2-${{ matrix.platform }} path: bin/openrct2.exe + if-no-files-found: error macos-xcode: name: macOS (x64) using Xcode runs-on: macos-latest - needs: [check-code-formatting] + needs: check-code-formatting steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Build OpenRCT2 run: | . scripts/setenv @@ -136,10 +132,11 @@ jobs: cd artifacts zip -rq openrct2-macos.zip OpenRCT2.app - name: Upload artifacts (CI) - uses: actions/upload-artifact@v2-preview + uses: actions/upload-artifact@v2 with: - name: "OpenRCT2-macOS" + name: OpenRCT2-${{ runner.os }}-xcode path: artifacts/openrct2-macos.zip + if-no-files-found: error - name: Upload artifacts (openrct2.org) run: | . scripts/setenv @@ -151,140 +148,107 @@ jobs: macos-cmake: name: macOS (x64) using CMake runs-on: macos-latest - needs: [check-code-formatting] + needs: check-code-formatting steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: ccache uses: hendrikmuhs/ccache-action@v1 with: key: macos - name: Build OpenRCT2 run: | - brew install ninja - . scripts/setenv -q && build -DWITH_TESTS=on -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_SHARED_LIBS=on + HOMEBREW_NO_ANALYTICS=1 brew install ninja + . scripts/setenv -q && build -DWITH_TESTS=on -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=on - name: Run Tests - shell: bash run: . scripts/setenv -q && run-tests - name: Build artifacts - shell: bash - run: . scripts/setenv -q && build-portable artifacts/OpenRCT2-MacOS-x64-cmake.tar.gz bin/install/usr + run: | + . scripts/setenv + mkdir -p artifacts + mv bin/OpenRCT2.app artifacts + echo -e "\033[0;36mCompressing OpenRCT2.app...\033[0m" + cd artifacts + zip -rqy openrct2-macos.zip OpenRCT2.app - name: Upload artifacts (CI) - uses: actions/upload-artifact@v2-preview + uses: actions/upload-artifact@v2 with: - name: "OpenRCT2-macOS-cmake" - path: artifacts - + name: OpenRCT2-${{ runner.os }}-cmake + path: artifacts/openrct2-macos.zip + if-no-files-found: error linux-portable: - name: Linux (x64, portable) + name: Linux (${{ matrix.platform }}, portable) runs-on: ubuntu-latest - needs: [check-code-formatting] + needs: check-code-formatting container: - image: openrct2/openrct2-build:0.3.1-bionic + image: ${{ matrix.image }} + strategy: + fail-fast: false + matrix: + platform: [x86_64, i686] + include: + - platform: x86_64 + image: openrct2/openrct2-build:0.3.1-bionic + cache_key: linux-portable + build_flags: -DCMAKE_POSITION_INDEPENDENT_CODE=on -DCMAKE_CXX_FLAGS="-g -gz" + - platform: i686 + image: openrct2/openrct2-build:0.3.1-bionic32 + cache_key: linux-portable-32 + build_flags: -DFORCE32=ON -DENABLE_SCRIPTING=OFF -DCMAKE_CXX_FLAGS="-m32 -gz" steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: ccache uses: hendrikmuhs/ccache-action@v1 with: - key: linux-portable + key: ${{ matrix.cache_key }} - name: Get pre-reqs - shell: bash run: . scripts/setenv && get-discord-rpc - name: Build OpenRCT2 - shell: bash - run: . scripts/setenv -q && build -DWITH_TESTS=on -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_SHARED_LIBS=ON -DPORTABLE=ON -DCMAKE_POSITION_INDEPENDENT_CODE=on -DCMAKE_CXX_FLAGS="-g -gz" + run: . scripts/setenv -q && build -DWITH_TESTS=on -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DPORTABLE=ON ${{ matrix.build_flags }} - name: Build artifacts - shell: bash - run: . scripts/setenv -q && build-portable artifacts/OpenRCT2-Linux-x86_64.tar.gz bin/install/usr + run: . scripts/setenv -q && build-portable artifacts/OpenRCT2-${{ runner.os }}-${{ matrix.platform }}.tar.gz bin/install/usr - name: Upload artifacts (CI) - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v2 with: - name: "OpenRCT2-Linux-x86_64" + name: OpenRCT2-${{ runner.os }}-${{ matrix.platform }} path: artifacts + if-no-files-found: error - name: Run Tests - shell: bash run: . scripts/setenv -q && run-tests - name: Upload artifacts (openrct2.org) - shell: bash run: | . scripts/setenv -q if [[ "$OPENRCT2_PUSH" == "true" ]]; then - upload-build artifacts/OpenRCT2-Linux-x86_64.tar.gz linux-x86_64 $OPENRCT2_VERSION $OPENRCT2_SHA1 $OPENRCT2_BRANCH - else - echo 'Not going to push build' - fi - linux-portable-32: - name: Linux (i686, portable) - runs-on: ubuntu-latest - needs: [check-code-formatting] - container: - image: openrct2/openrct2-build:0.3.1-bionic32 - steps: - - name: Checkout - uses: actions/checkout@v1 - - name: ccache - uses: hendrikmuhs/ccache-action@v1 - with: - key: linux-portable-32 - - name: Get pre-reqs - shell: bash - run: . scripts/setenv && get-discord-rpc - - name: Build OpenRCT2 - shell: bash - env: - TESTPAINT: true - run: . scripts/setenv -q && build -DWITH_TESTS=on -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_SHARED_LIBS=ON -DPORTABLE=ON -DFORCE32=ON -DENABLE_SCRIPTING=OFF -DCMAKE_CXX_FLAGS="-m32 -gz" - - name: Build artifacts - shell: bash - run: . scripts/setenv -q && build-portable artifacts/OpenRCT2-Linux-i686.tar.gz bin/install/usr - - name: Upload artifacts (CI) - uses: actions/upload-artifact@v1 - with: - name: "OpenRCT2-Linux-i686" - path: artifacts - - name: Run Tests - shell: bash - run: . scripts/setenv -q && run-tests - - name: Run testpaint - shell: bash - run: . scripts/setenv -q && run-testpaint - - name: Upload artifacts (openrct2.org) - shell: bash - run: | - . scripts/setenv -q - if [[ "$OPENRCT2_PUSH" == "true" ]]; then - upload-build artifacts/OpenRCT2-Linux-i686.tar.gz linux-i686 $OPENRCT2_VERSION $OPENRCT2_SHA1 $OPENRCT2_BRANCH + upload-build artifacts/OpenRCT2-${{ runner.os }}-${{ matrix.platform }}.tar.gz linux-${{ matrix.platform }} $OPENRCT2_VERSION $OPENRCT2_SHA1 $OPENRCT2_BRANCH else echo 'Not going to push build' fi linux-appimage: name: Linux (x64, AppImage) runs-on: ubuntu-latest - needs: [check-code-formatting] + needs: check-code-formatting container: image: openrct2/openrct2-build:0.3.1-bionic steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: ccache uses: hendrikmuhs/ccache-action@v1 with: key: linux-appimage - name: Get pre-reqs - shell: bash run: . scripts/setenv -q && get-discord-rpc - name: Build OpenRCT2 - shell: bash run: . scripts/setenv -q && build -DCMAKE_BUILD_TYPE=Release -DAPPIMAGE=ON -DOPENRCT2_USE_CCACHE=on - name: Build AppImage - shell: bash run: . scripts/setenv -q && build-appimage - name: Upload artifacts (CI) - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v2 with: name: OpenRCT2-AppImage path: artifacts + if-no-files-found: error linux-flathub-beta: name: Linux (Flathub beta channel) if: github.repository == 'OpenRCT2/OpenRCT2' && github.ref == 'refs/heads/develop' && github.event_name == 'push' @@ -299,14 +263,16 @@ jobs: client-payload: '{ "commit": "${{ github.sha }}" }' linux-docker: name: Linux (docker) - needs: [check-code-formatting] + needs: check-code-formatting if: github.repository == 'OpenRCT2/OpenRCT2' runs-on: ubuntu-latest steps: + - name: Checkout image + uses: actions/checkout@v2 + with: + repository: OpenRCT2/openrct2-docker - name: Build image - run: | - git clone --depth 1 https://github.com/OpenRCT2/openrct2-docker . - docker build -t openrct2/openrct2-cli:develop develop/cli + run: docker build -t openrct2/openrct2-cli:develop develop/cli - name: Push image env: OPENRCT2_DOCKER_USER: ${{ secrets.OPENRCT2_DOCKER_USER }} @@ -323,34 +289,32 @@ jobs: linux-clang: name: Linux (Debug, [http, network, OpenGL] disabled) using clang runs-on: ubuntu-latest - needs: [check-code-formatting] + needs: check-code-formatting container: image: openrct2/openrct2-build:0.3.1-bionic steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: ccache uses: hendrikmuhs/ccache-action@v1 with: key: linux-clang - name: Build OpenRCT2 - shell: bash run: . scripts/setenv && build -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Debug -DDISABLE_NETWORK=ON -DDISABLE_HTTP=ON -DDISABLE_OPENGL=ON android: name: Android runs-on: ubuntu-latest - needs: [check-code-formatting] + needs: check-code-formatting container: image: openrct2/openrct2-build:0.3.1-android steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: ccache uses: hendrikmuhs/ccache-action@v1 with: key: android - name: Build OpenRCT2 - shell: bash run: | . scripts/setenv pushd src/openrct2-android @@ -359,12 +323,12 @@ jobs: mkdir -p artifacts mv src/openrct2-android/app/build/outputs/apk/arm/pr/app-arm-pr.apk artifacts/openrct2-arm.apk - name: Upload artifacts (CI) - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v2 with: - name: "OpenRCT2-Android" + name: OpenRCT2-Android path: artifacts + if-no-files-found: error - name: Upload artifacts (openrct2.org) - shell: bash run: | . scripts/setenv -q if [[ "$OPENRCT2_PUSH" == "true" ]]; then diff --git a/.github/workflows/localisation.yml b/.github/workflows/localisation.yml index 99b47d587e..6efae26592 100644 --- a/.github/workflows/localisation.yml +++ b/.github/workflows/localisation.yml @@ -1,7 +1,7 @@ name: Localisation Merge on: schedule: - - cron: '0 4 * * *' + - cron: '0 4 * * *' jobs: merge-localisation: name: Merge Localisation @@ -18,7 +18,7 @@ jobs: - name: Clone repositories run: | echo "Cloning repositories..." - git clone -b master git@github.com:OpenRCT2/Localisation.git Localisation + git clone -b master --depth 1 git@github.com:OpenRCT2/Localisation.git Localisation git clone -b develop git@github.com:OpenRCT2/OpenRCT2.git OpenRCT2 - name: Copy over language files run: | @@ -29,8 +29,8 @@ jobs: cp $f "./OpenRCT2/data/language/$filename" done - name: Commit and push + working-directory: OpenRCT2 run: | - pushd ./OpenRCT2 if [[ $(git status -s) ]]; then echo "Committing and pushing..." git add . @@ -42,4 +42,3 @@ jobs: else echo "No changes to merge." fi - popd diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e5e6a387c..4a8cfb4a72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,14 +42,17 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}") -set(TITLE_SEQUENCE_URL "https://github.com/OpenRCT2/title-sequences/releases/download/v0.1.2c/title-sequences.zip") +set(TITLE_SEQUENCE_VERSION "0.1.2c") +set(TITLE_SEQUENCE_URL "https://github.com/OpenRCT2/title-sequences/releases/download/v${TITLE_SEQUENCE_VERSION}/title-sequences.zip") set(TITLE_SEQUENCE_SHA1 "304d13a126c15bf2c86ff13b81a2f2cc1856ac8d") -set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v1.0.21/objects.zip") +set(OBJECTS_VERSION "1.0.21") +set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v${OBJECTS_VERSION}/objects.zip") set(OBJECTS_SHA1 "c38af45d51a6e440386180feacf76c64720b6ac5") -set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v0.0.37/replays.zip") -set(REPLAYS_SHA1 "C31C299539EB86DA013AEE47C9B2B2F4609F52C4") +set(REPLAYS_VERSION "0.0.39") +set(REPLAYS_URL "https://github.com/OpenRCT2/replays/releases/download/v${REPLAYS_VERSION}/replays.zip") +set(REPLAYS_SHA1 "8AF797661D87394FBE1A059375D82632094290FB") option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.") option(WITH_TESTS "Build tests") @@ -59,7 +62,10 @@ option(DOWNLOAD_TITLE_SEQUENCES "Download title sequences during installation." option(DOWNLOAD_OBJECTS "Download objects during installation." ON) CMAKE_DEPENDENT_OPTION(DOWNLOAD_REPLAYS "Download replays during installation." ON "WITH_TESTS" OFF) -option(MACOS_USE_DEPENDENCIES "Use OpenRCT2 dependencies instead of system libraries" ON) +CMAKE_DEPENDENT_OPTION(MACOS_USE_DEPENDENCIES "Use OpenRCT2 dependencies instead of system libraries" ON + "APPLE" OFF) +CMAKE_DEPENDENT_OPTION(MACOS_BUNDLE "Build macOS application bundle (OpenRCT2.app)" ON + "MACOS_USE_DEPENDENCIES; NOT DISABLE_GUI" OFF) # Options option(STATIC "Create a static build.") @@ -100,52 +106,41 @@ if (APPIMAGE) set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib") endif () -if (APPLE AND MACOS_USE_DEPENDENCIES) +if (MACOS_USE_DEPENDENCIES) # if we're building on macOS, then we need the dependencies - # update dylibs + include(cmake/download.cmake) + set(MACOS_DYLIBS_VERSION "28") set(MACOS_DYLIBS_ZIPFILE "openrct2-libs-v${MACOS_DYLIBS_VERSION}-x64-macos-dylibs.zip") + set(MACOS_DYLIBS_SHA1 "29e5480376cf4ac5943f114387e32685204c8b78") set(MACOS_DYLIBS_DIR "${ROOT_DIR}/lib/macos") set(MACOS_DYLIBS_URL "https://github.com/OpenRCT2/Dependencies/releases/download/v${MACOS_DYLIBS_VERSION}/${MACOS_DYLIBS_ZIPFILE}") - if (NOT EXISTS ${MACOS_DYLIBS_DIR}) - set(DOWNLOAD_DYLIBS 1) - else () - file(READ "${MACOS_DYLIBS_DIR}/libversion" MACOS_DYLIBS_CACHED_VERSION) - if (NOT ${MACOS_DYLIBS_CACHED_VERSION} STREQUAL ${MACOS_DYLIBS_VERSION}) - message("Cached macOS dylibs out of date") - set(DOWNLOAD_DYLIBS 1) - endif () - endif () - if (DOWNLOAD_DYLIBS) - message("Downloading macOS dylibs") - file(DOWNLOAD "${MACOS_DYLIBS_URL}" "${MACOS_DYLIBS_DIR}/${MACOS_DYLIBS_ZIPFILE}") - file(ARCHIVE_EXTRACT - INPUT "${MACOS_DYLIBS_DIR}/${MACOS_DYLIBS_ZIPFILE}" - DESTINATION "${MACOS_DYLIBS_DIR}" - ) - file(WRITE - "${MACOS_DYLIBS_DIR}/libversion" - "${MACOS_DYLIBS_VERSION}" - ) - file(REMOVE "${MACOS_DYLIBS_DIR}/${MACOS_DYLIBS_ZIPFILE}") - endif () - # TODO: make the above routine a function, use it for objects, title sequences, and languages + download_openrct2_zip( + ZIP_VERSION ${MACOS_DYLIBS_VERSION} + DOWNLOAD_DIR ${MACOS_DYLIBS_DIR} + ZIP_URL ${MACOS_DYLIBS_URL} + SHA1 ${MACOS_DYLIBS_SHA1} + ) set(CMAKE_MACOSX_RPATH 1) list(APPEND CMAKE_PREFIX_PATH "${MACOS_DYLIBS_DIR}") - # the RPATH to be used when installing, but only if it's not a system directory - list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) - if("${isSystemDir}" STREQUAL "-1") - set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") - endif("${isSystemDir}" STREQUAL "-1") + # if we're making the OpenRCT2.app bundle, rpath will be handled by fixup_bundle + # if we're building the CLI executable, we need to do it ourselves + if (NOT MACOS_BUNDLE) + # the RPATH to be used when installing, but only if it's not a system directory + list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) + if("${isSystemDir}" STREQUAL "-1") + set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") + endif("${isSystemDir}" STREQUAL "-1") - # if the DESTDIR env var is defined, use it in the install RPATH - if(DEFINED ENV{DESTDIR}) - get_filename_component(destdirRealPath "$ENV{DESTDIR}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") - set(CMAKE_INSTALL_RPATH "${destdirRealPath}${CMAKE_INSTALL_PREFIX}/lib") - endif() + # if the DESTDIR env var is defined, use it in the install RPATH + if(DEFINED ENV{DESTDIR}) + get_filename_component(destdirRealPath "$ENV{DESTDIR}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") + set(CMAKE_INSTALL_RPATH "${destdirRealPath}${CMAKE_INSTALL_PREFIX}/lib") + endif() + endif () endif () # LIST of supported flags, use SET_CHECK_CXX_FLAGS() to apply to target. @@ -213,7 +208,7 @@ if (NOT DISABLE_DISCORD_RPC) add_definitions(-D__ENABLE_DISCORD__) include_directories(DISCORDRPC_PROCESS_INCLUDES) endif() - elseif (APPLE AND MACOS_USE_DEPENDENCIES) + elseif (MACOS_USE_DEPENDENCIES) find_package(discordrpc CONFIG REQUIRED) if(${DISCORDRPC_FOUND}) add_definitions(-D__ENABLE_DISCORD__) @@ -390,80 +385,89 @@ if (WITH_TESTS) include("${ROOT_DIR}/test/tests/CMakeLists.txt" NO_POLICY_SCOPE) endif () -# Install -# Don't recurse, grab all *.txt and *.md files -file(GLOB DOC_FILES "${ROOT_DIR}/distribution/*.txt") -list(APPEND DOC_FILES "${ROOT_DIR}/contributors.md" - "${ROOT_DIR}/licence.txt" - "${ROOT_DIR}/distribution/scripting.md" - "${ROOT_DIR}/distribution/openrct2.d.ts") +# macOS bundle "install" is handled in src/openrct2-ui/CMakeLists.txt +# This is because the openrct2 target is modified (and that is where that target is defined) +if (NOT MACOS_BUNDLE OR (MACOS_BUNDLE AND WITH_TESTS)) + # Install + # Don't recurse, grab all *.txt and *.md files + file(GLOB DOC_FILES "${ROOT_DIR}/distribution/*.txt") + list(APPEND DOC_FILES "${ROOT_DIR}/contributors.md" + "${ROOT_DIR}/licence.txt" + "${ROOT_DIR}/distribution/scripting.md" + "${ROOT_DIR}/distribution/openrct2.d.ts") -# CMake does not allow specifying a dependency chain which includes built-in -# targets, like `install`, so we have to trick it and execute dependency ourselves. -install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" --build \"${CMAKE_CURRENT_BINARY_DIR}\" --target g2)") -if (DOWNLOAD_TITLE_SEQUENCES) - # If openrct2.parkseq or data/sequence/ exists, assume all the title sequences are already present - install(CODE - "if (EXISTS \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}/sequence/openrct2.parkseq\" OR EXISTS ${CMAKE_SOURCE_DIR}/data/sequence/)\n\ - message(\"Using cached title sequences\")\n\ - else () \n\ - file(DOWNLOAD ${TITLE_SEQUENCE_URL} \$ENV{DESTDIR}${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}/sequence/title-sequences.zip EXPECTED_HASH SHA1=${TITLE_SEQUENCE_SHA1} SHOW_PROGRESS)\n\ - execute_process(COMMAND \"${CMAKE_COMMAND}\" -E chdir \$ENV{DESTDIR}${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}/sequence/ \"${CMAKE_COMMAND}\" -E tar xf title-sequences.zip)\n\ - file(REMOVE \$ENV{DESTDIR}${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}/sequence/title-sequences.zip)\n\ - endif ()") -endif () -if (DOWNLOAD_OBJECTS) - # If rct2.wtrcyan.json or data/object/ exists, assume all the objects are already present - install(CODE - "if (EXISTS \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}/object/rct2/water/rct2.wtrcyan.json\" OR EXISTS ${CMAKE_SOURCE_DIR}/data/object/)\n\ - message(\"Using cached objects\")\n\ - else () \n\ - file(DOWNLOAD ${OBJECTS_URL} \$ENV{DESTDIR}${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}/object/objects.zip EXPECTED_HASH SHA1=${OBJECTS_SHA1} SHOW_PROGRESS)\n\ - execute_process(COMMAND \"${CMAKE_COMMAND}\" -E chdir \$ENV{DESTDIR}${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}/object/ \"${CMAKE_COMMAND}\" -E tar xf objects.zip)\n\ - file(REMOVE \$ENV{DESTDIR}${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}/object/objects.zip)\n\ - endif ()") -endif () -if (DOWNLOAD_REPLAYS) - install(CODE - "if (EXISTS \${CMAKE_CURRENT_BINARY_DIR}/testdata/replays/)\n\ - message(\"Using cached replays\")\n\ - else () \n\ - file(DOWNLOAD ${REPLAYS_URL} \${CMAKE_CURRENT_BINARY_DIR}/testdata/replays/replays.zip EXPECTED_HASH SHA1=${REPLAYS_SHA1} SHOW_PROGRESS)\n\ - execute_process(COMMAND \"${CMAKE_COMMAND}\" -E chdir \${CMAKE_CURRENT_BINARY_DIR}/testdata/replays/ \"${CMAKE_COMMAND}\" -E tar xf replays.zip)\n\ - file(REMOVE \${CMAKE_CURRENT_BINARY_DIR}/testdata/replays/replays.zip)\n\ - endif ()") -endif () -install(TARGETS "libopenrct2" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}") -if(NOT DISABLE_GUI) - install(TARGETS "openrct2" RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") -endif() -install(TARGETS "openrct2-cli" OPTIONAL RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/g2.dat" DESTINATION "${CMAKE_INSTALL_DATADIR}/openrct2") -install(DIRECTORY "data/" DESTINATION "${CMAKE_INSTALL_DATADIR}/openrct2") -install(FILES ${DOC_FILES} DESTINATION "${CMAKE_INSTALL_DOCDIR}") -install(FILES "distribution/linux/openrct2.appdata.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo") -if (NOT DISABLE_GUI) - install(FILES "resources/logo/icon_x16.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/16x16/apps" RENAME "openrct2.png") - install(FILES "resources/logo/icon_x24.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/24x24/apps" RENAME "openrct2.png") - install(FILES "resources/logo/icon_x32.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/32x32/apps" RENAME "openrct2.png") - install(FILES "resources/logo/icon_x48.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps" RENAME "openrct2.png") - install(FILES "resources/logo/icon_x64.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/64x64/apps" RENAME "openrct2.png") - install(FILES "resources/logo/icon_x96.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/96x96/apps" RENAME "openrct2.png") - install(FILES "resources/logo/icon_x128.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/128x128/apps" RENAME "openrct2.png") - install(FILES "resources/logo/icon_x256.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps" RENAME "openrct2.png") - install(FILES "resources/logo/icon_flag.svg" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps" RENAME "openrct2.svg") - install(FILES "distribution/linux/openrct2.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications") - install(FILES "distribution/linux/openrct2-savegame.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications") - install(FILES "distribution/linux/openrct2-scenario.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications") - install(FILES "distribution/linux/openrct2-uri.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications") -endif() -install(FILES "distribution/linux/openrct2-mimeinfo.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/mime/packages/" RENAME "openrct2.xml") -install(DIRECTORY "distribution/man/" DESTINATION "${CMAKE_INSTALL_MANDIR}/man6" FILES_MATCHING PATTERN "*.6") + # CMake does not allow specifying a dependency chain which includes built-in + # targets, like `install`, so we have to trick it and execute dependency ourselves. + install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" --build \"${CMAKE_CURRENT_BINARY_DIR}\" --target g2)") + if (DOWNLOAD_TITLE_SEQUENCES) + # Checks if this version of the title sequences are already installed, updates if necessary + install(CODE " + include(${ROOT_DIR}/cmake/download.cmake) + download_openrct2_zip( + ZIP_VERSION ${TITLE_SEQUENCE_VERSION} + DOWNLOAD_DIR \$ENV{DESTDIR}${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}/sequence/ + ZIP_URL ${TITLE_SEQUENCE_URL} + SHA1 ${TITLE_SEQUENCE_SHA1} + )") + endif () + if (DOWNLOAD_OBJECTS) + # Checks if this version of the objects are already installed, updates if necessary + install(CODE " + include(${ROOT_DIR}/cmake/download.cmake) + download_openrct2_zip( + ZIP_VERSION ${OBJECTS_VERSION} + DOWNLOAD_DIR \$ENV{DESTDIR}${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}/object/ + ZIP_URL ${OBJECTS_URL} + SHA1 ${OBJECTS_SHA1} + )") + endif () + if (DOWNLOAD_REPLAYS) + # Checks if this version of the replays are already installed, updates if necessary + install(CODE " + include(${ROOT_DIR}/cmake/download.cmake) + download_openrct2_zip( + ZIP_VERSION ${REPLAYS_VERSION} + DOWNLOAD_DIR \${CMAKE_CURRENT_BINARY_DIR}/testdata/replays/ + ZIP_URL ${REPLAYS_URL} + SHA1 ${REPLAYS_SHA1} + )") + endif () + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/g2.dat" DESTINATION "${CMAKE_INSTALL_DATADIR}/openrct2") + install(DIRECTORY "data/" DESTINATION "${CMAKE_INSTALL_DATADIR}/openrct2") -if (APPLE AND MACOS_USE_DEPENDENCIES) - # Note: dependencies may have the same names as system installed libraries - # (via homebrew). A local CMAKE_INSTALL_PREFIX is recommended to avoid issues - file(GLOB DYLIB_FILES "${MACOS_DYLIBS_DIR}/lib/*.dylib") - install(FILES ${DYLIB_FILES} DESTINATION "${CMAKE_INSTALL_LIBDIR}") + # even when building WITH_TESTS, none of the below install steps are required for OpenRCT2.app + if (NOT MACOS_BUNDLE) + install(TARGETS "libopenrct2" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}") + if(NOT DISABLE_GUI) + install(TARGETS "openrct2" RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") + endif() + install(TARGETS "openrct2-cli" OPTIONAL RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") + install(FILES ${DOC_FILES} DESTINATION "${CMAKE_INSTALL_DOCDIR}") + install(FILES "distribution/linux/openrct2.appdata.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo") + if (NOT DISABLE_GUI) + install(FILES "resources/logo/icon_x16.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/16x16/apps" RENAME "openrct2.png") + install(FILES "resources/logo/icon_x24.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/24x24/apps" RENAME "openrct2.png") + install(FILES "resources/logo/icon_x32.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/32x32/apps" RENAME "openrct2.png") + install(FILES "resources/logo/icon_x48.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps" RENAME "openrct2.png") + install(FILES "resources/logo/icon_x64.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/64x64/apps" RENAME "openrct2.png") + install(FILES "resources/logo/icon_x96.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/96x96/apps" RENAME "openrct2.png") + install(FILES "resources/logo/icon_x128.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/128x128/apps" RENAME "openrct2.png") + install(FILES "resources/logo/icon_x256.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps" RENAME "openrct2.png") + install(FILES "resources/logo/icon_flag.svg" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps" RENAME "openrct2.svg") + install(FILES "distribution/linux/openrct2.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications") + install(FILES "distribution/linux/openrct2-savegame.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications") + install(FILES "distribution/linux/openrct2-scenario.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications") + install(FILES "distribution/linux/openrct2-uri.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications") + endif() + install(FILES "distribution/linux/openrct2-mimeinfo.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/mime/packages/" RENAME "openrct2.xml") + install(DIRECTORY "distribution/man/" DESTINATION "${CMAKE_INSTALL_MANDIR}/man6" FILES_MATCHING PATTERN "*.6") + + if (MACOS_USE_DEPENDENCIES) + # Note: dependencies may have the same names as system installed libraries + # (via homebrew). A local CMAKE_INSTALL_PREFIX is recommended to avoid issues + file(GLOB DYLIB_FILES "${MACOS_DYLIBS_DIR}/lib/*.dylib") + install(FILES ${DYLIB_FILES} DESTINATION "${CMAKE_INSTALL_LIBDIR}") + endif() + endif() endif() diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index e03ce30675..e03f799fe0 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -3607,7 +3607,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "version=\"1.0.20\"\nzipname=\"objects.zip\"\nliburl=\"https://github.com/OpenRCT2/objects/releases/download/v$version/$zipname\"\n\n[[ ! -d \"${SRCROOT}/data/object\" || ! -e \"${SRCROOT}/objectsversion\" || $(head -n 1 \"${SRCROOT}/objectsversion\") != $version ]]\noutdated=$?\n\nif [[ $outdated -eq 0 ]]; then\nif [[ -d \"${SRCROOT}/data/object\" ]]; then rm -r \"${SRCROOT}/data/object\"; fi\nmkdir -p \"${SRCROOT}/data/object\"\n\ncurl -L -o \"${SRCROOT}/data/object/$zipname\" \"$liburl\"\nunzip -uaq -d \"${SRCROOT}/data/object\" \"${SRCROOT}/data/object/$zipname\"\nrm \"${SRCROOT}/data/object/$zipname\"\n\necho $version > \"${SRCROOT}/objectsversion\"\nfi\n"; + shellScript = "version=\"1.0.20\"\nzipname=\"objects.zip\"\nliburl=\"https://github.com/OpenRCT2/objects/releases/download/v$version/$zipname\"\n\n[[ ! -d \"${SRCROOT}/data/object\" || ! -e \"${SRCROOT}/objectsversion\" || $(head -n 1 \"${SRCROOT}/objectsversion\") != $version ]]\noutdated=$?\n\nif [[ $outdated -eq 0 ]]; then\nif [[ -d \"${SRCROOT}/data/object\" ]]; then rm -r \"${SRCROOT}/data/object\"; fi\nmkdir -p \"${SRCROOT}/data/object\"\n\ncurl -fLo \"${SRCROOT}/data/object/$zipname\" \"$liburl\"\nunzip -uaq -d \"${SRCROOT}/data/object\" \"${SRCROOT}/data/object/$zipname\"\nrm \"${SRCROOT}/data/object/$zipname\"\n\necho $version > \"${SRCROOT}/objectsversion\"\nfi\n"; }; C68B2D471EC790710020651C /* Download Libraries */ = { isa = PBXShellScriptBuildPhase; @@ -3621,7 +3621,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "version=\"28\"\nzipname=\"openrct2-libs-v28-x64-macos-dylibs.zip\"\nliburl=\"https://github.com/OpenRCT2/Dependencies/releases/download/v$version/$zipname\"\n\n[[ ! -d \"${SRCROOT}/libxc\" || ! -e \"${SRCROOT}/libversion\" || $(head -n 1 \"${SRCROOT}/libversion\") != $version ]]\noutdated=$?\n\nif [[ $outdated -eq 0 ]]; then\nif [[ -d \"${SRCROOT}/libxc\" ]]; then rm -r \"${SRCROOT}/libxc\"; fi\nmkdir \"${SRCROOT}/libxc\"\n\ncurl -L -o \"${SRCROOT}/libxc/$zipname\" \"$liburl\"\nunzip -uaq -d \"${SRCROOT}/libxc\" \"${SRCROOT}/libxc/$zipname\"\nrm \"${SRCROOT}/libxc/$zipname\"\n\necho $version > \"${SRCROOT}/libversion\"\nfi\n"; + shellScript = "version=\"28\"\nzipname=\"openrct2-libs-v28-x64-macos-dylibs.zip\"\nliburl=\"https://github.com/OpenRCT2/Dependencies/releases/download/v$version/$zipname\"\n\n[[ ! -d \"${SRCROOT}/libxc\" || ! -e \"${SRCROOT}/libversion\" || $(head -n 1 \"${SRCROOT}/libversion\") != $version ]]\noutdated=$?\n\nif [[ $outdated -eq 0 ]]; then\nif [[ -d \"${SRCROOT}/libxc\" ]]; then rm -r \"${SRCROOT}/libxc\"; fi\nmkdir \"${SRCROOT}/libxc\"\n\ncurl -fLo \"${SRCROOT}/libxc/$zipname\" \"$liburl\"\nunzip -uaq -d \"${SRCROOT}/libxc\" \"${SRCROOT}/libxc/$zipname\"\nrm \"${SRCROOT}/libxc/$zipname\"\n\necho $version > \"${SRCROOT}/libversion\"\nfi\n"; }; D42C09D21C254F4E00309751 /* Build g2.dat */ = { isa = PBXShellScriptBuildPhase; @@ -3668,7 +3668,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "version=\"0.1.2c\"\nzipname=\"title-sequences.zip\"\nliburl=\"https://github.com/OpenRCT2/title-sequences/releases/download/v$version/$zipname\"\n\n[[ ! -d \"${SRCROOT}/data/sequence\" || ! -e \"${SRCROOT}/sequencesversion\" || $(head -n 1 \"${SRCROOT}/sequencesversion\") != $version ]]\noutdated=$?\n\nif [[ $outdated -eq 0 ]]; then\nif [[ -d \"${SRCROOT}/data/sequence\" ]]; then rm -r \"${SRCROOT}/data/sequence\"; fi\nmkdir -p \"${SRCROOT}/data/sequence\"\n\ncurl -L -o \"${SRCROOT}/data/sequence/$zipname\" \"$liburl\"\nunzip -uaq -d \"${SRCROOT}/data/sequence\" \"${SRCROOT}/data/sequence/$zipname\"\nrm \"${SRCROOT}/data/sequence/$zipname\"\n\necho $version > \"${SRCROOT}/sequencesversion\"\nfi\n"; + shellScript = "version=\"0.1.2c\"\nzipname=\"title-sequences.zip\"\nliburl=\"https://github.com/OpenRCT2/title-sequences/releases/download/v$version/$zipname\"\n\n[[ ! -d \"${SRCROOT}/data/sequence\" || ! -e \"${SRCROOT}/sequencesversion\" || $(head -n 1 \"${SRCROOT}/sequencesversion\") != $version ]]\noutdated=$?\n\nif [[ $outdated -eq 0 ]]; then\nif [[ -d \"${SRCROOT}/data/sequence\" ]]; then rm -r \"${SRCROOT}/data/sequence\"; fi\nmkdir -p \"${SRCROOT}/data/sequence\"\n\ncurl -fLo \"${SRCROOT}/data/sequence/$zipname\" \"$liburl\"\nunzip -uaq -d \"${SRCROOT}/data/sequence\" \"${SRCROOT}/data/sequence/$zipname\"\nrm \"${SRCROOT}/data/sequence/$zipname\"\n\necho $version > \"${SRCROOT}/sequencesversion\"\nfi\n"; }; F76C809F1EC4DB0300FA49E2 /* Get Git Variables */ = { isa = PBXShellScriptBuildPhase; diff --git a/cmake/download.cmake b/cmake/download.cmake new file mode 100644 index 0000000000..33ec3635bf --- /dev/null +++ b/cmake/download.cmake @@ -0,0 +1,41 @@ +function(download_openrct2_zip) + set(oneValueArgs ZIP_VERSION DOWNLOAD_DIR ZIP_URL SHA1) + cmake_parse_arguments(DOWNLOAD_OPENRCT2 "${options}" "${oneValueArgs}" + "${multiValueArgs}" ${ARGN} ) + + get_filename_component(ZIP_FILE_NAME ${DOWNLOAD_OPENRCT2_ZIP_URL} NAME) + + if (NOT EXISTS ${DOWNLOAD_OPENRCT2_DOWNLOAD_DIR}) + set(DOWNLOAD_ZIP 1) + else () + if (EXISTS "${DOWNLOAD_OPENRCT2_DOWNLOAD_DIR}/zipversion") + file(READ "${DOWNLOAD_OPENRCT2_DOWNLOAD_DIR}/zipversion" DOWNLOAD_OPENRCT2_CACHED_VERSION) + if (NOT ${DOWNLOAD_OPENRCT2_CACHED_VERSION} STREQUAL ${DOWNLOAD_OPENRCT2_ZIP_VERSION}) + message("Cache ${DOWNLOAD_OPENRCT2_DOWNLOAD_DIR} not up to date") + set(DOWNLOAD_ZIP 1) + endif () + else () + set(DOWNLOAD_ZIP 1) + endif () + endif () + if (DOWNLOAD_ZIP) + message("Downloading ${DOWNLOAD_OPENRCT2_DOWNLOAD_DIR}") + file(DOWNLOAD + "${DOWNLOAD_OPENRCT2_ZIP_URL}" "${DOWNLOAD_OPENRCT2_DOWNLOAD_DIR}/${ZIP_FILE_NAME}" + EXPECTED_HASH SHA1=${DOWNLOAD_OPENRCT2_SHA1} SHOW_PROGRESS) + if(${CMAKE_VERSION} VERSION_LESS "3.18.0") + execute_process(COMMAND ${CMAKE_COMMAND} -E chdir ${DOWNLOAD_OPENRCT2_DOWNLOAD_DIR} ${CMAKE_COMMAND} -E tar xf ${ZIP_FILE_NAME}) + else() + file(ARCHIVE_EXTRACT + INPUT "${DOWNLOAD_OPENRCT2_DOWNLOAD_DIR}/${ZIP_FILE_NAME}" + DESTINATION "${DOWNLOAD_OPENRCT2_DOWNLOAD_DIR}" + ) + endif() + file(WRITE + "${DOWNLOAD_OPENRCT2_DOWNLOAD_DIR}/zipversion" + "${DOWNLOAD_OPENRCT2_ZIP_VERSION}" + ) + file(REMOVE "${DOWNLOAD_OPENRCT2_DOWNLOAD_DIR}/${ZIP_FILE_NAME}") + endif () + +endfunction () diff --git a/data/shaders/drawline.vert b/data/shaders/drawline.vert index 2faf19dc2a..dea6af7f47 100644 --- a/data/shaders/drawline.vert +++ b/data/shaders/drawline.vert @@ -16,12 +16,12 @@ flat out uint fColour; void main() { - vec2 pos = clamp(vVertMat * vBounds, vClip.xy, vClip.zw); + vec2 pos = clamp(vVertMat * vec4(vBounds), vec2(vClip.xy), vec2(vClip.zw)); // Transform screen coordinates to viewport coordinates - pos = (pos * (2.0 / uScreenSize)) - 1.0; - pos.y *= -1; - float depth = 1.0 - (vDepth + 1) * DEPTH_INCREMENT; + pos = (pos * (2.0 / vec2(uScreenSize))) - 1.0; + pos.y *= -1.0; + float depth = 1.0 - (float(vDepth) + 1.0) * DEPTH_INCREMENT; fColour = vColour; diff --git a/data/shaders/drawrect.vert b/data/shaders/drawrect.vert index b752f364dc..6c1e0a9be7 100644 --- a/data/shaders/drawrect.vert +++ b/data/shaders/drawrect.vert @@ -30,16 +30,16 @@ flat out vec3 fPalettes; void main() { // Clamp position by vClip, correcting interpolated values for the clipping - vec2 m = clamp(((vVertMat * vClip) - (vVertMat * vBounds))/(vBounds.zw - vBounds.xy) + vVertVec, 0.0, 1.0); - vec2 pos = mix(vBounds.xy, vBounds.zw, m); + vec2 m = clamp(((vVertMat * vec4(vClip)) - (vVertMat * vec4(vBounds)))/vec2(vBounds.zw - vBounds.xy) + vVertVec, 0.0, 1.0); + vec2 pos = mix(vec2(vBounds.xy), vec2(vBounds.zw), m); fTexColour = vec3(mix(vTexColourBounds.xy, vTexColourBounds.zw, m), vTexColourAtlas); fTexMask = vec3(mix(vTexMaskBounds.xy, vTexMaskBounds.zw, m), vTexMaskAtlas); fPosition = pos; // Transform screen coordinates to texture coordinates - float depth = 1.0 - (vDepth + 1) * DEPTH_INCREMENT; - pos = pos / uScreenSize; + float depth = 1.0 - (float(vDepth) + 1.0) * DEPTH_INCREMENT; + pos = pos / vec2(uScreenSize); pos.y = pos.y * -1.0 + 1.0; fPeelPos = vec3(pos, depth * 0.5 + 0.5); diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 4a2928af94..cc11962863 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -3,11 +3,13 @@ - Feature: [#13967] Track List window now displays the path to the design when debugging tools are on. - Feature: [#14071] “Vandals stopped” statistic for security guards. - Feature: [#14296] Allow using early scenario completion in multiplayer. +- Change: [#14496] [Plugin] Rename Object to LoadedObject to fix conflicts with Typescript's Object interface. - Fix: [#11829] Visual glitches and crashes when using RCT1 assets from mismatched or corrupt CSG1.DAT and CSG1i.DAT files. - Fix: [#13581] Opening the Options menu causes a noticeable drop in FPS. - Fix: [#13894] Block brakes do not animate. - Fix: [#14315] Crash when trying to rename Air Powered Vertical Coaster in Korean. - Fix: [#14330] join_server uses default_port from config. +- Fix: [#14493] [Plugin] isHidden only works for tile elements up to the first element with a base height of over 32. 0.3.3 (2021-03-13) ------------------------------------------------------------------------ diff --git a/distribution/macos/Info.plist b/distribution/macos/Info.plist index 800f356eaa..f7fd4c88c5 100644 --- a/distribution/macos/Info.plist +++ b/distribution/macos/Info.plist @@ -3,13 +3,13 @@ CFBundleExecutable - $(EXECUTABLE_NAME) + ${EXECUTABLE_NAME} CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) + ${PRODUCT_BUNDLE_IDENTIFIER} CFBundleInfoDictionaryVersion 6.0 CFBundleName - $(PRODUCT_NAME) + ${PRODUCT_NAME} CFBundlePackageType APPL CFBundleShortVersionString @@ -17,7 +17,7 @@ CFBundleSignature ORCT LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) + ${MACOSX_DEPLOYMENT_TARGET} NSHumanReadableCopyright OpenRCT2 is licensed under the GNU General Public License version 3 CFBundleAllowMixedLocalizations diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index be6b219c94..ee736431ff 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -186,11 +186,11 @@ declare global { * @param type The object type. * @param index The index. */ - getObject(type: ObjectType, index: number): Object; + getObject(type: ObjectType, index: number): LoadedObject; getObject(type: "ride", index: number): RideObject; getObject(type: "small_scenery", index: number): SmallSceneryObject; - getAllObjects(type: ObjectType): Object[]; + getAllObjects(type: ObjectType): LoadedObject[]; getAllObjects(type: "ride"): RideObject[]; /** @@ -729,7 +729,7 @@ declare global { /** * Represents the definition of a loaded object (.DAT or .json) such a ride type or scenery item. */ - interface Object { + interface LoadedObject { /** * The object type. */ @@ -762,7 +762,7 @@ declare global { /** * Represents the object definition of a ride or stall. */ - interface RideObject extends Object { + interface RideObject extends LoadedObject { /** * The description of the ride / stall in the player's current language. */ @@ -845,7 +845,7 @@ declare global { /** * Represents the object definition of a small scenery item such a tree. */ - interface SmallSceneryObject extends Object { + interface SmallSceneryObject extends LoadedObject { /** * Raw bit flags that describe characteristics of the scenery item. */ diff --git a/openrct2.proj b/openrct2.proj index 365a794c31..11be434fc9 100644 --- a/openrct2.proj +++ b/openrct2.proj @@ -48,8 +48,8 @@ 304d13a126c15bf2c86ff13b81a2f2cc1856ac8d https://github.com/OpenRCT2/objects/releases/download/v1.0.21/objects.zip c38af45d51a6e440386180feacf76c64720b6ac5 - https://github.com/OpenRCT2/replays/releases/download/v0.0.37/replays.zip - C31C299539EB86DA013AEE47C9B2B2F4609F52C4 + https://github.com/OpenRCT2/replays/releases/download/v0.0.39/replays.zip + 8AF797661D87394FBE1A059375D82632094290FB diff --git a/scripts/build b/scripts/build index 160d7c331b..9274410488 100755 --- a/scripts/build +++ b/scripts/build @@ -1,5 +1,4 @@ -#!/bin/bash -set -e +#!/bin/bash -e # Ensure we are in root directory if [[ $(uname) == "Darwin" ]]; then diff --git a/scripts/build-appimage b/scripts/build-appimage index 498706c5ba..0bc94c9a14 100755 --- a/scripts/build-appimage +++ b/scripts/build-appimage @@ -1,5 +1,4 @@ -#!/bin/bash -set -e +#!/bin/bash -e echo -e "\033[0;36mBuilding AppImage for OpenRCT2...\033[0m" @@ -8,7 +7,7 @@ basedir="$(readlink -f `dirname $0`/..)" cd $basedir linuxdeploy=/tmp/linuxdeploy-x86_64.AppImage -curl -Lo $linuxdeploy https://github.com/TheAssassin/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage +curl -fLo $linuxdeploy https://github.com/TheAssassin/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage chmod +x $linuxdeploy pushd bin $linuxdeploy --appimage-extract-and-run --appdir install/ --output appimage --desktop-file install/usr/share/applications/openrct2.desktop diff --git a/scripts/build-installer b/scripts/build-installer index 49101bf4a5..2f2fb5adff 100755 --- a/scripts/build-installer +++ b/scripts/build-installer @@ -1,5 +1,5 @@ -#!/bin/bash -set -e +#!/bin/bash -e + if [[ "$#" -gt 2 || "$1" == "-h" ]]; then echo 'Create a Windows installer for OpenRCT2' echo '' diff --git a/scripts/build-portable b/scripts/build-portable index d1180b9dd5..bd4460cfa1 100755 --- a/scripts/build-portable +++ b/scripts/build-portable @@ -1,5 +1,4 @@ -#!/bin/bash -set -e +#!/bin/bash -e if [[ "$OSTYPE" == "cygwin" || "$OSTYPE" == "msys" ]]; then # Create a Windows symbols archive for OpenRCT2 diff --git a/scripts/build-symbols b/scripts/build-symbols index d3e28e446b..5fede436c6 100755 --- a/scripts/build-symbols +++ b/scripts/build-symbols @@ -1,5 +1,14 @@ -#!/bin/bash -set -e +#!/bin/bash -e + +# Check 7z or zip is available +if [ -x "$(command -v 7z)" ]; then + archiver="7z a" +elif [ -x "$(command -v zip)" ]; then + archiver=zip +else + echo -e >&2 "\033[0;7z and zip not found\033[0m" + exit 1 +fi # Create a Windows symbols archive for OpenRCT2 basedir="$(readlink -f `dirname $0`/..)" @@ -7,17 +16,11 @@ cd $basedir/bin destination=../artifacts/openrct2-symbols-$CONFIGURATION-$PLATFORM.zip -# Check 7z is available -if ! [ -x "$(command -v 7z)" ]; then - echo -e >&2 "\033[0;7z not found\033[0m" - exit 1 -fi - echo -e "\033[0;36mCreating symbols archive for OpenRCT2...\033[0m" if [[ -f $destination ]]; then rm $destination fi -7z a $destination openrct2.exe openrct2.com openrct2-win.pdb +$archiver $destination openrct2.exe openrct2.com openrct2-win.pdb destination=$(cygpath -w $(readlink -f $destination)) printf '\033[0;32m%s\033[0m\n' "${destination} created successfully" diff --git a/scripts/check-code-formatting b/scripts/check-code-formatting index 04cc0e1a0d..86c2e64b22 100755 --- a/scripts/check-code-formatting +++ b/scripts/check-code-formatting @@ -1,5 +1,4 @@ -#!/bin/sh -set -e +#!/bin/sh -e readlink_bin='readlink' diff --git a/scripts/get-discord-rpc b/scripts/get-discord-rpc index 1305efacb2..cd785ff567 100755 --- a/scripts/get-discord-rpc +++ b/scripts/get-discord-rpc @@ -1,5 +1,5 @@ -#!/bin/bash -set -e +#!/bin/bash -e + if [[ $(uname) == "Linux" ]]; then basedir="$(readlink -f `dirname $0`/..)" elif [[ $(uname) == "Darwin" ]]; then @@ -10,5 +10,5 @@ else fi cd $basedir -git clone https://github.com/discordapp/discord-rpc -b v3.4.0 -git clone https://github.com/janisozaur/rapidjson discord-rpc/thirdparty/rapidjson -b patch-1 +git clone --depth 1 -b v3.4.0 https://github.com/discordapp/discord-rpc +git clone --depth 1 -b patch-1 https://github.com/janisozaur/rapidjson discord-rpc/thirdparty/rapidjson diff --git a/scripts/install-nsis b/scripts/install-nsis index 43a1ec2029..a31d6e3d18 100755 --- a/scripts/install-nsis +++ b/scripts/install-nsis @@ -1,5 +1,5 @@ -#!/bin/bash -set -e +#!/bin/bash -e + if [[ "$#" -ne 0 && "$#" -ne 2 ]]; then echo 'Install a portable version of NSIS which can build the OpenRCT2 Windows installer.' echo '' @@ -11,7 +11,7 @@ fi if [[ "$1" == "-d" ]]; then echo -e "\033[0;36mDownloading prebuilt NSIS from GitHub...\033[0m" - curl -sLo nsis.zip "https://github.com/OpenRCT2/Dependencies/releases/download/v20/nsis.zip" + curl -sSfLO "https://github.com/OpenRCT2/Dependencies/releases/download/v20/nsis.zip" 7z -bd -y "-o$2" x nsis.zip rm nsis.zip echo -e "\033[0;32mNSIS downloaded, add "$2/bin" to PATH\033[0m" @@ -19,7 +19,7 @@ if [[ "$1" == "-d" ]]; then fi # Download NSIS with chocolatey and then download extra plugins -nsisdir="C:/ProgramData/chocolatey/lib/nsis.portable" +nsisdir="$ProgramData/chocolatey/lib/nsis.portable" if [[ -d $nsisdir ]] then echo -e "\033[0;36mNSIS already installed.\033[0m" @@ -30,13 +30,13 @@ echo -e "\033[0;36mDownloading NSIS from chocolatey...\033[0m" cinst nsis.portable --version=3.01-beta1 echo -e "\033[0;36mDownloading KillProcDLL for NSIS...\033[0m" -curl -sLo nsisxtra.zip "http://nsis.sourceforge.net/mediawiki/images/5/53/KillProcDll%26FindProcDll.zip" +curl -sSfLo nsisxtra.zip "http://nsis.sourceforge.net/mediawiki/images/5/53/KillProcDll%26FindProcDll.zip" 7z x nsisxtra.zip cp FindProcDLL.dll "$nsisdir/tools/nsis-3.0b1/Plugins/x86-ansi" echo -e "\033[0;36mDownloading UAC plugin for NSIS...\033[0m" -curl -sLo uac.zip "http://nsis.sourceforge.net/mediawiki/images/8/8f/UAC.zip" -7z x uac.zip +curl -sSfLO "http://nsis.sourceforge.net/mediawiki/images/8/8f/UAC.zip" +7z x UAC.zip cp UAC.nsh "$nsisdir/tools/nsis-3.0b1/Include" cp -r Plugins "$nsisdir/tools/nsis-3.0b1" diff --git a/scripts/linux/build-appimage-docker.sh b/scripts/linux/build-appimage-docker.sh index 8ac54e010a..cde760edf4 100755 --- a/scripts/linux/build-appimage-docker.sh +++ b/scripts/linux/build-appimage-docker.sh @@ -1,12 +1,10 @@ -#! /bin/bash - -set -ex +#!/bin/bash -ex REPO_ROOT=$(readlink -f $(dirname "$0")/../..) -docker run --rm -it -e NO_CLEANUP=1 -e CI=1 --device /dev/fuse:mrw -v $(readlink -f .):/ws openrct2/openrct2:ubuntu_amd64 bash -xc " +docker run --rm -it -e NO_CLEANUP=1 -e CI=1 --device /dev/fuse:mrw -v $(readlink -f .):/ws openrct2/openrct2:ubuntu_amd64 bash -exc " cd /ws apt-get update apt-get install -y wget libcairo2 -bash -xe scripts/linux/build-appimage.sh +scripts/linux/build-appimage.sh " diff --git a/scripts/linux/build-appimage.sh b/scripts/linux/build-appimage.sh index fd0da9511a..6d2b1529c7 100755 --- a/scripts/linux/build-appimage.sh +++ b/scripts/linux/build-appimage.sh @@ -1,7 +1,4 @@ -#! /bin/bash - -set -e -set -x +#!/bin/bash -ex # use RAM disk if possible if [ "$CI" == "" ] && [ -d /dev/shm ]; then @@ -18,7 +15,7 @@ cleanup () { fi } -[ "$NO_CLEANUP" == "" ] && trap cleanup EXIT +if [ "$NO_CLEANUP" == "" ] && trap cleanup EXIT # store repo root as variable REPO_ROOT=$(readlink -f $(dirname "$0")/../..) diff --git a/scripts/linux/build.sh b/scripts/linux/build.sh deleted file mode 100755 index bbc323b687..0000000000 --- a/scripts/linux/build.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/bash - -set -e - -if [[ $TRAVIS != "true" ]] -then - echo This script is only meant to be run on Travis-CI. - echo Please use CMake to build the project. - exit 1 -fi - -cachedir=.cache -mkdir -p $cachedir - -ci_env=`bash <(curl -s https://codecov.io/env)` - -# Sets default target to "linux", if none specified -TARGET=${TARGET-linux} - -if [[ ! -d build ]]; then - mkdir -p build -fi - -PARENT=$(readlink -f ./) -chmod -R a+rwX "$(pwd)" -chmod -R g+s "$(pwd)" - -pushd build - echo OPENRCT2_CMAKE_OPTS = "$OPENRCT2_CMAKE_OPTS" - if [[ $TARGET == "docker64" ]] - then - # CMAKE and MAKE opts from environment - docker run $ci_env -e CCACHE_DIR=/ccache -v $HOME/.ccache:/ccache -v "$PARENT":"$PARENT" -w "$PARENT"/build -i -t openrct2/openrct2:64bit-only bash -c "export PATH=/usr/lib/ccache/bin:\$PATH LD_PRELOAD=/usr/lib/libSegFault.so && ccache --show-stats > ccache_before && cmake ../ -DWITH_TESTS=on $OPENRCT2_CMAKE_OPTS && ninja all install $OPENRCT2_MAKE_OPTS && ccache --show-stats > ccache_after && ( diff -U100 ccache_before ccache_after || true ) && ./openrct2-cli scan-objects && ctest --output-on-failure && cd .. && bash <(curl -s https://codecov.io/bash) 2>\&1 | grep -v \"has arcs\"" - elif [[ $TARGET == "ubuntu_i686" ]] - then - # CMAKE and MAKE opts from environment - docker run $ci_env -e CCACHE_DIR=/ccache -v $HOME/.ccache:/ccache -v "$PARENT":"$PARENT" -w "$PARENT"/build -i -t openrct2/openrct2:ubuntu_i686 bash -c "export PATH=/usr/lib/ccache:\$PATH && ccache --show-stats > ccache_before && cmake ../ -DWITH_TESTS=on $OPENRCT2_CMAKE_OPTS && ninja all testpaint install $OPENRCT2_MAKE_OPTS && ccache --show-stats > ccache_after && ( diff -U100 ccache_before ccache_after || true ) && LD_PRELOAD=/lib/i386-linux-gnu/libSegFault.so ./openrct2-cli scan-objects && LD_PRELOAD=/lib/i386-linux-gnu/libSegFault.so ctest --output-on-failure && ( LD_PRELOAD=/lib/i386-linux-gnu/libSegFault.so ./testpaint --quiet || if [[ \$? -eq 1 ]] ; then echo Allowing failed tests to pass ; else echo here ; false; fi ) && cd .. && bash <(curl -s https://codecov.io/bash)" - elif [[ $TARGET == "ubuntu_amd64" ]] - then - # CMAKE and MAKE opts from environment - docker run $ci_env -e CCACHE_DIR=/ccache -v $HOME/.ccache:/ccache -v "$PARENT":"$PARENT" -w "$PARENT"/build -i -t openrct2/openrct2:ubuntu_amd64 bash -c "export PATH=/usr/lib/ccache:\$PATH LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so && ccache --show-stats > ccache_before && cmake ../ -DWITH_TESTS=on $OPENRCT2_CMAKE_OPTS && ninja $OPENRCT2_MAKE_OPTS install && ccache --show-stats > ccache_after && ( diff -U100 ccache_before ccache_after || true ) && ./openrct2-cli scan-objects && ctest --output-on-failure && cd .. && bash <(curl -s https://codecov.io/bash)" - elif [[ $TARGET == "windows" ]] - then - # CMAKE and MAKE opts from environment - docker run -v "$PARENT":"$PARENT" -w "$PARENT"/build -i -t openrct2/openrct2:mingw-arch bash -c "cmake ../ $OPENRCT2_CMAKE_OPTS && ninja $OPENRCT2_MAKE_OPTS" - else - echo "Unknown target $TARGET" - exit 1 - fi -popd - -if [[ $TARGET == "windows" ]]; then - if [[ ! -h openrct2.dll ]]; then - ln -s build/openrct2.dll openrct2.dll - fi -fi - -if [[ ! -h build/data ]]; then - ln -s ../data build/data -fi - -if [[ $TARGET == "ubuntu_i686" ]]; then - if [[ ! -h openrct2 ]]; then - ln -s build/openrct2 openrct2 - fi -fi - -if [[ -z "$DISABLE_G2_BUILD" ]]; then - echo Building: g2.dat - pushd build - ninja g2 - popd -fi - -if [[ $TARGET == "windows" ]]; then - if [[ -t 1 ]]; then - echo -e "\nDone! Run OpenRCT2 by typing:\n\n\033[95mwine openrct2.exe\n\033[0m" - else - echo -e "\nDone! Run OpenRCT2 by typing:\n\nwine openrct2.exe\n" - fi -else - if [[ -t 1 ]]; then - echo -e "\nDone! Run OpenRCT2 by typing:\n\n\033[95m./openrct2\n\033[0m" - else - echo -e "\nDone! Run OpenRCT2 by typing:\n\n./openrct2\n" - fi -fi diff --git a/scripts/linux/clean.sh b/scripts/linux/clean.sh deleted file mode 100755 index 91bf63302b..0000000000 --- a/scripts/linux/clean.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -ev - -if [[ $TRAVIS != "true" ]] -then - echo This script is only meant to be run on Travis-CI. - echo Please use CMake to build the project. - exit 1 -fi - - -sudo rm -rf /usr/local/cross-tools/i686-w64-mingw32 -sudo rm -rf /usr/local/cross-tools/orcalibs -sudo rm -rf /usr/local/cross-tools/orctlibs -rm -rf .cache -rm -rf build diff --git a/scripts/linux/install.sh b/scripts/linux/install.sh deleted file mode 100755 index 438fd0a7b0..0000000000 --- a/scripts/linux/install.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/bash - -if [[ $TRAVIS != "true" ]] -then - echo This script is only meant to be run on Travis-CI. - echo Please use CMake to build the project. - exit 1 -fi - -cachedir=.cache -if [[ $(uname -s) == "Darwin" ]]; then - liburl=https://openrct2.io/files/orctlibs-osx.zip -else - liburl=https://openrct2.io/files/orctlibs.zip -fi -mkdir -p "$cachedir" - -# Sets default target to "ubuntu_amd64", if none specified -TARGET=${TARGET-ubuntu_amd64} - -function has_cmd { - command -v "$1" >/dev/null 2>&1 -} - -function calculate_sha256 { - if has_cmd "shasum"; then - command shasum -a 256 "$1" | cut -f1 -d" " - elif has_cmd "sha256sum"; then - command sha256sum "$1" | cut -f1 -d" " - else - echo "Please install either sha256sum or shasum to continue" - exit 1 - fi -} - -function download { - if has_cmd "curl"; then - curl -L -o "$2" "$1" - elif has_cmd "wget"; then - wget -O "$2" "$1" - else - echo "Please install either wget or curl to continue" - exit 1 - fi -} - -function download_libs { - if [[ ! -f $cachedir/orctlibs.zip ]]; then - download $liburl $cachedir/orctlibs.zip; - fi - if [[ ! -d $cachedir/orctlibs ]]; then - mkdir -p $cachedir/orctlibs - pushd $cachedir/orctlibs - unzip -uaq ../orctlibs.zip - popd - fi -} - -function mac_os_install_mingw_32 { - local mingw_name="mingw-w32-bin_i686-darwin" - local mingw_tar="${mingw_name}_20130531.tar.bz2" - local mingw_path="/usr/local/$mingw_name" - - if [[ ! -f "$cachedir/$mingw_tar" ]]; then - download "https://downloads.sourceforge.net/project/mingw-w64/Toolchains targetting Win32/Automated Builds/$mingw_tar" "$cachedir/$mingw_tar" - fi - - if [[ ! -d "$mingw_path" ]]; then - echo "Extracting contents of $mingw_tar to $mingw_path" - echo "Don't forget to add $mingw_path/bin to your PATH variable!" - - mkdir "$mingw_path" - tar -xyf "$cachedir/$mingw_tar" -C "$mingw_path" - - pushd "$mingw_path" - find . -type d -exec chmod 755 {} \; - popd - fi -} - -echo "HOST = $(uname)" -echo "TARGET = $TARGET" - -if [[ "$(uname)" == "Darwin" ]]; then - if ! has_cmd "brew"; then - echo "Homebrew is not installed, or brew is not in your \$PATH" - echo "install instructions: http://brew.sh/" - exit 1 - fi - - brew install cmake - - if [[ $TARGET == "windows" ]]; then - brew install wine - mac_os_install_mingw_32 - else - brew install jansson sdl2 speex --universal - fi -elif [[ $(uname) == "Linux" ]]; then - # Clone discord-rpc for Discord's Rich Presence support - # Use tagged release to prevent upstream changes from breaking our code - git clone https://github.com/IntelOrca/discord-rpc -b fix/134-iothreadholder - # Use rapidjson with a hack for GCC 8, while awaiting a fix upstream: - # https://github.com/Tencent/rapidjson/issues/1205 - git clone https://github.com/janisozaur/rapidjson discord-rpc/thirdparty/rapidjson -b patch-1 - # prevent build.sh from re-doing all the steps again - case "$TARGET" in - "ubuntu_i686") - docker pull openrct2/openrct2:ubuntu_i686 - ;; - "ubuntu_amd64") - docker pull openrct2/openrct2:ubuntu_amd64 - ;; - "windows") - docker pull openrct2/openrct2:mingw-arch - ;; - "docker64") - docker pull openrct2/openrct2:64bit-only - ;; - *) - echo "unkown target $TARGET" - exit 1 - esac -fi - -if [[ $(uname -s) == "Darwin" ]]; then - download_libs - calculate_sha256 "$cachedir/orctlibs.zip" > "$libVFile" - echo "Downloaded library with sha256sum: $(cat "$libVFile")" - # Local libs are required for all targets -# $(uname -s) == "Darwin" -fi diff --git a/scripts/run-clang-format.py b/scripts/run-clang-format.py index 8f88bfc462..df3c498488 100755 --- a/scripts/run-clang-format.py +++ b/scripts/run-clang-format.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 + """A wrapper script around clang-format, suitable for linting multiple files and to use for continuous integration. diff --git a/scripts/run-testpaint b/scripts/run-testpaint index 479640a7ad..de0968afc3 100755 --- a/scripts/run-testpaint +++ b/scripts/run-testpaint @@ -1,5 +1,4 @@ -#!/bin/bash -set -e +#!/bin/bash -e # Ensure we are in root directory basedir="$(readlink -f `dirname $0`/..)" diff --git a/scripts/run-tests b/scripts/run-tests index a5cc969a77..e02f7d926b 100755 --- a/scripts/run-tests +++ b/scripts/run-tests @@ -1,5 +1,4 @@ -#!/bin/bash -set -e +#!/bin/bash -e # Ensure we are in root directory if [[ $(uname) == "Darwin" ]]; then @@ -11,7 +10,7 @@ cd $basedir/bin # Scan objects first so that does not happen within a test echo -e "\033[0;36mBuilding OpenRCT2 repository indexes...\033[0m" -./openrct2 scan-objects +./openrct2-cli scan-objects if [[ "$OSTYPE" == "cygwin" || "$OSTYPE" == "msys" ]]; then # Now run all the tests diff --git a/scripts/setenv b/scripts/setenv index b7791237e2..e34e5fd703 100755 --- a/scripts/setenv +++ b/scripts/setenv @@ -1,6 +1,6 @@ #!/bin/bash -# This sets up more environment variables using existing the environment +# This sets up more environment variables using the existing environment # It should be dot sourced into your environment if [[ "$GITHUB_ACTIONS" != "true" ]]; then export OPENRCT2_BUILD_SERVER=$(hostname) @@ -22,10 +22,10 @@ get_build_number() export OPENRCT2_BUILD=$(get_build_number) # Get the name of the branch and decide whether we should push the build to openrct2.org -export OPENRCT2_TAG= -export OPENRCT2_PUSH= +unset OPENRCT2_TAG +unset OPENRCT2_PUSH if [[ $GITHUB_REF == refs/tags/* ]]; then - export OPENRCT2_BRANCH= + unset OPENRCT2_BRANCH export OPENRCT2_TAG=true export OPENRCT2_PUSH=true else @@ -35,13 +35,13 @@ else fi fi if [[ "$OPENRCT2_ORG_TOKEN" == "" ]]; then - export OPENRCT2_PUSH= + unset OPENRCT2_PUSH fi # Get the short SHA1 export OPENRCT2_SHA1=$GITHUB_SHA export OPENRCT2_SHA1_SHORT=${OPENRCT2_SHA1:0:7} -export OPENRCT2_VERSION_EXTRA= +unset OPENRCT2_VERSION_EXTRA if [[ "$OPENRCT2_TAG" != "true" ]]; then export OPENRCT2_VERSION_EXTRA=$OPENRCT2_BRANCH-$OPENRCT2_SHA1_SHORT fi diff --git a/scripts/stats/count-rct-globals.php b/scripts/stats/count-rct-globals.php index ea04033d53..99ae2f901b 100755 --- a/scripts/stats/count-rct-globals.php +++ b/scripts/stats/count-rct-globals.php @@ -1,4 +1,5 @@ #!/usr/bin/env php + GetType() == TILE_ELEMENT_TYPE_BANNER) && (tileElement->AsBanner()->GetIndex() == number)) { - _tileElement = tileElement; + _bannerElement = tileElement->AsBanner(); return; } if (tileElement->IsLastForTile()) @@ -107,7 +107,7 @@ private: tileElement++; } } - _tileElement = nullptr; + _bannerElement = nullptr; } public: @@ -126,10 +126,10 @@ public: _banner = GetBanner(number); InitTileElement(); - if (_tileElement == nullptr) + if (_bannerElement == nullptr) return; - frame_no = _tileElement->GetBaseZ(); + frame_no = _bannerElement->GetBaseZ(); _bannerViewPos = CoordsXYZ{ _banner->position.ToCoordsXY().ToTileCentre(), frame_no }; CreateViewport(); } @@ -172,8 +172,11 @@ public: break; case WIDX_BANNER_DEMOLISH: { + if (_banner == nullptr || _bannerElement == nullptr) + break; + auto bannerRemoveAction = BannerRemoveAction( - { _banner->position.ToCoordsXY(), _tileElement->GetBaseZ(), _tileElement->AsBanner()->GetPosition() }); + { _banner->position.ToCoordsXY(), _bannerElement->GetBaseZ(), _bannerElement->GetPosition() }); GameActions::Execute(&bannerRemoveAction); break; } diff --git a/src/openrct2-ui/windows/EditorMain.cpp b/src/openrct2-ui/windows/EditorMain.cpp index ac93c5cf74..b7f22b4a62 100644 --- a/src/openrct2-ui/windows/EditorMain.cpp +++ b/src/openrct2-ui/windows/EditorMain.cpp @@ -48,7 +48,7 @@ rct_window* window_editor_main_open() gShowGridLinesRefCount = 0; gShowLandRightsRefCount = 0; gShowConstuctionRightsRefCount = 0; - gFootpathSelection = {}; + window_footpath_reset_selected_path(); context_open_window(WC_TOP_TOOLBAR); context_open_window_view(WV_EDITOR_BOTTOM_TOOLBAR); diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index f3b729e14c..24c75f3bc5 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -836,7 +836,8 @@ static void window_editor_object_selection_invalidate(rct_window* w) for (size_t i = 0; i < std::size(ObjectSelectionPages); i++) { auto widget = &w->widgets[WIDX_TAB_1 + i]; - if (!advancedMode && ObjectSelectionPages[i].IsAdvanced || ObjectSelectionPages[i].Image == SPR_NONE) + if ((!advancedMode && ObjectSelectionPages[i].IsAdvanced) + || ObjectSelectionPages[i].Image == static_cast(SPR_NONE)) { widget->type = WindowWidgetType::Empty; } diff --git a/src/openrct2-ui/windows/Finances.cpp b/src/openrct2-ui/windows/Finances.cpp index 650dfb284b..62db9b775d 100644 --- a/src/openrct2-ui/windows/Finances.cpp +++ b/src/openrct2-ui/windows/Finances.cpp @@ -733,7 +733,7 @@ static void window_finances_financial_graph_paint(rct_window* w, rct_drawpixelin continue; // Modifier balance then keep halving until less than 127 pixels - balance = abs(balance) >> yAxisScale; + balance = std::abs(balance) >> yAxisScale; while (balance > 127) { balance /= 2; @@ -836,7 +836,7 @@ static void window_finances_park_value_graph_paint(rct_window* w, rct_drawpixeli continue; // Modifier balance then keep halving until less than 255 pixels - balance = abs(balance) >> yAxisScale; + balance = std::abs(balance) >> yAxisScale; while (balance > 255) { balance /= 2; @@ -940,7 +940,7 @@ static void window_finances_profit_graph_paint(rct_window* w, rct_drawpixelinfo* continue; // Modifier balance then keep halving until less than 127 pixels - balance = abs(balance) >> yAxisScale; + balance = std::abs(balance) >> yAxisScale; while (balance > 127) { balance /= 2; diff --git a/src/openrct2-ui/windows/Footpath.cpp b/src/openrct2-ui/windows/Footpath.cpp index 493b1f86f2..c08835337b 100644 --- a/src/openrct2-ui/windows/Footpath.cpp +++ b/src/openrct2-ui/windows/Footpath.cpp @@ -35,6 +35,10 @@ static constexpr const int32_t WH = 421; static constexpr const int32_t WW = 106; static constexpr const uint16_t ARROW_PULSE_DURATION = 200; +static uint8_t _footpathConstructDirection; +static uint8_t _footpathConstructValidDirections; +static uint8_t _footpathConstructionMode; + static std::vector> _dropdownEntries; // clang-format off @@ -216,7 +220,7 @@ rct_window* window_footpath_open() show_gridlines(); tool_cancel(); - gFootpathConstructionMode = PATH_CONSTRUCTION_MODE_LAND; + _footpathConstructionMode = PATH_CONSTRUCTION_MODE_LAND; tool_set(window, WIDX_CONSTRUCT_ON_LAND, Tool::PathDown); input_set_flag(INPUT_FLAG_6, true); _footpathErrorOccured = false; @@ -257,7 +261,7 @@ static void window_footpath_mouseup(rct_window* w, rct_widgetindex widgetIndex) window_footpath_remove(); break; case WIDX_CONSTRUCT_ON_LAND: - if (gFootpathConstructionMode == PATH_CONSTRUCTION_MODE_LAND) + if (_footpathConstructionMode == PATH_CONSTRUCTION_MODE_LAND) { break; } @@ -267,14 +271,14 @@ static void window_footpath_mouseup(rct_window* w, rct_widgetindex widgetIndex) footpath_provisional_update(); map_invalidate_map_selection_tiles(); gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_CONSTRUCT; - gFootpathConstructionMode = PATH_CONSTRUCTION_MODE_LAND; + _footpathConstructionMode = PATH_CONSTRUCTION_MODE_LAND; tool_set(w, WIDX_CONSTRUCT_ON_LAND, Tool::PathDown); input_set_flag(INPUT_FLAG_6, true); _footpathErrorOccured = false; window_footpath_set_enabled_and_pressed_widgets(); break; case WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL: - if (gFootpathConstructionMode == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL_TOOL) + if (_footpathConstructionMode == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL_TOOL) { break; } @@ -284,7 +288,7 @@ static void window_footpath_mouseup(rct_window* w, rct_widgetindex widgetIndex) footpath_provisional_update(); map_invalidate_map_selection_tiles(); gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_CONSTRUCT; - gFootpathConstructionMode = PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL_TOOL; + _footpathConstructionMode = PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL_TOOL; tool_set(w, WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL, Tool::Crosshair); input_set_flag(INPUT_FLAG_6, true); _footpathErrorOccured = false; @@ -448,20 +452,20 @@ static void window_footpath_update_provisional_path_for_bridge_mode(rct_window* { int32_t slope; - if (gFootpathConstructionMode != PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL) + if (_footpathConstructionMode != PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL) { return; } // Recheck area for construction. Set by ride_construction window - if (gFootpathProvisionalFlags & PROVISIONAL_PATH_FLAG_2) + if (gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_2) { footpath_provisional_remove(); - gFootpathProvisionalFlags &= ~PROVISIONAL_PATH_FLAG_2; + gProvisionalFootpath.Flags &= ~PROVISIONAL_PATH_FLAG_2; } // Update provisional bridge mode path - if (!(gFootpathProvisionalFlags & PROVISIONAL_PATH_FLAG_1)) + if (!(gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1)) { ObjectEntryIndex type; ObjectEntryIndex railings = gFootpathSelection.Railings; @@ -488,12 +492,12 @@ static void window_footpath_update_provisional_path_for_bridge_mode(rct_window* { _footpathConstructionNextArrowPulse = curTime + ARROW_PULSE_DURATION; - gFootpathProvisionalFlags ^= PROVISIONAL_PATH_FLAG_SHOW_ARROW; + gProvisionalFootpath.Flags ^= PROVISIONAL_PATH_FLAG_SHOW_ARROW; CoordsXYZ footpathLoc; footpath_get_next_path_info(nullptr, footpathLoc, &slope); gMapSelectArrowPosition = footpathLoc; - gMapSelectArrowDirection = gFootpathConstructDirection; - if (gFootpathProvisionalFlags & PROVISIONAL_PATH_FLAG_SHOW_ARROW) + gMapSelectArrowDirection = _footpathConstructDirection; + if (gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_SHOW_ARROW) { gMapSelectFlags |= MAP_SELECT_FLAG_ENABLE_ARROW; } @@ -523,7 +527,7 @@ static void window_footpath_update(rct_window* w) } // Check tool - if (gFootpathConstructionMode == PATH_CONSTRUCTION_MODE_LAND) + if (_footpathConstructionMode == PATH_CONSTRUCTION_MODE_LAND) { if (!(input_test_flag(INPUT_FLAG_TOOL_ACTIVE))) { @@ -538,7 +542,7 @@ static void window_footpath_update(rct_window* w) window_close(w); } } - else if (gFootpathConstructionMode == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL_TOOL) + else if (_footpathConstructionMode == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL_TOOL) { if (!(input_test_flag(INPUT_FLAG_TOOL_ACTIVE))) { @@ -567,7 +571,7 @@ static void window_footpath_invalidate(rct_window* w) w->pressed_widgets |= gFootpathSelection.IsQueueSelected ? (1 << WIDX_QUEUELINE_TYPE) : (1 << WIDX_FOOTPATH_TYPE); // Enable / disable construct button - window_footpath_widgets[WIDX_CONSTRUCT].type = gFootpathConstructionMode == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL + window_footpath_widgets[WIDX_CONSTRUCT].type = _footpathConstructionMode == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL ? WindowWidgetType::ImgBtn : WindowWidgetType::Empty; @@ -637,7 +641,7 @@ static void window_footpath_paint(rct_window* w, rct_drawpixelinfo* dpi) if (!(w->disabled_widgets & (1 << WIDX_CONSTRUCT))) { // Get construction image - uint8_t direction = (gFootpathConstructDirection + get_current_rotation()) % 4; + uint8_t direction = (_footpathConstructDirection + get_current_rotation()) % 4; uint8_t slope = 0; if (gFootpathConstructSlope == 2) { @@ -815,7 +819,7 @@ static void window_footpath_show_railings_types_dialog(rct_window* w, rct_widget static void window_footpath_mousedown_direction(int32_t direction) { footpath_provisional_update(); - gFootpathConstructDirection = (direction - get_current_rotation()) & 3; + _footpathConstructDirection = (direction - get_current_rotation()) & 3; _window_footpath_cost = MONEY32_UNDEFINED; window_footpath_set_enabled_and_pressed_widgets(); } @@ -852,8 +856,8 @@ static void window_footpath_set_provisional_path_at_point(const ScreenCoordsXY& else { // Check for change - if ((gFootpathProvisionalFlags & PROVISIONAL_PATH_FLAG_1) - && gFootpathProvisionalPosition == CoordsXYZ{ info.Loc, info.Element->GetBaseZ() }) + if ((gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1) + && gProvisionalFootpath.Position == CoordsXYZ{ info.Loc, info.Element->GetBaseZ() }) { return; } @@ -1089,11 +1093,11 @@ static void window_footpath_start_bridge_at_point(const ScreenCoordsXY& screenCo tool_cancel(); gFootpathConstructFromPosition = { mapCoords, z }; - gFootpathConstructDirection = direction; - gFootpathProvisionalFlags = 0; + _footpathConstructDirection = direction; + gProvisionalFootpath.Flags = 0; gFootpathConstructSlope = 0; - gFootpathConstructionMode = PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL; - gFootpathConstructValidDirections = INVALID_DIRECTION; + _footpathConstructionMode = PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL; + _footpathConstructValidDirections = INVALID_DIRECTION; window_footpath_set_enabled_and_pressed_widgets(); } @@ -1121,7 +1125,7 @@ static void window_footpath_construct() type = gFootpathSelection.LegacyPath; } auto footpathPlaceAction = FootpathPlaceAction( - footpathLoc, slope, type, gFootpathSelection.Railings, gFootpathConstructDirection, constructFlags); + footpathLoc, slope, type, gFootpathSelection.Railings, _footpathConstructDirection, constructFlags); footpathPlaceAction.SetCallback([=](const GameAction* ga, const GameActions::Result* result) { if (result->Error == GameActions::Status::Ok) { @@ -1129,11 +1133,11 @@ static void window_footpath_construct() if (gFootpathConstructSlope == 0) { - gFootpathConstructValidDirections = INVALID_DIRECTION; + _footpathConstructValidDirections = INVALID_DIRECTION; } else { - gFootpathConstructValidDirections = gFootpathConstructDirection; + _footpathConstructValidDirections = _footpathConstructDirection; } if (gFootpathGroundFlags & ELEMENT_IS_UNDERGROUND) @@ -1166,14 +1170,14 @@ static void footpath_remove_tile_element(TileElement* tileElement) { uint8_t slopeDirection = tileElement->AsPath()->GetSlopeDirection(); slopeDirection = direction_reverse(slopeDirection); - if (slopeDirection == gFootpathConstructDirection) + if (slopeDirection == _footpathConstructDirection) { z += PATH_HEIGHT_STEP; } } // Find a connected edge - int32_t edge = direction_reverse(gFootpathConstructDirection); + int32_t edge = direction_reverse(_footpathConstructDirection); if (!(tileElement->AsPath()->GetEdges() & (1 << edge))) { edge = (edge + 1) & 3; @@ -1200,8 +1204,8 @@ static void footpath_remove_tile_element(TileElement* tileElement) gFootpathConstructFromPosition.x -= CoordsDirectionDelta[edge].x; gFootpathConstructFromPosition.y -= CoordsDirectionDelta[edge].y; gFootpathConstructFromPosition.z = z; - gFootpathConstructDirection = edge; - gFootpathConstructValidDirections = INVALID_DIRECTION; + _footpathConstructDirection = edge; + _footpathConstructValidDirections = INVALID_DIRECTION; } /** @@ -1232,7 +1236,7 @@ static TileElement* footpath_get_tile_element_to_remove() { if (tileElement->AsPath()->IsSloped()) { - if (direction_reverse(tileElement->AsPath()->GetSlopeDirection()) != gFootpathConstructDirection) + if (direction_reverse(tileElement->AsPath()->GetSlopeDirection()) != _footpathConstructDirection) { continue; } @@ -1244,7 +1248,7 @@ static TileElement* footpath_get_tile_element_to_remove() { if (!tileElement->AsPath()->IsSloped()) { - if ((tileElement->AsPath()->GetSlopeDirection()) == gFootpathConstructDirection) + if ((tileElement->AsPath()->GetSlopeDirection()) == _footpathConstructDirection) { continue; } @@ -1290,13 +1294,13 @@ static void window_footpath_set_enabled_and_pressed_widgets() return; } - if (gFootpathConstructionMode == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL) + if (_footpathConstructionMode == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL) { map_invalidate_map_selection_tiles(); gMapSelectFlags |= MAP_SELECT_FLAG_ENABLE_CONSTRUCT; gMapSelectFlags |= MAP_SELECT_FLAG_GREEN; - int32_t direction = gFootpathConstructDirection; + int32_t direction = _footpathConstructDirection; gMapSelectionTiles.clear(); gMapSelectionTiles.push_back({ gFootpathConstructFromPosition.x + CoordsDirectionDelta[direction].x, gFootpathConstructFromPosition.y + CoordsDirectionDelta[direction].y }); @@ -1308,10 +1312,10 @@ static void window_footpath_set_enabled_and_pressed_widgets() | (1LL << WIDX_SLOPEDOWN) | (1LL << WIDX_LEVEL) | (1LL << WIDX_SLOPEUP)); uint64_t disabledWidgets = 0; int32_t currentRotation = get_current_rotation(); - if (gFootpathConstructionMode >= PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL) + if (_footpathConstructionMode >= PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL) { // Set pressed directional widget - int32_t direction = (gFootpathConstructDirection + currentRotation) & 3; + int32_t direction = (_footpathConstructDirection + currentRotation) & 3; pressedWidgets |= (1LL << (WIDX_DIRECTION_NW + direction)); // Set pressed slope widget @@ -1330,7 +1334,7 @@ static void window_footpath_set_enabled_and_pressed_widgets() } // Enable / disable directional widgets - direction = gFootpathConstructValidDirections; + direction = _footpathConstructValidDirections; if (direction != INVALID_DIRECTION) { disabledWidgets |= (1 << WIDX_DIRECTION_NW) | (1 << WIDX_DIRECTION_NE) | (1 << WIDX_DIRECTION_SW) @@ -1359,7 +1363,7 @@ static void window_footpath_set_enabled_and_pressed_widgets() */ static void footpath_get_next_path_info(ObjectEntryIndex* type, CoordsXYZ& footpathLoc, int32_t* slope) { - auto direction = gFootpathConstructDirection; + auto direction = _footpathConstructDirection; footpathLoc.x = gFootpathConstructFromPosition.x + CoordsDirectionDelta[direction].x; footpathLoc.y = gFootpathConstructFromPosition.y + CoordsDirectionDelta[direction].y; footpathLoc.z = gFootpathConstructFromPosition.z; @@ -1370,7 +1374,7 @@ static void footpath_get_next_path_info(ObjectEntryIndex* type, CoordsXYZ& footp *slope = TILE_ELEMENT_SLOPE_FLAT; if (gFootpathConstructSlope != 0) { - *slope = gFootpathConstructDirection | TILE_ELEMENT_SLOPE_S_CORNER_UP; + *slope = _footpathConstructDirection | TILE_ELEMENT_SLOPE_S_CORNER_UP; if (gFootpathConstructSlope != 2) { footpathLoc.z -= PATH_HEIGHT_STEP; @@ -1520,12 +1524,12 @@ void window_footpath_keyboard_shortcut_turn_left() { rct_window* w = window_find_by_class(WC_FOOTPATH); if (w == nullptr || WidgetIsDisabled(w, WIDX_DIRECTION_NW) || WidgetIsDisabled(w, WIDX_DIRECTION_NE) - || WidgetIsDisabled(w, WIDX_DIRECTION_SW) || WidgetIsDisabled(w, WIDX_DIRECTION_SE) || gFootpathConstructionMode != 2) + || WidgetIsDisabled(w, WIDX_DIRECTION_SW) || WidgetIsDisabled(w, WIDX_DIRECTION_SE) || _footpathConstructionMode != 2) { return; } int32_t currentRotation = get_current_rotation(); - int32_t turnedRotation = gFootpathConstructDirection - currentRotation + (currentRotation % 2 == 1 ? 1 : -1); + int32_t turnedRotation = _footpathConstructDirection - currentRotation + (currentRotation % 2 == 1 ? 1 : -1); window_footpath_mousedown_direction(turnedRotation); } @@ -1533,12 +1537,12 @@ void window_footpath_keyboard_shortcut_turn_right() { rct_window* w = window_find_by_class(WC_FOOTPATH); if (w == nullptr || WidgetIsDisabled(w, WIDX_DIRECTION_NW) || WidgetIsDisabled(w, WIDX_DIRECTION_NE) - || WidgetIsDisabled(w, WIDX_DIRECTION_SW) || WidgetIsDisabled(w, WIDX_DIRECTION_SE) || gFootpathConstructionMode != 2) + || WidgetIsDisabled(w, WIDX_DIRECTION_SW) || WidgetIsDisabled(w, WIDX_DIRECTION_SE) || _footpathConstructionMode != 2) { return; } int32_t currentRotation = get_current_rotation(); - int32_t turnedRotation = gFootpathConstructDirection - currentRotation + (currentRotation % 2 == 1 ? -1 : 1); + int32_t turnedRotation = _footpathConstructDirection - currentRotation + (currentRotation % 2 == 1 ? -1 : 1); window_footpath_mousedown_direction(turnedRotation); } @@ -1610,3 +1614,8 @@ void window_footpath_keyboard_shortcut_build_current() window_event_mouse_up_call(w, WIDX_CONSTRUCT); } + +void window_footpath_reset_selected_path() +{ + gFootpathSelection = {}; +} diff --git a/src/openrct2-ui/windows/GameBottomToolbar.cpp b/src/openrct2-ui/windows/GameBottomToolbar.cpp index 7f34ffc4b4..b3299f2fef 100644 --- a/src/openrct2-ui/windows/GameBottomToolbar.cpp +++ b/src/openrct2-ui/windows/GameBottomToolbar.cpp @@ -601,8 +601,8 @@ static void window_game_bottom_toolbar_draw_news_item(rct_drawpixelinfo* dpi, rc return; auto clipCoords = ScreenCoordsXY{ 10, 19 }; - - if (peep->Is() && peep->AssignedStaffType == StaffType::Entertainer) + auto* staff = peep->As(); + if (staff != nullptr && staff->AssignedStaffType == StaffType::Entertainer) { clipCoords.y += 3; } @@ -614,17 +614,21 @@ static void window_game_bottom_toolbar_draw_news_item(rct_drawpixelinfo* dpi, rc auto image_id = ImageId(image_id_base, peep->TshirtColour, peep->TrousersColour); gfx_draw_sprite(&cliped_dpi, image_id, clipCoords); - if (image_id_base >= 0x2A1D && image_id_base < 0x2A3D) + auto* guest = peep->As(); + if (guest != nullptr) { - gfx_draw_sprite(&cliped_dpi, ImageId(image_id_base + 32, peep->BalloonColour), clipCoords); - } - else if (image_id_base >= 0x2BBD && image_id_base < 0x2BDD) - { - gfx_draw_sprite(&cliped_dpi, ImageId(image_id_base + 32, peep->UmbrellaColour), clipCoords); - } - else if (image_id_base >= 0x29DD && image_id_base < 0x29FD) - { - gfx_draw_sprite(&cliped_dpi, ImageId(image_id_base + 32, peep->HatColour), clipCoords); + if (image_id_base >= 0x2A1D && image_id_base < 0x2A3D) + { + gfx_draw_sprite(&cliped_dpi, ImageId(image_id_base + 32, guest->BalloonColour), clipCoords); + } + else if (image_id_base >= 0x2BBD && image_id_base < 0x2BDD) + { + gfx_draw_sprite(&cliped_dpi, ImageId(image_id_base + 32, guest->UmbrellaColour), clipCoords); + } + else if (image_id_base >= 0x29DD && image_id_base < 0x29FD) + { + gfx_draw_sprite(&cliped_dpi, ImageId(image_id_base + 32, guest->HatColour), clipCoords); + } } break; } diff --git a/src/openrct2-ui/windows/Guest.cpp b/src/openrct2-ui/windows/Guest.cpp index fe6d596cb6..f3f3d23591 100644 --- a/src/openrct2-ui/windows/Guest.cpp +++ b/src/openrct2-ui/windows/Guest.cpp @@ -756,7 +756,8 @@ static void window_guest_overview_tab_paint(rct_window* w, rct_drawpixelinfo* dp return; } - if (peep->Is() && peep->AssignedStaffType == StaffType::Entertainer) + auto* staff = peep->As(); + if (staff != nullptr && staff->AssignedStaffType == StaffType::Entertainer) screenCoords.y++; int32_t animationFrame = GetPeepAnimation(peep->SpriteType).base_image + 1; @@ -773,22 +774,26 @@ static void window_guest_overview_tab_paint(rct_window* w, rct_drawpixelinfo* dp auto sprite_id = ImageId(animationFrame, peep->TshirtColour, peep->TrousersColour); gfx_draw_sprite(&clip_dpi, sprite_id, screenCoords); - // If holding a balloon - if (animationFrame >= 0x2A1D && animationFrame < 0x2A3D) + auto* guest = peep->As(); + if (guest != nullptr) { - gfx_draw_sprite(&clip_dpi, ImageId(animationFrame + 32, peep->BalloonColour), screenCoords); - } + // If holding a balloon + if (animationFrame >= 0x2A1D && animationFrame < 0x2A3D) + { + gfx_draw_sprite(&clip_dpi, ImageId(animationFrame + 32, guest->BalloonColour), screenCoords); + } - // If holding umbrella - if (animationFrame >= 0x2BBD && animationFrame < 0x2BDD) - { - gfx_draw_sprite(&clip_dpi, ImageId(animationFrame + 32, peep->UmbrellaColour), screenCoords); - } + // If holding umbrella + if (animationFrame >= 0x2BBD && animationFrame < 0x2BDD) + { + gfx_draw_sprite(&clip_dpi, ImageId(animationFrame + 32, guest->UmbrellaColour), screenCoords); + } - // If wearing hat - if (animationFrame >= 0x29DD && animationFrame < 0x29FD) - { - gfx_draw_sprite(&clip_dpi, ImageId(animationFrame + 32, peep->HatColour), screenCoords); + // If wearing hat + if (animationFrame >= 0x29DD && animationFrame < 0x29FD) + { + gfx_draw_sprite(&clip_dpi, ImageId(animationFrame + 32, guest->HatColour), screenCoords); + } } } @@ -1831,7 +1836,7 @@ void window_guest_inventory_update(rct_window* w) } } -static std::pair window_guest_inventory_format_item(Peep* peep, ShopItem item) +static std::pair window_guest_inventory_format_item(Guest* guest, ShopItem item) { auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark(); auto parkName = park.Name.c_str(); @@ -1849,10 +1854,10 @@ static std::pair window_guest_inventory_format_item(Pe { case ShopItem::Balloon: ft.Rewind(); - ft.Add(SPRITE_ID_PALETTE_COLOUR_1(peep->BalloonColour) | GetShopItemDescriptor(item).Image); + ft.Add(SPRITE_ID_PALETTE_COLOUR_1(guest->BalloonColour) | GetShopItemDescriptor(item).Image); break; case ShopItem::Photo: - ride = get_ride(peep->Photo1RideRef); + ride = get_ride(guest->Photo1RideRef); if (ride != nullptr) { ft.Rewind(); @@ -1863,10 +1868,10 @@ static std::pair window_guest_inventory_format_item(Pe break; case ShopItem::Umbrella: ft.Rewind(); - ft.Add(SPRITE_ID_PALETTE_COLOUR_1(peep->UmbrellaColour) | GetShopItemDescriptor(item).Image); + ft.Add(SPRITE_ID_PALETTE_COLOUR_1(guest->UmbrellaColour) | GetShopItemDescriptor(item).Image); break; case ShopItem::Voucher: - switch (peep->VoucherType) + switch (guest->VoucherType) { case VOUCHER_TYPE_PARK_ENTRY_FREE: ft.Rewind(); @@ -1876,7 +1881,7 @@ static std::pair window_guest_inventory_format_item(Pe ft.Add(parkName); break; case VOUCHER_TYPE_RIDE_FREE: - ride = get_ride(peep->VoucherRideId); + ride = get_ride(guest->VoucherRideId); if (ride != nullptr) { ft.Rewind(); @@ -1896,20 +1901,20 @@ static std::pair window_guest_inventory_format_item(Pe ft.Rewind(); ft.Increment(6); ft.Add(STR_PEEP_INVENTORY_VOUCHER_FOOD_OR_DRINK_FREE); - ft.Add(GetShopItemDescriptor(peep->VoucherShopItem).Naming.Singular); + ft.Add(GetShopItemDescriptor(guest->VoucherShopItem).Naming.Singular); break; } break; case ShopItem::Hat: ft.Rewind(); - ft.Add(SPRITE_ID_PALETTE_COLOUR_1(peep->HatColour) | GetShopItemDescriptor(item).Image); + ft.Add(SPRITE_ID_PALETTE_COLOUR_1(guest->HatColour) | GetShopItemDescriptor(item).Image); break; case ShopItem::TShirt: ft.Rewind(); - ft.Add(SPRITE_ID_PALETTE_COLOUR_1(peep->TshirtColour) | GetShopItemDescriptor(item).Image); + ft.Add(SPRITE_ID_PALETTE_COLOUR_1(guest->TshirtColour) | GetShopItemDescriptor(item).Image); break; case ShopItem::Photo2: - ride = get_ride(peep->Photo2RideRef); + ride = get_ride(guest->Photo2RideRef); if (ride != nullptr) { ft.Rewind(); @@ -1918,7 +1923,7 @@ static std::pair window_guest_inventory_format_item(Pe } break; case ShopItem::Photo3: - ride = get_ride(peep->Photo3RideRef); + ride = get_ride(guest->Photo3RideRef); if (ride != nullptr) { ft.Rewind(); @@ -1927,7 +1932,7 @@ static std::pair window_guest_inventory_format_item(Pe } break; case ShopItem::Photo4: - ride = get_ride(peep->Photo4RideRef); + ride = get_ride(guest->Photo4RideRef); if (ride != nullptr) { ft.Rewind(); diff --git a/src/openrct2-ui/windows/GuestList.cpp b/src/openrct2-ui/windows/GuestList.cpp index 29f0f6b76f..8fe69021d3 100644 --- a/src/openrct2-ui/windows/GuestList.cpp +++ b/src/openrct2-ui/windows/GuestList.cpp @@ -773,7 +773,7 @@ private: } } - bool GuestShouldBeVisible(const Peep& peep) + bool GuestShouldBeVisible(const Guest& peep) { if (_trackingOnly && !(peep.PeepFlags & PEEP_FLAGS_TRACKING)) return false; @@ -794,7 +794,7 @@ private: return true; } - bool IsPeepInFilter(const Peep& peep) + bool IsPeepInFilter(const Guest& peep) { auto guestViewType = _selectedFilter == GuestFilterType::Guests ? GuestViewType::Actions : GuestViewType::Thoughts; auto peepArgs = GetArgumentsFromPeep(peep, guestViewType); @@ -875,7 +875,7 @@ private: /** * Calculates a hash value (arguments) for comparing peep actions/thoughts */ - static FilterArguments GetArgumentsFromPeep(const Peep& peep, GuestViewType type) + static FilterArguments GetArgumentsFromPeep(const Guest& peep, GuestViewType type) { FilterArguments result; Formatter ft(result.args); diff --git a/src/openrct2-ui/windows/Main.cpp b/src/openrct2-ui/windows/Main.cpp index 8df3749580..7e698b6750 100644 --- a/src/openrct2-ui/windows/Main.cpp +++ b/src/openrct2-ui/windows/Main.cpp @@ -48,7 +48,7 @@ rct_window* window_main_open() gShowGridLinesRefCount = 0; gShowLandRightsRefCount = 0; gShowConstuctionRightsRefCount = 0; - gFootpathSelection = {}; + window_footpath_reset_selected_path(); return window; } diff --git a/src/openrct2-ui/windows/Map.cpp b/src/openrct2-ui/windows/Map.cpp index c16fc37bcb..7b43cc9c7c 100644 --- a/src/openrct2-ui/windows/Map.cpp +++ b/src/openrct2-ui/windows/Map.cpp @@ -1327,7 +1327,7 @@ static void window_map_place_park_entrance_tool_down(const ScreenCoordsXY& scree CoordsXYZD parkEntrancePosition = place_park_entrance_get_map_position(screenCoords); if (!parkEntrancePosition.isNull()) { - auto gameAction = PlaceParkEntranceAction(parkEntrancePosition); + auto gameAction = PlaceParkEntranceAction(parkEntrancePosition, gFootpathSelectedId); auto result = GameActions::Execute(&gameAction); if (result->Error == GameActions::Status::Ok) { diff --git a/src/openrct2-ui/windows/News.cpp b/src/openrct2-ui/windows/News.cpp index baf68ef572..2bcc342b3d 100644 --- a/src/openrct2-ui/windows/News.cpp +++ b/src/openrct2-ui/windows/News.cpp @@ -33,6 +33,7 @@ enum WINDOW_NEWS_WIDGET_IDX { WIDX_SCROLL }; + static rct_widget window_news_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({372, 18}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Primary, SPR_TAB_GEARS_0), // settings @@ -40,309 +41,273 @@ static rct_widget window_news_widgets[] = { { WIDGETS_END }, }; -static void window_news_mouseup(rct_window *w, rct_widgetindex widgetIndex); -static void window_news_update(rct_window *w); -static void window_news_scrollgetsize(rct_window *w, int32_t scrollIndex, int32_t *width, int32_t *height); -static void window_news_scrollmousedown(rct_window *w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords); -static void window_news_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_news_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int32_t scrollIndex); - -static rct_window_event_list window_news_events([](auto& events) +class NewsWindow final : public Window { - events.mouse_up = &window_news_mouseup; - events.update = &window_news_update; - events.get_scroll_size = &window_news_scrollgetsize; - events.scroll_mousedown = &window_news_scrollmousedown; - events.paint = &window_news_paint; - events.scroll_paint = &window_news_scrollpaint; -}); -// clang-format on - -/** - * - * rct2: 0x0066E464 - */ -rct_window* window_news_open() -{ - rct_window* window; - - // Check if window is already open - window = window_bring_to_front_by_class(WC_RECENT_NEWS); - if (window == nullptr) +private: + int32_t _pressedNewsItemIndex, _pressedButtonIndex, _suspendUpdateTicks; + static int32_t CalculateItemHeight() { - window = WindowCreateAutoPos(400, 300, &window_news_events, WC_RECENT_NEWS, 0); - window->widgets = window_news_widgets; - window->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_SETTINGS); - WindowInitScrollWidgets(window); - window->news.var_480 = -1; + return 4 * font_get_line_height(FontSpriteBase::SMALL) + 2; } - // sub_66E4BA: - rct_widget* widget; - - int32_t width = 0; - int32_t height = 0; - window_get_scroll_size(window, 0, &width, &height); - widget = &window_news_widgets[WIDX_SCROLL]; - window->scrolls[0].v_top = std::max(0, height - (widget->height() - 1)); - WidgetScrollUpdateThumbs(window, WIDX_SCROLL); - - return window; -} - -static int32_t window_news_get_item_height() -{ - return 4 * font_get_line_height(FontSpriteBase::SMALL) + 2; -} - -/** - * - * rct2: 0x0066D4D5 - */ -static void window_news_mouseup(rct_window* w, rct_widgetindex widgetIndex) -{ - switch (widgetIndex) +public: + void OnOpen() override { - case WIDX_CLOSE: - window_close(w); - break; - case WIDX_SETTINGS: - context_open_window(WC_NOTIFICATION_OPTIONS); - break; - } -} + widgets = window_news_widgets; + enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_SETTINGS); + WindowInitScrollWidgets(this); + _pressedNewsItemIndex = -1; -/** - * - * rct2: 0x0066EAB8 - */ -static void window_news_update(rct_window* w) -{ - if (w->news.var_480 == -1 || --w->news.var_484 != 0) - { - return; + int32_t w = 0, h = 0; + rct_widget* widget = &widgets[WIDX_SCROLL]; + window_get_scroll_size(this, 0, &w, &h); + scrolls[0].v_top = std::max(0, h - (widget->height() - 1)); + WidgetScrollUpdateThumbs(this, WIDX_SCROLL); } - w->Invalidate(); - OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click2, 0, w->windowPos.x + (w->width / 2)); - - size_t j = w->news.var_480; - w->news.var_480 = -1; - if (j >= gNewsItems.GetArchived().size()) - return; - - const auto& newsItem = gNewsItems.GetArchived()[j]; - if (newsItem.HasButton()) - return; - if (w->news.var_482 == 1) + void OnMouseUp(rct_widgetindex widgetIndex) override { - News::OpenSubject(newsItem.Type, newsItem.Assoc); - } - else if (w->news.var_482 > 1) - { - auto subjectLoc = News::GetSubjectLocation(newsItem.Type, newsItem.Assoc); - if (subjectLoc != std::nullopt && (w = window_get_main()) != nullptr) + switch (widgetIndex) { - window_scroll_to_location(w, *subjectLoc); - } - } -} - -/** - * - * rct2: 0x0066EA3C - */ -static void window_news_scrollgetsize(rct_window* w, int32_t scrollIndex, int32_t* width, int32_t* height) -{ - *height = static_cast(gNewsItems.GetArchived().size()) * window_news_get_item_height(); -} - -/** - * - * rct2: 0x0066EA5C - */ -static void window_news_scrollmousedown(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords) -{ - int32_t itemHeight = window_news_get_item_height(); - - int32_t i = 0; - int32_t buttonIndex = 0; - auto mutableScreenCoords = screenCoords; - for (const auto& newsItem : gNewsItems.GetArchived()) - { - if (mutableScreenCoords.y < itemHeight) - { - if (newsItem.HasButton() || mutableScreenCoords.y < 14 || mutableScreenCoords.y >= 38 - || mutableScreenCoords.x < 328) - { - buttonIndex = 0; + case WIDX_CLOSE: + Close(); break; - } - else if (mutableScreenCoords.x < 351 && newsItem.TypeHasSubject()) - { - buttonIndex = 1; + case WIDX_SETTINGS: + context_open_window(WC_NOTIFICATION_OPTIONS); break; - } - else if (mutableScreenCoords.x < 376 && newsItem.TypeHasLocation()) - { - buttonIndex = 2; - break; - } } - mutableScreenCoords.y -= itemHeight; - i++; } - if (buttonIndex != 0) + void OnUpdate() override { - w->news.var_480 = i; - w->news.var_482 = buttonIndex; - w->news.var_484 = 4; - w->Invalidate(); - OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click1, 0, w->windowPos.x + (w->width / 2)); - } -} - -/** - * - * rct2: 0x0066E4E8 - */ -static void window_news_paint(rct_window* w, rct_drawpixelinfo* dpi) -{ - WindowDrawWidgets(w, dpi); -} - -/** - * - * rct2: 0x0066E4EE - */ -static void window_news_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t scrollIndex) -{ - int32_t lineHeight = font_get_line_height(FontSpriteBase::SMALL); - int32_t itemHeight = window_news_get_item_height(); - - int32_t y = 0; - int32_t i = 0; - for (const auto& newsItem : gNewsItems.GetArchived()) - { - if (y >= dpi->y + dpi->height) - break; - if (y + itemHeight < dpi->y) + if (_pressedNewsItemIndex == -1 || --_suspendUpdateTicks != 0) { - y += itemHeight; - i++; - continue; + return; } - // Background - gfx_fill_rect_inset( - dpi, { -1, y, 383, y + itemHeight - 1 }, w->colours[1], (INSET_RECT_FLAG_BORDER_INSET | INSET_RECT_FLAG_FILL_GREY)); + Invalidate(); + OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click2, 0, windowPos.x + (width / 2)); - // Date text - { - auto ft = Formatter(); - ft.Add(DateDayNames[newsItem.Day - 1]); - ft.Add(DateGameMonthNames[date_get_month(newsItem.MonthYear)]); - DrawTextBasic(dpi, { 2, y }, STR_NEWS_DATE_FORMAT, ft, { COLOUR_WHITE, FontSpriteBase::SMALL }); - } - // Item text - { - auto ft = Formatter(); - ft.Add(newsItem.Text.c_str()); - DrawTextWrapped(dpi, { 2, y + lineHeight }, 325, STR_BOTTOM_TOOLBAR_NEWS_TEXT, ft, { FontSpriteBase::SMALL }); - } - // Subject button - if ((newsItem.TypeHasSubject()) && !(newsItem.HasButton())) - { - auto screenCoords = ScreenCoordsXY{ 328, y + lineHeight + 4 }; + size_t j = _pressedNewsItemIndex; + _pressedNewsItemIndex = -1; - int32_t press = 0; - if (w->news.var_480 != -1) + if (j >= gNewsItems.GetArchived().size()) + { + return; + } + + const auto& newsItem = gNewsItems.GetArchived()[j]; + if (newsItem.HasButton()) + { + return; + } + + if (_pressedButtonIndex == 1) + { + News::OpenSubject(newsItem.Type, newsItem.Assoc); + } + else if (_pressedButtonIndex > 1) + { + static rct_window* _mainWindow; + auto subjectLoc = News::GetSubjectLocation(newsItem.Type, newsItem.Assoc); + if (subjectLoc != std::nullopt && (_mainWindow = window_get_main()) != nullptr) { - News::IsValidIndex(w->news.var_480 + News::ItemHistoryStart); - if (i == w->news.var_480 && w->news.var_482 == 1) - press = INSET_RECT_FLAG_BORDER_INSET; + window_scroll_to_location(_mainWindow, *subjectLoc); } - gfx_fill_rect_inset(dpi, { screenCoords, screenCoords + ScreenCoordsXY{ 23, 23 } }, w->colours[2], press); + } + } - switch (newsItem.Type) + ScreenSize OnScrollGetSize(int32_t scrollIndex) override + { + static int32_t _scrollHeight = static_cast(gNewsItems.GetArchived().size()) * CalculateItemHeight(); + return {WW, _scrollHeight}; + } + + void OnScrollMouseDown(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override + { + int32_t itemHeight = CalculateItemHeight(); + int32_t i = 0; + int32_t buttonIndex = 0; + auto mutableScreenCoords = screenCoords; + for (const auto& newsItem : gNewsItems.GetArchived()) + { + if (mutableScreenCoords.y < itemHeight) { - case News::ItemType::Ride: - gfx_draw_sprite(dpi, ImageId(SPR_RIDE), screenCoords); - break; - case News::ItemType::Peep: - case News::ItemType::PeepOnRide: + if (newsItem.HasButton() || mutableScreenCoords.y < 14 || mutableScreenCoords.y >= 38 + || mutableScreenCoords.x < 328) { - rct_drawpixelinfo cliped_dpi; - if (!clip_drawpixelinfo(&cliped_dpi, dpi, screenCoords + ScreenCoordsXY{ 1, 1 }, 22, 22)) - { - break; - } - - auto peep = TryGetEntity(newsItem.Assoc); - if (peep == nullptr) - break; - - auto clipCoords = ScreenCoordsXY{ 10, 19 }; - - // If normal peep set sprite to normal (no food) - // If staff set sprite to staff sprite - auto spriteType = PeepSpriteType::Normal; - if (peep->Is()) - { - spriteType = peep->SpriteType; - if (peep->AssignedStaffType == StaffType::Entertainer) - { - clipCoords.y += 3; - } - } - - uint32_t image_id = GetPeepAnimation(spriteType).base_image; - image_id += 0xA0000001; - image_id |= (peep->TshirtColour << 19) | (peep->TrousersColour << 24); - - gfx_draw_sprite(&cliped_dpi, ImageId::FromUInt32(image_id), clipCoords); + buttonIndex = 0; break; } - case News::ItemType::Money: - gfx_draw_sprite(dpi, ImageId(SPR_FINANCE), screenCoords); + else if (mutableScreenCoords.x < 351 && newsItem.TypeHasSubject()) + { + buttonIndex = 1; break; - case News::ItemType::Research: - gfx_draw_sprite(dpi, ImageId(newsItem.Assoc < 0x10000 ? SPR_NEW_SCENERY : SPR_NEW_RIDE), screenCoords); - break; - case News::ItemType::Peeps: - gfx_draw_sprite(dpi, ImageId(SPR_GUESTS), screenCoords); - break; - case News::ItemType::Award: - gfx_draw_sprite(dpi, ImageId(SPR_AWARD), screenCoords); - break; - case News::ItemType::Graph: - gfx_draw_sprite(dpi, ImageId(SPR_GRAPH), screenCoords); - break; - case News::ItemType::Null: - case News::ItemType::Blank: - case News::ItemType::Count: + } + else if (mutableScreenCoords.x < 376 && newsItem.TypeHasLocation()) + { + buttonIndex = 2; break; + } } + mutableScreenCoords.y -= itemHeight; + i++; } - // Location button - if ((newsItem.TypeHasLocation()) && !(newsItem.HasButton())) + if (buttonIndex != 0) { - auto screenCoords = ScreenCoordsXY{ 352, y + lineHeight + 4 }; - - int32_t press = 0; - if (w->news.var_480 != -1) - { - News::IsValidIndex(w->news.var_480 + News::ItemHistoryStart); - if (i == w->news.var_480 && w->news.var_482 == 2) - press = 0x20; - } - gfx_fill_rect_inset(dpi, { screenCoords, screenCoords + ScreenCoordsXY{ 23, 23 } }, w->colours[2], press); - gfx_draw_sprite(dpi, ImageId(SPR_LOCATE), screenCoords); + _pressedNewsItemIndex = i; + _pressedButtonIndex = buttonIndex; + _suspendUpdateTicks = 4; + Invalidate(); + OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click1, 0, windowPos.x + (width / 2)); } - - y += itemHeight; - i++; } + + void OnDraw(rct_drawpixelinfo& dpi) override + { + DrawWidgets(dpi); + } + + void OnScrollDraw(int32_t scrollIndex, rct_drawpixelinfo& dpi) override + { + int32_t lineHeight = font_get_line_height(FontSpriteBase::SMALL); + int32_t itemHeight = CalculateItemHeight(); + int32_t y = 0; + int32_t i = 0; + + for (const auto& newsItem : gNewsItems.GetArchived()) + { + if (y >= dpi.y + dpi.height) + break; + if (y + itemHeight < dpi.y) + { + y += itemHeight; + i++; + continue; + } + + // Background + gfx_fill_rect_inset( + &dpi, { -1, y, 383, y + itemHeight - 1 }, colours[1], (INSET_RECT_FLAG_BORDER_INSET | INSET_RECT_FLAG_FILL_GREY)); + + // Date text + { + auto ft = Formatter(); + ft.Add(DateDayNames[newsItem.Day - 1]); + ft.Add(DateGameMonthNames[date_get_month(newsItem.MonthYear)]); + DrawTextBasic(&dpi, { 2, y }, STR_NEWS_DATE_FORMAT, ft, { COLOUR_WHITE, FontSpriteBase::SMALL }); + } + // Item text + { + auto ft = Formatter(); + ft.Add(newsItem.Text.c_str()); + DrawTextWrapped(&dpi, { 2, y + lineHeight }, 325, STR_BOTTOM_TOOLBAR_NEWS_TEXT, ft, { FontSpriteBase::SMALL }); + } + // Subject button + if ((newsItem.TypeHasSubject()) && !(newsItem.HasButton())) + { + auto screenCoords = ScreenCoordsXY{ 328, y + lineHeight + 4 }; + + int32_t press = 0; + if (_pressedNewsItemIndex != -1) + { + News::IsValidIndex(_pressedNewsItemIndex + News::ItemHistoryStart); + if (i == _pressedNewsItemIndex && _pressedButtonIndex == 1) + { + press = INSET_RECT_FLAG_BORDER_INSET; + } + + } + gfx_fill_rect_inset(&dpi, { screenCoords, screenCoords + ScreenCoordsXY{ 23, 23 } }, colours[2], press); + + switch (newsItem.Type) + { + case News::ItemType::Ride: + gfx_draw_sprite(&dpi, ImageId(SPR_RIDE), screenCoords); + break; + case News::ItemType::Peep: + case News::ItemType::PeepOnRide: + { + rct_drawpixelinfo cliped_dpi; + if (!clip_drawpixelinfo(&cliped_dpi, &dpi, screenCoords + ScreenCoordsXY{ 1, 1 }, 22, 22)) + { + break; + } + + auto peep = TryGetEntity(newsItem.Assoc); + if (peep == nullptr) + { + break; + } + + auto clipCoords = ScreenCoordsXY{ 10, 19 }; + + // If normal peep set sprite to normal (no food) + // If staff set sprite to staff sprite + auto spriteType = PeepSpriteType::Normal; + auto* staff = peep->As(); + if (staff != nullptr) + { + spriteType = staff->SpriteType; + if (staff->AssignedStaffType == StaffType::Entertainer) + { + clipCoords.y += 3; + } + } + + uint32_t image_id = GetPeepAnimation(spriteType).base_image; + image_id += 0xA0000001; + image_id |= (peep->TshirtColour << 19) | (peep->TrousersColour << 24); + + gfx_draw_sprite(&cliped_dpi, ImageId::FromUInt32(image_id), clipCoords); + break; + } + case News::ItemType::Money: + gfx_draw_sprite(&dpi, ImageId(SPR_FINANCE), screenCoords); + break; + case News::ItemType::Research: + gfx_draw_sprite(&dpi, ImageId(newsItem.Assoc < 0x10000 ? SPR_NEW_SCENERY : SPR_NEW_RIDE), screenCoords); + break; + case News::ItemType::Peeps: + gfx_draw_sprite(&dpi, ImageId(SPR_GUESTS), screenCoords); + break; + case News::ItemType::Award: + gfx_draw_sprite(&dpi, ImageId(SPR_AWARD), screenCoords); + break; + case News::ItemType::Graph: + gfx_draw_sprite(&dpi, ImageId(SPR_GRAPH), screenCoords); + break; + case News::ItemType::Null: + case News::ItemType::Blank: + case News::ItemType::Count: + break; + } + } + + // Location button + if ((newsItem.TypeHasLocation()) && !(newsItem.HasButton())) + { + auto screenCoords = ScreenCoordsXY{ 352, y + lineHeight + 4 }; + + int32_t press = 0; + if (_pressedNewsItemIndex != -1) + { + News::IsValidIndex(_pressedNewsItemIndex + News::ItemHistoryStart); + if (i == _pressedNewsItemIndex && _pressedButtonIndex == 2) + press = 0x20; + } + gfx_fill_rect_inset(&dpi, { screenCoords, screenCoords + ScreenCoordsXY{ 23, 23 } }, colours[2], press); + gfx_draw_sprite(&dpi, ImageId(SPR_LOCATE), screenCoords); + } + + y += itemHeight; + i++; + } + } +}; + +rct_window* window_news_open() +{ + return WindowFocusOrCreate(WC_RECENT_NEWS, WW, WH, 0); } diff --git a/src/openrct2-ui/windows/RideConstruction.cpp b/src/openrct2-ui/windows/RideConstruction.cpp index ccc16dc305..8abb0d5653 100644 --- a/src/openrct2-ui/windows/RideConstruction.cpp +++ b/src/openrct2-ui/windows/RideConstruction.cpp @@ -650,7 +650,7 @@ static void window_ride_construction_mouseup(rct_window* w, rct_widgetindex widg case WIDX_CONSTRUCT: window_ride_construction_construct(w); // Force any footpath construction to recheck the area. - gFootpathProvisionalFlags |= PROVISIONAL_PATH_FLAG_2; + gProvisionalFootpath.Flags |= PROVISIONAL_PATH_FLAG_2; break; case WIDX_DEMOLISH: window_ride_construction_mouseup_demolish(w); @@ -1981,7 +1981,7 @@ static void window_ride_construction_entrance_click(rct_window* w) else { gRideEntranceExitPlaceType = ENTRANCE_TYPE_RIDE_ENTRANCE; - gRideEntranceExitPlaceRideIndex = w->number % MAX_RIDES; + gRideEntranceExitPlaceRideIndex = static_cast(w->number); gRideEntranceExitPlaceStationIndex = 0; input_set_flag(INPUT_FLAG_6, true); ride_construction_invalidate_current_track(); diff --git a/src/openrct2-ui/windows/Sign.cpp b/src/openrct2-ui/windows/Sign.cpp index eea34bc9db..c8e81b18af 100644 --- a/src/openrct2-ui/windows/Sign.cpp +++ b/src/openrct2-ui/windows/Sign.cpp @@ -52,45 +52,235 @@ static rct_widget window_sign_widgets[] = { { WIDGETS_END }, }; -static void window_sign_mouseup(rct_window *w, rct_widgetindex widgetIndex); -static void window_sign_mousedown(rct_window *w, rct_widgetindex widgetIndex, rct_widget* widget); -static void window_sign_dropdown(rct_window *w, rct_widgetindex widgetIndex, int32_t dropdownIndex); -static void window_sign_textinput(rct_window *w, rct_widgetindex widgetIndex, char *text); -static void window_sign_viewport_rotate(rct_window *w); -static void window_sign_invalidate(rct_window *w); -static void window_sign_paint(rct_window *w, rct_drawpixelinfo *dpi); - - -// 0x98E44C -static rct_window_event_list window_sign_events([](auto& events) -{ - events.mouse_up = &window_sign_mouseup; - events.mouse_down = &window_sign_mousedown; - events.dropdown = &window_sign_dropdown; - events.text_input = &window_sign_textinput; - events.viewport_rotate = &window_sign_viewport_rotate; - events.invalidate = &window_sign_invalidate; - events.paint = &window_sign_paint; -}); - -static void window_sign_small_mouseup(rct_window *w, rct_widgetindex widgetIndex); -static void window_sign_small_dropdown(rct_window *w, rct_widgetindex widgetIndex, int32_t dropdownIndex); -static void window_sign_small_invalidate(rct_window *w); - -// 0x9A410C -static rct_window_event_list window_sign_small_events([](auto& events) -{ - events.mouse_up = &window_sign_small_mouseup; - events.mouse_down = &window_sign_mousedown; - events.dropdown = &window_sign_small_dropdown; - events.text_input = &window_sign_textinput; - events.viewport_rotate = &window_sign_viewport_rotate; - events.invalidate = &window_sign_small_invalidate; - events.paint = &window_sign_paint; -}); // clang-format on -static void window_sign_show_text_input(rct_window* w); +class SignWindow final : public Window +{ +private: + bool _isSmall = false; + Banner* _banner = nullptr; + TileElement* _tileElement = nullptr; + + void ShowTextInput() + { + if (_banner != nullptr) + { + auto bannerText = _banner->GetText(); + window_text_input_raw_open(this, WIDX_SIGN_TEXT, STR_SIGN_TEXT_TITLE, STR_SIGN_TEXT_PROMPT, bannerText.c_str(), 32); + } + } + +public: + void OnOpen() override + { + widgets = window_sign_widgets; + enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_SIGN_TEXT) | (1 << WIDX_SIGN_DEMOLISH) | (1 << WIDX_MAIN_COLOUR) + | (1 << WIDX_TEXT_COLOUR); + + WindowInitScrollWidgets(this); + } + + /* + * Initializes the window and sets it's number and if it's small + * @return true if successfull + */ + bool Initialize(rct_windownumber windowNumber, const bool isSmall) + { + number = windowNumber; + _isSmall = isSmall; + + _banner = GetBanner(number); + if (_banner == nullptr) + return false; + + auto signViewPosition = _banner->position.ToCoordsXY().ToTileCentre(); + _tileElement = banner_get_tile_element(number); + if (_tileElement == nullptr) + return false; + + int32_t viewZ = _tileElement->GetBaseZ(); + frame_no = viewZ; + + if (_isSmall) + { + list_information_type = _tileElement->AsWall()->GetPrimaryColour(); + var_492 = _tileElement->AsWall()->GetSecondaryColour(); + SceneryEntry = _tileElement->AsWall()->GetEntryIndex(); + } + else + { + list_information_type = _tileElement->AsLargeScenery()->GetPrimaryColour(); + var_492 = _tileElement->AsLargeScenery()->GetSecondaryColour(); + SceneryEntry = _tileElement->AsLargeScenery()->GetEntryIndex(); + } + + // Create viewport + rct_widget& viewportWidget = window_sign_widgets[WIDX_VIEWPORT]; + + viewport_create( + this, windowPos + ScreenCoordsXY{ viewportWidget.left + 1, viewportWidget.top + 1 }, viewportWidget.width() - 1, + viewportWidget.height() - 1, 0, { signViewPosition, viewZ }, 0, SPRITE_INDEX_NULL); + + viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0; + Invalidate(); + + return true; + } + + void OnMouseUp(rct_widgetindex widgetIndex) override + { + switch (widgetIndex) + { + case WIDX_CLOSE: + Close(); + break; + case WIDX_SIGN_DEMOLISH: + { + auto bannerCoords = _banner->position.ToCoordsXY(); + + if (_isSmall) + { + CoordsXYZD wallLocation = { bannerCoords, _tileElement->GetBaseZ(), _tileElement->GetDirection() }; + auto wallRemoveAction = WallRemoveAction(wallLocation); + GameActions::Execute(&wallRemoveAction); + } + else + { + auto sceneryRemoveAction = LargeSceneryRemoveAction( + { bannerCoords, _tileElement->GetBaseZ(), _tileElement->GetDirection() }, + _tileElement->AsLargeScenery()->GetSequenceIndex()); + GameActions::Execute(&sceneryRemoveAction); + } + break; + } + case WIDX_SIGN_TEXT: + ShowTextInput(); + break; + } + } + + void OnMouseDown(rct_widgetindex widgetIndex) override + { + rct_widget* widget = &widgets[widgetIndex]; + switch (widgetIndex) + { + case WIDX_MAIN_COLOUR: + WindowDropdownShowColour(this, widget, TRANSLUCENT(colours[1]), static_cast(list_information_type)); + break; + case WIDX_TEXT_COLOUR: + WindowDropdownShowColour(this, widget, TRANSLUCENT(colours[1]), static_cast(var_492)); + break; + } + } + + void OnDropdown(rct_widgetindex widgetIndex, int32_t dropdownIndex) override + { + switch (widgetIndex) + { + case WIDX_MAIN_COLOUR: + { + if (dropdownIndex == -1) + return; + list_information_type = dropdownIndex; + auto signSetStyleAction = SignSetStyleAction(number, dropdownIndex, var_492, !_isSmall); + GameActions::Execute(&signSetStyleAction); + break; + } + case WIDX_TEXT_COLOUR: + { + if (dropdownIndex == -1) + return; + var_492 = dropdownIndex; + auto signSetStyleAction = SignSetStyleAction(number, list_information_type, dropdownIndex, !_isSmall); + GameActions::Execute(&signSetStyleAction); + break; + } + default: + return; + } + + Invalidate(); + } + + void OnTextInput(rct_widgetindex widgetIndex, std::string_view text) override + { + if (widgetIndex == WIDX_SIGN_TEXT && !text.empty()) + { + auto signSetNameAction = SignSetNameAction(number, std::string(text)); + GameActions::Execute(&signSetNameAction); + } + } + + void OnPrepareDraw() override + { + rct_widget* main_colour_btn = &window_sign_widgets[WIDX_MAIN_COLOUR]; + rct_widget* text_colour_btn = &window_sign_widgets[WIDX_TEXT_COLOUR]; + + if (_isSmall) + { + rct_scenery_entry* scenery_entry = get_wall_entry(SceneryEntry); + + main_colour_btn->type = WindowWidgetType::Empty; + text_colour_btn->type = WindowWidgetType::Empty; + + if (scenery_entry->wall.flags & WALL_SCENERY_HAS_PRIMARY_COLOUR) + { + main_colour_btn->type = WindowWidgetType::ColourBtn; + } + if (scenery_entry->wall.flags & WALL_SCENERY_HAS_SECONDARY_COLOUR) + { + text_colour_btn->type = WindowWidgetType::ColourBtn; + } + } + else + { + rct_scenery_entry* scenery_entry = get_large_scenery_entry(SceneryEntry); + + main_colour_btn->type = WindowWidgetType::Empty; + text_colour_btn->type = WindowWidgetType::Empty; + + if (scenery_entry->large_scenery.flags & LARGE_SCENERY_FLAG_HAS_PRIMARY_COLOUR) + { + main_colour_btn->type = WindowWidgetType::ColourBtn; + } + if (scenery_entry->large_scenery.flags & LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR) + { + text_colour_btn->type = WindowWidgetType::ColourBtn; + } + } + + main_colour_btn->image = SPRITE_ID_PALETTE_COLOUR_1(list_information_type) | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN; + text_colour_btn->image = SPRITE_ID_PALETTE_COLOUR_1(var_492) | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN; + } + + void OnDraw(rct_drawpixelinfo& dpi) override + { + DrawWidgets(dpi); + + if (viewport != nullptr) + { + window_draw_viewport(&dpi, this); + } + } + + void OnViewportRotate() override + { + RemoveViewport(); + + auto banner = GetBanner(number); + + auto signViewPos = CoordsXYZ{ banner->position.ToCoordsXY().ToTileCentre(), frame_no }; + + // Create viewport + rct_widget* viewportWidget = &window_sign_widgets[WIDX_VIEWPORT]; + viewport_create( + this, windowPos + ScreenCoordsXY{ viewportWidget->left + 1, viewportWidget->top + 1 }, viewportWidget->width() - 1, + viewportWidget->height() - 1, 0, signViewPos, 0, SPRITE_INDEX_NULL); + if (viewport != nullptr) + viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0; + Invalidate(); + } +}; /** * @@ -98,423 +288,42 @@ static void window_sign_show_text_input(rct_window* w); */ rct_window* window_sign_open(rct_windownumber number) { - rct_window* w; - rct_widget* viewportWidget; + auto* w = static_cast(window_bring_to_front_by_number(WC_BANNER, number)); - // Check if window is already open - w = window_bring_to_front_by_number(WC_BANNER, number); if (w != nullptr) return w; - w = WindowCreateAutoPos(WW, WH, &window_sign_events, WC_BANNER, WF_NO_SCROLLING); - w->widgets = window_sign_widgets; - w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_SIGN_TEXT) | (1 << WIDX_SIGN_DEMOLISH) | (1 << WIDX_MAIN_COLOUR) - | (1 << WIDX_TEXT_COLOUR); + w = WindowCreate(WC_BANNER, WW, WH, 0); - w->number = number; - WindowInitScrollWidgets(w); - - auto banner = GetBanner(w->number); - if (banner == nullptr) + if (w == nullptr) return nullptr; - auto signViewPos = banner->position.ToCoordsXY().ToTileCentre(); - TileElement* tile_element = map_get_first_element_at(signViewPos); - if (tile_element == nullptr) + bool result = w->Initialize(number, false); + if (result != true) return nullptr; - auto& tileElements = GetTileElements(); - while (1) - { - if (tile_element->GetType() == TILE_ELEMENT_TYPE_LARGE_SCENERY) - { - rct_scenery_entry* scenery_entry = tile_element->AsLargeScenery()->GetEntry(); - if (scenery_entry != nullptr && scenery_entry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) - { - auto bannerIndex = tile_element->AsLargeScenery()->GetBannerIndex(); - - if (bannerIndex == w->number) - break; - } - } - tile_element++; - if (tile_element >= &tileElements[tileElements.size()]) - { - return nullptr; - } - } - - int32_t view_z = tile_element->GetBaseZ(); - w->frame_no = view_z; - - w->list_information_type = tile_element->AsLargeScenery()->GetPrimaryColour(); - w->var_492 = tile_element->AsLargeScenery()->GetSecondaryColour(); - w->SceneryEntry = tile_element->AsLargeScenery()->GetEntryIndex(); - - // Create viewport - viewportWidget = &window_sign_widgets[WIDX_VIEWPORT]; - viewport_create( - w, w->windowPos + ScreenCoordsXY{ viewportWidget->left + 1, viewportWidget->top + 1 }, viewportWidget->width() - 1, - viewportWidget->height() - 1, 0, { signViewPos, view_z }, 0, SPRITE_INDEX_NULL); - - w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0; - w->Invalidate(); - return w; } -/** - * - * rct2: 0x6B9765 - */ -static void window_sign_mouseup(rct_window* w, rct_widgetindex widgetIndex) -{ - switch (widgetIndex) - { - case WIDX_CLOSE: - window_close(w); - break; - case WIDX_SIGN_DEMOLISH: - { - auto banner = GetBanner(w->number); - auto bannerCoords = banner->position.ToCoordsXY(); - auto tile_element = map_get_first_element_at(bannerCoords); - if (tile_element == nullptr) - return; - - auto& tileElements = GetTileElements(); - while (1) - { - if (tile_element->GetType() == TILE_ELEMENT_TYPE_LARGE_SCENERY) - { - rct_scenery_entry* scenery_entry = tile_element->AsLargeScenery()->GetEntry(); - if (scenery_entry->large_scenery.scrolling_mode != SCROLLING_MODE_NONE) - { - auto bannerIndex = tile_element->AsLargeScenery()->GetBannerIndex(); - if (bannerIndex == w->number) - break; - } - } - tile_element++; - if (tile_element >= &tileElements[tileElements.size()]) - { - return; - } - } - - auto sceneryRemoveAction = LargeSceneryRemoveAction( - { bannerCoords, tile_element->GetBaseZ(), tile_element->GetDirection() }, - tile_element->AsLargeScenery()->GetSequenceIndex()); - GameActions::Execute(&sceneryRemoveAction); - break; - } - case WIDX_SIGN_TEXT: - window_sign_show_text_input(w); - break; - } -} - -/** - * - * rct2: 0x6B9784 - & 0x6E6164 */ -static void window_sign_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) -{ - switch (widgetIndex) - { - case WIDX_MAIN_COLOUR: - WindowDropdownShowColour(w, widget, TRANSLUCENT(w->colours[1]), static_cast(w->list_information_type)); - break; - case WIDX_TEXT_COLOUR: - WindowDropdownShowColour(w, widget, TRANSLUCENT(w->colours[1]), static_cast(w->var_492)); - break; - } -} - -/** - * - * rct2: 0x6B979C - */ -static void window_sign_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) -{ - switch (widgetIndex) - { - case WIDX_MAIN_COLOUR: - { - if (dropdownIndex == -1) - return; - w->list_information_type = dropdownIndex; - auto signSetStyleAction = SignSetStyleAction(w->number, dropdownIndex, w->var_492, true); - GameActions::Execute(&signSetStyleAction); - break; - } - case WIDX_TEXT_COLOUR: - { - if (dropdownIndex == -1) - return; - w->var_492 = dropdownIndex; - auto signSetStyleAction = SignSetStyleAction(w->number, w->list_information_type, dropdownIndex, true); - GameActions::Execute(&signSetStyleAction); - break; - } - default: - return; - } - - w->Invalidate(); -} - -/** - * - * rct2: 0x6B9791, 0x6E6171 - */ -static void window_sign_textinput(rct_window* w, rct_widgetindex widgetIndex, char* text) -{ - if (widgetIndex == WIDX_SIGN_TEXT && text != nullptr) - { - auto signSetNameAction = SignSetNameAction(w->number, text); - GameActions::Execute(&signSetNameAction); - } -} - -/** - * - * rct2: 0x006B96F5 - */ -static void window_sign_invalidate(rct_window* w) -{ - rct_widget* main_colour_btn = &window_sign_widgets[WIDX_MAIN_COLOUR]; - rct_widget* text_colour_btn = &window_sign_widgets[WIDX_TEXT_COLOUR]; - - rct_scenery_entry* scenery_entry = get_large_scenery_entry(w->SceneryEntry); - - main_colour_btn->type = WindowWidgetType::Empty; - text_colour_btn->type = WindowWidgetType::Empty; - - if (scenery_entry->large_scenery.flags & LARGE_SCENERY_FLAG_HAS_PRIMARY_COLOUR) - { - main_colour_btn->type = WindowWidgetType::ColourBtn; - } - if (scenery_entry->large_scenery.flags & LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR) - { - text_colour_btn->type = WindowWidgetType::ColourBtn; - } - - main_colour_btn->image = SPRITE_ID_PALETTE_COLOUR_1(w->list_information_type) | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN; - text_colour_btn->image = SPRITE_ID_PALETTE_COLOUR_1(w->var_492) | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN; -} - -/** - * - * rct2: 0x006B9754, 0x006E6134 - */ -static void window_sign_paint(rct_window* w, rct_drawpixelinfo* dpi) -{ - WindowDrawWidgets(w, dpi); - - // Draw viewport - if (w->viewport != nullptr) - { - window_draw_viewport(dpi, w); - } -} - -/** - * - * rct2: 0x6B9A6C, 0x6E6424 - */ -static void window_sign_viewport_rotate(rct_window* w) -{ - w->RemoveViewport(); - - auto banner = GetBanner(w->number); - - auto signViewPos = CoordsXYZ{ banner->position.ToCoordsXY().ToTileCentre(), w->frame_no }; - - // Create viewport - rct_widget* viewportWidget = &window_sign_widgets[WIDX_VIEWPORT]; - viewport_create( - w, w->windowPos + ScreenCoordsXY{ viewportWidget->left + 1, viewportWidget->top + 1 }, viewportWidget->width() - 1, - viewportWidget->height() - 1, 0, signViewPos, 0, SPRITE_INDEX_NULL); - if (w->viewport != nullptr) - w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0; - w->Invalidate(); -} - /** * * rct2: 0x6E5F52 */ rct_window* window_sign_small_open(rct_windownumber number) { - rct_window* w; - rct_widget* viewportWidget; + auto* w = static_cast(window_bring_to_front_by_number(WC_BANNER, number)); - // Check if window is already open - w = window_bring_to_front_by_number(WC_BANNER, number); if (w != nullptr) return w; - w = WindowCreateAutoPos(WW, WH, &window_sign_small_events, WC_BANNER, 0); - w->widgets = window_sign_widgets; - w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_SIGN_TEXT) | (1 << WIDX_SIGN_DEMOLISH) | (1 << WIDX_MAIN_COLOUR) - | (1 << WIDX_TEXT_COLOUR); + w = WindowCreate(WC_BANNER, WW, WH, 0); - w->number = number; - WindowInitScrollWidgets(w); - w->colours[0] = COLOUR_DARK_BROWN; - w->colours[1] = COLOUR_DARK_BROWN; - w->colours[2] = COLOUR_DARK_BROWN; - - auto banner = GetBanner(w->number); - auto signViewPos = banner->position.ToCoordsXY().ToTileCentre(); - - TileElement* tile_element = map_get_first_element_at(signViewPos); - if (tile_element == nullptr) + if (w == nullptr) return nullptr; - while (1) - { - if (tile_element->GetType() == TILE_ELEMENT_TYPE_WALL) - { - rct_scenery_entry* scenery_entry = tile_element->AsWall()->GetEntry(); - if (scenery_entry->wall.scrolling_mode != SCROLLING_MODE_NONE) - { - if (tile_element->AsWall()->GetBannerIndex() == w->number) - break; - } - } - tile_element++; - } - - int32_t view_z = tile_element->GetBaseZ(); - w->frame_no = view_z; - - w->list_information_type = tile_element->AsWall()->GetPrimaryColour(); - w->var_492 = tile_element->AsWall()->GetSecondaryColour(); - w->SceneryEntry = tile_element->AsWall()->GetEntryIndex(); - - // Create viewport - viewportWidget = &window_sign_widgets[WIDX_VIEWPORT]; - viewport_create( - w, w->windowPos + ScreenCoordsXY{ viewportWidget->left + 1, viewportWidget->top + 1 }, viewportWidget->width() - 1, - viewportWidget->height() - 1, 0, { signViewPos, view_z }, 0, SPRITE_INDEX_NULL); - - w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0; - w->flags |= WF_NO_SCROLLING; - w->Invalidate(); + bool result = w->Initialize(number, true); + if (result != true) + return nullptr; return w; } - -/** - * - * rct2: 0x6E6145 - */ -static void window_sign_small_mouseup(rct_window* w, rct_widgetindex widgetIndex) -{ - switch (widgetIndex) - { - case WIDX_CLOSE: - window_close(w); - break; - case WIDX_SIGN_DEMOLISH: - { - auto banner = GetBanner(w->number); - auto bannerCoords = banner->position.ToCoordsXY(); - auto tile_element = map_get_first_element_at(bannerCoords); - if (tile_element == nullptr) - return; - while (true) - { - if (tile_element->GetType() == TILE_ELEMENT_TYPE_WALL) - { - rct_scenery_entry* scenery_entry = tile_element->AsWall()->GetEntry(); - if (scenery_entry->wall.scrolling_mode != SCROLLING_MODE_NONE) - { - if (tile_element->AsWall()->GetBannerIndex() == w->number) - break; - } - } - tile_element++; - } - CoordsXYZD wallLocation = { bannerCoords, tile_element->GetBaseZ(), tile_element->GetDirection() }; - auto wallRemoveAction = WallRemoveAction(wallLocation); - GameActions::Execute(&wallRemoveAction); - break; - } - case WIDX_SIGN_TEXT: - window_sign_show_text_input(w); - break; - } -} - -/** - * - * rct2: 0x6E617C - */ -static void window_sign_small_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) -{ - switch (widgetIndex) - { - case WIDX_MAIN_COLOUR: - { - if (dropdownIndex == -1) - return; - w->list_information_type = dropdownIndex; - auto signSetStyleAction = SignSetStyleAction(w->number, dropdownIndex, w->var_492, false); - GameActions::Execute(&signSetStyleAction); - break; - } - case WIDX_TEXT_COLOUR: - { - if (dropdownIndex == -1) - return; - w->var_492 = dropdownIndex; - auto signSetStyleAction = SignSetStyleAction(w->number, w->list_information_type, dropdownIndex, false); - GameActions::Execute(&signSetStyleAction); - break; - } - default: - return; - } - - w->Invalidate(); -} - -/** - * - * rct2: 0x006E60D5 - */ -static void window_sign_small_invalidate(rct_window* w) -{ - rct_widget* main_colour_btn = &window_sign_widgets[WIDX_MAIN_COLOUR]; - rct_widget* text_colour_btn = &window_sign_widgets[WIDX_TEXT_COLOUR]; - - rct_scenery_entry* scenery_entry = get_wall_entry(w->SceneryEntry); - - main_colour_btn->type = WindowWidgetType::Empty; - text_colour_btn->type = WindowWidgetType::Empty; - - if (scenery_entry->wall.flags & WALL_SCENERY_HAS_PRIMARY_COLOUR) - { - main_colour_btn->type = WindowWidgetType::ColourBtn; - } - if (scenery_entry->wall.flags & WALL_SCENERY_HAS_SECONDARY_COLOUR) - { - text_colour_btn->type = WindowWidgetType::ColourBtn; - } - - main_colour_btn->image = SPRITE_ID_PALETTE_COLOUR_1(w->list_information_type) | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN; - text_colour_btn->image = SPRITE_ID_PALETTE_COLOUR_1(w->var_492) | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN; -} - -static void window_sign_show_text_input(rct_window* w) -{ - auto banner = GetBanner(w->number); - if (banner != nullptr) - { - auto bannerText = banner->GetText(); - window_text_input_raw_open(w, WIDX_SIGN_TEXT, STR_SIGN_TEXT_TITLE, STR_SIGN_TEXT_PROMPT, bannerText.c_str(), 32); - } -} diff --git a/src/openrct2-ui/windows/Staff.cpp b/src/openrct2-ui/windows/Staff.cpp index d0bead3538..4ad444d416 100644 --- a/src/openrct2-ui/windows/Staff.cpp +++ b/src/openrct2-ui/windows/Staff.cpp @@ -1034,24 +1034,6 @@ void window_staff_overview_tab_paint(rct_window* w, rct_drawpixelinfo* dpi) ebx += eax; gfx_draw_sprite(&clip_dpi, ImageId(ebx, peep->TshirtColour, peep->TrousersColour), screenCoords); - - // If holding a balloon - if (ebx >= 0x2A1D && ebx < 0x2A3D) - { - gfx_draw_sprite(&clip_dpi, ImageId(ebx + 32, peep->BalloonColour), screenCoords); - } - - // If holding umbrella - if (ebx >= 0x2BBD && ebx < 0x2BDD) - { - gfx_draw_sprite(&clip_dpi, ImageId(ebx + 32, peep->UmbrellaColour), screenCoords); - } - - // If wearing hat - if (ebx >= 0x29DD && ebx < 0x29FD) - { - gfx_draw_sprite(&clip_dpi, ImageId(ebx + 32, peep->HatColour), screenCoords); - } } /** diff --git a/src/openrct2-ui/windows/Window.h b/src/openrct2-ui/windows/Window.h index 439d6f1698..1f14dd0289 100644 --- a/src/openrct2-ui/windows/Window.h +++ b/src/openrct2-ui/windows/Window.h @@ -47,6 +47,7 @@ rct_window* window_editor_main_open(); rct_window* window_editor_objective_options_open(); rct_window* window_editor_scenario_options_open(); rct_window* window_footpath_open(); +void window_footpath_reset_selected_path(); rct_window* window_guest_open(Peep* peep); rct_window* window_land_open(); rct_window* window_land_rights_open(); diff --git a/src/openrct2/GameStateSnapshots.cpp b/src/openrct2/GameStateSnapshots.cpp index 1c3a142530..69c065d405 100644 --- a/src/openrct2/GameStateSnapshots.cpp +++ b/src/openrct2/GameStateSnapshots.cpp @@ -197,7 +197,6 @@ struct GameStateSnapshots final : public IGameStateSnapshots { COMPARE_FIELD(SpriteBase, Type); COMPARE_FIELD(SpriteBase, sprite_index); - COMPARE_FIELD(SpriteBase, flags); COMPARE_FIELD(SpriteBase, x); COMPARE_FIELD(SpriteBase, y); COMPARE_FIELD(SpriteBase, z); @@ -219,11 +218,9 @@ struct GameStateSnapshots final : public IGameStateSnapshots COMPARE_FIELD(Peep, NextLoc.y); COMPARE_FIELD(Peep, NextLoc.z); COMPARE_FIELD(Peep, NextFlags); - COMPARE_FIELD(Peep, OutsideOfPark); COMPARE_FIELD(Peep, State); COMPARE_FIELD(Peep, SubState); COMPARE_FIELD(Peep, SpriteType); - COMPARE_FIELD(Peep, GuestNumRides); COMPARE_FIELD(Peep, TshirtColour); COMPARE_FIELD(Peep, TrousersColour); COMPARE_FIELD(Peep, DestinationX); @@ -232,27 +229,8 @@ struct GameStateSnapshots final : public IGameStateSnapshots COMPARE_FIELD(Peep, Var37); COMPARE_FIELD(Peep, Energy); COMPARE_FIELD(Peep, EnergyTarget); - COMPARE_FIELD(Peep, Happiness); - COMPARE_FIELD(Peep, HappinessTarget); - COMPARE_FIELD(Peep, Nausea); - COMPARE_FIELD(Peep, NauseaTarget); - COMPARE_FIELD(Peep, Hunger); - COMPARE_FIELD(Peep, Thirst); - COMPARE_FIELD(Peep, Toilet); COMPARE_FIELD(Peep, Mass); - COMPARE_FIELD(Peep, TimeToConsume); - COMPARE_FIELD(Peep, Intensity); - COMPARE_FIELD(Peep, NauseaTolerance); COMPARE_FIELD(Peep, WindowInvalidateFlags); - COMPARE_FIELD(Peep, PaidOnDrink); - for (int i = 0; i < 16; i++) - { - COMPARE_FIELD(Peep, RideTypesBeenOn[i]); - } - COMPARE_FIELD(Peep, ItemFlags); - COMPARE_FIELD(Peep, Photo2RideRef); - COMPARE_FIELD(Peep, Photo3RideRef); - COMPARE_FIELD(Peep, Photo4RideRef); COMPARE_FIELD(Peep, CurrentRide); COMPARE_FIELD(Peep, CurrentRideStation); COMPARE_FIELD(Peep, CurrentTrain); @@ -264,58 +242,102 @@ struct GameStateSnapshots final : public IGameStateSnapshots COMPARE_FIELD(Peep, Action); COMPARE_FIELD(Peep, ActionFrame); COMPARE_FIELD(Peep, StepProgress); - COMPARE_FIELD(Peep, GuestNextInQueue); COMPARE_FIELD(Peep, MazeLastEdge); COMPARE_FIELD(Peep, InteractionRideIndex); - COMPARE_FIELD(Peep, TimeInQueue); - for (int i = 0; i < 32; i++) - { - COMPARE_FIELD(Peep, RidesBeenOn[i]); - } COMPARE_FIELD(Peep, Id); - COMPARE_FIELD(Peep, CashInPocket); - COMPARE_FIELD(Peep, CashSpent); - COMPARE_FIELD(Peep, ParkEntryTime); - COMPARE_FIELD(Peep, RejoinQueueTimeout); - COMPARE_FIELD(Peep, PreviousRide); - COMPARE_FIELD(Peep, PreviousRideTimeOut); - for (int i = 0; i < PEEP_MAX_THOUGHTS; i++) - { - COMPARE_FIELD(Peep, Thoughts[i]); - } COMPARE_FIELD(Peep, PathCheckOptimisation); - COMPARE_FIELD(Peep, GuestHeadingToRideId); - COMPARE_FIELD(Peep, StaffOrders); - COMPARE_FIELD(Peep, Photo1RideRef); - COMPARE_FIELD(Peep, PeepFlags); COMPARE_FIELD(Peep, PathfindGoal); for (int i = 0; i < 4; i++) { COMPARE_FIELD(Peep, PathfindHistory[i]); } COMPARE_FIELD(Peep, WalkingFrameNum); - COMPARE_FIELD(Peep, LitterCount); - COMPARE_FIELD(Peep, GuestTimeOnRide); - COMPARE_FIELD(Peep, DisgustingCount); - COMPARE_FIELD(Peep, PaidToEnter); - COMPARE_FIELD(Peep, PaidOnRides); - COMPARE_FIELD(Peep, PaidOnFood); - COMPARE_FIELD(Peep, PaidOnSouvenirs); - COMPARE_FIELD(Peep, AmountOfFood); - COMPARE_FIELD(Peep, AmountOfDrinks); - COMPARE_FIELD(Peep, AmountOfSouvenirs); - COMPARE_FIELD(Peep, VandalismSeen); - COMPARE_FIELD(Peep, VoucherType); - COMPARE_FIELD(Peep, VoucherRideId); - COMPARE_FIELD(Peep, SurroundingsThoughtTimeout); - COMPARE_FIELD(Peep, Angriness); - COMPARE_FIELD(Peep, TimeLost); - COMPARE_FIELD(Peep, DaysInQueue); - COMPARE_FIELD(Peep, BalloonColour); - COMPARE_FIELD(Peep, UmbrellaColour); - COMPARE_FIELD(Peep, HatColour); - COMPARE_FIELD(Peep, FavouriteRide); - COMPARE_FIELD(Peep, FavouriteRideRating); + } + + void CompareSpriteDataStaff(const Staff& spriteBase, const Staff& spriteCmp, GameStateSpriteChange_t& changeData) const + { + CompareSpriteDataPeep(spriteBase, spriteCmp, changeData); + + COMPARE_FIELD(Staff, AssignedStaffType); + COMPARE_FIELD(Staff, MechanicTimeSinceCall); + COMPARE_FIELD(Staff, HireDate); + COMPARE_FIELD(Staff, StaffId); + COMPARE_FIELD(Staff, StaffOrders); + COMPARE_FIELD(Staff, StaffMowingTimeout); + COMPARE_FIELD(Staff, StaffRidesFixed); + COMPARE_FIELD(Staff, StaffRidesInspected); + COMPARE_FIELD(Staff, StaffLitterSwept); + COMPARE_FIELD(Staff, StaffBinsEmptied); + } + + void CompareSpriteDataGuest(const Guest& spriteBase, const Guest& spriteCmp, GameStateSpriteChange_t& changeData) const + { + CompareSpriteDataPeep(spriteBase, spriteCmp, changeData); + + COMPARE_FIELD(Guest, OutsideOfPark); + COMPARE_FIELD(Guest, GuestNumRides); + COMPARE_FIELD(Guest, Happiness); + COMPARE_FIELD(Guest, HappinessTarget); + COMPARE_FIELD(Guest, Nausea); + COMPARE_FIELD(Guest, NauseaTarget); + COMPARE_FIELD(Guest, Hunger); + COMPARE_FIELD(Guest, Thirst); + COMPARE_FIELD(Guest, Toilet); + COMPARE_FIELD(Guest, TimeToConsume); + COMPARE_FIELD(Guest, Intensity); + COMPARE_FIELD(Guest, NauseaTolerance); + COMPARE_FIELD(Guest, PaidOnDrink); + for (int i = 0; i < 16; i++) + { + COMPARE_FIELD(Guest, RideTypesBeenOn[i]); + } + COMPARE_FIELD(Guest, ItemFlags); + COMPARE_FIELD(Guest, Photo2RideRef); + COMPARE_FIELD(Guest, Photo3RideRef); + COMPARE_FIELD(Guest, Photo4RideRef); + COMPARE_FIELD(Guest, GuestNextInQueue); + COMPARE_FIELD(Guest, TimeInQueue); + for (int i = 0; i < 32; i++) + { + COMPARE_FIELD(Guest, RidesBeenOn[i]); + } + + COMPARE_FIELD(Guest, CashInPocket); + COMPARE_FIELD(Guest, CashSpent); + COMPARE_FIELD(Guest, ParkEntryTime); + COMPARE_FIELD(Guest, RejoinQueueTimeout); + COMPARE_FIELD(Guest, PreviousRide); + COMPARE_FIELD(Guest, PreviousRideTimeOut); + for (int i = 0; i < PEEP_MAX_THOUGHTS; i++) + { + COMPARE_FIELD(Guest, Thoughts[i]); + } + COMPARE_FIELD(Guest, GuestHeadingToRideId); + COMPARE_FIELD(Guest, GuestIsLostCountdown); + COMPARE_FIELD(Guest, Photo1RideRef); + COMPARE_FIELD(Guest, PeepFlags); + COMPARE_FIELD(Guest, LitterCount); + COMPARE_FIELD(Guest, GuestTimeOnRide); + COMPARE_FIELD(Guest, DisgustingCount); + COMPARE_FIELD(Guest, PaidToEnter); + COMPARE_FIELD(Guest, PaidOnRides); + COMPARE_FIELD(Guest, PaidOnFood); + COMPARE_FIELD(Guest, PaidOnSouvenirs); + COMPARE_FIELD(Guest, AmountOfFood); + COMPARE_FIELD(Guest, AmountOfDrinks); + COMPARE_FIELD(Guest, AmountOfSouvenirs); + COMPARE_FIELD(Guest, VandalismSeen); + COMPARE_FIELD(Guest, VoucherType); + COMPARE_FIELD(Guest, VoucherRideId); + COMPARE_FIELD(Guest, SurroundingsThoughtTimeout); + COMPARE_FIELD(Guest, Angriness); + COMPARE_FIELD(Guest, TimeLost); + COMPARE_FIELD(Guest, DaysInQueue); + COMPARE_FIELD(Guest, BalloonColour); + COMPARE_FIELD(Guest, UmbrellaColour); + COMPARE_FIELD(Guest, HatColour); + COMPARE_FIELD(Guest, FavouriteRide); + COMPARE_FIELD(Guest, FavouriteRideRating); } void CompareSpriteDataVehicle( @@ -392,6 +414,7 @@ struct GameStateSnapshots final : public IGameStateSnapshots COMPARE_FIELD(Vehicle, target_seat_rotation); COMPARE_FIELD(Vehicle, BoatLocation.x); COMPARE_FIELD(Vehicle, BoatLocation.y); + COMPARE_FIELD(Vehicle, IsCrashedVehicle); } void CompareSpriteDataLitter(const Litter& spriteBase, const Litter& spriteCmp, GameStateSpriteChange_t& changeData) const @@ -480,10 +503,12 @@ struct GameStateSnapshots final : public IGameStateSnapshots switch (spriteBase.misc.Type) { case EntityType::Guest: - CompareSpriteDataPeep(spriteBase.peep, spriteCmp.peep, changeData); + CompareSpriteDataGuest( + static_cast(spriteBase.peep), static_cast(spriteCmp.peep), changeData); break; case EntityType::Staff: - CompareSpriteDataPeep(spriteBase.peep, spriteCmp.peep, changeData); + CompareSpriteDataStaff( + static_cast(spriteBase.peep), static_cast(spriteCmp.peep), changeData); break; case EntityType::Vehicle: CompareSpriteDataVehicle(spriteBase.vehicle, spriteCmp.vehicle, changeData); diff --git a/src/openrct2/ParkFile.cpp b/src/openrct2/ParkFile.cpp index dd3de1e043..dbd6eb8133 100644 --- a/src/openrct2/ParkFile.cpp +++ b/src/openrct2/ParkFile.cpp @@ -1093,7 +1093,6 @@ namespace OpenRCT2 { cs.ReadWrite(entity.sprite_index); cs.ReadWrite(entity.sprite_height_negative); - cs.ReadWrite(entity.flags); cs.ReadWrite(entity.x); cs.ReadWrite(entity.y); cs.ReadWrite(entity.z); @@ -1343,6 +1342,7 @@ namespace OpenRCT2 cs.ReadWrite(entity.colours_extended); cs.ReadWrite(entity.seat_rotation); cs.ReadWrite(entity.target_seat_rotation); + cs.ReadWrite(entity.IsCrashedVehicle); } template<> void ParkFile::ReadWriteEntity(OrcaStream::ChunkStream& cs, Guest& entity) diff --git a/src/openrct2/actions/GameActionCompat.cpp b/src/openrct2/actions/GameActionCompat.cpp index 00c45e2090..15c9cc46e2 100644 --- a/src/openrct2/actions/GameActionCompat.cpp +++ b/src/openrct2/actions/GameActionCompat.cpp @@ -33,7 +33,7 @@ money32 park_entrance_place_ghost(const CoordsXYZD& entranceLoc) { park_entrance_remove_ghost(); - auto gameAction = PlaceParkEntranceAction(entranceLoc); + auto gameAction = PlaceParkEntranceAction(entranceLoc, gFootpathSelectedId); gameAction.SetFlags(GAME_COMMAND_FLAG_GHOST); auto result = GameActions::Execute(&gameAction); diff --git a/src/openrct2/actions/PlaceParkEntranceAction.cpp b/src/openrct2/actions/PlaceParkEntranceAction.cpp index 618d63db63..7697d6aa56 100644 --- a/src/openrct2/actions/PlaceParkEntranceAction.cpp +++ b/src/openrct2/actions/PlaceParkEntranceAction.cpp @@ -21,8 +21,9 @@ #include "../world/Sprite.h" #include "../world/Surface.h" -PlaceParkEntranceAction::PlaceParkEntranceAction(const CoordsXYZD& location) +PlaceParkEntranceAction::PlaceParkEntranceAction(const CoordsXYZD& location, ObjectEntryIndex pathType) : _loc(location) + , _pathType(pathType) { } @@ -36,6 +37,7 @@ void PlaceParkEntranceAction::Serialise(DataSerialiser& stream) GameAction::Serialise(stream); stream << DS_TAG(_loc); + stream << DS_TAG(_pathType); } GameActions::Result::Ptr PlaceParkEntranceAction::Query() const diff --git a/src/openrct2/actions/PlaceParkEntranceAction.h b/src/openrct2/actions/PlaceParkEntranceAction.h index 2514d3ae1a..5c251c2bc5 100644 --- a/src/openrct2/actions/PlaceParkEntranceAction.h +++ b/src/openrct2/actions/PlaceParkEntranceAction.h @@ -15,10 +15,11 @@ DEFINE_GAME_ACTION(PlaceParkEntranceAction, GameCommand::PlaceParkEntrance, Game { private: CoordsXYZD _loc; + ObjectEntryIndex _pathType; public: PlaceParkEntranceAction() = default; - PlaceParkEntranceAction(const CoordsXYZD& location); + PlaceParkEntranceAction(const CoordsXYZD& location, ObjectEntryIndex pathType); uint16_t GetActionFlags() const override; diff --git a/src/openrct2/actions/StaffHireNewAction.cpp b/src/openrct2/actions/StaffHireNewAction.cpp index 1055e3e642..49692d4648 100644 --- a/src/openrct2/actions/StaffHireNewAction.cpp +++ b/src/openrct2/actions/StaffHireNewAction.cpp @@ -128,7 +128,7 @@ GameActions::Result::Ptr StaffHireNewAction::QueryExecute(bool execute) const return MakeResult(GameActions::Status::NoFreeElements, STR_TOO_MANY_STAFF_IN_GAME); } - Peep* newPeep = CreateEntity(); + Staff* newPeep = CreateEntity(); if (newPeep == nullptr) { // Too many peeps exist already. @@ -149,13 +149,11 @@ GameActions::Result::Ptr StaffHireNewAction::QueryExecute(bool execute) const newPeep->WalkingFrameNum = 0; newPeep->ActionSpriteType = PeepActionSpriteType::None; newPeep->PathCheckOptimisation = 0; - newPeep->OutsideOfPark = false; newPeep->PeepFlags = 0; - newPeep->PaidToEnter = 0; - newPeep->PaidOnRides = 0; - newPeep->PaidOnFood = 0; - newPeep->PaidOnSouvenirs = 0; - newPeep->FavouriteRide = RIDE_ID_NULL; + newPeep->StaffLawnsMown = 0; + newPeep->StaffGardensWatered = 0; + newPeep->StaffLitterSwept = 0; + newPeep->StaffBinsEmptied = 0; newPeep->StaffOrders = _staffOrders; // We search for the first available Id for a given staff type diff --git a/src/openrct2/actions/TrackDesignAction.cpp b/src/openrct2/actions/TrackDesignAction.cpp index 7c827eaa91..090cfae3aa 100644 --- a/src/openrct2/actions/TrackDesignAction.cpp +++ b/src/openrct2/actions/TrackDesignAction.cpp @@ -261,9 +261,9 @@ GameActions::Result::Ptr TrackDesignAction::Execute() const ride->track_colour[i].supports = _td.track_support_colour[i]; } - for (int32_t i = 0; i <= MAX_VEHICLES_PER_RIDE; i++) + for (size_t i = 0; i <= MAX_VEHICLES_PER_RIDE; i++) { - auto tdIndex = std::min(size_t(i), std::size(_td.vehicle_colours) - 1); + auto tdIndex = std::min(i, std::size(_td.vehicle_colours) - 1); ride->vehicle_colours[i].Body = _td.vehicle_colours[tdIndex].body_colour; ride->vehicle_colours[i].Trim = _td.vehicle_colours[tdIndex].trim_colour; ride->vehicle_colours[i].Ternary = _td.vehicle_additional_colour[tdIndex]; diff --git a/src/openrct2/core/FileStream.cpp b/src/openrct2/core/FileStream.cpp index 3a1ff1654b..dd5473d0cd 100644 --- a/src/openrct2/core/FileStream.cpp +++ b/src/openrct2/core/FileStream.cpp @@ -13,6 +13,7 @@ #include "String.hpp" #include +#include #ifndef _WIN32 # include @@ -40,6 +41,11 @@ namespace OpenRCT2 { } + FileStream::FileStream(std::string_view path, int32_t fileMode) + : FileStream(std::string(path), fileMode) + { + } + FileStream::FileStream(const utf8* path, int32_t fileMode) { const char* mode; diff --git a/src/openrct2/core/FileStream.h b/src/openrct2/core/FileStream.h index d9fdcffd3d..572bd80c55 100644 --- a/src/openrct2/core/FileStream.h +++ b/src/openrct2/core/FileStream.h @@ -38,6 +38,7 @@ namespace OpenRCT2 public: FileStream(const fs::path& path, int32_t fileMode); FileStream(const std::string& path, int32_t fileMode); + FileStream(std::string_view path, int32_t fileMode); FileStream(const utf8* path, int32_t fileMode); ~FileStream() override; diff --git a/src/openrct2/management/Marketing.cpp b/src/openrct2/management/Marketing.cpp index 39d086e226..f458ea23e4 100644 --- a/src/openrct2/management/Marketing.cpp +++ b/src/openrct2/management/Marketing.cpp @@ -127,7 +127,7 @@ void marketing_update() window_invalidate_by_class(WC_FINANCES); } -void marketing_set_guest_campaign(Peep* peep, int32_t campaignType) +void marketing_set_guest_campaign(Guest* peep, int32_t campaignType) { auto campaign = marketing_get_campaign(campaignType); if (campaign == nullptr) diff --git a/src/openrct2/management/Marketing.h b/src/openrct2/management/Marketing.h index c74e51e6c3..7c0a13f422 100644 --- a/src/openrct2/management/Marketing.h +++ b/src/openrct2/management/Marketing.h @@ -63,7 +63,7 @@ extern std::vector gMarketingCampaigns; uint16_t marketing_get_campaign_guest_generation_probability(int32_t campaign); void marketing_update(); -void marketing_set_guest_campaign(Peep* peep, int32_t campaign); +void marketing_set_guest_campaign(Guest* peep, int32_t campaign); bool marketing_is_campaign_type_applicable(int32_t campaignType); MarketingCampaign* marketing_get_campaign(int32_t campaignType); void marketing_new_campaign(const MarketingCampaign& campaign); diff --git a/src/openrct2/network/NetworkBase.cpp b/src/openrct2/network/NetworkBase.cpp index f8ecdadbf0..d894cfaec9 100644 --- a/src/openrct2/network/NetworkBase.cpp +++ b/src/openrct2/network/NetworkBase.cpp @@ -39,7 +39,7 @@ // This string specifies which version of network stream current build uses. // It is used for making sure only compatible builds get connected, even within // single OpenRCT2 version. -#define NETWORK_STREAM_VERSION "10" +#define NETWORK_STREAM_VERSION "13" #define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION static Peep* _pickup_peep = nullptr; diff --git a/src/openrct2/paint/sprite/Paint.Peep.cpp b/src/openrct2/paint/sprite/Paint.Peep.cpp index f330c5ff40..db04c2f376 100644 --- a/src/openrct2/paint/sprite/Paint.Peep.cpp +++ b/src/openrct2/paint/sprite/Paint.Peep.cpp @@ -82,25 +82,28 @@ template<> void PaintEntity(paint_session* session, const Peep* peep, int32_t im uint32_t imageId = baseImageId | peep->TshirtColour << 19 | peep->TrousersColour << 24 | IMAGE_TYPE_REMAP | IMAGE_TYPE_REMAP_2_PLUS; PaintAddImageAsParent(session, imageId, 0, 0, 1, 1, 11, peep->z, 0, 0, peep->z + 5); - - if (baseImageId >= 10717 && baseImageId < 10749) + auto* guest = peep->As(); + if (guest != nullptr) { - imageId = (baseImageId + 32) | peep->HatColour << 19 | IMAGE_TYPE_REMAP; - PaintAddImageAsChild(session, imageId, 0, 0, 1, 1, 11, peep->z, 0, 0, peep->z + 5); - return; - } + if (baseImageId >= 10717 && baseImageId < 10749) + { + imageId = (baseImageId + 32) | guest->HatColour << 19 | IMAGE_TYPE_REMAP; + PaintAddImageAsChild(session, imageId, 0, 0, 1, 1, 11, peep->z, 0, 0, peep->z + 5); + return; + } - if (baseImageId >= 10781 && baseImageId < 10813) - { - imageId = (baseImageId + 32) | peep->BalloonColour << 19 | IMAGE_TYPE_REMAP; - PaintAddImageAsChild(session, imageId, 0, 0, 1, 1, 11, peep->z, 0, 0, peep->z + 5); - return; - } + if (baseImageId >= 10781 && baseImageId < 10813) + { + imageId = (baseImageId + 32) | guest->BalloonColour << 19 | IMAGE_TYPE_REMAP; + PaintAddImageAsChild(session, imageId, 0, 0, 1, 1, 11, peep->z, 0, 0, peep->z + 5); + return; + } - if (baseImageId >= 11197 && baseImageId < 11229) - { - imageId = (baseImageId + 32) | peep->UmbrellaColour << 19 | IMAGE_TYPE_REMAP; - PaintAddImageAsChild(session, imageId, 0, 0, 1, 1, 11, peep->z, 0, 0, peep->z + 5); - return; + if (baseImageId >= 11197 && baseImageId < 11229) + { + imageId = (baseImageId + 32) | guest->UmbrellaColour << 19 | IMAGE_TYPE_REMAP; + PaintAddImageAsChild(session, imageId, 0, 0, 1, 1, 11, peep->z, 0, 0, peep->z + 5); + return; + } } } diff --git a/src/openrct2/peep/Guest.cpp b/src/openrct2/peep/Guest.cpp index ac18ced5e9..dd275f0015 100644 --- a/src/openrct2/peep/Guest.cpp +++ b/src/openrct2/peep/Guest.cpp @@ -26,6 +26,8 @@ #include "../ride/Station.h" #include "../ride/Track.h" #include "../scenario/Scenario.h" +#include "../scripting/HookEngine.h" +#include "../scripting/ScriptEngine.h" #include "../util/Util.h" #include "../windows/Intent.h" #include "../world/Climate.h" @@ -204,28 +206,219 @@ static constexpr const char *gPeepEasterEggNames[] = { "DAVID ELLIS" }; +// Flags used by PeepThoughtToActionMap +enum PeepThoughtToActionFlag : uint8_t +{ + PEEP_THOUGHT_ACTION_NO_FLAGS = 0, + PEEP_THOUGHT_ACTION_FLAG_RIDE = (1 << 0), + PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_SINGULAR = (1 << 1), + PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_INDEFINITE = (1 << 2), +}; + +/** rct2: 0x00981DB0 */ +static struct +{ + PeepActionType action; + PeepThoughtToActionFlag flags; +} PeepThoughtToActionMap[] = { + { PeepActionType::ShakeHead, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::EmptyPockets, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::Wow, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_SINGULAR }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_INDEFINITE }, + { PeepActionType::ShakeHead, PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_INDEFINITE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::Wave, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::Joy, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::CheckTime, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::Wave, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::Wave, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::Disgust, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::BeingWatched, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::ShakeHead, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::Joy, PEEP_THOUGHT_ACTION_NO_FLAGS }, + { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, +}; + // These arrays contain the base minimum and maximum nausea ratings for peeps, based on their nausea tolerance level. static constexpr const ride_rating NauseaMinimumThresholds[] = { 0, 0, 200, 400 }; // clang-format on -static bool peep_has_voucher_for_free_ride(Peep* peep, Ride* ride); +static bool peep_has_voucher_for_free_ride(Guest* peep, Ride* ride); static void peep_ride_is_too_intense(Guest* peep, Ride* ride, bool peepAtRide); -static void peep_reset_ride_heading(Peep* peep); -static void peep_tried_to_enter_full_queue(Peep* peep, Ride* ride); +static void peep_reset_ride_heading(Guest* peep); +static void peep_tried_to_enter_full_queue(Guest* peep, Ride* ride); static int16_t peep_calculate_ride_satisfaction(Guest* peep, Ride* ride); -static void peep_update_favourite_ride(Peep* peep, Ride* ride); -static int16_t peep_calculate_ride_value_satisfaction(Peep* peep, Ride* ride); -static int16_t peep_calculate_ride_intensity_nausea_satisfaction(Peep* peep, Ride* ride); -static void peep_update_ride_nausea_growth(Peep* peep, Ride* ride); -static bool peep_should_go_on_ride_again(Peep* peep, Ride* ride); -static bool peep_should_preferred_intensity_increase(Peep* peep); -static bool peep_really_liked_ride(Peep* peep, Ride* ride); +static void peep_update_favourite_ride(Guest* peep, Ride* ride); +static int16_t peep_calculate_ride_value_satisfaction(Guest* peep, Ride* ride); +static int16_t peep_calculate_ride_intensity_nausea_satisfaction(Guest* peep, Ride* ride); +static void peep_update_ride_nausea_growth(Guest* peep, Ride* ride); +static bool peep_should_go_on_ride_again(Guest* peep, Ride* ride); +static bool peep_should_preferred_intensity_increase(Guest* peep); +static bool peep_really_liked_ride(Guest* peep, Ride* ride); static PeepThoughtType peep_assess_surroundings(int16_t centre_x, int16_t centre_y, int16_t centre_z); -static void peep_update_hunger(Peep* peep); -static void peep_decide_whether_to_leave_park(Peep* peep); -static void peep_leave_park(Peep* peep); +static void peep_update_hunger(Guest* peep); +static void peep_decide_whether_to_leave_park(Guest* peep); +static void peep_leave_park(Guest* peep); static void peep_head_for_nearest_ride_type(Guest* peep, int32_t rideType); static void peep_head_for_nearest_ride_with_flags(Guest* peep, int32_t rideTypeFlags); bool loc_690FD0(Peep* peep, ride_id_t* rideToView, uint8_t* rideSeatToView, TileElement* tileElement); @@ -1747,7 +1940,7 @@ bool Guest::ShouldGoOnRide(Ride* ride, int32_t entranceNum, bool atQueue, bool t else { // Check if there's room in the queue for the peep to enter. - Peep* lastPeepInQueue = GetEntity(ride->stations[entranceNum].LastPeepInQueue); + Guest* lastPeepInQueue = GetEntity(ride->stations[entranceNum].LastPeepInQueue); if (lastPeepInQueue != nullptr && (abs(lastPeepInQueue->z - z) <= 6)) { int32_t dx = abs(lastPeepInQueue->x - x); @@ -2153,7 +2346,7 @@ void Guest::ReadMap() } } -static bool peep_has_voucher_for_free_ride(Peep* peep, Ride* ride) +static bool peep_has_voucher_for_free_ride(Guest* peep, Ride* ride) { return peep->HasItem(ShopItem::Voucher) && peep->VoucherType == VOUCHER_TYPE_RIDE_FREE && peep->VoucherRideId == ride->id; } @@ -2163,7 +2356,7 @@ static bool peep_has_voucher_for_free_ride(Peep* peep, Ride* ride) * Does not effect peeps that walk up to the queue entrance. * This flag is reset the next time a peep successfully joins the queue. */ -static void peep_tried_to_enter_full_queue(Peep* peep, Ride* ride) +static void peep_tried_to_enter_full_queue(Guest* peep, Ride* ride) { ride->lifecycle_flags |= RIDE_LIFECYCLE_QUEUE_FULL; peep->PreviousRide = ride->id; @@ -2175,7 +2368,7 @@ static void peep_tried_to_enter_full_queue(Peep* peep, Ride* ride) } } -static void peep_reset_ride_heading(Peep* peep) +static void peep_reset_ride_heading(Guest* peep) { peep->GuestHeadingToRideId = RIDE_ID_NULL; peep->WindowInvalidateFlags |= PEEP_INVALIDATE_PEEP_ACTION; @@ -2448,7 +2641,7 @@ static int16_t peep_calculate_ride_satisfaction(Guest* peep, Ride* ride) * the ride becomes the peep's favourite. (This doesn't happen right away, but will be updated once the peep * exits the ride.) */ -static void peep_update_favourite_ride(Peep* peep, Ride* ride) +static void peep_update_favourite_ride(Guest* peep, Ride* ride) { peep->PeepFlags &= ~PEEP_FLAGS_RIDE_SHOULD_BE_MARKED_AS_FAVOURITE; uint8_t peepRideRating = std::clamp((ride->excitement / 4) + peep->Happiness, 0, PEEP_MAX_HAPPINESS); @@ -2463,7 +2656,7 @@ static void peep_update_favourite_ride(Peep* peep, Ride* ride) } /* rct2: 0x00695555 */ -static int16_t peep_calculate_ride_value_satisfaction(Peep* peep, Ride* ride) +static int16_t peep_calculate_ride_value_satisfaction(Guest* peep, Ride* ride) { if (gParkFlags & PARK_FLAGS_NO_MONEY) { @@ -2495,7 +2688,7 @@ static int16_t peep_calculate_ride_value_satisfaction(Peep* peep, Ride* ride) * of the ride fall exactly within the peep's preferences, but lower scores can still be achieved * if the peep's happiness is enough to offset it. */ -static int16_t peep_calculate_ride_intensity_nausea_satisfaction(Peep* peep, Ride* ride) +static int16_t peep_calculate_ride_intensity_nausea_satisfaction(Guest* peep, Ride* ride) { if (!ride_has_ratings(ride)) { @@ -2595,7 +2788,7 @@ static int16_t peep_calculate_ride_intensity_nausea_satisfaction(Peep* peep, Rid * - How hungry the peep is (+0% nausea at 50% hunger up to +100% nausea at 100% hunger) * - The peep's nausea tolerance (Final modifier: none: 100%, low: 50%, average: 25%, high: 12.5%) */ -static void peep_update_ride_nausea_growth(Peep* peep, Ride* ride) +static void peep_update_ride_nausea_growth(Guest* peep, Ride* ride) { uint32_t nauseaMultiplier = std::clamp(256 - peep->HappinessTarget, 64, 200); uint32_t nauseaGrowthRateChange = (ride->nausea * nauseaMultiplier) / 512; @@ -2604,7 +2797,7 @@ static void peep_update_ride_nausea_growth(Peep* peep, Ride* ride) peep->NauseaTarget = static_cast(std::min(peep->NauseaTarget + nauseaGrowthRateChange, 255u)); } -static bool peep_should_go_on_ride_again(Peep* peep, Ride* ride) +static bool peep_should_go_on_ride_again(Guest* peep, Ride* ride) { if (!ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_PEEP_WILL_RIDE_AGAIN)) return false; @@ -2637,7 +2830,7 @@ static bool peep_should_go_on_ride_again(Peep* peep, Ride* ride) return true; } -static bool peep_should_preferred_intensity_increase(Peep* peep) +static bool peep_should_preferred_intensity_increase(Guest* peep) { if (gParkFlags & PARK_FLAGS_PREF_LESS_INTENSE_RIDES) return false; @@ -2647,7 +2840,7 @@ static bool peep_should_preferred_intensity_increase(Peep* peep) return (scenario_rand() & 0xFF) >= static_cast(peep->Intensity); } -static bool peep_really_liked_ride(Peep* peep, Ride* ride) +static bool peep_really_liked_ride(Guest* peep, Ride* ride) { if (peep->Happiness < 215) return false; @@ -2779,7 +2972,7 @@ static PeepThoughtType peep_assess_surroundings(int16_t centre_x, int16_t centre * * rct2: 0x0068F9A9 */ -static void peep_update_hunger(Peep* peep) +static void peep_update_hunger(Guest* peep) { if (peep->Hunger >= 3) { @@ -2796,7 +2989,7 @@ static void peep_update_hunger(Peep* peep) * * rct2: 0x0068F8CD */ -static void peep_decide_whether_to_leave_park(Peep* peep) +static void peep_decide_whether_to_leave_park(Guest* peep) { if (peep->EnergyTarget >= 33) { @@ -2848,7 +3041,7 @@ static void peep_decide_whether_to_leave_park(Peep* peep) * * rct2: 0x0068F93E */ -static void peep_leave_park(Peep* peep) +static void peep_leave_park(Guest* peep) { peep->GuestHeadingToRideId = RIDE_ID_NULL; if (peep->PeepFlags & PEEP_FLAGS_LEAVING_PARK) @@ -3051,7 +3244,7 @@ void Guest::StopPurchaseThought(uint8_t ride_type) * * rct2: 0x0069AEB7 */ -static bool peep_should_use_cash_machine(Peep* peep, ride_id_t rideIndex) +static bool peep_should_use_cash_machine(Guest* peep, ride_id_t rideIndex) { if (gParkFlags & PARK_FLAGS_NO_MONEY) return false; @@ -3635,7 +3828,7 @@ void Guest::UpdateRideFreeVehicleEnterRide(Ride* ride) * * rct2: 0x00691FD4 */ -static void peep_update_ride_no_free_vehicle_rejoin_queue(Peep* peep, Ride* ride) +static void peep_update_ride_no_free_vehicle_rejoin_queue(Guest* peep, Ride* ride) { TileCoordsXYZD entranceLocation = ride_get_entrance_location(ride, peep->CurrentRideStation); @@ -4955,7 +5148,7 @@ void Guest::UpdateRide() } } -static void peep_update_walking_break_scenery(Peep* peep); +static void peep_update_walking_break_scenery(Guest* peep); static bool peep_find_ride_to_look_at(Peep* peep, uint8_t edge, ride_id_t* rideToView, uint8_t* rideSeatToView); /** @@ -5846,7 +6039,7 @@ static PathElement* FindBreakableElement(const CoordsXYZ& loc) * * rct2: 0x00690848 */ -static void peep_update_walking_break_scenery(Peep* peep) +static void peep_update_walking_break_scenery(Guest* peep) { if (gCheatsDisableVandalism) return; @@ -6553,3 +6746,597 @@ bool Guest::HeadingForRideOrParkExit() const { return (PeepFlags & PEEP_FLAGS_LEAVING_PARK) || (GuestHeadingToRideId != RIDE_ID_NULL); } + +/** + * rct2: 0x00698342 + * thought.item (eax) + * thought.type (ebx) + * argument_1 (esi & ebx) + * argument_2 (esi+2) + */ +void peep_thought_set_format_args(const rct_peep_thought* thought, Formatter& ft) +{ + ft.Add(PeepThoughts[EnumValue(thought->type)]); + + PeepThoughtToActionFlag flags = PeepThoughtToActionMap[EnumValue(thought->type)].flags; + if (flags & PEEP_THOUGHT_ACTION_FLAG_RIDE) + { + auto ride = get_ride(thought->item); + if (ride != nullptr) + { + ride->FormatNameTo(ft); + } + else + { + ft.Add(STR_NONE); + } + } + else if (flags & PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_SINGULAR) + { + ft.Add(GetShopItemDescriptor(ShopItem(thought->item)).Naming.Singular); + } + else if (flags & PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_INDEFINITE) + { + ft.Add(GetShopItemDescriptor(ShopItem(thought->item)).Naming.Indefinite); + } +} + +/** + * + * rct2: 0x699F5A + * al:thoughtType + * ah:thoughtArguments + * esi: peep + */ +void Guest::InsertNewThought(PeepThoughtType thoughtType, uint8_t thoughtArguments) +{ + PeepActionType newAction = PeepThoughtToActionMap[EnumValue(thoughtType)].action; + if (newAction != PeepActionType::None2 && this->Action >= PeepActionType::None1) + { + Action = newAction; + ActionFrame = 0; + ActionSpriteImageOffset = 0; + UpdateCurrentActionSpriteType(); + } + + for (int32_t i = 0; i < PEEP_MAX_THOUGHTS; ++i) + { + rct_peep_thought* thought = &Thoughts[i]; + // Remove the oldest thought by setting it to NONE. + if (thought->type == PeepThoughtType::None) + break; + + if (thought->type == thoughtType && thought->item == thoughtArguments) + { + // If the thought type has not changed then we need to move + // it to the top of the thought list. This is done by first removing the + // existing thought and placing it at the top. + if (i < PEEP_MAX_THOUGHTS - 2) + { + memmove(thought, thought + 1, sizeof(rct_peep_thought) * (PEEP_MAX_THOUGHTS - i - 1)); + } + break; + } + } + + memmove(&Thoughts[1], &Thoughts[0], sizeof(rct_peep_thought) * (PEEP_MAX_THOUGHTS - 1)); + + Thoughts[0].type = thoughtType; + Thoughts[0].item = thoughtArguments; + Thoughts[0].freshness = 0; + Thoughts[0].fresh_timeout = 0; + + WindowInvalidateFlags |= PEEP_INVALIDATE_PEEP_THOUGHTS; +} + +// clang-format off +/** rct2: 0x009823A0 */ +static constexpr const PeepNauseaTolerance nausea_tolerance_distribution[] = { + PeepNauseaTolerance::None, + PeepNauseaTolerance::Low, PeepNauseaTolerance::Low, + PeepNauseaTolerance::Average, PeepNauseaTolerance::Average, PeepNauseaTolerance::Average, + PeepNauseaTolerance::High, PeepNauseaTolerance::High, PeepNauseaTolerance::High, PeepNauseaTolerance::High, PeepNauseaTolerance::High, PeepNauseaTolerance::High, +}; + +/** rct2: 0x009823BC */ +static constexpr const uint8_t trouser_colours[] = { + COLOUR_BLACK, + COLOUR_GREY, + COLOUR_LIGHT_BROWN, + COLOUR_SATURATED_BROWN, + COLOUR_DARK_BROWN, + COLOUR_SALMON_PINK, + COLOUR_BLACK, + COLOUR_GREY, + COLOUR_LIGHT_BROWN, + COLOUR_SATURATED_BROWN, + COLOUR_DARK_BROWN, + COLOUR_SALMON_PINK, + COLOUR_BLACK, + COLOUR_GREY, + COLOUR_LIGHT_BROWN, + COLOUR_SATURATED_BROWN, + COLOUR_DARK_BROWN, + COLOUR_SALMON_PINK, + COLOUR_DARK_PURPLE, + COLOUR_LIGHT_PURPLE, + COLOUR_DARK_BLUE, + COLOUR_SATURATED_GREEN, + COLOUR_SATURATED_RED, + COLOUR_DARK_ORANGE, + COLOUR_BORDEAUX_RED, +}; + +/** rct2: 0x009823D5 */ +static constexpr const uint8_t tshirt_colours[] = { + COLOUR_BLACK, + COLOUR_GREY, + COLOUR_LIGHT_BROWN, + COLOUR_SATURATED_BROWN, + COLOUR_DARK_BROWN, + COLOUR_SALMON_PINK, + COLOUR_BLACK, + COLOUR_GREY, + COLOUR_LIGHT_BROWN, + COLOUR_SATURATED_BROWN, + COLOUR_DARK_BROWN, + COLOUR_SALMON_PINK, + COLOUR_DARK_PURPLE, + COLOUR_LIGHT_PURPLE, + COLOUR_DARK_BLUE, + COLOUR_SATURATED_GREEN, + COLOUR_SATURATED_RED, + COLOUR_DARK_ORANGE, + COLOUR_BORDEAUX_RED, + COLOUR_WHITE, + COLOUR_BRIGHT_PURPLE, + COLOUR_LIGHT_BLUE, + COLOUR_TEAL, + COLOUR_DARK_GREEN, + COLOUR_MOSS_GREEN, + COLOUR_BRIGHT_GREEN, + COLOUR_OLIVE_GREEN, + COLOUR_DARK_OLIVE_GREEN, + COLOUR_YELLOW, + COLOUR_LIGHT_ORANGE, + COLOUR_BRIGHT_RED, + COLOUR_DARK_PINK, + COLOUR_BRIGHT_PINK, +}; +// clang-format on + +/** + * + * rct2: 0x0069A05D + */ +Guest* Guest::Generate(const CoordsXYZ& coords) +{ + if (GetNumFreeEntities() < 400) + return nullptr; + + Guest* peep = CreateEntity(); + peep->SpriteType = PeepSpriteType::Normal; + peep->OutsideOfPark = true; + peep->State = PeepState::Falling; + peep->Action = PeepActionType::None2; + peep->SpecialSprite = 0; + peep->ActionSpriteImageOffset = 0; + peep->WalkingFrameNum = 0; + peep->ActionSpriteType = PeepActionSpriteType::None; + peep->PeepFlags = 0; + peep->FavouriteRide = RIDE_ID_NULL; + peep->FavouriteRideRating = 0; + + const rct_sprite_bounds* spriteBounds = &GetSpriteBounds(peep->SpriteType, peep->ActionSpriteType); + peep->sprite_width = spriteBounds->sprite_width; + peep->sprite_height_negative = spriteBounds->sprite_height_negative; + peep->sprite_height_positive = spriteBounds->sprite_height_positive; + + peep->MoveTo(coords); + peep->sprite_direction = 0; + peep->Mass = (scenario_rand() & 0x1F) + 45; + peep->PathCheckOptimisation = 0; + peep->InteractionRideIndex = RIDE_ID_NULL; + peep->PreviousRide = RIDE_ID_NULL; + peep->Thoughts->type = PeepThoughtType::None; + peep->WindowInvalidateFlags = 0; + + uint8_t intensityHighest = (scenario_rand() & 0x7) + 3; + uint8_t intensityLowest = std::min(intensityHighest, static_cast(7)) - 3; + + if (intensityHighest >= 7) + intensityHighest = 15; + + /* Check which intensity boxes are enabled + * and apply the appropriate intensity settings. */ + if (gParkFlags & PARK_FLAGS_PREF_LESS_INTENSE_RIDES) + { + if (gParkFlags & PARK_FLAGS_PREF_MORE_INTENSE_RIDES) + { + intensityLowest = 0; + intensityHighest = 15; + } + else + { + intensityLowest = 0; + intensityHighest = 4; + } + } + else if (gParkFlags & PARK_FLAGS_PREF_MORE_INTENSE_RIDES) + { + intensityLowest = 9; + intensityHighest = 15; + } + + peep->Intensity = IntensityRange(intensityLowest, intensityHighest); + + uint8_t nauseaTolerance = scenario_rand() & 0x7; + if (gParkFlags & PARK_FLAGS_PREF_MORE_INTENSE_RIDES) + { + nauseaTolerance += 4; + } + + peep->NauseaTolerance = nausea_tolerance_distribution[nauseaTolerance]; + + /* Scenario editor limits initial guest happiness to between 37..253. + * To be on the safe side, assume the value could have been hacked + * to any value 0..255. */ + peep->Happiness = gGuestInitialHappiness; + /* Assume a default initial happiness of 0 is wrong and set + * to 128 (50%) instead. */ + if (gGuestInitialHappiness == 0) + peep->Happiness = 128; + /* Initial value will vary by -15..16 */ + int8_t happinessDelta = (scenario_rand() & 0x1F) - 15; + /* Adjust by the delta, clamping at min=0 and max=255. */ + peep->Happiness = std::clamp(peep->Happiness + happinessDelta, 0, PEEP_MAX_HAPPINESS); + peep->HappinessTarget = peep->Happiness; + peep->Nausea = 0; + peep->NauseaTarget = 0; + + /* Scenario editor limits initial guest hunger to between 37..253. + * To be on the safe side, assume the value could have been hacked + * to any value 0..255. */ + peep->Hunger = gGuestInitialHunger; + /* Initial value will vary by -15..16 */ + int8_t hungerDelta = (scenario_rand() & 0x1F) - 15; + /* Adjust by the delta, clamping at min=0 and max=255. */ + peep->Hunger = std::clamp(peep->Hunger + hungerDelta, 0, PEEP_MAX_HUNGER); + + /* Scenario editor limits initial guest thirst to between 37..253. + * To be on the safe side, assume the value could have been hacked + * to any value 0..255. */ + peep->Thirst = gGuestInitialThirst; + /* Initial value will vary by -15..16 */ + int8_t thirstDelta = (scenario_rand() & 0x1F) - 15; + /* Adjust by the delta, clamping at min=0 and max=255. */ + peep->Thirst = std::clamp(peep->Thirst + thirstDelta, 0, PEEP_MAX_THIRST); + + peep->Toilet = 0; + peep->TimeToConsume = 0; + std::fill_n(peep->RidesBeenOn, 32, 0x00); + + peep->GuestNumRides = 0; + std::fill_n(peep->RideTypesBeenOn, 16, 0x00); + peep->Id = gNextGuestNumber++; + peep->Name = nullptr; + + money32 cash = (scenario_rand() & 0x3) * 100 - 100 + gGuestInitialCash; + if (cash < 0) + cash = 0; + + if (gGuestInitialCash == 0) + { + cash = 500; + } + + if (gParkFlags & PARK_FLAGS_NO_MONEY) + { + cash = 0; + } + + if (gGuestInitialCash == MONEY16_UNDEFINED) + { + cash = 0; + } + + peep->CashInPocket = cash; + peep->CashSpent = 0; + peep->ParkEntryTime = -1; + peep->ResetPathfindGoal(); + peep->RemoveAllItems(); + peep->GuestHeadingToRideId = RIDE_ID_NULL; + peep->LitterCount = 0; + peep->DisgustingCount = 0; + peep->VandalismSeen = 0; + peep->PaidToEnter = 0; + peep->PaidOnRides = 0; + peep->PaidOnFood = 0; + peep->PaidOnDrink = 0; + peep->PaidOnSouvenirs = 0; + peep->AmountOfFood = 0; + peep->AmountOfDrinks = 0; + peep->AmountOfSouvenirs = 0; + peep->SurroundingsThoughtTimeout = 0; + peep->Angriness = 0; + peep->TimeLost = 0; + + uint8_t tshirtColour = static_cast(scenario_rand() % std::size(tshirt_colours)); + peep->TshirtColour = tshirt_colours[tshirtColour]; + + uint8_t trousersColour = static_cast(scenario_rand() % std::size(trouser_colours)); + peep->TrousersColour = trouser_colours[trousersColour]; + + /* Minimum energy is capped at 32 and maximum at 128, so this initialises + * a peep with approx 34%-100% energy. (65 - 32) / (128 - 32) ≈ 34% */ + uint8_t energy = (scenario_rand() % 64) + 65; + peep->Energy = energy; + peep->EnergyTarget = energy; + + increment_guests_heading_for_park(); + +#ifdef ENABLE_SCRIPTING + auto& hookEngine = OpenRCT2::GetContext()->GetScriptEngine().GetHookEngine(); + if (hookEngine.HasSubscriptions(OpenRCT2::Scripting::HOOK_TYPE::GUEST_GENERATION)) + { + auto ctx = OpenRCT2::GetContext()->GetScriptEngine().GetContext(); + + // Create event args object + auto obj = OpenRCT2::Scripting::DukObject(ctx); + obj.Set("id", peep->sprite_index); + + // Call the subscriptions + auto e = obj.Take(); + hookEngine.Call(OpenRCT2::Scripting::HOOK_TYPE::GUEST_GENERATION, e, true); + } +#endif + + return peep; +} + +enum +{ + PEEP_FACE_OFFSET_ANGRY = 0, + PEEP_FACE_OFFSET_VERY_VERY_SICK, + PEEP_FACE_OFFSET_VERY_SICK, + PEEP_FACE_OFFSET_SICK, + PEEP_FACE_OFFSET_VERY_TIRED, + PEEP_FACE_OFFSET_TIRED, + PEEP_FACE_OFFSET_VERY_VERY_UNHAPPY, + PEEP_FACE_OFFSET_VERY_UNHAPPY, + PEEP_FACE_OFFSET_UNHAPPY, + PEEP_FACE_OFFSET_NORMAL, + PEEP_FACE_OFFSET_HAPPY, + PEEP_FACE_OFFSET_VERY_HAPPY, + PEEP_FACE_OFFSET_VERY_VERY_HAPPY, +}; + +static constexpr const int32_t face_sprite_small[] = { + SPR_PEEP_SMALL_FACE_ANGRY, + SPR_PEEP_SMALL_FACE_VERY_VERY_SICK, + SPR_PEEP_SMALL_FACE_VERY_SICK, + SPR_PEEP_SMALL_FACE_SICK, + SPR_PEEP_SMALL_FACE_VERY_TIRED, + SPR_PEEP_SMALL_FACE_TIRED, + SPR_PEEP_SMALL_FACE_VERY_VERY_UNHAPPY, + SPR_PEEP_SMALL_FACE_VERY_UNHAPPY, + SPR_PEEP_SMALL_FACE_UNHAPPY, + SPR_PEEP_SMALL_FACE_NORMAL, + SPR_PEEP_SMALL_FACE_HAPPY, + SPR_PEEP_SMALL_FACE_VERY_HAPPY, + SPR_PEEP_SMALL_FACE_VERY_VERY_HAPPY, +}; + +static constexpr const int32_t face_sprite_large[] = { + SPR_PEEP_LARGE_FACE_ANGRY_0, + SPR_PEEP_LARGE_FACE_VERY_VERY_SICK_0, + SPR_PEEP_LARGE_FACE_VERY_SICK_0, + SPR_PEEP_LARGE_FACE_SICK, + SPR_PEEP_LARGE_FACE_VERY_TIRED, + SPR_PEEP_LARGE_FACE_TIRED, + SPR_PEEP_LARGE_FACE_VERY_VERY_UNHAPPY, + SPR_PEEP_LARGE_FACE_VERY_UNHAPPY, + SPR_PEEP_LARGE_FACE_UNHAPPY, + SPR_PEEP_LARGE_FACE_NORMAL, + SPR_PEEP_LARGE_FACE_HAPPY, + SPR_PEEP_LARGE_FACE_VERY_HAPPY, + SPR_PEEP_LARGE_FACE_VERY_VERY_HAPPY, +}; + +static int32_t get_face_sprite_offset(Guest* peep) +{ + // ANGRY + if (peep->Angriness > 0) + return PEEP_FACE_OFFSET_ANGRY; + + // VERY_VERY_SICK + if (peep->Nausea > 200) + return PEEP_FACE_OFFSET_VERY_VERY_SICK; + + // VERY_SICK + if (peep->Nausea > 170) + return PEEP_FACE_OFFSET_VERY_SICK; + + // SICK + if (peep->Nausea > 140) + return PEEP_FACE_OFFSET_SICK; + + // VERY_TIRED + if (peep->Energy < 46) + return PEEP_FACE_OFFSET_VERY_TIRED; + + // TIRED + if (peep->Energy < 70) + return PEEP_FACE_OFFSET_TIRED; + + int32_t offset = PEEP_FACE_OFFSET_VERY_VERY_UNHAPPY; + // There are 7 different happiness based faces + for (int32_t i = 37; peep->Happiness >= i; i += 37) + { + offset++; + } + + return offset; +} + +/** + * Function split into large and small sprite + * rct2: 0x00698721 + */ +int32_t get_peep_face_sprite_small(Guest* peep) +{ + return face_sprite_small[get_face_sprite_offset(peep)]; +} + +/** + * Function split into large and small sprite + * rct2: 0x00698721 + */ +int32_t get_peep_face_sprite_large(Guest* peep) +{ + return face_sprite_large[get_face_sprite_offset(peep)]; +} + +/** + * + * rct2: 0x00693CBB + */ +bool Guest::UpdateQueuePosition(PeepActionType previous_action) +{ + TimeInQueue++; + + auto* guestNext = GetEntity(GuestNextInQueue); + if (guestNext == nullptr) + { + return false; + } + + int16_t x_diff = abs(guestNext->x - x); + int16_t y_diff = abs(guestNext->y - y); + int16_t z_diff = abs(guestNext->z - z); + + if (z_diff > 10) + return false; + + if (x_diff < y_diff) + { + int16_t temp_x = x_diff; + x_diff = y_diff; + y_diff = temp_x; + } + + x_diff += y_diff / 2; + if (x_diff > 7) + { + if (x_diff > 13) + { + if ((x & 0xFFE0) != (guestNext->x & 0xFFE0) || (y & 0xFFE0) != (guestNext->y & 0xFFE0)) + return false; + } + + if (sprite_direction != guestNext->sprite_direction) + return false; + + switch (guestNext->sprite_direction / 8) + { + case 0: + if (x >= guestNext->x) + return false; + break; + case 1: + if (y <= guestNext->y) + return false; + break; + case 2: + if (x <= guestNext->x) + return false; + break; + case 3: + if (y >= guestNext->y) + return false; + break; + } + } + + if (Action < PeepActionType::None1) + UpdateAction(); + + if (Action != PeepActionType::None2) + return true; + + Action = PeepActionType::None1; + NextActionSpriteType = PeepActionSpriteType::WatchRide; + if (previous_action != PeepActionType::None1) + Invalidate(); + return true; +} + +/** + * + * rct2: 0x006966A9 + */ +void Guest::RemoveFromQueue() +{ + auto ride = get_ride(CurrentRide); + if (ride == nullptr) + return; + + auto& station = ride->stations[CurrentRideStation]; + // Make sure we don't underflow, building while paused might reset it to 0 where peeps have + // not yet left the queue. + if (station.QueueLength > 0) + { + station.QueueLength--; + } + + if (sprite_index == station.LastPeepInQueue) + { + station.LastPeepInQueue = GuestNextInQueue; + return; + } + + auto* otherGuest = GetEntity(station.LastPeepInQueue); + if (otherGuest == nullptr) + { + log_error("Invalid Guest Queue list!"); + return; + } + for (; otherGuest != nullptr; otherGuest = GetEntity(otherGuest->GuestNextInQueue)) + { + if (sprite_index == otherGuest->GuestNextInQueue) + { + otherGuest->GuestNextInQueue = GuestNextInQueue; + return; + } + } +} + +uint64_t Guest::GetItemFlags() const +{ + return ItemFlags; +} + +void Guest::SetItemFlags(uint64_t itemFlags) +{ + ItemFlags = itemFlags; +} + +void Guest::RemoveAllItems() +{ + ItemFlags = 0; +} + +void Guest::RemoveItem(ShopItem item) +{ + ItemFlags &= ~EnumToFlag(item); +} + +void Guest::GiveItem(ShopItem item) +{ + ItemFlags |= EnumToFlag(item); +} + +bool Guest::HasItem(ShopItem peepItem) const +{ + return GetItemFlags() & EnumToFlag(peepItem); +} diff --git a/src/openrct2/peep/GuestPathfinding.cpp b/src/openrct2/peep/GuestPathfinding.cpp index a6a5134087..57ac7c0b09 100644 --- a/src/openrct2/peep/GuestPathfinding.cpp +++ b/src/openrct2/peep/GuestPathfinding.cpp @@ -34,9 +34,9 @@ ride_id_t gPeepPathFindQueueRideIndex; #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 // Use to guard calls to log messages -bool gPathFindDebug = false; +static bool _pathFindDebug = false; // Use to put the peep name in the log message -utf8 gPathFindDebugPeepName[256]; +static utf8 _pathFindDebugPeepName[256]; #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 static int32_t guest_surface_path_finding(Peep* peep); @@ -493,15 +493,19 @@ static uint8_t peep_pathfind_get_max_number_junctions(Peep* peep) return 8; } - if (peep->PeepFlags & PEEP_FLAGS_LEAVING_PARK && peep->GuestIsLostCountdown < 90) + auto* guest = peep->As(); + if (guest == nullptr) + return 8; + + if (guest->PeepFlags & PEEP_FLAGS_LEAVING_PARK && guest->GuestIsLostCountdown < 90) { return 8; } - if (peep->HasItem(ShopItem::Map)) + if (guest->HasItem(ShopItem::Map)) return 7; - if (peep->PeepFlags & PEEP_FLAGS_LEAVING_PARK) + if (guest->PeepFlags & PEEP_FLAGS_LEAVING_PARK) return 7; return 5; @@ -1269,10 +1273,10 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) TileCoordsXYZ goal = gPeepPathFindGoalPosition; #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { log_verbose( - "Choose direction for %s for goal %d,%d,%d from %d,%d,%d", gPathFindDebugPeepName, goal.x, goal.y, goal.z, loc.x, + "Choose direction for %s for goal %d,%d,%d from %d,%d,%d", _pathFindDebugPeepName, goal.x, goal.y, goal.z, loc.x, loc.y, loc.z); } #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 @@ -1362,7 +1366,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) edges = pathfindHistory.direction; #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { log_verbose( "Getting untried edges from pf_history for %d,%d,%d: %s,%s,%s,%s", loc.x, loc.y, loc.z, @@ -1384,7 +1388,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) edges = pathfindHistory.direction; #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { log_verbose("All edges tried for %d,%d,%d - resetting to all untried", loc.x, loc.y, loc.z); } @@ -1408,7 +1412,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) // Clear pathfinding history std::fill_n(reinterpret_cast(peep->PathfindHistory), sizeof(peep->PathfindHistory), 0xFF); #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { log_verbose("New goal; clearing pf_history."); } @@ -1433,7 +1437,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) uint8_t bestDirectionList[16]; TileCoordsXYZ bestXYZ; - if (gPathFindDebug) + if (_pathFindDebug) { log_verbose("Pathfind start for goal %d,%d,%d from %d,%d,%d", goal.x, goal.y, goal.z, loc.x, loc.y, loc.z); } @@ -1515,7 +1519,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) endJunctionList, endDirectionList, &endXYZ, &endSteps); #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { log_verbose( "Pathfind test edge: %d score: %d steps: %d end: %d,%d,%d junctions: %d", test_edge, score, endSteps, @@ -1556,7 +1560,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) if (best_score == 0xFFFF) { #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { log_verbose("Pathfind heuristic search failed."); } @@ -1564,7 +1568,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) return INVALID_DIRECTION; } #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { log_verbose("Pathfind best edge %d with score %d steps %d", chosen_edge, best_score, best_sub); for (uint8_t listIdx = 0; listIdx < bestJunctions; listIdx++) @@ -1592,7 +1596,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) * entered the junction from those left to try. */ peep->PathfindHistory[i].direction &= ~(1 << direction_reverse(peep->PeepDirection)); #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { log_verbose( "Updating existing pf_history (in index: %d) for %d,%d,%d without entry edge %d & exit edge %d.", i, @@ -1617,7 +1621,7 @@ Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) * entered the junction from those left to try. */ peep->PathfindHistory[i].direction &= ~(1 << direction_reverse(peep->PeepDirection)); #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { log_verbose( "Storing new pf_history (in index: %d) for %d,%d,%d without entry edge %d & exit edge %d.", i, loc.x, loc.y, @@ -1980,9 +1984,9 @@ int32_t guest_path_finding(Guest* peep) { #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 PathfindLoggingEnable(peep); - if (gPathFindDebug) + if (_pathFindDebug) { - log_info("Starting guest_path_finding for %s", gPathFindDebugPeepName); + log_info("Starting guest_path_finding for %s", _pathFindDebugPeepName); } #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 @@ -2050,10 +2054,10 @@ int32_t guest_path_finding(Guest* peep) if ((edges & ~(1 << direction)) == 0) { #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { log_info( - "Completed guest_path_finding for %s - taking only direction available: %d.", gPathFindDebugPeepName, + "Completed guest_path_finding for %s - taking only direction available: %d.", _pathFindDebugPeepName, direction); } PathfindLoggingDisable(); @@ -2068,9 +2072,9 @@ int32_t guest_path_finding(Guest* peep) if (peep->OutsideOfPark) { #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { - log_info("Completed guest_path_finding for %s - peep is outside the park.", gPathFindDebugPeepName); + log_info("Completed guest_path_finding for %s - peep is outside the park.", _pathFindDebugPeepName); } PathfindLoggingDisable(); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 @@ -2138,9 +2142,9 @@ int32_t guest_path_finding(Guest* peep) if (peep->PeepFlags & PEEP_FLAGS_LEAVING_PARK) { #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { - log_info("Completed guest_path_finding for %s - peep is leaving the park.", gPathFindDebugPeepName); + log_info("Completed guest_path_finding for %s - peep is leaving the park.", _pathFindDebugPeepName); } PathfindLoggingDisable(); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 @@ -2150,9 +2154,9 @@ int32_t guest_path_finding(Guest* peep) if (peep->GuestHeadingToRideId == RIDE_ID_NULL) { #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { - log_info("Completed guest_path_finding for %s - peep is aimless.", gPathFindDebugPeepName); + log_info("Completed guest_path_finding for %s - peep is aimless.", _pathFindDebugPeepName); } PathfindLoggingDisable(); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 @@ -2165,10 +2169,10 @@ int32_t guest_path_finding(Guest* peep) if (ride == nullptr || ride->status != RIDE_STATUS_OPEN) { #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { log_info( - "Completed guest_path_finding for %s - peep is heading to closed ride == aimless.", gPathFindDebugPeepName); + "Completed guest_path_finding for %s - peep is heading to closed ride == aimless.", _pathFindDebugPeepName); } PathfindLoggingDisable(); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 @@ -2249,9 +2253,9 @@ int32_t guest_path_finding(Guest* peep) peep->ResetPathfindGoal(); #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { - log_info("Completed guest_path_finding for %s - failed to choose a direction == aimless.", gPathFindDebugPeepName); + log_info("Completed guest_path_finding for %s - failed to choose a direction == aimless.", _pathFindDebugPeepName); } PathfindLoggingDisable(); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 @@ -2259,9 +2263,9 @@ int32_t guest_path_finding(Guest* peep) return guest_path_find_aimless(peep, edges); } #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { - log_info("Completed guest_path_finding for %s - direction chosen: %d.", gPathFindDebugPeepName, direction); + log_info("Completed guest_path_finding for %s - direction chosen: %d.", _pathFindDebugPeepName, direction); } PathfindLoggingDisable(); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 @@ -2302,9 +2306,9 @@ bool IsValidPathZAndDirection(TileElement* tileElement, int32_t currentZ, int32_ void Peep::ResetPathfindGoal() { #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (gPathFindDebug) + if (_pathFindDebug) { - log_info("Resetting PathfindGoal for %s", gPathFindDebugPeepName); + log_info("Resetting PathfindGoal for %s", _pathFindDebugPeepName); } #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 diff --git a/src/openrct2/peep/Peep.cpp b/src/openrct2/peep/Peep.cpp index f6dc7d7a47..daf4e082cc 100644 --- a/src/openrct2/peep/Peep.cpp +++ b/src/openrct2/peep/Peep.cpp @@ -31,8 +31,6 @@ #include "../ride/Station.h" #include "../ride/Track.h" #include "../scenario/Scenario.h" -#include "../scripting/HookEngine.h" -#include "../scripting/ScriptEngine.h" #include "../sprites.h" #include "../util/Util.h" #include "../windows/Intent.h" @@ -76,197 +74,6 @@ static void peep_128_tick_update(Peep* peep, int32_t index); static void peep_release_balloon(Guest* peep, int16_t spawn_height); // clang-format off -// Flags used by PeepThoughtToActionMap -enum PeepThoughtToActionFlag : uint8_t -{ - PEEP_THOUGHT_ACTION_NO_FLAGS = 0, - PEEP_THOUGHT_ACTION_FLAG_RIDE = (1 << 0), - PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_SINGULAR = (1 << 1), - PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_INDEFINITE = (1 << 2), -}; - -/** rct2: 0x00981DB0 */ -static struct -{ - PeepActionType action; - PeepThoughtToActionFlag flags; -} PeepThoughtToActionMap[] = { - { PeepActionType::ShakeHead, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::EmptyPockets, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::Wow, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_SINGULAR }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_INDEFINITE }, - { PeepActionType::ShakeHead, PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_INDEFINITE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::Wave, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::Joy, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::CheckTime, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::Wave, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::Wave, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::Disgust, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::BeingWatched, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::ShakeHead, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::Joy, PEEP_THOUGHT_ACTION_NO_FLAGS }, - { PeepActionType::None2, PEEP_THOUGHT_ACTION_FLAG_RIDE }, -}; - static PeepActionSpriteType PeepSpecialSpriteToSpriteTypeMap[] = { PeepActionSpriteType::None, PeepActionSpriteType::HoldMat, @@ -379,11 +186,6 @@ bool Peep::CanBePickedUp() const return false; } -Peep* try_get_guest(uint16_t spriteIndex) -{ - return TryGetEntity(spriteIndex); -} - int32_t peep_get_staff_count() { return GetEntityListCount(EntityType::Staff); @@ -653,20 +455,21 @@ std::optional Peep::UpdateAction(int16_t& xy_distance) } ActionSpriteImageOffset = peepAnimation[EnumValue(ActionSpriteType)].frame_offsets[ActionFrame]; + auto* guest = As(); // If not throwing up and not at the frame where sick appears. - if (Action != PeepActionType::ThrowUp || ActionFrame != 15) + if (Action != PeepActionType::ThrowUp || ActionFrame != 15 || guest == nullptr) { return { { x, y } }; } // We are throwing up - Hunger /= 2; - NauseaTarget /= 2; + guest->Hunger /= 2; + guest->NauseaTarget /= 2; - if (Nausea < 30) - Nausea = 0; + if (guest->Nausea < 30) + guest->Nausea = 0; else - Nausea -= 30; + guest->Nausea -= 30; WindowInvalidateFlags |= PEEP_INVALIDATE_PEEP_2; @@ -811,11 +614,11 @@ std::unique_ptr Peep::Place(const TileCoordsXYZ& location, ActionSpriteType = PeepActionSpriteType::None; PathCheckOptimisation = 0; EntityTweener::Get().Reset(); - - if (Is()) + auto* guest = As(); + if (guest != nullptr) { ActionSpriteType = PeepActionSpriteType::Invalid; - HappinessTarget = std::max(HappinessTarget - 10, 0); + guest->HappinessTarget = std::max(guest->HappinessTarget - 10, 0); UpdateCurrentActionSpriteType(); } } @@ -840,18 +643,19 @@ void peep_sprite_remove(Peep* peep) window_close_by_number(WC_FIRE_PROMPT, EnumValue(peep->Type)); + auto* staff = peep->As(); // Needed for invalidations after sprite removal - bool wasGuest = peep->Is(); + bool wasGuest = staff == nullptr; if (wasGuest) { News::DisableNewsItems(News::ItemType::PeepOnRide, peep->sprite_index); } else { - gStaffModes[peep->StaffId] = StaffMode::None; + gStaffModes[staff->StaffId] = StaffMode::None; staff_update_greyed_patrol_areas(); - News::DisableNewsItems(News::ItemType::Peep, peep->sprite_index); + News::DisableNewsItems(News::ItemType::Peep, staff->sprite_index); } sprite_remove(peep); @@ -864,9 +668,10 @@ void peep_sprite_remove(Peep* peep) */ void Peep::Remove() { - if (Is()) + auto* guest = As(); + if (guest != nullptr) { - if (!OutsideOfPark) + if (!guest->OutsideOfPark) { decrement_guests_in_park(); auto intent = Intent(INTENT_ACTION_UPDATE_GUEST_COUNT); @@ -946,10 +751,9 @@ void Peep::UpdateFalling() { // Drop balloon if held peep_release_balloon(guest, height); + guest->InsertNewThought(PeepThoughtType::Drowning, PEEP_THOUGHT_ITEM_NONE); } - InsertNewThought(PeepThoughtType::Drowning, PEEP_THOUGHT_ITEM_NONE); - Action = PeepActionType::Drowning; ActionFrame = 0; ActionSpriteImageOffset = 0; @@ -1036,14 +840,15 @@ void Peep::UpdatePicked() if (gCurrentTicks & 0x1F) return; SubState++; - if (SubState == 13) + auto* guest = As(); + if (SubState == 13 && guest != nullptr) { - InsertNewThought(PeepThoughtType::Help, PEEP_THOUGHT_ITEM_NONE); + guest->InsertNewThought(PeepThoughtType::Help, PEEP_THOUGHT_ITEM_NONE); } } /* From peep_update */ -static void peep_update_thoughts(Peep* peep) +static void peep_update_thoughts(Guest* peep) { // Thoughts must always have a gap of at least // 220 ticks in age between them. In order to @@ -1109,13 +914,14 @@ static void peep_update_thoughts(Peep* peep) */ void Peep::Update() { - if (Is()) + auto* guest = As(); + if (guest != nullptr) { - if (PreviousRide != RIDE_ID_NULL) - if (++PreviousRideTimeOut >= 720) - PreviousRide = RIDE_ID_NULL; + if (guest->PreviousRide != RIDE_ID_NULL) + if (++guest->PreviousRideTimeOut >= 720) + guest->PreviousRide = RIDE_ID_NULL; - peep_update_thoughts(this); + peep_update_thoughts(guest); } // Walking speed logic @@ -1135,7 +941,6 @@ void Peep::Update() StepProgress = carryCheck; if (carryCheck <= 255) { - auto* guest = As(); if (guest != nullptr) { guest->UpdateEasterEggInteractions(); @@ -1160,7 +965,6 @@ void Peep::Update() break; default: { - auto* guest = As(); if (guest != nullptr) { guest->UpdateGuest(); @@ -1475,319 +1279,6 @@ void peep_update_days_in_queue() } } -// clang-format off -/** rct2: 0x009823A0 */ -static constexpr const PeepNauseaTolerance nausea_tolerance_distribution[] = { - PeepNauseaTolerance::None, - PeepNauseaTolerance::Low, PeepNauseaTolerance::Low, - PeepNauseaTolerance::Average, PeepNauseaTolerance::Average, PeepNauseaTolerance::Average, - PeepNauseaTolerance::High, PeepNauseaTolerance::High, PeepNauseaTolerance::High, PeepNauseaTolerance::High, PeepNauseaTolerance::High, PeepNauseaTolerance::High, -}; - -/** rct2: 0x009823BC */ -static constexpr const uint8_t trouser_colours[] = { - COLOUR_BLACK, - COLOUR_GREY, - COLOUR_LIGHT_BROWN, - COLOUR_SATURATED_BROWN, - COLOUR_DARK_BROWN, - COLOUR_SALMON_PINK, - COLOUR_BLACK, - COLOUR_GREY, - COLOUR_LIGHT_BROWN, - COLOUR_SATURATED_BROWN, - COLOUR_DARK_BROWN, - COLOUR_SALMON_PINK, - COLOUR_BLACK, - COLOUR_GREY, - COLOUR_LIGHT_BROWN, - COLOUR_SATURATED_BROWN, - COLOUR_DARK_BROWN, - COLOUR_SALMON_PINK, - COLOUR_DARK_PURPLE, - COLOUR_LIGHT_PURPLE, - COLOUR_DARK_BLUE, - COLOUR_SATURATED_GREEN, - COLOUR_SATURATED_RED, - COLOUR_DARK_ORANGE, - COLOUR_BORDEAUX_RED, -}; - -/** rct2: 0x009823D5 */ -static constexpr const uint8_t tshirt_colours[] = { - COLOUR_BLACK, - COLOUR_GREY, - COLOUR_LIGHT_BROWN, - COLOUR_SATURATED_BROWN, - COLOUR_DARK_BROWN, - COLOUR_SALMON_PINK, - COLOUR_BLACK, - COLOUR_GREY, - COLOUR_LIGHT_BROWN, - COLOUR_SATURATED_BROWN, - COLOUR_DARK_BROWN, - COLOUR_SALMON_PINK, - COLOUR_DARK_PURPLE, - COLOUR_LIGHT_PURPLE, - COLOUR_DARK_BLUE, - COLOUR_SATURATED_GREEN, - COLOUR_SATURATED_RED, - COLOUR_DARK_ORANGE, - COLOUR_BORDEAUX_RED, - COLOUR_WHITE, - COLOUR_BRIGHT_PURPLE, - COLOUR_LIGHT_BLUE, - COLOUR_TEAL, - COLOUR_DARK_GREEN, - COLOUR_MOSS_GREEN, - COLOUR_BRIGHT_GREEN, - COLOUR_OLIVE_GREEN, - COLOUR_DARK_OLIVE_GREEN, - COLOUR_YELLOW, - COLOUR_LIGHT_ORANGE, - COLOUR_BRIGHT_RED, - COLOUR_DARK_PINK, - COLOUR_BRIGHT_PINK, -}; -// clang-format on - -/** - * - * rct2: 0x699F5A - * al:thoughtType - * ah:thoughtArguments - * esi: peep - */ -void Peep::InsertNewThought(PeepThoughtType thoughtType, uint8_t thoughtArguments) -{ - PeepActionType newAction = PeepThoughtToActionMap[EnumValue(thoughtType)].action; - if (newAction != PeepActionType::None2 && this->Action >= PeepActionType::None1) - { - Action = newAction; - ActionFrame = 0; - ActionSpriteImageOffset = 0; - UpdateCurrentActionSpriteType(); - } - - for (int32_t i = 0; i < PEEP_MAX_THOUGHTS; ++i) - { - rct_peep_thought* thought = &Thoughts[i]; - // Remove the oldest thought by setting it to NONE. - if (thought->type == PeepThoughtType::None) - break; - - if (thought->type == thoughtType && thought->item == thoughtArguments) - { - // If the thought type has not changed then we need to move - // it to the top of the thought list. This is done by first removing the - // existing thought and placing it at the top. - if (i < PEEP_MAX_THOUGHTS - 2) - { - memmove(thought, thought + 1, sizeof(rct_peep_thought) * (PEEP_MAX_THOUGHTS - i - 1)); - } - break; - } - } - - memmove(&Thoughts[1], &Thoughts[0], sizeof(rct_peep_thought) * (PEEP_MAX_THOUGHTS - 1)); - - Thoughts[0].type = thoughtType; - Thoughts[0].item = thoughtArguments; - Thoughts[0].freshness = 0; - Thoughts[0].fresh_timeout = 0; - - WindowInvalidateFlags |= PEEP_INVALIDATE_PEEP_THOUGHTS; -} - -/** - * - * rct2: 0x0069A05D - */ -Peep* Peep::Generate(const CoordsXYZ& coords) -{ - if (GetNumFreeEntities() < 400) - return nullptr; - - Peep* peep = CreateEntity(); - peep->SpriteType = PeepSpriteType::Normal; - peep->OutsideOfPark = true; - peep->State = PeepState::Falling; - peep->Action = PeepActionType::None2; - peep->SpecialSprite = 0; - peep->ActionSpriteImageOffset = 0; - peep->WalkingFrameNum = 0; - peep->ActionSpriteType = PeepActionSpriteType::None; - peep->PeepFlags = 0; - peep->FavouriteRide = RIDE_ID_NULL; - peep->FavouriteRideRating = 0; - - const rct_sprite_bounds* spriteBounds = &GetSpriteBounds(peep->SpriteType, peep->ActionSpriteType); - peep->sprite_width = spriteBounds->sprite_width; - peep->sprite_height_negative = spriteBounds->sprite_height_negative; - peep->sprite_height_positive = spriteBounds->sprite_height_positive; - - peep->MoveTo(coords); - peep->sprite_direction = 0; - peep->Mass = (scenario_rand() & 0x1F) + 45; - peep->PathCheckOptimisation = 0; - peep->InteractionRideIndex = RIDE_ID_NULL; - peep->PreviousRide = RIDE_ID_NULL; - peep->Thoughts->type = PeepThoughtType::None; - peep->WindowInvalidateFlags = 0; - - uint8_t intensityHighest = (scenario_rand() & 0x7) + 3; - uint8_t intensityLowest = std::min(intensityHighest, static_cast(7)) - 3; - - if (intensityHighest >= 7) - intensityHighest = 15; - - /* Check which intensity boxes are enabled - * and apply the appropriate intensity settings. */ - if (gParkFlags & PARK_FLAGS_PREF_LESS_INTENSE_RIDES) - { - if (gParkFlags & PARK_FLAGS_PREF_MORE_INTENSE_RIDES) - { - intensityLowest = 0; - intensityHighest = 15; - } - else - { - intensityLowest = 0; - intensityHighest = 4; - } - } - else if (gParkFlags & PARK_FLAGS_PREF_MORE_INTENSE_RIDES) - { - intensityLowest = 9; - intensityHighest = 15; - } - - peep->Intensity = IntensityRange(intensityLowest, intensityHighest); - - uint8_t nauseaTolerance = scenario_rand() & 0x7; - if (gParkFlags & PARK_FLAGS_PREF_MORE_INTENSE_RIDES) - { - nauseaTolerance += 4; - } - - peep->NauseaTolerance = nausea_tolerance_distribution[nauseaTolerance]; - - /* Scenario editor limits initial guest happiness to between 37..253. - * To be on the safe side, assume the value could have been hacked - * to any value 0..255. */ - peep->Happiness = gGuestInitialHappiness; - /* Assume a default initial happiness of 0 is wrong and set - * to 128 (50%) instead. */ - if (gGuestInitialHappiness == 0) - peep->Happiness = 128; - /* Initial value will vary by -15..16 */ - int8_t happinessDelta = (scenario_rand() & 0x1F) - 15; - /* Adjust by the delta, clamping at min=0 and max=255. */ - peep->Happiness = std::clamp(peep->Happiness + happinessDelta, 0, PEEP_MAX_HAPPINESS); - peep->HappinessTarget = peep->Happiness; - peep->Nausea = 0; - peep->NauseaTarget = 0; - - /* Scenario editor limits initial guest hunger to between 37..253. - * To be on the safe side, assume the value could have been hacked - * to any value 0..255. */ - peep->Hunger = gGuestInitialHunger; - /* Initial value will vary by -15..16 */ - int8_t hungerDelta = (scenario_rand() & 0x1F) - 15; - /* Adjust by the delta, clamping at min=0 and max=255. */ - peep->Hunger = std::clamp(peep->Hunger + hungerDelta, 0, PEEP_MAX_HUNGER); - - /* Scenario editor limits initial guest thirst to between 37..253. - * To be on the safe side, assume the value could have been hacked - * to any value 0..255. */ - peep->Thirst = gGuestInitialThirst; - /* Initial value will vary by -15..16 */ - int8_t thirstDelta = (scenario_rand() & 0x1F) - 15; - /* Adjust by the delta, clamping at min=0 and max=255. */ - peep->Thirst = std::clamp(peep->Thirst + thirstDelta, 0, PEEP_MAX_THIRST); - - peep->Toilet = 0; - peep->TimeToConsume = 0; - std::fill_n(peep->RidesBeenOn, 32, 0x00); - - peep->GuestNumRides = 0; - std::fill_n(peep->RideTypesBeenOn, 16, 0x00); - peep->Id = gNextGuestNumber++; - peep->Name = nullptr; - - money32 cash = (scenario_rand() & 0x3) * 100 - 100 + gGuestInitialCash; - if (cash < 0) - cash = 0; - - if (gGuestInitialCash == 0) - { - cash = 500; - } - - if (gParkFlags & PARK_FLAGS_NO_MONEY) - { - cash = 0; - } - - if (gGuestInitialCash == MONEY16_UNDEFINED) - { - cash = 0; - } - - peep->CashInPocket = cash; - peep->CashSpent = 0; - peep->ParkEntryTime = -1; - peep->ResetPathfindGoal(); - peep->RemoveAllItems(); - peep->GuestHeadingToRideId = RIDE_ID_NULL; - peep->LitterCount = 0; - peep->DisgustingCount = 0; - peep->VandalismSeen = 0; - peep->PaidToEnter = 0; - peep->PaidOnRides = 0; - peep->PaidOnFood = 0; - peep->PaidOnDrink = 0; - peep->PaidOnSouvenirs = 0; - peep->AmountOfFood = 0; - peep->AmountOfDrinks = 0; - peep->AmountOfSouvenirs = 0; - peep->SurroundingsThoughtTimeout = 0; - peep->Angriness = 0; - peep->TimeLost = 0; - - uint8_t tshirtColour = static_cast(scenario_rand() % std::size(tshirt_colours)); - peep->TshirtColour = tshirt_colours[tshirtColour]; - - uint8_t trousersColour = static_cast(scenario_rand() % std::size(trouser_colours)); - peep->TrousersColour = trouser_colours[trousersColour]; - - /* Minimum energy is capped at 32 and maximum at 128, so this initialises - * a peep with approx 34%-100% energy. (65 - 32) / (128 - 32) ≈ 34% */ - uint8_t energy = (scenario_rand() % 64) + 65; - peep->Energy = energy; - peep->EnergyTarget = energy; - - increment_guests_heading_for_park(); - -#ifdef ENABLE_SCRIPTING - auto& hookEngine = OpenRCT2::GetContext()->GetScriptEngine().GetHookEngine(); - if (hookEngine.HasSubscriptions(OpenRCT2::Scripting::HOOK_TYPE::GUEST_GENERATION)) - { - auto ctx = OpenRCT2::GetContext()->GetScriptEngine().GetContext(); - - // Create event args object - auto obj = OpenRCT2::Scripting::DukObject(ctx); - obj.Set("id", peep->sprite_index); - - // Call the subscriptions - auto e = obj.Take(); - hookEngine.Call(OpenRCT2::Scripting::HOOK_TYPE::GUEST_GENERATION, e, true); - } -#endif - - return peep; -} - void Peep::FormatActionTo(Formatter& ft) const { switch (State) @@ -1831,20 +1322,26 @@ void Peep::FormatActionTo(Formatter& ft) const } case PeepState::Walking: case PeepState::UsingBin: - if (GuestHeadingToRideId != RIDE_ID_NULL) + { + auto* guest = As(); + if (guest != nullptr) { - auto ride = get_ride(GuestHeadingToRideId); - if (ride != nullptr) + if (guest->GuestHeadingToRideId != RIDE_ID_NULL) { - ft.Add(STR_HEADING_FOR); - ride->FormatNameTo(ft); + auto ride = get_ride(guest->GuestHeadingToRideId); + if (ride != nullptr) + { + ft.Add(STR_HEADING_FOR); + ride->FormatNameTo(ft); + } + } + else + { + ft.Add((PeepFlags & PEEP_FLAGS_LEAVING_PARK) ? STR_LEAVING_PARK : STR_WALKING); } } - else - { - ft.Add((PeepFlags & PEEP_FLAGS_LEAVING_PARK) ? STR_LEAVING_PARK : STR_WALKING); - } break; + } case PeepState::QueuingFront: case PeepState::Queuing: { @@ -1966,7 +1463,8 @@ void Peep::FormatNameTo(Formatter& ft) const { if (Name == nullptr) { - if (Is()) + auto* staff = As(); + if (staff != nullptr) { static constexpr const rct_string_id staffNames[] = { STR_HANDYMAN_X, @@ -1975,7 +1473,7 @@ void Peep::FormatNameTo(Formatter& ft) const STR_ENTERTAINER_X, }; - auto staffNameIndex = static_cast(AssignedStaffType); + auto staffNameIndex = static_cast(staff->AssignedStaffType); if (staffNameIndex > sizeof(staffNames)) { staffNameIndex = 0; @@ -2030,152 +1528,16 @@ bool Peep::SetName(std::string_view value) return false; } -/** - * rct2: 0x00698342 - * thought.item (eax) - * thought.type (ebx) - * argument_1 (esi & ebx) - * argument_2 (esi+2) - */ -void peep_thought_set_format_args(const rct_peep_thought* thought, Formatter& ft) -{ - ft.Add(PeepThoughts[EnumValue(thought->type)]); - - PeepThoughtToActionFlag flags = PeepThoughtToActionMap[EnumValue(thought->type)].flags; - if (flags & PEEP_THOUGHT_ACTION_FLAG_RIDE) - { - auto ride = get_ride(thought->item); - if (ride != nullptr) - { - ride->FormatNameTo(ft); - } - else - { - ft.Add(STR_NONE); - } - } - else if (flags & PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_SINGULAR) - { - ft.Add(GetShopItemDescriptor(ShopItem(thought->item)).Naming.Singular); - } - else if (flags & PEEP_THOUGHT_ACTION_FLAG_SHOP_ITEM_INDEFINITE) - { - ft.Add(GetShopItemDescriptor(ShopItem(thought->item)).Naming.Indefinite); - } -} - -enum -{ - PEEP_FACE_OFFSET_ANGRY = 0, - PEEP_FACE_OFFSET_VERY_VERY_SICK, - PEEP_FACE_OFFSET_VERY_SICK, - PEEP_FACE_OFFSET_SICK, - PEEP_FACE_OFFSET_VERY_TIRED, - PEEP_FACE_OFFSET_TIRED, - PEEP_FACE_OFFSET_VERY_VERY_UNHAPPY, - PEEP_FACE_OFFSET_VERY_UNHAPPY, - PEEP_FACE_OFFSET_UNHAPPY, - PEEP_FACE_OFFSET_NORMAL, - PEEP_FACE_OFFSET_HAPPY, - PEEP_FACE_OFFSET_VERY_HAPPY, - PEEP_FACE_OFFSET_VERY_VERY_HAPPY, -}; - -static constexpr const int32_t face_sprite_small[] = { - SPR_PEEP_SMALL_FACE_ANGRY, - SPR_PEEP_SMALL_FACE_VERY_VERY_SICK, - SPR_PEEP_SMALL_FACE_VERY_SICK, - SPR_PEEP_SMALL_FACE_SICK, - SPR_PEEP_SMALL_FACE_VERY_TIRED, - SPR_PEEP_SMALL_FACE_TIRED, - SPR_PEEP_SMALL_FACE_VERY_VERY_UNHAPPY, - SPR_PEEP_SMALL_FACE_VERY_UNHAPPY, - SPR_PEEP_SMALL_FACE_UNHAPPY, - SPR_PEEP_SMALL_FACE_NORMAL, - SPR_PEEP_SMALL_FACE_HAPPY, - SPR_PEEP_SMALL_FACE_VERY_HAPPY, - SPR_PEEP_SMALL_FACE_VERY_VERY_HAPPY, -}; - -static constexpr const int32_t face_sprite_large[] = { - SPR_PEEP_LARGE_FACE_ANGRY_0, - SPR_PEEP_LARGE_FACE_VERY_VERY_SICK_0, - SPR_PEEP_LARGE_FACE_VERY_SICK_0, - SPR_PEEP_LARGE_FACE_SICK, - SPR_PEEP_LARGE_FACE_VERY_TIRED, - SPR_PEEP_LARGE_FACE_TIRED, - SPR_PEEP_LARGE_FACE_VERY_VERY_UNHAPPY, - SPR_PEEP_LARGE_FACE_VERY_UNHAPPY, - SPR_PEEP_LARGE_FACE_UNHAPPY, - SPR_PEEP_LARGE_FACE_NORMAL, - SPR_PEEP_LARGE_FACE_HAPPY, - SPR_PEEP_LARGE_FACE_VERY_HAPPY, - SPR_PEEP_LARGE_FACE_VERY_VERY_HAPPY, -}; - -static int32_t get_face_sprite_offset(Peep* peep) -{ - // ANGRY - if (peep->Angriness > 0) - return PEEP_FACE_OFFSET_ANGRY; - - // VERY_VERY_SICK - if (peep->Nausea > 200) - return PEEP_FACE_OFFSET_VERY_VERY_SICK; - - // VERY_SICK - if (peep->Nausea > 170) - return PEEP_FACE_OFFSET_VERY_SICK; - - // SICK - if (peep->Nausea > 140) - return PEEP_FACE_OFFSET_SICK; - - // VERY_TIRED - if (peep->Energy < 46) - return PEEP_FACE_OFFSET_VERY_TIRED; - - // TIRED - if (peep->Energy < 70) - return PEEP_FACE_OFFSET_TIRED; - - int32_t offset = PEEP_FACE_OFFSET_VERY_VERY_UNHAPPY; - // There are 7 different happiness based faces - for (int32_t i = 37; peep->Happiness >= i; i += 37) - { - offset++; - } - - return offset; -} - -/** - * Function split into large and small sprite - * rct2: 0x00698721 - */ -int32_t get_peep_face_sprite_small(Peep* peep) -{ - return face_sprite_small[get_face_sprite_offset(peep)]; -} - -/** - * Function split into large and small sprite - * rct2: 0x00698721 - */ -int32_t get_peep_face_sprite_large(Peep* peep) -{ - return face_sprite_large[get_face_sprite_offset(peep)]; -} - void peep_set_map_tooltip(Peep* peep) { auto ft = Formatter(); - if (peep->Is()) + auto* guest = peep->As(); + if (guest != nullptr) { ft.Add((peep->PeepFlags & PEEP_FLAGS_TRACKING) ? STR_TRACKED_GUEST_MAP_TIP : STR_GUEST_MAP_TIP); - ft.Add(get_peep_face_sprite_small(peep)); - peep->FormatNameTo(ft); - peep->FormatActionTo(ft); + ft.Add(get_peep_face_sprite_small(guest)); + guest->FormatNameTo(ft); + guest->FormatActionTo(ft); } else { @@ -2207,80 +1569,6 @@ void Peep::SwitchNextActionSpriteType() } } -/** - * - * rct2: 0x00693CBB - */ -static bool peep_update_queue_position(Peep* peep, PeepActionType previous_action) -{ - peep->TimeInQueue++; - - auto* guestNext = GetEntity(peep->GuestNextInQueue); - if (guestNext == nullptr) - { - return false; - } - - int16_t x_diff = abs(guestNext->x - peep->x); - int16_t y_diff = abs(guestNext->y - peep->y); - int16_t z_diff = abs(guestNext->z - peep->z); - - if (z_diff > 10) - return false; - - if (x_diff < y_diff) - { - int16_t temp_x = x_diff; - x_diff = y_diff; - y_diff = temp_x; - } - - x_diff += y_diff / 2; - if (x_diff > 7) - { - if (x_diff > 13) - { - if ((peep->x & 0xFFE0) != (guestNext->x & 0xFFE0) || (peep->y & 0xFFE0) != (guestNext->y & 0xFFE0)) - return false; - } - - if (peep->sprite_direction != guestNext->sprite_direction) - return false; - - switch (guestNext->sprite_direction / 8) - { - case 0: - if (peep->x >= guestNext->x) - return false; - break; - case 1: - if (peep->y <= guestNext->y) - return false; - break; - case 2: - if (peep->x <= guestNext->x) - return false; - break; - case 3: - if (peep->y >= guestNext->y) - return false; - break; - } - } - - if (peep->Action < PeepActionType::None1) - peep->UpdateAction(); - - if (peep->Action != PeepActionType::None2) - return true; - - peep->Action = PeepActionType::None1; - peep->NextActionSpriteType = PeepActionSpriteType::WatchRide; - if (previous_action != PeepActionType::None1) - peep->Invalidate(); - return true; -} - /** * * rct2: 0x00693EF2 @@ -2350,26 +1638,26 @@ static bool peep_interact_with_entrance(Peep* peep, const CoordsXYE& coords, uin return true; } - if (peep->State == PeepState::Queuing) + if (guest->State == PeepState::Queuing) { // Guest is in the ride queue. - peep->RideSubState = PeepRideSubState::AtQueueFront; - peep->ActionSpriteImageOffset = _unk_F1AEF0; + guest->RideSubState = PeepRideSubState::AtQueueFront; + guest->ActionSpriteImageOffset = _unk_F1AEF0; return true; } // Guest is on a normal path, i.e. ride has no queue. - if (peep->InteractionRideIndex == rideIndex) + if (guest->InteractionRideIndex == rideIndex) { // Peep is retrying the ride entrance without leaving // the path tile and without trying any other ride // attached to this path tile. i.e. stick with the // peeps previous decision not to go on the ride. - peep_return_to_centre_of_tile(peep); + peep_return_to_centre_of_tile(guest); return true; } - peep->TimeLost = 0; + guest->TimeLost = 0; auto stationNum = tile_element->AsEntrance()->GetStationIndex(); // Guest walks up to the ride for the first time since entering // the path tile or since considering another ride attached to @@ -2378,35 +1666,35 @@ static bool peep_interact_with_entrance(Peep* peep, const CoordsXYE& coords, uin { // Peep remembers that this is the last ride they // considered while on this path tile. - peep->InteractionRideIndex = rideIndex; - peep_return_to_centre_of_tile(peep); + guest->InteractionRideIndex = rideIndex; + peep_return_to_centre_of_tile(guest); return true; } // Guest has decided to go on the ride. - peep->ActionSpriteImageOffset = _unk_F1AEF0; - peep->InteractionRideIndex = rideIndex; + guest->ActionSpriteImageOffset = _unk_F1AEF0; + guest->InteractionRideIndex = rideIndex; uint16_t previous_last = ride->stations[stationNum].LastPeepInQueue; - ride->stations[stationNum].LastPeepInQueue = peep->sprite_index; - peep->GuestNextInQueue = previous_last; + ride->stations[stationNum].LastPeepInQueue = guest->sprite_index; + guest->GuestNextInQueue = previous_last; ride->stations[stationNum].QueueLength++; - peep->CurrentRide = rideIndex; - peep->CurrentRideStation = stationNum; - peep->DaysInQueue = 0; - peep->SetState(PeepState::Queuing); - peep->RideSubState = PeepRideSubState::AtQueueFront; - peep->TimeInQueue = 0; - if (peep->PeepFlags & PEEP_FLAGS_TRACKING) + guest->CurrentRide = rideIndex; + guest->CurrentRideStation = stationNum; + guest->DaysInQueue = 0; + guest->SetState(PeepState::Queuing); + guest->RideSubState = PeepRideSubState::AtQueueFront; + guest->TimeInQueue = 0; + if (guest->PeepFlags & PEEP_FLAGS_TRACKING) { auto ft = Formatter(); - peep->FormatNameTo(ft); + guest->FormatNameTo(ft); ride->FormatNameTo(ft); if (gConfigNotifications.guest_queuing_for_ride) { News::AddItemToQueue( - News::ItemType::PeepOnRide, STR_PEEP_TRACKING_PEEP_JOINED_QUEUE_FOR_X, peep->sprite_index, ft); + News::ItemType::PeepOnRide, STR_PEEP_TRACKING_PEEP_JOINED_QUEUE_FOR_X, guest->sprite_index, ft); } } } @@ -2424,49 +1712,49 @@ static bool peep_interact_with_entrance(Peep* peep, const CoordsXYE& coords, uin // If not the centre of the entrance arch if (tile_element->AsEntrance()->GetSequenceIndex() != 0) { - peep_return_to_centre_of_tile(peep); + peep_return_to_centre_of_tile(guest); return true; } uint8_t entranceDirection = tile_element->GetDirection(); - if (entranceDirection != peep->PeepDirection) + if (entranceDirection != guest->PeepDirection) { - if (direction_reverse(entranceDirection) != peep->PeepDirection) + if (direction_reverse(entranceDirection) != guest->PeepDirection) { - peep_return_to_centre_of_tile(peep); + peep_return_to_centre_of_tile(guest); return true; } // Peep is leaving the park. - if (peep->State != PeepState::Walking) + if (guest->State != PeepState::Walking) { - peep_return_to_centre_of_tile(peep); + peep_return_to_centre_of_tile(guest); return true; } - if (!(peep->PeepFlags & PEEP_FLAGS_LEAVING_PARK)) + if (!(guest->PeepFlags & PEEP_FLAGS_LEAVING_PARK)) { // If the park is open and leaving flag isn't set return to centre if (gParkFlags & PARK_FLAGS_PARK_OPEN) { - peep_return_to_centre_of_tile(peep); + peep_return_to_centre_of_tile(guest); return true; } } - auto destination = peep->GetDestination() + CoordsDirectionDelta[peep->PeepDirection]; - peep->SetDestination(destination, 9); - peep->MoveTo({ coords, peep->z }); - peep->SetState(PeepState::LeavingPark); + auto destination = guest->GetDestination() + CoordsDirectionDelta[guest->PeepDirection]; + guest->SetDestination(destination, 9); + guest->MoveTo({ coords, guest->z }); + guest->SetState(PeepState::LeavingPark); - peep->Var37 = 0; - if (peep->PeepFlags & PEEP_FLAGS_TRACKING) + guest->Var37 = 0; + if (guest->PeepFlags & PEEP_FLAGS_TRACKING) { auto ft = Formatter(); - peep->FormatNameTo(ft); + guest->FormatNameTo(ft); if (gConfigNotifications.guest_left_park) { - News::AddItemToQueue(News::ItemType::PeepOnRide, STR_PEEP_TRACKING_LEFT_PARK, peep->sprite_index, ft); + News::AddItemToQueue(News::ItemType::PeepOnRide, STR_PEEP_TRACKING_LEFT_PARK, guest->sprite_index, ft); } } return true; @@ -2474,19 +1762,19 @@ static bool peep_interact_with_entrance(Peep* peep, const CoordsXYE& coords, uin // Peep is entering the park. - if (peep->State != PeepState::EnteringPark) + if (guest->State != PeepState::EnteringPark) { - peep_return_to_centre_of_tile(peep); + peep_return_to_centre_of_tile(guest); return true; } if (!(gParkFlags & PARK_FLAGS_PARK_OPEN)) { - peep->State = PeepState::LeavingPark; - peep->Var37 = 1; + guest->State = PeepState::LeavingPark; + guest->Var37 = 1; decrement_guests_heading_for_park(); - peep_window_state_update(peep); - peep_return_to_centre_of_tile(peep); + peep_window_state_update(guest); + peep_return_to_centre_of_tile(guest); return true; } @@ -2546,55 +1834,55 @@ static bool peep_interact_with_entrance(Peep* peep, const CoordsXYE& coords, uin if (!found) { - peep->State = PeepState::LeavingPark; - peep->Var37 = 1; + guest->State = PeepState::LeavingPark; + guest->Var37 = 1; decrement_guests_heading_for_park(); - peep_window_state_update(peep); - peep_return_to_centre_of_tile(peep); + peep_window_state_update(guest); + peep_return_to_centre_of_tile(guest); return true; } money16 entranceFee = park_get_entrance_fee(); if (entranceFee != 0) { - if (peep->HasItem(ShopItem::Voucher)) + if (guest->HasItem(ShopItem::Voucher)) { - if (peep->VoucherType == VOUCHER_TYPE_PARK_ENTRY_HALF_PRICE) + if (guest->VoucherType == VOUCHER_TYPE_PARK_ENTRY_HALF_PRICE) { entranceFee /= 2; - peep->RemoveItem(ShopItem::Voucher); - peep->WindowInvalidateFlags |= PEEP_INVALIDATE_PEEP_INVENTORY; + guest->RemoveItem(ShopItem::Voucher); + guest->WindowInvalidateFlags |= PEEP_INVALIDATE_PEEP_INVENTORY; } - else if (peep->VoucherType == VOUCHER_TYPE_PARK_ENTRY_FREE) + else if (guest->VoucherType == VOUCHER_TYPE_PARK_ENTRY_FREE) { entranceFee = 0; - peep->RemoveItem(ShopItem::Voucher); - peep->WindowInvalidateFlags |= PEEP_INVALIDATE_PEEP_INVENTORY; + guest->RemoveItem(ShopItem::Voucher); + guest->WindowInvalidateFlags |= PEEP_INVALIDATE_PEEP_INVENTORY; } } - if (entranceFee > peep->CashInPocket) + if (entranceFee > guest->CashInPocket) { - peep->State = PeepState::LeavingPark; - peep->Var37 = 1; + guest->State = PeepState::LeavingPark; + guest->Var37 = 1; decrement_guests_heading_for_park(); - peep_window_state_update(peep); - peep_return_to_centre_of_tile(peep); + peep_window_state_update(guest); + peep_return_to_centre_of_tile(guest); return true; } gTotalIncomeFromAdmissions += entranceFee; - guest->SpendMoney(peep->PaidToEnter, entranceFee, ExpenditureType::ParkEntranceTickets); - peep->PeepFlags |= PEEP_FLAGS_HAS_PAID_FOR_PARK_ENTRY; + guest->SpendMoney(guest->PaidToEnter, entranceFee, ExpenditureType::ParkEntranceTickets); + guest->PeepFlags |= PEEP_FLAGS_HAS_PAID_FOR_PARK_ENTRY; } gTotalAdmissions++; window_invalidate_by_number(WC_PARK_INFORMATION, 0); - peep->Var37 = 1; - auto destination = peep->GetDestination(); - destination += CoordsDirectionDelta[peep->PeepDirection]; - peep->SetDestination(destination, 7); - peep->MoveTo({ coords, peep->z }); + guest->Var37 = 1; + auto destination = guest->GetDestination(); + destination += CoordsDirectionDelta[guest->PeepDirection]; + guest->SetDestination(destination, 7); + guest->MoveTo({ coords, guest->z }); } return true; } @@ -2611,15 +1899,16 @@ static void peep_footpath_move_forward(Peep* peep, const CoordsXYE& coords, bool int16_t z = peep->GetZOnSlope(coords.x, coords.y); - if (peep->Is()) + auto* guest = peep->As(); + if (guest == nullptr) { peep->MoveTo({ coords, z }); return; } - uint8_t vandalThoughtTimeout = (peep->VandalismSeen & 0xC0) >> 6; + uint8_t vandalThoughtTimeout = (guest->VandalismSeen & 0xC0) >> 6; // Advance the vandalised tiles by 1 - uint8_t vandalisedTiles = (peep->VandalismSeen * 2) & 0x3F; + uint8_t vandalisedTiles = (guest->VandalismSeen * 2) & 0x3F; if (vandalism) { @@ -2630,8 +1919,8 @@ static void peep_footpath_move_forward(Peep* peep, const CoordsXYE& coords, bool { if ((scenario_rand() & 0xFFFF) <= 10922) { - peep->InsertNewThought(PeepThoughtType::Vandalism, PEEP_THOUGHT_ITEM_NONE); - peep->HappinessTarget = std::max(0, peep->HappinessTarget - 17); + guest->InsertNewThought(PeepThoughtType::Vandalism, PEEP_THOUGHT_ITEM_NONE); + guest->HappinessTarget = std::max(0, guest->HappinessTarget - 17); } vandalThoughtTimeout = 3; } @@ -2642,7 +1931,7 @@ static void peep_footpath_move_forward(Peep* peep, const CoordsXYE& coords, bool vandalThoughtTimeout--; } - peep->VandalismSeen = (vandalThoughtTimeout << 6) | vandalisedTiles; + guest->VandalismSeen = (vandalThoughtTimeout << 6) | vandalisedTiles; uint16_t crowded = 0; uint8_t litter_count = 0; uint8_t sick_count = 0; @@ -2654,14 +1943,14 @@ static void peep_footpath_move_forward(Peep* peep, const CoordsXYE& coords, bool if (other_peep->State != PeepState::Walking) continue; - if (abs(other_peep->z - peep->NextLoc.z) > 16) + if (abs(other_peep->z - guest->NextLoc.z) > 16) continue; crowded++; continue; } else if (auto litter = entity->As(); litter != nullptr) { - if (abs(litter->z - peep->NextLoc.z) > 16) + if (abs(litter->z - guest->NextLoc.z) > 16) continue; litter_count++; @@ -2673,23 +1962,23 @@ static void peep_footpath_move_forward(Peep* peep, const CoordsXYE& coords, bool } } - if (crowded >= 10 && peep->State == PeepState::Walking && (scenario_rand() & 0xFFFF) <= 21845) + if (crowded >= 10 && guest->State == PeepState::Walking && (scenario_rand() & 0xFFFF) <= 21845) { - peep->InsertNewThought(PeepThoughtType::Crowded, PEEP_THOUGHT_ITEM_NONE); - peep->HappinessTarget = std::max(0, peep->HappinessTarget - 14); + guest->InsertNewThought(PeepThoughtType::Crowded, PEEP_THOUGHT_ITEM_NONE); + guest->HappinessTarget = std::max(0, guest->HappinessTarget - 14); } litter_count = std::min(static_cast(3), litter_count); sick_count = std::min(static_cast(3), sick_count); - uint8_t disgusting_time = peep->DisgustingCount & 0xC0; - uint8_t disgusting_count = ((peep->DisgustingCount & 0xF) << 2) | sick_count; - peep->DisgustingCount = disgusting_count | disgusting_time; + uint8_t disgusting_time = guest->DisgustingCount & 0xC0; + uint8_t disgusting_count = ((guest->DisgustingCount & 0xF) << 2) | sick_count; + guest->DisgustingCount = disgusting_count | disgusting_time; if (disgusting_time & 0xC0 && (scenario_rand() & 0xFFFF) <= 4369) { // Reduce the disgusting time - peep->DisgustingCount -= 0x40; + guest->DisgustingCount -= 0x40; } else { @@ -2701,21 +1990,21 @@ static void peep_footpath_move_forward(Peep* peep, const CoordsXYE& coords, bool if (total_sick >= 3 && (scenario_rand() & 0xFFFF) <= 10922) { - peep->InsertNewThought(PeepThoughtType::PathDisgusting, PEEP_THOUGHT_ITEM_NONE); - peep->HappinessTarget = std::max(0, peep->HappinessTarget - 17); + guest->InsertNewThought(PeepThoughtType::PathDisgusting, PEEP_THOUGHT_ITEM_NONE); + guest->HappinessTarget = std::max(0, guest->HappinessTarget - 17); // Reset disgusting time - peep->DisgustingCount |= 0xC0; + guest->DisgustingCount |= 0xC0; } } - uint8_t litter_time = peep->LitterCount & 0xC0; - litter_count = ((peep->LitterCount & 0xF) << 2) | litter_count; - peep->LitterCount = litter_count | litter_time; + uint8_t litter_time = guest->LitterCount & 0xC0; + litter_count = ((guest->LitterCount & 0xF) << 2) | litter_count; + guest->LitterCount = litter_count | litter_time; if (litter_time & 0xC0 && (scenario_rand() & 0xFFFF) <= 4369) { // Reduce the litter time - peep->LitterCount -= 0x40; + guest->LitterCount -= 0x40; } else { @@ -2727,14 +2016,14 @@ static void peep_footpath_move_forward(Peep* peep, const CoordsXYE& coords, bool if (total_litter >= 3 && (scenario_rand() & 0xFFFF) <= 10922) { - peep->InsertNewThought(PeepThoughtType::BadLitter, PEEP_THOUGHT_ITEM_NONE); - peep->HappinessTarget = std::max(0, peep->HappinessTarget - 17); + guest->InsertNewThought(PeepThoughtType::BadLitter, PEEP_THOUGHT_ITEM_NONE); + guest->HappinessTarget = std::max(0, guest->HappinessTarget - 17); // Reset litter time - peep->LitterCount |= 0xC0; + guest->LitterCount |= 0xC0; } } - peep->MoveTo({ coords, z }); + guest->MoveTo({ coords, z }); } /** @@ -2753,54 +2042,54 @@ static void peep_interact_with_path(Peep* peep, const CoordsXYE& coords) } int16_t z = tile_element->GetBaseZ(); + auto* guest = peep->As(); if (map_is_location_owned({ coords, z })) { - if (peep->OutsideOfPark) + if (guest && guest->OutsideOfPark) { - peep_return_to_centre_of_tile(peep); + peep_return_to_centre_of_tile(guest); return; } } else { - if (!peep->OutsideOfPark) + if (guest == nullptr || !guest->OutsideOfPark) { peep_return_to_centre_of_tile(peep); return; } } - auto* guest = peep->As(); if (guest != nullptr && tile_element->AsPath()->IsQueue()) { auto rideIndex = tile_element->AsPath()->GetRideIndex(); - if (peep->State == PeepState::Queuing) + if (guest->State == PeepState::Queuing) { // Check if this queue is connected to the ride the // peep is queuing for, i.e. the player hasn't edited // the queue, rebuilt the ride, etc. - if (peep->CurrentRide == rideIndex) + if (guest->CurrentRide == rideIndex) { - peep_footpath_move_forward(peep, { coords, tile_element }, vandalism_present); + peep_footpath_move_forward(guest, { coords, tile_element }, vandalism_present); } else { // Queue got disconnected from the original ride. - peep->InteractionRideIndex = RIDE_ID_NULL; + guest->InteractionRideIndex = RIDE_ID_NULL; guest->RemoveFromQueue(); - peep->SetState(PeepState::One); - peep_footpath_move_forward(peep, { coords, tile_element }, vandalism_present); + guest->SetState(PeepState::One); + peep_footpath_move_forward(guest, { coords, tile_element }, vandalism_present); } } else { // Peep is not queuing. - peep->TimeLost = 0; + guest->TimeLost = 0; auto stationNum = tile_element->AsPath()->GetStationIndex(); if ((tile_element->AsPath()->HasQueueBanner()) && (tile_element->AsPath()->GetQueueBannerDirection() - == direction_reverse(peep->PeepDirection)) // Ride sign is facing the direction the peep is walking + == direction_reverse(guest->PeepDirection)) // Ride sign is facing the direction the peep is walking ) { /* Peep is approaching the entrance of a ride queue. @@ -2809,59 +2098,59 @@ static void peep_interact_with_path(Peep* peep, const CoordsXYE& coords) if (ride != nullptr && guest->ShouldGoOnRide(ride, stationNum, true, false)) { // Peep has decided to go on the ride at the queue. - peep->InteractionRideIndex = rideIndex; + guest->InteractionRideIndex = rideIndex; // Add the peep to the ride queue. uint16_t old_last_peep = ride->stations[stationNum].LastPeepInQueue; - ride->stations[stationNum].LastPeepInQueue = peep->sprite_index; - peep->GuestNextInQueue = old_last_peep; + ride->stations[stationNum].LastPeepInQueue = guest->sprite_index; + guest->GuestNextInQueue = old_last_peep; ride->stations[stationNum].QueueLength++; - peep_decrement_num_riders(peep); - peep->CurrentRide = rideIndex; - peep->CurrentRideStation = stationNum; - peep->State = PeepState::Queuing; - peep->DaysInQueue = 0; - peep_window_state_update(peep); + peep_decrement_num_riders(guest); + guest->CurrentRide = rideIndex; + guest->CurrentRideStation = stationNum; + guest->State = PeepState::Queuing; + guest->DaysInQueue = 0; + peep_window_state_update(guest); - peep->RideSubState = PeepRideSubState::InQueue; - peep->DestinationTolerance = 2; - peep->TimeInQueue = 0; - if (peep->PeepFlags & PEEP_FLAGS_TRACKING) + guest->RideSubState = PeepRideSubState::InQueue; + guest->DestinationTolerance = 2; + guest->TimeInQueue = 0; + if (guest->PeepFlags & PEEP_FLAGS_TRACKING) { auto ft = Formatter(); - peep->FormatNameTo(ft); + guest->FormatNameTo(ft); ride->FormatNameTo(ft); if (gConfigNotifications.guest_queuing_for_ride) { News::AddItemToQueue( - News::ItemType::PeepOnRide, STR_PEEP_TRACKING_PEEP_JOINED_QUEUE_FOR_X, peep->sprite_index, ft); + News::ItemType::PeepOnRide, STR_PEEP_TRACKING_PEEP_JOINED_QUEUE_FOR_X, guest->sprite_index, ft); } } - peep_footpath_move_forward(peep, { coords, tile_element }, vandalism_present); + peep_footpath_move_forward(guest, { coords, tile_element }, vandalism_present); } else { // Peep has decided not to go on the ride. - peep_return_to_centre_of_tile(peep); + peep_return_to_centre_of_tile(guest); } } else { /* Peep is approaching a queue tile without a ride * sign facing the peep. */ - peep_footpath_move_forward(peep, { coords, tile_element }, vandalism_present); + peep_footpath_move_forward(guest, { coords, tile_element }, vandalism_present); } } } else { peep->InteractionRideIndex = RIDE_ID_NULL; - if (peep->State == PeepState::Queuing) + if (guest != nullptr && peep->State == PeepState::Queuing) { - peep->RemoveFromQueue(); - peep->SetState(PeepState::One); + guest->RemoveFromQueue(); + guest->SetState(PeepState::One); } peep_footpath_move_forward(peep, { coords, tile_element }, vandalism_present); } @@ -2887,37 +2176,37 @@ static bool peep_interact_with_shop(Peep* peep, const CoordsXYE& coords) // If we are queuing ignore the 'shop' // This can happen when paths clip through track - if (peep->State == PeepState::Queuing) + if (guest->State == PeepState::Queuing) { return false; } - peep->TimeLost = 0; + guest->TimeLost = 0; if (ride->status != RIDE_STATUS_OPEN) { - peep_return_to_centre_of_tile(peep); + peep_return_to_centre_of_tile(guest); return true; } - if (peep->InteractionRideIndex == rideIndex) + if (guest->InteractionRideIndex == rideIndex) { - peep_return_to_centre_of_tile(peep); + peep_return_to_centre_of_tile(guest); return true; } - if (peep->PeepFlags & PEEP_FLAGS_LEAVING_PARK) + if (guest->PeepFlags & PEEP_FLAGS_LEAVING_PARK) { - peep_return_to_centre_of_tile(peep); + peep_return_to_centre_of_tile(guest); return true; } if (ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_PEEP_SHOULD_GO_INSIDE_FACILITY)) { - peep->TimeLost = 0; + guest->TimeLost = 0; if (!guest->ShouldGoOnRide(ride, 0, false, false)) { - peep_return_to_centre_of_tile(peep); + peep_return_to_centre_of_tile(guest); return true; } @@ -2933,35 +2222,35 @@ static bool peep_interact_with_shop(Peep* peep, const CoordsXYE& coords) } auto coordsCentre = coords.ToTileCentre(); - peep->SetDestination(coordsCentre, 3); - peep->CurrentRide = rideIndex; - peep->SetState(PeepState::EnteringRide); - peep->RideSubState = PeepRideSubState::ApproachShop; + guest->SetDestination(coordsCentre, 3); + guest->CurrentRide = rideIndex; + guest->SetState(PeepState::EnteringRide); + guest->RideSubState = PeepRideSubState::ApproachShop; - peep->GuestTimeOnRide = 0; + guest->GuestTimeOnRide = 0; ride->cur_num_customers++; - if (peep->PeepFlags & PEEP_FLAGS_TRACKING) + if (guest->PeepFlags & PEEP_FLAGS_TRACKING) { auto ft = Formatter(); - peep->FormatNameTo(ft); + guest->FormatNameTo(ft); ride->FormatNameTo(ft); rct_string_id string_id = ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_IN_RIDE) ? STR_PEEP_TRACKING_PEEP_IS_IN_X : STR_PEEP_TRACKING_PEEP_IS_ON_X; if (gConfigNotifications.guest_used_facility) { - News::AddItemToQueue(News::ItemType::PeepOnRide, string_id, peep->sprite_index, ft); + News::AddItemToQueue(News::ItemType::PeepOnRide, string_id, guest->sprite_index, ft); } } } else { - if (peep->GuestHeadingToRideId == rideIndex) - peep->GuestHeadingToRideId = RIDE_ID_NULL; - peep->ActionSpriteImageOffset = _unk_F1AEF0; - peep->SetState(PeepState::Buying); - peep->CurrentRide = rideIndex; - peep->SubState = 0; + if (guest->GuestHeadingToRideId == rideIndex) + guest->GuestHeadingToRideId = RIDE_ID_NULL; + guest->ActionSpriteImageOffset = _unk_F1AEF0; + guest->SetState(PeepState::Buying); + guest->CurrentRide = rideIndex; + guest->SubState = 0; } return true; @@ -2985,9 +2274,10 @@ void Peep::PerformNextAction(uint8_t& pathing_result, TileElement*& tile_result) if (Action == PeepActionType::None1) Action = PeepActionType::None2; - if (State == PeepState::Queuing) + auto* guest = As(); + if (State == PeepState::Queuing && guest != nullptr) { - if (peep_update_queue_position(this, previousAction)) + if (guest->UpdateQueuePosition(previousAction)) return; } @@ -2997,7 +2287,6 @@ void Peep::PerformNextAction(uint8_t& pathing_result, TileElement*& tile_result) pathing_result |= PATHING_DESTINATION_REACHED; uint8_t result = 0; - auto* guest = As(); if (guest != nullptr) { result = guest_path_finding(guest); @@ -3026,7 +2315,7 @@ void Peep::PerformNextAction(uint8_t& pathing_result, TileElement*& tile_result) if (map_is_edge(newLoc)) { - if (OutsideOfPark) + if (guest != nullptr && guest->OutsideOfPark) { pathing_result |= PATHING_OUTSIDE_PARK; } @@ -3079,9 +2368,9 @@ void Peep::PerformNextAction(uint8_t& pathing_result, TileElement*& tile_result) if (height <= 3 || (Is() && height <= 32)) { InteractionRideIndex = RIDE_ID_NULL; - if (State == PeepState::Queuing) + if (guest != nullptr && State == PeepState::Queuing) { - RemoveFromQueue(); + guest->RemoveFromQueue(); SetState(PeepState::One); } @@ -3105,12 +2394,13 @@ void Peep::PerformNextAction(uint8_t& pathing_result, TileElement*& tile_result) return; } - if (Is() && !GetNextIsSurface()) + auto* staff = As(); + if (staff != nullptr && !GetNextIsSurface()) { // Prevent staff from leaving the path on their own unless they're allowed to mow. - if (!((this->StaffOrders & STAFF_ORDERS_MOWING) && this->StaffMowingTimeout >= 12)) + if (!((staff->StaffOrders & STAFF_ORDERS_MOWING) && staff->StaffMowingTimeout >= 12)) { - peep_return_to_centre_of_tile(this); + peep_return_to_centre_of_tile(staff); return; } } @@ -3296,89 +2586,20 @@ static void peep_release_balloon(Guest* peep, int16_t spawn_height) } } -/** - * - * rct2: 0x006966A9 - */ -void Peep::RemoveFromQueue() -{ - auto ride = get_ride(CurrentRide); - if (ride == nullptr) - return; - - auto& station = ride->stations[CurrentRideStation]; - // Make sure we don't underflow, building while paused might reset it to 0 where peeps have - // not yet left the queue. - if (station.QueueLength > 0) - { - station.QueueLength--; - } - - if (sprite_index == station.LastPeepInQueue) - { - station.LastPeepInQueue = GuestNextInQueue; - return; - } - - auto* otherGuest = GetEntity(station.LastPeepInQueue); - if (otherGuest == nullptr) - { - log_error("Invalid Guest Queue list!"); - return; - } - for (; otherGuest != nullptr; otherGuest = GetEntity(otherGuest->GuestNextInQueue)) - { - if (sprite_index == otherGuest->GuestNextInQueue) - { - otherGuest->GuestNextInQueue = GuestNextInQueue; - return; - } - } -} - /** * * rct2: 0x0069A512 */ void Peep::RemoveFromRide() { - if (State == PeepState::Queuing) + auto* guest = As(); + if (guest != nullptr && State == PeepState::Queuing) { - RemoveFromQueue(); + guest->RemoveFromQueue(); } StateReset(); } -uint64_t Peep::GetItemFlags() const -{ - return ItemFlags; -} - -void Peep::SetItemFlags(uint64_t itemFlags) -{ - ItemFlags = itemFlags; -} - -void Peep::RemoveAllItems() -{ - ItemFlags = 0; -} - -void Peep::RemoveItem(ShopItem item) -{ - ItemFlags &= ~EnumToFlag(item); -} - -void Peep::GiveItem(ShopItem item) -{ - ItemFlags |= EnumToFlag(item); -} - -bool Peep::HasItem(ShopItem peepItem) const -{ - return GetItemFlags() & EnumToFlag(peepItem); -} - void Peep::SetDestination(const CoordsXY& coords) { DestinationX = static_cast(coords.x); diff --git a/src/openrct2/peep/Peep.h b/src/openrct2/peep/Peep.h index 90209e13a2..094831c7c6 100644 --- a/src/openrct2/peep/Peep.h +++ b/src/openrct2/peep/Peep.h @@ -736,10 +736,7 @@ public: // Peep void Pickup(); void PickupAbort(int32_t old_x); std::unique_ptr Place(const TileCoordsXYZ& location, bool apply); - static Peep* Generate(const CoordsXYZ& coords); - void RemoveFromQueue(); void RemoveFromRide(); - void InsertNewThought(PeepThoughtType thought_type, uint8_t thought_arguments); void FormatActionTo(Formatter&) const; void FormatNameTo(Formatter&) const; std::string GetName() const; @@ -748,12 +745,6 @@ public: // Peep // Reset the peep's stored goal, which means they will forget any stored pathfinding history // on the next peep_pathfind_choose_direction call. void ResetPathfindGoal(); - uint64_t GetItemFlags() const; - void SetItemFlags(uint64_t itemFlags); - void RemoveAllItems(); - void RemoveItem(ShopItem item); - void GiveItem(ShopItem item); - bool HasItem(ShopItem peepItem) const; void SetDestination(const CoordsXY& coords); void SetDestination(const CoordsXY& coords, int32_t tolerance); @@ -816,6 +807,17 @@ public: void HandleEasterEggName(); int32_t GetEasterEggNameId() const; void UpdateEasterEggInteractions(); + void InsertNewThought(PeepThoughtType thought_type, uint8_t thought_arguments); + static Guest* Generate(const CoordsXYZ& coords); + bool UpdateQueuePosition(PeepActionType previous_action); + void RemoveFromQueue(); + + uint64_t GetItemFlags() const; + void SetItemFlags(uint64_t itemFlags); + void RemoveAllItems(); + void RemoveItem(ShopItem item); + void GiveItem(ShopItem item); + bool HasItem(ShopItem peepItem) const; private: void UpdateRide(); @@ -1006,7 +1008,6 @@ extern uint32_t gNextGuestNumber; extern uint8_t gPeepWarningThrottle[16]; -Peep* try_get_guest(uint16_t spriteIndex); int32_t peep_get_staff_count(); void peep_update_all(); void peep_problem_warnings_update(); @@ -1015,8 +1016,8 @@ void peep_update_crowd_noise(); void peep_update_days_in_queue(); void peep_applause(); void peep_thought_set_format_args(const rct_peep_thought* thought, Formatter& ft); -int32_t get_peep_face_sprite_small(Peep* peep); -int32_t get_peep_face_sprite_large(Peep* peep); +int32_t get_peep_face_sprite_small(Guest* peep); +int32_t get_peep_face_sprite_large(Guest* peep); void peep_sprite_remove(Peep* peep); void peep_window_state_update(Peep* peep); diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index edc8b8a32e..575b4eb101 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -1253,157 +1253,38 @@ private: dst->SetName(GetUserString(src->name_string_idx)); } - dst->OutsideOfPark = static_cast(src->outside_of_park); - dst->State = static_cast(src->state); dst->SubState = src->sub_state; dst->NextLoc = { src->next_x, src->next_y, src->next_z * RCT1_COORDS_Z_STEP }; dst->NextFlags = src->next_flags; dst->Var37 = src->var_37; - dst->TimeToConsume = src->time_to_consume; dst->StepProgress = src->step_progress; - dst->VandalismSeen = src->vandalism_seen; - dst->TshirtColour = RCT1::GetColour(src->tshirt_colour); dst->TrousersColour = RCT1::GetColour(src->trousers_colour); - dst->UmbrellaColour = RCT1::GetColour(src->umbrella_colour); - dst->HatColour = RCT1::GetColour(src->hat_colour); - - // Balloons were always blue in RCT1 without AA/LL - if (_gameVersion == FILE_VERSION_RCT1) - { - dst->BalloonColour = COLOUR_LIGHT_BLUE; - } - else - { - dst->BalloonColour = RCT1::GetColour(src->balloon_colour); - } - dst->DestinationX = src->destination_x; dst->DestinationY = src->destination_y; dst->DestinationTolerance = src->destination_tolerance; dst->PeepDirection = src->direction; - dst->Energy = src->energy; dst->EnergyTarget = src->energy_target; - dst->Happiness = src->happiness; - dst->HappinessTarget = src->happiness_target; - dst->Nausea = src->nausea; - dst->NauseaTarget = src->nausea_target; - dst->Hunger = src->hunger; - dst->Thirst = src->thirst; - dst->Toilet = src->toilet; dst->Mass = src->mass; - - dst->LitterCount = src->litter_count; - dst->DisgustingCount = src->disgusting_count; - - dst->Intensity = static_cast(src->intensity); - dst->NauseaTolerance = static_cast(src->nausea_tolerance); dst->WindowInvalidateFlags = 0; - dst->CurrentRide = RCT12RideIdToOpenRCT2RideId(src->current_ride); dst->CurrentRideStation = src->current_ride_station; dst->CurrentTrain = src->current_train; dst->CurrentCar = src->current_car; dst->CurrentSeat = src->current_seat; - dst->GuestTimeOnRide = src->time_on_ride; - dst->DaysInQueue = src->days_in_queue; - dst->InteractionRideIndex = RCT12RideIdToOpenRCT2RideId(src->interaction_ride_index); - dst->Id = src->id; - dst->CashInPocket = src->cash_in_pocket; - dst->CashSpent = src->cash_spent; - // This doubles as staff hire date - dst->ParkEntryTime = src->park_entry_time; - - // This doubles as staff type - dst->GuestNumRides = src->no_of_rides; - - dst->AmountOfDrinks = src->no_of_drinks; - dst->AmountOfFood = src->no_of_food; - dst->AmountOfSouvenirs = src->no_of_souvenirs; - - dst->PaidToEnter = src->paid_to_enter; - dst->PaidOnRides = src->paid_on_rides; - dst->PaidOnDrink = src->paid_on_drink; - dst->PaidOnFood = src->paid_on_food; - dst->PaidOnSouvenirs = src->paid_on_souvenirs; - - dst->VoucherRideId = RCT12RideIdToOpenRCT2RideId(src->voucher_arguments); - dst->VoucherType = src->voucher_type; - - dst->SurroundingsThoughtTimeout = src->surroundings_thought_timeout; - dst->Angriness = src->angriness; - dst->TimeLost = src->time_lost; - - for (size_t i = 0; i < 32; i++) - { - dst->RidesBeenOn[i] = src->rides_been_on[i]; - } - for (size_t i = 0; i < 16; i++) - { - dst->RideTypesBeenOn[i] = src->ride_types_been_on[i]; - } - - dst->Photo1RideRef = RCT12RideIdToOpenRCT2RideId(src->photo1_ride_ref); - - for (size_t i = 0; i < std::size(src->thoughts); i++) - { - auto srcThought = &src->thoughts[i]; - auto dstThought = &dst->Thoughts[i]; - dstThought->type = static_cast(srcThought->type); - dstThought->item = srcThought->item; - dstThought->freshness = srcThought->freshness; - dstThought->fresh_timeout = srcThought->fresh_timeout; - } - - dst->PreviousRide = RCT12RideIdToOpenRCT2RideId(src->previous_ride); - dst->PreviousRideTimeOut = src->previous_ride_time_out; - dst->PathCheckOptimisation = 0; - dst->GuestHeadingToRideId = RCT12RideIdToOpenRCT2RideId(src->guest_heading_to_ride_id); - // Doubles as staff orders - dst->GuestIsLostCountdown = src->peep_is_lost_countdown; - // The ID is fixed later - dst->GuestNextInQueue = src->next_in_queue; - dst->PeepFlags = 0; dst->PathfindGoal.x = 0xFF; dst->PathfindGoal.y = 0xFF; dst->PathfindGoal.z = 0xFF; dst->PathfindGoal.direction = INVALID_DIRECTION; - - // Guests' favourite ride was only saved in LL. - // Set it to N/A if the save comes from the original or AA. - if (_gameVersion == FILE_VERSION_RCT1_LL) - { - dst->FavouriteRide = RCT12RideIdToOpenRCT2RideId(src->favourite_ride); - dst->FavouriteRideRating = src->favourite_ride_rating; - } - else - { - dst->FavouriteRide = RIDE_ID_NULL; - dst->FavouriteRideRating = 0; - } - - dst->SetItemFlags(src->GetItemFlags()); - - if (dst->Is()) - { - if (dst->OutsideOfPark && dst->State != PeepState::LeavingPark) - { - increment_guests_heading_for_park(); - } - else - { - increment_guests_in_park(); - } - } } - void ImportStaffPatrolArea(Peep* staffmember) + void ImportStaffPatrolArea(Staff* staffmember) { // The patrol areas in RCT1 are encoded as follows, for coordinates x and y, separately for every staff member: // - Chop off the 7 lowest bits of the x and y coordinates, which leaves 5 bits per coordinate. @@ -1446,7 +1327,6 @@ private: void ImportEntityCommonProperties(SpriteBase* dst, const RCT12SpriteBase* src) { - dst->flags = src->flags; dst->sprite_direction = src->sprite_direction; dst->sprite_width = src->sprite_width; dst->sprite_height_negative = src->sprite_height_negative; @@ -2853,6 +2733,7 @@ template<> void S4Importer::ImportEntity(const RCT12SpriteBase& srcBase dst->num_peeps = src->num_peeps; dst->next_free_seat = src->next_free_seat; + dst->IsCrashedVehicle = src->flags & RCT12_SPRITE_FLAGS_IS_CRASHED_VEHICLE_SPRITE; } template<> void S4Importer::ImportEntity(const RCT12SpriteBase& srcBase) @@ -2860,6 +2741,102 @@ template<> void S4Importer::ImportEntity(const RCT12SpriteBase& srcBase) auto* dst = CreateEntityAt(srcBase.sprite_index); auto* src = static_cast(&srcBase); ImportPeep(dst, src); + + dst->OutsideOfPark = static_cast(src->outside_of_park); + dst->TimeToConsume = src->time_to_consume; + dst->VandalismSeen = src->vandalism_seen; + dst->UmbrellaColour = RCT1::GetColour(src->umbrella_colour); + dst->HatColour = RCT1::GetColour(src->hat_colour); + + // Balloons were always blue in RCT1 without AA/LL + if (_gameVersion == FILE_VERSION_RCT1) + { + dst->BalloonColour = COLOUR_LIGHT_BLUE; + } + else + { + dst->BalloonColour = RCT1::GetColour(src->balloon_colour); + } + dst->Happiness = src->happiness; + dst->HappinessTarget = src->happiness_target; + dst->Nausea = src->nausea; + dst->NauseaTarget = src->nausea_target; + dst->Hunger = src->hunger; + dst->Thirst = src->thirst; + dst->Toilet = src->toilet; + dst->LitterCount = src->litter_count; + dst->DisgustingCount = src->disgusting_count; + dst->Intensity = static_cast(src->intensity); + dst->NauseaTolerance = static_cast(src->nausea_tolerance); + dst->GuestTimeOnRide = src->time_on_ride; + dst->DaysInQueue = src->days_in_queue; + dst->CashInPocket = src->cash_in_pocket; + dst->CashSpent = src->cash_spent; + dst->ParkEntryTime = src->park_entry_time; + dst->GuestNumRides = src->no_of_rides; + dst->AmountOfDrinks = src->no_of_drinks; + dst->AmountOfFood = src->no_of_food; + dst->AmountOfSouvenirs = src->no_of_souvenirs; + dst->PaidToEnter = src->paid_to_enter; + dst->PaidOnRides = src->paid_on_rides; + dst->PaidOnDrink = src->paid_on_drink; + dst->PaidOnFood = src->paid_on_food; + dst->PaidOnSouvenirs = src->paid_on_souvenirs; + dst->VoucherRideId = RCT12RideIdToOpenRCT2RideId(src->voucher_arguments); + dst->VoucherType = src->voucher_type; + dst->SurroundingsThoughtTimeout = src->surroundings_thought_timeout; + dst->Angriness = src->angriness; + dst->TimeLost = src->time_lost; + + for (size_t i = 0; i < 32; i++) + { + dst->RidesBeenOn[i] = src->rides_been_on[i]; + } + for (size_t i = 0; i < 16; i++) + { + dst->RideTypesBeenOn[i] = src->ride_types_been_on[i]; + } + + dst->Photo1RideRef = RCT12RideIdToOpenRCT2RideId(src->photo1_ride_ref); + + for (size_t i = 0; i < std::size(src->thoughts); i++) + { + auto srcThought = &src->thoughts[i]; + auto dstThought = &dst->Thoughts[i]; + dstThought->type = static_cast(srcThought->type); + dstThought->item = srcThought->item; + dstThought->freshness = srcThought->freshness; + dstThought->fresh_timeout = srcThought->fresh_timeout; + } + + dst->PreviousRide = RCT12RideIdToOpenRCT2RideId(src->previous_ride); + dst->PreviousRideTimeOut = src->previous_ride_time_out; + dst->GuestHeadingToRideId = RCT12RideIdToOpenRCT2RideId(src->guest_heading_to_ride_id); + dst->GuestIsLostCountdown = src->peep_is_lost_countdown; + dst->GuestNextInQueue = src->next_in_queue; + // Guests' favourite ride was only saved in LL. + // Set it to N/A if the save comes from the original or AA. + if (_gameVersion == FILE_VERSION_RCT1_LL) + { + dst->FavouriteRide = RCT12RideIdToOpenRCT2RideId(src->favourite_ride); + dst->FavouriteRideRating = src->favourite_ride_rating; + } + else + { + dst->FavouriteRide = RIDE_ID_NULL; + dst->FavouriteRideRating = 0; + } + + dst->SetItemFlags(src->GetItemFlags()); + + if (dst->OutsideOfPark && dst->State != PeepState::LeavingPark) + { + increment_guests_heading_for_park(); + } + else + { + increment_guests_in_park(); + } } template<> void S4Importer::ImportEntity(const RCT12SpriteBase& srcBase) @@ -2867,6 +2844,16 @@ template<> void S4Importer::ImportEntity(const RCT12SpriteBase& srcBase) auto* dst = CreateEntityAt(srcBase.sprite_index); auto* src = static_cast(&srcBase); ImportPeep(dst, src); + dst->AssignedStaffType = StaffType(src->staff_type); + dst->MechanicTimeSinceCall = src->mechanic_time_since_call; + dst->HireDate = src->park_entry_time; + dst->StaffId = src->staff_id; + dst->StaffOrders = src->staff_orders; + dst->StaffMowingTimeout = src->staff_mowing_timeout; + dst->StaffLawnsMown = src->paid_to_enter; + dst->StaffGardensWatered = src->paid_on_rides; + dst->StaffLitterSwept = src->paid_on_food; + dst->StaffBinsEmptied = src->paid_on_souvenirs; } template<> void S4Importer::ImportEntity(const RCT12SpriteBase& srcBase) diff --git a/src/openrct2/rct1/T4Importer.cpp b/src/openrct2/rct1/T4Importer.cpp index 707159c2ff..31a19d0d34 100644 --- a/src/openrct2/rct1/T4Importer.cpp +++ b/src/openrct2/rct1/T4Importer.cpp @@ -209,7 +209,7 @@ private: } } // Set remaining vehicles to same colour as first vehicle - for (int32_t i = RCT1_MAX_TRAINS_PER_RIDE; size_t(i) < std::size(td->vehicle_colours); i++) + for (size_t i = RCT1_MAX_TRAINS_PER_RIDE; i < std::size(td->vehicle_colours); i++) { td->vehicle_colours[i] = td->vehicle_colours[0]; td->vehicle_additional_colour[i] = td->vehicle_additional_colour[0]; diff --git a/src/openrct2/rct12/RCT12.h b/src/openrct2/rct12/RCT12.h index fa7a4aaa4c..2e9f1a7613 100644 --- a/src/openrct2/rct12/RCT12.h +++ b/src/openrct2/rct12/RCT12.h @@ -175,6 +175,11 @@ enum RCT12_STATION_STYLE_INVISIBLE, // Added by OpenRCT2 }; +enum +{ + RCT12_SPRITE_FLAGS_IS_CRASHED_VEHICLE_SPRITE = 1 << 7, +}; + #pragma pack(push, 1) struct RCT12xy8 diff --git a/src/openrct2/rct2/RCT2.h b/src/openrct2/rct2/RCT2.h index e99957989c..0be4960f0e 100644 --- a/src/openrct2/rct2/RCT2.h +++ b/src/openrct2/rct2/RCT2.h @@ -812,5 +812,6 @@ struct FootpathMapping std::string_view Railing; }; -const FootpathMapping* GetFootpathSurfaceId(const ObjectEntryDescriptor& desc, bool ideallyLoaded = false, bool isQueue = false); +const FootpathMapping* GetFootpathSurfaceId( + const ObjectEntryDescriptor& desc, bool ideallyLoaded = false, bool isQueue = false); std::optional GetBestObjectEntryForSurface(std::string_view surface, std::string_view railings); diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index c5019673ee..bb832ff9ce 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -1388,11 +1388,9 @@ public: } dst->NextLoc = { src->next_x, src->next_y, src->next_z * COORDS_Z_STEP }; dst->NextFlags = src->next_flags; - dst->OutsideOfPark = static_cast(src->outside_of_park); dst->State = static_cast(src->state); dst->SubState = src->sub_state; dst->SpriteType = static_cast(src->sprite_type); - dst->GuestNumRides = src->no_of_rides; dst->TshirtColour = src->tshirt_colour; dst->TrousersColour = src->trousers_colour; dst->DestinationX = src->destination_x; @@ -1401,27 +1399,8 @@ public: dst->Var37 = src->var_37; dst->Energy = src->energy; dst->EnergyTarget = src->energy_target; - dst->Happiness = src->happiness; - dst->HappinessTarget = src->happiness_target; - dst->Nausea = src->nausea; - dst->NauseaTarget = src->nausea_target; - dst->Hunger = src->hunger; - dst->Thirst = src->thirst; - dst->Toilet = src->toilet; dst->Mass = src->mass; - dst->TimeToConsume = src->time_to_consume; - dst->Intensity = static_cast(src->intensity); - dst->NauseaTolerance = static_cast(src->nausea_tolerance); dst->WindowInvalidateFlags = src->window_invalidate_flags; - dst->PaidOnDrink = src->paid_on_drink; - for (size_t i = 0; i < std::size(src->ride_types_been_on); i++) - { - dst->RideTypesBeenOn[i] = src->ride_types_been_on[i]; - } - dst->SetItemFlags(src->GetItemFlags()); - dst->Photo2RideRef = RCT12RideIdToOpenRCT2RideId(src->photo2_ride_ref); - dst->Photo3RideRef = RCT12RideIdToOpenRCT2RideId(src->photo3_ride_ref); - dst->Photo4RideRef = RCT12RideIdToOpenRCT2RideId(src->photo4_ride_ref); dst->CurrentRide = RCT12RideIdToOpenRCT2RideId(src->current_ride); dst->CurrentRideStation = src->current_ride_station; dst->CurrentTrain = src->current_train; @@ -1433,34 +1412,10 @@ public: dst->Action = static_cast(src->action); dst->ActionFrame = src->action_frame; dst->StepProgress = src->step_progress; - dst->GuestNextInQueue = src->next_in_queue; dst->PeepDirection = src->direction; dst->InteractionRideIndex = RCT12RideIdToOpenRCT2RideId(src->interaction_ride_index); - dst->TimeInQueue = src->time_in_queue; - for (size_t i = 0; i < std::size(src->rides_been_on); i++) - { - dst->RidesBeenOn[i] = src->rides_been_on[i]; - } dst->Id = src->id; - dst->CashInPocket = src->cash_in_pocket; - dst->CashSpent = src->cash_spent; - dst->ParkEntryTime = src->park_entry_time; - dst->RejoinQueueTimeout = src->rejoin_queue_timeout; - dst->PreviousRide = RCT12RideIdToOpenRCT2RideId(src->previous_ride); - dst->PreviousRideTimeOut = src->previous_ride_time_out; - for (size_t i = 0; i < std::size(src->thoughts); i++) - { - auto srcThought = &src->thoughts[i]; - auto dstThought = &dst->Thoughts[i]; - dstThought->type = static_cast(srcThought->type); - dstThought->item = srcThought->item; - dstThought->freshness = srcThought->freshness; - dstThought->fresh_timeout = srcThought->fresh_timeout; - } dst->PathCheckOptimisation = src->path_check_optimisation; - dst->GuestHeadingToRideId = RCT12RideIdToOpenRCT2RideId(src->guest_heading_to_ride_id); - dst->GuestIsLostCountdown = src->peep_is_lost_countdown; - dst->Photo1RideRef = RCT12RideIdToOpenRCT2RideId(src->photo1_ride_ref); dst->PeepFlags = src->peep_flags; dst->PathfindGoal = src->pathfind_goal; for (size_t i = 0; i < std::size(src->pathfind_history); i++) @@ -1468,28 +1423,6 @@ public: dst->PathfindHistory[i] = src->pathfind_history[i]; } dst->WalkingFrameNum = src->no_action_frame_num; - dst->LitterCount = src->litter_count; - dst->GuestTimeOnRide = src->time_on_ride; - dst->DisgustingCount = src->disgusting_count; - dst->PaidToEnter = src->paid_to_enter; - dst->PaidOnRides = src->paid_on_rides; - dst->PaidOnFood = src->paid_on_food; - dst->PaidOnSouvenirs = src->paid_on_souvenirs; - dst->AmountOfFood = src->no_of_food; - dst->AmountOfDrinks = src->no_of_drinks; - dst->AmountOfSouvenirs = src->no_of_souvenirs; - dst->VandalismSeen = src->vandalism_seen; - dst->VoucherType = src->voucher_type; - dst->VoucherRideId = RCT12RideIdToOpenRCT2RideId(src->voucher_arguments); - dst->SurroundingsThoughtTimeout = src->surroundings_thought_timeout; - dst->Angriness = src->angriness; - dst->TimeLost = src->time_lost; - dst->DaysInQueue = src->days_in_queue; - dst->BalloonColour = src->balloon_colour; - dst->UmbrellaColour = src->umbrella_colour; - dst->HatColour = src->hat_colour; - dst->FavouriteRide = RCT12RideIdToOpenRCT2RideId(src->favourite_ride); - dst->FavouriteRideRating = src->favourite_ride_rating; } constexpr EntityType GetEntityTypeFromRCT2Sprite(const RCT12SpriteBase* src) @@ -1560,7 +1493,6 @@ public: dst->Type = GetEntityTypeFromRCT2Sprite(src); dst->sprite_height_negative = src->sprite_height_negative; dst->sprite_index = src->sprite_index; - dst->flags = src->flags; dst->x = src->x; dst->y = src->y; dst->z = src->z; @@ -1757,6 +1689,7 @@ template<> void S6Importer::ImportEntity(const RCT12SpriteBase& baseSrc dst->colours_extended = src->colours_extended; dst->seat_rotation = src->seat_rotation; dst->target_seat_rotation = src->target_seat_rotation; + dst->IsCrashedVehicle = src->flags & RCT12_SPRITE_FLAGS_IS_CRASHED_VEHICLE_SPRITE; } template<> void S6Importer::ImportEntity(const RCT12SpriteBase& baseSrc) @@ -1764,6 +1697,74 @@ template<> void S6Importer::ImportEntity(const RCT12SpriteBase& baseSrc) auto dst = CreateEntityAt(baseSrc.sprite_index); auto src = static_cast(&baseSrc); ImportEntityPeep(dst, src); + + dst->OutsideOfPark = static_cast(src->outside_of_park); + dst->GuestNumRides = src->no_of_rides; + dst->Happiness = src->happiness; + dst->HappinessTarget = src->happiness_target; + dst->Nausea = src->nausea; + dst->NauseaTarget = src->nausea_target; + dst->Hunger = src->hunger; + dst->Thirst = src->thirst; + dst->Toilet = src->toilet; + dst->TimeToConsume = src->time_to_consume; + dst->Intensity = static_cast(src->intensity); + dst->NauseaTolerance = static_cast(src->nausea_tolerance); + dst->PaidOnDrink = src->paid_on_drink; + for (size_t i = 0; i < std::size(src->ride_types_been_on); i++) + { + dst->RideTypesBeenOn[i] = src->ride_types_been_on[i]; + } + dst->SetItemFlags(src->GetItemFlags()); + dst->Photo1RideRef = RCT12RideIdToOpenRCT2RideId(src->photo1_ride_ref); + dst->Photo2RideRef = RCT12RideIdToOpenRCT2RideId(src->photo2_ride_ref); + dst->Photo3RideRef = RCT12RideIdToOpenRCT2RideId(src->photo3_ride_ref); + dst->Photo4RideRef = RCT12RideIdToOpenRCT2RideId(src->photo4_ride_ref); + dst->GuestNextInQueue = src->next_in_queue; + dst->TimeInQueue = src->time_in_queue; + for (size_t i = 0; i < std::size(src->rides_been_on); i++) + { + dst->RidesBeenOn[i] = src->rides_been_on[i]; + } + dst->CashInPocket = src->cash_in_pocket; + dst->CashSpent = src->cash_spent; + dst->ParkEntryTime = src->park_entry_time; + dst->RejoinQueueTimeout = src->rejoin_queue_timeout; + dst->PreviousRide = RCT12RideIdToOpenRCT2RideId(src->previous_ride); + dst->PreviousRideTimeOut = src->previous_ride_time_out; + for (size_t i = 0; i < std::size(src->thoughts); i++) + { + auto srcThought = &src->thoughts[i]; + auto dstThought = &dst->Thoughts[i]; + dstThought->type = static_cast(srcThought->type); + dstThought->item = srcThought->item; + dstThought->freshness = srcThought->freshness; + dstThought->fresh_timeout = srcThought->fresh_timeout; + } + dst->GuestHeadingToRideId = RCT12RideIdToOpenRCT2RideId(src->guest_heading_to_ride_id); + dst->GuestIsLostCountdown = src->peep_is_lost_countdown; + dst->LitterCount = src->litter_count; + dst->GuestTimeOnRide = src->time_on_ride; + dst->DisgustingCount = src->disgusting_count; + dst->PaidToEnter = src->paid_to_enter; + dst->PaidOnRides = src->paid_on_rides; + dst->PaidOnFood = src->paid_on_food; + dst->PaidOnSouvenirs = src->paid_on_souvenirs; + dst->AmountOfFood = src->no_of_food; + dst->AmountOfDrinks = src->no_of_drinks; + dst->AmountOfSouvenirs = src->no_of_souvenirs; + dst->VandalismSeen = src->vandalism_seen; + dst->VoucherType = src->voucher_type; + dst->VoucherRideId = RCT12RideIdToOpenRCT2RideId(src->voucher_arguments); + dst->SurroundingsThoughtTimeout = src->surroundings_thought_timeout; + dst->Angriness = src->angriness; + dst->TimeLost = src->time_lost; + dst->DaysInQueue = src->days_in_queue; + dst->BalloonColour = src->balloon_colour; + dst->UmbrellaColour = src->umbrella_colour; + dst->HatColour = src->hat_colour; + dst->FavouriteRide = RCT12RideIdToOpenRCT2RideId(src->favourite_ride); + dst->FavouriteRideRating = src->favourite_ride_rating; } template<> void S6Importer::ImportEntity(const RCT12SpriteBase& baseSrc) @@ -1771,6 +1772,17 @@ template<> void S6Importer::ImportEntity(const RCT12SpriteBase& baseSrc) auto dst = CreateEntityAt(baseSrc.sprite_index); auto src = static_cast(&baseSrc); ImportEntityPeep(dst, src); + + dst->AssignedStaffType = StaffType(src->staff_type); + dst->MechanicTimeSinceCall = src->mechanic_time_since_call; + dst->HireDate = src->park_entry_time; + dst->StaffId = src->staff_id; + dst->StaffOrders = src->staff_orders; + dst->StaffMowingTimeout = src->staff_mowing_timeout; + dst->StaffLawnsMown = src->paid_to_enter; + dst->StaffGardensWatered = src->paid_on_rides; + dst->StaffLitterSwept = src->paid_on_food; + dst->StaffBinsEmptied = src->paid_on_souvenirs; } template<> void S6Importer::ImportEntity(const RCT12SpriteBase& baseSrc) diff --git a/src/openrct2/ride/CableLift.cpp b/src/openrct2/ride/CableLift.cpp index 5d9791d242..c1dfc7d154 100644 --- a/src/openrct2/ride/CableLift.cpp +++ b/src/openrct2/ride/CableLift.cpp @@ -79,6 +79,7 @@ Vehicle* cable_lift_segment_create( current->num_peeps = 0; current->next_free_seat = 0; current->BoatLocation.setNull(); + current->IsCrashedVehicle = false; return current; } diff --git a/src/openrct2/ride/Ride.cpp b/src/openrct2/ride/Ride.cpp index 47b8bd4a71..887dd2f9c1 100644 --- a/src/openrct2/ride/Ride.cpp +++ b/src/openrct2/ride/Ride.cpp @@ -131,7 +131,7 @@ Direction gRideEntranceExitPlaceDirection; ObjectEntryIndex gLastEntranceStyle; // Static function declarations -Peep* find_closest_mechanic(const CoordsXY& entrancePosition, int32_t forInspection); +Staff* find_closest_mechanic(const CoordsXY& entrancePosition, int32_t forInspection); static void ride_breakdown_status_update(Ride* ride); static void ride_breakdown_update(Ride* ride); static void ride_call_closest_mechanic(Ride* ride); @@ -309,12 +309,12 @@ int32_t Ride::GetMaxQueueTime() const return static_cast(queueTime); } -Peep* Ride::GetQueueHeadGuest(StationIndex stationIndex) const +Guest* Ride::GetQueueHeadGuest(StationIndex stationIndex) const { - Peep* peep; - Peep* result = nullptr; + Guest* peep; + Guest* result = nullptr; uint16_t spriteIndex = stations[stationIndex].LastPeepInQueue; - while ((peep = try_get_guest(spriteIndex)) != nullptr) + while ((peep = TryGetEntity(spriteIndex)) != nullptr) { spriteIndex = peep->GuestNextInQueue; result = peep; @@ -325,9 +325,9 @@ Peep* Ride::GetQueueHeadGuest(StationIndex stationIndex) const void Ride::UpdateQueueLength(StationIndex stationIndex) { uint16_t count = 0; - Peep* peep; + Guest* peep; uint16_t spriteIndex = stations[stationIndex].LastPeepInQueue; - while ((peep = try_get_guest(spriteIndex)) != nullptr) + while ((peep = TryGetEntity(spriteIndex)) != nullptr) { spriteIndex = peep->GuestNextInQueue; count++; @@ -335,13 +335,13 @@ void Ride::UpdateQueueLength(StationIndex stationIndex) stations[stationIndex].QueueLength = count; } -void Ride::QueueInsertGuestAtFront(StationIndex stationIndex, Peep* peep) +void Ride::QueueInsertGuestAtFront(StationIndex stationIndex, Guest* peep) { assert(stationIndex < MAX_STATIONS); assert(peep != nullptr); peep->GuestNextInQueue = SPRITE_INDEX_NULL; - Peep* queueHeadGuest = GetQueueHeadGuest(peep->CurrentRideStation); + auto* queueHeadGuest = GetQueueHeadGuest(peep->CurrentRideStation); if (queueHeadGuest == nullptr) { stations[peep->CurrentRideStation].LastPeepInQueue = peep->sprite_index; @@ -2698,7 +2698,7 @@ static void ride_call_closest_mechanic(Ride* ride) ride_call_mechanic(ride, mechanic, forInspection); } -Peep* ride_find_closest_mechanic(Ride* ride, int32_t forInspection) +Staff* ride_find_closest_mechanic(Ride* ride, int32_t forInspection) { // Get either exit position or entrance position if there is no exit auto stationIndex = ride->inspection_station; @@ -2727,9 +2727,9 @@ Peep* ride_find_closest_mechanic(Ride* ride, int32_t forInspection) * rct2: 0x006B774B (forInspection = 0) * rct2: 0x006B78C3 (forInspection = 1) */ -Peep* find_closest_mechanic(const CoordsXY& entrancePosition, int32_t forInspection) +Staff* find_closest_mechanic(const CoordsXY& entrancePosition, int32_t forInspection) { - Peep* closestMechanic = nullptr; + Staff* closestMechanic = nullptr; uint32_t closestDistance = std::numeric_limits::max(); for (auto peep : EntityList()) @@ -3095,7 +3095,7 @@ vehicle_colour ride_get_vehicle_colour(Ride* ride, int32_t vehicleIndex) vehicle_colour result; // Prevent indexing array out of bounds - vehicleIndex = std::min(vehicleIndex, MAX_CARS_PER_TRAIN); + vehicleIndex = std::min(vehicleIndex, MAX_CARS_PER_TRAIN); result.main = ride->vehicle_colours[vehicleIndex].Body; result.additional_1 = ride->vehicle_colours[vehicleIndex].Trim; @@ -4270,6 +4270,7 @@ static Vehicle* vehicle_create_car( vehicle->num_peeps = 0; vehicle->next_free_seat = 0; vehicle->BoatLocation.setNull(); + vehicle->IsCrashedVehicle = false; return vehicle; } @@ -6401,7 +6402,7 @@ void Ride::UpdateMaxVehicles() { case RideMode::ContinuousCircuitBlockSectioned: case RideMode::PoweredLaunchBlockSectioned: - maxNumTrains = std::clamp(num_stations + num_block_brakes - 1, 1, int32_t(MAX_VEHICLES_PER_RIDE)); + maxNumTrains = std::clamp(num_stations + num_block_brakes - 1, 1, MAX_VEHICLES_PER_RIDE); break; case RideMode::ReverseInclineLaunchedShuttle: case RideMode::PoweredLaunchPasstrough: @@ -7347,3 +7348,17 @@ void Ride::SetMaxCarsPerTrain(uint8_t newValue) min_max_cars_per_train &= ~0x0F; min_max_cars_per_train |= newValue & 0x0F; } + +uint8_t Ride::GetNumShelteredSections() const +{ + return num_sheltered_sections & ShelteredSectionsBits::NumShelteredSectionsMask; +} + +void Ride::IncreaseNumShelteredSections() +{ + auto newNumShelteredSections = GetNumShelteredSections(); + if (newNumShelteredSections != 0x1F) + newNumShelteredSections++; + num_sheltered_sections &= ~ShelteredSectionsBits::NumShelteredSectionsMask; + num_sheltered_sections |= newNumShelteredSections; +} diff --git a/src/openrct2/ride/Ride.h b/src/openrct2/ride/Ride.h index 5c5ed6749f..ba5b2d82e3 100644 --- a/src/openrct2/ride/Ride.h +++ b/src/openrct2/ride/Ride.h @@ -26,9 +26,9 @@ struct IObjectManager; class Formatter; class StationObject; -struct Peep; struct Ride; struct RideTypeDescriptor; +struct Guest; struct Staff; struct Vehicle; @@ -190,6 +190,13 @@ enum class RideClassification KioskOrFacility }; +namespace ShelteredSectionsBits +{ + constexpr const uint8_t NumShelteredSectionsMask = 0b00011111; + constexpr const uint8_t RotatingWhileSheltered = 0b00100000; + constexpr const uint8_t BankingWhileSheltered = 0b01000000; +}; // namespace ShelteredSectionsBits + struct TrackDesign; enum class RideMode : uint8_t; @@ -430,8 +437,8 @@ public: int32_t GetTotalQueueLength() const; int32_t GetMaxQueueTime() const; - void QueueInsertGuestAtFront(StationIndex stationIndex, Peep* peep); - Peep* GetQueueHeadGuest(StationIndex stationIndex) const; + void QueueInsertGuestAtFront(StationIndex stationIndex, Guest* peep); + Guest* GetQueueHeadGuest(StationIndex stationIndex) const; void SetNameToDefault(); std::string GetName() const; @@ -453,6 +460,9 @@ public: uint8_t GetMaxCarsPerTrain() const; void SetMinCarsPerTrain(uint8_t newValue); void SetMaxCarsPerTrain(uint8_t newValue); + + uint8_t GetNumShelteredSections() const; + void IncreaseNumShelteredSections(); }; #pragma pack(push, 1) @@ -1131,7 +1141,7 @@ int32_t ride_get_unused_preset_vehicle_colour(ObjectEntryIndex subType); void ride_set_vehicle_colours_to_random_preset(Ride* ride, uint8_t preset_index); void ride_measurements_update(); void ride_breakdown_add_news_item(Ride* ride); -Peep* ride_find_closest_mechanic(Ride* ride, int32_t forInspection); +Staff* ride_find_closest_mechanic(Ride* ride, int32_t forInspection); int32_t ride_initialise_construction_window(Ride* ride); void ride_construction_invalidate_current_track(); std::optional sub_6C683D( diff --git a/src/openrct2/ride/RideRatings.cpp b/src/openrct2/ride/RideRatings.cpp index 33e4b6fcbd..b987d941be 100644 --- a/src/openrct2/ride/RideRatings.cpp +++ b/src/openrct2/ride/RideRatings.cpp @@ -1326,19 +1326,19 @@ static RatingTuple ride_ratings_get_sheltered_ratings(Ride* ride) /*eax = (ride->var_11C * 30340) >> 16;*/ /*nausea += eax;*/ - if (ride->num_sheltered_sections & 0x40) + if (ride->num_sheltered_sections & ShelteredSectionsBits::BankingWhileSheltered) { excitement += 20; nausea += 15; } - if (ride->num_sheltered_sections & 0x20) + if (ride->num_sheltered_sections & ShelteredSectionsBits::RotatingWhileSheltered) { excitement += 20; nausea += 15; } - uint8_t lowerVal = ride->num_sheltered_sections & 0x1F; + uint8_t lowerVal = ride->GetNumShelteredSections(); lowerVal = std::min(lowerVal, 11); excitement += (lowerVal * 774516) >> 16; diff --git a/src/openrct2/ride/Vehicle.cpp b/src/openrct2/ride/Vehicle.cpp index 54b30cc77c..a466a98b60 100644 --- a/src/openrct2/ride/Vehicle.cpp +++ b/src/openrct2/ride/Vehicle.cpp @@ -1909,20 +1909,16 @@ void Vehicle::UpdateMeasurements() { curRide->testing_flags |= RIDE_TESTING_SHELTERED; - uint8_t numShelteredSections = curRide->num_sheltered_sections & 0x1F; - if (numShelteredSections != 0x1F) - numShelteredSections++; - curRide->num_sheltered_sections &= ~0x1F; - curRide->num_sheltered_sections |= numShelteredSections; + curRide->IncreaseNumShelteredSections(); if (vehicle_sprite_type != 0) { - curRide->num_sheltered_sections |= (1 << 5); + curRide->num_sheltered_sections |= ShelteredSectionsBits::RotatingWhileSheltered; } if (bank_rotation != 0) { - curRide->num_sheltered_sections |= (1 << 6); + curRide->num_sheltered_sections |= ShelteredSectionsBits::BankingWhileSheltered; } } @@ -3610,7 +3606,7 @@ void Vehicle::UpdateCollisionSetup() crashed_vehicle_particle_create(train->colours, { train->x, train->y, train->z }); } - train->flags |= SPRITE_FLAGS_IS_CRASHED_VEHICLE_SPRITE; + train->IsCrashedVehicle = true; train->var_C8 = scenario_rand(); train->var_CA = scenario_rand(); @@ -5369,7 +5365,7 @@ void Vehicle::CrashOnLand() while (numParticles-- != 0) crashed_vehicle_particle_create(colours, { x, y, z }); - flags |= SPRITE_FLAGS_IS_CRASHED_VEHICLE_SPRITE; + IsCrashedVehicle = true; animation_frame = 0; var_C8 = 0; sprite_width = 13; @@ -5432,7 +5428,7 @@ void Vehicle::CrashOnWater() for (int32_t i = 0; i < 10; ++i) crashed_vehicle_particle_create(colours, { x - 4, y + 8, z }); - flags |= SPRITE_FLAGS_IS_CRASHED_VEHICLE_SPRITE; + IsCrashedVehicle = true; animation_frame = 0; var_C8 = 0; sprite_width = 13; diff --git a/src/openrct2/ride/Vehicle.h b/src/openrct2/ride/Vehicle.h index 455e759687..a21814b8b4 100644 --- a/src/openrct2/ride/Vehicle.h +++ b/src/openrct2/ride/Vehicle.h @@ -204,6 +204,7 @@ struct Vehicle : SpriteBase uint8_t seat_rotation; uint8_t target_seat_rotation; CoordsXY BoatLocation; + bool IsCrashedVehicle; constexpr bool IsHead() const { diff --git a/src/openrct2/ride/VehiclePaint.cpp b/src/openrct2/ride/VehiclePaint.cpp index 9183704028..92d57a506b 100644 --- a/src/openrct2/ride/VehiclePaint.cpp +++ b/src/openrct2/ride/VehiclePaint.cpp @@ -3140,7 +3140,7 @@ template<> void PaintEntity(paint_session* session, const Vehicle* vehicle, int3 int32_t y = vehicle->y; int32_t z = vehicle->z; - if (vehicle->flags & SPRITE_FLAGS_IS_CRASHED_VEHICLE_SPRITE) + if (vehicle->IsCrashedVehicle) { uint32_t ebx = 22965 + vehicle->animation_frame; PaintAddImageAsParent(session, ebx, 0, 0, 1, 1, 0, z, 0, 0, z + 2); diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp index 6df7aac6a8..4370785923 100644 --- a/src/openrct2/world/Footpath.cpp +++ b/src/openrct2/world/Footpath.cpp @@ -43,18 +43,10 @@ void footpath_update_queue_entrance_banner(const CoordsXY& footpathPos, TileElement* tileElement); FootpathSelection gFootpathSelection; -uint8_t gFootpathProvisionalFlags; -CoordsXYZ gFootpathProvisionalPosition; -ObjectEntryIndex gFootpathProvisionalSurfaceIndex; -ObjectEntryIndex gFootpathProvisionalRailingsIndex; -uint8_t gFootpathProvisionalSlope; -PathConstructFlags gFootpathProvisionalConstructFlags; -uint8_t gFootpathConstructionMode; +ProvisionalFootpath gProvisionalFootpath; +uint16_t gFootpathSelectedId; CoordsXYZ gFootpathConstructFromPosition; -uint8_t gFootpathConstructDirection; uint8_t gFootpathConstructSlope; -uint8_t gFootpathConstructValidDirections; -money32 gFootpathPrice; uint8_t gFootpathGroundFlags; static ride_id_t* _footpathQueueChainNext; @@ -163,12 +155,12 @@ money32 footpath_provisional_set( cost = res->Error == GameActions::Status::Ok ? res->Cost : MONEY32_UNDEFINED; if (res->Error == GameActions::Status::Ok) { - gFootpathProvisionalSurfaceIndex = type; - gFootpathProvisionalRailingsIndex = railingsType; - gFootpathProvisionalPosition = footpathLoc; - gFootpathProvisionalSlope = slope; - gFootpathProvisionalConstructFlags = constructFlags; - gFootpathProvisionalFlags |= PROVISIONAL_PATH_FLAG_1; + gProvisionalFootpath.SurfaceIndex = type; + gProvisionalFootpath.RailingsIndex = railingsType; + gProvisionalFootpath.Position = footpathLoc; + gProvisionalFootpath.Slope = slope; + gProvisionalFootpath.ConstructFlags = constructFlags; + gProvisionalFootpath.Flags |= PROVISIONAL_PATH_FLAG_1; if (gFootpathGroundFlags & ELEMENT_IS_UNDERGROUND) { @@ -192,15 +184,15 @@ money32 footpath_provisional_set( } else if ( gFootpathConstructSlope == TILE_ELEMENT_SLOPE_FLAT - || gFootpathProvisionalPosition.z < gFootpathConstructFromPosition.z) + || gProvisionalFootpath.Position.z < gFootpathConstructFromPosition.z) { // Going either straight on, or down. - virtual_floor_set_height(gFootpathProvisionalPosition.z); + virtual_floor_set_height(gProvisionalFootpath.Position.z); } else { // Going up in the world! - virtual_floor_set_height(gFootpathProvisionalPosition.z + LAND_HEIGHT_STEP); + virtual_floor_set_height(gProvisionalFootpath.Position.z + LAND_HEIGHT_STEP); } } @@ -213,12 +205,12 @@ money32 footpath_provisional_set( */ void footpath_provisional_remove() { - if (gFootpathProvisionalFlags & PROVISIONAL_PATH_FLAG_1) + if (gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1) { - gFootpathProvisionalFlags &= ~PROVISIONAL_PATH_FLAG_1; + gProvisionalFootpath.Flags &= ~PROVISIONAL_PATH_FLAG_1; footpath_remove( - gFootpathProvisionalPosition, + gProvisionalFootpath.Position, GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST); } @@ -230,9 +222,9 @@ void footpath_provisional_remove() */ void footpath_provisional_update() { - if (gFootpathProvisionalFlags & PROVISIONAL_PATH_FLAG_SHOW_ARROW) + if (gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_SHOW_ARROW) { - gFootpathProvisionalFlags &= ~PROVISIONAL_PATH_FLAG_SHOW_ARROW; + gProvisionalFootpath.Flags &= ~PROVISIONAL_PATH_FLAG_SHOW_ARROW; gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_ARROW; map_invalidate_tile_full(gFootpathConstructFromPosition); diff --git a/src/openrct2/world/Footpath.h b/src/openrct2/world/Footpath.h index d2976cd1a7..d544d7b684 100644 --- a/src/openrct2/world/Footpath.h +++ b/src/openrct2/world/Footpath.h @@ -67,6 +67,38 @@ struct PathRailingsEntry uint8_t scrolling_mode; }; +using PathConstructFlags = uint8_t; +namespace PathConstructFlag +{ + constexpr PathConstructFlags IsQueue = 1 << 0; + constexpr PathConstructFlags IsPathObject = 1 << 1; +} // namespace PathConstructFlag + +struct FootpathSelection +{ + ObjectEntryIndex LegacyPath = OBJECT_ENTRY_INDEX_NULL; + ObjectEntryIndex NormalSurface = OBJECT_ENTRY_INDEX_NULL; + ObjectEntryIndex QueueSurface = OBJECT_ENTRY_INDEX_NULL; + ObjectEntryIndex Railings = OBJECT_ENTRY_INDEX_NULL; + bool IsQueueSelected{}; + + ObjectEntryIndex GetSelectedSurface() const + { + return IsQueueSelected ? QueueSurface : NormalSurface; + } +}; + +struct ProvisionalFootpath +{ + ObjectEntryIndex Type; + CoordsXYZ Position; + uint8_t Slope; + uint8_t Flags; + ObjectEntryIndex SurfaceIndex; + ObjectEntryIndex RailingsIndex; + PathConstructFlags ConstructFlags; +}; + // Masks for values stored in TileElement.type enum { @@ -155,40 +187,11 @@ enum FOOTPATH_CONNECTED_MAP_EDGE_IGNORE_NO_ENTRY = (1 << 7) }; -using PathConstructFlags = uint8_t; -namespace PathConstructFlag -{ - constexpr PathConstructFlags IsQueue = 1 << 0; - constexpr PathConstructFlags IsPathObject = 1 << 1; -} // namespace PathConstructFlag - -struct FootpathSelection -{ - ObjectEntryIndex LegacyPath = OBJECT_ENTRY_INDEX_NULL; - ObjectEntryIndex NormalSurface = OBJECT_ENTRY_INDEX_NULL; - ObjectEntryIndex QueueSurface = OBJECT_ENTRY_INDEX_NULL; - ObjectEntryIndex Railings = OBJECT_ENTRY_INDEX_NULL; - bool IsQueueSelected{}; - - ObjectEntryIndex GetSelectedSurface() const - { - return IsQueueSelected ? QueueSurface : NormalSurface; - } -}; - extern FootpathSelection gFootpathSelection; -extern uint8_t gFootpathProvisionalFlags; -extern CoordsXYZ gFootpathProvisionalPosition; -extern ObjectEntryIndex gFootpathProvisionalSurfaceIndex; -extern ObjectEntryIndex gFootpathProvisionalRailingsIndex; -extern uint8_t gFootpathProvisionalSlope; -extern PathConstructFlags gFootpathProvisionalConstructFlags; -extern uint8_t gFootpathConstructionMode; +extern ProvisionalFootpath gProvisionalFootpath; +extern uint16_t gFootpathSelectedId; extern CoordsXYZ gFootpathConstructFromPosition; -extern uint8_t gFootpathConstructDirection; extern uint8_t gFootpathConstructSlope; -extern uint8_t gFootpathConstructValidDirections; -extern money32 gFootpathPrice; extern uint8_t gFootpathGroundFlags; // Given a direction, this will return how to increase/decrease the x and y coordinates. diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index b2322d3279..2be43a52f9 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -1530,10 +1530,10 @@ void map_update_tiles() void map_remove_provisional_elements() { - if (gFootpathProvisionalFlags & PROVISIONAL_PATH_FLAG_1) + if (gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1) { footpath_provisional_remove(); - gFootpathProvisionalFlags |= PROVISIONAL_PATH_FLAG_1; + gProvisionalFootpath.Flags |= PROVISIONAL_PATH_FLAG_1; } if (window_find_by_class(WC_RIDE_CONSTRUCTION) != nullptr) { @@ -1551,12 +1551,12 @@ void map_remove_provisional_elements() void map_restore_provisional_elements() { - if (gFootpathProvisionalFlags & PROVISIONAL_PATH_FLAG_1) + if (gProvisionalFootpath.Flags & PROVISIONAL_PATH_FLAG_1) { - gFootpathProvisionalFlags &= ~PROVISIONAL_PATH_FLAG_1; + gProvisionalFootpath.Flags &= ~PROVISIONAL_PATH_FLAG_1; footpath_provisional_set( - gFootpathProvisionalSurfaceIndex, gFootpathProvisionalRailingsIndex, gFootpathProvisionalPosition, - gFootpathProvisionalSlope, gFootpathProvisionalConstructFlags); + gProvisionalFootpath.SurfaceIndex, gProvisionalFootpath.RailingsIndex, gProvisionalFootpath.Position, + gProvisionalFootpath.Slope, gProvisionalFootpath.ConstructFlags); } if (window_find_by_class(WC_RIDE_CONSTRUCTION) != nullptr) { diff --git a/src/openrct2/world/Park.cpp b/src/openrct2/world/Park.cpp index a8f2acf248..1291e9d7bb 100644 --- a/src/openrct2/world/Park.cpp +++ b/src/openrct2/world/Park.cpp @@ -700,7 +700,7 @@ void Park::GenerateGuests() } } -Peep* Park::GenerateGuestFromCampaign(int32_t campaign) +Guest* Park::GenerateGuestFromCampaign(int32_t campaign) { auto peep = GenerateGuest(); if (peep != nullptr) @@ -710,14 +710,14 @@ Peep* Park::GenerateGuestFromCampaign(int32_t campaign) return peep; } -Peep* Park::GenerateGuest() +Guest* Park::GenerateGuest() { - Peep* peep = nullptr; + Guest* peep = nullptr; const auto spawn = get_random_peep_spawn(); if (spawn != nullptr) { auto direction = direction_reverse(spawn->direction); - peep = Peep::Generate({ spawn->x, spawn->y, spawn->z }); + peep = Guest::Generate({ spawn->x, spawn->y, spawn->z }); if (peep != nullptr) { peep->sprite_direction = direction << 3; diff --git a/src/openrct2/world/Park.h b/src/openrct2/world/Park.h index 26ecb941a2..b4ec887bbf 100644 --- a/src/openrct2/world/Park.h +++ b/src/openrct2/world/Park.h @@ -18,8 +18,6 @@ #define MAX_ENTRANCE_FEE MONEY(200, 00) -struct Peep; - enum : uint32_t { PARK_FLAGS_PARK_OPEN = (1 << 0), @@ -43,7 +41,7 @@ enum : uint32_t PARK_FLAGS_UNLOCK_ALL_PRICES = (1u << 31), // OpenRCT2 only! }; -struct Peep; +struct Guest; struct rct_ride; namespace OpenRCT2 @@ -73,7 +71,7 @@ namespace OpenRCT2 money64 CalculateCompanyValue() const; static uint8_t CalculateGuestInitialHappiness(uint8_t percentage); - Peep* GenerateGuest(); + Guest* GenerateGuest(); void ResetHistories(); void UpdateHistories(); @@ -85,7 +83,7 @@ namespace OpenRCT2 uint32_t CalculateGuestGenerationProbability() const; void GenerateGuests(); - Peep* GenerateGuestFromCampaign(int32_t campaign); + Guest* GenerateGuestFromCampaign(int32_t campaign); }; } // namespace OpenRCT2 diff --git a/src/openrct2/world/Sprite.cpp b/src/openrct2/world/Sprite.cpp index bbcf8cbdd3..2f5c123196 100644 --- a/src/openrct2/world/Sprite.cpp +++ b/src/openrct2/world/Sprite.cpp @@ -427,7 +427,6 @@ static void PrepareNewEntity(SpriteBase* base, const EntityType type) base->sprite_width = 0x10; base->sprite_height_negative = 0x14; base->sprite_height_positive = 0x8; - base->flags = 0; base->sprite_left = LOCATION_NULL; SpriteSpatialInsert(base, { LOCATION_NULL, 0 }); diff --git a/src/openrct2/world/SpriteBase.h b/src/openrct2/world/SpriteBase.h index 09194f2800..43a9efe234 100644 --- a/src/openrct2/world/SpriteBase.h +++ b/src/openrct2/world/SpriteBase.h @@ -29,10 +29,9 @@ struct SpriteBase // Height from centre of sprite to bottom uint8_t sprite_height_negative; uint16_t sprite_index; - uint16_t flags; - int32_t x; - int32_t y; - int32_t z; + int16_t x; + int16_t y; + int16_t z; // Width from centre of sprite to edge uint8_t sprite_width; // Height from centre of sprite to top diff --git a/test/tests/Pathfinding.cpp b/test/tests/Pathfinding.cpp index 974f5c6136..4986ea0140 100644 --- a/test/tests/Pathfinding.cpp +++ b/test/tests/Pathfinding.cpp @@ -69,7 +69,7 @@ protected: // Our start position is in tile coordinates, but we need to give the peep spawn // position in actual world coords (32 units per tile X/Y, 8 per Z level). // Add 16 so the peep spawns in the center of the tile. - Peep* peep = Peep::Generate(pos->ToCoordsXYZ().ToTileCentre()); + auto* peep = Guest::Generate(pos->ToCoordsXYZ().ToTileCentre()); // Peeps that are outside of the park use specialized pathfinding which we don't want to // use here diff --git a/test/tests/S6ImportExportTests.cpp b/test/tests/S6ImportExportTests.cpp index 8adaf1fe33..a4bc8ac241 100644 --- a/test/tests/S6ImportExportTests.cpp +++ b/test/tests/S6ImportExportTests.cpp @@ -147,7 +147,6 @@ static void CompareSpriteDataCommon(const SpriteBase& left, const SpriteBase& ri { COMPARE_FIELD(Type); COMPARE_FIELD(sprite_index); - COMPARE_FIELD(flags); COMPARE_FIELD(x); COMPARE_FIELD(y); COMPARE_FIELD(z); @@ -170,11 +169,9 @@ static void CompareSpriteDataPeep(const Peep& left, const Peep& right) COMPARE_FIELD(NextLoc.y); COMPARE_FIELD(NextLoc.z); COMPARE_FIELD(NextFlags); - COMPARE_FIELD(OutsideOfPark); COMPARE_FIELD(State); COMPARE_FIELD(SubState); COMPARE_FIELD(SpriteType); - COMPARE_FIELD(GuestNumRides); COMPARE_FIELD(TshirtColour); COMPARE_FIELD(TrousersColour); COMPARE_FIELD(DestinationX); @@ -183,27 +180,8 @@ static void CompareSpriteDataPeep(const Peep& left, const Peep& right) COMPARE_FIELD(Var37); COMPARE_FIELD(Energy); COMPARE_FIELD(EnergyTarget); - COMPARE_FIELD(Happiness); - COMPARE_FIELD(HappinessTarget); - COMPARE_FIELD(Nausea); - COMPARE_FIELD(NauseaTarget); - COMPARE_FIELD(Hunger); - COMPARE_FIELD(Thirst); - COMPARE_FIELD(Toilet); COMPARE_FIELD(Mass); - COMPARE_FIELD(TimeToConsume); - COMPARE_FIELD(Intensity); - COMPARE_FIELD(NauseaTolerance); COMPARE_FIELD(WindowInvalidateFlags); - COMPARE_FIELD(PaidOnDrink); - for (int i = 0; i < PEEP_MAX_THOUGHTS; i++) - { - COMPARE_FIELD(RideTypesBeenOn[i]); - } - COMPARE_FIELD(ItemFlags); - COMPARE_FIELD(Photo2RideRef); - COMPARE_FIELD(Photo3RideRef); - COMPARE_FIELD(Photo4RideRef); COMPARE_FIELD(CurrentRide); COMPARE_FIELD(CurrentRideStation); COMPARE_FIELD(CurrentTrain); @@ -215,32 +193,10 @@ static void CompareSpriteDataPeep(const Peep& left, const Peep& right) COMPARE_FIELD(Action); COMPARE_FIELD(ActionFrame); COMPARE_FIELD(StepProgress); - COMPARE_FIELD(GuestNextInQueue); COMPARE_FIELD(MazeLastEdge); COMPARE_FIELD(InteractionRideIndex); - COMPARE_FIELD(TimeInQueue); - for (int i = 0; i < 32; i++) - { - COMPARE_FIELD(RidesBeenOn[i]); - } COMPARE_FIELD(Id); - COMPARE_FIELD(CashInPocket); - COMPARE_FIELD(CashSpent); - COMPARE_FIELD(ParkEntryTime); - COMPARE_FIELD(RejoinQueueTimeout); - COMPARE_FIELD(PreviousRide); - COMPARE_FIELD(PreviousRideTimeOut); - for (int i = 0; i < PEEP_MAX_THOUGHTS; i++) - { - COMPARE_FIELD(Thoughts[i].type); - COMPARE_FIELD(Thoughts[i].item); - COMPARE_FIELD(Thoughts[i].freshness); - COMPARE_FIELD(Thoughts[i].fresh_timeout); - } COMPARE_FIELD(PathCheckOptimisation); - COMPARE_FIELD(GuestHeadingToRideId); - COMPARE_FIELD(StaffOrders); - COMPARE_FIELD(Photo1RideRef); COMPARE_FIELD(PeepFlags); COMPARE_FIELD(PathfindGoal.x); COMPARE_FIELD(PathfindGoal.y); @@ -254,6 +210,54 @@ static void CompareSpriteDataPeep(const Peep& left, const Peep& right) COMPARE_FIELD(PathfindHistory[i].direction); } COMPARE_FIELD(WalkingFrameNum); +} + +static void CompareSpriteDataGuest(const Guest& left, const Guest& right) +{ + CompareSpriteDataPeep(left, right); + COMPARE_FIELD(OutsideOfPark); + COMPARE_FIELD(GuestNumRides); + COMPARE_FIELD(Happiness); + COMPARE_FIELD(HappinessTarget); + COMPARE_FIELD(Nausea); + COMPARE_FIELD(NauseaTarget); + COMPARE_FIELD(Hunger); + COMPARE_FIELD(Thirst); + COMPARE_FIELD(Toilet); + COMPARE_FIELD(TimeToConsume); + COMPARE_FIELD(Intensity); + COMPARE_FIELD(NauseaTolerance); + COMPARE_FIELD(PaidOnDrink); + for (int i = 0; i < PEEP_MAX_THOUGHTS; i++) + { + COMPARE_FIELD(RideTypesBeenOn[i]); + } + COMPARE_FIELD(ItemFlags); + COMPARE_FIELD(Photo2RideRef); + COMPARE_FIELD(Photo3RideRef); + COMPARE_FIELD(Photo4RideRef); + COMPARE_FIELD(GuestNextInQueue); + COMPARE_FIELD(TimeInQueue); + for (int i = 0; i < 32; i++) + { + COMPARE_FIELD(RidesBeenOn[i]); + } + COMPARE_FIELD(CashInPocket); + COMPARE_FIELD(CashSpent); + COMPARE_FIELD(ParkEntryTime); + COMPARE_FIELD(RejoinQueueTimeout); + COMPARE_FIELD(PreviousRide); + COMPARE_FIELD(PreviousRideTimeOut); + for (int i = 0; i < PEEP_MAX_THOUGHTS; i++) + { + COMPARE_FIELD(Thoughts[i].type); + COMPARE_FIELD(Thoughts[i].item); + COMPARE_FIELD(Thoughts[i].freshness); + COMPARE_FIELD(Thoughts[i].fresh_timeout); + } + COMPARE_FIELD(GuestHeadingToRideId); + COMPARE_FIELD(GuestIsLostCountdown); + COMPARE_FIELD(Photo1RideRef); COMPARE_FIELD(LitterCount); COMPARE_FIELD(GuestTimeOnRide); COMPARE_FIELD(DisgustingCount); @@ -278,6 +282,22 @@ static void CompareSpriteDataPeep(const Peep& left, const Peep& right) COMPARE_FIELD(FavouriteRideRating); } +static void CompareSpriteDataStaff(const Staff& left, const Staff& right) +{ + CompareSpriteDataPeep(left, right); + + COMPARE_FIELD(AssignedStaffType); + COMPARE_FIELD(MechanicTimeSinceCall); + COMPARE_FIELD(HireDate); + COMPARE_FIELD(StaffId); + COMPARE_FIELD(StaffOrders); + COMPARE_FIELD(StaffMowingTimeout); + COMPARE_FIELD(StaffRidesFixed); + COMPARE_FIELD(StaffRidesInspected); + COMPARE_FIELD(StaffLitterSwept); + COMPARE_FIELD(StaffBinsEmptied); +} + static void CompareSpriteDataVehicle(const Vehicle& left, const Vehicle& right) { COMPARE_FIELD(SubType); @@ -351,6 +371,7 @@ static void CompareSpriteDataVehicle(const Vehicle& left, const Vehicle& right) COMPARE_FIELD(colours_extended); COMPARE_FIELD(seat_rotation); COMPARE_FIELD(target_seat_rotation); + COMPARE_FIELD(IsCrashedVehicle); } static void CompareSpriteDataLitter(const Litter& left, const Litter& right) @@ -428,8 +449,10 @@ static void CompareSpriteData(const rct_sprite& left, const rct_sprite& right) switch (left.misc.Type) { case EntityType::Guest: + CompareSpriteDataGuest(static_cast(left.peep), static_cast(right.peep)); + break; case EntityType::Staff: - CompareSpriteDataPeep(left.peep, right.peep); + CompareSpriteDataStaff(static_cast(left.peep), static_cast(right.peep)); break; case EntityType::Vehicle: CompareSpriteDataVehicle(left.vehicle, right.vehicle);