From 9bbc0f983eed5ae3dec82425d6e97b30d8abed55 Mon Sep 17 00:00:00 2001 From: dkeruza-neo Date: Sun, 9 Mar 2025 00:44:55 -0500 Subject: [PATCH] Check the changelog. --- .github/workflows/ci.yml | 73 - .github/workflows/flatpak-build.yml | 44 + .github/workflows/linux-build.yml | 45 + .github/workflows/main.yml | 48 + docs/changelog | 20 +- docs/guide.md | 169 +- docs/lindbergh.conf | 78 +- scripts/flatpak/.gitignore | 4 + scripts/flatpak/assets/ld.so.conf | 4 + scripts/flatpak/assets/libstdc++.so.5 | Bin 0 -> 730084 bytes scripts/flatpak/assets/ncurses-5.9.patch | 36 + .../flatpak/com.github.lindberghloader.yml | 323 ++++ src/lindbergh/card_reader.c | 27 +- src/lindbergh/config.c | 36 +- src/lindbergh/config.h | 8 +- src/lindbergh/customcursor.c | 229 +++ src/lindbergh/customcursor.h | 10 + src/lindbergh/eeprom.c | 38 +- src/lindbergh/eeprom_settings.c | 1 - src/lindbergh/evdevinput.c | 91 +- src/lindbergh/evdevinput.h | 8 +- src/lindbergh/gluthooks.c | 32 +- src/lindbergh/glxhooks.c | 83 +- src/lindbergh/hook.c | 241 ++- src/lindbergh/input.c | 171 +- src/lindbergh/lindbergh.c | 39 +- src/lindbergh/patch.c | 425 ++--- src/lindbergh/resolution.c | 1436 ++++++++++------- src/lindbergh/sdlcalls.c | 187 +-- src/lindbergh/securityboard.c | 2 +- src/lindbergh/shader_patches.c | 767 +++++---- src/lindbergh/stb_image.h | 16 +- src/lindbergh/touchscreen.c | 85 + src/lindbergh/touchscreen.h | 9 + src/lindbergh/x11hooks.c | 72 +- 35 files changed, 3185 insertions(+), 1672 deletions(-) delete mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/flatpak-build.yml create mode 100644 .github/workflows/linux-build.yml create mode 100644 .github/workflows/main.yml create mode 100644 scripts/flatpak/.gitignore create mode 100644 scripts/flatpak/assets/ld.so.conf create mode 100644 scripts/flatpak/assets/libstdc++.so.5 create mode 100644 scripts/flatpak/assets/ncurses-5.9.patch create mode 100644 scripts/flatpak/com.github.lindberghloader.yml create mode 100644 src/lindbergh/customcursor.c create mode 100644 src/lindbergh/customcursor.h create mode 100644 src/lindbergh/touchscreen.c create mode 100644 src/lindbergh/touchscreen.h diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index d2f2e97..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: Build and Release Lindbergh - -on: - push: - branches: - - master - pull_request: - branches: - - master - -permissions: - contents: write - -jobs: - build-and-release: - runs-on: ubuntu-latest - - steps: - # Checkout the repository - - name: Checkout repository - uses: actions/checkout@v3 - - # Set up Docker Buildx - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - # Build the Docker image - - name: Build Docker image - run: | - docker build --target lindbergh-build -t lindbergh-loader . - - # Extract build artifacts - - name: Extract build artifacts - run: | - docker create --name lindbergh-builder lindbergh-loader - docker cp lindbergh-builder:/output ./build - docker rm lindbergh-builder - - # Compress the build directory - - name: Compress build directory - run: tar -czvf build.tar.gz -C ./build . - - # Archive the build directory as an artifact for debugging - - name: Archive build directory - uses: actions/upload-artifact@v4 - with: - name: build-output - path: ./build - - # Create a GitHub release and capture the upload URL (only on push events) - - name: Create Release - if: github.event_name == 'push' - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: v${{ github.run_number }} - release_name: "Build v${{ github.run_number }}" - draft: false - prerelease: false - - # Upload the compressed build artifact to the release (only on push events) - - name: Upload Release Asset - if: github.event_name == 'push' - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./build.tar.gz - asset_name: build.tar.gz - asset_content_type: application/gzip diff --git a/.github/workflows/flatpak-build.yml b/.github/workflows/flatpak-build.yml new file mode 100644 index 0000000..e17a7f9 --- /dev/null +++ b/.github/workflows/flatpak-build.yml @@ -0,0 +1,44 @@ +name: 📦 Linux Flatpak + +on: + workflow_call: + workflow_dispatch: + +jobs: + linux-flatpak-build: + name: "Build" + + runs-on: ubuntu-latest + container: + image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.8 + options: --privileged + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + set-safe-directory: ${{ env.GITHUB_WORKSPACE }} + + # Work around container ownership issue + - name: Set Safe Directory + shell: bash + run: git config --global --add safe.directory "*" + + - name: Build Flatpak + uses: flathub-infra/flatpak-github-actions/flatpak-builder@master + with: + bundle: lindbergh-loader.flatpak + upload-artifact: false + manifest-path: scripts/flatpak/com.github.lindberghloader.yml + build-bundle: true + verbose: true + branch: stable + cache: true + restore-cache: true + cache-key: flatpak-${{ hashFiles('scripts/flatpak/*.yaml') }} + + - name: Upload Flatpak + uses: actions/upload-artifact@v4 + with: + name: "linux-flatpak" + path: "lindbergh-loader.flatpak" diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml new file mode 100644 index 0000000..d424499 --- /dev/null +++ b/.github/workflows/linux-build.yml @@ -0,0 +1,45 @@ +name: Build and Release Lindbergh + +on: + workflow_call: + workflow_dispatch: + +permissions: + contents: write + +jobs: + build-and-release: + runs-on: ubuntu-latest + + steps: + # Checkout the repository + - name: Checkout repository + uses: actions/checkout@v3 + + # Set up Docker Buildx + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + # Build the Docker image + - name: Build Docker image + run: | + docker build --target lindbergh-build -t lindbergh-loader . + + # Extract build artifacts + - name: Extract build artifacts + run: | + docker create --name lindbergh-builder lindbergh-loader + docker cp lindbergh-builder:/output ./build + docker rm lindbergh-builder + + # Compress the build directory + - name: Compress build directory + run: tar -czvf build.tar.gz -C ./build . + + # Archive the build directory as an artifact for debugging + - name: Archive build directory + uses: actions/upload-artifact@v4 + with: + name: linux-build + path: build.tar.gz + diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..a4a01de --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,48 @@ +name: Automated Builds + +on: + workflow_dispatch: + pull_request: + paths-ignore: + - '**.md' + - '.github/ISSUE_TEMPLATE/*' + push: + branches: + - main + paths-ignore: + - '**.md' + - '.github/ISSUE_TEMPLATE/*' + +jobs: + linux-build: + name: 💻 Linux + uses: "./.github/workflows/linux-build.yml" + linux-flatpak: + name: 📦 Linux Flatpak + uses: "./.github/workflows/flatpak-build.yml" + + create-release: + name: 📤 Create Release + needs: [linux-build, linux-flatpak] + runs-on: ubuntu-22.04 + if: github.ref == 'refs/heads/main' + steps: + - name: Download Artifacts + uses: actions/download-artifact@v4 + with: + path: ./artifacts/ + + - name: Display Downloaded Artifacts + run: find ./artifacts/ + + - name: Create Preview Release + if: github.ref == 'refs/heads/main' + uses: "marvinpinto/action-automatic-releases@latest" + with: + repo_token: "${{ secrets.GITHUB_TOKEN }}" + automatic_release_tag: v${{ github.run_number }} + prerelease: false + title: "Build v${{ github.run_number }}" + files: | + ./artifacts/linux-flatpak/lindbergh-loader.flatpak + ./artifacts/linux-build/build.tar.gz diff --git a/docs/changelog b/docs/changelog index e2edcb5..279c680 100644 --- a/docs/changelog +++ b/docs/changelog @@ -2,7 +2,25 @@ All notable changes to this project will be documented in this file. -## [2.0.3] +## [2.0.4] +### Added + - Boost render res option for Rambo, LGJ, HOD4, HOD-EX, ID4/ID5, 2Spicy and Harley. + - Flatpak build as a bundle. (For installation, read the guide in docs folder.) + - Add COINS with evdev for player 2. + - Merged code that adds support for COINS with evdev. + - Makefile, lindbergh.c and shader_patches.c changes to support Flatpak. + - "--zink" option in lindbergh elf to run the games using Zink. + - "--nvidia" option in lindbergh elf to force the secondary nVidia GPU in laptops. + - Click and drag in PH touchscreen. + - Hide custom crosshair cursor in PH when not needed. + - Custom mouse cursors working with X11, GLX and Glut. + - Custom mouse cursor in Primeval Hunt TouchScreen. + - TouchScreen emulation fro Primeval Hunt + - Display a warning if the distro you are running is not based on Debian. + - Cleaned up most of the code changing Ifs to Switch and sorting Alphabetically. + - Let's go Jungle and Let's go Jungle Special resolution patches. + +## [2.0.3] 2025-02-02 ### Added - Display a warning when loading an Elf that is not clean. - Added to the lib folder, common libraries that are usually missing. diff --git a/docs/guide.md b/docs/guide.md index 3822f80..7833f0e 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -4,31 +4,67 @@ The follow list of games are supported. It is worth noting that there are multiple releases of these games, and some specific releases may not be supported. -| Game Name | Game ID | DVP | NVidia | Intel (Mesa) | AMD (Mesa) | AMD (proprietary) | -|---------------------------------|---------|----------|--------|--------------|------------|-------------------| -| 2 Spicy | SBMV | DVP-0027 | ✓ | ✓ | ✓ | ✓ | -| After Burner Climax | SBLR | DVP-0009 | ✓ | ✓ | ✓ | | -| Ghost Squad Evolution | SBNJ | DVP-0029 | ✓ | ✓ | ✓ | ✓ | -| Harley Davidson | SBRG | DVP-5007 | ✓ | ✓ | ✓ | ✓ | -| Hummer Extreme | SBST | DVP-0079 | ✓ | ✓ | ✓ | ✓ | -| Hummer | SBQN | DVP-0057 | ✓ | ✓ | ✓ | ✓ | -| Let's Go Jungle | SBLU | DVP-0011 | ✓ | ✓ | ✓ | | -| Let's Go Jungle Special | SBNR | DVP-0036 | ✓ | ✓ | ✓ | | -| Outrun 2 SP SDX | SBMB | DVP-0015 | ✓ | ✓ | ✓ | ✓ | -| R-Tuned | SBQW | DVP-0060 | ✓ | ✓ | ✓ | ✓ | -| Race TV | SBPF | DVP-0044 | ✓ | ✓ | ✓ | ✓ | -| Rambo | SBQL | DVP-0069 | ✓ | ✓ | ✓ | ✓ | -| The House of the Dead 4 | SBLC | DVP-0003 | ✓ | ✓ | ✓ | ✓ | -| The House of the Dead 4 Special | SBLS | DVP-0010 | ✓ | ✓ | ✓ | ✓ | -| The House of the Dead Ex | SBRC | DVP-0063 | ✓ | ✓ | ✓ | ✓ | -| Virtua Fighter 5 | SBLM | DVP-0008 | ✓ | ✓ | ✓ | ✓ | -| Virtua Fighter 5 R | SBQU | DVP-5004 | ✓ | ✓ | ✓ | ✓ | -| Virtua Fighter 5 FS | SBUV | DVP-5019 | ✓ | ✓ | ✓ | ✓ | -| Initial D 4 | SBNK | DVP-0030 | ✓ | ✓ | ✓ | ✓ | -| Initial D 5 | SBTS | DVP-0075 | ✓ | ✓ | ✓ | | -| Virtua Tennis 3 | SBKX | DVP-0005 | ✓ | ✓ | ✓ | ✓ | -| Primeval Hunt | SBPP | DVP-0048 | ✓ | ✓ | ✓ | ✓ | - +| Game Name | Game ID | DVP | NVidia | Intel (Mesa) | AMD (Mesa) | AMD (proprietary) | +|--------------------------------------------------|---------|-----------|--------|--------------|------------|-------------------| +| After Burner Climax | SBLR | DVP-0009 | ✓ | ✓ | ✓ | | +| After Burner Climax Rev A | SBLR | DVP-0009A | ✓ | ✓ | ✓ | | +| After Burner Climax Rev B | SBLR | DVP-0009B | ✓ | ✓ | ✓ | | +| After Burner Climax SDX | SBMN | DVP-0018 | ✓ | ✓ | ✓ | | +| After Burner Climax SDX Rev A | SBMN | DVP-0018A | ✓ | ✓ | ✓ | | +| After Burner Climax SE | SBLR | DVP-0031 | ✓ | ✓ | ✓ | | +| After Burner Climax SE Rev A | SBLR | DVP-0031A | ✓ | ✓ | ✓ | | +| Ghost Squad Evolution | SBNJ | DVP-0029 | ✓ | ✓ | ✓ | ✓ | +| Harley Davidson | SBRG | DVP-5007 | ✓ | ✓ | ✓ | ✓ | +| Hummer | SBQN | DVP-0057B | ✓ | ✓ | ✓ | ✓ | +| Hummer SDLX | SBST | DVP-0057 | ✓ | ✓ | ✓ | ✓ | +| Hummer Extreme | SBST | DVP-0079 | ✓ | ✓ | ✓ | ✓ | +| Hummer Extreme MDX | SBST | DVP-0083 | ✓ | ✓ | ✓ | ✓ | +| Initial D Arcade Stage 4 Rev A | SBML | DVP-0019A | ✓ | ✓ | ✓ | ✓ | +| Initial D Arcade Stage 4 Rev B | SBML | DVP-0019B | ✓ | ✓ | ✓ | ✓ | +| Initial D Arcade Stage 4 Rev C | SBML | DVP-0019C | ✓ | ✓ | ✓ | ✓ | +| Initial D Arcade Stage 4 Rev D | SBML | DVP-0019D | ✓ | ✓ | ✓ | ✓ | +| Initial D Arcade Stage 4 Rev G | SBML | DVP-0019G | ✓ | ✓ | ✓ | ✓ | +| Initial D Arcade Stage 4 Export Rev B | SBNK | DVP-0030B | ✓ | ✓ | ✓ | ✓ | +| Initial D Arcade Stage 4 Export Rev C | SBNK | DVP-0030C | ✓ | ✓ | ✓ | ✓ | +| Initial D Arcade Stage 4 Export Rev D | SBNK | DVP-0030D | ✓ | ✓ | ✓ | ✓ | +| Initial D 5 EXP | SBRY | DVP-0075 | ✓ | ✓ | ✓ | | +| Initial D 5 EXP 2.0 | SBTS | DVP-0084 | ✓ | ✓ | ✓ | | +| Initial D 5 EXP 2.0 Rev A | SBQN | DVP-0084A | ✓ | ✓ | ✓ | | +| Initial D Arcade Stage 5 Rev A | SBQZ | DVP-0070A | ✓ | ✓ | ✓ | | +| Initial D Arcade Stage 5 Rev F | SBQZ | DVP-0070F | ✓ | ✓ | ✓ | | +| Let's Go Jungle | SBLU | DVP-0011 | ✓ | ✓ | ✓ | | +| Let's Go Jungle! Rev A | SBLU | DVP-0011A | ✓ | ✓ | ✓ | | +| Let's Go Jungle Special | SBNR | DVP-0036 | ✓ | ✓ | ✓ | | +| SEGA Network Taisen Mahjong MJ4 | SBPN | DVP-0049G | ✓ | ✓ | ✓ | ✓ | +| SEGA Network Taisen Mahjong MJ4 Evolution | SBTA | DVP-0081 | ✓ | ✓ | ✓ | ✓ | +| Outrun 2 SP SDX | SBMB | DVP-0015 | ✓ | ✓ | ✓ | ✓ | +| Outrun 2 SP SDX Rev A | SBMB | DVP-0015A | ✓ | ✓ | ✓ | ✓ | +| Primeval Hunt | SBPP | DVP-0048 | ✓ | ✓ | ✓ | ✓ | +| Rambo | SBQL | DVP-0069 | ✓ | ✓ | ✓ | ✓ | +| R-Tuned | SBQW | DVP-0060 | ✓ | ✓ | ✓ | ✓ | +| Sega Race TV | SBPF | DVP-0044 | ✓ | ✓ | ✓ | ✓ | +| The House of the Dead 4 Rev A | SBLC | DVP-0003A | ✓ | ✓ | ✓ | ✓ | +| The House of the Dead 4 Rev B | SBLC | DVP-0003B | ✓ | ✓ | ✓ | ✓ | +| The House of the Dead 4 Rev C | SBLC | DVP-0003C | ✓ | ✓ | ✓ | ✓ | +| The House of the Dead 4 Special | SBLS | DVP-0010 | ✓ | ✓ | ✓ | ✓ | +| The House of the Dead 4 Special Rev B | SBLS | DVP-0010B | ✓ | ✓ | ✓ | ✓ | +| The House of the Dead Ex | SBRC | DVP-0063 | ✓ | ✓ | ✓ | ✓ | +| Too Spicy | SBMV | DVP-0027 | ✓ | ✓ | ✓ | ✓ | +| Virtua Fighter 5 | SBLM | DVP-0008 | ✓ | ✓ | ✓ | ✓ | +| Virtua Fighter 5 Rev A | SBLM | DVP-0008A | ✓ | ✓ | ✓ | ✓ | +| Virtua Fighter 5 Rev B | SBLM | DVP-0008B | ✓ | ✓ | ✓ | ✓ | +| Virtua Fighter 5 Rev E (Public Version C) | SBLM | DVP-0008E | ✓ | ✓ | ✓ | ✓ | +| Virtua Fighter 5 Export | SBLM | DVP-0043 | ✓ | ✓ | ✓ | ✓ | +| Virtua Fighter 5 Final Showdown REV A | SBUV | DVP-5019 | ✓ | ✓ | ✓ | ✓ | +| Virtua Fighter 5 Final Showdown REV B | SBXX | DVP-5020 | ✓ | ✓ | ✓ | ✓ | +| Virtua Fighter 5 Final Showdown REV B ver 6.0000 | SBXX | DVP-5020 | ✓ | ✓ | ✓ | ✓ | +| Virtua Fighter 5 R | SBQU | DVP-5004 | ✓ | ✓ | ✓ | ✓ | +| Virtua Fighter 5 R Rev D | SBQU | DVP-5004D | ✓ | ✓ | ✓ | ✓ | +| Virtua Fighter 5 R Rev G | SBQU | DVP-5004G | ✓ | ✓ | ✓ | ✓ | +| Virtua Tennis 3 | SBKX | DVP-0005 | ✓ | ✓ | ✓ | ✓ | +| Virtua Tennis 3 Rev A | SBKX | DVP-0005A | ✓ | ✓ | ✓ | ✓ | +| Virtua Tennis 3 Rev B | SBKX | DVP-0005B | ✓ | ✓ | ✓ | ✓ | +| Virtua Tennis 3 Rev C | SBKX | DVP-0005C | ✓ | ✓ | ✓ | ✓ | ## Game Issues & Fixes @@ -48,26 +84,11 @@ sudo ln -s /lib/i386-linux-gnu/libglut.so /lib/i386-linux-gnu/libglut.so.3 ### Let's Go Jungle Rev A -The game must be run in export mode to have the stereo sound option. +- The game must be run in export mode to have the stereo sound option. ### Outrun 2 SP SDX -You need to set `SKIP_OUTRUN_CABINET_CHECK` to 1 in `lindbergh.conf` to play in DX, SDX or Standard cabinet types. - -### Ghost Squad / 2Spicy - -You may have sound issues such as the game complaining that the system cannot open `/dev[/sound]/dsp`. You **must not** use the `libopenal.so.0` files that came with the game, please delete those if you've moved them into your game folder. Do the following: - -``` -sudo apt install pipewire-audio-client-libraries:i386 -sudo cp /usr/share/doc/pipewire/examples/alsa.conf.d/99-pipewire-default.conf /etc/alsa/conf.d/ -``` - -Then in the game folder you must create a symlink to the `libopenal.so.1` library installed on your system: - -``` -ln -s /usr/lib/i386-linux-gnu/libopenal.so.1 libopenal.so.0 -``` +- You need to set `SKIP_OUTRUN_CABINET_CHECK` to 1 in `lindbergh.conf` to play in DX, SDX or Standard cabinet types. ## Configuration File : lindbergh.conf @@ -135,3 +156,67 @@ Will cause input on analogue input 1 to be clamped as follows: There are currently no audio options that you can set. If you have a stereo sound card installed then the audio will be downmixed to stereo. If you have a 5.1 sound card installed and the game supports surround sound, each surround channel should be passed through properly and should play sound as it was originally intended. + +## Installing and Running the Flatpak + +### Prerequisites + +Before installing the main package, ensure that Flatpak is set up on your system. If Flatpak is not installed, follow the official [Flatpak setup guide](https://flatpak.org/setup/). + +### Installation + +Once downloaded, install Lindbergh Loader by running the following command in your terminal: + +``` +flatpak install lindbergh-loader-dev.flatpak +``` + +Additionally, install the required dependencies: + +``` +flatpak install org.freedesktop.Platform.Compat.i386//24.08 +flatpak install org.freedesktop.Platform.GL32.default//24.08 +``` +Intel GPU Users (VAAPI Support): + +``` +flatpak install org.freedesktop.Platform.VAAPI.Intel.i386//24.08 +``` + +NVIDIA GPU Users (Driver Support): + +If your system uses an NVIDIA GPU, you need to install the matching NVIDIA driver package for your system. +To check your NVIDIA driver version, run: + +``` +nvidia-smi +``` +Then, install the corresponding Flatpak package, replacing 570-86-16 with your actual driver version: + +``` +flatpak install org.freedesktop.Platform.GL32.nvidia-570-86-16 +``` + +### Running Lindbergh Loader + +Once installed, launch the application with: + +``` +flatpak run com.github.lindberghloader.dev +``` + +### Managing Game Locations + +By default, games should be added to: + +``` +~/Games +``` + +If you need to add more locations, install Flatseal: + +``` +flatpak install com.github.tchx84.Flatseal +``` + +Then, run Flatseal and grant Lindbergh Loader access to additional directories. diff --git a/docs/lindbergh.conf b/docs/lindbergh.conf index 9a4a712..d9e124b 100644 --- a/docs/lindbergh.conf +++ b/docs/lindbergh.conf @@ -1,5 +1,5 @@ # SEGA Lindbergh Emulator Configuration File -# By the Lindbergh Development Team +# By the Lindbergh Development Team 2024-2025 # Set the requested dip switch width here WIDTH AUTO @@ -7,28 +7,31 @@ WIDTH AUTO # Set the requested dip switch height here HEIGHT AUTO +# Boost render resolution in HOD4/2Spicy/Harley/Rambo/HOD-EX/ID4/ID5 and LGJ +# BOOST_RENDER_RES 1 + # Set if the emulator should go full screen -FULLSCREEN 0 +# FULLSCREEN 0 # Sets the Input Mode # Mode 0: will use both SDL/X11 and EVDEV inputs (default) # Mode 1: will use SDL/X11 inputs only # Mode 2: will use EVDEV raw inputs only, which should be configured at the bottom of the settings file -INPUT_MODE 0 +# INPUT_MODE 0 # Set to 1 if you want to disable SDL (Fixes SRTV boost bar) -NO_SDL 0 +# NO_SDL 0 # Set the Region ( JP/US/EX ) -REGION EX +# REGION EX # Set if you want the game to be Free Play -FREEPLAY 1 +# FREEPLAY 1 # Set if the emulator should emulate JVS and use the keyboard/mouse for controls. # If this is set to 0, then the emulator will route the traffic to the serial device # defined in JVS_PATH if it has been defined. -EMULATE_JVS 1 +# EMULATE_JVS 1 # Set if the emulator should emulate the rideboard used in the special games here # If this is set to 0, then the emulator will route the traffic to one of the serial ports @@ -41,8 +44,12 @@ EMULATE_DRIVEBOARD AUTO # Set if the emulator should emulate the motion board from Outrun 2 SP SDX here # If this is set to 0, then the emulator will route the traffic to one of the serial ports EMULATE_MOTIONBOARD AUTO + # Set if the loader should emulate the card reader in Virtua Tenis 3 -# EMULATE_CARDREADER 1 +EMULATE_CARDREADER AUTO + +# Set to 1 if the loader should emulate the touchscreen with the mouse in PH. +# EMULATE_TOUCHSCREEN 1 # Card File for reader 1 # CARDFILE_01 Card_01.crd @@ -51,7 +58,7 @@ EMULATE_MOTIONBOARD AUTO # CARDFILE_02 Card_02.crd # Define the path to pass the JVS packets to if JVS is not being emulated. -JVS_PATH /dev/ttyUSB0 +# JVS_PATH /dev/ttyUSB0 # Define the path to pass the first serial port to if it's not being emulated. # SERIAL_1_PATH /dev/ttyUSB0 @@ -60,47 +67,47 @@ JVS_PATH /dev/ttyUSB0 # SERIAL_2_PATH /dev/ttyUSB0 # Define the path to the sram.bin file -SRAM_PATH sram.bin +# SRAM_PATH sram.bin # Define the path to the eeprom.bin file -EEPROM_PATH eeprom.bin +# EEPROM_PATH eeprom.bin # Set the GPU vendor (0 = Autodetect / 1 = NVidia / 2 = AMD / 3 = ATI(AMD-PRO) / 4 = Intel / 5 = Unknown) -GPU_VENDOR 0 +# GPU_VENDOR 0 # Set if you want to see debug messages in the console -DEBUG_MSGS 0 +# DEBUG_MSGS 0 # Set if you'd like to add a border for optical light gun tracking -BORDER_ENABLED 0 +# BORDER_ENABLED 0 # Set the thickness of the white border as a percentage of the width of the screen -WHITE_BORDER_PERCENTAGE 2 +# WHITE_BORDER_PERCENTAGE 2 # Set the thickness of the black border which sits around the # white border as a percentage of the width of the screen -BLACK_BORDER_PERCENTAGE 0 +# BLACK_BORDER_PERCENTAGE 0 # Set to true if you experience flickering in hummer -HUMMER_FLICKER_FIX 0 +# HUMMER_FLICKER_FIX 0 # Set to keep the aspect ratio (4:3) in games like Sega Race TV and Primeval Hunt -KEEP_ASPECT_RATIO 0 +# KEEP_ASPECT_RATIO 0 # Set to 0 if you want to disable the Glare effect in OutRun -OUTRUN_LENS_GLARE_ENABLED 1 +# OUTRUN_LENS_GLARE_ENABLED 1 # Set to 1 to bypass cabinet checks including drive board and tower in Outrun 2 SP SDX -SKIP_OUTRUN_CABINET_CHECK 0 +# SKIP_OUTRUN_CABINET_CHECK 0 # Set to 1 if you want to limit the FPS in games that are not limited like OutRun2 -FPS_LIMITER_ENABLED 0 +# FPS_LIMITER_ENABLED 0 # Set the target FPS (will only work if FPS_LIMITER_ENABLED = 1) -FPS_TARGET 60 +# FPS_TARGET 60 # Set to 1 if you want to render LGJ using the mesa patches instead of nVidia (fixes some glitches) -LGJ_RENDER_WITH_MESA 1 +# LGJ_RENDER_WITH_MESA 1 # Set the Primeval Hunt mode # Mode 0: Default (Side by Side) @@ -108,37 +115,48 @@ LGJ_RENDER_WITH_MESA 1 # Mode 2: Side by Side # Mode 3: 3ds mode 1 (Touch screen to the right) # Mode 4: 3ds mode 2 (Touch screen to the bottom) -PRIMEVAL_HUNT_MODE 1 +# PRIMEVAL_HUNT_MODE 1 # Disble to use the original fonts instead of the built in font in the loader -DISABLE_BUILTIN_FONT 0 +# DISABLE_BUILTIN_FONT 0 # Disble to use the original logos instead of the built in logos in the loader -DISABLE_BUILTIN_LOGOS 0 +# DISABLE_BUILTIN_LOGOS 0 # Set to 0 to enable the mouse pointer/Cursor -HIDE_CURSOR 1 +# HIDE_CURSOR 1 # Set the custom mouse pointer from a PNG file (Usefull for shooting games) # CUSTOM_CURSOR myCustomCursor.png # Set the width of the custom cursor -CUSTOM_CURSOR_WIDTH 32 +# CUSTOM_CURSOR_WIDTH 32 # Set the height of the custom cursor -CUSTOM_CURSOR_HEIGHT 32 +# CUSTOM_CURSOR_HEIGHT 32 + +# Set a custom cursor for the touch screen in Primeval Hunt +# PH_TOUCH_CURSOR myCustomHandCursor.png + +# Set the width of the custom cursor +# PH_TOUCH_CURSOR_WIDTH 32 + +# Set the height of the custom cursor +# PH_TOUCH_CURSOR_HEIGHT 32 # Hacky way to make MJ4 work at prohibited times? # MJ4_ENABLED_ALL_THE_TIME 1 # Sets the IP address in the eeprom for Outrun link (you have to put your NIC ip) # OR2_IP 192.168.1.2 +# OR2_NETMASK 255.255.255.0 + # House of the dead 4 speed fix set the frequency of your CPU in Ghz (The speed reported by the manufacturer) # CPU_FREQ_GHZ 4.0 # Set the colour of the lindbergh to change the Segaboot logo # Possible colours are: YELLOW, RED, BLUE, SILVER, REDEX -LINDBERGH_COLOUR YELLOW +# LINDBERGH_COLOUR YELLOW # X11 MODE (Input Mode 1) # To find the value pairs for these run `xev` on linux diff --git a/scripts/flatpak/.gitignore b/scripts/flatpak/.gitignore new file mode 100644 index 0000000..60b1a16 --- /dev/null +++ b/scripts/flatpak/.gitignore @@ -0,0 +1,4 @@ +.flatpak-builder/ +build/ +repo/ +*.flatpak diff --git a/scripts/flatpak/assets/ld.so.conf b/scripts/flatpak/assets/ld.so.conf new file mode 100644 index 0000000..46a5635 --- /dev/null +++ b/scripts/flatpak/assets/ld.so.conf @@ -0,0 +1,4 @@ +# We just make any GL32 extension have higher priority +include /run/flatpak/ld.so.conf.d/app-*-org.freedesktop.Platform.GL32.*.conf +/app/lib32 +/app/lib/i386-linux-gnu \ No newline at end of file diff --git a/scripts/flatpak/assets/libstdc++.so.5 b/scripts/flatpak/assets/libstdc++.so.5 new file mode 100644 index 0000000000000000000000000000000000000000..e733843743bf865613d4c6419bf6e8953136dac0 GIT binary patch literal 730084 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 z zX?#y`E9Ez#9g`Pf|3jWHmoXCGbewz+=F7^%%F|2_?)$l)@`*Azq?{n%ig_^08=R#4 z{wmo(8JwbAhW!Qd9Ok{`mx|=5@)YYW)VxRLc>j3)WM9 zH0-d*O7y?vud1a^^rI^o?v(OWfkH&hN`dRRx za+2Q_@-+SHvF}KJ1pOcRL+GQ)Kce1{zs7usybkLg@>f-Imi(Z|Jb41|Lw-hNk=zVD z5BYTTFXRVGq=x16)^b@wp2E6@{B?;eC%=dFHThAIP2}s)Zj?!78+jD{7|Q`{r+hco z36#ODlINqHsu zJC-*%MfuOwa+s{DkZJPWB1e^Nj0ZW!dhxYVS*ENp^$6=u=6eF`P0G*3{GBpbPx;m& zSx(*~vVvRJtR3-Do4maW4%m%9p9Dw zSL{!aKP{Fya#xL9WS8P*k)`zz%X+da62@&mArBuilLtvsfj z;ywV}k13OM|MzN1k<+k~B;Qyg`^mRsyd#%m9Y{V5>pyY@)&;lX<40lHsTA(vP`z=M=Oi*+6K_23~BAL~f+ zAm(4JAK(n-B{8^T0#Ov&v-*2lw^LEy}&h^Njxh*!z)BjLAjvK#i0#{xfY+gm~mfpl>Jt8}muBxmG60-=dt! zdvM-@tbsm{{4nM*M?u{=J7 zeGKxm)pAjJn&k)i0_6w8o}KUWY0QJjr&mZFS&VZ!%BAE_i(~}}ooNHP3;GyxJ;pWV z2J(;CKO|dVPflVDx0QT0^eW1J@<&*IlKVx*$-iMgg6tMKsGKBma%_tH2?e?i!vD_|5`2kmE+{g zie-{~C)VNQk42`)XJX!_oF*$U?vVcj{SNsp*x8UN^k2$3^0DP|j(i`+6Y`B%|B&Cp z`ib=gyh!;cC~3+|Dy5Em4%PwWIlQ;Bp8PZPbmU*ErJ4K}*lm(;$Nryk6Zu)}+Zx7X zD~Uaue)3+-Ta-!im(c&RUvCy!POihefP5DAy~uvpeUSs$XCYsSafUoDvYGs%$X4>J zSbvf~g5Hk&1;#J(&(JrJs7ZUtk|G%=%TeFRhZo5NS&#VO4LOW; z1NjQ*Wy!-uGE4q9^lId1p%*8=StMu3?_gho{2}z@GC{k=Nl| z7}nB0f@M!pL5j68sP$MOC{r4l3mr&Q|6|0|Uy@&V{q$oevAA)g5Q zE^-a_)5w1=lXmi2tOv-BGU+7;V8=ne0qu(XP?=1URajS%4}^Z3d?fVNv|H*p?0 z3_S|Dt3qnXL+D@0=?Ym+-idRC#0Y zU_XR>2+k>z?btUYM`JQh{x{Bjk;kE*CVzx^GCFO_nMEP{TUh9r&YFBH?1gcTy5do=4<-Kzc8TP2kxBBgn75OU!}v-* zUgQwD65|WGO5`wkwa7Htgmp8yT4aX22J1iaT9ISqM%Y)7*NM!Mn?z2K&%roEK40V% z*#Wa7@+OhfQ7|+z6XO;+E3$?B0>&?L4&xX3 zb&-DZI~d2vGnhA#-^X}H{s7|{c}`?6c^>m8@`A`d@;CVY+Bkzy#k9+{eKXM7yVdR4_4w6eT4w4VWI7l`^&qy|5 z-9WCvxJa&reuaD{#z*p6jF03-=po2wWB;FoesZ3CF7_|U=V9C=pAY*Fva?7ok}rh* zliXY+QVYHa=iJDfFpnW$0zD_W6?Xe%PmwGkg z$rkecMY5H=1Lw}k58@mpIb9?P@*}XnBtHiGWb!{TZzkt3pCP}6`3(7e=uOD;nAec= znAec^LBB)(wnz?;zlWZT{3GT&e$k`KW8n|vVbf5;`+=OiBl{R{aJtRKn8z%GP*0?ylzPr*JT`Bdy*lTBE!kk5j> z2Kj8*X^@*>|4g=GznZ+hST2$6m`_2cQ*k5opkxQ;Rpbj`e?Yzj^LnxicJ1Ug%(uwi zVp&G^7fU_46Z0=}5c4l`2=g!Um6(5#w_!h;+*d5kaROCt#;Q9xay5_uUx40^{8F)u zk*9DTnfywzjFVr*`2h0k(D#wwgnbWr8tV!2TiDknzgH{=$@yYAME(kTL-PNiKPE5W z`;))M_b301?@#^(-=CBcIYw4s9!OSVzlN-X9)f&eiJT-K47(k2DfANLLvgN^d_;+y zAs>l-Ch}3(uOt7dM9z~du@6E%8TLNpI_SB`rl5fGecJctuvy*SfJe_<8?C;5UVqHYO3-fmJ-6gV>d@t-? z$@gRaPTqn2Fmf96c=98d$CERd$CJlk?@pe;e4hLQ_L<1LFs~<1VO~#u1@n6HyO`IL zXG`QD`D5J2LH@KvrpWV{?~}j4e4qRk=KJI#_T|Y-C32Mf3%)-oIM+;8mdY$yh5bpg z4*E>;!B`)V4}qNu`Ecwnl8?c;XtD|G268>t4dgSR&m*6S^#geg)(_-HtRKkhOJ$L4 z!#aX&$37GJe5@yM*FnXN(4Ui=v92Irgndi$CfFa5Tc8gjUxNK=vKRUkvLEXYasd0| z?Ly{jam2vWu zurnq;dL{snqwvrmwZ!MSMisnDmAjnK!C*hf4~HbFl@J{{+#$(AxX zM?M>NEMyz(Kgs8n$pYC9`z5loOcu!(WB;A(h8;fHTPAXUaHvd5$y;C#N{+xjfgFV% zmE42-V8~mc*C1bseNFOq>`RcZ!Tvn?TIf5-3D~WWZ^Suj@-5h(BHxbnDfuqgH;{+Q zWCQtbtXIkRVZBPeAL~`}gIKSU)7S?gKa6!N`B9udAU}@%9r7sFvE-+*jwL^feN%E4 z_B7;|%Opj973*8_+c-~7eh2$R7M5Og4t6MHJNDnm zj&c#~(Nw$u``+Yc*rSnK%B6g8Y5COpzDy{mD!C{^Vcr{Ym_HhK#{3i>$1WV`OcG z94D7l$SnCF?6;8*u8@=DGVH68kEoD2@=+CXnp}?a$K+!xnofT3~jzAwn?uI^wd@1xXDg zxs{c~~&?hPOxiG4}(v9Na}9|yYt^6{`!C0D?{glvMH0Qt0- zoFUi4-jIBHOwN(dhW$Tz9nOJ}tvKgJJ|FilkS~bIBKachlaV*Y6oW~^p6Z_5NF`VlpKNFKJ*keO>Zf(Cd-khW?!V4$iNTzk!~Q{2lasq zoih0>=nKh>*heRCfZmXN9`uG}C-jEo3vmww`7h8PlK%>OEb=8dPe%5^4vO3fy&^dX zy&`!F^ory#^oryj*l$6{SMgHZOG3T^_UGhnu%jhkgZ&J00{hS88(`N$z76L9$#-Bs znw*0DIr)CrC6k9MWhMCm?01nzaL$MPXr(lhpTIc)^1mu&1NkZ3gF@a}DVxa8z)qJu zQ7P@@7b>NbysJ_+lXt_ufINl$G4k8kpCw_l+E2oUFhRl=FG<4IBt_l}dqom^Hhan6 z!fuLO#JL{w_pqBF{|b8}@^7&JBXO_z0kQ=5-H=tVpCGS-y$5+e*h!H~ao&S`DDG7t zAC7$|@{!mVCYQq=lzd#394DV#C9~vHtK*DAjuo6v?7}@2gTX%7Q|4k^RkD=46?RDEE1`!bUk7_Gasv8j@(noWNWKYrY4XiDH%LxFKTX~N z{WSRj*qf2l&{LBi#yJJ@qtI8A|5+vNpSUE`Xe`lKtepRWd=|2fKgr7x@0?f1oz`h508v7pP&#L7Bxq$r-@;B9Ti2MWgLCA~v{$xpwOp{A+PZIfH*q@RQfqfPE zSe)-7pHd^o$<^3@CfC=<3G(SRa*})o&i|1caK8=tESwJ`uZ0~ixe@kQWLu4#BX6jY z^JF{r>&Y8omqm8q+$Grw`&aT`a2}cL!94_IZw(asU>tTc_e5eJX@dMijZBh%f*lljKitbo-oI83k@dAQ zMLw-o4wKj5ULW#0ocAMJVQ)dU!9J91huuBdiF<#@7vg*^`7f|XB431aO60%R$|>?C zwK7L`c94e}MWvPizNRxXma;XDd? zd#woe)hi}pzfHa!=S#?gwNgXA19qqKW_-FghGP(Qn@;97K6!{xwcGiFXhHs7C84CBF`y2jqM;&E)-#cgIC6wuS@2ruR zQszJR&KP+a<$B6fM&_UWD=1GIc{$|<%Hu|+SAR3*q>)!r-avV)kr}jq6XkXzW7AIh z+bM4_GNblyrrcoU^^~_#t~c@q%Ken7SxJW#p}trzuYwxtH<`<#8i3YyHP4Cykt-JWF}2 zk(t&0la$+yoT5BOd4rLe_5L%I8;p$2Kj}Y5x!%a*l;f$R~+p)2N}>=Lde<7O=SFT8;4B|C&&Wwg@+naYG6H ze_Pf+IY3Scd&phnq%aO=G5_Saa5K4^91~tij*_FoUUCmPBD|U$BL{?A$h~Br@EUTQ z>=pKr2gx2`KRHQu3Ad4l$WGz4AhCt&Em@Mf}u92Jg|tH}}JEo3J-AlyT)CHsVLBfH36;TXAr>=E8d z_K;n|z2s)HQ+OL0Ctv8laGcyiwhQ->ePoO9Ai0g49+UM?4v z$lc_a@NROH92HKHd&m*tz2q1u)M}(`$PI5rFnp{iv3D=NaWUsK3+(7mSJsa{3Kf z|6~hJoQ6}v5weY(6y8X-ljFkOB4q*$Hc8f-~3tP!)vPIZN9wVn;m-SD!;KXS-C2S|#$VuUHGEUCW zf8h#p1vw^MNp_H6Vmh2P8ZMH;_HT^T;?EL;r=1U5TgZ0d#bh7ZBHTc3Bd1@J^-m6vQ^Fo{7da`sj2t1yg`3IUJyU1SQ7`cJ$5#CDnkX^#PWSo4V|H9kIUa~_tPHrLFh5N`pvPF21 z+(u5PW&M)_hsaLhadL|65Vk?A9S^s1_k%ImU z+sQU^Qn;LKC&z^=$Q9(6a3$G6jtV=-)#Qk971>D+2v?Kw22k{0xQ6T^dxf3k2C_#O zmufKoWS4L)xtZ(~#$_AKKiMJdA~S$7Y!_Zk_K_{Z4dga*`ej-F>+oNlfui$ z5prC(ncPi|3F8tD=ARrD_L6(Z5#iP37&#!^LhdE|gx8ScWUsJ~JV^Ek`^ibNOSp|Z zM0N_}@($*o><|u+HL_i}gPbN?guBRNiv8kNyis$To6Pcq17%=+S@SZZb~P z(0}30WCuAa93@wiBf?wAPI5rFhg?hc3ExI`k-fq(as$~Typ`-ByM%km&19$WHnNxO z5RQ}aq$~O_+(*XEe)L~>klaR2kIMQd2goVmB)N;66y8OSkmJHb-b+UUG~a5Z1`OWS{UTIZpNpr^$n4kMKTnlI#*5BM*_C!sFx=*&%F!X>ZZUc3~?y zO|}Tz$YbR6h^&7yPSVhSVLRDIP70Tk?c}&{1sNx5=)W*thJ*PhM}-~aYH~!lii{I9 z^k2A|Tub%|*N|OgudtKcK=ugFBYVg$;aYMt*(r>dpkn^X4q+F$g=`nbWh~4;*&^IP zZX>7vDeIpcAg6>qCX{tIs=JIGPtC>bYc=)dq5vXdMT?jhHbeZseqU1YCt zjNCx>2yZ3hB593uyWHF7W6Cp=1ylfA-e@*vqGypNnDyM)Kc zLu9A$I5|aj2wULVwP<9!u$7!9TZC=oF>?AvS^s4GB@Xmo*iOb91kitBT$025ljFh_ z^CNnt!hhxsSRg`3IU<|u+ zHL_i}gPbN?guBRNzC|P3g{|Z?*&=KskCD^Q z%laod>h$C_6oETI8JUM+lBkcKC(r4klaR2r)2$;1LTx&lH5g33hyFE$Z_EzayL09yqg>)M}<@5 z9&$u@FF8gI2y5hCvQK!F94C8))8s+2M|dAONp=a3k%!1m;c;?`>=3qKYuBQY?ZUYH ziuos7gl*(8a{5{Jzm#mTgHytGvW=V+#-&)yKRGU3L9QUjge%Doa#Ywst|mu>tH@4r zK)9M*OZExZkX>Z2u#?60RjTlbyo2bc^{XJA_?iURW5m3oj=7$QI!S zavM4QKNINx>Er-8CF~)0k(0v9$Psc}xS8BdjtQ?MN6ArPFS&;t5nfG>kpsdlEN$YbR69`^q#vgL4a zN;pEck(0t3$#!yFxSL!-jtOrjJIGPtD7l&(5#B;}k^{m$=llY8^|8v ztz-|`CEQDHCOd_ePoO9Ai0g4-p&3$L=KQs!bx%$IVrr093jVr zhsfRJnDB0LlpGaKk$cDy;l1P-IUuZ&d&xfGQF5H@6;6`}$sXZ-=B+v_K;n|wd7{9Qy7=EG5=(Tu#4P6 zwhJ#N`^XmI267uY{Wn?v>+oNlft;%jrk|Xg`3IU)M}<@59&$u@FF8gI2y5hCvQK!F94C8))8s+2M|dAONp=a3 zk%!1m;c;?`>=3pfw9}%I?ZSAuB<7!N5w?-X$myqK{gW-_;FPePY$GRy%gJ_fT)2W< zL5>Mmk{#rzu!CGpjtJv&J?5Vr5UwWIl6}H>IV0wu>=kyB8^|8vd1MdSC0t8xCOd_3 z=^pb>b_l!3Eo8g!VzQ5H5pE#2k<(Ag`X>j-DPa$}i<}h3<$cUQIWF8x?k2~CahV_U zPmT(E$vxzV@M?0591w0H_mX|WYshi3SJ+1$BzuJY>_)Go#Y0xM;H%X zVE)N2;aYMt*(tn$>?J#dUE~(BU3f9sN45wzklV=V$7TJK1LTyjhulR@3NIr^$Z_Fj zayL09ypkLxM}@uQ9&$u@H91BO2)B@X$v)vV?047J;Hu+lI#+0BM*_C!fVMX zvO_pP*2s3@4sx1o5$+<7k<*XK`X^hC2B(B0WE(jtype1t$A!De737%kX0n4E6^@dt z$r0f#WG6Ww+(WJ<`-E>JyU1SQ7`cJ$5#CDnkX^#PAr4$VuT{Ttjw|y~0j% z1KA@ykL)44gloyoWT!A5(!u(&IZd_*cag`)>4#C z2*=4SWV>)5*+;er50cx+>4#+flLO?GaFX0bP73cLN62yEA#yi4CcK**B}au*A%SOCtE%aP6^w|HgZz9oNOn@g)7Jv=kyB8^|8vd1MdSC0t8xCOd@}kiBGwu#4P6whQAWgP4D^MYw_7Mo#}( z);~EwP6>O+UF4)N9ty+!ljFk8-b+YI2Mm5N;v&l6}H!$Z@h) z*hd~DdxY`O80Mes5^f_8k)6V8$tki!I6&6OcHs_knrsp7B9D>NJ7xWoEuR3Vgd=1d zIVrr6Y$wNsyU7*gnDAz@gB%r(lB>xP;Von*IRM6UX=iD8V#RWHFrmJU_lT$=3-+R& zasP~oq`GQ+XCe}jG&dqmF!6mP35{9<_t}uh(mGEKF_P99Z*{7nHTS$bq1rni_a7aK zTNS~H$Fm=|4)=$ct0dHCJ$qF`4YeS>Vy)7KUz?a1iR%x@DXYe{xl+@=@W;$lbsQto zxzm4`di`!hNID;HosBjrqpK3(5Wiyfzu}jWVYRXEV%5RxO%-4m6hFNwTG?Fk>}a} z&}gaJRI2Djhjx@`S4qLmY-FoF^!BHewN*AHt+v}PJw2v!zLJ*KpdYdw;|j|^(7jWsCqsV+mn8K} zBlYj5PK_&;7VS_;{nt13vO|Tbl~vM-=l{iC--%Reh^GYTiZq;kd2|@(YEz|R=Y?0xDoPtZ#+P}YOp%rk$yk(sAXoM`N)^Pk z`~Eo|A16#$c4q6JL^y5+R0S2{$+%uj9D+3TV8Y2XK-$u6REGQgPK31ZA+zXpG4b& z?WGfVM=BZz4VPI+p?6DKUsXd5I1=RWz5VLM1U~wF>mGatWy{ZAz-J>5%NnwAt+A8= zYZZk|i$Ez*gbZC#tE}3mw2mq5 zKpfIf!P1_?_5{C&-Ma*@OJLZp-@5=x9-lO&6!&hmu~aEhmRg~?R_#;U$5qrr-Hh*z zGFBmzRD(ueXjW6>cP^OY|AabAd2Oa=pSq}ADX$6*TBVjX`_QvHQG;HU;@+z?X(K-g zyOU;-hvgJ`42lf2KQpKGF6L-TD(+FGDLuRzL%{i2u{_+#-^2IY@b6jLQ*Utqe)T#= zesm=Ui$i%I4q?^n$Dz;EkOPtu+F_-LcY2XSouPCxr`mv4T1};nSYc z_&y{GEkhyUOOd^lZJn)u5Q;mL`etn(e0??4hxuda^;R`>8x~VK9rc(vU>iv}tHa7!%2vP+sFi z=o2L$a3=I=&CG+;t#+JNw(;frF&?uCz*7h9RDZburw6 z($!AsG(N_FYoFxDGJu_Z$XldfRSM>ptY%djKlP-`J>gD$SmUhqw0+{WU?3NbcgELM zXQUmoG8NX6p+AJsAnBo0wfOni+l_%ePOjfhEwab6(wC*4y;Y$#*}CD(`0X z`edn_I0u+8wBtbLEU&H2YUqQ^)f}`Xw|62k!yiL?LksER}@)B&A zFnVEkOeQ~${ln8CYUDlc*wZ`rG!62fIBeUViapJANAtCE40$Ev24pm~@-t8_QdN!r zi&JXlCt;LF?qn@e9ji(5pP{FBjzq%l9<$)j=M;P;3J$bCIH&b?3-tA#pZDNbQ)_EI1Ngj?A7M~M z9UuQvzQSHFDVX0(VKq{i3VStD6jRun`wJEJk6uAaLt$@0i4Q>TGYUJ(D*hc6c2!2y z4p3pAgv+~XCp(x`*wQ;g6Na#4425leOohFMA5W{W|AsxQDk_6Z;I@Baz=YI;P}s{6 zS5M7jr0HSp|IPy84-?^xmP$Z(){+}q%ROCmP zji~Y0PpQa1JdA<4qo8uVMGDk-(``y)j7``&%r=KR>2a9Ky(FiyTkfZF-!P~3rv+s_ zbGu}54=PO$DUC^%wQINrr4;kW>mg*p#F4mx9UNV2==>9KDExtS{!ic^Oz)4crca&m z1K-0RAAtXpqw{N7`oZh`?SJ5ia$iAN$oI!@f#J;4`5WP&W8k%`@N){C|4d8iGxt-g zKT{2z|IGc}_%);Rw{FMhxAP-tk!K*M+C`7#>-_5^g<%yW15+_UTf~?CD!uwnb}*~+rFVwTzedaGeDh=K z{5F0(tAia~UMMkeC@^JIzNhb=IVUjSNM0)`5m|`klVY- zPWln-)xqlgJF~mn&%BKeaKY%NshRCC^S~>UnonO>-8awSvLOh zWpOJGGH7B$CR3}gG3%)D&kc=D6*c)HTt=w%f~d)+oT$lG*l)AU3X~aYA1aKRoQpMU zYUyVD9=@OE{w(bm5Q|{qg1_f_=AAgYRj=R3cxs4uTVaSLYO;*$9#Io<6edSaD;IZM^n2J zl93lRITkvf>eh^!oMR-&MolJm<}2i{Qn>E!MQg&H<7^Y{2!!rZ=q0u*8#VdNJxHSm zgT(QF04;!qVOC`moz`LsnFDV`O=O~EY9wkR)0&wFsax&zpvcKllWmxweu;)4YGOqa z_%3?X#Ad)iXSMO0A|-`8YrrzT8L2WHJ86c9kwi^I(ik;a8Lsy-!yS-nRXUhe$kIDQ zAwPhA8&0_SF%|Ny{J4~rN-)I`;oO3oq+p4(pqkG~+zo37?}2 zCU);J^zk-RAG`X|B=yQX{2)UnR%A5w=MemQsi(&OrKxrD zFR{Ew?kFBJxh5xO@*6B(v*dLsIn=&wx|m6>W}f{#2jU4l@tF0WN1!u4ux9?=T_|K) z&Ab;&;(#^ttq{B%&1_@o^q&t-GY9WLDN|_XL(F)#shO9-#!)q%PWzc3&+g<9nlTgZ z&5f8zx3T&d>DG2ZZuWHYBj_24nOxMDudaVDDP(VNr0^IiO#eAT*(;*12ccZ@)%7JY zq%_p^M%4KL7pkeQ#g#1LKmR{h*SxQgtKf31esOg@v5UQ82eazhbd(w7E`vj0sB80M zs_QX`&-Cj0*HW;kNvLba2Mo=A5bFB1t@*u~T3xrGJ;l^@d|SS{P7ZSZ|2@?8Vzgz_ zT;-|j>+XFY>UtG26{>49X3}w%_Pzh1f;w@iNX+E=I2z>cpt4?RD(fZOaO%+#Lto#2 zpQ*14;tcOIU~&PQ1kAXTF3}eg+$0R4R zRwvCpg3WEkjiezxB9D_U1e16ZU=}>B?2Z+8Q{|jLD@nYKkta&ZEJK)lkh*@p=-CL=#1SSZp)S_n&$k^h{j6d zqw1Q+amI~Izl{r9L#Tj11GgGCAaIir3u9cXmm-ct5wP!eoS>ECXQ}G8zT%hn)tCTTQ%6RnQ11KX}SVpz9V;}FvZG!~~Cc01z?(p)y9ID2tO4&WFmH#=KLY$wT{RAhscG_uKLn2+KYz1gG!VgO1({WEl}$1>Y`euz8qb` z{bRdQUy&z?>Y{lgBTBy-S`3xI_~~p^sm+JzQbvD=XrG})a7&cqb+k0{`G=&hr5LXw z19c;E72L6vyw5M%5=GBkBXhK9Yz{FmL+RJuxa*~=cVM&#b*ish`X z-G-~z^IyIA$g+D%)D;jP>y=$4xY|Ac)r($I(!4^IpTB(C{N+>RNBkRy>4<;-1zlIG zsk;xyJ@lj0>pLI~GWm$8%?QOya20X~T6?x?L1V4z;>bAf2%n{$Bl$lk`TbNN2bCYI zjY}ZsPW9nZ-kv|}H(-BAcXygQ)z8CE#{FL-^_QnkEw^j$mefHbby-2`YTjJJ+(RC& zl7!7j$a%=FjBvdySH_y6klPo)U46z=$~D8j-Oax`*r zg{iz2QD}Nta7W^^;1fU`hAT8s(QH^D4La7fQ|#GiO%c%|o!OP~S=FBPI2- zcxzft>RH88%LVwq!&43>?mz~vT&gvU+<6#SHRLt)*(_siT9i6lp|yte*{OSOlw!WG z*IS^Rzl42mfecEX?@OMOisqSFkO#ULc|;fUIl5qC9Dj9|x|l77K87^JuxH9PdUjY> zxIc!EKy{mE;vq5fa&_uI5LsfsR}JLo)Vx)7ABqBG!anoUNj)-C%aaOWN&QVD z^_$&Orj}Lp9Z7wHk$PuA>YP>eMM*eA?|E)l^;PvKJidaCm7-(QET9YErooda9F8YB zW*Ck$5TTSiiRLWd4GR!V1p7t03TF9m_~6B6IVgD=i{{zG7UyWEoLN3ivK@tNc@{T( zsZD!|HHFG?0bVzXXz4CEZ0IMpHr zjFvje?%5F6PRu@*Qb{=1{mk91y!tQq<{>Wa9iYLyrLHoQjazCE7 zO5mfBn7XuDoiV@vqS%mJYr?}sVjhynf8frH69_AptyoH^`V*|JbpYM8VuV9&|?lfn; z4;s89?q8xm@)OcZl;xPT8JB(|yuJ$!Q0m~QRv3E`YSHC2`*+y<)oPtpsVi6NDwMj) zz~AluLzTKJrOu($RV(W|kT29%sbBW4vyMEgHdQFg`Rssp&rcv@_rZZy2K+14&;s*m zD}MJjRg*j2zdnfkB9T46#wQ29HJXn#$wjghg3PWB--w?BBi;D_5BdJ)tq2+i6BqB0 zSt#z8bMu=s`eN0@-~6HE{nB)Ki_F}~lB)!{^qEuJ?d>P5Y4T=C;H!%(2x)w#B zq1PmQAd|)OR7}?CbeplZw35P^D*vD}g@Ws3rb;(WJyRYk`n;KXcgsP|)HT?6aHejB zBf^>b>d%VIlxdeJ4cZ$}=-B_`ovTcLZgz6a6>6pyD>fjhuQyVkJauZZVn3DC=NYN- zmP2#mrR*Fl=97dAkWhR>Q+j1{v)~3q$m(1AH)N#upTEkCNj*YD^`hUov9H%-MD-FQ zQf7ziB}#Ppog7pnB2ut*#!#*Og>LZrvt{W^BfmJYD@KWPP$GqFA(pr<|1f+UC+$|4 z56J(6kVZUZg8}_W)-A}a6wz1hlJe_F`Tlj@d@19Q11Y1(%6SLp6v4#61Ln#xb>6AJ zM(?2Wta$X6y`CjHZ_SiC?;YA+eMKeVqD`UmuEOlUADu^CIfc&qZobar8#Sf9oSI*6 zmPYlj??iqP?X8$+;{wBh1YF#=V-z4BtGGMIM81K_itD_)5aJFduDJjG=)6lM@7Jcw zTV&=IO0EwhSDwzhQglUT+VXVX8bjy3E88d0dB?#KET;1^Gj)(UZ}LoKbYAbqJe`*} zQ{zxkqVqB{by)PEX6i=lOgK|_@uUtj^$jT4Ni$_?F-n700y`E=Jbd4Q>AWXkCW48Z zjnwa@^KOyU7aFOj(RphnVFMD1&NIhEbe;yS5w2g;zacXw`)|sONmfryt@Ac;<1@9+ z>%!`wlb@&a7>k@*=belaxv(0s#PfCDU9dHf|36aat>FZG9J8Ho;i($0l4Q+DW;oJ* z^U3^ByRD@4^>C;X3Wxdsh^lys#<@~MrC8R`J+^RYpZhJD;J;yXM$BjTQSymW^1FYS zWyzLtNp|aDw3a32KK1(D33LcSN7y2IfGrP=n*Nx8fuSQ!VAy` zago~xF=DMB;Z`X-Oo8@CE&flVAW2t+GUz|AtIkbl$8eSmvTM3mUDgqj^5JzOLTQ&_ zY#R0d$MnN!c+|tUdE+R$qE2hH;Q~3+kdoQ)cJGHU$%h+-qKz7;wWGM&5SpUm&(iAhwSxe-8a! zMzg7J|8|OPf}?pZyt%*?i!n9QZ$z0_xCY$YFb0-6V@gx6y22Xv;fai`YJKILF}108 z`@1tjTI~rNTLFCK5O|4&mZ$s^UmasLZwr&g0`#odUO!?QI;l?4lf($e@-iAAw+RYmv_# zRo&6fc-htWGUtk#tkMa{TG-wZR~{+r;1yXFkDxS0L+t@exU>r=1{fPW4WukF*TYU- zZJ-PuI($ZLjk3J@s&HwHOQPPPEHRgaB(*CmYSgAEM=5NLC>uCFWgTIuse(hDnUj;> zV@~uTvBDcM4A^iJ7swS@AkV9>#f6|=Fb(j@S?I%Dm|wU7BlRxav&~iQ&30iX0w_@Bb=Sh>XP#C z3V%tz;@+Y(bz>gXrk=1hs2+iIJUOaRnl@tTmg6>l7%Hl@8=u+L#?2_OQg!#>EAtt1 zwQ1wTnK+!~izOGW+h7NQlw#Gmjz{Yd@jy`3*R8K@WIYizBQ*>npWT&Ub`=||%A z`jL2jB?JT?;#>Zx(tlLzKV%;kzSPNO@uwf7jb>b8pkB9Rx*AYs_d^j3Knvi%aJ^@s zzCq7_I)89+VE;$6@)%sjfqI|*rC?_+N}3q)c?zZ8D&Evr^u%@MGL}Lk`YY^b&Y!>$IBv+ifuScm@Km z1zA*~EUFAV$FSL=DrJ#FSyZiDNtXq0M_2^yq1W5YBPn^w2?kDk9nMNH@!*}aECcRc z6rAv-Efj>AXawvA-r}<>FJO$29~N%uR_JmhgLq=O$-%Ss+|_yycf#%?XFpBQCqw8; zqa8*s@SM$mey*0=Uthz9nrd#p+df0tz{a*7qO|WC*${RQA*XsYx(wYTl~SBgxsA=_ zT?A+$K2J1i?Tlac7gqO?^-v?H>H2Zxrp$r*4R`1x_XUWBJ_fZsB9YS*c)8juTR8^z z-N7+Pvv7%$jdHNZ;f>RF-Gxup9oQE@C&P;!DG9WXSXyT)t!C5{D>`oyF^Jd==+pH# zOi^fTqO5ZsK49kI6YxuB?9Qe^NAa&?X!-MU7%isKehITOY|)dp{*_-PkwlN18K(y~ zU>g!loO?T#XsZpw(YX`vBdf#tb>7RP>TJw>S3AmGAHZnAy+v@>SR+PBjZ)Ib^pXM( zFqy^wRk(>LYmsqXN6(GvD0*v2*Ufbf<{YRK6`ei0V*`%Bk{{VB?QhVR2i6It<1tvE zVB+VuVT08^w7;&#hAT5zE9m(I9LguCp(%SuT!8_?&wpaT0_{&&6!$~^BSeq}rGFSV zYzaPP#-Wiig+Q|Y79f3*akW!!mRHW%p)}$BJP+Z~FvEND55U=DIhX%@Vxq*oYvf)= zyZdoR0tMZ`h&06SPKY1V)OX@%|H$4vJ;OO?=d}{)&%?jfwfE&WiLx>Ff_bOsSmGA# z30MK_|Bcj*1*zMzBL!V@tE9acX&>O|7{1M!>XHh25leU}M3R0WRLSv5T3G=X(r*p@S5*lPh|F+kzEtO> z3S8l`w6?&3NA2qM)i@EDGpM+CojT*4rOOOY*E*|Z&4}TjSSCS() zp~2#MN|Wct^)AQ5zKP>nONSRA5%t^A#%*WJjh!9^ewK37@zcf;%u#TkFYB6x4^&1- zCOlOfqShXLWFN(r`jnEgj_2Qnv{k6kY8!$bHdn z$Md`08pjUiFety=ZgXbQ?Zbz^kGj$A8=K&C;Wxah4RK!MMOs`$SHXA%6V3lU%hK~m*?eeujX>--(ueZO9U)n)g84hqTtNp3>@waQr63`jO*SETVJ><;lYqy*M6 z+%R$MTjqKi%u{eOu2>QOT8GALANdzn2ZBeyXd2mNhgx zoAZ20cwI}s`|q-s+6R9g0{9`cS68xshmw8X(mE^9{&$PNU6s=*1Wqt{rV&ADpHY`P zu**7T&JND3F~f3HDc2{kbjMMyUIZn?e?AuqXP>=A$GhAkVFZ^U9${#Clo581$gFJ< z2W9kBciMl1J_IGIdvB<(Mh|Pm{r{vw_{xtaCNi?eLpb+dSnFfmdq>1vzVd4^84r#; zkzWa{+X)C7(6-};Sb3{+AduI&H{zxw0ed!ZB3IrHA~HLxH;| z;l^EMcfO`HZsW!Hy0Xv?pURC7q#4&!=Jd^MvWFMT_NNpDEABzHDPF>ns|dFyIoe#u zt-V<3mH4n6n|1mv{wh1WIkD7+x)gU`*@n2(mOP<#uycP|=Z`_y-k12X)p>|p-5LbK z%{@2zsg|i8zD)pyqq1c<1V$CyOQ9N8Xx7A6!g2cqeYbH|6sZ%oSavb%qW>Vdckg83pq2-D5jlZM*Mp}HT{ zKUCexe)qi=b!kP}omdl(LyV!37FNz*DB;O_OE{ZyIl_j!1@jj=E-J+*fj4pEBu?AI@fgD;ih3+(Sm()^JzxDn9pazH`r=!bKr2+5N3Z zi8hb*2c@b|-%9G49ai-5UW@_qDgSWqWK=)spX4UQzggm+g-!T;TLi7ZO%U`K?@eqf4Q)p_#2VUx%_SQJH)(!d)y3sX64z&&N>7ko zPRZ=y6{t-a9Qh~asATwiv`Oe^GlT>eMR+BoTyZD2YoCHDJl35Y{sIzYMCl?193V=E zVWsI_EQixw$@_1I!9K{^gd#?XROajiMOL(jUGBVLBLX)HgQELgvRB16L-!(8XuV)! z#V==B<|4dFQ-ezn)$^A-E;`m&G3Q{#m`h|V&zeb)&Wf(FJJ`%?$G4&3V-u~jALNH4 zJK^7>K-{KGvuSyD2IFm%f9*|3dXwI^eB=BI=H*6H@)`njfMIXl z%S+?fe;KE0gIIhEO8k#7Zop45i05&GeE+1n;3I~lt|h2z?tVHeh233O?wdw zxTJq%SEfC3(eEu-Kg55cvOA%i*r`nBL6^&{n%mkxGjaeKz;#6Zyu`d2iQt&re8&7P ztx=u~y}&@T9Xvt3z=4PvPhJW9 z7ghL=V?^LE^)$!a{imK*g{!5neH&-ms}iT4R^9r#1dB&TPhC{mI;8*pm_ABo6zvJ9 zeE9!2>$`;yW0RR1>oHT^E~zdvQoYEF9GQp^{jRWl|4n=^u{L?6gj2XpthfCycgY*Entx zz-U_+WMP_UTPKW6FtHT1XQFLu*v?H@G0+(Y5pBB|J0a#gThA%cwk3Xy<3U8**w_yc zZF6CFQ6$N^Qk3KX;Y79HB5`^HkVw%hlTsg|(eAZw&GELuw_=yl)QH_2D zJh5Qn8{N8&-U*?fLPuk3VbPXK>Q5S}Z!AdNk`1%KyZVfzef0)20=GoY2fm@MsKC*1 z*>y%3$}M*a#!)z2gYaqNyw}kW1$^qFaYR=1ZOi@m78>bzh7fBUY)-xz!g*Vl4(j1BKnXteOMdl7j<{B405 ze{*rr-y{CExP-1cvOTHThtJ0PK_u$uhz6qJdd$$834#~_xGy5n!3W?h$dwJiJ<0$a zI*DTMjg+F5-r;6zJgx&6-FJ=YpGqC zF}xa8qt7>+Yc?nFb|marF!AgrBk*=c)r05+|3=8+2xY0utzqkx^S9?j-#(TZDvaHy zAsGy`wM`t?UTWSZ%-@?xobDJp%e*^7)h0r_8jg(-^BlRK-x^V*ZHV6CdfHuRDgDA$ z*ot6cAzF7}@whc+JdXDT(7;LYIBc^2j!m{4+{;b#Nin%Kunsaqf}1+--L2=NKj^3#qf^{ke)ufx*62!Vf$JeIZZk&5Wm7Ch_qX$@uXbDX zq0S4^{aN%GN2)$tk{YCVKb9@1YPq6f~l80*gfNF2=kUiQZY!Z3Io=mLPg( zhVJ}&;0~7-7_vjG&RrTV@4`w)kPmUR#%+k%sbvh;VLps-8lx9T!N45?*a)mKoW{wb zbmhnJ7<@rw&4}T3gYsf{Emva6nQx8911C6Y!ILD7gL9H4uc}`PrN*&DD^Rj6Y(={V z*#`Gke1;ebgL{=~<5s-R3cuO$A=;!z^p+!pIK#g=KccsW4Kx*8K%yv_h~9r<0;t?_ zBYLv=XlA->M9+nEW<;-sc`^~bW2A&kL~jk6!yu#Vz>hQvX+>BNgJ1HI;diMd%!uA< zc<7XH0xC?=}8g2qQ(H_?xk%li0GvuMeiBW8^Iog z1~deBgx({y#1d)EC(xSzrHI}o*NC6lc@JfFQbg|t`4mA2an0X`Uvj_^y$del0%b(+ zampa0SMM*PC*xWyqIWhF=#&w?JJ42!5(>j()*1A8ap8E;pG zdRpcDL8UQ$@o`~~Rb4cW_#T62vz4V4N-{KHWl9@fkpt^=Q3^#+0el)(iV?oU5LPi> z=FQ+9vZ2rXGg9(O9Gmu|b0oO;v}iH(U1EEmlr{}tC3_#r$}VVI{49v=z3hVo6^rfh zK}7w@ZA9bHA+$1uYjvY}5x#Q}eG9dZTEg>s^%x&6TqqZs5k3jq*$}pq2;Zksj--N;QP_GS%X}SvJ^e2Ibv1B^RwJWY!nv9C#|RSRWN0Q!Xe`AwlLh>8VJXTA zud~sM+WH-2hh~KA^h)Z-TMt3;E)*}1No_>&X8cYKJtPkhIz}Eee=WtIR9e3gwXi9@ zm!d4S2Y(kZ`_Ak2EL83+BPfoF@X7-mYf516V;scHU$Bvc*|I7-v6!Aj9`>05JT~@* z%aB9*0bgVC=;%W*@>9JHBhMoDNHQ}&e45Z4K>8@!;jpN|#2$sS%E&g9pEyj$9RKWM zRHjc>rVKufjxuD9rHqGRFtPtf87!I}zFr8*lEvDTEks|3tO|eUZq*p>NXYrW6wr(U zC~10T985^&HuwdITj%^qucCkIDhR0>d4_GIPjIRfI2#3KBuZ_^^8jU?FR^t+hOLND z-SkcLJx8d@I)ABWhG5~i%Mh%cIfC`0tYD$>`UE$xLMcsYkt=aXW%~2P>ts|EdKCSJ zV&Nf)oZ<2aa4qaG`fkg}Ua>#&wE@o52>zUzDV9O=*V5r8Scj}M9Yd$DsARrOn~6I_ zynH1KB1Gdkl~k^WhdlDMZkQ;Ph9pm1BEy9urjyH`W#n>TsmuYrZZyK8hTfwSvX?jchg*GpyQXF5CwZvuaca* zEqSHB4qpZLACZiuGAPa^{sx={qcQoVYA3MNh?Lre_p?Z;l*ivnIhW!K%454|INV^m zouk)eS7&ri7~&+t)QPVcEz3xg*(GC1Y{EoBp{>;A_{{;Cggh0gD}mNeC}a8yz%mj< zYxnE#WBy*Aa(ZtK;Ol;4nr=3Q$uW$8Eo4HMvQmlcqSd(T@pZi!p%-W5t7)SRrlNB~ zmrYscNv!ipqt4%R6+?Bb!fk8wJtMkh(ay#GGMM;6C&n@E<5c{JX9=su3*+;N4&ALg z``c!exk6Vs)HcURA^+?^$WT`?Z$P~tfQmVW+V~k$PA19h05o|paXpGP)ZRLH71PS> zCdqLQa+rFPU8>J!LtT^}p3?^t^N}v2%?{E&KL0H=B}bLz*+*Kg>Fwi2(P6rMl+*?G zu>-|tbW~^@l8+ai(?06Iihblpo89ZCSEW|q$+hg8!o_%I?4zh5Q*7RXvMERyUT>B) zjyU%u`}o-d(nGM1Y{Prn$5)|UgNggEoWef74ga!mjwjj2+og=lP=-0rx`{LGE-n{@VDJq$h?Blu6 zS5r#m_bx|;lkMX*^nygT-@`r{aygxSJbOK*^0R@AuHpW*P!97f*&NC7#ufSY@f`?{ zkuBen9rGDlvVJ62mCdFl%RNulJ^Ux25^?@-lxo_?Tc#>?u!^Pnq*NDHU&cPFQqBr| zF^zqsgdC84{0!nOAHY7Y_hSBFAI(3IAlfObbT+{MrhSxYy4e&a(>|J_bsDVYLD@$; zHqKMlc_izEeUv(D9g$|zrS%RmfH_$YUDQKA-e~JmivVCM(&%*{zGK}BG8K_>y zM|GDi&tDsf>XnbYz#ZdLncd!`9pkfbxq^w`UOt6Itc6Z4oYhGd@kS}*`zXVlSu_l` z&9sQGpO-0Ql10P?Rh#xLDd2b%kY^DkxLpSUIRJ~eglamoV?0y}{OgZ$WXQ0HFJNSg zj29b@Z}P$rYrbKO@FY_x!ZDR8G_T5iZV9r(6f*G?TgAgrL+DZ51S#AqF2zcI&#mH0 zXakx;QxIVa4M8+ap(%^6a}tZn;v0oq#b&6cDdq5NY#NG~!d&IXs2Lfm@eEHBC-@l93ppP zxIvW422&`mhFPWIqly~&wJACd{h9ncLBe%LYz!Ca^@m>I#xSRHQ-dADNLePxP*B;i ztPB=UDw8*9={rJe!H#e#EE(>b{eH)8dOf1+5!;_Y6Q5w(nd&9itR$*}}EOufi9-;&K{SiG|(-Di>R z{aU=oPDfKFSv*ellv_cuc#7z#sY9igq1>#+8;5|KTS56XFH{=-F4~}`@kNf~!zL8B zcrQbl6eP?Bw_fG`rZ7}mIlZ2N#bf2~Y4Kiy+Qj=${8L!G7Zy*R)kzlbzom>;lwrYVjFBEK1wMaqjtm{V#rrY*ToI#5 z7EeU!y)53T^t+}Hj#i_Fq89H{x|yGT^Y;V#^4$Cxg2>IEE{Fxe(GnyqE{l^a-uIxI zrj*0;FF=KpH-FdBp_$g=8Im}i#XGN!aya**j6T^0$9!6gcar3oxG>-1b!M~WTfFL{ zX`7Nr4vS}>GAgX?>n$$!NdtZT0Dt?Ub04{pwQwy2#rYVvEu7REZ)bZkQe?dWAW&(9DoY>I84zr z7B7LwbTDxZiZv|W-}JWe;fUfE?^?;R3OP)@$Tt5fo6WFz=S#Yik|<{=Rtc;U%~ZRf_jk@v$MC57yZg z>tSq(A#lhe`b1v8PEDWBWri{V$+%9WwC+757UWvkLn5u?${_Rx(1r7AYnLD)^)I? zG_RwX0dAGCww_`PD^jC-r5F2vBE z$Vt;(Mcc?PRh5k&NuXro?k~=zC+$aS$VR4 z#`}@=rxzTotlx?pQ^|T+=Y3pD+>R8N_p(mz846_nLSFI9mHEXkR56XrSFs8Bs}^!C zl;@%tVypI_4KkEjgFjn&dnVQ_-fdD|6&kckqRXg7Verj`@?-PYdBYfD2)MacP{l-6 zzGuLhD85$0#n#HX2z5=lR=x*Ye{gH15B}T##afxPXFd)FD42NV{EUA70bIhu)seR& zp*=#DNCVQ^>0`yaG`_-&KSq(>P;<*sMAJZO@&o9aO++0U_wS}a% zB}Q$gXYnWcX8ID&udPi=bx5g$vP0Kv^UCM8oX-s_a-5X^N{ha-GUu>wnnEq-uz7Lj zM>67!@2n@5b>3;D#XEHBZ0494i+vnwf`_*OJrg321&6axeNb_Dlb)zP{L4!%xOQkEvHd(MgO!8RPvKc{IpPvKEOW{+Rc&@Z#0@OVVaUrql&-{Y6&`wH3xuuM4r{60M% zKb307xgrpS9?!#wTJh`ipk54bBYWywErsm+9z7n>%oATeAkAEj9!%r$JO-_T_rIW6 z!{cdzmYQ}&-7GnNh#Zt2=yZwx&dp{sWc5->_cf%;vjXqS<9Ys|t-$Z5u>yG>54{ce zHFCS^z&xJ1uVRD@?Jv0tJf1J2>a54J5o_59A?Uw~$D{vhdOVwrL0kZLUcE~bkHyzJViP8LJPYa%z~kAl1Oo|=$6P4z zc#MT&cs%A>K@;HdnDT8$w&H80sK;|5Eq-?En!i^3D-U+9T)B+><$bdcusbNSRwj8o zbD_S2iGO)B`g!PEsJUQuvV$Zq+( zBj}89DgR&JnbzasY-Uc@ z56a{DBQ);+4<66!u;{sQ8o2=!UT@0sKKRe{cqkBt$78Gp!{ad*gzoW}3&Mg0@xSiz zG<-XEp%gUq8*C^%9+BK>Jf6#8nQ;H{+w^$aD1O)J0#WGkJcDoyzrOfOMLeD_N+B~) zh~e?v4h?Vsd(kiAj8QZ*wxX}W(+VaYSVi&S-|XYHX1q#5t<;04q3xy04E^I!e4et1 zf0qtPV6T-$Hf;FukB`^3^$g15qip(V{0#kL#d?(P91bj!fD8Xb!J^U--fvM}r7^x6 z>a(AXzwnd4;;ux9A-MfN&?Z&63f_Ua$M}JKenigaSOe(8=cNyCugvWO-sp9`*@qpt z%WJlK9^Nlx{*FH^W5XMB@J|CanN~f6vUo0^MZo8?^p6$mT%!;Ag-7=P(0`vaAIwmEKIk|Vn~!UjPtk|hpgn@ye|9$epyg=5zscuU=6tUA;U<`p zVB!b(Tx3f6!1*xypwEZd2hNAthl2Ug`%r8?qz^^r<1bD6eEbS4p{Q&fFKvG0TkK03 zl5EZg#0-7BC+Bmuv`T-^KAtKWAFxWqP)m5(wQG<}3t+g^>l=_Ugx7Ua8r18TVQBg2 zpnAO@bIl`u?GIRN=3XUR&gD{0J)D zxBW3tM!!0kSc9U%twY>1wU6s@9;?<4mjolpt7Y0k&J<#z$^b?#+}f)Jpz3;|u;E4x z;jh`I%eF5X?~Jd*yP3NcA<-P{{##2H&7~&!q8|zs}7S^ zJ=t8ORlFZyw(7TVTk=}<$FEM+s&Y2OY}IbFRe#0~+-%hyh|gk&fmW4I(JDV|Nig9m z)~cmBt@>zTtE}jI@v+*R+p1Ac8}^{uyqs25WLmWj%B$E|{SRg$nE1_#B4c%5V|J{r zIICc+?wB)GtJdVU%F5|vt8T(Z!W^qBVgK~8(y$(iwW>i{RbH%BpUG*}FdUY=8En9p z#m8zvu3YWr0%5CcIjtHMbIut&bBb2|9+DSKtXp1WtgbmdJ62~Ew(26xLh)9W=8jc^ zDOVR^r(llN@=U9?VG$J@t4e8=)>NcbZ(;qL(tbZ~x8;r1=~Ir?P;RTPGG}miUA9$m z$hba($4}9!_2_djab~erotx9D&la}og{rB>YAq+tT!Sfdtm<-F^&gp5MX-p9ja3?w z7ffthR%EOm#xgU<>RN1P^TsObnyOWO)VgM?9Hv~w+}W|(h?S?0)!SG^#ai_(Y1Q$? zTJE49r$}OwI7|oL0RH8P{92+H4iKGVnjNzd+=Ii5t#> z*$lNHFP$L1Yf$?Z8k4u%GIRV?a-1hQ1~CSi96awYn&bPD<0Q$k40D;uu^)XZnuE_( z1rsHbBbr-B-&8qfN{&a*WIuXybIkbs6m>iX0Ydywa&%#0Gp$N~Zi*Z?OO78(j*8r| zx~VXS`Ml}{l4HK);OHU(!)j*HvwVx{2tOY?iPhoH@XB9h&v+E_yzA#A|65DhD~@$; z{y!M`ubn3UOAtrgf06tg`P}@M8Tpq^lmB+ff0^XxJmlt|Z{$CGn*0|?{`r!hvyz+t z{2HVGCr;CU$^Vvz{pTFz=AUEazjm7ZFG29pf631o%gxXCp>zC~=I58cFVASU>MECL zHh6{DLda2zF|LPqE&8*~hUJdCS`QP%V^)h49aeRmg^BpSsmQr};g+I;?9QVln9J@BTv zDbL2`$6vEa<_q_7!no|#5554g8O=z5PoH^21n@G8MLy*;U+z5*nP<^Jzdeh6zLYik z+7u5%8Vs(X$rfz@P6gkenJ%ikE|i>KX3kbyU|p-l|B>ik(%$8sDfhpjt(0sf{@ zoxi`X6=I#yfjRFxI!;P^<#d#W_YknOqm;K~X2%f;Q5usx zBy0T=MgU{DsO41tSpeQ^xk@i)U||c#2=57@th77vu9ux$s2B0}iF(QE`L8OigUXxj zluFgrf_GG__`|~1N7QAH;B{QP6zd}jehY0cng7;Wc}ZbT6-Tm)R@*?GQH8wf1~0Vn zv?vX$`Jx)M934TdV-X@6e0?bAv(6g$Q7d$VRY6n-GrrJQ*6|xQ5$$)E^1HGJe15!i z53NjNhu5{pkC~x3;d-w4&&Qy%c%Q?-8gWdp#+GB&ID0Rjf^Qm=93Qzv^8c~-Cg4$2 zS^IbrA_Rzb(5NV=QDFo{2N0DAYG7zU#wZ{WH(YVwwIiqrr0uk%rf5VViZiI_ILf%9 zEaH+FXiPv+0a0*Q+^TJy0f~r+)zQ%40co5;(4elCJ^r_={H1@ik>g`^5D@WNc`MeF$ac~!@j591wA0LWk zhkkAebjDvv$4z)pmgeDoxrM{cAO=DW-EiW0%=%R|co0k-MWw^J3f8x-& z2RzLQ6G4T&a5yi^;4RDDf#w*^LBU4x+cJ_=z%Li01@!4=3Y=ZcgWy0_-7K|VAp-aW z_SLVObp|D0V?3s2Bw75B+0R3mFC}_rX=5{X<>tOS3&vnmv-uo>38hFELBXcI!<@d)U8d zjlkKLAzey=$?O0NDfKrgb(1dj&%xeOPKGk%uyvc1_3N^i9*44y8gitcf}V?d@~l&& zW=GTnWk*y-z~SH{&;!q}B|V%B6oj`nsq3N|aguH0uyP!H3)2p$nJ_WX8P+e>a5%?n zSfQH&qPY1M_E-FyWQbaCK!^vU_YIRy!QLc@Pcdkm!Zx12F9Ar5VHN!O;vjiFh`*oe zf!9;2*e#wSSTdnP7yf=8#<05a$1{K?b*?Td#J_b;+l?=28diaKS*a&jTfJpuJBGSP zHbjlABRg6SH0Y5Xq(-(EUw871Yzy2x7@2(8KmEw46Dh+BJHlcbT&VOQ5dUwr04oxf zmRXX{0<5qG!K)CA?uqH{$^x7W-cM%%wm_I-|H}`6c`U#~#6p+l1?Q?}_P@3O?~&fd zu{Xy8Tp-4@dnE$}LO!D(0QvtYO*$r9f!)3V*=Tmtbg4@pC#AE!r57ic_F911Qs=E9 z2@BBbL)NpS3EURoG|GRs(V#5AD?lrxpi>|!665h$fDc0M2cuV^4-Wr`V-mwx+^nR9 ztp=?dr1St?`e#s|Tec|4DQCKf1vp4b@2N|_nOs_1fL)~2w|@ZCWok(l;A7N(87#mn zyZ=iT;NPJgg3)sJcw>bzvH~;b49T?C>#%DwTYxu6%>k@Q3vgmqU{5oX0od^%z@7%+ z#O(NoS~jXPpL$9wKMr^bhtM5yg#=+=wXvJ&w zeeo|?eUphBuhkbxXZ20NO6}ig^%efhR^P-VtM4hG&bIpS4MtxjDfh;J`1Qr!)8^T} zg_xg`7buw|T5K8_2S$~? ztv7)?G}4BwiAHGlP0WssPcr+yIuM`BVay7p#Go9->^r(2YuRSs``YZ=A8+Nh2yONq z(MeVQADeyOYP0WmkU&D4UaM~kmZrhznI&ngzO{Q}fa$EhHxF}Lea~QVmSXi)q*{Gp zG?(7$y9O-)q;9F^w)##}pDDElu`gio97?+stM3)K4TI4sr=+p^ESTK3)t4~&KpoZ; zsdFakh}Cy@73d2(tcPQiQLO9pFw>cQ(`d{~wfLJh@7rrXw10%OzvX0Y@!9PkjP{Gg zsFaI9RK*g|d#~afFnfo3mobv;HVG_eV{~=KDQ8TaL|FLU7tPpT51Iao9x1?5o(d*_Q-W zYb~t0V06w&(yg}odh9Ev(iJ3*fv~e2^X}Pw9K-Jt3Tm=y&5&2ToOWE{iyu#T1N zBhs9_T^)w+PNb>GN1HfSNaxZ_kd&N=T|M79UjSDOA*vZC(B_(L+uYbpoR_e!1dNVx zt-;bFZbmjJa-L`Mi0>%_vi%5<2M24IJr#J{s6H~Pijv47?xQ(2-_V%I>* zM}|pQMj?!Q_10Nb4a<*ppdR2+=W+}h##lk#Pb|BJVKpVy!ys!M9HdJ+r@1(=vXf%w zt6t)tDb7LDE>9rvm1o@pWe|*xJCV2+Jk2^1eJUi|c)Cu?6r&9B1ZAi)!@ne;0S%ps zkqkOtc!9!%i7RF__heV=k#F_qd$YLp3~|<*Z6_uW z0-<9Kh5~kns3%}|Dp)T5rUr{fO}yI1R*`sU?5BP)h&3QUg%st-z`2e^ox(N4P9Y@s zDNg2^DI~OAa7{<4yRLr<*Nku~+t~OFT!`~8Q1)NsnzMWu(7(tv2eR(Jhii0D4Y@|g z+K_A1PvIJd*SNXn({AY7%4YBK@5eV~BIH3AlJjr;}IXdG&;(P-3MqcQ2`8ZM!W z1`>1|k87J1#GR5YxT(Y5912z97Wyrb(5%DYj)BHF9SaY8jb?`OxoZuH6$xGR#?N9d zUk^|3;V4Nj27X!Ei#P7XtFkNgBbNaI~?M71Usj<$UFtn(K_ec=2DbVG1H=kcGU?(|HN z(r4<@!OW#)oqvv$?ygIpnOs`0^N*EMEyrS_YL>2@;|tpZoVM^z+U5xnwHw8zfuAST zpibSO&F}@hy}{@+Xfd>LU{z%v0M`rPlP$h&p?_uvzs)Lw3SSc_!U|3rC8MovgW~2)cto)tImevO zU*-({8(NBk;PZ^KjdYpUAHr5=af4ZXY>-y@LIuQ1tDLm7dJ0<&v6ZG0vHi>$H3}dY zIDe^UMC)?x|*k*5Ijk@86mI@g>pW5ng{Sk+p`$tU*AM^GEf7s*Qn zYT^jHhUSbN1a3%ysi~xZq}Dp2J$VZtFk>;Q?GB+;Na?u>3rPg*B{bfrWWF+xgw_%` zF)|j}+`!T2gyxG_+L)nvf_0>X+dqqNL!}S^=OEZQy&c==P3*J;21Ul^!yGfpK4u%Y zNE>sUHq=kFLC-q8^L85@(1td}%vYL0zwY6zXHz|PF&xfThVxom4ktHhO0pUB6;?y` zJkm`m(Z(HYBV^AI`U$ORd|o7#U*Th z1h6Cd{G<2+eyYLPytS=(L;L}L63%jJq2aIMf0J_}Vz)xU#USrmBpnBZ9n%QKK39cC z;k)M(`u#X|5o?KeDyi1`7@Qd`u`bEA(BN80>lA$?TDdn2?qGDs(NqD#vw-Tr>xd>{ zQ#>6bPnsdEB6$)N;#=FBSyHfur)?D5A;C7DzT=Z)b3wOr2?G1Eck)o5wJHxVD?c}L-!aF$gF8-fw!}LIejx}Uz5(J;sI z$DZqFAO>@#y-efCIs-PD;kjN5u35$Bn(zG5b|GMoIuFb%cd-Ta%d5)Csu1iOgO81~=xiWFn0YGihuNaIr_rSDq?J}^{vX8>r z5s(#;VMXTH@x@C69dZ21A(|K?!(`xNu_*Ikm0C3i8Zo}kXw+qnMHy1nAK_Tivr`s0 z1d`alAjKz+;Q(&I0Ib|2(BxT#$O;)+NMgseCuIdqCG_AxnZf;T??Eqoa*ay$y#C|MnrehX^|5})BL3vX28lTL*1Oe9%H~{B|Ku2R6z7NIs0JnuT zp@f#@ixL(Jg*3N=JLVisFkFjnWc4tglH0fFut_Dt(Q zsJ~$Jo5M-G=K~Dl=TIP~M6ott)lgOWZI-Y43A{D;Z}P9iU+e%ko7Mff`+~p^x&6=_ z-HgkMDHWRhAM=k{eIma{81uH=9CG5s$e8`H?#69jtE2_IS}OXS z)G|3MYx0o*EpTwTQDDQP<8W*hNPkvu%-#X0u{yK@;i@a+?^#C>mix!B2O^-Y!MyG2 zX+Zk`oPF^Ztc$m4uN)iz{f|dO;>q zQiJTnETP32{}hm|#1la_9wNYzjBi8q2BUvIC=zoN_Etw8MAp9Nx9SOT#*cp}95L-;umdlZ5)7`=YKOc1-e zAS1;7tJX!YOb~02>A4`*fgo}qb`7S}3dAbllm%BF_pLzedOQ(gZ6W*|h}{T15R4Ao zHxtDA`+l1c>zxT=>maFI5L=J&yC7D~$INnU1Uy85SetJIVgvC+h^+-@17e|#JtF=s z%GGA|hk}9pFNBu`?gjCMinm7ZtRer=`W2qfs>&@{fdSYxJQzt}KghCrBD{NW0>~|- z)|cPrV69(%K;o|3<77TCDS+3lRUa4?IrFIgf7X!l0vE-06qu zsUdv~XI8tDH0*&Potk594{pU}+Su&~v`1TPAigqbvTen~a0mt%f1Y(}(YW1=njc~s zw+&SYs|FRY{VTxts9E7Hzp6h;((ma}O>`*u@lu(cjek$Bj;=S!K;8+4Ii zLYIKgHIHsN(^?6!8H~>AL>{Gk8Ufse+HHm&=uk?`#^|VK)CVWix z+0qAL((#XyKII5;a0IrSJHFT3; zCT$=$wTBjv%k4l=NgfOLv@U?i4MvYF0B5_dz#geq8q9x`d$gGODZ2vnj$Mj&ovY04 z)h;l%x3u-C&xN^y448WdE^yMJuloLUm;*ccExFH~=;JZr0|oFL1MF7oTR^l_Y`OgoJ<6nXas<}8T^w#CH6=x#QXw7d!fx++6y*~_v26VJ&ze7 zI=@E;fnK|Z$T1MI84yYN3nFnEjt$bde3)ARnI-eQ&ES(N>#ENMk&ohuh&&OZP$YBb zR6O1X=^2b(vX>W+HOiV-AW9%`4Y%pschS>x2KF}4}ywyY< zId8c}-EMGR6y%#g*Y0uN1>oQElL@1{SXofN`>c2`M6er!nnk%UHG!YzJ6sxCo)iBv z!I{|P63$$WZKRCY>|kwx!$V?Uty!N6LRZrRg27$|X_=8TmqDloqto-f7+r+TD^yL- znGZm&I*84nBd(Qp`=eb)-FbAxv0x$5^4?!6Ys4OV|Bm`las(Q4opsWEU19w8$ zsq=vX7>+HQv`V2Lu8%eV!tjm6pRrE<1aN7xCeTv?mEuG7^z&DfXt6GXkj4Es9o=BC z6^m&7Uhv!t7!I;~HxU{nlA{YH$9|L?y!Rr>B(P=3mlQoOq7l1#vUYzHK8kpQRsFGy zypA3VjJ&Kvrjc7OK#=47uMVJy$^r*@o>AWlr?`x|)b5s}25vgg5QF%pG1fAwsCXMr zUqJALZKo;NE92x&3?aol@Zcy{^wha1r*O0iz1sbyQTtzP6de8eBbn*Dc;Za2fedtM zkF^k%SpT)RrB4RU!T3p~IUa>bvANDhjjy_jZ%1@3UVh7MRkxR91v;7|2KHQa)QJ8e z>$sjv!Yho@jT46ymljl>81WaFy|Gpr?^AUckL09ICdl2vO>g_gknM;=qtDrvd_Al&WrkjWYFUTZSh&)C!kJ8{D&A|AD~ zv0bv)mda#4L?JM6`GMws*sF^a_E!0lj0vJ0a2|%RJ7jV!$|*9D{npI3{L65tfR%6g zK*;22x>rCZLm*t!&-76UXRLqQxmnmF$*zJ|US>JO)Uzy^2*vLs;7tvxss5afe^riVgzOqPah#|VX6hJgTMJ)MRDqEqGc48V3yIAhm+uJ+TI3156+T6$96o41*$i;!>+Xr@-7%%mbO;FTZ<7&E2MZWimPZC z$>9aw+6-!zKq6oGRe;|txsmHEl5211P!o1VH8Kt#;io~(TZgpUv%ptP^VA&DAGXS- z#Cqamyp#3ByZAvZ-iY$%nEn;vHNNV_ct`91Y`z=PzXB?r3(Hkxppwp8hm6cF;!06M z{|^8&%L0*{hK0o@WgZmJJW$I-<9*W?pT{q@SrBLA1Jqo2=vnz*h&^n~$xf&r#K~;u zDzaV5lJPrkIj+N6a#Z4;BBga!;{*D6(ppbne#F(C>5E~ z4rJ704#W^H2xGX%kb*0L)LiR@wMsZ`=js7R^gvEMj3o$o3WJ*1jKhD_a=3!a;Ryub z5}sEy$gEuJTeR97rlHh_Vqq&X-xDCx#{6Earx#wUp-AmT^d`1~fFmUTshDdSp9>6X zwqHWf#y?2Zx>KE$@hdlC(c!-M>XoSF+a%5_7#)%gW=iM3vPxi8izq#q9D^VUf}ta= zbgx4y$y`#({7jBVj^15?W?E4JAHqC`3Yf75?KW8}@kG#$hp1JnI`$0~dlPaJ=l^60 zi$TIk+|=9eCG(ap{h*Y-%3FGlw=~yx>&~=pmZB%4DB^VNm=H*5EnLA!V)z~l_k305 zx-4Hcla(+ZI~d5En2Y22r}f9%5aKWaqX)iHkkf~V*jejOGyqF`09Vgg~{Z{}{4Eq}`ui^j6vHG1bE}9TQ!%+{>OO~nd@!Nn( zv7tLy4}Jkl@Jdv-&Rj+MiN6UNs=-UrP!aYyJv1~0vK!|=?A$}rF*FVR`7QL26niHW zcaD_q?k#<7O6f%0CADjJsk8alJs_!!o$y(z6YwDMc>-FJjs=M&&edy%`R_Ra52G^+ z%n{8v!!CkD?MCHwMDW_Eym9&jOCF+8@Y8BUK;ZbeLr=@Whv{W6mw;sGq?Yh67(_Ur z!_1}<7h(@n3+x-(+2Lh|5C%H-Srgh>;G4O0$%Zy2(!Do~2z|b={VJxwEH@D; zO_K@^XTZ=N4Tyq=>J?_EdpjmO*L5~wO4Mk381=#EdpiIdrGPa8ULuNj5jFZ2WO*?9 z0O}HGG=6mD3a2vV8};NPQuaEO{kKJpwtY8E)TmAvN<@tw3Y*W#JYm$R&Mr!h8m*xy zNTjF?&C^k%_t0tIO4R5INL1W^_zU4D((fXy1(GS3$r85cvhJ4}m!bxtW=D`Eor4aR^kWCcV~DA?<2%`%tJOi$>Yln)J8JY@&OTi%>haR*r`y@;0wh)0t->A! z>*%P_?;-AS{woUoTcbt~h6Ti^Q42A!%!Eorjdq85#i&smhlm=rk@eq=8vP0aG8mor zGl@4{)aYq&z-NdlSkS))e1Qw?Ge(W_dm?JI;{Q$5=pQj)*IwLd*xhjL#XUo>d1jAq z{YOC45^KU65a^B8JUr2u8ID~{;dO~7djV1&{-14`Aa)=&!4$+&qDHF~#2PY3jaDFP zGy%2WM%3tb`0X8lx}rumBbpJQJr3HC8gw)tGlTY0cuo+h*L8(}wv2uhfcAUHASFiy zwr9cC4Mq?9DHCk#VXbALMhCW;;x!U*U5*&$e=jv=j2f-OfF0mj^)%p}z4Sx)m>Fcf z;er7*#+n3VhvA7Jdl{m{p~i05MF>VW{g?@2Q{jnM5K9v^D*Ov-%oH{HpQFZqF>3UB z%*FwyD{AyItUCbM6ErP0(%kg|)*Usv4o(x$;`BxV>C3 z!8Qs;$8X65u`Fyw{1zdWF>18sGY`bF2qFh!7h|uW6^Px8)gK^s)G~qCcsvneJHYY| z#4d+s2}b+=kO^XMW2fr32(gS&qi~C?B}HdvA%dB z#NGgFI}q!K_?TccYjY-u&BhK?28c~n+7~$+{{;<^F>3TL7_bXsv$3<_g4nOLoijsh zFRT*)v8E*gu`E0hVza>64#aYxVuR7Q|CtG5SHot_0I~n7g;zv(Xu7w?S>`*^iLthPZQ_BNgfvCF~P4#ZYL5d@>N|B(q|{b3hofY^W43dtBXdIARQ zf>?io$br}ch?i;wVo$=+0UEpXHG$Y{x;+4~eh_{R#2$hk!2NIEXM$K;n0voPh-Hi# z-2(%5L98u7`|;6T@Y)-$IK8bgkKO``PM4}v9@?3#2x}?17e=2(H!Vc$p0ApA?dvC zj2gWH=A1a*y-}kT+y}IyM&GP&C2I72+JjyvJ(q;1VCk6AncB`8xe{|&ZnftenykTi zq8If;@EYa-C(v$0jdq8s3r06v@HnO4VxJ1Ti&JYYYLq8eTVFyC!)?7AQKK;$b`mvu zAy#+Z`8iRex4el`rq%0ZncQV~;^cmXcyG z?Q53EOb*a9@kEUpnW9F!a5fS(dJh&?-r1;Tb%@WSaEc&m^t_j3LNoEi3H8E+G>;;7 z?LKG)#J_z@9%a;MhUk%>V5kVaO|&T-Cy47PQAQU^tlHn{boB&@`WfC?GN7z5fV@`* ziRR+C1yFqt7zBwO2V5e;utFbqw>q%C#E8C}*r<{i(c@5G9f7iY(S=)SXQdAl{fM9D z+0DmJ(<{&+SZvvoOA}F21~*7-0{0O*E(RbQts!{9xqJ+^7YzH1kU8v6g}@?uE((~;O^`xDkyLx-`xxqo4^`QZr`Z(iG19) z6~r0u8>_f$yD_m*B)hh|84&shj6MU(dhinhLK6+k(MufDG%Wb+iKbw!o%Jw0F$f4f zdy$~*9y}3cJt5^3Pp83IHFQ`oI`S(o&W@*PAUI2egI*eSBg^(ffTspa3wxo3R(a~L zFw7LT3^%qCe6@y%VhrdCg(z1DXePc|1(lw_&~EY7#bC~Ixdvn=>#7J)&1hqD5f!tm zc2%Xh9bshv ziT`5!C+#xXR1ZML+EPdFi+bWe;pJfb=X}5f@t^d0Ksopz1k-D~MEobz2jV}!aD#!{ zN!)RhZSa+_Yy=El?cU9i6-rVZNJ+6TV_tU={<#>-AG@|1yQ8L8g6$Cg83xKQ@OnIP z;Ag>8l^$;kV8{leRiA?vGDd%Pw#V#>{;Yr`{GUXBR@0*MT2yJn9?nNOg`qW&r`}n5 z)c2S0ssKZ?pO=ZgM;{9&dL0CwOV+#(?GubX`q?gI%?U8ol&qQWmNgnNzUq7UmeHTS z&|Uahb^DO4z-{J;5=MXy3|ak`{G797Th9M54%7?5-HHP}g$CveJ(r-r_zbN@7!Eqc zks>g0?Oc#fEL}}CFa@smR)okbxLaapQ+c004`6JxrqKTaA#w=RTzY!9Dxf5S(cz!E z3Eji*U&5dgLjR*3B{`fISnWp*ijXqsQfoSp1y;@!2|9{4=5CNoPgQX!Un`S)7iJSCH}zSW-0OJak)Sux`b>@l?Iy$8^nrvJ z*~X-f*Vsg&@kAQgk)Z#8Bnd`ePFw3`Z!Jc+ye7p>6qj@4@+A_qK;qR4!z+AYF)1Yu zbWe)UFKx}(y{?;Mcj0XKPUsU8(AV!f(i0ybBFbtOIX1-?}DC+W5 zs=O+^U0umW}FWVD{Z(@794jg@wrs4;7tynn?ce!VG3AbaRMLz%mdSx(T zM+ZXd1fzNDz<%kxSk_}vtyeB-wma)KZhh5F@g<&R+Pp=aDG5(jGc>io2=<{ zg#bo9Fkomz9p8B`R7fy-!TZG7X_@0Yx4;5Z@tusVN1sXYokQ?8lpNpr5IWZJo%3P% zIq{ug(wBA$$O_$w?~D`eT%m8k4>OD5orvtLTvd5fsIs9YaE)2E(#)~3Z^{iZlvt!f8dIkV4TnpA(tmh~c@dTE}kg26(Jz?GhV>;IJY`r|01CFtQrq?vw zj_fNAuMXDpFWPIxD;_7lCDwB`UJ~d1;EWS1$T8JxzNT6C@tv!YUD`Sh$&$926nZwA~XCK?`(OAL7+Pf2#4}~W8Id=ebrnLMndz3 z;Tvi}n&VjN2BT@qYvI+_O zj)WGWH6r*704CgE_+Jf-tLmQ>I9vDLXjU#m`##;_t7c`xmdA0B_6#8P6*(9I% zGj`9%Q!-S(>grf$dp$#2I~WPo=^j6U@@0<;0!OgN!@NE2qkCK+J^I2c5Yn!t=T{IZ z7}gHMzqrXi53|jZs%H6O04aP93x=lR99^?)o|!wHle;<5)#2>wU~gCU5y6G&Fq-`lZDNLLb;rX6a%V5O`=MO3uX+gDasE z;>*~@ga^&g(_q9+p_07p$c?y;Wj!(y`fMFgKF{#a^@Vu0fSSyXmmrW^%))tn8jN*6 zJZt*r@+`ogR-;iII*lx^JgY0@s#!Ld2tNt+sF%bSRM^eRMz?($bQ_h6QR;_hp`}d! zVzhvAb`u}azABX_2DqER)syw0=TKudM&`ToDh{P`o*G%7t!Ck3)wHoG)7YxmaQd-b zhK7wz_ShCUV_V=I+ew+nb{NN|vF4i+CD2|W1sIh$6k(oO`m~vQ521fGaHL4CJ?Ov} zE~EK?dHA2+fjJ0-GlRDdqAS!`$zirxk&!JuR~f5&Zbnbg4Ra;y4->u( zE-TZ&K4j%Ll^}1*A<*eqXJEA;*ZiP>eZ>!KNLyaut(f0ivBd~Iv6!`uzLE0fX4(44 zh-RLFy#ou3yMNw+_q?A1H1ZvIKW5>D%{X8wxA@Q;cE0H+QULQ{p9X^9T1I3qT^~=;!)ZGl21*3JX)qOm{}$MQY0gl@paZA06#1Fj3N!ds6CY$iaTnWF$3 zhVqPmrf6tlB7+L~#nzWVHST{#V^nEW^Qd-~P-ed556`7+!V1a%G=CJgQwJGELXTW7 zO^bZF3*8`z^tcGLY}xuGYMumx@M+J1RW@}`h5(Cih*U1u#6kx72sR9*9aER*QuSeB zX!sw4iGkG%ew$_ZJ;(6Ri}>dim(95u=YA|O^UUMTQ+5=ufbDR9gYVv@Jyzjp5)7!V z>3{4f{~Y|<+bo}pDX>9iY@7)}h}9#;n>1M8-2*5iwJiJ;+$xvPV1>Re;^*WH|LmkH zllJ6!B8L!e2a}%4X6qbi>tQnc2G)&#%+C)4Og0}QyG-~AVG!1ZSjz^ZM>Po!Oflu9 z5Ay^YxBJn^%`w^~Euo0#ui5hJ4=Fr92;~@mmwnJyZ71!%+bBzMZTIv?@?`aogzF4h zJ;2wLgOj*Tu>j5DK3g08(QM;HbI6MYjsB%7ac{_rvWq?MVZm~Ts>*0qAQxY=;ZIu% zd!o9b#vcvrfjqZco2n|8W(B&arHR%cS&>&rEar{*Fgp){crr`5f~J0xdyDu z9~ebKmG&~>{&UbE=>K&Mql6*X=wFu&gB+I-aDjD#k<+Ke98wRMysu$WFEE)6z=OO1 zlXU`<_X(5tLrnscb%05Wz~ud`KtJ==d|MwGKT#d!acmyzufCSVZ{PpT6A46D_1U_^ zEKoXD8)tHMyr=4ym>))(&Tw3gIb$l?I)m>Sr}8TmoZ8H6G*d5Zr`qyZkcGHEmTk$P zbaRd|o7&hJna9*GX-s400XUfk)eh}|%tAXm`tBMJ+{Li66AQdiVSImRB1d~pVm78V z0}e3}XE15@2V2I!Q=Hc$A^j{1&Eov~DA;bkEQQ({<(q)aOUzfgA#tux1I`dU3;<0W z{y;%ZiyVKlD64LG7JY0(qC0P_6K>kioIeXUHQ+p#fypHK3<%<@8OPnp^WOQCyE zY8dwV^{NJS&%th;Z6MMo#AA~NDmU%hvoRFVrKo#sF*;uY0H;@mi{d^S1`>Pdj&X2+ zrCczB!Fvm0Z0WU!)g2R{u-eMPoiPjk-2^2U{|X}-2HuS?PDn=RMQS>0I5c}OT8K&X z*@}InJ-04BC9vO5OB+A|<$EDI2A)m(R+-TDwi9|sLepV* zPa6(twRuEJpQB5+%UoJ+zPwOMAEirw@S?YEcq8dKL2j{iycEnq!O(_mGqe$|Af#DV zuQ71tgB}h|`1>ElbpDx`hxlE70TJT%!~JD8iSFbT=p`>iMaGOWsj7MWg!lAjaeCiY+WGT9f`KM zB*~>UW6vkN=9oaUc<5V3=ElDxky)_pt$j#5A0>QTkHIm)Zv!z#!HDf$Ya>m+^P0k2 zBn7sDWr>RkM*pr$UEwLE{7PfbB3(lZ562B*1&uk~Lrb%bpSHf97iim;o;>g2kZCHm!MU)E5mzIVzj8)1ogXPFfGxDXN`%^Y`9VL|fV3P%Oz2tpa> zt1rpdHy)F2xTlDHL}MciX#30omf16=quddyZRZJ)nFbhR>1-0HW>dG?h)cfRb* zv$Nf&FKwSj>wR`j?UQt2mUNZdmDC-Wnl6fXJO#&3X#;8*T?Dr~5MuL7exyv+s1T9% zAzCe?;Gx_mhh<4e4hHQuy6r|A;EA+tI6DPh8iT-POU-iIlQ_%~Gd&ho6kB+oKg-YnvP zQsy`fZU@e>t(xP1Ox_$UNpAo5ID8jw~r*))8=fcGePS7A#I)cNp--Lw#T(Zs^z1a zmn$3YCs(#=>pVjfD%8&wPZ*|c264ENVLdq98rV$sYZI^ZV(=z0zfySm<;N9I_r;=8 zNwTx=f+@byo~dWm6o&2zMn^3Gl+e*3@J?xQoLpLbpkt-<;kxwZCo-0nRZ~wX{o{Pq zb~LGU568WhB?VWaAmHbMhMxWd4`U)&&EFG7f5@x(9AWzql;hVvNU6#FeN-FLi1<+hmlKKFC{oeEQPjCn=H&8|Psr zFuQ1*U=V-Bz|7D{jbqo%;xaNgc(6~s4QmXuzggBbQo70X_kzEwP{mr~G|@t_+YfU!2BBiJ3(wAi}EmRnh(&y;XCnT5F4z4St)Uha~Fa?m) zfx?q0tuv_)Y`Sx8?eN=+)5%)Y>-6#;Dy@9~>>gRcjohOl?%)q7?P{p4lG52`8DfR# z*+yutQ8vrBsH{kW6%c&lTeOBQ?vrtyDNx-RK6&7NR>a?6mi92qd6a7b-W8c;bKtD* zYL?E%8|pZ`EHq0W!yjD8nU6oYEn{J;HiR~!{xZWq-6)$G!G8Cq$e3=_C?SOMl}!cB zZALfObTDy@Y;WTY94@Ll$%U5!QYfDoGs>z>w1FX+ zWz`%<%US)*&`L&$aIkD$Hq+&92?SG+q}2-2y6j%`g-93wbhB)xk!_61bAk8Jt2dfJqddc;T_1n_}5Cj?SqQkysb>$yjAY!LYiaTO@ljb7OQ<{G{)c27`p*# z1M=?~VypsQAfl_R5K+ZNM!1CAPqjnvFL^B7n?K6Bg8c}=+J5{>%?)&gAz;PlRWlhw zsg(sjUJegT6pf&0q-?P&ZPda*Y?0#V{Z;tiaE1ED+-k%@`B|=Xu30DJh+u`5 zfXNuFn~cpYhxn;I*|ikXVX=AefQ4~OQVYL+)-ma8KEEEQzdnMmk;+-7nrq!M_CXPd z8IFWvM-T4k9Bh4*)d=l3hH(QyOO{c~(=409xOAe0G}ai#oj5Jn3}Y-$cp`pB>J&=O z#&4qzhhh_YMi{>77VA^=5UC}OYQi|lAMG$eLuj=Y<`H17%UcULmTfI&n6G^^!#J>8 za5r1M_swkRv!<$!Z?k;WQBW`s5q=(jLqB8_lv5B=7OG?GZG3m%j)$r`4its2!$TxO zLL{{IRG?kC!$Ck>OWNm@AFUe6o`h9-O=x0s_Jl4~x3$T_>)>_LBvU`ufJ zb$a%{peQl)kb19Y&$pOR3~g}s>+o04ei@sUHjAYjbqR}E%Q5*DMF@Jcj{TpQzkm5i zQsRkJVEHyHPyw^{CIKj# z*-x4w_xl#r3j7AC1C#M>`>&h;@edgOE&~j|1OqD=#;!w20&jYy0^VCL;JqzVjn|;> z>i8CfR3RykA(FgJ2Z1~0?afB*9E^p#(lhZ+W7AhJgX*6bm|#Zu-B+Joyfl!nVICWc zAx8W)W?e$2p#Q2G(&H}1eUvlqz0nBAy}lyNxTW=1(Q|wbt{Oom8dRkaTK~Lb0viyX zr6=;%jsywz&+~=r@ff=V0EtAdBv>NN1ayM(o`D%hd_^=PY{yp$=vwt&2nP6$ z^f3W{ZM z)wcx%e7*X%G;nn!BC-w&7MfRuA7Y4i)?(-)C$n8Z76FH24lq~1UdR#Z7VU5&gdE9Vi<6RywYuw$W5))DbMPPw|gp)XDfIh``_YMhH$OD{RX)!W;3z zch_D3ZB-qa2m`e63eP~_2K-wr&%O}PmUfiE6JTjlf#?X}9Mi)t=soJKv012qn(qm0 zJ+j|g{1pN~jBr^^q_oBytYQj%)mP(_Z;>b;Gs3=4%2w1@C|vND(-WRJlq5CBl2%?gl}$c8&PHRlyEZprj1O>H>LHXq!ol1UkmT^&AQFt2n2lQ5i5YBl1=zRTEyv@$o=`mYxgwuUW@`2TW?dwJ;L852gXZ zempj6Gxv}5vs23*0oVZkS^Nr2nt%3c`Foj=4 zY%7tTzVKfhCh=8=PCArCt;leG8o2{nX4+DI^4Fxim-`s}vy$FVx(29Ceus3O#mVowIM#OlJ%EFI ztzgzJ2N#aV5uaDqs)dFM( zTR4`leFY7(~@e_@dw&dz#+`+cB^kLTGw~d^xe3`7^Q%{|cVLOZQIA7QypJ zyt7sADg2Iax8INE%4%YFA@Eg+$BXfcV(J|Hjc-)%{6DI9C*dz_o3dGEL=2l+>4s|y zjO=dMVXTs@lg+Z^aKuUbnTciIBh$dL{eVwE%}YHeV7E8^zL$Cq=euXU<$Qd1m$%$6 zST4rSOQEu__*!J1hfd$(>+Jxsx8X&6E%e+NTS5dhsW4l+*djx=ZQJ4|+E2HOr@F#>j*=+o_-<8edu&is!(WKE!#V06Z82Pvs?IH6^sZJ=R@Z zwF49yj4uBRT`seQC6&viv%nxe76OoZ zLIra^x~`jYIzFl1%ph4NHyDif{lMTt5Ter{^Eg-?#KReXmL(QJckh2+q zlg=oeZkEo0>jq(^?9Ifpe-3IgQnh7tFS=|>r_=EzUbH-E69Q%Zba*k4&4Dm8f3?}c zSMPtEBQVRJMoVx#ktC?v;9#hvOs)n^Msn|c_~YAj_pfe zt}}=^mxImpPgPuk_zcmASsjvU>7|^apBH+m{trD2^=!#yiX* z#@~N{7(X8(-H6asBSX^vi5RY$@bB@$tSqdlJ%&Fp&xLg57tKJ9Rv1A9}ECI0%fU+82b!UuA zDJXNHm=R*i3m*Za6M<0&V!rCP+oMe}N7PCgcu}hmri>REO%X93!T=`MA--wZpuPlJ z$`h3Zoyak-3I8IHP0d5FnyIXOHO0~zjE6j!r<@8sw?!7x%ElYn@Oktm zQmL$d$^S5~Zkzyg$XHCV#MO9GkTRtmdcvAVuPMtrnG2;AFy6EX8LtK_0S?h#8$bqd zn~8VP!9tg^K>lHnlw2CuavoR|^xWR0($y4MD<4R4E$P}yU z({zdnc~5%d%EDKDEXpP-?uQ3u+G)RWKH`~GI-FFqQw0=HjvV3iD-4Erb zc3dd&mIn#kSrIAjp``HSRC(F$Qi9t0uqr#N=O*Anyd#(gH}&%2E+Pkfas`nVu%8D6hB_r9^bt+;uy#EVg(G$WCN`kU}Gxi6>mD2ja5ac~z1R7AKe{B@^f6e>>Kt0cnus4$@_C_Lgybg3NLCCwD20ym5r zUkga(d^W=raGcqdv_8|1a4gpfYUct%PjF<45-~-Im?7?M8Fd2*g@yg`FE+VwRb5R^ zmAu2o)vR)ik6%nxn*o?2YI#HM=-v z39&R!Uc)!U=^A~E+o-S|lAY8=t2T(h?sozN9*w<_vW*%N!p2$z{l;ak{f>O{DBs=h zeK!s7V%Ksa%8{T|_XNHkgx8I-$&?-2OXf-yV)rnHMX-rSpP!(5pHi5pR-D>ZdK&x=ZI^GZGdm6s!sFU zdw8%1u$#2@%4MWAX_jIc|aewtA+NN`~MLucnvndEOrOcpcJ!)dM9lYVOtP(hnYYEnFy>P*(T?}T^f6e zEkVwWXod{o83}*p3)}D4$&3gRKv_pk5hVEPbK*$pgGWDsfq~s(a7ki3-7t(|;a*>8 zFEpdXUv?~qO?qhVm>KB${_S|}_z+`X|BUB_GzyfnP|J3(d!(|40zLstkx=JeO@vWy z(aYz=bGl^%C7dV%i*ILmn?1~Nq$)JcSP_wbUS;xZ`7qQMI z+fYYbHuU?7DPSnxgEe4^I@NYSWE1I{95F`8+UZwefa)z#4`5#)Lr$xn8Yw-bd1Y@N zC6-9fCb3e8UhRj4gh9@^V=Jik(e@==!r|j)k-B5L<@xHDm)((=R%h>2h zrEr9*3NjW;sE(B=hJ~V(p`j)PrWJm|)@33aUc*F&8@ul(0MWzuUFah^oY)kQD@zea zNh(P9>lV9xYvNno*(}%A5Z1=PVn^d!q;4YLs-5yWN(szG_LmzVKVo0P!DZIksK!jK zzfZ^O{qQ;hf2i`-D*h)JfbH0g`2I4yTwACZjoTS_sI}o!G&?*(peIN3J_Qy1qFwN$ zH?+h^kHeEl28al>xTfc?>v@Hbuw&K2^v1?jDF`oN-4p0#MUo}pjiD>l?5c81Q=b5edxjWJ7HPYu8SD%SnjW0{v=V!15 zTA62>sQlo@8d@EQM@1qb5~lW*F26vu44kIOc}83vGI^T@OXgS8U@`3B<82&VfR}}+ zij%Ww3hr^kPHtgTKLirs^S)OCCXMja^y4XTFqLZtFf_2zd2awBetF0}JqlwuJ1}$q;~RAbyUZ{KN|&z)+xcP6YN+NpoXv z9wOallY)omqkTA=0^M?3Mk1(hxu^Y`r2Sd?ScKA9_QHjYa|Hnhq42;sw!fU~C^($i zegV|WV%%+O_-CShG|ref`YzznTkPp#FLr_RC}%Qo12a%_b$4XlApq%vi)=( zpF~^Ejo%}Kh(83G`>f^@_%kJlyergTFltqc_@huEZD}cZGQsPSf_ANM{=`}@q^(7k z@zip~PCqO4Zbv=FPM2#owjX)UE&5%?NR0$oIaRY{atVGhkhoYf!Aq51f8qB*n>e|jo{QQJ`&qJWfV`>fTxQ1v`pBCgV8stFy`cZ+>byf zsoK8`gK^PLvc-``6Q|?=|4I5h%hhMX%9(-<+SES3fbG*tpSxpm>?eJ0nC#3mk*l^( z+CHyqz0cjTtRBVUH5k3#)n`|rQ&juIaLK36^JmyTt;{oHeq2#1##8cfcPE#&TZUX( zJ0G{lza<~n1VMXW$8h6QgLKHLDFCm)`R^{PkKECJsl{~uiesp)0SH>ah}OJq%0>W*ry?vu%N zU9x7VRNp&gmW>xC&oW8Y?2&$sJFi!BycO<%|CFq`7p`KQ|6JklU?LayhO|5w!%Dst ze%KvZbFlRJ-5pM!30c#HQ%=qQZN1Okku^_3Cn5jW)n`K1JOSvZ_L<#!pSvS#j+Z`j zTzw{F&9Q0wj37*}71;jYmo;Mi9s+F@jK*&h4$bo#zjvIKU`?B=rA{1@KNx*6ZJl9B zb-U zboJhZbX0NN31@h7OI#crO(u*A4w|hqKXTo;E^aORFQy&riz~~R#fqOOrsU5m;-NxO%=H)N*GKn zcc?-vjV<7$VDz7$ZM z>(%*3*lWc3?T5ezO~L1xq@VrDXA;kF+I zi0dre2r9Ocg*%N4FzsYpGZNM8EZpG6S#lThhJrLSx2em>-az!OBeRR=s-1= zr`d-d%hM2bbRo|miEj!GMi%V|xCfbhZj{=Yw>wb*>Mp-Y5-TYH8pADkhm0z2&8cb< z`D8@6uVjSh;cFx!(V3D_$4#+5ureY#D_|SGH-$H`T~eRqwK<__?NCzktrnvIl5hWs zKLp%Ap;qx;XWj8_man=WLLZsUa2WpT^waMUx)qXLX(Zo%f`_U)4i|-2;UN+smQ3j# zp;mc1`F6*tAWfZoTh?vsV3mB!A*M^d<$FoKl>#dHb~7XkHNMjr3>M_9qk~#6%m3CM(V_C?9JIXThV{PoX1`i`$HH#KAS_+X%Ck z9fKy#wMpDbJ3=9^{Iw=&3LR#}8%&v5vGn6f$rZdrlD9(thUU%MdF&Ef7-PV#%K*OE zGx5IA7f5o{g{akz>gkh(Zbnz1MJXLuk8?GT#EoQ!yLtWK6QtJ9l7PQ$hW zc=1|>g0cG0rGjnje0(6PcPLbsBS)9qB+yhjy0Ur8x!;KQ%yP6-b?2fGQ+2tYgQQeG z36=-s1p@k42WI99=wl~hV2tCbbxWSDbVuxJv=?8P810Wc)M!snH(F`^F~HBx%tg`CO_%hpSjF#PE=09ylK} z5lM~2UlI+tITOV_h}}RTchN*4r#9z@ozUuGsir3id1U3V|2>u}cdh&bM;)U<7 zZp2C*Netsyg+F)((zfB>VwE%*o`bhEHuWuIDhwM`5FzXwiMs>;lrX=iF&7N7mO6*G9hq+Kxw&XS^vVLb#YS__#g(~rx(*G^s zR#i}E8kn?2h}PbyfQ;5+N%>`iiEC64kF)^LCS~01)RuEKP!VDZeVd{AltI@>(QVj9cC+v`BI{BJyvsMBg#Zw<{}WVV^lX69Y2E z*22zZJ_36A0*0?dtyw+50pOWDW7AR68gpD<$C&iQom^&t8Nsp$Bb^^?NxT2ZAS4PGvDA5*?tDkh@6kH0VgA zS_qsu3&4=@e(sN`rVjjY!tXRECnf!oxqac84(Ir)dD2b7a2iiIs}T&9qQ~+@X^&9* zTt&^MoOOekf%Hkg-xGdfEvn$ilvGVQU?NRECN(akPg40wR|DzE?*^wy{XLLo{QfYc zd9oEwKo#$cI@8o^U|b42A-={G%N4LA2(2^tE)i=Gyb@1Ply0-+Xj&KJKv%NF0?5xt zp;$i>nraErAZ%$5mfJy^&hc)W4jKq$#O_u{)dK}xsrmVP6BY4OIjl?rPv_ITqA@QxYE z(p!XHZyfJ1wX=N@n1@tfB=`2GD~|`GVdX!jTaik&RY{TdX?R`1l{mmF-KlscQg@La z>70#+^%{=HW3ulimFz2?*5q7YNh$WE`brL{*?NzvD-1mIVR*@YUC?Tl^$BPN=igtX zJZe|KHfYWN_MDWyLzgbjTw45ZK`C9TOLt5zt^IH3NvR`HO5w)se;Wo~$mD-}ij=SY zZ<6V|w>0$Wh2BhGu#`&lHT{z18*);7Pwfj%1IJwq_c2m@O_L|eA#jhGxJ=KLWL}-< z3l&MN-(r-`0!4I|%v`^u_R`KM0Vv6{cbxIRP4O*83rO)TogK-Iz-|xq4otS zV^>+e`K+k3e9MsK+ig4vchk5;maj^d1t%iIm$|*+Lx?Vw)u|G-kmp<24fq#DdRlLE zsxos+yPBtpTT|Rx)+NW_i?pWwchH6pp?8%KqrG_0&_~j%CTlRJ=JQf$ok=Szni5>7 zd#6frHABiL#*^g`MJg*YC_&6vnY`Mn)2p`}U-gmjKvmUo{8(-H@E}3-qASy+^GZ1* zOj|+HdAVLu7NW2E1?IQXVJBKyr9Nnf-J2sx^+@MkDRN$F>7{WAma2AUz;b*|cB@Pq z!gSu+JoKp2a`ipRSf8p%2u)%Yspg7lB8pYP!cI%238PXMie)|OtKQ0Gjtf%5^TBI6 zVOLGDv<4?5A&XWg>}pG46j-BocOEN6DflDPealTJcS5FP5tG zhTPypW$g;hGsM-W@=lHtWG~s4!<^l}A@oli44jreWi|;Jx5ynFI zT!JsT){DbQgc~^n^ zl~RME>rX*ZcS?;OWKWe2B>xu6JaJ?e2A_ay5c#*Z=Rhb+TVhYZLecAlMB?t7;x^SV z#aX2qAqn?#B5{|CJtuKjL6Ywjq>a_9w;^pek{hO2)Y-c%#H?K^VbYw=O6L^m{MV^R z2MtS3+y&b3(azodVjxCc%dR4lW||T>yRc}qtbWV+}@0QT|>@?3ba>Q zyKN>mt9)AI>uR5B1T92_MVllgNJv4_mGsd~^44}DBVV^*1jb}Lk-O4~>a}8V^Mfh9nWaUE zEOs&kxI|bO-46LZIuYBO9&L<8KoyVzt`uDgEiPeR7u=;C({Oewqv6P8=SH6uR4cnH za!7;T_!@+buc|t}&N2#v1!()-+kAJw_ub2Qr*d*t zDz{!e{FSd&PA=i0b8?lJK^LiFkw<_5l~F0!v~j4jnSh#eA>0_^WeY?-yg#t=DtfWi zkxzCG?_Y>?kyso{sN+ zP}-%=BjiAR*35qB`!2lJeFsk2&3^Al>GuP!-|kX65ofIwVc$=6f}~pXl{j?KnfU$y zOsqY}qx{;fbllc1q$XUwk7j`1-KRx8&YbMSos53=m}Pap`GAn$YrV| zo3pJfsO=008P6^~#MkCnjEp0(Po~W$TWHIr?HTxZyCl?7s@dfK4lMoH%5A8FQxxTp zOPxF_ds=oHEo->!7lMs?4MNGsnaC-NHhc~$%QWO^D=;seP%EZh!css^t?kIuUQVbH zWZ5`5wX(TIvGy#Ns`zLt>j017vp6H3Yyg%ysJ|3&)m6iTc(_^BRr`{53%a(3ypRQ2 zS$6_j;l>CRDKcw~2saR#)bSm$Uzk(tIn{1TAHcB)Mb!R8!l)99Dz=UZwX$&$i!gsy zom`-fo|LmG1WV-i9%yEal(t!of~zN6|C^mZD`-`GODq5=E4tzPsq%e+BForD_?;3~ zNg{tX$x_Cqy2_tD1S7}ZXu?u%CP2lPs`F=4t>mvEtz1^J)X=nc;F+yj$;_YSN`QeB z0@m0Y7_1kbCtwkx^Ji11I|7yJW<@xS{Fn7h9trRjK-JK@xbeSjBUS~!XWe;FBGi!yZKyZf<3rP!h9Aa)i0 ziLXx1q?IF)=#-N=PGQfDF$h5Z`4LLg_5+D$?UOO$|2f^`hkKuvQ@YHc=cM!<-qO6R z*;QKQvE-%ZEF|Tzq{(#2oX2v!bew~Z8Aim+*+k6sv83meIPVC23oegiavsa>#9S{0 zf8+k6Qm4;EZ24rxN5N`I?elM^wK~rdeXACdMls~I`IYxS^u~TSk66Oe%K5b8&ONYT6A-y1lwnnAU8l&=?aw*}k z+F#5w^K=$%HB@q%EZXH=1SF-^nX_n*JB;)2WYKnRJ&U$5S-4EQo3rMf<|)VhWK5(z z9o?o)q%GqLK3yU$54p@03lD2CPa^HjJt4Rfn_J`glt`q#4=f=;6qyof$8q45DFffl zT-qm21%S0!jl-yLa%n%|QzDnvhhgAQg+`S~J1hPOem<|{pq&xB_6)MYoKr;*QpAwV zNJ}7t%z3mANv*5X)`B<8EfU|6LeiRdm+elnN6Q4FgkB6NHjQ2Q=MMan-!} zXx@~XdB<*Iy1L`+$WCuYF+s5`Nv-@8niV3Z;KI-@mL}dMd6Q_CGc6V(AsWi>`MS<| z&)v>0H=2*n@A3HZ2Q%~DbKd8i>s)u|I@fs}D?Qnl-qb1DuUhH7eCgg!(H>x>Hcrw$ zfru6E6S(8EoT9B|tDRG{gZbE;Q?%a{qiWkETRoO2`l}T($eepEh~+0iXFBSCdXNYPilZAH%&fCM}x$&Jbx4xQrXu& zrq}hjldG2Xl$fKP1z|WpcFN&jSc`b(!HJca{0DpHyH--?L8~*ZVx4c4)nPQ@d6_n= zb_~@@M-%BW8ZT?vk5?YdVd!8D=D}DIZ`x?~uqIxQRT|CRaB|sBmeqNkOa|~jD%QEY ztWMEr=3BLEs8%|f&r47%&&^ST^{4USv@uGIjC6u=Pa5%s^#-uy3Ha(y`|PSZJ?C>g z%QTT-0V_LquH!l_94g?iMRPHFXSV<~h$6_%5rKMLY4&Jl0?Ib^B722tw&0uVTI&tXUR7lM9XLm|> zk`t>&i=)f#SR0P%^mnXjAKAQEh3jNyK-wM32RI@h#%p=~2G)p}m(jyK}IW?(a+QR9@O=lI&!qUi<>8+H`a1AxdMvTWo2{ zPI7&1cNtS@nfR&|45e^7h}#TXHgKV#KNoZ_wkMvsk_J))P5q&up#oKR_Z(_rx;E-e z+c^1Pb_R3FZhW(~;(--YqsV%a6Y*Vx+FQr;%QlN0UvP-{4r`4xu z@`u)G@)}Ef^BZh^ac?fBuzK?Y_uThJPwCAkXj;A5mQR-s{Uxq$#G~g%H@!B0ip1Jr ztc|?I5yf??I`?(GACmp2*4pJpx7ZBPv-|h03$5EttPX5&8k+Vb2w>PI30Kdk;`cs7 zMVp3dS1{eMjP#E51-v-eQPAwp3-FgU&eC&Pa(7z|-)c4Vh7-iWFx`mU2cEl5iR+2%PN}jD3(vfZJgc_?Zxb&i9!$G9L!8-1YiLGZn(Z;#=HlPRWm@8+I+>gy@gPqFR-mEy{?XmTBL%k@<1)oA0{Xz~^4+`3R5 zrm1J_hY={6T*i;U2FE+T$zeB+1!$|_fk7Hft7$f&j z#XcExZb!!vkA)oZ1c^IbHsm|i)IcC6-K>;(zr`r08D7t%73k(Z({-XyiUCC? zwmqcb$)@cNX?TjGGdbIAHo@iB^V*lT&e*|~NA=U#KNwKdN4lu=9xV_y9>XPC9SkAg zXT~6<_xZ5j(WK=NS5|7Rgi_J(p|)QpZQpp!=;h64!;2=0yOg)a)==JOE%jqR5-s+x4liKg_0+k!X_tcUSDpYDa+z4Lvl>DB$cX`UV}! zVW!HuqY4Y)b;sKEjtF;e=ZH|y9j>R3@OSlUF`q<}I@zG(5N^t{%ggr0uIe@AyMw+l zj_is9>7!MZ>`Bf}7>%60;Bi&GJWkNFdF0CDUf3zw?w=9PykGu{PNHv*XvQE^On}l!lsv)-OmoBC(e+gr7p(EdXv&6 zE?zCe^lj4NWVI82|5D<;@u~Zy1~`UB(wySgBNGetpauhz$W|v-zLV&vP4!DRw5HOg zGI`7Q(LL>EBkd9g&6#(NAY%v?7oK=oGkTWPaZ}A`tI>RNcx#8fEqyqD69uKuOrPoj z=1$f|-1=Gf+?zXZgU*6$G0O^cDzDCY2fI4g$3wT`Vw7$#sRHg1S)m>K| zL=_ckB0``f0Ei>6!p>8h+Yrn$;&#u^>M=@1m$gNV{VKvSHs+o!Qsi(;~yvOuSb#Jd027GUxyf z;;HHKS~9I6g~Jd7UB7eaE|`tw_EaPiEv%l5PU~6o)YgUSD6T@1_a!$reJ%Ai#x0a= zFvis-)N1yXp&D%KD0e*ZJ~2es#0dW*OZs8+PsbgvBA9 zme>(%-l|=u#x^tLcKS&t)LLejnC(O8R>=eIBn-WYsYZ#S#OrWxB#L6`em4A7tzQdF ze|5KN^27$+|4O|R5*JBwm!8yQldO$`^wFZ3yd384q9N|kki04`icjnq$^BIh){>xk zc<5MK)ki=914?~Ao2x~kE?oVvBy3a@Fl*{U0sBM@%0HhLR3MJu{ut&pp# z`vs?TZ^Qtr-vOWIaY!<~f*6c|b(v`GLXBwK4=^gZ8T?m4VYusVQ5#Vda8GW3o9H%A zize;6u&EJ@PviFHfjTEr-ThrZa!BA8OnF+0MGyU?janz;hElciu(K)JLkOf$9IuXE z))d8`k|G(s95;jk6(sZ&*So;B`|}bS>(OW3yQ)5?_;h{V4)qlD%RL2^Lpj|QT|c(&3DM9s~kfX&r4ozLd@ZS%-r zK#oLvoBMIDPBi&A4}87ca=yE&SMg0%zs;vuAZaXMN{1^)X(P-&GM+LmCg$Cn&h?z= zTKBYQq95`T{qu05n^=cx)cd*#2v6Lbwh>((+anycQ~A|7%cn&bPwD3dkGtsx&pPyU z1`Ka*$4B3cGk|?+x9;KyevF;Vs#D_y7W*i%w00q_KFY_5XitGy6Gf~SNMcEVX|E$R2jinr3$NBw_hrQ*jyY<$i zE9B?;WptS5@a3e)sejj1x&D=N_)qw|`u9UVjl(@1-&FFOlK)We72L$T7SQFQ1R~uA z8oFlcpE&LpIH{pV-;c#^Vefkn{UVcycX$5=*H9Ss@(ka=jRXJoGx7{yfVwWug>y(W ziy+pzi8a-Dhe~vB;hsAgg_L=Q(d2uSPB*S7azBV#V9CVOTLbGbGKKC~b7O zoP1)lx~0!$#q(T|6QIVGg<2Et`pwg>Uks0NDc*|fi1Iq@GOzG70B@$ePFvNw8yNXU z^1fw)P*@Z2L-E+ayCThB0c0rgPW5Gzl22lxv-IxYy}pN+N4 zn2n*RYb{iWE;W$RKZNEQ^~hKgn#+idX*F<2WEVW5QBRJw!v=b)A=}d>K;9&OPjhWg zM%#YNrz_J`ljvk&s6jOh@2swN4yA%Er}F-yp?N=RqI;UxX-ya4V|@)Dt3UT0Yi-t( z6Ar2X+rD#QT8HgQ2Fv3(8X;R`kh|`e!e964*FsZ9-Lq+HX7`(kXv8uL-PoIU(1&a_`&HS&Zt=(oun?mlJRD8_27T2PYiI0Lxp{nd8tziB&CWM%Mqee@x~$7M z+Fx68m0d7;3r=pR5q49*{^8R_dldg%g)!F_RLuVHY4_dXtCWAx{Yv<2seW}>C%PX% zxjf?5o$&qS>(ZYfHyaCG*m; zhY;>z3RZFAQ3r2}_eXtF&ODLsijO*Ba@YPfcQ|Dcv@C6})w;*tQ=~53t574uc_V)| zt+6X>0JbqiRe$CpWRQ@sJMic9IcraG2X@0*f0*TD_uu-Qj6rz(A-_VSBYEE!O+&UVLM&LJ_hF9R^hBVv=bC%HXPjF~FbNi=06v`s%lEFR@spTS+hh#cihU6XYRO37g`Jv*4orqcmZ%H8i5X_k*V-~P446!BK$|z627OSd$Pur+jxA#|Id+xM8)kZ!xEcu2Q5Xp{BdkgccNq<-&% zZtvJi?|ss377OjIq1z4!;U?&IGV>bJ?JorE@^pIu=8I>NpU}G5P^9o?9e`}Z+*Isd z#FG=S@^UY)Nj2Vu*rwL+^^^NIZrq`Upm?gD{70dnhMWD!Ubt*-9Lge1o*Xh70LOvj z%h$TlkK?_>dJ#V!B6j!kHNR|b*$z51EDahv5Mk~kOEu0xe$@~2hhfXq%0~5zH+kBj~8*@o5Cx0%>?Fu=Y8?xJ5>1RJyQu?aOr7gqrIani} z`6(5OGCWVy+CFh_MXVq)JOK*|8Z5~Zke`+f(M64b%W$H1jC;jkO`{G>SUjb!Fo(5n z4joz##O*zGjnzWsc1RZ8vSv0Xo3p}rwz!?m$>F3Oml>Oit%BX6izG^elnp!DmV=lu zwaaED`LK@dE9At6$V!`&!}-CsxLG-z4TCt{EyQRzBi*?AMNJq7GaPHs=eie9b;-Vp zi0M>~#526f%CW{~WNsc&HfNGvwG>^{EKn-e+{yrkoHGBOq@Z@M!aYF4m`*|aIDWKs z^~MwN89Yx)e;gZO4{BMULt)C}TN0`I;CK>Wq<7X2ce3j-Wbw=nyU1Qiyzq_&wa4D% zMlNDcZ3378=VwIAkYIp|sF?$^6B=)q==^H#TW@DeZAh@A*r<9v`WZUZFy1;_DvL(7 z%+s5EMzZf!0lU=69#*VwL^CHyn)Z|`t)}EY>m7;2k&)~GQp+<3{DJNLqVp$Jw@+Xzi|2&(^3QYME{y4y#Gd1sE9x|+ zqw!VIdxJ(alSdGBAXQhItuj~=_iSlG`d!%VV~92YevMDGas6b?A83yM`bdtEkmoC9>6C^ zIAkY9U}KN!73XnfY|!{9m9qD+L`W@8aT}(k5h<$x=4bz&<7e%$!d=%s0iiS2Srs&Z z>$cM&ja^NV(My^mJgPQu1zsl?e1Be{`VDo5R5yLGwWYJFiKJNuQX8G$uf3XK>Eh&P z8MugzEs966~Dh2`5F`8YiVr^zTyC^ou3uSxh!K4LUh{w!LS6 z-V^8ujoKvOEhuEA{cpGnyWM{p~oHox^kDuFto_D4vdEQeD zEH*QJ_@VmEH3R!BMWE6+Th;4R+&i!fRn#~5i*D+?1^KKbR?ilD?9M7V6`P*V$5px+ zlWVzDGZ~}QhHZZTiGo~I9cypeMY%rHgMK5L-4&`eG}#{65d^NFIlLz!JLw_W$v?sqc_r-5}y+ZFu!9bgxPf|_#glJHc zcxClIPp6OnJebd`(^n1~svj_)XaLGH+2V~utJg3G*wUdA4oe4~&HQEW|Cjh|hM1&r zh6-yP{;6yklgt*AG!E{HX|Vy0Q^7{;ns~4Js*hkGqHQ}%fxc4{ZTpwXl=2Vx%Jplj z7jy4|0*BZIfTgDT=e76^#m`Lcb`#C7%EZ59p%avP) zUgJ;FT@n)+wcIN_+Y}4c)0$Z5t5PVQg|LZ{FI+u2pa`PVxQhIBo733J)|OR-aI($22C-~UoT+B^ zC$r{_t?IEq*@=DbUJ2zzWrIB8(iKN~V^(U;?-q{Pe%bgYPc>~Y$D1OfW z4?>|c*D+Dv9fdP%P;|;eB+uS$r7!oTckR8jo!hwDN+0D*=fnub@Al_5zG|iRqLf>4 z;VA1Qv<^pPWABL*{0YIba~uEr`nznZhx4O+U%8or6Vn`N}V;Y6qv#1 zQs0TBmKXMhD2SaB;Sq0bWJAr@UZfJ+{LI5>poLRQl;T$s4QOq-4mMa2ZQCBU4UVhX z@Bs6~zPt9AM|Gs0U2~6g#9L3W?`t|9l6;SJWcJ5Ox5#NdXyD?8NN~y8F>6xIcV7J+ zMI>S~x+WOMrGRF}HZp~vtw2_*X#ZmHg&MC*rb+Q%Xb-BrP#1) z-+6aqZoNsCG>Uqdor~~vztkDKwYvL(^n_^8GT6C#7n(0pg^FvcDnH^`IXStjy22S(h>W!yWXw4|Uff7{9N4J`I;2GO`5wQk82 zh)?Wnrkt4}>4w$nmpBj|2=%g0VL;-U+qQ)ZZTVT7YTm%#a28m1D0!Rm`S8nMGzYeX z(Msur2+UdnL9&UqzF}=0uz79udwDb4@(XG=F8OX6)&>qe#52ok5N}q4{H-?KoRwFJ zyUn_e0ou4Yaekm#a&5{oG1*&JsMS@dA&pR$oHa+$(PWl`1&UT|`5J5a%Uj&?rGMMp zmfTUd4YJ@z0;z3_7#w zhI&Mfho@q%>fpYpJT!X~Y!=U)sTSo5p!c;5H!`DfHeeD(RcuC$x+2;GE3JMU?fc<7 z5%5xEVfR&=B!PK0le4>7!?^*r$}}aQMcI&GYE4-Xl6IMMb!~9E!7+dZSR7*);t!4% z*ZqYKNTt-k1F5MsQhTwi<)o&T6?C5ZI=PyKTEk$%joH!g3|YdLaC$*Wf}-lr?o+4`MY6zx2BOieD!v5_%rWSLQtbMi{^ zF5;c3#<{I6b4^L!<&>m+g1nN%GT&u%nOng!&&4vM{k-a%XViACl2qSqyhSr_G`4=f z<(1zeOj*!8FQ<&i^x;*}bn^=Tj%B=~CVe!#JE0Er9O%k}NOrgXyi3B*Ji3pj6K}a_ znHEtq`9%bvej8egsJ3t8{PkiglA(Iw&To%zr`G?bg`p~;IA35@(EZw5&n=KUm78J8 z-f~YClv@SMJ=u+Ypit-jSXFi5+TX+3zl`;IJabrNvu1zCe==z>6#o4Zraq{zNh}$x zsn@ue-a0x|C01tAz4|Jd^jFqZRcXeVZOmNj)Y_{5qm%wfck!fuJ_<}}`MjgDgZetw z6ydz@g^k<7dB1esrsiEvayaj=Zlihk@%qYhJxU=1?=!Pyq;nO- z2v=DkKq;&CdOgTA0+AC2qPV0f3CZ`}(xJ_5l1iOc zNgob-kcC&K77z-l1+NpfearDigJ_|h21PuHH%~WBE~P_Ydcro+_+B$)PgvV4ZxEwU z>(3YQ#xk}|^Ex5%MAch=&NXdHF+|v~3z?-|^^IA)^*S935zmaMD%A^?k!ps4C04m@ zSe;Yqx%i|hp&krOiSy4b0r%gWnf%LQ&MPcnjx#x{4Ri{aILycxJ!%B6tLk zitOf-z8E8d(nhN3i$AnqbbhD_v2*8kWF#90Yu$#{u!CC&OC;Mag4nGP zFS_Jh`&0hV@8DEgdAAZWoJ+}Yx4kBRoToO%mN1-tk+nm2FHUB0f@ zlNRy}K?i)0)1gf&9%Pxl(fP+k6!04~tbNvr8l8`RW}jy*OX#z+X%I&c^cSL&aD^d) z%DIXrA1(;bJ6E5JN;ZAkDri0rY#nQFZJA!xyc>GjwN{Xy5Mi5;x3Cqa<6^lZQ2AN> zzRYEDpsWctKsLH*!fzobO+~XJlM+QRvKZ7tddLcWNb$cj} z8wlNSWT3Nqh1bPTp{QB^z9V^j$j_vSWH8D}r1|LYu_@9rw0+jq^fP+hza)n8$K<6W zg9webU)mjAqNc%( z%0=Q<7C$OuJH$h==pinT-0o!YGB}PtsmXuHTC5)@89WRb)U7Ug0n|jP4>arE;^<{v z3Eve8;O)G}1aK;q^y1S%QY{FeR8>I$^+qRvdhQRrdaqx54m|`=!5$Mp9XBZ!Ks&w~ z3gF4CPxAt(zjy&u?X40(wYE6|Xk%tJKc+zS<_Mso-Uy(*zfS?|S}6gva(xQmP!m8? zwq5{t`==K`dsrfXqK9jod8j0SFDs_s*oy$_eI|hFRfz!p9_eucxMN-bBYf*a07J^X zgvd((-@+9S1@H>J&IHiKQE)vi+vO+(GoIP?tw0KJAYqsFfYo#Vla)!b)LdDng>~F$1~Gtg8F5n`G!nVh0#p2I+H8bIiRdg z(P)mbYD0RAX8E(_qmid;bMwq2`qSZH^%!_4qvTKdW1Q(pL*)O=LCgZadfEB0>hzq? z=RA`hhv(>Kco}x17nH%Dz`gOzC2OGy4Q$jBvy=`YHk9oeTxO*Y^QE8Yy|nEb9BHLL z>Pz2IR=NmfaHthr^`^~!5f%KfA9#s@z^K*Qg$?%*b|@V=e?IdWM(I%o|KvkgUw*T| z(%X8PdJA_*#d$SrP0uG$AYM&|uP9^)qS)jn{}8UCSM zy667bv7S~%+kOP(j*iGr=hGp`B;R3i>v0jv0SFzkQfG3KDm$#CF}Bc%CY4)Nxj$89 z{h8?dlVz8Se)|6CDgBv3D7LylqFq->ek&0_LVM^QxCk*0XzX*D3#RhXlZv! z-QAd;C)dSB zcWR{^ZM&K(E?UQ)Ve&16eC#asDw=!)BDXG7S83r@`*EoKNIomkv|*72d`Y@-HgFdj zq&)6$X4J+7T4C6n7KmV|C^pLcad_hphSu^z$RU=>pwXW1xUc!KBG&jLd&`DFWL*;? zAzMPi0C0$e)<;7mEa{Skd~33Q)-u6vPbVm1gvdNC+HC@n@OGFx71obv@@s@{ym^D;C%b*EMF^&wH@E7V9 z-V%q)Y^@UBwXW)N|6tPW!K|eOO&C7Y0&h<}^U#EflBkoX@Y%g;>?|>TG^u@`)`f@i zy(*ggzIX{L8`1()7A9c{aft{^7_a;j-4Q0?@zkpp$0>fA=L(d-$tqFM6sA4%c%>nE zn~~{IQ>X{kxxa02%zp|T(nC{>ZCu{8-Pp#b0U>0y%~e+>#r)zmG^V~7B;gF^}@Wi%^k!~VGz)otlQ3@ZXjPT^nj7jT@cUBNsQML!#=HOQ)K9LB-a9;pF?+bm!QFqVe)9?-LYA=Ht84O{|a{)$^ZLxso#n?4=tNn{~Qt_34D~-;sU3N>jNOlU5 zm+lw*h09*9PuDXb4gttXrPYpuIP{U~eOS+P{`0SjR0Bq4o|Hp4Opd3l$K_=Sm>kVd z@NDuphvU>U1*rE|IhbbRe7ZBsexdtLf`x*#{W6@x6-)RnoI@#u5a-YgNZYV&^Eiik zP=n1X#yLz|N7BR8465O3R71*aX&yf?bjW%@9Xbs@W=&IM%#!9W2T8rd-Ak(uAH@ZFy+JuWv&`f;Kz>E9-B?_Rxkk6mw96LN}D>l->++nN1zL$qN6dRVUCfuihvCdHBs0l zz41Ky;_lUzL-YeAT%=4oQhLWB>7EvmQU+I~Z0FM)2M2y=BT`ukw0un);L{i)(Hs77vPJQLgyRj#{auH3AbymQ}+%#yc=@eu`?3NeL zNnwWv@y@(>j_T3jIn+{zujA8o*kc_2DNokk0N{E;9DYxmmIVPb1>9oscp)7 zjM2^EYp2bx^;9!WCY!T8J?yF4q(69CG}#aP$<{r7Mmw!{-5d(-(9}zafM@duBmI)M zxY0W+P(ap52SzgPq-ZfJZZR^MQy-f6il=)FSS$FxiScrR%yi_=Dk=rTT1JGg8 z*xYXQPMOM)4%*d?u1p72_ZYLVw?$DcVjRDe10A}Hpbu1kdqEED$v9vAeG%gTb!emu zu}wqPZ$jX`D^Ln`DD-Rb!(=ya%?}q*u){IJv2;h>K9bMScRbQFN4;l`zPjAgcl@cg zg2LGb@37)*FGj3AuRr*f>*PI-r1BW^)BH!*$uvdO$t0h}kcU}89?p_7=RB9G^K$2L ztVzjqQdnTE30$4H!y$K3s-!$_Q0jFEV}YSH-L zeoo`=stDwB+WpKM7>TpZdh+KJ@UU^;w4PANf+uT#Mui4ldeLRmE?vl(7MFfg2(<*k zdbX;4zD#v0^6SJu0j~rA@n{+*GL^bdoEB7%TIbP=BR9BMRN^1iZh_!9I_+-Dou!q5 zcirg3IAI69D%l+=T_qFvDukBx6fxZ|j(5MekN$WfMr7d9QGs|4cnKRQi z!P0c!5kICSy!p_P6r3nBfkwv~Ja_1L4^+dKebR-g0v86HrGZzk9y_R({;I&JjaArVW6zQ6F0eR6ae)}hECi+`0C@W~;Fj`k-X6{5J zi%8`?= z?t3Zx^$-2>P>i!^?gj_ND5dGh2NWYi+>74^0`8$0NAX)^e%{TkTN+1`7oktPY|9)m|ggo1SIQtJOa zeA|1!;a47$akYMtn&)2JJs+jlX*$o)2Hznr5zll!9U%wu%KtVhVHC>wLe|JS9`0=KDfr zyd4qPY#RPe>j>}3oTrM#G#n2@$1{VT_)sMG2lQmiX;><`yJF6_MshDg8a5%h4{6Ea z2{m5Di_iuKBgyg1tLzkg2pVn*9eKZWx_-{q(P0M=4Yi!V7MtCAe(y*3oHq^uZ?Rbb%H%o=&S_eNU&!*+0Ns@yyMS8Ijzfge^p6 z+~YU&dTY@IpT4z-YoYq z>V44d)*pNTbbHHm;FfzHzl7H}LAMRKmm%F+RXn8IDe!7M^XWfqJ>7nF@B5(J+28*F z=(h15y=2Sjb{Rsr3A!!SlHc>&5h@xKJW13c??Ky5X2JD9-s4?c*bG2Uy*Ja_XtubOJ`-MhX=PYhE5hv{lq4_% z!b>_+34TFodaa|}=H$BepxjoswmEsOJz8U)h6H0ki3mp$A~9-+mUvwNLU4oXGr83$ zcm%Du{9T7>Nq~f4p3;&9X{nQ!OAO$ zT*H_gq+Fx$WW-;KU+Gu9yg#@ML}j%fY&qzW?Cg7K+z=QSukR-i#t=4g2t8wan2mIS zIq)B+4S`G>oSG2HT}GUU2b3T@7?!Zy!Z4=28x|*?$$`e=5E+HW7`cxl16A&rX>1V4 z2@aBrh_FsW9QL3HSP_)*TtzSeWt`9(DC5mPrLJH>JSbzj?pH;qjF!U)6}hqb zV}TBE@Tr+<-%uH|4`5p{Zj$1h20M`CmQOg?r%GLumHz6i$J1|5w6?C|%;NcjNhH^N@kc*xrVKSb%gSR;_M!z#6 zB*xibMlt2=d-$0Y7zM%DK{qmu;E@ml-eUoM?o3A(=GhM5Ge8_>q$BV8M?u4k5Vj1+iM{y?Of9`Hj;v52)fJjQn6G0vcSq`1;#%Hc5*b0rN< z)crKYOYj&GO8kqqR7)#(jF7EuL~MrSldBj@A@zzO8QUG2p1br)D54yzpTP_WB!+ji zqT_1Qb#ZrNFip#D;#N!-*>0E%uPo+l^oWM(i{I`?(rjA6U_)l)+`Et&TdlX~mF)04 z-UXRae-{p#a4Yq#Jr0`^P39}jI|AL@DRpDiVHgh9>b=_2g&wp>gU=-G#7>b^kV&tBA}v8wK1G znbF?#I?HYj_!=^!y01CNuGiYA7{2osv5SxyXYi#rWX7GOMK^`aINc*Ng85+Zp6v|B zF;cqje(}=cm-}fd({*F|H)tknDIgw_`(+GWla2ixUg`v$azyiNY^Je*=L>^Ef*s+D zIRWVKf@*{t;FduQE@X-oD4ES?3M2kU=TfC4t;RFOT+*>%ih=MQHkg#SH(Twi;gr zm{F*Vz&l+UDYl3usEnK!S((Rv%7W4eM5BNiKM+(#ba7sF%kzG90{ zzVtTbrTrW&$rNq=Am#T;N3;N%m%(U-MFgcjR+r z-@I8O;ei(;vkEr22zgP4K%h&)Y?U=~Ff*t)r5(Uw*E6ovTf$ycHb-!2tp@-5|E00_ za8CRI_ev1FM$l?{r3xRDAK*hZr&+H;P493Q5zivn#pVr6ZuT^+1Nwgfyz6ozbf8nJ zE}Ze=6P(!-l^kFzBdk{i*hRlGa_g-gZN0HjZ7sZi^V%9QZ}Zz4R@9cQ_l9KKtg&Ng zjA4t1^Kg=gfQOSTEH)iqFT1_(CQbTB+vqB^_z`RIFY~vg#fjH%UW?d~o-m6)en|BE z77cC*%;H&_HHSyIQL>nZc0+VZuEqFeUu*O2`)m$v8J})JahrzV5Ut}O1MD0J5A_DK znB7qtB#&+x;&-miLmYT?%M(ukD{*pm0Tw8pX`@k~{7sMsmjf&U(rog`lwx!=;WD^* zgI<4?u<>#Qy0whLJ=+Aj;=g}MQHQSh+_i{TXLje=PTGC}e}?}1uGYc7&Qk}kbk2L; zf07FM;Mb9#1G0yEV}Xo}!@jgsC_M+bm2)d6Z442tx}{yvI{rtkLi)+hJ^rW$wbrwv1;yX}LdF-@; zEH|(ao=ww&q_jB{yEp^7NbI%Q6W@yHZUQ>(F~tGAEj?DnOE4BceZOY=&3nsMP2tT6 z0O%oxUhpsBHuS{O*3=Sa-LS0q%M$K^n5iHbV}6^3dTI^eiW{TtX|Dppr2=FIHCiE< zp_*X|nmdKIH9BPX;wW8u`Y^k{K`J5SjK!WaXeF9tl~T|O|1C_tP%+Hxp%_BnCxq4u zp%$HLj%06~2BjUc-Wf$~(%6Gdw91~4R}Q!S#PJ9rkP@&(cm%~RdtR;_zAt91%p)FN zPuc3BayS)f&npLqwRq;HG{kIH>><+(QT<{K@g`gp&pdojk%lM(TJ#Jvo>eXkBVI8@ z!Oa{njKsSygvHrf>oC){V%gy*(g(LXZ86jMBV-M*7VE%Tob8Tb=9R{#`JxhF`KIAF zd(j)l6odmprU>yCL#DVYDW))ueO7@f$`yw=qF^q*OSC4hHDvFd2M}tFx}I929oFlW zBdqZkia6p+sDw>ujhk7Sg$(cs6)({mZ@?1xzjLKE4B^dUEkazho4sHBp+%YmxCz?g z{)V%-js<2OXVHZK4WuAkRt>nC5u}?S5$;cRz|C+D<^_Pai$ygID|b~h$0-M`Ca(gW zCeSyWB^k`Ue@uN#U4GFWI9I;3%X-Ed2?o*Qy%F=18ZvA}yqPPd)WBAB+0?NaS58PR zac@X;)S?0sOR9-C+KY^jT^cqZe#&MxbVUUbSpccq`|&cAVB!AjW0*-CB`b{5OV=f} zs_Jip2w~osdyN2>Ai|imTC51|CORlO2v*>65s$@)W94#y{iQA0@$DYj&4Z?~vuQV@ zw|+;)H6#6L#&xVED_?y1f|f5G9fg>GSfpg^nh2i$%CY0EfJvTvTF~oSRz3) z#MTDpU)l0{b9m@AV(b~*K;du<1+C}+AJdV?3M*7OUUnvidj~{J)N2|vLj_7)EvryQwbN`UDXXH^n^9!>5mD4*K7`99q~)Qs;mc6}0+X z0;I+3v@sOoD~2$qiW)ibiDai;0iBcfgc+R1S^U)75MO&qw05sjs_ z*n%2AQ#`zYtZ2g^XqYnYLp%l>4x*Pm!&IcwO|vC?<9s$dvUg}|3BZaaf@k8d-A}zu zlVv(0d|N1ZNAo5Vyl@21D(;WqsUyXLr{4v^)3R@qg6E>cCiaAKdV!_kXp17vrpqJdlBov2K`w~1|GlcuqW1-^(uk)(B;Hgo= zGE9CT3D z-KprMWxQM=dbEC)q-A`|@f6@Pt>r<>qqNYaR=rW;x-Z%zR3K+WM~EpYrCpnyeG5(M zDy`)~FS1Mue!{U#=ywS<-B33SIs8sa+5>lbHxpggC_GHuY9l_o27fkX@9>@l1TR~Eilj~ zbY%$zNu#iifgDq3u$c}de&&|?4ZebBVHv;r-T!*<0ppS-Pz z7Eb5LHtDKw?xQ5QEORAmqkyv+C-Dy4l0CVZUNR#EebZ5@Y#yRkugd1)ttZb;H*AVL zlAa<~F(s(Z6m(5TC0+Bv^>B>*vLb6W@=j4{{SUX6N(VN*A1Y<((N;21x3*gP6sWDF z((%PqD%_ghpG9mu^Z2dol%NrCFy-)1Y@riwE7|Rpv6pQ4w$HHj6wmy)wDjQe(!;H^ z;Yi z4PS-@*I>5!GCa73#UNiso|Y-1(=`@at`4r5V}FbU*RXj{shZ##wxRekD7c1=h+vUU0`2mR^cvdw!^;A>{9zev&-xY&6ej@@VqL!kQHe>lez^yLVPY`P1IK= z#`RYE6kqzt-b-61#@DR$zP|J)%1RgET#vSb5eiCy6xc64$%Og|R2H>nKCW_U%j&<-DjY%u zZGuZ{ARBLJ6_Ln#l~J12uXxEAtF#T3^1GWL?Z_(PkC$9L5nHNRy5xM`hf_poZ$4hk z*yiD>uBQFcTpu38XCF`r(1Ww?pNdbJ<)U~ z6Q}kp4MNLGE6ja$i((n-a8br$T{o|Y+0g}jYcz@5wd5fx{vkRMG|bz0tY0!}y=YX* z?Sm0*Z_EUhdy`sBXL8@648a#S(tWkr%-qEAjNP1<DCzvEY%Ca2-pX$yY_}X3}vP0f1!2sR|NdfDp_Jp>;_N8xC*`HE3df&bF*fZ@7f9i}qTb28&XHl#7UFwNNZ%4+%nYSAow#C-QGtb;; zIt)=T1MMA#XU?Uu(p);L^9-RD{GW<-eq6DR>9ZeMwezV~q|f$X63CjXsLy)dzkG_l z;?ruGiT(GK9{me>-?({SEB*HOTpRLqSDAkjje}`@9 zjhpwum3G`*@H*4>uCJ;^(~D-HW|(he2enG=$LUsjL}}?WE0;EUf7U9zb3+Nee?>on zL=D%0RXP<01JoEVZal6=N5xzZ$fEinQTNf^y(_W*N{h(mhuq@kobUQzsfq&pkjF@# z+ooE?nuQW68=d_DtD1P`8`nFD{OH&Fmfvq#=`p_aYv=S@+T{08E4{rh{XltXFTWqN zQh&Qn@+&DQwnp2;dzatyE_U+EJ>!3KazVaZ%d*MYWk_H=Gm{tQ4HGU5$+6fW*>c%{ zA?d_Cu*YPNI93oFDl3J=XV;$LoY8T3m{_QwMw{kK`fK9}{f3W#y`RTNLstchiW zaqxy=x*k0?)S_99GCMlEV5v6ZE41UmNvHBpzs4LbtW0!f>^Cxe4ep6UW@`CORnuq? zfc7l{rsl$QI`7>%dCNy>am)Fnr5E^My21N&KT5r2-EU$}Df4N{$iy6q<&zY9`rL)Z ziD#P9o1oAAmFV;I>5e`_QvU_|?5dT3`pc{fl&L_Uech8SpwEaaH%*^`lu>)TlU?oT zGdUX&EaU#y>G_;*b8PbIh$&q$kKbqvW0UOM8cX@V|9?ajJ81C2w|I3Y+riu%8;n0j zxJ46>$AJ$fo+SR8c&ZMFO*{ifB$#-1D)wkF@m!e2?gs|wmTkr5>Bc$ol}X7^9=P`U zVJK~Q#isMk`~q0&a0v)a2;uqLu;!?a4Z)SO7MN?Z=AK~UfwcVA6T!sMiCi_!lME9~ z9A`ZkZ#_8NdT@mG;AmP6j-Q2?%#1ENa3`J9s2i63_0{j{cDFH|(Y81}GsGSm+g8#M z8=g9bbfI>!@OLSvNsCQ~sc#g!PjyfHq}^E6^hKES0Ap&w#P{P2xZPSCu2GDJQ?#0j z)x?)->0H9vozz~^{U*1YZSbDkntO2BF5ft&Wp*^ts=m3NRQaAX(i0Ep_4-xTxdNcq z#k}kshZlJy_fT@|gUXD$pN8@e!aqpN+OXr#vUY$wzXJ^VP}aOxl|vx%5YWreE$@?@r{%By)0hCp_VJ=Eama zPeFk&5q1XiVQPznpFHQ?Ds5#B^>p>+3#W?n?1T4|m z5xY0I)*=w(!Cq?-2pIHQi$K7m*IEPuHoev&5OC_X7J-0SukEn+JQ`eU5eOLOT8lt< z-W_CreL79@gz@g3Dcg`PuTs$|` z&>l=|VwDg~oT^OTiC0R#u5Go(>3*Aiq5JLjh3-$cFLdAHHi+A`7PnFNEp8Kg8pgki z`~_ot*JpTtJ_^F~{xsfD#QS#|?{i3N0Y%0BHasLCp=tTHd*~$~Q9%M`kf0c< zbwo#%E@898BtXQdECFpjB%nQ-&=?E-(SEP`W5@jRa_~3zv>*rHhA+SA@l7n-y`5sWy9%=v&pdjq1i}XARIyC?y(wuQOnDD&oc-Kac^Ag-JD5~7 zFhxlhri1@Lv9!nT=!$8=aW&@F`olBnhPx6VbrWgex^DjG_HI{W0X0NIvOuNL=;u$} zle|WYw&{L(!G->mPe;Z}*oD6%m^gUd;m1_hG@V6A;SM`3N>rpYgwnyONbPn}Q>zVa zh-9D9S|E0>fyeTkj)c&??!@3;>Hr#ufh1aH_m5sHctF1Oi?-d)Yxow4wrPM)0eNNf zFO&@f5f?y^yF`r_+@k^`oWYbd7C9WySBEX{b=a9WHjT>`&{i?B>0psLV?9P+Ylb|x z;u2YA+KD8FbwB46;GMjG4%!gB;K%iKx*W-lXFQaBHqSap&Mzq6H) zJskfro~doascjk56_c_o<~b;5Jhvh{d8%X66|&CI^Dusk>0-4oT}C4r<(_z^%Tz_% z_V-Np$&l%yZ6+TLL&r2Mb*7N3+8W3QSx$ndW5f%kV|Plu5wf8`*%^a~4PwJ_`y=FR z@0asq>{7@+5V8Mw*QAK1UtOGof=YEJVoR%YU-Hy$ILUh5{O2xtFIC+u@Q}vDmNt#% z1WaPvh-HcP;GeR)3_a6)3LOBbP6)l_0HoUG8AbGJ^BN1ujCGTz=gF;wx zb$V=U$kpxI3#sj%<}fb>Zm!7|MD->xFYBZ=v?Yl!&c=abns3*rXzZy*(#B@a$Eel!(2a%h(Flo%eTfDsS&9N0YiV+ttq9%~!|4I$fh_5SBU| z9D6$VNxlWKS0P5KZd#%P=l<2)Z^$;&IwrpABx3>F4s2eZ=r}h!4_=OETDek6H?_f@ z@*VS+QM`97tT3xe!VJNNevMyg`<2{4Gh&vJ_yO(?3MQlAeT>>@oad1G{p`n4mZEnf z8Z7yy>hsPE+(W0t7V0T_><|p1Mm3yIBR&x8d>y;c?qEo)GsQkQsL@3ZIr~Av(t!h0 zYg*sgtLXyI#vkF$L0X5jrNVadx>;&MGvG8^YR%{+uo0(+wvFhzg5xwHekzH54f5Vh z_g^&=@yTu)U(+1x9aY_bppshdGVppmO06Cji?+q+)VQxi+rGeOdg8<5Mn|VT&BW_0 z@QuU1^xj68vwFqGl|fo$OmqENJu5-}XC*i{s6R;_Y&|Q%c|rXd@?h)F)(WxyT&>Sy zgBd~{@70!yWek)0lIYM*1U)953p-iEpIjy>-97|5kwB zpq^FV%%J{ofH8u4R(-by^{o2lbd#WLU9|hfg8BkZ z*I()Hr-`?!kB-OV61$XPst56Q`+m536qk8&ci#nZbHN?Zb=k z?j?h-we!5`;I~93()HV>lCO%a&C3G2jf5zvwvp_iV+f1dIM0ggb_HsbK16zQgHAk#o7yH`&OTCH7)I2BWRzt7&&gr{n8(!QhhHmKzxYOrC*zVZjzzR&Hfr!MgJ&kOT9Vtz+(EH2T6>gwk0p@3HD|KKhw zzNX!sCxGoJ<9pUBdP}zl1&JAKg)pD$72h=fVjE4YUXL!#F1m>KJFA+YDQ!b~wRN4| zZ7V(F$VdrCus)b7P7FDF+qF|75t^2@jLCi^1_4oUG`nM-a&k>eOFR;5SN?p zPU{453u4$wo*=%!o?Bji+(H?4#2|=w*z+r`?oxdRIVZl%zO?0jEiGV7(($~ z$&2iUEs^A!=4mbY6|E(_6w0d;`KO{aSDRtQ-{!@RUmJ&T?^bF;ZSEXBa}LY+3-a9B zt3?~PUDNjTjms8uBV5e@)UoEMY?iyTBeyfpB`Uu<+S#*L;m|Jit17pCJ&ifhc#3e* zrp)KKZM$zsJc1WLIJI5wA=UL_UYnX#E82~(bJ+g5I+M9R6y{kp?>Rs{Np#fZe*X@B zUKc5LGVZ(P=IQ;;`@ruwTN@HB8}fH3W}H9tM}JF4r`^(lyycyj1E`>-+EMu3Zs!W6 zZ+oP_A{Z0Tw0zt4_Dnk?x>707=-tUQb6Nq5F|5;Kb&jl9=aGtaY@ctURr?6liuP3> zVT}|dhI8*jrF}kHEZLXoZ?AZ~+3m};e7Q&e!qPHH*=KOi*#GsVztVeY+n4#7m7d~D z?@?ab@5{ukR0E}Y?#p~j8~9F@oyQmXasgMC+ww-Rkvj_ z)3eVYe11G>8-ZoyDK5?W&-F>RP|~d)6vk7d7=>e^{CKSH!B)3_Uv(cnyR0sw3$yvw z6RU}5mQE=j-Bbu&Iy&Eqx15q^nUGUUbi!gQo%W@_*?Vcz2{&5l(|zeLl$9P{h-{s21wT(g%jU}qm(S+w ze;PbSkm#th=v}BG$|61ddG2v2iJX(Up%fKc&Spb59Es_Hjp%UlKQ1oO1K(q3tz62i z^b=P4hoz;@u3Xx*^c<^j0Tqh0^q$h{iK!K{UzE-FO{;V;l{PP%?~Vz)&t>y1K;^h> zzELil5A4GVw{s;rBVjThZlBBNBfDu?&wRc~>_A~QiXiSx8Ck%zo2(yJ;mwOJneRb0 zrG!3w6I&NcZ81$@E??xs%jMfw4#NP;=IhxRrSe5`S5PFM%6BH4s^X6CTK~}=DDNW{Eh56rjVohI(6CqEA(q;DJEDS_Ev)_eI z7I#y~q||>1OPhT@$VylH(*GjKpqJ7nivz9nQ{Qs$UR++<+vk_j;_=Mglydx9oHy~9 zaYki~vr%6u*ypLXr~}Uopd!NG9;b*S8V_Z!vDbf@*R!EPwEA35+d=d8#{1hF=6m+Z z{_apG?Jr`!oG{-=&S8926@F%4S$y;P>oT9kwBu9U-vS*5&yBrP#knyUI# zUWbd>ydGJ?YPy@cI|*-hKgsUR{I1y3zH|J#pFQ&2iN>F*`#bccnDa%v=)BE0Z}Tt~ zSMf~r0@Gb(j>4hRjiuaTb)r`1`EORLvwg)nrpH#Wwuoo$q*{?4J4NnN;_2w-d7HEB z6<<@!c*D1i>(RdwZvKXqKERj0r1#Rs&10<)uA0?`)-BI=>P(Z`2HhwxrD4 zJd4#$xwqMcA&F;hgA=)8vV>lPw}O1=)JVb@8woH=1ZSdUfRp=WGl5hrJNKLTcbnS zi|tK*?>NHAZ;vd#e)hsYeti>JY8A8iK0C&lrHS|sA9xnu9(p-C|2#&eeU3tw+KKLo z->Kc4EWRYWKB$I1v-rM78MSvgt2b#bpT+kICMTY`=bTN@r(zc0j-wrY_Qqs>;Pk21 z%jxftZcn&~J_oxeTR@+4j^8wW>M5i4zKRdx=rcL{JI>I=GdG-FmO2vipv)EWMl6@g z5=Gwlyoh31e4WY$?JCLQo5bGDL%}5WZaRWV?AJ(DZm~nvEQqW+R8D*~nQg_?#wJ z_xC4g7_-MjZrViR-j6A0`=ist#J%g?6F*OznYi~`R&=m(Ng{~b<@AYrnxlg>SL{H= zW{!!?o^qK_G2FeV2ew1|cy^F`lzQ7b(e_Bw`D~S*?sjO$GfGh>E8(#b7V`8O+WiHj zmZx{KiY-3Tt%M4BdR)*treP+@Nm&b6TdJOr4PAG?PfIryrRu$WtmCh@@$p0cI)~L& zJTvM{@t5M&&W&b=Z8LK9Za7fgwp_ihYi$F6mFDVAn`6H4++do8yxAn2X7O(J38z`G z8(x@Zk#5*wnuWRHh-nt%h99Sexq8z&>^+YL(_CnKc`(gF+gqQj_tVeOb;qaCB#4|i zKzG8ccZtj=GymFdoOFStYtqHq;+)i^EzU_(wZ%E=bHCQ>3QPw2JsB(bg{NEF;epq>RmpoaR1W2c#i+Lds^W5q7>DMZr~#Gn-Vh{ zbaOr<&yo=Hd{0K+G?jb=SyKd{kda4<>zIZ%`2NWP-*@Htz9>c2lJat_AT*Y0){>#! zAuI2E%n948k=FZ5^Cl^nc2SBUo;3 zJjP{2^~lgWph44LDMQbhjLGT@8G7uhy9~V;i^Yl=ddh*0_(AQKA3{DuZ#(y>kfXA- z8G3tIk4qJEn4xzc2ClaZJp?^WzS4H5OVqJ;kYtjBAqNa8w+3uZC<47}S*hTiRGijOZm6^FI&481r4 zuUT2)GxRRuw-`|QEoA7`4a=VHo_GdShTbU8fV+nb7;Q^S2Uu2IG!fT#U42V!xGo}Q zWJ+orLw-H{lV&MoO2?2Y%qwkc(H)r0-u@*vH29ef8)T0cg{}EJ`Oj>Ge06+-7Y_G9n>GSF3itses#)d<>$4mN|CVG z=rZ$u9Yo@y_z_1D@8x!_7&&>1d24Dt=afmwYkpNJc~6iIH@2CSJQ;adP}*@9iE3#| zUVk3JZFw~iZM%S1Nia_4(cLnwgHr-78i?^LAu?o3(Zpi(Vi%9=ZfEUTe3mRV-)3|cVRG$(t zUZIiFQSHm4;!!nSh|_hJ8%;f?4}>H^anH+yYe6`E9LH6enKyzl^|{1>?7aqBR=2Gx?i1> z9i+acPZsCgy`*vO=J=txDCe##;VO1nu7QT{dSuLC-CXB?_LkH?`n=J z%DxkM)0}Kj_8tGTf+HX9B+G|m1xG#{D>(Au&bE9wvhU_V2sG`MWZzBy^t&5#J86h% zYi*Y0qmY1SAg;>6Gx$}d;klF)GVzj@k3uq@^J>Y*Gw;+=@>+9Ki(Y2ARLaV8U&zW+ zQk7-pS^kBx@{}{B_w!kK z2kN;aiZWcZ$aO(FQW9%(e;0iVS$RwKv-z&TF|yCf(?iEISTzOnblzc$v+{l-GXFfx z$`c1NPwyuyuL+6E5w>AvVEp_+WaahoqRq_8b8q+nv+~4~mX&8KUS;L^^tLc7&-b}v zR^A3x-mI*=y|w8;#?*Go*zK=eAeSgql$H0oC9s(W8$Pi_jmWpLeIs~-!|tf)FhTDD zm-LpNrF>7_UB{fKW9-e&^WtarRv9OPKO| zmwk6BzZR)T9${r%THew2-QpEK<=3U<9dFMqYT?uVI_y2C+ViFM-KG64v+qj#%Uvjn zD>+Y8N*kNO3|p6+cM*=72(-VFNsqSVJmdL%a^C1da^94~N|;vmoH@c?hPmcNnR(T{ zWai~aag){iG^~gT$K}dr=KYaB5h~YTx7}n*+jh^)r{&F3MRO#AV@S(etvOd(-deGT zONH%&rOu-JWodbjC@s&KV4Q%0?akew-s7x1@EzHB>nWxJ$rvola>mo$gV6wlmOvCi)**0Ei?Ut6`Ss8+OVchD%> zNUYk-UDAu}6=T&h^Yg#sd-ShlmsD}-cxDG*`ikC5+b+w_R{Es|_wI)B(telab%I3k z%mb9_xy$lrZHxD^OZtWVSSOX`-}Ze`F1UL?mt8cz&|?LdRaN|?qY1X zXOz;q4_n=!uet}8*BzdB-?Ob&{b;I}W))VI3}Rr~iR*K0Y^NqEfgpbklg}v}@40^g zYR1!4rvqw(?Qq%U2}$6Y0)Vdy2rq+`j6sSE0@gez`)`6l@yz0*tSjX5lpdkv4&XZX zsz`Rq=fwrJmRMv_9%oH`f`er@cnq20N?-}IiICswpUZtWm8ryVSDya&$y#HjA9POWO8<( z)qCnl>ak$5xehpg^bxzs`IMkqrmQ7{QngMr zn6Qw_rg`tM;ulezISx6{D}h7z$qQ6Tor|o_*ot+wFRL>gCUiv4j<#wM^$e^{cp6@Z z#Ocdwvdz2EQex>2EKE5%Gf-4qa-b1DG^#vO`Rot$xTkEj;Vh}vsVM%iuO&S9ASQ?V zzmIS{H%kGQ(#)H%wDDZpN`KXt{zmVmjpt6c(j$E7G3BMb&K_f>wxN_8Y4OhZ@67WU zlvr7fyIYpol7gb;I{S6nK>ts&SqpXc%3bq=%IiPlzlW_f*O(S-_+M8pZ94lpt8g+E zigfl)pW*e1nk~@Tlk7D+yLLnU;gy_cu}2H+lJB$W`|YjnvlFe)mFvzZuM4k*xzdlq z5An=ws+a2Qqg5wAh)`$meQ<9&d%EAmj<81Ye6^)IyWYC8gX>D4I{V@M>D>QOoqYuy z8qZ9MIr;f_xnH8`JZ%HQ8Zr54u+ks%rMr4BZSu3bmF_;=z5AB3(nUIZ9Ra6!W(fsN zXNSBP>g?;GpLF)KX8XJ}_0-v;_b%w{xl;4!jbWs-*!+e%JFuosR8tjo_MV4$VJp+w zldazFst2g#jdsIoRq&DEh_$J@_ERcq?4ed=)nQb*(XMjsTVua*q=>MP;ypF?z6`BQ zubGx#XmwH*>%6^JX`LdCeXUhHPCYBv*psD)6B~*(cI|#V;@pv6289|s_gTHahd1;& z^p7b2a}uK~YV2*T@npKe{LGh*^W4`qE<)!_oo<~75|CC}>tmBGDb-(KLGO7`uDw!*jmh0_Z zr>MmqKGB2ad2i<5Y{;Hsbv|9O&a{ek%+e0CYO4>W+lAH9z*_p7Sh<<2(U*xHkpImq zptH`}|;Qi~XJ@1dQn@Q!np^B$U&KF>-YR9bpu<OxL9Ngd zSJpbue}Ky_=q(apv;77J1N%3w5{INeo$qXDQ=I*?I;o0vzFJnN*#23yqX&H#yZY>fIQc}wE5Sp^uE4y(0gg)>I1Cw#zWk@Pb(`u zys$ps&I$u*7RaBCff9N< z?k4#kw8LFm!T~LWI{Z8+3_mn6|N zJ8o<`XKeFbP1`17_g0gD(0x07_^nE%k661py7-t4$tSP+9Q`eSwu7+ExJva@CAnn+ zDCA+UT8Vdbzao10ESrn;V4)g0w!*tdR(SWo1?qshl7H)G^pb4RTR)};wA-Vz6<;{2 zBPT4hq8I)dp(}aeGCj}>7pZYZpIQ@+pKB#oq}CJ>WMFE2uDbMnsq*(t)q_rsJ;7Tq z;A*g|)VRV128bAMp0FX=arG-jJ({EnPcYA^&hlcvD;oGv6`NP!)b(UmasKyUlT z(jZzaG$#(#^=RY?iBnJfND(LQ^Oobq>W%PO;|gxw>3^K##Z=1zh8rBSwtBe|iVH}1 zWZR)NQvD!N(Abgah}vz${Nf@WYY*nHk#L0VeM|{13oaeWMQ-jUCGHZ_MQ*yeNAN1P z&nr{|Rj3=5-J1#~MEv$<=C2IaI8Qv?u_5(@c(+6BT*G8OG-h$Cp`&RO-Acqds)K$= z4liP{!<=%Mac+!TIHt4D_4 z`7rf2lAHBT(HlM`1}S=Q^j$TpJbzFn3-?W1P4z@5cpm!U|5mJXa9N!q3wNhg zyO?S{R(N|1h7Mt1o`81ZRBxm$Jh$f_;;|l!y$!f@rHefdY39wl)yz>untPP&E@@FP z>`z%tx?_Vwc!(Soc_t;6>EEbs;@<~4>+vs{;Xa~xT~_)=UwU!xrOh(kVx`aVrEe@N zU1XUqwu0j*SkW?V>&JI27OD@+^lKdB&@$~UV}|zl(E)k?0O=xfyp1*W!~w<$p{TUO z+!Z~tXJI$if2E~Qu3XwYvY%RoOQ}%gk?o_EZDRH2#rce1Pq){MaP696D7cR!7*g3B zS)CD9=dI6G;_9~JmW-7k#ZBs?|s)kXXc!l$%V8& z-}8T-f1mG@yf_SdVW^utE!J-yp4Epq>al)k|z z{f~sw7P+sGf}>DS(C&1`%sK1921pT2Acj#B($KjPPhlbwny<)g;q1PE` zaNrJmbXiKAaatnINB~)JO!YCAFF;ltAHBy9wd`VC%BGVcjKWxdwIGYz*@kXu)W;7v z4AUh@1c-GBEn}R>vl81ovHkW=P8>QE#&eM#Y|tkl5ST#!@(|GTm8FMu{P2!4&=seG z>!~qToTR_9LVFl1&doV2X2DqZ!4mny(@v%A;R4GltrFlohOr354QU7;ZIP|~{SYFp z7qAs1Y0ZA+_6<6Ts>+rFL8NN|aqI?)oB&7)Tp4*n`S9)LR)Qs0h_4g#P#lwr8QnAu z#9`^y8K;D%BQX;0vfI;(niT-Y%#+X$qk_O7G+;oh`A3jcWoM|A#|P%Tdm{=g{`Z>9^lDx*hWrK9k@89NeD)f-Ut{&3CUR2GNl z2~%0A8mTirWu2Q6>R7DQSgCdtswJVSe_&#3UCM^%p%kTcg0Qr6{yqu7}ZVcM+AO;Y+?qx8}3mlo^t zb1CgMN`KSO-nPZM93=&}o!pLfSp-zVq5P1`@wFS zbG&Ywmc(94q?f~`mnyp254e|$y3osJ7$$#sVLrz)4$^esy=}pg)h&)4)rDSOgaz@3Z;@VBb&F$*3358&*l6h`TY6azIDO#rLj2lU zFI!IGSYAAd9NWzUum>z-I^D#bjAf4WGFp1s+^w<9>q0Mmq?au}<5;G5Yb?24=;dV? zA%A#|^s=>Ey)5D8w-b(ykzV>pFLSyj$>X}v%U0-kfB5AS$+6`K#vb_Wf6X0xCu5l_ zy^N7wMt6&2)m`W%M|#S=NiP>kFRQw>_HXY(FGoo)+m7d0YP%)L{kzc1 zV!&hMKbKyXcWYjj5ny$~v9Z$2QPRuH-IB41UFbyz0QH9#4y}0SmSC!rvCNZR z#!4?O-J1RRUFd~=KYv*7&#^Rii(|)kp_e7_v-!jGq?fF2t(WE8_NC&OGnku4_qIMk z`Z!kl7}#+i;)F|hwG0auR1}K$$exmz>_|m%hdzY$8V&MPOxNhAFc&8?{=Y&)1{C7xg19) zNHV#PF0PLcfCByDKT98-;K*+G@muNREa{^Y6xr=QdP*N_k0!4=!I0hV<4K@Q#J{DF zP7q|b`#4Yf=q-JCJGQ#r?&Dv;e*W+?N0C>ZVASM3y0|`ONgu`1M<)n1xsNWckHe*p zPy2Bko#4~tKDxL*UIezp{#W|w1f6!fk1^6mAL*kLY})NUwgK@0|Kin%PBCM*`%JUECwQ^jeGs?$!?#NxouI|!KDxL*CP^R1OCOzJ#pFJ^xIVT6 z=lR1c`jA(hAjRZ9y0||6D1H1w`sf5F9%vup@s#^q`atPr$B`UK$LI$xbGjjWzy~?A z49A237mFNP_T4b*Zi@pl*gQ4d;K&;R^r)YK(@4PvMgS0trQ>wDhD-=Zce__h&wwkl z2p?aLuGFJEYl;{C(xcBRU-419_KDZ@a70wapJ}0Z7SOLhTr3oKteXyuV%`zf{RmUo zC>~v(lH$Tdim%8hm5r}m8v2d^N-+@(m!A3bcWzbe2wEcJlX&YSc`69i+(}MBi zzJL?yWaKA=#9Z1!B%%Dz|zPb`kLov29Z#?IDQs|8|Cv88 z@oWirTG9ia*7U#)8`Dv5zUK>M#5z{<=!Kq^N|5sj8lCeByYrgA1<+qXZN2C7H1w(= zgUx-lc*A6Xrv;rF9p>Xovu`W9MU!k#^*X1wwBtZkFw66KVAWvbXqnu1{-_ru664Q` zHnW_&n)kmkigXoq#K8yzV;4&yrzV`riZGct&oVMI`x=~E@rNHhoczsI6K_m;-R>U9 zxMR+G>)cBagCoB=^}+r52q~HeF|m`gO};VlJi;^)dpyoP7Lre9zh~X%9{DRlaS*fb z&=`J_pD_8`1FLe4$v3GxL#S&zjMR;=&ps}AngWof_2G>X#2*op^K1>4>0m9U0B`@f zLyJJNR<<=X^nzenQ_$CF5dwGh1M)|`u&kwW4h7+6tr9QqH5r+;1K(wcR5Vj6GCVCA zIIDy_Ju%Vv0JTGo^R%*0G)Gopy1V-C_z;(m<_skxjTwO(nkXk|Pl?L$TAB2T`B+C$ zc|@id_qO<(`_9X_Sjt3PK28H|S{cP9zig{1F*wZD5*qO`D6tC6F`DDm!pyk5d`x-y zIIwDjRbDRWK@H~84vVf)^1}QAA}L@Cj4!+81Cykx82 zi#U@%{HrWS+9o{H=j*SfZJMf6;%1@NiYH{9d(-hv2l>@ufwkUZm zWK-$V^H2x-ctq|hnOB@Ud84wb2>w_ro`#Cichs5Oftsg(oT?w8jB)C&;T48HY4ksCx;P)*rt05OOO{-2ya!VAS1)4wynk&hSk* zKLwSoO$xMRVP)s;^5mr91QUY!^F6z~z35MPo4zoN3+6im36i&r!OHTqQuXXD zQtBzN*Xf9zTF?j@rN9l2m904T1g^Lexbg)Ct6>c5lbF&R_&PnX zr8TfJ8^fz4N79@5yeqpPKO$9?JJY;>B|o%LcR1y{R+<&P(-FuK+hev*SNQ@ya9-2-F z3)Amar$d?`FYfAlz$Bav;Hep$a*>yW@vjSC)AZdRVV#x3MnP6aIUVzR$l02qc^GJ7 z*3EG7m?)osQzzH~K|D&&F;L>b zTa<>xt;Q;~NZeO;iQ9~YkAe&LJHX?*?;IJP%@jOP3JQ0FxL&Ow$M+GEBrlK_Jzs$U zC4;1bG8mzhneAi*HfPp-mm$)a*viLz^p}b96m5>k5d3Unm>b=kjp4lv1iPJ*nmi-D zWkw*b+tcwJqmo#P>*r&F<$B<2M_^A8=yg}`rM&LJoZQ>NoLsrloD*%7KPwoYlBDV5 zlw8d{j5#F>Wl9EOAR1=`*ev4UjFh$Hm+5ttIs`t|tbE1_kocygNwG*g9-y(z2nF9S zU0^;U4$Mbci|^yA%I#_11z-_0OO7^b9$p;5A2q!7M=6)dKpo5lrZxlffg*T_%hCcA z7g$_O34cH84j`G{#z#Wd8Lz21VgCoS78Eez;Xv4l$NIc>f0h8 z{^^K)SR)@Ei+`w<57)&%yd)oR#@B4)FY@6>oboXm4atXw*ax@dvy+b@%f~A)4*7VA z<>OfMV?WEsLi6KiFbb*@cTJx8@oCFPxB2mU%g4RogmhG3`S_*zaTip9*(M(Zmy&N; zKE7#w3|KxsV}88A@^OLr(QWxS$NczDh_%_#HRi{MEgvVSkKXIdQX`EI=a?Uc7}aV{ z!Vg+t2LfbO!_wR}Irz0c4W|p~j3mN%0e~~oLkeAqh#(62-jo82;IP1*C=h)P84y$x zzB}cw^l|X7zi0JX;H4HAg;1aLF$up)Av%Xyh#W+6JoS?Dzux>O3?iLnSx zL(M|;&a=?nEF|w`2PP`!xNG(zVVaDNVFDJqo`tqDjas19?5@@y-LTM)9 z(1)rJ<4r8|DhsWYLRXsI{lzRq_Yw<*SZKZ!8f+4NrCEsHO%}SAg~m#u#pbk}Y!;$> zl7)WGLh{UKz-6|y1G(6QnLH)HLdUYur_9h6Xf+96VHRSLpM~}SI7Xh6LetFd=9`5W zg<_#~EHpz3c}+e|Fbgq^#6mBz&M4a@HVbV-jx#0WMoU+* zP&2-k>(4w3p=z_C~v3M2Tr`>wGsytz#XL(=O6%l)bQfmnMb;pr14u% zm5kO%iY2L{+s5TZx2A4sfYDMv)lxsU1c={JLxx4+j>D3{L&MI)AD*19&V-%`b=A(9 zQ0VJ4eX5ksH%cQ9tG%>wSNUuym4Q-Ppa^ngy{mk}_h6EFt}`L?z#UumS??;_===iP z2;6^8>l&S}Nol`Px;;AYl2VtWlot3CWW-A6t=rqD^Rv&}r*pWpnb}1;50TOzwPlFN zwnyhz2XX9+P)Z97O`!9`f45KP*&Wb%ueA9qqvy`%{VFM4&;!n?(TF7Z#b49(e>ljS2lp!u9t1$xj{E`}r0I`J>FbQr z8{klmm!3SSVCNCCFoVe-mAh{xZfSP9kp?ELvy@>L&4YKT5aL}8QVjS^Mm^f z8)hD+Wxs-5*7^91Plfd}zN>lHcM{HgAcfGVS6$3wjXwqUA3WZ&)*Wa75y|1N^of- z!EwC35Oloi`?X>^UUg|@4XvDyLhjS%EN~Un8keAVtsyhhr8_thTH&)8wSZUWF?@$U z8+MvBz>VRZ=YqpOu=`-R7-qd@ofF44&?>VYy^FNxQJ_$%*nwF*NI&QU#p}xNFk$}= z*6Tw*!v~x_Z~9@MarT@ZE!^lk1Hi~1Zu=n>?{9;-OvQWRB)or`vd)FJI^zG9(vPAv zF0`XpllKk9&Rj4EY3g|+-NDPVlCG3bWa^{7GR9+0&WFhSO1F7^!P+3WJ<=I+rD0;S zf~^TtQ)}EmuXJsH5luRnl@<&y+bkPjrZgq<*MUJutXsVnU5cOk6HXR5#46|FNBvcl zFze&C3z_$rQRyC3LR`kPkq7d@{IfwD++Gewi#Ae(8Q(gciUgOvJkEN@IdCC;5}Y&N zg>Xz@&%wd6PiEZ*y}{w@M`78-hF)Lq*}zRbloIIjwBkqc0hqF}X)PKJ$T6;RC(6p} z43rw$^`aeU$stVCSHTHD>e)^Zt*#eB|MDTL%L%PAR9_#jPI*+-b5KLCu~x@JH5k>)`Y*H9In!E_}O_{Kp-9{(EkQYYLaz|wcQ5t?n1U1xDVD> zGVN&r!H>K=j=EqT%Uok=Aqqi{4NO|-B`v&6AcWi4lCF>a3s^PU(N9z@keB-3tSyMQ z5YM$@cI!SSC1zfSo*{fi-w#JHw@3qur5=z?3-4T!;o#V6*j|imAX~k}+A5yCQXIR1 zZ9+ekH=#D5qm^mAR;5q*6b1NKIYI^bW<<|ue!8Xk9WVj0VdKpi)%>B-d?N;H;5(*( z=7cE6t5d&$mIFRT@TRO$+U1KWimQjI=DFtd`>o9jR~P+@HOGNw3|(>61+EITHMzPP zB5uy?B}pyZBrWteL?u%T2zIv5Y)G}xL>dkwtq5pAS{u?$!KW4^OAOuk7Uoe4$Pp?E zaDz>Ni!9`<`j3TQGN3K=q6M7BB!C>*tJ%rf-x?p#yrdQ$mlpIyL6hyA$&%%&1+HJc z2rW?EU_kY@0r5VaF`yPeNlZSr9w-zWjWI(vs>VcWzvt>SH6&Vm2eH&vnNf)DtasUp zoMfU}cqi5n)k3~yP%o%fVrpTPsD%fmx*Sp>S69WWL&(2|3Be?buKK;TI^OnDQaB%b zKVAk5Tx6_b?lMFz{P8{f1?4PiK{lFH3-_pYMg00$+m+cG$~FVJ*rXY1L3XkB*&1hQ zVI3DZng!p}aJ3H$cl!pmu#hLWt!hEG%;szzs#*{R-(zh-sRf;C;qTIpdAAK}L1*jL zU&hsfI6EwAVd=NRvB8vq5!P05{Zesk65FI&K$eSIV~i%#L@m_FTHs$vzg;a{W@&yC z*RVNkWXDj=?^@61mui8$cGSXITge;licu^AK8DBFDd%+69Rh+5byc2ri;>$X*7Q433eZeTmbkvLZu96!DJEaua8Ve9e(*#T8^Q}x5E%}d_Eh(4iwp-f4dGJ(CqCP zLa?E#azmQ8m1|_yhq6P!m-T6QC8?|#OAxB#GdddZiz_esNwA@y7ICP$=(oX!=$p~K zD1nM^p+xj8^|$CE;-@Bd_zWw`kI}yx73W94)yf-D3!}b+f5tD_dC_Y1XLt2g@a;vv zjy@TEoP;%`MSjB%_eK}+*ZMR$tHB@NNsBP|KYv`67CDz5!7}78BDq6^+}a4^^=7k& zvX!r;id-}%iOWf1hLE^Ca;c^8=kV}FzvhL0A#*czd->7`-w`m|TOmavyYWxtd;EuV zyq*?$jlX|k{JtbD@-%)l_K|SZO9I+IKqdIYlUfC+BifcCzqxIHT*=MU0_tgQrdH0_uG%WtS%7HoIv)1GHl}P{M&K!~$%c#+f;$AbNqR!u-N>lkZr9a_}h+zRcCYHi+AV%4xZD%Rj{F^rsv1!K~phw9KG6HUu5 zGlr2V)brTlqFS&@2stL!A_)1Jv}l6lp2koJNd+x~EXr?@v@irpBe{jG&7_GSnfBCd zfy@w`%ofnke(t&!HLFqW^bWMr@T9a5gU7KudEP92Fz3EZ|YV)2MYYZ$Z zm&Qy)Y-JHj$@J;P&?y#H5g*H(fmM^G<;T@P6I%XZH3w?q;gl_38jZC~7K$U*VBwG4 zRxip+ISEfl%S6P9EEG^|u<%W3q0wZaZ5n?iEtrVdoCJl7<9wSfEle|Muu0?%@5Ce$ zt3-gX$&_NLwl(GKZ^Onlj(yFJId}oV#^BSWg)DO^*hqg$S|IjK9K66^WAH0rD6~ae z%{6HweeK#9>4JAjx3QS+kZJ?Xj&0R`fQ2&zj3Xw-HAg&7s?AB++o~0@Y8)o9tyIG@ z>BnksK4(hLDOS0B>wPlH#IaWC(O15W7S+<_vN3TimrVoV)FKy{lf3Y*mljPRYqCBd za5m0?8fjrl$`&XnkvSdBh#LuOL-`1xzBiw`qh)=C8 zP<{lW8iUV}7HU(H{uLNwu{ngL=3;7s>mD|hj|kEM2G#!OulKdJ272NYaWl=Zw&)SG z2?O1i;vtq5{t1dg-Ea1{1%1uNS@Xl-nC_D*-$igGeJ{S|1`oFbY4rR}%)%>DXya~e zQ7+VEs>T;S%Ep^IyRw25OJIbr2`6AOik;d7G&+xisKF-1Jl2VmG@$lgD97jyb&N6- zQV6WMExI+jCAt|ueS)7iM%PEzMb}1~qaQ?@qVGi;@$;(a%4ltL1%6%@T^d~yT^xNi z`ZB!bk_2S{`iMS7lt;AnJfOEfeDgN(P#eBuN&MknQr7z6<{D3y?{GQnTG@KgtZk+% znBL{UPzVk|zT<8Je9VmL;rSJM*hlW6)Wij@koLsY;7XZ}BPqf4Z!plHRqEeA<9!yc z1bAN5mr?U@I$h@>-+KJ%P8`HRKoB{tTBv1CAxh-2)mH7I`L1Bu)_qKmxYg#@&R>Eu z+}tMkwV!}sklV_y9XSoC*ckgu&=>Ikf61{kDIs1Rl~*;LIQONZ5Ev7ZS1HeyxCHZ- zqcOg`xi$JPg?0HvoSZzgcFtkHw_7)qU(|HAs4d*ew8&Gj;Z zB8PCb_AP)-h@g0s?b6AyZ5T}_doWXGpJOrKr;o!j~ z*rH_+V%aL0E5#4Q?hluJLEcU=wG8em7{HO!6Y^{zGtS?%uZ^2j-$_gmml@oPthZV* zpCk%2a-BHz8>sRTJ~xxeGI0~+1vyC3HGu(Xr2`T_L+gp&bLnR{aN3<(Uz~==K(tZA z5OoQ9n%sZv4+V#hP>13RkmqDZWnC+M6}*P2!EDYZqVY8H$76wsxIWV}M(@z@SSC)t zH)ur&xx1_D(b@3QTzB9t{D9CqVnk(4g=Nh%e;3%_=DjBPZ=9odFIl6N=Ik6bF1^36 z+`XcX1XIIe3?Lt!I`v%c94c1@Jk9Cs@Z8t;sjQ|5z|O}ghH)|Lv6tMLv(=9L^Fu2spGcwar}qtx`&0kJ!Hgg*pz6UrNPKqoY%mW zU?mP|dzvCV=%lpa5g?R$b`T7TnrS4Fy+pqcP~RV(_PI*CxU0y+#5ne&#Rj2 zOY`+32m7NnQZfL0l=&sz`VwEd=60_r@nRtOJL4l12_BM02((EXxdXo;s)f5b4*Ueg z*BEjPqtH+W`{6theDCyTz!QQC6z<^ejFCIEvQ=791uoQJFm%b|Z_wRs6NW&jChWi} z8ty@7NCJ)jdHbc5-B%dpEMG^GsmiII{{r>Qe6qpaJkJ@dH~)rf52WQbq9=^30ZPK; z@%NYLLtxtc;eDTx$AcR@I{So8cQ2{TLIcWX)3~FBZ_omdFZxcvqxHD=m9U(S1xYwi z8f+D<%_EjvN~D5qf?@Dm@Wx7fIibx+7*y?5QsG{*7qbZ86;wt~R1G;!2b*vugq>GG zeGT{EZ!PZoRziS-8@!I{wcfKR%YCRn*81kj*=0HB7x@Kc%}%8f%L)uXx*GSVT1c5d z5)6}+p_3@lcKIg(kDgABx~zQ$H)!Qs3(NIWZ@v?Kp6b0lxEK8|iQI~w$WKJ4*&^Sd zS0_xsMSU%RIo`ke6sE`+5xZH1ZZH+@6}4QZ>>CyJ^S}xmtihXeG$w|1Tp$fhMFWAB zi#pVI-vQ}~zQcK6`+8K`?lxjcYP*Zn{6N*klkCY9;pz}Y7^4tv#|ugzPv2ROiqKQg z)LEv^bDBD@PX{{h+?O#-=$&%-NDZBLG8t^@yxDU^2f3?PfoG!b-oy_O0o;9RDlBiF zc|A4I)m%X4>!xY_!Cg2+I}F=wbV{A4Pl1M&G|m)~ET!-cp~6E3 zHPLquVr`Ac;|ZqLc9mUOGvAF}NoDufc9q@nU_O+c(OTpjrRjiusg{}||B7k4d~9>L z3P&PtX|6(Oy1zqN`opt6NulW;gx0RAq^8?L?sTH*LXH{$!Zag`W3smUooKs?1a0>{ ztrN9f1+<;kO=Y(thh{sqvYYc?DZ5p0#U&`ak#BUU?2gBu$>x6{3@IxqmWW#&p{nS)#*>e!grwO&H^pDV6j7#ZxF7d#X zhFnm~jfR#h(2C{+q1qt5e~0uAhj$m@=augJ>Zs>dL(jcy>N$@NG&?W22M6Li(Q|iW z5In-=10|+_x&X0rY;wl$(WyH_cQ&}|`{lWc&kMtI8i zg`Kc_;J;*o^#dVn1$^cptW*(J^`;^$2ZSl^8|M~p1A_F2F9dZMISyDt`UErV9Mz*& zf9rF7`ne1Dwc!Q7Z=_HLa>9SdZ@LoCu7j%LyBB_snk6Jbxm_&RNjU?hEds+fTN}CSL-POxV4LIsS|s*OL!%>M@?I> z=Q1vJUj{G=J{RDI7(Eh>(`#U01sN`tzaND44YcVPLK3GxORb^K)!{URIQ05Q-wVNm zj=w%BilIOJ8FbTNN{kY&=-ueg)5=%J!ohGeb3ru3Rs_vVR?RbUuMrm_6 z3gH4u4Pu{8-_=MwxHFh(nWde+QcTgVdNq)9eEoy1>ajHY%@m@QXW_w!M&dj!br_GZ zz6cc-Z7^r1fAkgeM^|(~!f1u_`afZO{NX3ofijG;jnKy~qqeid&r0c;M(H)S(wMcW z*rOS5<}lhl1q zFM|P51EaIk&7XG`Wu^Nv_3dQJTl(`)Ln$@rTiJ%{h5jCL?Is3n8ln-dpg@a-!e(q5 z{NYDFOhMuMV5m@dsM#ARQIv9tn){l18Y~P=t}d&arlk0^jwvo8#jojmo)U^rR}{yZ zMg1Fz#6bD$3{5mdKTo2(k5Im4Z3@bdFeyJwmN@o)YLzDw-zzooGdR8NvpWDh2I5C3 z;(hoH?6wmBD!@F6-;1R~;=y&kAOs{i4Vv2@9t^4jEkG3uEqmsv;Fv;^&tm1_G3Nal zGj?$6>#n{CFy6hS#5>>fJg|)B&2(wi!>Uk<-Uud`-&J3P-+a9S+i*ATar_9Qqm4SJ zLc8;vD*P6j*w+DwUsJ0Uggnje`>^3<8UxQ$K=N|%KyV0T@F}Q^9LOOyV9(>nYz@8; zXsEVHKp^YjSl~m>cnQT*i|F+#7_VcH{ysKvi0>N!+VM?p!qzxlbkPIUg^i@IT4)P; z9w()W#HBU0ATa281T-$!@RuPZR9O@FIhUJs5yl|{J!#X*AJ;sO&@56sCvhQ}gf7P6 zRS>#3G68^JKZSGMH?js`pCtDOUkEMMza4ia^o=~gtpLPtI=5q)vdcY37M$_3EV$mf z9}p^%##YaM5>s5SPsazmpA_Q-ns@;xx7fjdAdSI#CBcRi@SKf5{Ih0C0W!zq=uymb zG8t4VDOd;s#f_!ispcBDESvdl0*ux<)|tgQA!Mn?sgpWv$m#8B41T~#u9^+M34Qx& zuyEK#R>TMESsW^BcCQ%c1tY;{d6x+j4hGVjnxh!sNC_dA!EErHGpK|Ck^nXBM zio){P@F5B>0*7}Z3K~^*qkbQR1{1@}dSv~7c;d~@dcyERL)Z0u6_xJQ-+o;9zWWvO zJ>D_upNWpi_e!iM3*XDJ`nCX&BLDFRitl(ks}i0R$bNR-e9znBxY`I>6#HL@v462* z|4w)Hn$+y4oCV7lcFz9azGY$m%Q5yZjkLNiGV2H17Jw+ri7So_4 zaj{6E#T;B6GY5Z7HV5Y>ngbE!)aD>qUX2GeLO3>F5G;R$Qb)A`0fe6YtBe@FSbWab zSg=u4g3<>RMyg$^Tug0D<=Sn-Q!%-~fF8x>p%a0;1zOi`8~$Xo4MOjqK(CmGA;I$d zK)$hFgk&qZR9G-u%RxVnZiC!EY327(Jiy+zNf=X%>X@PMP^CNQQR^FdJ;6}C0H=lN zbM71Am0fD9(sxkUzFO!SJ;yK=7&K8$Co2|A6AcCyj3F&& z0wMat>F)_tu!zd?Aat=QDvK#9CxBojDood;Y(^X(Y)Y-PUIzNWvw@u}t=E>u#|^+z zuJl%sS38|HgBSvqnx>d00|6y`cur(S2@Kg!S3Fc?%z#j0QYo;-R(ZK$WvB8o1{{L| zy9APj3F~Vpu*KZ1*{8&6K)C;f0-O71nUB}0BRuhrF&{g45DfD%f`-JL4?%BFLSZ8R zWusxY7i0Bq!s>P8ZJH`mqCW&m60LW9Cfc#yU7m?S@HLteSiTVEW0Pm8dqpvVA1}*f zC|jLPJ|oi*UcJWJpe@hB7wAL-$|1c%D(2gH(2B@vCyVucy09Ac^_V7$^*)=wW{Tsi zFbOzi>Z73*!Tj`xg!$)CN0!Bz4}@|vIwteqrWJ`>kB@*$vh{B?as8pbGr zk1Iilp{13kmATpp^Mm)_QBIJy6=Qu58r3W@l9#w%zD~Vfx{R@EupcmI2^b5?wG6W~ z-K+I7G<_MD2bKUL&%j$;7P-*1{W(!wC}j(kswLRsqf$^*OR>^0o1DhBas5-zpB;S- z0jlj}{tf|$F@Jp^?U=vb#^NFWJ6JsPpOg6;`Jl|-E%+?~eZ3BZ$@y!;N-*coK)qK& zyZggK-Z55>bw+*-A`W=nba_U;2ROIPNHqzTXedfbW073|ZDq8~D}% z-?QMK!n%3)e&Kr${FcD?^U*Q+eg}<7Y~5IP`rDu@k^eNDykCX~P2UV^I04>U;6}YX z7MiOd6oajyDC!S9$PFhhpxXnR@4!c!-~fo#x5o1y1!Z_j)gJXzd%}7A({pgvJr(_o zMs+&|)9(Jex1R9~j4D%4=x^MI(KhJY;rK|{f}aMexCOr%Ydxj^U_G=u@ZZX0ejvE& z(pO_Xgdqb!@g5`GIj#bceDFd}^_>Ddz{pi1KVE}txMO~(L5DzDG&vAF%kV6(z>*Nu zIxL>r?RcU2+d84ya<1!mli2f3uECkiGbqNJ(Sk8ScH8(N2qqwAooW((q}fyFq3PSv zzgdRg?Fs4PQERfci3K2X*(oTkfKK*@MgU_*&GR2!In1W8j7HQ!mBeGoE4wW=fv zD{-&CxFS@pYrHwhsYm-fWJfo(?M!>yc=#!FB&XuWxP?w)xP(ib(bv>op(1tw3ZOy1 z47wNjA8Ij?22j~qgl=*Ez>=aB2>?e|&`com0>`zlF$nDKX%6`|27Rl5*mI)v9vqs*wN{N$CyH!g&AGUi!~TrRmFtbCZY282-{9mukObwVNHm?OIQs zvlufSxz;kZ3E2?j;pWMRY=i={>NC@A6I!2{W>&JDb@HR*=s#iQ^$ibD^+n$>s0FtY z&MX`&6ny;_m~T0=kcDjp)}lJI;Lz9n8NWi2{*BvnTU<|W>6@Ny2uhm%K9n!=-=aa* zcn~!WhRKSN7!K~DKP#nX8l?(IrDChGTcO?YhcCh3aS{SN2D9elq!;%oaEHTFgtl*m z##C0m79DGDoCivI8YoNRktWOPmUtdqv74L5D7k8+n8$o7^iV zdAS;}9i~r!$7RgpL2?ESqG&*3oDvcj@i5YO5RwX^Hm@)dej&yQxz%riBEd>E&RGo; z)qzt*oE_5-z5=i>Zu!~NV8C^Ad8dHF=RSrxU#9O2VXEr&)9@P{YOxkk|95DS`gJia zg4%~*_OQZzO#>jmFKBZgGn2Cro<8PT6p2Q_{Mwh8k~z4fIy?bU}Jl&^BHDCO*$ zGb&*{Ob8|m7@9$KxH0Lkz}B-CK9X1nKtB;#xiIf63qImJ9gcmW!cgjVx(OV54feZO zTE<-CWmyi;4tdrBP|94l$}{(=tm#XT7`QTUw)9(;t4?Ub-o% zbPRb=^*t?hZbBWXoqU8=mWc}NcZNnd zy+;Q2_g=;o={>k$ZD4;E4x`m=$>1U4En@ynbbfGKu|C{ zJw^vzucO<+K$`PU?>K2zCg#Px2%a?*T%B*p-iYX6LmSTD`He0A0k9?O&-F~Rc zCaJEB$`{2elWX)K4v@0nyw1h>KZ<DQHB#bLg#aKk_{uaL^w<2IDctyb;o$D6zH}^>I=oy2Kv&ej;8?0~6zs@9Zgz zQ7=bvEw~WzdoxDO?&2p9^mnma@Q3d=S~Vlz7q-{xip$yR)zWGU;Fj5{E%NP?HbzE3Dvd&=q{#PGcN<#(d*qw`(S&UiSI}24;dA?;*xh8xTly=v zi_-iWzZsG5w;xu@@@5fY zBNPu)6m#VZkidu!LbFu!Z&BT+ihSn^<@%x&l=m_z?=G z=zGoxd{?6o1K$JiH(TKQG1ity#~g%5S?quV-}JI|BknyOG93qh30oGm-Tw>Wo)PyZ zX)5kLr)zOV7qa%&{{VMO zB%Q4m1yH?SpN$U*Veb-%AW`dnXe9%+n*P7nDFH)Xp#&sEy~p2aO2G4+Ltfs%2?ukc zSF3qdQSaEaTBF``YOGQ3iiD{5A^;n6tP=IseyX7N1(4)U1T(4T z()erpF^j{Xb>aSd&o5lhpboYNy_>m<0N3Y3`NX--nD@6pop}H6CB^krG4FL?k6M25 zBL{Kj+kzHx=38Rk9W(!|poRI29SQS)l92a5AVr;UKL=I@+#m3F;l6p~VBX(4-- zYT*7wRl@xmYEFB|djdKp_j^No#&>Ggi1)QHL;mp47ooE|ig*XnkO6-z5$^!LCPlpa zNQ+xuumS!H;`I$%Zi#qrg-*u%zo?N!LoDL$j5lCLybogU2@&syq^Yayoj1kdl8IMu zl5*#wTo)qV7tJ^2@KsR)M#P(D;0lWwcs#)j3{NxzBE_lA00PK3UxbJ;+-GvghzFq% zvqYfmaT%|QVj?V4t%7Or>2Vt=t||>7az>6By)=&)brA197t5*>Y5c=Olty(HO4$U) zyW=*Yqj)z+B<-+P*zw{B6vN#J63euH}Xb; zftX7hA2SfQ83y7~xZV@=lr`La9rRyh2g>TlRmx(y6dw}8-6v8ZV6kk%8suUzWySLf z#q+S|1t4@B?*`ga3TtT!Yw<~HYhj79cC4^!s^bGU)Rf2z5fn1A7xO2@%a$U_A0Ci-oO5vVX;%hyTL0p69-_oyF3#=%!|*28SmD9l5qC| zNK_}x|MY%g{#Sn$=9_kVG=FWM`IkW@g87HvBFvZlq@DRW+_+#dG-DCQEk``sJp>j7 z_y3-aN4s|dYFc*42DWlaxpgR)6z%>GxTxmno!Dx*Q(-HdD2$|DEtc47$E#&BA&H?T z%xE_v-P64|(?mBg?s2PlHgN>#0hbLtAM1vU~TI)%XhoPx3dlM^U_CokA0d@U?ssgijIJBZMd&YcJ zEabe6dd65e)>!vd;8^0CS*+#*M-2a4tlMy#Z9WXRb$|yvyAm?^vf%on z$A#PYvW_$N!G+lgIayY7wNdOzr9 z73p5>!(bb9Cq5)>x&O%(h%I*rswnO+utbeppxFK4rGFKESfa+C%r!W1oJoN;ZjSO_ zN`U(lU}Xllk3;LGgF?TCz1gF}2|Q5S-It)I62q~BSQiub1y&)gexSudWrIF+XFz2breq!%G*a_j~rLA07xAMQWGhC*5+9wnFc_$!`NR}nGjjL51 z#I}!0CL<*?e}g@BA~QebLI;HpJQ1U?JF)FK|MS>(B}|z=e8Cf7Psg$CIsZqo?QDY7 z_F~&_LzVl(+T)#3KW@%X72Eb^{NcL4U^uAoS$z0X+Kg+jmQoKJrS`( z7RcEq0mf|YhsO4Y-+P3!HHEVkk6%Z@O@+LUqCY{!uXk|b`e?Txa=i*UF-M)}gm3vT zEAd9!fR!P~{k*Op#2HQm2RFCouL@z#h!i|c`lDE(?2p!C8(%%qwFwkQR~xYfE^u2trtRAWj5Q7 zTJItDvPZ42rjx(@0L;xW&xl$NxdCHs(67U92{V2cdL=yh_RlO~y$d%HmdhXR|8R<# z8VS~^nYx8Dz;iMFaIc4GfsJzp6=~ih z2~0aYX7D~%fT1g+YoWanoBaRsDFbDlp}n-RgSAQHaB2Z6YLX+c85fCLktYlBLES!Abo?t}Lx&@N-$gu>*aFqI7SZW$TFyxxtdbIJ%c!l848LvFRzOHFK!(6a%uJ zE3i3oTyXs0DjczxzN2BJi_dHZZ*qE%Mn)K~O8f%#nTE}L+qhxsKxJ5CUTr!35dF-w z+j4@%gTM&o6a#^BQ(~OHQu>PrY^C>7{lpOwPfUCVL*oy>iE_+g5%>fr z8NgEBHX6YN=EQiRH*)VI;VJaM2yuxWD-uM(t zGP=~95qW=R5n|~6@NM@CkIgg0#>8CAvD#0zNS)iH&V?!K9Br$^*%>dTk3s3K&rYah z$N^6fZ~%vV6s#0syUbBTiFFo)U+vBq=L4=3W|Dz+c0fCGew-mp7Mjh#_KfK;3}o_D zwPn(9E`u`H@ysBnHqU-O5045bDSR*5!;){1R4JHiBU{RCi!AeX>VufCCuP1aWm37= ztK>f-sDSrx?}h&KId_g6oaOzEHgcRczQ0z1M0NuUVGEmQ4af(QK=5K6!Xbr~_@QY= z&rs#MU}ckr|I6etW6#D69Fha1q&?C`_BV&;fm*lkopDGy1VvyBzZ}{>`YHMH1KdAq zpRZ2c65xS{fOnS(jVF>ugQIb7K79p7Uox2Tk0$j=U<#6M8QOz-9r?55>AT*1uNQe9`KU)8h?Ot%PE|cJ@bfRW7>QtS5^Ly=5sTxV@VE_E1)Ni zgQ;H&YEcPq&Li{WfX3)nmORzBRsC)Ln6_xM;(CnbJRNrjmJiOq-jk8G0wxegt6go{ zWG9kSB2Q3yb75(o`yNlj&Qi?A8O#pEW2wU@yFwQ`L#3`6JwQNOdM$I~^KO03XQCD) z6<>Mn@T^&GJHNxB(s4Wm&NFPtcn>BG_#H$J2hS1y@!}((`>%)x%QuF6jR``;W0p8U z$vBY|yc#B%U;5%`oK~7QsFW9x@Kes9(rgGLi?vM{=3Y|n!e8gBG+pldR|ZP+(ve`z zRdrhya#--OrP3S}7+yMX*1^?lgQWw#jzDQ{I*v_8&Idn)EQojoFofh}lVhw#2B9yo znG4p-{XMWAoCEKX`|||Um1L8+6I&muY)n*oe5gf#ke(ef0*xO{C-2uv;;vO|0xkx< z1qc@Yue+hf_60NfFAN~wJ1_{HfdwAji0T~I(v;(R8#=`-{&N=p8r!9992@m! zKN-@OcTsO%gwfz>Vc=rBNi*&=Odc$6Q8fcN)YJhq1h!<=tic2VH5`fw>>a4gPUl16 z8`1$M`0kX?i9g}P`t+*L@#4%s`C% zdWHI_hr9Yo{3JcAN@o+HG*=ACNBT`q)0}}J0N?VB8BoQgISro8D4f>dVLUJ`*hfR6 zLSD+)j7u4oei1xfl~JBm;mj{< zexqf~qOI}hTLjvk#{Bp43G3C96)T~+qu&^_cRA$LA3o`iYW8pgybK{|S3{{o2rd9GCmWo-zam3rf(*U}q1G^~p9GQB z7gL3UyO<8iD8}g^Ioav0&@Ur%y!FxNMGwpS)=2bgAmxc2Bjr;-bZEpf;^UBG9>MaY zY+8W1x$Rk5iL(_7cFyS9b+;Av7->Tge-o_-xv zvK=kgz!LexTq^Wkka1;4`g=!3$)wi#;o0;}H*mgbqrIaKVhB4_+bA!m5OU6ElHc7;aB~50 zb6sUq4`SyN@d5y_bJu}04!j9)b^$ooRW|l$7d&Gv82EV*fEeD3EtJeZkhwy?1AoV-ZXJfV}DZA^_uuT5& zO@7!P!CMkRg+2Gd4kut6`g2V$FKwcJozy)Obs1jd&cJXZ4vSYd_qOLs*GtRVPu+Mc3ATK zU8Ejmf>>9eEE{2&(?fGHF4OU$|Lt08D;E{YQmMGsXG=dJk_kjlyh#{`M zH0EW7?*RK*1#`s_VJ24orQvrhg*#jAD2drhUF20m>0tiDiY0RC`E=@NVa9Q(SgcYd zL?+Sr$QYuZ@cyi13`9O|SVOorJnN#%jr|VzXUhznrC$eQ;}4&C8)YX;p(Jsj8dA{X zGV~wciO9aikU!ZBqehl~qO|evxmFosBS2gdPkZaqSR;mp_#U>vAATD(Y?8DLV^1~A z6q0n=#c0ziNwYeVq_L(X<-{Z@N11AoDQ;16CZoX)1WF&9N}yhd3skis4Q?RH6asaU zAyAB%#sq364o##Gs5w}BKaoIv4u2&01{%5{P!oBGKnYY#8yOl!mOAF#srQ9j82jHj zlqi}04|v!hL56I1JimmT`opiF26YA^RVv>>yqbp3@tdRn8o)cA^VmT!4;vu!jwic| zYd8HaY4viWRrBWP$o5*TmR1K#t3%EEsNCC?N;^m350q6&Hc_+FU2_Nx7V}zTc_L-9 z=%9C%@{*u<4KalhyP)Ho(9KS5vY{NH8L;BvK@sJ!&Z->Tf4q;iIuA^sa;YeY!zgVs zpXF-h?DV*LKo9ePm+0Yh4DXeXo-CES8LpcVDiu67X{}Q*r{BhfuyjhOR21VboNJ8! z!%!>F;Gn#zR>mThCoi~~vfn>)6cv!6WnGc4fp94wn2@O$sgZp-9%;Zg{oj}efB3Ci zFo`$@g88M(c*jIR{@jllTO@48Y?7wGA@yodkCo5^SqU|MnN7!7^^_@@F1=FfUcf$W zcCwNldAkoF$xc#k{NY1TH^EL8#Veb3@<=KB`RoMkb^vx#8z-}BxQ!F+QyjEF6`U`;WDYy2eiS=-B^f*n8(~fRMC_z_(Ya(=%ue#iPE4&m zLhKN`4qY-WR3c404gZ3n)~3Y#OC8xs@i=tJPWC1o=%QNV7;JX(T&Vue?BqxYJ?6iH zvXjD2{++-kLB}Q8$seKZ5&yf{DnnK~c~!g-!%qG~YCMP<-L;b=VYa}SxFlKaWRfIx z!A?GY4H`7;WGaDbE=wg)u#=`h!A^=ad_^x~vOuM@lNVBolLczxO+T4Hy#eP}w*{&N zdaP4B`5pFLIRD_IM2QN!x*T05$dJvVy(Kk*sA08}r^Tz;?c}RR(N6w?9R!D&7ELsx zt<`I!)iaD%O*{D!hF}n5Z*_{a>X24Po2}AL9w+TYy&c<05t&Zxq@f(TU?)3uNyhAC zgwpok*vUq)nRe3DeWlYvr6R|xe~&-FPKsKw+R1GbVs_HdtA?F4RzjETNt_^oOor^PJRP3;SaxovNr9uFs;kGfJ=UE&Z>1Ic_|ub$3SMuMiRIowvn9n3p8Qq zGpU$hAX|&A`fMVeATkW3`cVwz6dK6B^z>@`_(oBDi+E||Oau4Z4CJj)T-H*d5^16u z;M_2f6YU#GBUhIdE6$zVm5rn$R5Fy*MW&gY!Wproy}FzZRK!QWuEp;G5FBGK`A(%u{gkTb7{?`GErw}327a{7) z^hFG#XTTz8MiV1{`;&>#Gru$$b|50uANbf1AsdqCL}Q&&JvsF+AZM8W-&2M}Tl|)N zB}k3UYP}*gDpA8~3(tsGvsSdq#&g+0X-~EmV3SVb2(1tuE{t z@gR@rf=v`N5he;Z{B}uu#`ZRgVW3IdX7SQcsYvd7K!r4dRDaPIEStpv(_sXECEG(o zcSZ(Sese|sjm;v~wAw2=QtTBS`a2LIe|W*~z~;COY%J;228N{GWvCakfez}zQ^v&R z)6{B7HgLSuJ%)YSY+yRffgzY?-6R`$q}2WVdaE`Qsa{2u6PIdAN(7bw@qd)H>9GT_ zfxjX}GMiQ#*nu-OrpID7a84)A)P0~kzDaya4hG03QT-TqrXImvxON|Qk#V2|XKG3t zcr!GWwUpsLs{-(j`@W1r2(n3R#|C!3Ni=QXmzSBG>Og^!c$*D8?t+*CGiN->2A%*Z z_lLi`j?$9C1~wI<Ss{s{_yi?Bee~@Bi;z;pzORLHD;rRO?D2z2A%-R zq-4ix1CwN@3pOxF-ge+VedGL8A_N;~iV$p|xSg80okQ(hyR~}K zMH@JV9Rwf2?WuPBrjw=B6O2|(8~C^OTD?eG-ElQr{hieYx}}|u@rRCVV6xvd*#^RI zNe+4JY=~rn9ZRx-Wm2~v`?T4>bI(btn`8s&m-dG@ zU1`;3BGqZ}%H}@sOIQN<|54V^V|dLJam9W_OTMf?J@hw@Q?JwTUvX=ftus8^281+k zGt;(@JQHD7bzT!kxU~|TcWUDKX?Vj+VEB5QuoDMn@q9ebCc9As2ZN>Ml5F5Ett1C- zemsO&>U7uKPHYu-^H0OCh)hb1l4X3q6c>Mg1_2!B;4eQ1#ac-oz56#K{w3*e>Du0N zA$oy+#3Asd(g?SiyyMAN&p~%^s8v5s!SdubbEy_kKMsvPYX0bo+ynq+I3J#*qj*u8 z7+mvl%hG9)Mt~|g`l*6VI30&BdeQ|F+cCua7j9r?YD>Oos<_}2Ry)kdK@=%RaQqiu znN?!>owUZKE{R^KGwfz)^OmllP*8-TEyJRhEn zCvf4+t5VL$WdxEM2Oq_``9?E7@gi15WCs2QvZIf-YqM{J@$iR-|Ax|?!e$TSrmi!a zJxJQv^=qq?TlcNsLs!IC8Ey6+0A+vp9n`SNdjIaodim)GD(fepM*FfZ`-l!?{i+06 zA7hvG9B$?0(5FbfUQfW%fyh5lkV@o{Bh?i72h1N`k>AEe{-rWBn=JBmsYLz=TCHS} z&%ONrM&z$lL2JZw{>LK!CY)<=k#B#WeJhrRKV14N%DiafRPlWq#<)Og9EloMjPZ|n zv`u3eF7}@7c@AQXZNEeZ!D_)60sMWp{xkXhf#tioE^WPijN@*|e~V)5&BPv4+v}}4 zgS}Nqt2->cEtT)nEZ+^pe5ca3CK=V6roR6*)n z52F%J&X+i~NmD{|T}ne5IHg2s$b`N6QW%h~`0ZSw648%HVJOyb?3lfXieb2}kAdTqQd6sSc7%Z&F zQ0iY}wf2wf!~!&b8yZ<>`OOu13cpb*)h^$aVwdmIKZ6Vd|4xDE#1YPxvpPjM&q}?S zs24*xeE3T*jROr+){+p;^-}k2_Gv>nx5kyfSvLvcoF;XDxZJAyWlfzIuWTZm3@N)B zWo=r&TL|aI1J?TIcBu6e5YCm|ML1`3l^W_^8c9GnuiMo9Q*nf&eiVeGel!uzwVcLU zn$Sg6C?4PGm0p<|;pEYmAKMR>UKuKtCQbp??+U`1W(!KUhj2RIW0(lX2hYL(0^xA* zHiUEMFsr&ZB{az^5kf@5AHM7|N_Pr`vn}q{j9H8%&-?|_#*t`)8W}3jSSjY&t|#J+ zfDR%Y#zAoY=h6gO?-s%doOYlHXFO_j8Q~XStNA?(t+f^Z&!Z`&WfY7%8$ zwDCCDwnQ9n!yMO0jWbZgig5bHtJx9GlpoMRor4_&^RV@3`&=QMQS!Z|JpSEWm$u&a z0D1!dqnH)pJb!MCNPBPJ?qzQeNUJ;GTQ_@KFW=`{z8kCWA!+|A{GlU+V-@@^Bb;f1 za4epfju1}gURe|2Tuf>IsS!?Z;0UYJrsT>{iLAB50Lh7PMBuClXW$tzgkvmR1K}8J z*FZSt^6d)3`4K)+od3B5A`(Y9(=O>0;k+aD7NDLT;k*W)L40><%h`92RQaXq3O7I$ zGDYeF9GBzvy{9dbJgN)(_MW(}Mtl5tF|Kg{GcIN4yxhr$(Rf4OyxVcwByjXaWl=0y z1k;3~rU^3mPAM`Hf^>Wl(4gp0P((`j6xePnB~R1tFG-?g7J!OBTx_9)GL4IB?eV5l zi*NF#8gUZx<`KwFO5S`pBqeXQLWv{)_xLz(I-&@?=`uyzi`wDM1*Bxj-3c$XT`q*2 z1VRi+OkfZj{o)jnci^FU@VJK2k~_VwC>)YtKD|sz_p_I-N?n>6MD$##ppTWYvj>ju#*@)};93OT zc~rM&>}YT7M2S%L`9zN81yr?AwrW5-lr56dx7kZSkh-)`Hcu*ywNv)bd{Wj3wsk~V zsZ>3}-q$kX9IKR@JnJW=zbvzjo0PuLUizNYrG>JwQsF2&WlwN%1|IK(XGciY&n~iY;TgKXQ}OIeh&25F_R-XcdW7eW{ow+3)kQsWhSX>qW1HWesil0Mevp)2V=ukY6Ju*^7N7}4^43Ac`@@f; zf@MwIA!}l3CzAJ&RK3dH*TRcZ_O(yHUP_;BFFiMPX`$>KsnF9-**CH#<{Q?mJq_0e zr0Ea;;{qGcju%@eR?fOPAP7 zTY9ir{b!}_Ox6YM1CEY$k#e=pmeL-h^!F*ofE8rCGid(HTP&G%dIqvi8J&AmRuSWE#3s3seA}a%?qcZ~@0S zXXC;X(!dQy9|z~!DM`dWGo|$TM(IrnJY&Q9I4P1#itZJP)~29nCY*DMBIVi53~b)5 z?E2_f4lcc?w6wMaEdli{nvUUVJ(;a&K7f_KtqT7|s5Btooi*>y?MJj%2=x%Gw`XPu zhi=Z)0!wjyBe=cp>x|HxyZ5OpRAkPuQ!wPd$RzeNJXpOxm|3%vnJME*b5Z0!nC<97 z{R6%!E3@`=6eSG~6ULCzXl7dL9Wnz7r`OEoBLl^^Gt~ z{_s;M4#W(G`S;ow1j(3tBpEbJbb-aXg=QGcsrxn~m~XGY35iogXc^eJgrQ-X<_@v$D%b~YhZtR(9_~A#^TrR<+{|$ zTA(U3%A9Z0Qw)_E^y#5d^Y#U0!ru$IaId+oaJRR2uy>#VDd_a*R}Ew$oOLaMRk?C0 zk+jf{ym~a*@o+Io;G@-)#r^J=hG>CiZm6>GmL_|2=D!zm99p=2=8=VaXPgjhE?B#3 z7l!A4X?L(k$l=!RWvL+Y_ytzEqETvam`?Gv+{l{unruZpC~mbr;-o z^MKGuOJ82})d%X~v_PHHzo!Zene~}!tbyDCds-<2c`*`#JtA|^98_IT#RuduQJudR ztx*y&kehDFJ&8c4?uVxKhs#D19%LyhW;y-)tI+t(Q$v$8LnWC2e}OH#!H~k0-r-bh zS7jlO_I_|C*gC66a5qLG(j3^%Khd9Q}QmPs-lWA7epoEl~UralDyi_e4% z*F`^7Isjd;reuvAi~}@0O;DNroHIBhCpacMcnkA>y^9>VJB=K9baAHJq2Bdw~UD9twwc`1r=wJ|x`y#rx&nDwo7c#oMBaeyRk7*m}E>dyof zlCki$vp~P(unZOt(~5J0#Un8BBtA5%@0s|Q7gb&Q2L$aNXMItT{R#PCbM$XAvVk#z z(2JfaG<|qJXqsD;=AFvpMU#+xT+?@$gVaX`4VJSMN^UE~-{ zpOJ$cg08Atm>Ux7CRm*JOVLDTIp*&~GMw}odDZWF50-KVrMCu)bC4l!c=5nly^$lQ zc%U~UeMT-S-YvF{yN2<3FbRhsKt6n=!<&h0ruofN!xi>q<7x#b9 zQ(E&vm}EnZ3kNNwMaPDv^j${jW7;n*d#wAV^skN5-^n&mAhy}IvCjz94$-fZvS*^K z1vW2-;M*@(shXA*<!0H$6Z{`+trAL-S&KQ5CI{IGz2CNkx;1R>M7ThFA~xxtmuZ!MV5Kzv35To;phWda?M1Sn}dPB< zwaNVsZdKg>9Ihk}6Sp2yy^NE9r+u(u)fM<=w!mo}1~EpTy3qz?M`c#*`8KPd1bRS4 zXcs)KUhpn6iw`eB7Tz~#iL2N8j=_5F=Uy@l31O?|W+BB$j<@&D5@fw~1WNMKAyYAT zt1;uuBrcr@U(OspGI!<>?WR05f%FGRGh2%+vrJ9ns+ujzq$E8!GB3E-y<}y)DT7%9 zqb;TuXh#zJtGSY>gasQ(HgmpXuZ>5NF7F|Q^#nSyNld}0MQ$+^3L)Ghy#E?uYGY&OpD;J{VnS(&+_xYc&$9Cm8WV=qWORdfb}0aIC#^*;P^b` zydU4+$a%k0<-8v`SlOw`1#Q5Fix8bf{_|l1Pls1#xkKDba_NuD)kf#!zgM$1Sl;R# z1GN)nXoqr50Q%Zyx~220X6x`B|jn&I-r`kgUp#DkD}DrwhgJpKVe+r+2&*=;nk> zI)Wk*TnUgecO)q%)icx94E8=Lf8J>9~0a^@DVuvzB0A<54fr>E6JFvgzv=!%sysr)eoD@)5 zL^Djt>_rB5Ku`Tq`dvTxsPY(`mfF*R|gGM+A#_8#zP$a?f=Dx@^lGE@DaoZRh;##X z>i+OwQPzS;Pwv?TMEa=IyiRIb5$U4<7VRR^A;1+W5$VO!+R<#yhDaYfh|<~>MCv8J}n?V9Sk+3nefz+08brIMAmlxTWm^AwomLa(dHqA z#ek;6NAC+w-{(C-W`V{4_|SxnP;N66E|tx9KzCsC4bz|@8Ig5N1};5~xb$RGucCCq zaP}!&szFQ0-d2WVgQW?(lN`0#1UA*ZXL4$bPLrjL-6yw?m-Z1rnnys&-DeDry5VT% zX4v9t#xo??o?=VeHg2e)JK9~*DRAh2hO+y*QS3c)KU*nS z%Qy~&^(lAK@Ei~hjo11waOfbRan~s(s&j|#fhhrXCJu$kRZw(%M^KbNE*q#$4AL`uIZV!$4k1IR82M9TLx<5-iDrV#0k zh$i9wQ;hZ$h;$Ude~p1iOAi2%?h~hl7<)R;kiry*$K%phK}QHKy`SqQoxnf7ffHEj zuD+S%3Z&)$+;{S_TjV$RkGVz^+I$7_;15?0h785A>8kXYDA`K~r1Zu1(hnq+HZ&ja zRU!X1N~@Dr3E1@a4r0@BoTLU@BK-ESsh~GFW4Xh2>AMQpdUy~{fGQs#SKlwdX~1&t zc7n4MVq-@FmWv<>b_KxcU<~6~f7d|Hs>x zz(-Xi|K}KBz~BrpO4O)PqDy{VOJB3m&qX3kW^Lo*G89ZOb3a2NnPi|Cs zz);`SNI1K=4607n|DdVFiDci_CcAL^ccc8h9awix7GVjQYYZ|Ny;2YAM@OR*sbyL*qwi?u5V1Dy z=(MXX8%Ifq7`7t8h{enR`*7giVd_-26f}&!n{pJ7@i=zy{>UUfiW@V!E<)xf5lk*>K6cRHidzQUC{F+Suu1&)X=hL29sqB zp6vaK^Jv)rKhbKQPgz9h$BkRbp|X}>zQ?>4LsEfRW76`vg4)u!un3a>d3+Mi>r{^9{&shY@tD@8!$9KbUv8t z-5SpY0FKicS~|`T6t_nclwD!1MCnSq|6v1(Imn3w z*B5X-7$zt#xw0aq&s)+bn6gh}+fGX#r30bfMCRfV&>ICp1tDOZC!o2kS`HE+tKp&*2zqRPC*wmexLd>*tbMD;}G?;(^m7={OJ_8yp3~KsXr2 z+1Le0^eR5|?Ylu)>~tU{`m`vn42lKF_QNsTGG!WkuI50QGc#O<0}Qn~=r)Ftd&7;GRQc0!NUP!ecPzM!GR@gPc9{0<`7zJ@^I zT--E`&5~c|89T9;LjL!|WR{QyeZFNC{z3aB&sqAuBYi{d^>rln9T)a)p{-R!s1XRm z2tll~7Ddj(D5W#(^^g!%n?f~PFkOa|xi8U^H$MG&XB()5Ca84QQx8BdF&P+0V+=i! zs(2xPD=C+yd^Y?&tC5Xx-PM4tF}gtg>@vPVXaV>C@`Wz$*nwXP@@$5HTGuS>u0VK1 zAY8o{5FWBY(Dz;bEZuvfJMO#C9w`Tf1b|944uVD!rhCFwjE>?yN;9cL(rA;na4Tkt zTP)1=n2S!#=B{W&>KuInc62DG5TQ=5>VEL?Orv4?9>VL7psoFphYoE=PKHwA)Dnx) zQu^K}eJ^gWZ%%Sw3JJ|XaJ4Z;02~egAs_MJQ!kmj} z?M?#jqeEmaLNP5Okc8voTQFOnkKid|{we#kS*%0MJ1LAy`F+y&V)hj&$GKtmzI7@y zdGNEJUqDjwAzhS`^H?}^IyfXVjbk_WH%tmJ#3!ZlQ#c|)Cgg*(1`(XbQ8L~y2V=a^ zJP5Zg=8t}gF)3x=C^i+i|CX}veX06tTm7o^o6dej*XQA|;09OM?bv)LOk`ziD(=w3 zH!Xs3kw83#5CNmOOVTPcTg!cn^6K2eB((D(*mmbca1kTR~ zrGs;g9gesPvIioO3L_m>3WRdg$ik9>`c+}}DfGYZSdUDAyFHI{^oOfAS0EIqOlf|MhU5YT=Q zh9bqfQC3J6Wsb2GHUR$Lflx9v5>B|@iMjHUD!(U;9qX7oSR7+=&l=y;f|oXUj|jZ0 z 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 literal 0 HcmV?d00001 diff --git a/scripts/flatpak/assets/ncurses-5.9.patch b/scripts/flatpak/assets/ncurses-5.9.patch new file mode 100644 index 0000000..7a2f8a5 --- /dev/null +++ b/scripts/flatpak/assets/ncurses-5.9.patch @@ -0,0 +1,36 @@ +diff --color -ruN ncurses-5.9.orig/c++/cursesf.h ncurses-5.9/c++/cursesf.h +--- ncurses-5.9.orig/c++/cursesf.h 2005-08-13 20:08:24.000000000 +0200 ++++ ncurses-5.9/c++/cursesf.h 2025-02-21 14:45:57.002814632 +0100 +@@ -703,7 +703,7 @@ + virtual ~NCursesUserForm() { + }; + +- inline T* UserData (void) const { ++ inline T* UserData (void) { + return reinterpret_cast(get_user ()); + }; + +diff --color -ruN ncurses-5.9.orig/c++/cursesm.h ncurses-5.9/c++/cursesm.h +--- ncurses-5.9.orig/c++/cursesm.h 2005-08-13 20:10:36.000000000 +0200 ++++ ncurses-5.9/c++/cursesm.h 2025-02-21 14:47:21.238076003 +0100 +@@ -659,7 +659,7 @@ + virtual ~NCursesUserMenu() { + }; + +- inline T* UserData (void) const { ++ inline T* UserData (void) { + return reinterpret_cast(get_user ()); + }; + +diff --color -ruN ncurses-5.9.orig/c++/cursesp.h ncurses-5.9/c++/cursesp.h +--- ncurses-5.9.orig/c++/cursesp.h 2008-08-16 19:20:23.000000000 +0200 ++++ ncurses-5.9/c++/cursesp.h 2025-02-21 14:45:19.718735744 +0100 +@@ -251,7 +251,7 @@ + + virtual ~NCursesUserPanel() {}; + +- T* UserData (void) const ++ T* UserData (void) + { + return reinterpret_cast(get_user ()); + }; diff --git a/scripts/flatpak/com.github.lindberghloader.yml b/scripts/flatpak/com.github.lindberghloader.yml new file mode 100644 index 0000000..64b6f49 --- /dev/null +++ b/scripts/flatpak/com.github.lindberghloader.yml @@ -0,0 +1,323 @@ +app-id: com.github.lindberghloader +runtime: org.freedesktop.Platform +runtime-version: &runtime-version '24.08' +x-gl-version: &gl-version '1.4' +x-gl-versions: &gl-versions 24.08;1.4 +x-gl-merge-dirs: &gl-merge-dirs vulkan/icd.d;glvnd/egl_vendor.d;egl/egl_external_platform.d;OpenCL/vendors;lib/dri;lib/d3d;lib/gbm;vulkan/explicit_layer.d;vulkan/implicit_layer.d +sdk: org.freedesktop.Sdk +command: lindbergh + +sdk-extensions: + - org.freedesktop.Sdk.Extension.toolchain-i386 + - org.freedesktop.Sdk.Compat.i386 + +x-arch-build-options: + i386: &i386-build-options + libdir: /app/lib32 + env: + CC: /usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-gcc + CXX: /usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-g++ + LD: /usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-ld + LDFLAGS: "-L/app/lib32" + +finish-args: + - --env=LD_LIBRARY_PATH=/app/lib32:$LD_LIBRARY_PATH + - --env=LDFLAGS="-L/app/lib32" + - --env=PATH=/app/bin:/usr/bin + - --allow=multiarch + - --share=ipc + - --share=network + - --socket=x11 + - --socket=wayland + - --device=all + - --socket=pulseaudio + - --filesystem=~/Games + +add-extensions: + org.freedesktop.Platform.Compat.i386: + directory: lib/i386-linux-gnu + version: *runtime-version + no-autodownload: true + + org.freedesktop.Platform.Compat.i386.Debug: + directory: lib/debug/lib/i386-linux-gnu + version: *runtime-version + no-autodownload: true + + org.freedesktop.Platform.GL32: + directory: lib/i386-linux-gnu/GL + version: *gl-version + versions: *gl-versions + subdirectories: true + no-autodownload: true + autodelete: false + add-ld-path: lib + merge-dirs: *gl-merge-dirs + download-if: active-gl-driver + enable-if: active-gl-driver + autoprune-unless: active-gl-driver + + org.freedesktop.Platform.GL32.Debug: + directory: lib/debug/lib/i386-linux-gnu/GL + version: *gl-version + versions: *gl-versions + subdirectories: true + no-autodownload: true + merge-dirs: *gl-merge-dirs + enable-if: active-gl-driver + autoprune-unless: active-gl-driver + +modules: + - name: libstdcxx5 + buildsystem: simple + build-commands: + - mkdir -p /app/lib32 + - install -Dm644 libstdc++.so.5 /app/lib32/libstdc++.so.5 + sources: + - type: file + path: ./assets/libstdc++.so.5 + + - name: libGLU + buildsystem: autotools + config-opts: + - --host=i686-unknown-linux-gnu + - --prefix=/app + build-options: + arch: + x86_64: *i386-build-options + sources: + - type: archive + url: https://mesa.freedesktop.org/archive/glu/glu-9.0.2.tar.xz + sha256: 6e7280ff585c6a1d9dfcdf2fca489251634b3377bfc33c29e4002466a38d02d4 + + - name: freeglut + buildsystem: cmake + config-opts: + - -DCMAKE_BUILD_TYPE=Release + - -DCMAKE_INSTALL_PREFIX=/app + sources: + - type: archive + url: https://downloads.sourceforge.net/freeglut/freeglut-3.2.2.tar.gz + sha256: c5944a082df0bba96b5756dddb1f75d0cd72ce27b5395c6c1dde85c2ff297a50 + build-options: + arch: + x86_64: *i386-build-options + + - name: libFAudio-Dynamic + buildsystem: cmake-ninja + config-opts: + - -DCMAKE_BUILD_TYPE=Release + - -DCMAKE_INSTALL_PREFIX=/app + - -DBUILD_SDL3=off + - -DCMAKE_INSTALL_LIBDIR=/app/lib32 + build-options: + arch: + x86_64: *i386-build-options + env: + CFLAGS: "-m32 -mstackrealign" + CXXFLAGS: "-m32 -mstackrealign" + sources: + - type: git + url: https://github.com/FNA-XNA/FAudio.git + tag: "24.12" + + - name: libxmu + buildsystem: autotools + config-opts: + - --libdir=/app/lib32 + - --with-shared + sources: + - type: archive + url: https://xorg.freedesktop.org/releases/individual/lib/libXmu-1.2.1.tar.gz + sha256: bf0902583dd1123856c11e0a5085bd3c6e9886fbbd44954464975fd7d52eb599 + build-options: +# arch: +# x86_64: *i386-build-options + env: + CC: /usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-gcc + CXX: /usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-g++ + LD: /usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-ld + libdir: /app/lib32 + + - name: libmd + buildsystem: autotools + config-opts: + - --libdir=/app/lib32 + sources: + - type: archive + url: https://archive.hadrons.org/software/libmd/libmd-1.1.0.tar.xz + sha256: 1bd6aa42275313af3141c7cf2e5b964e8b1fd488025caf2f971f43b00776b332 + build-options: + arch: + x86_64: *i386-build-options + + - name: libbsd + buildsystem: autotools + config-opts: + - --libdir=/app/lib32 + sources: + - type: archive + url: https://libbsd.freedesktop.org/releases/libbsd-0.12.2.tar.xz + sha256: b88cc9163d0c652aaf39a99991d974ddba1c3a9711db8f1b5838af2a14731014 + build-options: + arch: + x86_64: *i386-build-options + + - name: ncurses + buildsystem: autotools + config-opts: + - --libdir=/app/lib32 + - --with-shared + - --without-debug + sources: + - type: archive + url: https://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.9.tar.gz + sha256: 9046298fb440324c9d4135ecea7879ffed8546dd1b58e59430ea07a4633f563b + - type: patch + path: ./assets/ncurses-5.9.patch + build-options: + arch: + x86_64: *i386-build-options + env: + CPPFLAGS: "-P" + CXXFLAGS: "-std=c++14" + + - name: nvidia-cg-toolkit + buildsystem: simple + build-commands: + - install -Dm755 usr/lib/libCg.so /app/lib32/libCg.so + - install -Dm755 usr/lib/libCgGL.so /app/lib32/libCgGL.so + sources: + - type: archive + url: http://developer.download.nvidia.com/cg/Cg_3.1/Cg-3.1_April2012_x86.tgz + sha256: cef3591e436f528852db0e8c145d3842f920e0c89bcfb219c466797cb7b18879 + + - name: libsndio-dynamic + buildsystem: autotools + config-opts: + - --libdir=/app/lib32 + - --enable-dynamic + - --enable-alsa + sources: + - type: archive + url: https://www.sndio.org/sndio-1.10.0.tar.gz + sha256: bebd3bfd01c50c9376cf3e7814b9379bed9e17d0393b5113b7eb7a3d0d038c54 + build-options: + arch: + x86_64: *i386-build-options + + - name: libsndio-static + buildsystem: autotools + config-opts: + - --libdir=/app/lib32 + - --enable-static + - --enable-alsa + sources: + - type: archive + url: https://www.sndio.org/sndio-1.10.0.tar.gz + sha256: bebd3bfd01c50c9376cf3e7814b9379bed9e17d0393b5113b7eb7a3d0d038c54 + build-options: + arch: + x86_64: *i386-build-options + + - name: libopenal + buildsystem: cmake + config-opts: + - -DCMAKE_INSTALL_LIBDIR=/app/lib32 + - -DALSOFT_BACKEND_PULSEAUDIO=ON + - -DALSOFT_BACKEND_ALSA=ON + - -DALSOFT_BACKEND_JACK=OFF + - -DALSOFT_BACKEND_SNDIO=ON + - -DSOUNDIO_INCLUDE_DIR=/app/include + - -DSOUNDIO_LIBRARY=/app/lib32/libsndio.so + sources: + - type: archive + url: https://github.com/kcat/openal-soft/archive/refs/tags/openal-soft-1.17.2.tar.gz + sha256: 11ea176f6cbf9763dbce0953dd77ab72d032b4ad95f07afffb91844abb174033 + build-options: + arch: + x86_64: *i386-build-options + env: + CFLAGS: "-m32 -mstackrealign" + CXXFLAGS: "-m32 -std=c++14 -mstackrealign" + + - name: openssl + buildsystem: simple + build-commands: + - ./Configure --prefix=/app --openssldir=/app/etc/ssl shared 386 no-asm no-krb5 linux-pentium + - make CC=/usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-gcc RANLIB=/usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-ranlib + - mv libcrypto.* /app/lib32 + - mv libssl.* /app/lib32 + sources: + - type: archive + url: https://github.com/openssl/openssl/archive/refs/tags/OpenSSL_0_9_7.tar.gz + sha256: 14e3a90f75994689e8c1bef098a97021f225a1a1623a7b8012079bd8b2eca1e8 + + - name: libpcsclite + buildsystem: meson + config-opts: + - --libdir=/app/lib32 + - -Dpolkit=false + - -Dlibsystemd=false + build-options: + arch: + x86_64: *i386-build-options + env: + CFLAGS: "-m32" + CXXFLAGS: "-m32" + LDFLAGS: "-m32" + PKG_CONFIG_PATH: "/app/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig" + LD_LIBRARY_PATH: "/app/lib32:/usr/lib/i386-linux-gnu/pkgconfig:$LD_LIBRARY_PATH" + sources: + - type: archive + url: https://pcsclite.apdu.fr/files/pcsc-lite-2.3.1.tar.xz + sha256: a641d44d57affe1edd8365dd75307afc307e7eefb4e7ad839f6f146baa41ed56 + + - name: lindbergh-loader + buildsystem: simple + build-commands: + - export LD_LIBRARY_PATH=/app/lib32:$LD_LIBRARY_PATH + - make + - mkdir -p /app/bin + - mkdir -p /app/lib/i386-linux-gnu + - mkdir -p /app/lib/i386-linux-gnu/GL + - install -Dm755 ./build/lindbergh /app/bin/ + - install -Dm755 ./build/lindbergh.so /app/lib32/ + - install -Dm755 ./build/libsegaapi.so /app/lib32/ + - install -Dm755 ./build/libkswapapi.so /app/lib32/ + - install -Dm755 ./build/libposixtime.so /app/lib32/ + - install -Dm755 ./libs/libCg.so /app/lib32/libCg2.so + - ln -s -f libposixtime.so /app/lib32/libposixtime.so.1 + - ln -s -f libposixtime.so /app/lib32/libposixtime.so.2.4 + - ln -s -f libopenal.so /app/lib32/libopenal.so.0 + - ln -s -f libkswapapi.so /app/lib32/libGLcore.so.1 + - ln -s -f libkswapapi.so /app/lib32/libnvidia-tls.so.1 + - mv /app/lib/libopenal* /app/lib32/ + build-options: + arch: + x86_64: *i386-build-options + sources: + - type: dir + path: ../.. + + - name: bundle-setup + buildsystem: simple + build-commands: + - install -Dm644 -t /app/etc ld.so.conf + sources: + - type: file + path: ./assets/ld.so.conf + + - name: cleanup + buildsystem: simple + build-commands: + - find /app/lib /app/lib32 -name '*.a' -type f -delete + - find /app/lib /app/lib32 -name '*.la' -type f -delete + - find /app/bin -mindepth 1 ! -name "lindbergh*" -exec rm -f {} \; + - rm -d /app/lib/terminfo + - rm -rf /app/lib/pkgconfig /app/lib32/pkgconfig /app/share/pkgconfig /app/lib32/cmake /app/lib/debug /app/include /app/man /app/share + - rm /app/lib32/libmenu.* + - rm /app/lib32/libform.* + - rm /app/lib32/libpanel.* + - rm /app/lib32/libXmuu.* + - rm /app/lib32/libbsd.so diff --git a/src/lindbergh/card_reader.c b/src/lindbergh/card_reader.c index cfa054b..ba83c47 100644 --- a/src/lindbergh/card_reader.c +++ b/src/lindbergh/card_reader.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -11,6 +10,8 @@ #define BLOCKSIZE 8 +extern uint32_t gId; + uint8_t cardHeader[] = {0x08, 0x00, 0x00, 0x00, 0x81, 0x00, 0x59, 0xda, 0x00, 0x00, 0x54, 0x4d, 0x50, 0x06, 0x03, 0x23, 0x10, 0x41, 0x62, 0xad, 0x00, 0x2b, 0x0b, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x71, 0x52, 0x70, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xd2}; @@ -38,17 +39,27 @@ void initWriteCmd(int fdIdx) int initCardReader() { - uint32_t gId = getConfig()->crc32; - if (gId != VIRTUA_TENNIS_3 && gId != VIRTUA_TENNIS_3_TEST && gId != VIRTUA_TENNIS_3_REVA && gId != VIRTUA_TENNIS_3_REVA_TEST && - gId != VIRTUA_TENNIS_3_REVB && gId != VIRTUA_TENNIS_3_REVB_TEST && gId != VIRTUA_TENNIS_3_REVC && - gId != VIRTUA_TENNIS_3_REVC_TEST && gId != R_TUNED) + EmulatorConfig *config = getConfig(); + + switch (gId) { - printf("Warning: This Game does not support Card Reader, please disable the card reader emulation in the config file.\n"); - printf(" I will disable the card reader for you.\n"); - EmulatorConfig *config = getConfig(); + case R_TUNED: + case VIRTUA_TENNIS_3: + case VIRTUA_TENNIS_3_TEST: + case VIRTUA_TENNIS_3_REVA: + case VIRTUA_TENNIS_3_REVA_TEST: + case VIRTUA_TENNIS_3_REVB: + case VIRTUA_TENNIS_3_REVB_TEST: + case VIRTUA_TENNIS_3_REVC: + case VIRTUA_TENNIS_3_REVC_TEST: + // Code for supported games + break; + default: + printf("Warning: This Game does not support Card Reader, I will disable the card reader for you.\n"); config->emulateCardreader = 0; return 0; } + if (getConfig()->emulateCardreader && getConfig()->emulateDriveboard && gId != R_TUNED) { printf("Warning: This Game does not support Card Reader and Driver Board emulation enabled at the same time.\n"); diff --git a/src/lindbergh/config.c b/src/lindbergh/config.c index 2bae715..1ae5b8c 100644 --- a/src/lindbergh/config.c +++ b/src/lindbergh/config.c @@ -619,6 +619,7 @@ static int detectGame(uint32_t elf_crc) config.gameReleaseYear = "2008"; config.gameNativeResolutions = "640x480"; config.emulateDriveboard = 1; + config.emulateCardreader = 1; config.gameStatus = WORKING; config.gameType = DRIVING; config.width = 640; @@ -947,6 +948,7 @@ static int detectGame(uint32_t elf_crc) config.gameID = "SBKX"; config.gameReleaseYear = "2006"; config.gameNativeResolutions = "640x480, 1360x768"; + config.emulateCardreader = 1; config.gameStatus = WORKING; config.width = 1360; config.height = 768; @@ -962,6 +964,7 @@ static int detectGame(uint32_t elf_crc) config.gameID = "SBKX"; config.gameReleaseYear = "2006"; config.gameNativeResolutions = "640x480, 1360x768"; + config.emulateCardreader = 1; config.gameType = FIGHTING; config.gameStatus = WORKING; config.width = 1360; @@ -978,6 +981,7 @@ static int detectGame(uint32_t elf_crc) config.gameID = "SBKX"; config.gameReleaseYear = "2006"; config.gameNativeResolutions = "640x480, 1360x768"; + config.emulateCardreader = 1; config.gameType = FIGHTING; config.gameStatus = WORKING; config.width = 1360; @@ -994,6 +998,7 @@ static int detectGame(uint32_t elf_crc) config.gameID = "SBKX"; config.gameReleaseYear = "2006"; config.gameNativeResolutions = "640x480, 1360x768"; + config.emulateCardreader = 1; config.gameType = FIGHTING; config.gameStatus = WORKING; config.width = 1360; @@ -1069,7 +1074,7 @@ int getNextIntOrAuto(char *saveptr, int defaultValue) { strcpy(nextToken, getNextToken(NULL, " ", &saveptr)); toLowerCase(nextToken); - if(strcmp(nextToken, "auto") == 0) + if (strcmp(nextToken, "auto") == 0) return defaultValue; return atoi(nextToken); @@ -1099,6 +1104,9 @@ int readConfig(FILE *configFile, EmulatorConfig *config) config->height = getNextIntOrAuto(saveptr, defaultValue); } + else if (strcmp(command, "BOOST_RENDER_RES") == 0) + config->boostRenderRes = atoi(getNextToken(NULL, " ", &saveptr)); + else if (strcmp(command, "EEPROM_PATH") == 0) strcpy(config->eepromPath, getNextToken(NULL, " ", &saveptr)); @@ -1121,7 +1129,13 @@ int readConfig(FILE *configFile, EmulatorConfig *config) } else if (strcmp(command, "EMULATE_CARDREADER") == 0) - config->emulateCardreader = atoi(getNextToken(NULL, " ", &saveptr)); + { + int defaultValue = config->emulateCardreader; + config->emulateCardreader = getNextIntOrAuto(saveptr, defaultValue); + } + + else if (strcmp(command, "EMULATE_TOUCHSCREEN") == 0) + config->emulateTouchscreen = atoi(getNextToken(NULL, " ", &saveptr)); else if (strcmp(command, "CARDFILE_01") == 0) strcpy(config->cardFile1, getNextToken(NULL, " ", &saveptr)); @@ -1237,6 +1251,15 @@ int readConfig(FILE *configFile, EmulatorConfig *config) else if (strcmp(command, "CUSTOM_CURSOR_HEIGHT") == 0) config->customCursorHeight = atoi(getNextToken(NULL, " ", &saveptr)); + else if (strcmp(command, "PH_TOUCH_CURSOR") == 0) + strcpy(config->phTouchCursor, getNextToken(NULL, " ", &saveptr)); + + else if (strcmp(command, "PH_TOUCH_CURSOR_WIDTH") == 0) + config->phTouchCursorWidth = atoi(getNextToken(NULL, " ", &saveptr)); + + else if (strcmp(command, "PH_TOUCH_CURSOR_HEIGHT") == 0) + config->phTouchCursorHeight = atoi(getNextToken(NULL, " ", &saveptr)); + else if (strcmp(command, "MJ4_ENABLED_ALL_THE_TIME") == 0) config->phMode = atoi(getNextToken(NULL, " ", &saveptr)); @@ -1380,6 +1403,8 @@ int readConfig(FILE *configFile, EmulatorConfig *config) strncpy(config->arcadeInputs.player2_button_9, getNextToken(NULL, " ", &saveptr), INPUT_STRING_LENGTH - 1); else if (strcmp(command, "PLAYER_2_BUTTON_10") == 0) strncpy(config->arcadeInputs.player2_button_10, getNextToken(NULL, " ", &saveptr), INPUT_STRING_LENGTH - 1); + else if (strcmp(command, "PLAYER_2_COIN") == 0) + strncpy(config->arcadeInputs.player2_coin, getNextToken(NULL, " ", &saveptr), INPUT_STRING_LENGTH - 1); // Analogue inputs else if (strcmp(command, "ANALOGUE_1") == 0) @@ -1496,6 +1521,7 @@ int initConfig(const char* configFilePath) config.emulateDriveboard = 0; config.emulateMotionboard = 0; config.emulateCardreader = 0; + config.emulateTouchscreen = 0; strcpy(config.cardFile1, "Card_01.crd"); strcpy(config.cardFile2, "Card_02.crd"); config.emulateJVS = 1; @@ -1508,6 +1534,7 @@ int initConfig(const char* configFilePath) strcpy(config.serial2Path, "/dev/ttyS1"); config.width = 640; config.height = 480; + config.boostRenderRes = 1; config.region = EX; config.freeplay = -1; config.showDebugMessages = 0; @@ -1528,13 +1555,16 @@ int initConfig(const char* configFilePath) config.fpsLimiter = 0; config.fpsTarget = 60; config.noSDL = 0; - config.phMode = 1; + config.phMode = 2; config.disableBuiltinFont = 0; config.disableBuiltinLogos = 0; config.hideCursor = 1; strcpy(config.customCursor, ""); config.customCursorWidth = 32; config.customCursorHeight = 32; + strcpy(config.phTouchCursor, ""); + config.phTouchCursorWidth = 32; + config.phTouchCursorHeight = 32; config.mj4EnabledAtT = 0; strcpy(config.or2IP, ""); diff --git a/src/lindbergh/config.h b/src/lindbergh/config.h index ff0385e..0f22635 100644 --- a/src/lindbergh/config.h +++ b/src/lindbergh/config.h @@ -202,7 +202,8 @@ typedef struct { char player2_button_8[INPUT_STRING_LENGTH]; char player2_button_9[INPUT_STRING_LENGTH]; char player2_button_10[INPUT_STRING_LENGTH]; - + char player2_coin[INPUT_STRING_LENGTH]; + // Analogue inputs char analogue_1[INPUT_STRING_LENGTH]; char analogue_2[INPUT_STRING_LENGTH]; @@ -225,6 +226,7 @@ typedef struct int emulateDriveboard; int emulateMotionboard; int emulateCardreader; + int emulateTouchscreen; char cardFile1[MAX_PATH_LENGTH]; char cardFile2[MAX_PATH_LENGTH]; int emulateJVS; @@ -236,6 +238,7 @@ typedef struct char serial2Path[MAX_PATH_LENGTH]; int width; int height; + int boostRenderRes; Colour lindberghColour; GameStatus gameStatus; GameType gameType; @@ -268,6 +271,9 @@ typedef struct char customCursor[MAX_PATH_LENGTH]; int customCursorWidth; int customCursorHeight; + char phTouchCursor[MAX_PATH_LENGTH]; + int phTouchCursorWidth; + int phTouchCursorHeight; int mj4EnabledAtT; char or2IP[16]; char or2Netmask[16]; diff --git a/src/lindbergh/customcursor.c b/src/lindbergh/customcursor.c new file mode 100644 index 0000000..0d9fb3f --- /dev/null +++ b/src/lindbergh/customcursor.c @@ -0,0 +1,229 @@ +#include +#include +#include +#include +#include +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" +#define STBI_ONLY_PNG +#define STBI_SUPPORT_ZLIB +#define STBI_NO_SIMD + + +#include +#include +#include + +#include "config.h" + +extern Display *x11Display; +extern Window window; + +void *customCursor; +void *phTouchCursor; +void *blankCursor; + +SDL_Surface *createSurfaceFromStb(unsigned char *data, int width, int height, int channels) +{ + Uint32 rmask, gmask, bmask, amask; + if (channels == 4) + { + rmask = 0x000000FF; + gmask = 0x0000FF00; + bmask = 0x00FF0000; + amask = 0xFF000000; + } + else if (channels == 3) + { + rmask = 0x000000FF; + gmask = 0x0000FF00; + bmask = 0x00FF0000; + amask = 0; + } + else + { + fprintf(stderr, "Unsupported image format with %d channels.\n", channels); + return NULL; + } + + return SDL_CreateRGBSurfaceFrom(data, width, height, channels * 8, width * channels, rmask, gmask, bmask, amask); +} + +int loadNewCursor(const char *cursorFileName, void **cursor, int customWidth, int customHeight) +{ + int width, height, channels; + unsigned char *imageData = stbi_load(cursorFileName, &width, &height, &channels, 0); + if (!imageData) + { + fprintf(stderr, "Failed to load image: %s\n", cursorFileName); + return 0; + } + + SDL_Surface *originalSurface = createSurfaceFromStb(imageData, width, height, channels); + if (!originalSurface) + { + stbi_image_free(imageData); + return 0; + } + + SDL_Surface *resizedSurface = + SDL_CreateRGBSurface(0, customWidth, customHeight, originalSurface->format->BitsPerPixel, originalSurface->format->Rmask, + originalSurface->format->Gmask, originalSurface->format->Bmask, originalSurface->format->Amask); + if (!resizedSurface) + { + fprintf(stderr, "SDL_CreateRGBSurface Error: %s\n", SDL_GetError()); + SDL_FreeSurface(originalSurface); + stbi_image_free(imageData); + return 0; + } + + SDL_Rect srcRect = {0, 0, originalSurface->w, originalSurface->h}; + SDL_Rect destRect = {0, 0, customWidth, customHeight}; + if (SDL_BlitScaled(originalSurface, &srcRect, resizedSurface, &destRect) != 0) + { + fprintf(stderr, "SDL_BlitScaled Error: %s\n", SDL_GetError()); + SDL_FreeSurface(resizedSurface); + SDL_FreeSurface(originalSurface); + stbi_image_free(imageData); + return 0; + } + + if (getConfig()->noSDL == 0) + { + *cursor = SDL_CreateColorCursor(resizedSurface, customWidth / 2, customHeight / 2); + if (!*cursor) + { + fprintf(stderr, "SDL_CreateColorCursor Error: %s\n", SDL_GetError()); + SDL_FreeSurface(resizedSurface); + SDL_FreeSurface(originalSurface); + stbi_image_free(imageData); + return 0; + } + + SDL_FreeSurface(resizedSurface); + SDL_FreeSurface(originalSurface); + } + else + { + XcursorImage *xcursor = XcursorImageCreate(resizedSurface->w, resizedSurface->h); + if (!xcursor) + return None; + + xcursor->xhot = customWidth / 2; + xcursor->yhot = customHeight / 2; + xcursor->width = resizedSurface->w; + xcursor->height = resizedSurface->h; + + // Convert SDL surface to Xcursor format (32-bit ARGB) + for (int y = 0; y < resizedSurface->h; ++y) + { + for (int x = 0; x < resizedSurface->w; ++x) + { + Uint32 pixel = ((Uint32 *)resizedSurface->pixels)[y * resizedSurface->w + x]; + Uint8 r, g, b, a; + SDL_GetRGBA(pixel, resizedSurface->format, &r, &g, &b, &a); + xcursor->pixels[y * resizedSurface->w + x] = (a << 24) | (r << 16) | (g << 8) | b; + } + } + + *cursor = (void*)XcursorImageLoadCursor(x11Display, xcursor); + XcursorImageDestroy(xcursor); + + } + return 1; +} + +void loadCursors() +{ + if (strcmp(getConfig()->customCursor, "") != 0) + { + if (!loadNewCursor(getConfig()->customCursor, (void *)&customCursor, getConfig()->customCursorWidth, + getConfig()->customCursorHeight)) + { + fprintf(stderr, "Custom cursor could not be loaded!\n"); + exit(1); + } + } + + if (strcmp(getConfig()->phTouchCursor, "") != 0) + { + if (!loadNewCursor(getConfig()->phTouchCursor, (void *)&phTouchCursor, getConfig()->phTouchCursorWidth, + getConfig()->phTouchCursorHeight)) + + { + fprintf(stderr, "Custom cursor could not be loaded!\n"); + exit(1); + } + } + + if(getConfig()->noSDL) + { + XColor dummyColor; + Pixmap blankPixmap; + blankPixmap = XCreatePixmap(x11Display, window, 1, 1, 1); + if (!blankPixmap) + { + fprintf(stderr, "Failed to create blank pixmap\n"); + } + + blankCursor = (void*)XCreatePixmapCursor(x11Display, blankPixmap, blankPixmap, &dummyColor, &dummyColor, 0, 0); + if (!blankCursor) + { + fprintf(stderr, "Failed to create blank cursor\n"); + XFreePixmap(x11Display, blankPixmap); + } + } +} + +void setCursor(void *cursor) +{ + if (getConfig()->noSDL == 0) + { + if (SDL_GetCursor() != NULL) + SDL_SetCursor(cursor); + } + else + { + XDefineCursor(x11Display, window, (Cursor)cursor); + XFlush(x11Display); + } +} + +void hideCursor() +{ + if (getConfig()->noSDL == 0) + { + SDL_ShowCursor(SDL_DISABLE); + } + else + { + XDefineCursor(x11Display, window, (Cursor)blankCursor); + XFlush(x11Display); + } +} + +void showCursor() +{ + if (getConfig()->noSDL == 0) + { + SDL_ShowCursor(SDL_ENABLE); + } + else + { + XDefineCursor(x11Display, window, (Cursor)customCursor); + XFlush(x11Display); + } +} + +void showPhCursor() +{ + if (getConfig()->noSDL == 0) + { + SDL_ShowCursor(SDL_ENABLE); + } + else + { + XDefineCursor(x11Display, window, (Cursor)phTouchCursor); + XFlush(x11Display); + } +} \ No newline at end of file diff --git a/src/lindbergh/customcursor.h b/src/lindbergh/customcursor.h new file mode 100644 index 0000000..edcd541 --- /dev/null +++ b/src/lindbergh/customcursor.h @@ -0,0 +1,10 @@ +#ifndef CUSTOM_CURSORS_H +#define CUSTOM_CURSORS_H + +int loadNewCursor(const char *cursorFileName, void **cursor, int customWidth, int customHeight); +void loadCursors(); +void setCursor(void *cursor); +void hideCursor(); +void showCursor(); +void showPhCursor(); +#endif diff --git a/src/lindbergh/eeprom.c b/src/lindbergh/eeprom.c index 4859806..02d1ef2 100644 --- a/src/lindbergh/eeprom.c +++ b/src/lindbergh/eeprom.c @@ -16,6 +16,8 @@ #define I2C_SEEK 2 #define I2C_WRITE 3 +extern uint32_t gId; + union i2c_smbus_data { uint8_t byte; uint16_t word; @@ -68,36 +70,40 @@ int initEeprom() setFreeplay(eeprom, getConfig()->freeplay); } - if ((getConfig()->crc32 == LETS_GO_JUNGLE_SPECIAL) || (getConfig()->crc32 == THE_HOUSE_OF_THE_DEAD_EX) || - (getConfig()->crc32 == THE_HOUSE_OF_THE_DEAD_4_SPECIAL) || - (getConfig()->crc32 == THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB)) + switch (gId) { + case LETS_GO_JUNGLE_SPECIAL: + case THE_HOUSE_OF_THE_DEAD_EX: + case THE_HOUSE_OF_THE_DEAD_4_SPECIAL: + case THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB: if (fixCreditSection(eeprom) != 0) { printf("Error initializing eeprom settings."); fclose(eeprom); return 1; } - } - - if (getConfig()->crc32 == HUMMER || getConfig()->crc32 == HUMMER_SDLX || getConfig()->crc32 == HUMMER_EXTREME || - getConfig()->crc32 == HUMMER_EXTREME_MDX) - { + break; + case HUMMER: + case HUMMER_SDLX: + case HUMMER_EXTREME: + case HUMMER_EXTREME_MDX: if (fixCoinAssignmentsHummer(eeprom) != 0) { printf("Error initializing eeprom settings."); fclose(eeprom); return 1; } - } - - if ((getConfig()->crc32 == OUTRUN_2_SP_SDX || getConfig()->crc32 == OUTRUN_2_SP_SDX_REVA) && strcmp(getConfig()->or2IP, "") != 0) - { - if (setIP(eeprom, getConfig()->or2IP, getConfig()->or2Netmask) != 0) + break; + case OUTRUN_2_SP_SDX: + case OUTRUN_2_SP_SDX_REVA: + if (strcmp(getConfig()->or2IP, "") != 0) { - printf("Error setting the new IP address."); - fclose(eeprom); - return 1; + if (setIP(eeprom, getConfig()->or2IP, getConfig()->or2Netmask) != 0) + { + printf("Error setting the new IP address."); + fclose(eeprom); + return 1; + } } } diff --git a/src/lindbergh/eeprom_settings.c b/src/lindbergh/eeprom_settings.c index 545ff01..8cb2642 100644 --- a/src/lindbergh/eeprom_settings.c +++ b/src/lindbergh/eeprom_settings.c @@ -3,7 +3,6 @@ #include #include -#include "config.h" #include "eeprom_settings.h" uint32_t crc32_table[255]; diff --git a/src/lindbergh/evdevinput.c b/src/lindbergh/evdevinput.c index 84e1d38..ffe5e31 100644 --- a/src/lindbergh/evdevinput.c +++ b/src/lindbergh/evdevinput.c @@ -59,6 +59,7 @@ ArcadeInput arcadeInputs[] = {{"TEST_BUTTON", 0, BUTTON_TEST, 1}, {"PLAYER_2_BUTTON_8", 2, BUTTON_8, 1}, {"PLAYER_2_BUTTON_9", 2, BUTTON_9, 1}, {"PLAYER_2_BUTTON_10", 2, BUTTON_10, 1}, + {"PLAYER_2_COIN", 2, COIN, 1}, {"ANALOGUE_1", 0, ANALOGUE_1, 1}, {"ANALOGUE_2", 0, ANALOGUE_2, 1}, @@ -921,18 +922,19 @@ static ControllerStatus listControllers(Controllers *controllers) strcat(controllerInput->inputName, "_"); strcat(controllerInput->inputName, codename(EV_KEY, code)); normaliseName(controllerInput->inputName); - if(snprintf(controllerInput->inputTechName, SIZE, "%s:KEY:%i", controllers->controller[i].path, code) >= 1024) { - // hum ok, truncated value - } - strcpy(controllerInput->inputTechNegName, "-"); // unassignable value (not "" while some conf are empty) + // if(snprintf(controllerInput->inputTechName, SIZE, "%s:KEY:%i", controllers->controller[i].path, + // code) >= 1024) { + // // hum ok, truncated value + // } + // strcpy(controllerInput->inputTechNegName, "-"); // unassignable value (not "" while some conf are empty) } } } if (test_bit(EV_ABS, bit[0])) { - ioctl(controller, EVIOCGBIT(EV_ABS, ABS_MAX), bit[EV_ABS]); - for (int code = 0; code < ABS_MAX; code++) + ioctl(controller, EVIOCGBIT(EV_ABS, KEY_MAX), bit[EV_ABS]); + for (int code = 0; code < KEY_MAX; code++) { if (test_bit(code, bit[EV_ABS])) { @@ -946,12 +948,14 @@ static ControllerStatus listControllers(Controllers *controllers) strcat(controllerInput->inputName, "_"); strcat(controllerInput->inputName, codename(EV_ABS, code)); normaliseName(controllerInput->inputName); - if(snprintf(controllerInput->inputTechName, SIZE, "%s:ABS:%i", controllers->controller[i].path, code) >= 1024) { - // hum ok, truncated value - } - if(snprintf(controllerInput->inputTechNegName, SIZE, "%s:ABS_NEG:%i", controllers->controller[i].path, code) >= 1024) { - // hum ok, truncated value - } + // if(snprintf(controllerInput->inputTechName, SIZE, "%s:ABS:%i", controllers->controller[i].path, + // code) >= 1024) { + // // hum ok, truncated value + // } + // if(snprintf(controllerInput->inputTechNegName, SIZE, "%s:ABS_NEG:%i", + // controllers->controller[i].path, code) >= 1024) { + // // hum ok, truncated value + // } ControllerInput *minControllerInput = &controllers->controller[i].inputs[controllers->controller[i].inputCount++]; @@ -960,12 +964,14 @@ static ControllerStatus listControllers(Controllers *controllers) minControllerInput->specialFunction = ANALOGUE_TO_DIGITAL_MIN; strcpy(minControllerInput->inputName, controllerInput->inputName); strcat(minControllerInput->inputName, "_MIN"); - if(snprintf(minControllerInput->inputTechName, SIZE, "%s:ABS:%i:MIN", controllers->controller[i].path, code) >= 1024) { - // hum ok, truncated value - } - if(snprintf(minControllerInput->inputTechNegName, SIZE, "%s:ABS_NEG:%i:MIN", controllers->controller[i].path, code) >= 1024) { - // hum ok, truncated value - } + // if(snprintf(minControllerInput->inputTechName, SIZE, "%s:ABS:%i:MIN", + // controllers->controller[i].path, code) >= 1024) { + // // hum ok, truncated value + // } + // if(snprintf(minControllerInput->inputTechNegName, SIZE, "%s:ABS_NEG:%i:MIN", + // controllers->controller[i].path, code) >= 1024) { + // // hum ok, truncated value + // } ControllerInput *maxControllerInput = &controllers->controller[i].inputs[controllers->controller[i].inputCount++]; @@ -974,24 +980,27 @@ static ControllerStatus listControllers(Controllers *controllers) maxControllerInput->specialFunction = ANALOGUE_TO_DIGITAL_MAX; strcpy(maxControllerInput->inputName, controllerInput->inputName); strcat(maxControllerInput->inputName, "_MAX"); - if(snprintf(maxControllerInput->inputTechName, SIZE, "%s:ABS:%i:MAX", controllers->controller[i].path, code) >= 1024) { - // hum ok, truncated value - } - if(snprintf(maxControllerInput->inputTechNegName, SIZE, "%s:ABS_NEG:%i:MAX", controllers->controller[i].path, code) >= 1024) { - // hum ok, truncated value - } - - ControllerInput *shakeControllerInput = - &controllers->controller[i].inputs[controllers->controller[i].inputCount++]; - shakeControllerInput->evType = EV_ABS; - shakeControllerInput->evCode = code; - shakeControllerInput->specialFunction = ANALOGUE_SHAKE; - strcpy(shakeControllerInput->inputName, controllerInput->inputName); - strcat(shakeControllerInput->inputName, "_SHAKE"); - if(snprintf(shakeControllerInput->inputTechName, SIZE, "%s:ABS:%i:SHAKE", controllers->controller[i].path, code) >= 1024) { - // hum ok, truncated value - } + // if(snprintf(maxControllerInput->inputTechName, SIZE, "%s:ABS:%i:MAX", + // controllers->controller[i].path, code) >= 1024) { + // // hum ok, truncated value + // } + // if(snprintf(maxControllerInput->inputTechNegName, SIZE, "%s:ABS_NEG:%i:MAX", + // controllers->controller[i].path, code) >= 1024) { + // // hum ok, truncated value + // } + // ControllerInput *shakeControllerInput = + // &controllers->controller[i].inputs[controllers->controller[i].inputCount++]; + // shakeControllerInput->evType = EV_ABS; + // shakeControllerInput->evCode = code; + // shakeControllerInput->specialFunction = ANALOGUE_SHAKE; + // strcpy(shakeControllerInput->inputName, controllerInput->inputName); + // strcat(shakeControllerInput->inputName, "_SHAKE"); + // if(snprintf(shakeControllerInput->inputTechName, SIZE, "%s:ABS:%i:SHAKE", + // controllers->controller[i].path, code) >= 1024) { + // // hum ok, truncated value + // } + // struct input_absinfo absoluteFeatures; ioctl(controller, EVIOCGABS(code), &absoluteFeatures); controllers->controller[i].absMin[code] = absoluteFeatures.minimum; @@ -1183,6 +1192,8 @@ char *getMapping(char *mapping) return "TEST_BUTTON"; if (strcmp(mapping, config->arcadeInputs.player1_coin) == 0) return "PLAYER_1_COIN"; + if (strcmp(mapping, config->arcadeInputs.player2_coin) == 0) + return "PLAYER_2_COIN"; // Player 1 controls if (strcmp(mapping, config->arcadeInputs.player1_button_start) == 0) @@ -1429,9 +1440,15 @@ ControllerStatus startControllerThreads(Controllers *controllers) if (strstr(input.name, "ANALOGUE") != NULL) controllers->controller[i].keyTriggers[controllers->controller[i].inputs[j].evCode].isAnalogue = 1; - if (strcmp(input.name, "PLAYER_1_COIN") == 0) { + if (strcmp(input.name, "PLAYER_1_COIN") == 0) + { controllers->controller[i].keyTriggers[controllers->controller[i].inputs[j].evCode].isCoin = 1; - } + } + + if (strcmp(input.name, "PLAYER_2_COIN") == 0) + { + controllers->controller[i].keyTriggers[controllers->controller[i].inputs[j].evCode].isCoin = 1; + } } break; diff --git a/src/lindbergh/evdevinput.h b/src/lindbergh/evdevinput.h index 373b131..462c30d 100644 --- a/src/lindbergh/evdevinput.h +++ b/src/lindbergh/evdevinput.h @@ -2,7 +2,7 @@ #include -#define SIZE 1024 +#define SIZE 128 #define CONTROLLER_THREAD_MAX 256 @@ -69,12 +69,12 @@ typedef struct typedef struct { char name[SIZE]; - char path[SIZE]; - char physicalLocation[SIZE]; + char path[320]; + char physicalLocation[128]; int absMax[ABS_MAX]; int absMin[ABS_MAX]; - ControllerInput inputs[SIZE]; + ControllerInput inputs[320]; int inputCount; ArcadeInput keyTriggers[KEY_MAX]; diff --git a/src/lindbergh/gluthooks.c b/src/lindbergh/gluthooks.c index 64b59de..88dd6cd 100644 --- a/src/lindbergh/gluthooks.c +++ b/src/lindbergh/gluthooks.c @@ -24,6 +24,7 @@ #include "border.h" #include "resolution.h" +extern uint32_t gId; extern SDL_Window *SDLwindow; extern char SDLgameTitle[]; extern fps_limit fpsLimit; @@ -36,7 +37,9 @@ void *idleFunc = NULL; void FGAPIENTRY glutInit(int *argcp, char **argv) { - if (*argcp > 1 && getConfig()->crc32 == SEGA_RACE_TV) + void FGAPIENTRY (*_glutInit)(int *argcp, char **argv) = dlsym(RTLD_NEXT, "glutInit"); + + if (*argcp > 1 && gId == SEGA_RACE_TV) { if (isTestMode()) { @@ -45,8 +48,14 @@ void FGAPIENTRY glutInit(int *argcp, char **argv) printf("Forced to use SDL to make Test mode render fine.\n"); } } - GLUTGame = true; + if (getConfig()->noSDL) + { + _glutInit(argcp, argv); + return; + } + + GLUTGame = true; initSDL(argcp, argv); } @@ -102,10 +111,13 @@ void FGAPIENTRY glutSwapBuffers(void) return; } - int gId = config->crc32; - if (gId == OUTRUN_2_SP_SDX || gId == OUTRUN_2_SP_SDX_REVA || gId == OUTRUN_2_SP_SDX_REVA_TEST || gId == OUTRUN_2_SP_SDX_REVA_TEST2 || - gId == OUTRUN_2_SP_SDX_TEST) + switch (gId) { + case OUTRUN_2_SP_SDX: + case OUTRUN_2_SP_SDX_REVA: + case OUTRUN_2_SP_SDX_REVA_TEST: + case OUTRUN_2_SP_SDX_REVA_TEST2: + case OUTRUN_2_SP_SDX_TEST: pollEvents(); } @@ -174,11 +186,15 @@ void FGAPIENTRY glutSetCursor(int glutCursor) if (getConfig()->noSDL) { void FGAPIENTRY (*_glutSetCursor)(int glutCursor) = dlsym(RTLD_NEXT, "glutSetCursor"); - _glutSetCursor(glutCursor); + if(strcmp(getConfig()->customCursor, "") == 0) + _glutSetCursor(glutCursor); return; } - SDL_Cursor *cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); - SDL_SetCursor(cursor); + if (strcmp(getConfig()->customCursor, "") == 0) + { + SDL_Cursor *cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); + SDL_SetCursor(cursor); + } } void FGAPIENTRY glutDisplayFunc(void (*callback)(void)) diff --git a/src/lindbergh/glxhooks.c b/src/lindbergh/glxhooks.c index aaeff97..c78ba3f 100644 --- a/src/lindbergh/glxhooks.c +++ b/src/lindbergh/glxhooks.c @@ -1,4 +1,3 @@ -#include #define GL_GLEXT_PROTOTYPES #ifndef __i386__ #define __i386__ @@ -20,6 +19,7 @@ #include #include #include +#include #include "fps_limiter.h" #include "sdlcalls.h" @@ -28,11 +28,12 @@ #include "border.h" bool sdlGame = false; +extern uint32_t gId; extern SDL_Window *SDLwindow; extern SDL_GLContext SDLcontext; extern char SDLgameTitle[]; extern fps_limit fpsLimit; -extern Window win; +extern Window window; void glXSwapBuffers(Display *dpy, GLXDrawable drawable) { @@ -43,14 +44,22 @@ void glXSwapBuffers(Display *dpy, GLXDrawable drawable) if (config->borderEnabled) drawGameBorder(config->width, config->height, config->whiteBorderPercentage, config->blackBorderPercentage); - int gId = getConfig()->crc32; - if (getConfig()->noSDL && (gId == OUTRUN_2_SP_SDX || gId == OUTRUN_2_SP_SDX_REVA || gId == OUTRUN_2_SP_SDX_REVA_TEST || - gId == OUTRUN_2_SP_SDX_REVA_TEST2 || gId == OUTRUN_2_SP_SDX_TEST)) + if (getConfig()->noSDL) { - XEvent event; - while (XPending(dpy)) + switch (gId) { - XNextEvent(dpy, &event); + case OUTRUN_2_SP_SDX: + case OUTRUN_2_SP_SDX_REVA: + case OUTRUN_2_SP_SDX_REVA_TEST: + case OUTRUN_2_SP_SDX_REVA_TEST2: + case OUTRUN_2_SP_SDX_TEST: + { + XEvent event; + while (XPending(dpy)) + { + XNextEvent(dpy, &event); + } + } } } else @@ -76,7 +85,7 @@ void glXSwapBuffers(Display *dpy, GLXDrawable drawable) if (getConfig()->noSDL) { - XStoreName(dpy, win, ""); + XStoreName(dpy, window, ""); return; } char windowTitle[512]; @@ -229,28 +238,37 @@ GLXFBConfig *glXChooseFBConfig(Display *dpy, int screen, const int *attrib_list, GLXFBConfig *(*_glXChooseFBConfig)(Display *dpy, int screen, const int *attrib_list, int *nelements) = dlsym(RTLD_NEXT, "glXChooseFBConfig"); - int gId = getConfig()->crc32; char *__GLX_VENDOR_LIBRARY_NAME = getenv("__GLX_VENDOR_LIBRARY_NAME"); char *__NV_PRIME_RENDER_OFFLOAD = getenv("__NV_PRIME_RENDER_OFFLOAD"); if (__GLX_VENDOR_LIBRARY_NAME == NULL) __GLX_VENDOR_LIBRARY_NAME = " "; if (__NV_PRIME_RENDER_OFFLOAD == NULL) __NV_PRIME_RENDER_OFFLOAD = " "; - if ((strcmp(__GLX_VENDOR_LIBRARY_NAME, "nvidia") == 0) && (strcmp(__NV_PRIME_RENDER_OFFLOAD, "1") == 0) && - ((gId == THE_HOUSE_OF_THE_DEAD_4_REVA) || (gId == THE_HOUSE_OF_THE_DEAD_4_REVB) || - (gId == THE_HOUSE_OF_THE_DEAD_4_REVC) || (gId == THE_HOUSE_OF_THE_DEAD_4_SPECIAL) || - (gId == THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB) || (gId == THE_HOUSE_OF_THE_DEAD_EX) || (gId == TOO_SPICY))) + + switch (gId) { - for (int i = 0; attrib_list[i] != None; i += 2) + case THE_HOUSE_OF_THE_DEAD_4_REVA: + case THE_HOUSE_OF_THE_DEAD_4_REVB: + case THE_HOUSE_OF_THE_DEAD_4_REVC: + case THE_HOUSE_OF_THE_DEAD_4_SPECIAL: + case THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB: + case THE_HOUSE_OF_THE_DEAD_EX: + case TOO_SPICY: + { + if (strcmp(__GLX_VENDOR_LIBRARY_NAME, "nvidia") == 0 && strcmp(__NV_PRIME_RENDER_OFFLOAD, "1") == 0) { - if (attrib_list[i] == GLX_DOUBLEBUFFER) + for (int i = 0; attrib_list[i] != None; i += 2) { - int *ptr = (int *)&attrib_list[i + 1]; - patchMemory((intptr_t)ptr, "01"); - setVariable((intptr_t)ptr, GLX_DONT_CARE); + if (attrib_list[i] == GLX_DOUBLEBUFFER) + { + int *ptr = (int *)&attrib_list[i + 1]; + patchMemory((intptr_t)ptr, "01"); + setVariable((intptr_t)ptr, GLX_DONT_CARE); + } } } } + } return _glXChooseFBConfig(dpy, screen, attrib_list, nelements); } @@ -306,20 +324,31 @@ GLXFBConfigSGIX *glXChooseFBConfigSGIX(Display *dpy, int screen, int *attrib_lis __GLX_VENDOR_LIBRARY_NAME = " "; if (__NV_PRIME_RENDER_OFFLOAD == NULL) __NV_PRIME_RENDER_OFFLOAD = " "; - if ((strcmp(__GLX_VENDOR_LIBRARY_NAME, "nvidia") == 0) && (strcmp(__NV_PRIME_RENDER_OFFLOAD, "1") == 0) && - ((gId == INITIALD_4_REVA) || (gId == INITIALD_4_REVB) || (gId == INITIALD_4_REVC) || (gId == INITIALD_4_REVD) || - (gId == INITIALD_4_REVG) || (gId == INITIALD_4_EXP_REVB) || (gId == INITIALD_4_EXP_REVC) || - gId == INITIALD_4_EXP_REVD)) + + switch (gId) { - for (int i = 0; attrib_list[i] != None; i += 2) + case INITIALD_4_REVA: + case INITIALD_4_REVB: + case INITIALD_4_REVC: + case INITIALD_4_REVD: + case INITIALD_4_REVG: + case INITIALD_4_EXP_REVB: + case INITIALD_4_EXP_REVC: + case INITIALD_4_EXP_REVD: + { + if (strcmp(__GLX_VENDOR_LIBRARY_NAME, "nvidia") == 0 && strcmp(__NV_PRIME_RENDER_OFFLOAD, "1") == 0) { - if (attrib_list[i] == GLX_DOUBLEBUFFER) + for (int i = 0; attrib_list[i] != None; i += 2) { - int *ptr = (int *)&attrib_list[i + 1]; - patchMemory((intptr_t)ptr, "01"); + if (attrib_list[i] == GLX_DOUBLEBUFFER) + { + int *ptr = (int *)&attrib_list[i + 1]; + patchMemory((intptr_t)ptr, "01"); + } } } } + } return glXChooseFBConfig(dpy, screen, attrib_list, nelements); } diff --git a/src/lindbergh/hook.c b/src/lindbergh/hook.c index 76746f8..4722a53 100644 --- a/src/lindbergh/hook.c +++ b/src/lindbergh/hook.c @@ -46,6 +46,7 @@ #include "fps_limiter.h" #include "evdevinput.h" #include "card_reader.h" +#include "touchscreen.h" #include "log.h" #include "resources/font.h" #include "resources/logo.h" @@ -80,9 +81,12 @@ int logoTGAidx = 0; uint32_t elf_crc = 0; +uint32_t gId = 0; + extern int hummerExtremeShaderFileIndex; extern bool cachedShaderFilesLoaded; extern char vf5StageNameAbbr[5]; +bool phShowCursorInGame = false; extern fps_limit fpsLimit; Controllers controllers = {0}; @@ -102,7 +106,9 @@ static void handleSegfault(int signal, siginfo_t *info, void *ptr) ucontext_t *ctx = ptr; // Get the address of the instruction causing the segfault - uint8_t *code = (uint8_t *)ctx->uc_mcontext.gregs[REG_EIP]; + // uint8_t *code = (uint8_t *)ctx->uc_mcontext.gregs[REG_EIP]; + greg_t eip_value = ctx->uc_mcontext.gregs[REG_EIP]; + uint8_t *code = (uint8_t *)(uintptr_t)eip_value; // Use uintptr_t to ensure proper alignment switch (*code) { @@ -171,9 +177,36 @@ static void handleSegfault(int signal, siginfo_t *info, void *ptr) } } +char *checkIDlike() +{ + FILE *file = fopen("/etc/os-release", "r"); + if (!file) + { + perror("Failed to open /etc/os-release"); + return NULL; + } + + char line[256]; + char *result = NULL; + + while (fgets(line, sizeof(line), file)) + { + if (strncmp(line, "ID_LIKE=", 8) == 0) + { + char *id_like = strchr(line, '='); + if (id_like) + { + result = strdup(id_like); + break; + } + } + } + fclose(file); + return result; +} + void __attribute__((constructor)) hook_init() { - // Get offsets of the Game's ELF and calculate CRC32. dl_iterate_phdr(callback, NULL); @@ -183,15 +216,27 @@ void __attribute__((constructor)) hook_init() act.sa_flags = SA_SIGINFO; sigaction(SIGSEGV, &act, NULL); - char *(*_getenv)(const char *name) = dlsym(RTLD_NEXT, "getenv"); - char* envPath = _getenv("LINDBERGH_CONFIG_PATH"); + char *envPath = getenv("LINDBERGH_CONFIG_PATH"); initConfig(envPath); + gId = getConfig()->crc32; + + char *id_like = checkIDlike(); + if (id_like == NULL) + { + log_warn("Unable to get system info on current OS"); + } + else if (strstr(id_like, "debian") == NULL) + { + log_warn("Seems like you're not in debian-like system. There might be unexpected issues."); + } + if (getConfig()->fpsLimiter == 1) { fpsLimit.targetFrameTime = 1000000 / getConfig()->fpsTarget; fpsLimit.frameEnd = Clock_now(); } + getGPUVendor(); if (initPatch() != 0) @@ -236,8 +281,6 @@ void __attribute__((constructor)) hook_init() if (initControllers(&controllers) != 0) exit(1); - - securityBoardSetDipResolution(getConfig()->width, getConfig()->height); printf("\nSEGA Lindbergh Emulator\nBy the Lindbergh Development Team 2025\n\n"); @@ -255,16 +298,26 @@ void __attribute__((constructor)) hook_init() } printf("\n"); - if (getConfig()->GPUVendor == ATI_GPU && - ((getConfig()->crc32 == LETS_GO_JUNGLE) || (getConfig()->crc32 == LETS_GO_JUNGLE_REVA) || - (getConfig()->crc32 == LETS_GO_JUNGLE_SPECIAL) || (getConfig()->crc32 == AFTER_BURNER_CLIMAX) || - (getConfig()->crc32 == AFTER_BURNER_CLIMAX_REVA) || (getConfig()->crc32 == AFTER_BURNER_CLIMAX_REVB) || - (getConfig()->crc32 == AFTER_BURNER_CLIMAX_SDX) || (getConfig()->crc32 == AFTER_BURNER_CLIMAX_SDX_REVA) || - (getConfig()->crc32 == AFTER_BURNER_CLIMAX_SE) || (getConfig()->crc32 == AFTER_BURNER_CLIMAX_SE_REVA) || - (getConfig()->crc32 == INITIALD_5_JAP_REVA) || (getConfig()->crc32 == INITIALD_5_JAP_REVF) || - (getConfig()->crc32 == INITIALD_5_EXP_20) || (getConfig()->crc32 == INITIALD_5_EXP_20A))) + switch (gId) { - printf("WARNING: Game %s is unsupported in AMD GPU with ATI driver\n", getGameName()); + case LETS_GO_JUNGLE: + case LETS_GO_JUNGLE_REVA: + case LETS_GO_JUNGLE_SPECIAL: + case AFTER_BURNER_CLIMAX: + case AFTER_BURNER_CLIMAX_REVA: + case AFTER_BURNER_CLIMAX_REVB: + case AFTER_BURNER_CLIMAX_SDX: + case AFTER_BURNER_CLIMAX_SDX_REVA: + case AFTER_BURNER_CLIMAX_SE: + case AFTER_BURNER_CLIMAX_SE_REVA: + case INITIALD_5_JAP_REVA: + case INITIALD_5_JAP_REVF: + case INITIALD_5_EXP_20: + case INITIALD_5_EXP_20A: + if (getConfig()->GPUVendor == ATI_GPU) + { + printf("WARNING: Game %s is unsupported in AMD GPU with ATI driver\n", getGameName()); + } } } @@ -272,9 +325,13 @@ DIR *opendir(const char *dirname) { DIR *(*_opendir)(const char *dirname) = dlsym(RTLD_NEXT, "opendir"); - int gId = getConfig()->crc32; - if (gId == INITIALD_5_EXP || gId == INITIALD_5_EXP_20 || gId == INITIALD_5_EXP_20A || gId == INITIALD_5_JAP_REVA || gId == INITIALD_5_JAP_REVF) + switch (gId) { + case INITIALD_5_EXP: + case INITIALD_5_EXP_20: + case INITIALD_5_EXP_20A: + case INITIALD_5_JAP_REVA: + case INITIALD_5_JAP_REVF: if (strcmp(dirname, "/tmp/") == 0) { return _opendir(dirname + 1); @@ -317,10 +374,11 @@ int open(const char *pathname, int flags, ...) if (strcmp(pathname, "/dev/ttyS0") == 0 || strcmp(pathname, "/dev/tts/0") == 0) { - if (getConfig()->emulateDriveboard == 0 && getConfig()->emulateRideboard == 0 && getConfig()->emulateCardreader == 0) + if (getConfig()->emulateDriveboard == 0 && getConfig()->emulateRideboard == 0 && getConfig()->emulateCardreader == 0 && + getConfig()->emulateTouchscreen == 0) return _open(getConfig()->serial1Path, flags, mode); - if (hooks[SERIAL0] != -1 && getConfig()->emulateCardreader && getConfig()->crc32 != R_TUNED) + if (hooks[SERIAL0] != -1 && getConfig()->emulateCardreader && gId != R_TUNED) { return hooks[SERIAL0]; } @@ -328,7 +386,7 @@ int open(const char *pathname, int flags, ...) hooks[SERIAL0] = _open(HOOK_FILE_NAME, flags, mode); printf("Warning: SERIAL0 Opened %d\n", hooks[SERIAL0]); - if (getConfig()->emulateCardreader == 1 && getConfig()->crc32 != R_TUNED) + if (getConfig()->emulateCardreader == 1 && gId != R_TUNED) cardReaderSetFd(0, hooks[SERIAL0], getConfig()->cardFile1); return hooks[SERIAL0]; @@ -339,7 +397,7 @@ int open(const char *pathname, int flags, ...) if (getConfig()->emulateDriveboard == 0 && getConfig()->emulateMotionboard == 0 && getConfig()->emulateCardreader == 0) return _open(getConfig()->serial2Path, flags, mode); - if (hooks[SERIAL1] != -1 && getConfig()->emulateCardreader && getConfig()->crc32 != R_TUNED) + if (hooks[SERIAL1] != -1 && getConfig()->emulateCardreader && gId != R_TUNED) { return hooks[SERIAL1]; } @@ -393,6 +451,11 @@ FILE *fopen(const char *restrict pathname, const char *restrict mode) { FILE *(*_fopen)(const char *restrict pathname, const char *restrict mode) = dlsym(RTLD_NEXT, "fopen"); + if (strcmp(pathname, "/proc/net/route") == 0) + { + return NULL; + } + if (strcmp(pathname, "/root/lindbergrc") == 0) { return _fopen("lindbergrc", mode); @@ -515,13 +578,6 @@ FILE *fopen(const char *restrict pathname, const char *restrict mode) return 0; } - if (strcmp("./../fs/data/cse_credit.bnk", pathname) == 0) - { - void *addr = __builtin_return_address(0); - fileHooks[FILE_HARLEY] = _fopen(pathname, mode); - return fileHooks[FILE_HARLEY]; - } - if (cachedShaderFilesLoaded) { void *addr = __builtin_return_address(0); @@ -554,15 +610,35 @@ FILE *fopen(const char *restrict pathname, const char *restrict mode) } } - int gId = getConfig()->crc32; - if (gId == INITIALD_5_EXP || gId == INITIALD_5_EXP_20 || gId == INITIALD_5_EXP_20A || gId == INITIALD_5_JAP_REVA || gId == INITIALD_5_JAP_REVF) + switch (gId) { + case INITIALD_5_EXP: + case INITIALD_5_EXP_20: + case INITIALD_5_EXP_20A: + case INITIALD_5_JAP_REVA: + case INITIALD_5_JAP_REVF: if (strncmp(pathname, "/tmp/", 5) == 0) { return fopen(pathname + 1, mode); } } + if (gId == PRIMEVAL_HUNT) + { + if (strstr(pathname, "/data/lua/texture/start_stage") != NULL) + phShowCursorInGame = true; + else if (strstr(pathname, "/data/texture/weapon_select/") != NULL) + phShowCursorInGame = false; + else if (strstr(pathname, "/data/texture/stage_select/") != NULL) + phShowCursorInGame = false; + else if (strstr(pathname, "/data/texture/name_entry/") != NULL) + phShowCursorInGame = false; + else if (strstr(pathname, "/data/texture/game_end/") != NULL) + phShowCursorInGame = false; + else if (strstr(pathname, "/data/lua/stage/bonus_0") != NULL) + phShowCursorInGame = true; + } + // printf("Path= %s\n", pathname); return _fopen(pathname, mode); @@ -636,28 +712,31 @@ FILE *fopen64(const char *pathname, const char *mode) } } - if ((getConfig()->crc32 == HUMMER) || (getConfig()->crc32 == HUMMER_SDLX) || - (getConfig()->crc32 == HUMMER_EXTREME) || (getConfig()->crc32 == HUMMER_EXTREME_MDX)) + int idx; + switch (gId) { - int idx; + case HUMMER: + case HUMMER_SDLX: + case HUMMER_EXTREME: + case HUMMER_EXTREME_MDX: if (shaderFileInList(pathname, &idx)) { hummerExtremeShaderFileIndex = idx; } - } - - if ((getConfig()->crc32 == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA || getConfig()->crc32 == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB || - getConfig()->crc32 == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000) && - (getConfig()->GPUVendor != NVIDIA_GPU && getConfig()->GPUVendor != ATI_GPU)) - { - char *filename = basename((char *)pathname); - if (strstr(filename, "light_") || strstr(filename, "glow_")) + break; + case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA: + case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB: + case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000: + if (getConfig()->GPUVendor != NVIDIA_GPU && getConfig()->GPUVendor != ATI_GPU) { - printf("Stage: %s\n", filename); - char *start = strchr(filename, '_') + 1; - char *end = strstr(filename, ".txt"); - strncpy(vf5StageNameAbbr, start, end - start); - vf5StageNameAbbr[end - start] = '\0'; + char *filename = basename((char *)pathname); + if (strstr(filename, "light_") || strstr(filename, "glow_")) + { + char *start = strchr(filename, '_') + 1; + char *end = strstr(filename, ".txt"); + strncpy(vf5StageNameAbbr, start, end - start); + vf5StageNameAbbr[end - start] = '\0'; + } } } @@ -785,6 +864,11 @@ ssize_t read(int fd, void *buf, size_t count) // If we don't hook the serial just reply with nothing if (fd == hooks[SERIAL0] || fd == hooks[SERIAL1]) { + if (gId == PRIMEVAL_HUNT && getConfig()->emulateTouchscreen == 1) + { + phRead(fd, buf, count); + return 1; + } return -1; } @@ -817,10 +901,10 @@ size_t fread(void *buf, size_t size, size_t count, FILE *stream) return freadReplace(buf, size, count, fileRead[FILE_RW2]); } - if (stream == fileHooks[FILE_HARLEY]) - { - return harleyFreadReplace(buf, size, count, fileHooks[FILE_HARLEY]); - } + // if (stream == fileHooks[FILE_HARLEY]) + // { + // return harleyFreadReplace(buf, size, count, fileHooks[FILE_HARLEY]); + // } if (stream == fileHooks[FILE_FONT_ABC]) { @@ -926,7 +1010,7 @@ ssize_t write(int fd, const void *buf, size_t count) return driveboardWrite(fd, buf, count); } - if (fd == hooks[SERIAL1] && getConfig()->emulateDriveboard && getConfig()->crc32 != R_TUNED) + if (fd == hooks[SERIAL1] && getConfig()->emulateDriveboard && gId != R_TUNED) { return driveboardWrite(fd, buf, count); } @@ -960,10 +1044,9 @@ int ioctl(int fd, unsigned int request, void *data) return baseboardIoctl(fd, request, data); } - // Just accept any IOCTL on serial ports and ignore it if (fd == hooks[SERIAL0] || fd == hooks[SERIAL1]) { - if (request == 0x541b && getConfig()->crc32 == R_TUNED && fd == hooks[SERIAL1]) + if (request == 0x541b && gId == R_TUNED && fd == hooks[SERIAL1]) { uint8_t d = 1; memcpy(data, &d, sizeof(uint8_t)); @@ -1232,26 +1315,40 @@ int setenv(const char *name, const char *value, int overwrite) char *getenv(const char *name) { char *(*_getenv)(const char *name) = dlsym(RTLD_NEXT, "getenv"); - int gId = getConfig()->crc32; - if ((strcmp(name, "TEA_DIR") == 0) && - ((gId == VIRTUA_TENNIS_3) || (gId == VIRTUA_TENNIS_3_TEST) || (gId == VIRTUA_TENNIS_3_REVA) || - (gId == VIRTUA_TENNIS_3_REVA_TEST) || (gId == VIRTUA_TENNIS_3_REVB) || (gId == VIRTUA_TENNIS_3_REVB_TEST) || - (gId == VIRTUA_TENNIS_3_REVC) || (gId == VIRTUA_TENNIS_3_REVC_TEST) || ((gId == RAMBO)) || (gId == TOO_SPICY))) + + if (strcmp(name, "TEA_DIR") == 0) { - if (getcwd(envpath, 100) == NULL) - return ""; - char *ptr = strrchr(envpath, '/'); - if (ptr == NULL) - return ""; - *ptr = '\0'; - return envpath; - } - else if (strcmp(name, "TEA_DIR") == 0) - { - if (getcwd(envpath, 100) == NULL) - return ""; - return envpath; + switch (gId) + { + case VIRTUA_TENNIS_3: + case VIRTUA_TENNIS_3_TEST: + case VIRTUA_TENNIS_3_REVA: + case VIRTUA_TENNIS_3_REVA_TEST: + case VIRTUA_TENNIS_3_REVB: + case VIRTUA_TENNIS_3_REVB_TEST: + case VIRTUA_TENNIS_3_REVC: + case VIRTUA_TENNIS_3_REVC_TEST: + case RAMBO: + case TOO_SPICY: + { + if (getcwd(envpath, 100) == NULL) + return ""; + char *ptr = strrchr(envpath, '/'); + if (ptr == NULL) + return ""; + *ptr = '\0'; + return envpath; + } + break; + default: + { + if (getcwd(envpath, 100) == NULL) + return ""; + return envpath; + } + } } + if (strcmp(name, "__GL_SYNC_TO_VBLANK") == 0) { return ""; @@ -1292,7 +1389,7 @@ struct tm *localtime_r(const time_t *timep, struct tm *result) struct tm *(*_localtime_r)(const time_t *, struct tm *) = (struct tm * (*)(const time_t *, struct tm *)) dlsym(RTLD_NEXT, "localtime_r"); - if ((getConfig()->crc32 == MJ4_REVG || getConfig()->crc32 == MJ4_EVO) && getConfig()->mj4EnabledAtT == 1) + if ((gId == MJ4_REVG || gId == MJ4_EVO) && getConfig()->mj4EnabledAtT == 1) { time_t target_time = 1735286445; struct tm *res = _localtime_r(&target_time, result); diff --git a/src/lindbergh/input.c b/src/lindbergh/input.c index 9aa8530..82f4548 100644 --- a/src/lindbergh/input.c +++ b/src/lindbergh/input.c @@ -1,11 +1,15 @@ #ifndef __i386__ #define __i386__ +#include "customcursor.h" #endif #undef __x86_64__ #include #include "jvs.h" #include "config.h" +#include "customcursor.h" +#include "patch.h" +#include "touchscreen.h" #include #include @@ -20,6 +24,12 @@ GameType gameType = SHOOTING; int jvsAnalogueInBits = 10; extern int phX, phY, phW, phH; +extern int phX2, phY2, phW2, phH2; +int phIsDragging = 0; + +extern void *customCursor; +extern void *phTouchCursor; +extern bool phShowCursorInGame; int initInput() { @@ -35,6 +45,105 @@ int initInput() return 0; } +void phTouchScreenCursor(int mX, int mY, int *motX, int *motY) +{ + if (getConfig()->emulateTouchscreen) + { + switch (getConfig()->phMode) + { + case 0: + case 2: + case 3: + if ((mX >= phX2 && mX <= (phX2 + phW2) && mY >= phY2 && mY <= (phY2 + phH2)) && getConfig()->hideCursor == 0) + { + setCursor(phTouchCursor); + showPhCursor(); + } + else if (getConfig()->hideCursor == 1 || phShowCursorInGame == false) + { + hideCursor(); + } + else if (phShowCursorInGame && getConfig()->hideCursor == 0) + { + setCursor(customCursor); + showCursor(); + } + break; + case 4: + if ((mX >= phX2 && mX <= (phX2 + phW2) && mY >= (phY2 + phH) && mY <= (phY2 + (phH2 + phH))) && getConfig()->hideCursor == 0) + { + setCursor(phTouchCursor); + showPhCursor(); + } + else if (getConfig()->hideCursor == 1 || phShowCursorInGame == false) + { + hideCursor(); + } + else if (phShowCursorInGame && getConfig()->hideCursor == 0) + { + setCursor(customCursor); + showCursor(); + } + } + } + if (mX < phX) + *motX = phX; + if (mX > (phW + phX)) + *motX = (phW + phX) - 1; + if (mY > phH + phY) + *motY = (phH + phY) - 1; + if (mY < phY) + *motY = phY; +} + +void phTouchClick(int mX, int mY, int type) +{ + int x, y; + bool insideTouchScreen = false; + switch (getConfig()->phMode) + { + case 0: + case 2: + case 3: + if (mX >= phX2 && mX <= (phX2 + phW2) && mY >= phY2 && mY <= (phY2 + phH2)) + { + x = mX - phW; + y = mY - phY2; + insideTouchScreen = true; + } + break; + case 4: + if (mX >= phX2 && mX <= (phX2 + phW2) && mY >= (phY2 + phH) && mY <= (phY2 + (phH2 + phH))) + { + x = mX - phX2; + y = mY - phH; + insideTouchScreen = true; + } + } + if (insideTouchScreen) + { + if (type == ButtonPress) + phCoordinates(x, y, phW2, phH2, ButtonPress); + else if (type == SDL_MOUSEBUTTONDOWN) + phCoordinates(x, y, phW2, phH2, SDL_MOUSEBUTTONDOWN); + else if (type == ButtonRelease) + phCoordinates(x, y, phW2, phH2, ButtonRelease); + else if (type == SDL_MOUSEBUTTONUP) + phCoordinates(x, y, phW2, phH2, SDL_MOUSEBUTTONUP); + else if (type == MotionNotify) + phCoordinates(x, y, phW2, phH2, MotionNotify); + else if (type == SDL_MOUSEMOTION) + phCoordinates(x, y, phW2, phH2, SDL_MOUSEMOTION); + } + else + { + if (getConfig()->noSDL) + setSwitch(PLAYER_1, BUTTON_1, type == ButtonPress); + else + setSwitch(PLAYER_1, BUTTON_1, type == SDL_MOUSEBUTTONDOWN); + } +} + /** * Button mapping used for driving games */ @@ -281,16 +390,15 @@ int XNextEventShooting(Display *display, XEvent *event_return, int returnValue) { int mX = event_return->xmotion.x; int mY = event_return->xmotion.y; - if (mX < phX) - mX = phX; - if (mX > (phW + phX)) - mX = (phW + phX) - 1; - if (mY > phH + phY) - mY = (phH + phY) - 1; - if (mY < phY) - mY = phY; - setAnalogue(ANALOGUE_1, ((double)(mX - phX) / (double)phW) * pow(2, jvsAnalogueInBits)); - setAnalogue(ANALOGUE_2, ((double)(mY - phY) / (double)phH) * pow(2, jvsAnalogueInBits)); + + if (phIsDragging) + phTouchClick(mX, mY, event_return->type); + + int motX = mX, motY = mY; + phTouchScreenCursor(mX, mY, &motX, &motY); + + setAnalogue(ANALOGUE_1, ((double)(motX - phX) / (double)phW) * pow(2, jvsAnalogueInBits)); + setAnalogue(ANALOGUE_2, ((double)(motY - phY) / (double)phH) * pow(2, jvsAnalogueInBits)); } else { @@ -335,7 +443,17 @@ int XNextEventShooting(Display *display, XEvent *event_return, int returnValue) { if (event_return->xbutton.button == 1) // Trigger { - setSwitch(PLAYER_1, BUTTON_1, event_return->type == ButtonPress); + if (getConfig()->crc32 == PRIMEVAL_HUNT && getConfig()->emulateTouchscreen) + { + int mX = event_return->xmotion.x; + int mY = event_return->xmotion.y; + phTouchClick(mX, mY, event_return->type); + phIsDragging = (event_return->type == ButtonPress ? 1 : 0); + } + else + { + setSwitch(PLAYER_1, BUTTON_1, event_return->type == ButtonPress); + } } else if (event_return->xbutton.button == 3) // Reload { @@ -534,16 +652,15 @@ void sdlEventShooting(SDL_Event *event) { int mX = event->motion.x; int mY = event->motion.y; - if (mX < phX) - mX = phX; - if (mX > (phW + phX)) - mX = (phW + phX) - 1; - if (mY > phH + phY) - mY = (phH + phY) - 1; - if (mY < phY) - mY = phY; - setAnalogue(ANALOGUE_1, ((double)(mX - phX) / (double)phW) * pow(2, jvsAnalogueInBits)); - setAnalogue(ANALOGUE_2, ((double)(mY - phY) / (double)phH) * pow(2, jvsAnalogueInBits)); + + if (phIsDragging) + phTouchClick(mX, mY, event->type); + + int motX = mX, motY = mY; + phTouchScreenCursor(mX, mY, &motX, &motY); + + setAnalogue(ANALOGUE_1, ((double)(motX - phX) / (double)phW) * pow(2, jvsAnalogueInBits)); + setAnalogue(ANALOGUE_2, ((double)(motY - phY) / (double)phH) * pow(2, jvsAnalogueInBits)); } else { @@ -587,7 +704,17 @@ void sdlEventShooting(SDL_Event *event) { if (event->button.button == SDL_BUTTON_LEFT) // Trigger { - setSwitch(PLAYER_1, BUTTON_1, event->type == SDL_MOUSEBUTTONDOWN); + if (getConfig()->crc32 == PRIMEVAL_HUNT && getConfig()->emulateTouchscreen) + { + int mX = event->motion.x; + int mY = event->motion.y; + phTouchClick(mX, mY, event->type); + phIsDragging = (event->type == SDL_MOUSEBUTTONDOWN ? 1 : 0); + } + else + { + setSwitch(PLAYER_1, BUTTON_1, event->type == SDL_MOUSEBUTTONDOWN); + } } else if (event->button.button == SDL_BUTTON_RIGHT) // Reload { diff --git a/src/lindbergh/lindbergh.c b/src/lindbergh/lindbergh.c index 3eb7f30..e143b1b 100644 --- a/src/lindbergh/lindbergh.c +++ b/src/lindbergh/lindbergh.c @@ -85,6 +85,7 @@ uint32_t cleanElfCRC32[] = { 0x9BFD0D98, // DVP-0019D | id4.elf 0x9CF9BBCC, // DVP-0019G | id4.elf 0xFA0F6AB0, // DVP-0027A | apacheM.elf + 0x5A7F315E, // DVP-0027A | apachetestM.elf 0x9D414D18, // DVP-0029A | vsg 0xC345E213, // DVP-0030B | id4.elf 0x98E6A516, // DVP-0030C | id4.elf @@ -182,6 +183,7 @@ void isCleanElf(char *command) printf("\033[1;31m"); printf("Warning: The ELF you are running is not Clean and might cause unwanted behavior.\n"); printf(" Make sure you ELF and game dump are clean before reporting issues.\n"); + printf(" If you are sure the ELF is clean, please report it to us.\n"); printf("\033[0m"); } } @@ -215,7 +217,7 @@ void testModePath(char *name) if (strcmp(name, "./apacheM.elf") == 0) { - strcpy(name, "./apacheTestM.elf"); + strcpy(name, "./apachetestM.elf"); return; } @@ -233,7 +235,7 @@ void testModePath(char *name) * Makes sure the environment variables are set correctly * to run the game. */ -void setEnvironmentVariables(int isFlatpak, int zink) +void setEnvironmentVariables(int isFlatpak, int zink, int nvidia) { // Ensure the library path is set correctly char libraryPath[128] = {0}; @@ -254,9 +256,15 @@ void setEnvironmentVariables(int isFlatpak, int zink) setenv(LD_PRELOAD, PRELOAD_FILE_NAME, 1); else setenv(LD_PRELOAD, PRELOAD_FILE_FLATPAK, 1); - - if(zink) + + if (zink) setenv("MESA_LOADER_DRIVER_OVERRIDE", "zink", 1); + + if (nvidia) + { + setenv("__GLX_VENDOR_LIBRARY_NAME", "nvidia", 1); + setenv("__NV_PRIME_RENDER_OFFLOAD", "1", 1); + } } /** @@ -268,6 +276,8 @@ void printUsage(char *argv[]) printf("Options:\n"); printf(" --test | -t Runs the test mode\n"); printf(" --segaboot | -s Runs segaboot\n"); + printf(" --zink | -z Runs with Zink\n"); + printf(" --nvidia | -n Runs with nVidia GPU when is as a secondary GPU in a laptop\n"); printf(" --gdb Runs with GDB\n"); printf(" --list-controllers Lists available controllers and inputs\n"); printf(" --version Displays the version of the loader and team's names\n"); @@ -408,6 +418,7 @@ int main(int argc, char *argv[]) int testMode = 0; int gdb = 0; int zink = 0; + int nvidia = 0; int forceGame = 0; int segaboot = 0; char extConfigPath[PATH_MAX] = {0}; @@ -433,19 +444,25 @@ int main(int argc, char *argv[]) continue; } - if (strcmp(argv[i], "--zink") == 0) + if (strcmp(argv[i], "-z") == 0 || strcmp(argv[i], "--ziink") == 0) { zink = 1; continue; } - + + if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--nvidia") == 0) + { + nvidia = 1; + continue; + } + if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--config") == 0) { - if (i+1 >= argc) + if (i + 1 >= argc) { break; } - strncpy(extConfigPath, argv[i+1], PATH_MAX); + strncpy(extConfigPath, argv[i + 1], PATH_MAX); i += 1; continue; } @@ -455,8 +472,8 @@ int main(int argc, char *argv[]) } // Ensure environment variables are set correctly - setEnvironmentVariables(isFlatpak, zink); - + setEnvironmentVariables(isFlatpak, zink, nvidia); + char command[128] = {0}; strcpy(command, "./"); if (forceGame) @@ -492,7 +509,7 @@ int main(int argc, char *argv[]) if (extConfigPath[0] != '\0') { - setenv(LINDBERGH_CONFIG_PATH,extConfigPath,1); + setenv(LINDBERGH_CONFIG_PATH, extConfigPath, 1); } log_info("Starting $ %s", command); diff --git a/src/lindbergh/patch.c b/src/lindbergh/patch.c index 473fa73..ccbb639 100644 --- a/src/lindbergh/patch.c +++ b/src/lindbergh/patch.c @@ -1,13 +1,11 @@ #ifndef _GNU_SOURCE #define _GNU_SOURCE -#include #endif #include #define GL_GLEXT_PROTOTYPES #include "patch.h" #include -#include #include #include @@ -24,13 +22,19 @@ #include "shader_patches.h" #include "glxhooks.h" #include "log.h" +#include "customcursor.h" +extern uint32_t gId; char elfID[4]; void *amDipswContextAddr; extern void *glVertex3fPatchRetAddrABC[4]; extern void *glVertex3fNoPatchRetAddrABC[4]; void *hod4CursorHideShowCAVEAddress; +extern void *customCursor; +extern void *phTouchCursor; +extern void *blankCursor; + void setVariable(size_t address, size_t value) { int pagesize = sysconf(_SC_PAGE_SIZE); @@ -175,7 +179,6 @@ int amDongleUpdate() int amDongleUserInfoEx(int a, int b, char *_arcadeContext) { - uint32_t gId = getConfig()->crc32; char *gameID; switch (gId) { @@ -322,9 +325,8 @@ int or2snprintf(char *s, size_t n, const char *format, ...) return ret; } - // printf hook, used by OR2 -int patchedPrintf(char *format,...) +int patchedPrintf(char *format, ...) { if (format == NULL) return 0; @@ -370,7 +372,7 @@ void hod4CursorHideShow(int param1) { if (hod4PrevValue != 3 || hod4InTutorial) { - SDL_ShowCursor(SDL_DISABLE); + hideCursor(); } hod4PrevValue = 0; } @@ -379,7 +381,7 @@ void hod4CursorHideShow(int param1) { if (!hod4InTutorial) { - SDL_ShowCursor(SDL_ENABLE); + showCursor(); hod4PrevValue = 3; } } @@ -392,7 +394,7 @@ void hod4CursorHideShow(int param1) case 5: case 11: { - SDL_ShowCursor(SDL_DISABLE); + hideCursor(); } } } @@ -421,8 +423,9 @@ int hod4VsPrintf(char *str, const char *format, va_list arg) int initPatch() { EmulatorConfig *config = getConfig(); + int GPUVendor = getConfig()->GPUVendor; - switch (config->crc32) + switch (gId) { case AFTER_BURNER_CLIMAX: // DVP-0009 { @@ -440,7 +443,7 @@ int initPatch() detourFunction(0x081e2a9c, amDipswInit); detourFunction(0x081e2b38, amDipswExit); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804e1e4, gl_ProgramStringARB); } @@ -462,7 +465,7 @@ int initPatch() detourFunction(0x081e31e4, amDipswInit); detourFunction(0x081e3280, amDipswExit); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804e1e4, gl_ProgramStringARB); } @@ -484,7 +487,7 @@ int initPatch() detourFunction(0x081e3248, amDipswInit); detourFunction(0x081e32e4, amDipswExit); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804e1ec, gl_ProgramStringARB); } @@ -505,7 +508,7 @@ int initPatch() detourFunction(0x081e47a4, amDipswInit); detourFunction(0x081e4840, amDipswExit); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804e244, gl_ProgramStringARB); } @@ -527,7 +530,7 @@ int initPatch() detourFunction(0x081e478c, amDipswInit); detourFunction(0x081e4828, amDipswExit); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804e24c, gl_ProgramStringARB); } @@ -549,7 +552,7 @@ int initPatch() detourFunction(0x081e3294, amDipswInit); detourFunction(0x081e3330, amDipswExit); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804e1e4, gl_ProgramStringARB); } @@ -571,7 +574,7 @@ int initPatch() detourFunction(0x081e327c, amDipswInit); detourFunction(0x081e3318, amDipswExit); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804e1ec, gl_ProgramStringARB); } @@ -601,7 +604,7 @@ int initPatch() detourFunction(0x080e7f94, stubRetZero); cacheModedShaderFiles(); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { gsEvoElfShaderPatcher(); detourFunction(0x0804c334, gl_ProgramStringARB); @@ -623,7 +626,7 @@ int initPatch() detourFunction(0x08394825, amDipswGetData); detourFunction(0x08395da5, amDongleUserInfoEx); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { cacheModedShaderFiles(); loadLibCg(); @@ -910,7 +913,7 @@ int initPatch() setVariable(0x0857f0e9, 0x000126e9); // Avoid Full Screen set from Game patchMemory(0x087bc56c, "ab"); // Skips initialization - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x08078860, gl_MultiTexCoord2fARB); detourFunction(0x080788d0, gl_Color4ub); @@ -965,7 +968,7 @@ int initPatch() setVariable(0x0857ee69, 0x000126e9); // Avoid Full Screen set from Game patchMemory(0x087bc2ec, "eb"); // Skips initialization - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x08078860, gl_MultiTexCoord2fARB); detourFunction(0x080788d0, gl_Color4ub); @@ -1020,7 +1023,7 @@ int initPatch() setVariable(0x08580979, 0x000126e9); // Avoid Full Screen set from Game patchMemory(0x087beb6c, "5b"); // Skips initialization - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x080788ec, gl_MultiTexCoord2fARB); detourFunction(0x0807895c, gl_Color4ub); @@ -1076,7 +1079,7 @@ int initPatch() patchMemory(0x08799adc, "df"); // Skips initialization setVariable(0x085593c9, 0x000126e9); // Avoid Full Screen set from Game - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x08078980, gl_MultiTexCoord2fARB); detourFunction(0x080789f0, gl_Color4ub); @@ -1132,7 +1135,7 @@ int initPatch() patchMemory(0x08799d9c, "cf"); // Skips initialization setVariable(0x08559609, 0x000126e9); // Avoid Full Screen set from Game - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x080789a4, gl_MultiTexCoord2fARB); detourFunction(0x08078a14, gl_Color4ub); @@ -1188,7 +1191,7 @@ int initPatch() patchMemory(0x087a2efc, "ff"); // Skips initialization setVariable(0x08561e79, 0x000126e9); // Avoid Full Screen set from Game - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x080789a4, gl_MultiTexCoord2fARB); detourFunction(0x08078a14, gl_Color4ub); @@ -1244,7 +1247,7 @@ int initPatch() patchMemory(0x087a025c, "6f"); // Skips initialization setVariable(0x0855f519, 0x000126e9); // Avoid Full Screen set from Game - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x080789a4, gl_MultiTexCoord2fARB); detourFunction(0x08078a14, gl_Color4ub); @@ -1300,7 +1303,7 @@ int initPatch() patchMemory(0x087e9ebc, "3f36"); // Skips initialization setVariable(0x08599819, 0x000126e9); // Avoid Full Screen set from Game - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0807a298, gl_MultiTexCoord2fARB); detourFunction(0x0807a308, gl_Color4ub); @@ -1358,7 +1361,7 @@ int initPatch() patchMemory(0x08789a49, "e92601000090"); // Prevents Full Screen set from the game // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0807a3f0, gl_MultiTexCoord2fARB); detourFunction(0x0807a470, gl_Color4ub); @@ -1424,7 +1427,7 @@ int initPatch() detourFunction(0x089382e0, stubRetZero); // Eliminates amsInit Function // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0807a6c0, gl_MultiTexCoord2fARB); detourFunction(0x0807a740, gl_Color4ub); @@ -1490,7 +1493,7 @@ int initPatch() detourFunction(0x08938530, stubRetZero); // Eliminates amsInit Function // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0807a6c0, gl_MultiTexCoord2fARB); detourFunction(0x0807a740, gl_Color4ub); @@ -1548,7 +1551,7 @@ int initPatch() patchMemory(0x08441f99, "eb60"); // tickInitAddress // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0807a3f0, gl_MultiTexCoord2fARB); detourFunction(0x0807a470, gl_Color4ub); @@ -1613,7 +1616,7 @@ int initPatch() detourFunction(0x0850fba0, stubRetZero); // isUseServerBox // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0807a42c, gl_MultiTexCoord2fARB); detourFunction(0x0807a4ac, gl_Color4ub); @@ -1629,54 +1632,6 @@ int initPatch() patchMemory(0x0875e1ae, "00"); // Fix cutscenes } break; - case LETS_GO_JUNGLE_REVA: - { - if (config->showDebugMessages == 1) - { - setVariable(0x08c10604, 2); // amBackupDebugLevel - setVariable(0x08c10620, 2); // amCreditDebugLevel - setVariable(0x08c10878, 2); // amDipswDebugLevel - setVariable(0x08c1087c, 2); // amDongleDebugLevel - setVariable(0x08c10880, 2); // amEepromDebugLevel - setVariable(0x08c10884, 2); // amHwmonitorDebugLevel - setVariable(0x08c10888, 2); // amJvsDebugLevel - setVariable(0x08c1088c, 2); // amLibDebugLevel - setVariable(0x08c10890, 2); // amMiscDebugLevel - setVariable(0x08c10898, 2); // amSysDataDebugLevel - setVariable(0x08c108a0, 2); // bcLibDebugLevel - setVariable(0x08c10894, 2); // amOsinfoDebugLevel - setVariable(0x08c108a4, 0x0FFFFFFF); // s_logMask - detourFunction(0x08074a8c, _putConsole); // Debug Messages - } - // Security - detourFunction(0x084e9fbc, amDongleInit); - detourFunction(0x084ea378, amDongleIsAvailable); - detourFunction(0x084ea29c, amDongleUpdate); - patchMemory(0x0807b86a, "9090"); // Patch initializeArcadeBackup - // Fixes - amDipswContextAddr = (void *)0x08c43e08; // Address of amDipswContext - detourFunction(0x084e9de0, amDipswInit); - detourFunction(0x084e9e7c, amDipswExit); - detourFunction(0x084e9ef2, amDipswGetData); - detourFunction(0x084e9f6a, amDipswSetLed); - patchMemory(0x084125f0, "9090"); // No full screen - - // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU || getConfig()->lgjRenderWithMesa) - { - detourFunction(0x08071790, gl_MultiTexCoord2fARB); - detourFunction(0x08071800, gl_Color4ub); - detourFunction(0x08071a30, gl_Vertex3f); - detourFunction(0x08072080, gl_TexCoord2f); - detourFunction(0x08072110, cg_GLIsProfileSupported); - detourFunction(0x08071e50, gl_ProgramStringARB); - cacheModedShaderFiles(); - } - detourFunction(0x080722e0, gl_ProgramParameters4fvNV); - // patchMemory(0x083f4626, "909090909090"); - detourFunction(0x08072520, gl_XGetProcAddressARB); - } - break; case LETS_GO_JUNGLE: { if (config->showDebugMessages == 1) @@ -1710,7 +1665,7 @@ int initPatch() patchMemory(0x0840d858, "9090"); // No full screen // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU || getConfig()->lgjRenderWithMesa) + if (GPUVendor != NVIDIA_GPU || getConfig()->lgjRenderWithMesa) { detourFunction(0x080716e4, gl_MultiTexCoord2fARB); detourFunction(0x08071754, gl_Color4ub); @@ -1725,6 +1680,54 @@ int initPatch() detourFunction(0x08072454, gl_XGetProcAddressARB); } break; + case LETS_GO_JUNGLE_REVA: + { + if (config->showDebugMessages == 1) + { + setVariable(0x08c10604, 2); // amBackupDebugLevel + setVariable(0x08c10620, 2); // amCreditDebugLevel + setVariable(0x08c10878, 2); // amDipswDebugLevel + setVariable(0x08c1087c, 2); // amDongleDebugLevel + setVariable(0x08c10880, 2); // amEepromDebugLevel + setVariable(0x08c10884, 2); // amHwmonitorDebugLevel + setVariable(0x08c10888, 2); // amJvsDebugLevel + setVariable(0x08c1088c, 2); // amLibDebugLevel + setVariable(0x08c10890, 2); // amMiscDebugLevel + setVariable(0x08c10898, 2); // amSysDataDebugLevel + setVariable(0x08c108a0, 2); // bcLibDebugLevel + setVariable(0x08c10894, 2); // amOsinfoDebugLevel + setVariable(0x08c108a4, 0x0FFFFFFF); // s_logMask + detourFunction(0x08074a8c, _putConsole); // Debug Messages + } + // Security + detourFunction(0x084e9fbc, amDongleInit); + detourFunction(0x084ea378, amDongleIsAvailable); + detourFunction(0x084ea29c, amDongleUpdate); + patchMemory(0x0807b86a, "9090"); // Patch initializeArcadeBackup + // Fixes + amDipswContextAddr = (void *)0x08c43e08; // Address of amDipswContext + detourFunction(0x084e9de0, amDipswInit); + detourFunction(0x084e9e7c, amDipswExit); + detourFunction(0x084e9ef2, amDipswGetData); + detourFunction(0x084e9f6a, amDipswSetLed); + patchMemory(0x084125f0, "9090"); // No full screen + + // Mesa Patches + if (GPUVendor != NVIDIA_GPU || getConfig()->lgjRenderWithMesa) + { + detourFunction(0x08071790, gl_MultiTexCoord2fARB); + detourFunction(0x08071800, gl_Color4ub); + detourFunction(0x08071a30, gl_Vertex3f); + detourFunction(0x08072080, gl_TexCoord2f); + detourFunction(0x08072110, cg_GLIsProfileSupported); + detourFunction(0x08071e50, gl_ProgramStringARB); + cacheModedShaderFiles(); + } + detourFunction(0x080722e0, gl_ProgramParameters4fvNV); + // patchMemory(0x083f4626, "909090909090"); + detourFunction(0x08072520, gl_XGetProcAddressARB); + } + break; case LETS_GO_JUNGLE_SPECIAL: { if (config->showDebugMessages == 1) @@ -1758,7 +1761,7 @@ int initPatch() patchMemory(0x08438954, "9090"); // No full screen // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU || getConfig()->lgjRenderWithMesa) + if (GPUVendor != NVIDIA_GPU || getConfig()->lgjRenderWithMesa) { detourFunction(0x080718e0, gl_MultiTexCoord2fARB); detourFunction(0x08071950, gl_Color4ub); @@ -1773,6 +1776,32 @@ int initPatch() detourFunction(0x080726c0, gl_XGetProcAddressARB); } break; + case MJ4_EVO: + { + detourFunction(0x08840b61, amDongleInit); + detourFunction(0x0883f3ed, amDongleIsAvailable); + detourFunction(0x0883f40a, amDongleIsDevelop); + detourFunction(0x0883ff0e, amDongleUpdate); + + // Fixes and patches to bypss network check + amDipswContextAddr = (void *)0x0af8ff3c; // Address of amDipswContext + detourFunction(0x0883f180, amDipswInit); + detourFunction(0x0883f204, amDipswExit); + detourFunction(0x0883f279, amDipswGetData); + detourFunction(0x0883f2ef, amDipswSetLed); + + patchMemory(0x080ea0d1, "909090909090"); + detourFunction(0x080e327c, stubRetZero); // skip checks + detourFunction(0x080ee4fa, stubRetZero); + patchMemory(0x080ea0bf, "75"); + patchMemory(0x08c035b8, "00"); + + if (GPUVendor != NVIDIA_GPU) + { + detourFunction(0x08051314, gl_ProgramStringARB); + } + } + break; case MJ4_REVG: { setVariable(0x0acf85d4, 2); @@ -1818,38 +1847,12 @@ int initPatch() patchMemory(0x08732fd3, "2e2f00"); // Patch /home/disk2 folder // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x08050ebc, gl_ProgramStringARB); } } break; - case MJ4_EVO: - { - detourFunction(0x08840b61, amDongleInit); - detourFunction(0x0883f3ed, amDongleIsAvailable); - detourFunction(0x0883f40a, amDongleIsDevelop); - detourFunction(0x0883ff0e, amDongleUpdate); - - // Fixes and patches to bypss network check - amDipswContextAddr = (void *)0x0af8ff3c; // Address of amDipswContext - detourFunction(0x0883f180, amDipswInit); - detourFunction(0x0883f204, amDipswExit); - detourFunction(0x0883f279, amDipswGetData); - detourFunction(0x0883f2ef, amDipswSetLed); - - patchMemory(0x080ea0d1, "909090909090"); - detourFunction(0x080e327c, stubRetZero); // skip checks - detourFunction(0x080ee4fa, stubRetZero); - patchMemory(0x080ea0bf, "75"); - patchMemory(0x08c035b8, "00"); - - if (getConfig()->GPUVendor != NVIDIA_GPU) - { - detourFunction(0x08051314, gl_ProgramStringARB); - } - } - break; case OUTRUN_2_SP_SDX: { if (config->showDebugMessages == 1) @@ -1888,7 +1891,7 @@ int initPatch() // Shader Patches detourFunction(0x0804ca98, gl_ProgramStringARB); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804cf38, glGenProgramsARB); // Replaces glGenProgramsNV detourFunction(0x0804c548, gl_BindProgramNV); // Replaces glBindProgramNV @@ -1906,26 +1909,6 @@ int initPatch() detourFunction(0x0804d148, or2snprintf); // Fixes a bug in snprintf libc 2.39?? } break; - case OUTRUN_2_SP_SDX_TEST: - { - // Security - detourFunction(0x08066204, amDongleInit); - detourFunction(0x08066585, amDongleIsAvailable); - detourFunction(0x080664a9, amDongleUpdate); - detourFunction(0x080665a5, amDongleIsDevelop); - - // Fixes - amDipswContextAddr = (void *)0x080980e8; // Address of amDipswContext - detourFunction(0x08066028, amDipswInit); - detourFunction(0x080660c4, amDipswExit); - detourFunction(0x0806613a, amDipswGetData); - detourFunction(0x080661b2, amDipswSetLed); // Stub amDipswSetLed - detourFunction(0x08066028, amDipswInit); - - // Patch to allow selection of all cabinet types - patchMemory(0x08054a88, "9090909090"); - } - break; case OUTRUN_2_SP_SDX_REVA: { if (config->showDebugMessages == 1) @@ -1967,7 +1950,7 @@ int initPatch() // Shader Patches detourFunction(0x0804ca98, gl_ProgramStringARB); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804cf38, glGenProgramsARB); // Replaces glGenProgramsNV detourFunction(0x0804c548, gl_BindProgramNV); // Replaces glBindProgramNV @@ -2014,6 +1997,26 @@ int initPatch() patchMemory(0x08054ac4, "9090909090"); } break; + case OUTRUN_2_SP_SDX_TEST: + { + // Security + detourFunction(0x08066204, amDongleInit); + detourFunction(0x08066585, amDongleIsAvailable); + detourFunction(0x080664a9, amDongleUpdate); + detourFunction(0x080665a5, amDongleIsDevelop); + + // Fixes + amDipswContextAddr = (void *)0x080980e8; // Address of amDipswContext + detourFunction(0x08066028, amDipswInit); + detourFunction(0x080660c4, amDipswExit); + detourFunction(0x0806613a, amDipswGetData); + detourFunction(0x080661b2, amDipswSetLed); // Stub amDipswSetLed + detourFunction(0x08066028, amDipswInit); + + // Patch to allow selection of all cabinet types + patchMemory(0x08054a88, "9090909090"); + } + break; case PRIMEVAL_HUNT: { // Security @@ -2052,7 +2055,7 @@ int initPatch() detourFunction(0x082c3103, amDipswSetLed); cacheModedShaderFiles(); // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { loadLibCg(); cacheNnstdshader(); @@ -2087,7 +2090,7 @@ int initPatch() patchMemory(0x838C498, "2e2f524f4d5f4c414e472f656e00"); // Patch /home/disk0 folder // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x080507e8, gl_ProgramStringARB); } @@ -2143,7 +2146,7 @@ int initPatch() srtvElfShaderPatcher(); // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { patchMemory(0x082d3ce9, "9090"); // Force GL_NVX_conditional_render } @@ -2406,22 +2409,6 @@ int initPatch() } } break; - case THE_HOUSE_OF_THE_DEAD_4_SPECIAL_TEST: - { - detourFunction(0x0806e9ec, amDongleInit); - detourFunction(0x0806ecff, amDongleIsAvailable); - detourFunction(0x0806ec66, amDongleUpdate); - // Fixes - amDipswContextAddr = (void *)0x080b2e88; // Address of amDipswContext - detourFunction(0x0806e794, amDipswInit); - detourFunction(0x0806e829, amDipswExit); - detourFunction(0x0806e89f, amDipswGetData); - detourFunction(0x0806e917, amDipswSetLed); - - // CPU patch to support AMD processors - patchMemory(0x08054bf0, "9090909090"); //__intel_new_proc_init_P - } - break; case THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB: { detourFunction(0x08363438, amDongleInit); @@ -2464,6 +2451,22 @@ int initPatch() patchMemory(0x08054820, "9090909090"); //__intel_new_proc_init_P } break; + case THE_HOUSE_OF_THE_DEAD_4_SPECIAL_TEST: + { + detourFunction(0x0806e9ec, amDongleInit); + detourFunction(0x0806ecff, amDongleIsAvailable); + detourFunction(0x0806ec66, amDongleUpdate); + // Fixes + amDipswContextAddr = (void *)0x080b2e88; // Address of amDipswContext + detourFunction(0x0806e794, amDipswInit); + detourFunction(0x0806e829, amDipswExit); + detourFunction(0x0806e89f, amDipswGetData); + detourFunction(0x0806e917, amDipswSetLed); + + // CPU patch to support AMD processors + patchMemory(0x08054bf0, "9090909090"); //__intel_new_proc_init_P + } + break; case THE_HOUSE_OF_THE_DEAD_EX: { detourFunction(0x084ba886, amDongleInit); @@ -2482,7 +2485,7 @@ int initPatch() patchMemory(0x0804e4a7, "9090909090"); //__intel_new_proc_init_P // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { patchMemory(0x08503bfa, "6d657361"); // Rename compile folder to compmesa cacheModedShaderFiles(); @@ -2528,6 +2531,7 @@ int initPatch() patchMemory(0x08210f3c, "9090909090909090"); patchMemory(0x08210f45, "01"); patchMemory(0x08210f49, "909090"); + patchMemory(0x082ef5d0, "9090909090"); // Fixes amDipswContextAddr = (void *)0x0c8ed0cc; detourFunction(0x08318f84, amDipswInit); @@ -2543,7 +2547,7 @@ int initPatch() detourFunction(0x081cbcd2, stubRetOne); // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { loadLibCg(); cacheNnstdshader(); @@ -2607,7 +2611,7 @@ int initPatch() patchMemory(0x080a36de, "9090909090"); patchMemory(0x080a35ed, "ffffffff"); patchMemory(0x080a3620, "ffffffff"); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x08051b9c, gl_ProgramStringARB); } @@ -2630,7 +2634,7 @@ int initPatch() detourFunction(0x08094d28, stubRetZero); patchMemory(0x080a29a5, "EB"); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0805160c, gl_ProgramStringARB); } @@ -2661,11 +2665,11 @@ int initPatch() patchMemory(0x88AB0C1, "2e2f666f6f3100"); // Patch /home/disk2 folder patchMemory(0x88AB0D2, "2e2f666f6f3200"); // Patch /home/disk2 folder patchMemory(0x89C8F24, "2e2f00"); // Patch /home/disk2 folder - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x08052aa4, gl_ProgramStringARB); } - if (getConfig()->GPUVendor != NVIDIA_GPU || getConfig()->GPUVendor == ATI_GPU) + if (GPUVendor != NVIDIA_GPU || GPUVendor == ATI_GPU) { hookVf5FSExposure(0x08148279, 0x0814844a, 0x08148b42, 0x08148d52); } @@ -2696,11 +2700,11 @@ int initPatch() patchMemory(0x88CACBD, "2e2f666f6f3100"); // Patch /home/disk2 folder patchMemory(0x88CACCE, "2e2f666f6f3200"); // Patch /home/disk2 folder patchMemory(0x89DE5AA, "2e2f00"); // Patch /home/disk2 folder - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x08052840, gl_ProgramStringARB); } - if (getConfig()->GPUVendor != NVIDIA_GPU || getConfig()->GPUVendor == ATI_GPU) + if (GPUVendor != NVIDIA_GPU || GPUVendor == ATI_GPU) { hookVf5FSExposure(0x08148a47, 0x08148c18, 0x08149310, 0x08149520); } @@ -2732,11 +2736,11 @@ int initPatch() patchMemory(0x88CD4AE, "2e2f666f6f3200"); // Patch /home/disk2 folder patchMemory(0x89ED9C4, "2e2f00"); // Patch /home/disk2 folder - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x08052b20, gl_ProgramStringARB); } - if (getConfig()->GPUVendor != NVIDIA_GPU || getConfig()->GPUVendor == ATI_GPU) + if (GPUVendor != NVIDIA_GPU || GPUVendor == ATI_GPU) { hookVf5FSExposure(0x081489f7, 0x08148bc8, 0x081492c0, 0x081494d0); } @@ -2769,7 +2773,7 @@ int initPatch() patchMemory(0x0810030c, "ffffffff"); patchMemory(0x08100313, "ffffffff"); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x08052a68, gl_ProgramStringARB); } @@ -2802,7 +2806,7 @@ int initPatch() patchMemory(0x08119204, "ffffffff"); patchMemory(0x0811920b, "ffffffff"); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x08052a84, gl_ProgramStringARB); } @@ -2835,7 +2839,7 @@ int initPatch() patchMemory(0x08119384, "ffffffff"); patchMemory(0x0811938b, "ffffffff"); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x08052a70, gl_ProgramStringARB); } @@ -2873,7 +2877,7 @@ int initPatch() patchMemory(0x080a6356, "9090909090"); patchMemory(0x080a6265, "ffffffff"); patchMemory(0x080a6298, "ffffffff"); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x08051c4c, gl_ProgramStringARB); } @@ -2909,7 +2913,7 @@ int initPatch() patchMemory(0x080b5682, "9090909090"); patchMemory(0x080B5591, "ffffffff"); patchMemory(0x080B55C4, "ffffffff"); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x08052088, gl_ProgramStringARB); } @@ -2946,7 +2950,7 @@ int initPatch() patchMemory(0x080e16b6, "9090909090"); patchMemory(0x080e15bd, "ffffffff"); patchMemory(0x080e15f7, "ffffffff"); - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x08052fbc, gl_ProgramStringARB); } @@ -2954,7 +2958,6 @@ int initPatch() patchMemory(0x080e173c, "B810000000"); } break; - case VIRTUA_TENNIS_3: { if (config->showDebugMessages == 1) @@ -2972,12 +2975,12 @@ int initPatch() detourFunction(0x0831beb9, amDipswExit); detourFunction(0x0831bf2f, amDipswGetData); detourFunction(0x0831bfa7, stubRetZero); - setVariable(0x0827a7c7, 0x34891beb); // Disable Fullscreen set from the game + setVariable(0x0827a7c7, 0x34891beb); // Disable Fullscreen set from the game detourFunction(0x08177acc, stubRetOne); // Patch seterror // Mesa - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804d458, cg_GLGetLatestProfile); detourFunction(0x0804dcd8, cg_GLIsProfileSupported); @@ -2994,37 +2997,6 @@ int initPatch() } } break; - case VIRTUA_TENNIS_3_TEST: - { - if (config->showDebugMessages == 1) - { - // Debug - detourFunction(0x08054c64, _putConsole); // Debug Messages - } - // Security - detourFunction(0x0815f060, amDongleInit); - detourFunction(0x0815f373, amDongleIsAvailable); - detourFunction(0x0815f2da, amDongleUpdate); - // Fixes - amDipswContextAddr = (void *)0x085e4a6c; // Address of amDipswContext - detourFunction(0x0815c9b0, amDipswInit); - detourFunction(0x0815ca45, amDipswExit); - detourFunction(0x0815cabb, amDipswGetData); - detourFunction(0x0815cb33, amDipswSetLed); - patchMemory(0x0806f983, "EB"); // Avoid Full Screen set from Game - - // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU) - { - detourFunction(0x0804ce54, cg_GLIsProfileSupported); - detourFunction(0x0804c724, gl_Color4ub); - detourFunction(0x0804c8b4, gl_Vertex3f); - detourFunction(0x0804cdc4, gl_TexCoord2f); - patchMemory(0x0806a01a, "31FF90"); - cacheModedShaderFiles(); - } - } - break; case VIRTUA_TENNIS_3_REVA: { if (config->showDebugMessages == 1) @@ -3042,11 +3014,11 @@ int initPatch() detourFunction(0x0831bf5d, amDipswExit); detourFunction(0x0831bfd3, amDipswGetData); detourFunction(0x0831c04b, stubRetZero); - setVariable(0x0827a7f7, 0x34891beb); // Disable Fullscreen set from the game - detourFunction(0x08177afc, stubRetOne); // Patch seterror + setVariable(0x0827a7f7, 0x34891beb); // Disable Fullscreen set from the game + detourFunction(0x08177afc, stubRetOne); // Patch seterror // Mesa - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804d458, cg_GLGetLatestProfile); detourFunction(0x0804dcd8, cg_GLIsProfileSupported); @@ -3083,7 +3055,7 @@ int initPatch() patchMemory(0x0806fd8f, "EB"); // Avoid Full Screen set from Game // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804ce54, cg_GLIsProfileSupported); detourFunction(0x0804c724, gl_Color4ub); @@ -3111,11 +3083,11 @@ int initPatch() detourFunction(0x0831c149, amDipswExit); detourFunction(0x0831c1bf, amDipswGetData); detourFunction(0x0831c237, stubRetZero); - setVariable(0x0827a9e3, 0x34891beb); // Disable Fullscreen set from the game - detourFunction(0x08177bf0, stubRetOne); // Patch seterror + setVariable(0x0827a9e3, 0x34891beb); // Disable Fullscreen set from the game + detourFunction(0x08177bf0, stubRetOne); // Patch seterror // Mesa - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804d458, cg_GLGetLatestProfile); detourFunction(0x0804dcd8, cg_GLIsProfileSupported); @@ -3152,7 +3124,7 @@ int initPatch() patchMemory(0x0806fa33, "EB"); // Avoid Full Screen set from Game // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804ce54, cg_GLIsProfileSupported); detourFunction(0x0804c724, gl_Color4ub); @@ -3180,11 +3152,11 @@ int initPatch() detourFunction(0x0831c561, amDipswExit); detourFunction(0x0831c5d7, amDipswGetData); detourFunction(0x0831c64f, stubRetZero); - setVariable(0x0827ae1b, 0x34891beb); // Disable Fullscreen set from the game - detourFunction(0x08177c1c, stubRetOne); // Patch seterror + setVariable(0x0827ae1b, 0x34891beb); // Disable Fullscreen set from the game + detourFunction(0x08177c1c, stubRetOne); // Patch seterror // Mesa - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804d458, cg_GLGetLatestProfile); detourFunction(0x0804dcd8, cg_GLIsProfileSupported); @@ -3228,7 +3200,7 @@ int initPatch() patchMemory(0x0806fe3f, "EB"); // Avoid Full Screen set from Game // Mesa Patches - if (getConfig()->GPUVendor != NVIDIA_GPU) + if (GPUVendor != NVIDIA_GPU) { detourFunction(0x0804ce54, cg_GLIsProfileSupported); detourFunction(0x0804c724, gl_Color4ub); @@ -3239,6 +3211,37 @@ int initPatch() } } break; + case VIRTUA_TENNIS_3_TEST: + { + if (config->showDebugMessages == 1) + { + // Debug + detourFunction(0x08054c64, _putConsole); // Debug Messages + } + // Security + detourFunction(0x0815f060, amDongleInit); + detourFunction(0x0815f373, amDongleIsAvailable); + detourFunction(0x0815f2da, amDongleUpdate); + // Fixes + amDipswContextAddr = (void *)0x085e4a6c; // Address of amDipswContext + detourFunction(0x0815c9b0, amDipswInit); + detourFunction(0x0815ca45, amDipswExit); + detourFunction(0x0815cabb, amDipswGetData); + detourFunction(0x0815cb33, amDipswSetLed); + patchMemory(0x0806f983, "EB"); // Avoid Full Screen set from Game + + // Mesa Patches + if (GPUVendor != NVIDIA_GPU) + { + detourFunction(0x0804ce54, cg_GLIsProfileSupported); + detourFunction(0x0804c724, gl_Color4ub); + detourFunction(0x0804c8b4, gl_Vertex3f); + detourFunction(0x0804cdc4, gl_TexCoord2f); + patchMemory(0x0806a01a, "31FF90"); + cacheModedShaderFiles(); + } + } + break; default: break; } diff --git a/src/lindbergh/resolution.c b/src/lindbergh/resolution.c index ee0ca07..950727b 100644 --- a/src/lindbergh/resolution.c +++ b/src/lindbergh/resolution.c @@ -1,5 +1,6 @@ #include "config.h" #include +#include #include #include #include @@ -15,17 +16,22 @@ #include "patch.h" #include "resolution.h" +extern uint32_t gId; +extern SDL_Window *SDLwindow; +int gWidth, gHeight; + int srtvX = 0; int srtvW, srtvH; int phX, phY, phW, phH; +int phX2, phY2, phW2, phH2; int vf5FSwidth; void *glVertex3fPatchRetAddrABC[4]; void *glVertex3fNoPatchRetAddrABC[4]; -GLenum curTargetABC = 0; -GLuint curTextureIDABC = 0; +GLenum curTarget = 0; +GLuint curTextureID = 0; const GLfloat *texCoordABC[4]; vertexABC vABC[4]; @@ -62,16 +68,7 @@ int idTextShift = 0; float id4NewCaptionY; float idShiftX = 0.0; float isShiftY = 0.0; - -uint32_t harleyCreditsOffsets[] = { - 0x000000e8, 0x0000012c, 0x00000170, 0x00000468, 0x000004ac, 0x000004f0, 0x00000578, 0x000005bc, 0x00000a88, 0x00000c48, 0x00000c8c, - 0x00000e98, 0x00000edc, 0x00000f20, 0x00000f64, 0x00000fa8, 0x00000fec, 0x00001030, 0x00001074, 0x000010b8, 0x00001638, 0x0000167c, - 0x000016c0, 0x00001704, 0x00001748, 0x0000178c, 0x000017d0, 0x00001814, 0x00001da8, 0x00001dec, 0x00002008, 0x0000204c, 0x00002090, - 0x000020d4, 0x00002118, 0x0000215c, 0x000021a0, 0x000021e4, 0x00002228, 0x000027a8, 0x000027e0, 0x00002830, 0x00002874, 0x000028b8, - 0x000028fc, 0x00002940, 0x00002e48, 0x00002e8c, 0x000030a8, 0x000030ec, 0x00003130, 0x00003174, 0x000034b8, 0x000034fc, 0x00003540, - 0x00003584, 0x000038b8, 0x000038fc, 0x00003b58, 0x00003b9c, 0x00003f48, 0x000041c8, 0x0000420c, 0x00004250, 0x00004294}; - -int harleyCreditsOffsetsSize = 65; +bool myEnableScaling = false; int hummerRespatch() { @@ -80,58 +77,17 @@ int hummerRespatch() (addr == (void *)0x080d8b4f) || (addr == (void *)0x080d8bbb) || (addr == (void *)0x08159eb0) || (addr == (void *)0x08159eec) || (addr == (void *)0x08159f64) || (addr == (void *)0x08163490) || (addr == (void *)0x081634cc) || (addr == (void *)0x08163544)) { - return getConfig()->width - 1; + return gWidth - 1; } else if ((addr == (void *)0x080d8b78) || (addr == (void *)0x080d8bae) || (addr == (void *)0x080d8c1a) || (addr == (void *)0x080d8b34) || (addr == (void *)0x080d8b6a) || (addr == (void *)0x080d8bd6) || (addr == (void *)0x08159ece) || (addr == (void *)0x08159f0a) || (addr == (void *)0x08159f82) || (addr == (void *)0x081634ae) || (addr == (void *)0x081634ea) || (addr == (void *)0x08163562)) { - return getConfig()->height; + return gHeight; } return 1280; } -size_t harleyFreadReplace(void *buf, size_t size, size_t count, FILE *stream) -{ - size_t (*_fread)(void *buf, size_t size, size_t count, FILE *stream) = dlsym(RTLD_NEXT, "fread"); - - int s = _fread(buf, size, count, stream); - if (getConfig()->width == 1360 || getConfig()->width == 640) - return s; - - for (int x = 0; x < harleyCreditsOffsetsSize; x++) - { - float oldX, idx; - idx = 1.2; //((float)getConfig()->width / 1360.0) * 0.81459; - memcpy(&oldX, buf + harleyCreditsOffsets[x], sizeof(float)); - float newX = oldX - (((float)getConfig()->width - 1360.0) / 2); - float newY = (((600.0 * (float)getConfig()->height) / 768.0) - 600.0) * -1; - - if (getConfig()->width > 1920) - { - newX = oldX - ((((float)getConfig()->width - 1360.0) / 2) / idx); - newY = (((600.0 * (float)getConfig()->height) / 768.0) - (600.0 * idx)) * -1; - // Move the words "CREDIT(S)" and "TO START" and "TO CONTINUE" a little to the right - if (harleyCreditsOffsets[x] == 0x00000f20 || harleyCreditsOffsets[x] == 0x00001030 || harleyCreditsOffsets[x] == 0x00000f64 || - harleyCreditsOffsets[x] == 0x00001074 || harleyCreditsOffsets[x] == 0x0000167c || harleyCreditsOffsets[x] == 0x00001814 || - harleyCreditsOffsets[x] == 0x00001638 || harleyCreditsOffsets[x] == 0x000017d0) - { - newX -= idx * 10; - } - // Do not scale "TO START" and "TO CONTINUE" - if (harleyCreditsOffsets[x] != 0x0000167c && harleyCreditsOffsets[x] != 0x00001814 && harleyCreditsOffsets[x] != 0x00000f64 && - harleyCreditsOffsets[x] != 0x00001074) - { - memcpy(buf + harleyCreditsOffsets[x] - 8, &idx, sizeof(float)); - memcpy(buf + harleyCreditsOffsets[x] - 12, &idx, sizeof(float)); - } - } - memcpy(buf + harleyCreditsOffsets[x], &newX, sizeof(float)); - memcpy(buf + harleyCreditsOffsets[x] + 4, &newY, sizeof(float)); - } - return s; -} - /** * Function which games use to scale the output, some games behave well when this is changed * others less so. @@ -144,13 +100,13 @@ void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdou void *returnAddress = __builtin_return_address(0); - switch (getConfig()->crc32) + switch (gId) { case THE_HOUSE_OF_THE_DEAD_4_REVA: case THE_HOUSE_OF_THE_DEAD_4_REVB: case THE_HOUSE_OF_THE_DEAD_4_REVC: { - if ((getConfig()->width != 1280 && getConfig()->height != 768) || (getConfig()->width != 640 && getConfig()->height != 480)) + if ((gWidth != 1280 && gHeight != 768) || (gWidth != 640 && gHeight != 480)) { right = 1280.0; bottom = 720.0; @@ -160,7 +116,7 @@ void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdou case THE_HOUSE_OF_THE_DEAD_4_SPECIAL: case THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB: { - if (getConfig()->width != 1024 && getConfig()->height != 768) + if (gWidth != 1024 && gHeight != 768) { if (right == 1024.0 && bottom == 768.0) { @@ -172,9 +128,9 @@ void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdou break; case SEGA_RACE_TV: { - if (getConfig()->width != 640 && getConfig()->height != 480) + if (gWidth != 640 && gHeight != 480) { - if ((right == 640.0 && bottom == 480.0) && (getConfig()->width != 640 && getConfig()->height != 480)) + if ((right == 640.0 && bottom == 480.0) && (gWidth != 640 && gHeight != 480)) { right = 600000.0; bottom = 600000.0; @@ -184,7 +140,7 @@ void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdou break; case THE_HOUSE_OF_THE_DEAD_EX: { - if (getConfig()->width != 1280 && getConfig()->height != 768) + if (gWidth != 1360 && gHeight != 768) { right = 600.0; bottom = 480.0; @@ -208,17 +164,17 @@ void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) void *returnAddress = __builtin_return_address(0); - switch (getConfig()->crc32) + switch (gId) { case HUMMER: case HUMMER_SDLX: { - if (getConfig()->width != 1280 && getConfig()->height != 768) + if (gWidth != 1280 && gHeight != 768) { if (width == 1280 && height == 768) { - width = getConfig()->width; - height = getConfig()->height; + width = gWidth; + height = gHeight; } } } @@ -229,12 +185,12 @@ void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) case OUTRUN_2_SP_SDX_REVA_TEST: case OUTRUN_2_SP_SDX_REVA_TEST2: { - if (getConfig()->width != 800 && getConfig()->height != 480) + if (gWidth != 800 && gHeight != 480) { if ((width >= 800) && (width != 1024)) { - width = getConfig()->width; - height = getConfig()->height; + width = gWidth; + height = gHeight; } } } @@ -242,7 +198,7 @@ void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) case SEGA_RACE_TV: { - if (getConfig()->width != 640 && getConfig()->height != 480) + if (gWidth != 640 && gHeight != 480) { if (width == 640 && height == 480 && returnAddress == (void *)0x08123932) { @@ -258,30 +214,30 @@ void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) } } break; - case THE_HOUSE_OF_THE_DEAD_4_REVA: + // case THE_HOUSE_OF_THE_DEAD_4_REVA: + // case THE_HOUSE_OF_THE_DEAD_4_REVB: + // case THE_HOUSE_OF_THE_DEAD_4_REVC: case THE_HOUSE_OF_THE_DEAD_4_REVA_TEST: - case THE_HOUSE_OF_THE_DEAD_4_REVB: case THE_HOUSE_OF_THE_DEAD_4_REVB_TEST: - case THE_HOUSE_OF_THE_DEAD_4_REVC: case THE_HOUSE_OF_THE_DEAD_4_REVC_TEST: case THE_HOUSE_OF_THE_DEAD_EX_TEST: { if (width == 640 && height == 480) { - width = getConfig()->width; - height = getConfig()->height; + width = gWidth; + height = gHeight; } } break; case THE_HOUSE_OF_THE_DEAD_4_SPECIAL: case THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB: { - if (getConfig()->width != 1024 && getConfig()->height != 768) + if (gWidth != 1024 && gHeight != 768) { if (width == 1024 && height == 768) { - width = getConfig()->width; - height = getConfig()->height; + width = gWidth; + height = gHeight; x = 250; y = 100; } @@ -295,11 +251,33 @@ void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) case VIRTUA_FIGHTER_5_R_REVD: case VIRTUA_FIGHTER_5_R_REVG: { - if ((getConfig()->width != 640 && getConfig()->height != 480) || (getConfig()->width != 1280 && getConfig()->height != 768)) + if ((gWidth != 640 && gHeight != 480) || (gWidth != 1280 && gHeight != 768)) { if (width == vf5FSwidth) { - width = getConfig()->width; + width = gWidth; + } + } + } + break; + case PRIMEVAL_HUNT: + { + if (isTestMode() && gWidth != 1280 && gHeight != 480) + { + if (getConfig()->keepAspectRatio) + { + width = gWidth / 2; + height = ((gWidth / 2) / 4) * 3; + y = (gHeight - height) / 2; + } + else + { + width = gWidth / 2; + height = gHeight; + } + if (x == 640) + { + x = width = gWidth / 2; } } } @@ -317,9 +295,9 @@ void glTexImage2D(unsigned int target, int level, int internalformat, int width, void (*_glTexImage2D)(unsigned int target, int level, int internalformat, int width, int height, int border, unsigned int format, unsigned int type, const void *pixels) = dlsym(RTLD_NEXT, "glTexImage2D"); - if (getConfig()->width != 800 && getConfig()->height != 480) + if (gWidth != 800 && gHeight != 480) { - switch (getConfig()->crc32) + switch (gId) { case OUTRUN_2_SP_SDX: case OUTRUN_2_SP_SDX_REVA: @@ -327,8 +305,8 @@ void glTexImage2D(unsigned int target, int level, int internalformat, int width, void *addr = __builtin_return_address(0); if ((width >= 800) && (width != 1024) && (addr != (void *)0x80d78d5) && (addr != (void *)0x080d7941)) { - width = getConfig()->width; - height = getConfig()->height; + width = gWidth; + height = gHeight; } } break; @@ -344,7 +322,7 @@ void glTexParameteri(unsigned int target, unsigned int pname, int param) void (*_glTexParameteri)(unsigned int, unsigned int, int) = dlsym(RTLD_NEXT, "glTexParameteri"); - switch (getConfig()->crc32) + switch (gId) { case OUTRUN_2_SP_SDX: case OUTRUN_2_SP_SDX_REVA: @@ -390,10 +368,10 @@ int isTestMode() return false; } -void glBindTextureABC(GLenum target, GLuint texture) +void myGlBindTexture(GLenum target, GLuint texture) { - curTargetABC = target; - curTextureIDABC = texture; + // const char *targetName = ""; + // switch (target) void (*_glBindTexture)(GLenum, GLuint) = dlsym(RTLD_NEXT, "glBindTexture"); _glBindTexture(target, texture); @@ -403,17 +381,17 @@ void scaleABCVertex() { for (int idx = 0; idx < 4; idx++) { - vABC[idx].x *= (getConfig()->width / 640.0); - vABC[idx].y *= (getConfig()->height / 480.0); + vABC[idx].x *= (gWidth / 640.0); + vABC[idx].y *= (gHeight / 480.0); } } void scaleNumbers() { lockedCountABC++; - float newFontWidth = 8 * ((getConfig()->height / 480.0) * 0.8); - float newFontHeight = 16 * ((getConfig()->height / 480.0) * 0.8); - float newY = 8.0 * (getConfig()->height / 480.0); + float newFontWidth = 8 * ((gHeight / 480.0) * 0.8); + float newFontHeight = 16 * ((gHeight / 480.0) * 0.8); + float newY = 8.0 * (gHeight / 480.0); switch (lockedCountABC) { case 1: @@ -459,7 +437,7 @@ void scaleByAngle(float percentage, float shift) { percentage = (percentage == 0.0 ? 1 : percentage / 100.0); float sizeX, sizeY, newHalfSizeX, newHalfSizeY; - float idx = (getConfig()->height / 480.0) * percentage; + float idx = (gHeight / 480.0) * percentage; switch ((int)angleABC) { case 0: @@ -533,7 +511,7 @@ void shiftTarget(float percentage) { percentage = percentage / 100; float size, newHalfSize; - float idx = (getConfig()->height / 480.0) * percentage; + float idx = (gHeight / 480.0) * percentage; switch ((int)angleABC) { case 0: @@ -599,7 +577,7 @@ void glVertex3fABC1(GLfloat x, GLfloat y, GLfloat z) return; } - if (curTargetABC == GL_TEXTURE_2D && (getConfig()->width != 640 || getConfig()->height != 480)) + if (curTarget == GL_TEXTURE_2D && (gWidth != 640 || gHeight != 480)) { float sizeX, sizeY; sizeX = vABC[1].x - vABC[0].x; @@ -610,16 +588,16 @@ void glVertex3fABC1(GLfloat x, GLfloat y, GLfloat z) // Cut scene video if (textureIDABC == 0x20350) { - float idx = (getConfig()->height / 480.0); + float idx = (gHeight / 480.0); if (vABC[2].y < 65.0 && vABC[3].y < 65.0) { vABC[2].y *= idx * 1.5; vABC[3].y *= idx * 1.5; } - else if ((vABC[0].y > (getConfig()->height - 65.0)) && (vABC[1].y > (getConfig()->height - 65.0))) + else if ((vABC[0].y > (gHeight - 65.0)) && (vABC[1].y > (gHeight - 65.0))) { - vABC[0].y += (getConfig()->height - vABC[0].y) - ((getConfig()->height - vABC[0].y) * (idx * 1.5)); - vABC[1].y += (getConfig()->height - vABC[1].y) - ((getConfig()->height - vABC[1].y) * (idx * 1.5)); + vABC[0].y += (gHeight - vABC[0].y) - ((gHeight - vABC[0].y) * (idx * 1.5)); + vABC[1].y += (gHeight - vABC[1].y) - ((gHeight - vABC[1].y) * (idx * 1.5)); } scale = false; } @@ -670,14 +648,14 @@ void glVertex3fABC1(GLfloat x, GLfloat y, GLfloat z) // Press Start Button / Insert Coins else if (textureIDABC == 0x20138 || textureIDABC == 0x2013a) { - float newSizeX = sizeX * (getConfig()->width / 640.0); - float newSizeY = sizeY * (getConfig()->height / 480.0); - vABC[0].x = (getConfig()->width - newSizeX) / 2; + float newSizeX = sizeX * (gWidth / 640.0); + float newSizeY = sizeY * (gHeight / 480.0); + vABC[0].x = (gWidth - newSizeX) / 2; vABC[1].x = vABC[0].x + newSizeX; vABC[2].x = vABC[1].x; vABC[3].x = vABC[0].x; - vABC[0].y = getConfig()->height - ((newSizeY * 2) + 30); + vABC[0].y = gHeight - ((newSizeY * 2) + 30); vABC[1].y = vABC[0].y; vABC[2].y = vABC[0].y + newSizeY; vABC[3].y = vABC[0].y + newSizeY; @@ -686,17 +664,17 @@ void glVertex3fABC1(GLfloat x, GLfloat y, GLfloat z) // FREE PLAY / Credits / Credit count else if (textureIDABC >= 0x20057 && textureIDABC <= 0x20062) { - float newSizeX = sizeX * (getConfig()->width / 640.0); - float newSizeY = sizeY * (getConfig()->height / 480.0); + float newSizeX = sizeX * (gWidth / 640.0); + float newSizeY = sizeY * (gHeight / 480.0); - vABC[0].x = (getConfig()->width - newSizeX) / 2; + vABC[0].x = (gWidth - newSizeX) / 2; if (sizeX == 88.0) { - vABC[0].x -= (16 * (getConfig()->width / 640.0)) * 1.5; + vABC[0].x -= (16 * (gWidth / 640.0)) * 1.5; } if (sizeX == 16.0) { - float creditsSize = (88 * (getConfig()->width / 640.0)) / 2; + float creditsSize = (88 * (gWidth / 640.0)) / 2; if (prevCreditXABC == x) creditCountABC = 1; if (creditCountABC == 0) @@ -716,7 +694,7 @@ void glVertex3fABC1(GLfloat x, GLfloat y, GLfloat z) vABC[2].x = vABC[1].x; vABC[3].x = vABC[0].x; - vABC[0].y = getConfig()->height - (newSizeY + 20); + vABC[0].y = gHeight - (newSizeY + 20); vABC[1].y = vABC[0].y; vABC[2].y = vABC[0].y + newSizeY; vABC[3].y = vABC[0].y + newSizeY; @@ -726,8 +704,8 @@ void glVertex3fABC1(GLfloat x, GLfloat y, GLfloat z) else if (textureIDABC == 0x20064) { - float sizeIncX = 26.0 * (getConfig()->height / 480.0); - float sizeIncY = 8.0 * (getConfig()->height / 480.0); + float sizeIncX = 26.0 * (gHeight / 480.0); + float sizeIncY = 8.0 * (gHeight / 480.0); vABC[0].x -= sizeIncX / 2.0; vABC[1].x += sizeIncX / 2.0; vABC[2].x += sizeIncX / 2.0; @@ -760,8 +738,8 @@ void glVertex3fABC1(GLfloat x, GLfloat y, GLfloat z) { for (int x = 0; x < 4; x++) { - vABC[x].x = vABC[x].x * (getConfig()->width / 640.0); - vABC[x].y = vABC[x].y * (getConfig()->height / 480.0); + vABC[x].x = vABC[x].x * (gWidth / 640.0); + vABC[x].y = vABC[x].y * (gHeight / 480.0); } scale = false; } @@ -774,7 +752,7 @@ void glVertex3fABC1(GLfloat x, GLfloat y, GLfloat z) // Green arrows in the crosshair else if (textureIDABC == 0x2014c) { - float shift = (20.0 * (getConfig()->height / 480.0) - 20.0) / 2.0; + float shift = (20.0 * (gHeight / 480.0) - 20.0) / 2.0; scaleByAngle(80, shift - 5.0); switch ((int)angleABC) { @@ -825,8 +803,8 @@ void glVertex3fABC1(GLfloat x, GLfloat y, GLfloat z) else if (textureIDABC == 0x20141 || textureIDABC == 0x20142 || textureIDABC == 0x20143 || textureIDABC == 0x20144 || textureIDABC == 0x20145) { - float sizeIncX = 6.0 * (getConfig()->height / 480.0) - 6.0; - float sizeIncY = 10.0 * (getConfig()->height / 480.0) - 10.0; + float sizeIncX = 6.0 * (gHeight / 480.0) - 6.0; + float sizeIncY = 10.0 * (gHeight / 480.0) - 10.0; vABC[0].x -= sizeIncX / 2.0; vABC[0].y -= sizeIncY / 2.0; vABC[1].x += sizeIncX / 2.0; @@ -840,8 +818,8 @@ void glVertex3fABC1(GLfloat x, GLfloat y, GLfloat z) // 0x201E2 Friend, 0x201e3 Target, 0x201C5 Enemy and 0x201C6 Missile words else if (textureIDABC == 0x201E2 || textureIDABC == 0x201e3 || textureIDABC == 0x201C5 || textureIDABC == 0x201C6) { - float newHalfSizeX = ((sizeX * ((getConfig()->height / 480.0) * 0.8)) - sizeX) / 2.0; - float newSizeY = (sizeY * ((getConfig()->height / 480.0) * 0.8)) - sizeY; + float newHalfSizeX = ((sizeX * ((gHeight / 480.0) * 0.8)) - sizeX) / 2.0; + float newSizeY = (sizeY * ((gHeight / 480.0) * 0.8)) - sizeY; vABC[0].x -= newHalfSizeX; vABC[0].y -= newSizeY * 2; vABC[1].x += newHalfSizeX; @@ -859,8 +837,8 @@ void glVertex3fABC1(GLfloat x, GLfloat y, GLfloat z) textureIDABC == 0x20312 || textureIDABC == 0x201e4 || textureIDABC == 0x201e5 || textureIDABC == 0x201e6 || textureIDABC == 0x201C7) { - float newHalfSizeX = ((sizeX * ((getConfig()->height / 480.0) * 0.8)) - sizeX) / 2.0; - float newSizeY = (sizeY * ((getConfig()->height / 480.0) * 0.8)) - sizeY; + float newHalfSizeX = ((sizeX * ((gHeight / 480.0) * 0.8)) - sizeX) / 2.0; + float newSizeY = (sizeY * ((gHeight / 480.0) * 0.8)) - sizeY; vABC[0].x -= newHalfSizeX; vABC[0].y -= newSizeY; vABC[1].x += newHalfSizeX; @@ -872,8 +850,8 @@ void glVertex3fABC1(GLfloat x, GLfloat y, GLfloat z) // Fonts and Subtitles in Cut scene Y position else if (textureIDABC == 0x30008) { - int width = getConfig()->width; - int height = getConfig()->height; + int width = gWidth; + int height = gHeight; float idx = ((height / 480.0) / 10) + 1; float heightShiftUp = height * ((((height / 2.0) - 216) / height) - 0.05); if (vABC[0].y == ((height / 2.0) - 216) || vABC[0].y == (((height / 2.0) - 216) + sizeY + 2)) @@ -893,8 +871,8 @@ void glVertex3fABC1(GLfloat x, GLfloat y, GLfloat z) vABC[3].y -= sizeY - 16; scaleABCVertex(); - float widthScaleIdx = getConfig()->width / 640.0; - float fontSizeScaled = 8 * (getConfig()->height / 480.0); + float widthScaleIdx = gWidth / 640.0; + float fontSizeScaled = 8 * (gHeight / 480.0); float fontWidthAfterScaled = 8 * widthScaleIdx; if (originalPosition == (374 - fontSizeScaled)) { @@ -932,7 +910,7 @@ void glVertex3fABC1(GLfloat x, GLfloat y, GLfloat z) { for (int x = 0; x < 4; x++) { - vABC[x].y *= ((getConfig()->height / 480.0) / 10) + 1; + vABC[x].y *= ((gHeight / 480.0) / 10) + 1; } } scale = false; @@ -954,8 +932,8 @@ void glVertex3fABC2(GLfloat x, GLfloat y, GLfloat z) { void (*_glVertex3f)(GLfloat x, GLfloat y, GLfloat z) = dlsym(RTLD_NEXT, "glVertex3f"); - GLfloat scaledX = x * (getConfig()->width / 640.0); - GLfloat scaledY = y * (getConfig()->height / 480.0); + GLfloat scaledX = x * (gWidth / 640.0); + GLfloat scaledY = y * (gHeight / 480.0); _glVertex3f(scaledX, scaledY, z); } @@ -977,7 +955,7 @@ void glClearColorPH(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) void vf5WidthFix(void *param1) { - if (getConfig()->width > 1920) + if (gWidth > 1920) setVariable(0x86eb208, 1920); (((void (*)(void *))0x080d4c24)(param1)); } @@ -1015,11 +993,11 @@ void idDisplayTexture(void *p1, void *p2, int p3, int p4, int p5) { float newX = 0; if (p4 > 200) - newX = ((float)getConfig()->width / 2) - ((1360.0 / 2) - p4); + newX = ((float)gWidth / 2) - ((1360.0 / 2) - p4); else newX = p4; - float newY = (float)getConfig()->height * (p5 / 768.0); + float newY = (float)gHeight * (p5 / 768.0); idDisplayTextureFixCAVE(p1, p2, p3, (int)newX, (int)newY); } @@ -1040,7 +1018,7 @@ void calculateShift(int W, int H, float *ShiftX, float *ShiftY, bool right) void idDrawBallon(void *p1, void *p2, float p3, float p4, float p5, float p6, float p7, bool p8) { - calculateShift(getConfig()->width, getConfig()->height, &idShiftX, &isShiftY, p8); + calculateShift(gWidth, gHeight, &idShiftX, &isShiftY, p8); idDrawBallonFixCAVE(p1, p2, p3 + idShiftX, p4 + isShiftY, p5, p6, p7, p8); } @@ -1062,8 +1040,8 @@ void idTestText(long p1, long p2, unsigned int p3, char *p4) void patchABCMarkers(uint32_t addrCtrlEnemyInfo, uint32_t addrCtrlPlayerRivalFont, uint32_t addrCtrlEnemyPursuit2d) { // ctrl_enemy_information - newWidthRange_CEI_ABC = getConfig()->width + 100.0; - newHeightRange_CEI_ABC = getConfig()->height + 68.0; + newWidthRange_CEI_ABC = gWidth + 100.0; + newHeightRange_CEI_ABC = gHeight + 68.0; uint32_t *widthRangePtr_CEI = (uint32_t *)&newWidthRange_CEI_ABC; // 750 uint32_t *heightRangePtr_CEI = (uint32_t *)&newHeightRange_CEI_ABC; // 548 setVariable(addrCtrlEnemyInfo + 0x127, (size_t)widthRangePtr_CEI); // 750 @@ -1072,18 +1050,18 @@ void patchABCMarkers(uint32_t addrCtrlEnemyInfo, uint32_t addrCtrlPlayerRivalFon setVariable(addrCtrlEnemyInfo + 0x44c, (size_t)heightRangePtr_CEI); // 548 // Ctrl_Enemy_Pursuit_2d and Ctrl_Player, Rival_Font - newWidthABC = (float)getConfig()->width; // 640 - newHeightABC = (float)getConfig()->height; // 480 - newReducedWidthABC = (float)getConfig()->width - 40; // 600 - newReducedHeightABC = (float)getConfig()->height - 40; // 440 - newHalfWidthABC = (float)getConfig()->width / 2.0; // 320 - newHalfHeightABC = (float)getConfig()->height / 2.0; // 240 - newWidthRangeABC = getConfig()->width + 90.0; // 730 - newHeightRangeABC = getConfig()->height + 90.0; // 570 - new410ABC = (getConfig()->width / 2.0) + 90.0; // 410 - new330ABC = (getConfig()->height / 2.0) + 90.0; // 330 - new280ABC = (getConfig()->width / 2.0) - 40.0; // 280 - new200ABC = (getConfig()->height / 2.0) - 40.0; // 200 + newWidthABC = (float)gWidth; // 640 + newHeightABC = (float)gHeight; // 480 + newReducedWidthABC = (float)gWidth - 40; // 600 + newReducedHeightABC = (float)gHeight - 40; // 440 + newHalfWidthABC = (float)gWidth / 2.0; // 320 + newHalfHeightABC = (float)gHeight / 2.0; // 240 + newWidthRangeABC = gWidth + 90.0; // 730 + newHeightRangeABC = gHeight + 90.0; // 570 + new410ABC = (gWidth / 2.0) + 90.0; // 410 + new330ABC = (gHeight / 2.0) + 90.0; // 330 + new280ABC = (gWidth / 2.0) - 40.0; // 280 + new200ABC = (gHeight / 2.0) - 40.0; // 200 newWidthPtrABC = (uint32_t *)&newWidthABC; newHeightPtrABC = (uint32_t *)&newHeightABC; @@ -1147,7 +1125,7 @@ void patchABCMarkers(uint32_t addrCtrlEnemyInfo, uint32_t addrCtrlPlayerRivalFon void hookABCGLFunctions(uint32_t glBindTextureAddr, uint32_t glVertex3fAddr1, uint32_t glVertex3fAddr2) { - replaceCallAtAddress(glBindTextureAddr, glBindTextureABC); + replaceCallAtAddress(glBindTextureAddr, myGlBindTexture); replaceCallAtAddress(glVertex3fAddr1, glTexCoord2fvABC); replaceCallAtAddress(glVertex3fAddr1 + 0x1f, glVertex3fABC1); @@ -1197,11 +1175,11 @@ void glVertex3fHOD4(GLfloat x, GLfloat y, GLfloat z) void *returnAddress = __builtin_return_address(0); - float scaleX = getConfig()->width / 1280.0f; - float scaleY = getConfig()->height / 768.0f; + float scaleX = gWidth / 1280.0f; + float scaleY = gHeight / 768.0f; - float TestX = ((((getConfig()->width - 1280.0) / 2.0) * 1.1116317809) / 1280.0) * (1.5 / scaleX); - float TestY = ((((getConfig()->height - 768.0) / 2.0) * 0.666979044) / 768.0) * (1.5 / scaleX); + float TestX = ((((gWidth - 1280.0) / 2.0) * 1.1116317809) / 1280.0) * (1.5 / scaleX); + float TestY = ((((gHeight - 768.0) / 2.0) * 0.666979044) / 768.0) * (1.5 / scaleX); float OffsetX = TestX; // test float OffsetY = TestY; @@ -1212,7 +1190,7 @@ void glVertex3fHOD4(GLfloat x, GLfloat y, GLfloat z) if (z == -1.510000f) { // logo 2d elemtents target - if (curTextureIDGE != 260) // target boss fight + if (curTextureID != 260) // target boss fight { x += OffsetX; y -= OffsetY; @@ -1290,18 +1268,54 @@ void glVertex3fHOD4(GLfloat x, GLfloat y, GLfloat z) _glVertex3f(x, y, z); } +void glVertex3fHarley(GLfloat x, GLfloat y, GLfloat z) +{ + int (*_glVertex3f)(GLfloat x, GLfloat y, GLfloat z) = dlsym(RTLD_NEXT, "glVertex3f"); + + float scaleX = gWidth / 1360.0f; + float scaleY = gHeight / 768.0f; + + float OffsetX = ((gWidth - 1360.0) / 2.0) * 0.85; + float OffsetY = ((gHeight - 768.0) / 2.0) * 0.85; + + if (curTextureID == 71) + { + + x += OffsetX; + y -= OffsetY; + x *= scaleX; + y *= scaleY; + } + void *addr = __builtin_return_address(0); + // printf("glVertex3f is hooked: x=%f, y=%f, z=%f\n", x, y, z); + // printf("z values: %.10f\n", z); + + // if ( z == -3517.2272949219f){ //1360x768 + // if ( z == -4271.795898f){ //900p + if (z == -5300.7529296875) + { // 1080p + printf("glVertex3f hooked: x=%f, y=%f, z=%f, addr: %p\n", x, y, z, addr); + x -= 350; + y += 150; + } + + _glVertex3f(x, y, z); +} int initResolutionPatches() { - switch (getConfig()->crc32) + gWidth = getConfig()->width; + gHeight = getConfig()->height; + + switch (gId) { case AFTER_BURNER_CLIMAX: { - if (getConfig()->width == 640 && getConfig()->height == 480) + if (gWidth == 640 && gHeight == 480) break; - setVariable(0x082c0308, getConfig()->width); - setVariable(0x082c030c, getConfig()->height); - float newFontScale = getConfig()->height / 480.0; + setVariable(0x082c0308, gWidth); + setVariable(0x082c030c, gHeight); + float newFontScale = gHeight / 480.0; unsigned int *newFontScalePtr = (unsigned int *)&newFontScale; setVariable(0x0806cd72, *newFontScalePtr); abcDrawSpriteCAVEAddress = (void *)0x08076a28 + 6; @@ -1313,11 +1327,11 @@ int initResolutionPatches() break; case AFTER_BURNER_CLIMAX_REVA: { - if (getConfig()->width == 640 && getConfig()->height == 480) + if (gWidth == 640 && gHeight == 480) break; - setVariable(0x082c0a68, getConfig()->width); - setVariable(0x082c0a6c, getConfig()->height); - float newFontScale = getConfig()->height / 480.0; + setVariable(0x082c0a68, gWidth); + setVariable(0x082c0a6c, gHeight); + float newFontScale = gHeight / 480.0; unsigned int *newFontScalePtr = (unsigned int *)&newFontScale; setVariable(0x0806cd6a, *newFontScalePtr); abcDrawSpriteCAVEAddress = (void *)0x08076a20 + 6; @@ -1329,11 +1343,11 @@ int initResolutionPatches() break; case AFTER_BURNER_CLIMAX_REVB: { - if (getConfig()->width == 640 && getConfig()->height == 480) + if (gWidth == 640 && gHeight == 480) break; - setVariable(0x082C0AE8, getConfig()->width); - setVariable(0x082C0AEC, getConfig()->height); - float newFontScale = getConfig()->height / 480.0; + setVariable(0x082C0AE8, gWidth); + setVariable(0x082C0AEC, gHeight); + float newFontScale = gHeight / 480.0; unsigned int *newFontScalePtr = (unsigned int *)&newFontScale; setVariable(0x0806cd72, *newFontScalePtr); abcDrawSpriteCAVEAddress = (void *)0x08076a28 + 6; @@ -1345,11 +1359,11 @@ int initResolutionPatches() break; case AFTER_BURNER_CLIMAX_SDX: { - if (getConfig()->width == 640 && getConfig()->height == 480) + if (gWidth == 640 && gHeight == 480) break; - setVariable(0x082c2228, getConfig()->width); - setVariable(0x082c222c, getConfig()->height); - float newFontScale = getConfig()->height / 480.0; + setVariable(0x082c2228, gWidth); + setVariable(0x082c222c, gHeight); + float newFontScale = gHeight / 480.0; unsigned int *newFontScalePtr = (unsigned int *)&newFontScale; setVariable(0x0806ce2e, *newFontScalePtr); abcDrawSpriteCAVEAddress = (void *)0x08076ae4 + 6; @@ -1361,11 +1375,11 @@ int initResolutionPatches() break; case AFTER_BURNER_CLIMAX_SDX_REVA: { - if (getConfig()->width == 640 && getConfig()->height == 480) + if (gWidth == 640 && gHeight == 480) break; - setVariable(0x082c2228, getConfig()->width); - setVariable(0x082c222c, getConfig()->height); - float newFontScale = getConfig()->height / 480.0; + setVariable(0x082c2228, gWidth); + setVariable(0x082c222c, gHeight); + float newFontScale = gHeight / 480.0; unsigned int *newFontScalePtr = (unsigned int *)&newFontScale; setVariable(0x0806ce36, *newFontScalePtr); abcDrawSpriteCAVEAddress = (void *)0x08076aec + 6; @@ -1377,11 +1391,11 @@ int initResolutionPatches() break; case AFTER_BURNER_CLIMAX_SE: { - if (getConfig()->width == 640 && getConfig()->height == 480) + if (gWidth == 640 && gHeight == 480) break; - setVariable(0x082c0b28, getConfig()->width); - setVariable(0x082c0b2c, getConfig()->height); - float newFontScale = getConfig()->height / 480.0; + setVariable(0x082c0b28, gWidth); + setVariable(0x082c0b2c, gHeight); + float newFontScale = gHeight / 480.0; unsigned int *newFontScalePtr = (unsigned int *)&newFontScale; setVariable(0x0806cd6a, *newFontScalePtr); abcDrawSpriteCAVEAddress = (void *)0x08076a20 + 6; @@ -1393,11 +1407,11 @@ int initResolutionPatches() break; case AFTER_BURNER_CLIMAX_SE_REVA: { - if (getConfig()->width == 640 && getConfig()->height == 480) + if (gWidth == 640 && gHeight == 480) break; - setVariable(0x082c0b28, getConfig()->width); - setVariable(0x082c0b2c, getConfig()->height); - float newFontScale = getConfig()->height / 480.0; + setVariable(0x082c0b28, gWidth); + setVariable(0x082c0b2c, gHeight); + float newFontScale = gHeight / 480.0; unsigned int *newFontScalePtr = (unsigned int *)&newFontScale; setVariable(0x0806cd72, *newFontScalePtr); abcDrawSpriteCAVEAddress = (void *)0x08076a28 + 6; @@ -1417,10 +1431,21 @@ int initResolutionPatches() break; case HARLEY_DAVIDSON: { - if (getConfig()->width <= 1360 && getConfig()->height <= 768) + int w = gWidth; + int h = gHeight; + if (gWidth == 1360 && gHeight == 768) + { + if (getConfig()->boostRenderRes) + { + setVariable(0x088a55e0, w); // render res + patchMemory(0x08056c31, "9090909090"); + } break; - int w = getConfig()->width; - int h = getConfig()->height; + } + else if (gWidth == 640 && gHeight == 480) + { + break; + } setVariable(0x088a57e0, w); // main res setVariable(0x088a57e4, h); setVariable(0x088a57e8, w); @@ -1433,16 +1458,15 @@ int initResolutionPatches() patchMemory(0x082a8500, "9090909090"); // restype patchMemory(0x088a55e4, "14"); patchMemory(0x082a2412, "00008040"); // Fixes white logo background. - if (getConfig()->width > 1360) - { - unsigned int idx = ((21 * h) / 768) + 1; - setVariable(0x082a250e, idx); - } + unsigned int idx = ((21 * h) / 768) + 1; + setVariable(0x082a250e, idx); + detourFunction(0x0804c700, glVertex3fHarley); + detourFunction(0x0804d220, myGlBindTexture); } break; case HUMMER: { - if (getConfig()->width <= 1280 && getConfig()->height <= 768) + if (gWidth <= 1280 && gHeight <= 768) break; replaceCallAtAddress(0x080d8b58, hummerRespatch); replaceCallAtAddress(0x080d8b73, hummerRespatch); @@ -1454,7 +1478,7 @@ int initResolutionPatches() break; case HUMMER_EXTREME: { - if (getConfig()->width <= 1280 && getConfig()->height <= 768) + if (gWidth <= 1280 && gHeight <= 768) break; replaceCallAtAddress(0x08159eab, hummerRespatch); replaceCallAtAddress(0x08159ec9, hummerRespatch); @@ -1466,7 +1490,7 @@ int initResolutionPatches() break; case HUMMER_EXTREME_MDX: { - if (getConfig()->width <= 1280 && getConfig()->height <= 768) + if (gWidth <= 1280 && gHeight <= 768) break; replaceCallAtAddress(0x0816348b, hummerRespatch); replaceCallAtAddress(0x081634a9, hummerRespatch); @@ -1478,7 +1502,7 @@ int initResolutionPatches() break; case HUMMER_SDLX: { - if (getConfig()->width <= 1280 && getConfig()->height <= 768) + if (gWidth <= 1280 && gHeight <= 768) break; replaceCallAtAddress(0x080d8b14, hummerRespatch); replaceCallAtAddress(0x080d8b2f, hummerRespatch); @@ -1490,24 +1514,34 @@ int initResolutionPatches() break; case INITIALD_4_EXP_REVB: { - if (getConfig()->width == 1360 && getConfig()->height == 768) + if (gWidth == 1360 && gHeight == 768) + { + if (getConfig()->boostRenderRes) + { + setVariable(0x082560a2, gWidth); // Set ResX + setVariable(0x08256162, gWidth); // Set ResX + setVariable(0x08256222, gWidth); // Set ResX + setVariable(0x08256281, gWidth); // Set ResX + } break; - setVariable(0x0837979d, 0x0000f0e9); // Force set resolution - setVariable(0x08379893, getConfig()->width); // Set ResX - setVariable(0x08379898, getConfig()->height); // Set ResY + } + setVariable(0x0837979d, 0x0000f0e9); // Force set resolution + setVariable(0x08379893, gWidth); // Set ResX + setVariable(0x08379898, gHeight); // Set ResY // Renderbuffer Resolution - setVariable(0x082560a2, getConfig()->width); // Set ResX - setVariable(0x0825609a, getConfig()->height); // Set ResY - setVariable(0x08256162, getConfig()->width); // Set ResX - setVariable(0x0825615a, getConfig()->height); // Set ResY - setVariable(0x08256222, getConfig()->width); // Set ResX - setVariable(0x0825621a, getConfig()->height); // Set ResY - setVariable(0x08256281, getConfig()->width); // Set ResX - setVariable(0x08256279, getConfig()->height); // Set ResY - setVariable(0x08256b27, getConfig()->width); // Set ResX - setVariable(0x08256b1f, getConfig()->height); // Set ResY - setVariable(0x08256bb2, getConfig()->width); // Set ResX - setVariable(0x08256baa, getConfig()->height); // Set ResY + setVariable(0x082560a2, gWidth); // Set ResX + setVariable(0x0825609a, gHeight); // Set ResY + setVariable(0x08256162, gWidth); // Set ResX + setVariable(0x0825615a, gHeight); // Set ResY + setVariable(0x08256222, gWidth); // Set ResX + setVariable(0x0825621a, gHeight); // Set ResY + setVariable(0x08256281, gWidth); // Set ResX + setVariable(0x08256279, gHeight); // Set ResY + + setVariable(0x08256b27, gWidth); // Set ResX + setVariable(0x08256b1f, gHeight); // Set ResY + setVariable(0x08256bb2, gWidth); // Set ResX + setVariable(0x08256baa, gHeight); // Set ResY idDisplayTextureCAVEAddress = (void *)0x08337360 + 5; detourFunction(0x08337360, idDisplayTexture); @@ -1516,7 +1550,7 @@ int initResolutionPatches() patchMemory(0x0857dfe9, "01"); // FSAA Enabled setVariable(0x089ea1d0, 1); // FSAA Quality // Fix Subtitles Position - id4NewCaptionY = ((getConfig()->height - 768.0) / 2) + 64.0; + id4NewCaptionY = ((gHeight - 768.0) / 2) + 64.0; detourFunction(0x081f0f91, yTxtPatch); id4NewCaptionYCAVEAddress = (void *)(0x081f0f91 + 8); // Ballon fix @@ -1525,10 +1559,10 @@ int initResolutionPatches() detourFunction(0x081ef2ee, idDrawBallon); replaceCallAtAddress(0x081f084a, id4DrawText); // Scale Testmode text - if (isTestMode() && getConfig()->width >= 1920) + if (isTestMode() && gWidth >= 1920) { patchMemory(0x0899bb78, "02"); - idTextShift = (getConfig()->width == 1920 ? 27 : ((1920 / getConfig()->width) * 27) + 2); + idTextShift = (gWidth == 1920 ? 27 : ((1920 / gWidth) * 27) + 2); idTestTextAddress = (void *)0x08579e92; replaceCallAtAddress(0x0835a1fe, idTestText); } @@ -1536,24 +1570,33 @@ int initResolutionPatches() break; case INITIALD_4_EXP_REVC: { - if (getConfig()->width == 1360 && getConfig()->height == 768) + if (gWidth == 1360 && gHeight == 768) + { + if (getConfig()->boostRenderRes) + { + setVariable(0x08256192, gWidth); // Set ResX + setVariable(0x08256252, gWidth); // Set ResX + setVariable(0x08256312, gWidth); // Set ResX + setVariable(0x08256371, gWidth); // Set ResX + } break; - setVariable(0x0837961d, 0x0000f0e9); // Force set resolution - setVariable(0x08379713, getConfig()->width); // Set ResX - setVariable(0x08379718, getConfig()->height); // Set ResY + } + setVariable(0x0837961d, 0x0000f0e9); // Force set resolution + setVariable(0x08379713, gWidth); // Set ResX + setVariable(0x08379718, gHeight); // Set ResY // Renderbuffer Resolution - setVariable(0x08256192, getConfig()->width); // Set ResX - setVariable(0x0825618a, getConfig()->height); // Set ResY - setVariable(0x08256252, getConfig()->width); // Set ResX - setVariable(0x0825624a, getConfig()->height); // Set ResY - setVariable(0x08256312, getConfig()->width); // Set ResX - setVariable(0x0825630a, getConfig()->height); // Set ResY - setVariable(0x08256371, getConfig()->width); // Set ResX - setVariable(0x08256369, getConfig()->height); // Set ResY - setVariable(0x08256c17, getConfig()->width); // Set ResX - setVariable(0x08256c0f, getConfig()->height); // Set ResY - setVariable(0x08256ca2, getConfig()->width); // Set ResX - setVariable(0x08256c9a, getConfig()->height); // Set ResY + setVariable(0x08256192, gWidth); // Set ResX + setVariable(0x0825618a, gHeight); // Set ResY + setVariable(0x08256252, gWidth); // Set ResX + setVariable(0x0825624a, gHeight); // Set ResY + setVariable(0x08256312, gWidth); // Set ResX + setVariable(0x0825630a, gHeight); // Set ResY + setVariable(0x08256371, gWidth); // Set ResX + setVariable(0x08256369, gHeight); // Set ResY + setVariable(0x08256c17, gWidth); // Set ResX + setVariable(0x08256c0f, gHeight); // Set ResY + setVariable(0x08256ca2, gWidth); // Set ResX + setVariable(0x08256c9a, gHeight); // Set ResY idDisplayTextureCAVEAddress = (void *)0x08337200 + 5; detourFunction(0x08337200, idDisplayTexture); @@ -1562,10 +1605,10 @@ int initResolutionPatches() patchMemory(0x0857dd69, "01"); // FSAA Enabled setVariable(0x089ea1d0, 1); // FSAA Quality // Fix Subtitles - float newCaptionY = ((getConfig()->height - 768.0) / 2) + 64.0; + float newCaptionY = ((gHeight - 768.0) / 2) + 64.0; setVariable(0x089a7d58, *(unsigned int *)&newCaptionY); // Fix Subtitles Position - id4NewCaptionY = ((getConfig()->height - 768.0) / 2) + 64.0; + id4NewCaptionY = ((gHeight - 768.0) / 2) + 64.0; detourFunction(0x081f1051, yTxtPatch); id4NewCaptionYCAVEAddress = (void *)(0x081f1051 + 8); // Ballon fix @@ -1574,10 +1617,10 @@ int initResolutionPatches() detourFunction(0x081ef39e, idDrawBallon); replaceCallAtAddress(0x081f08fc, id4DrawText); // Scale Testmode text - if (isTestMode() && getConfig()->width >= 1920) + if (isTestMode() && gWidth >= 1920) { patchMemory(0x0899bb78, "02"); - idTextShift = (getConfig()->width == 1920 ? 27 : ((1920 / getConfig()->width) * 27) + 2); + idTextShift = (gWidth == 1920 ? 27 : ((1920 / gWidth) * 27) + 2); idTestTextAddress = (void *)0x08579c12; replaceCallAtAddress(0x0835a09e, idTestText); } @@ -1585,24 +1628,33 @@ int initResolutionPatches() break; case INITIALD_4_EXP_REVD: { - if (getConfig()->width == 1360 && getConfig()->height == 768) + if (gWidth == 1360 && gHeight == 768) + { + if (getConfig()->boostRenderRes) + { + setVariable(0x0825728a, gWidth); // Set ResX + setVariable(0x0825734a, gWidth); // Set ResX + setVariable(0x0825740a, gWidth); // Set ResX + setVariable(0x08257469, gWidth); // Set ResX + } break; - setVariable(0x0837b12d, 0x0000f0e9); // Force set resolution - setVariable(0x0837b223, getConfig()->width); // Set ResX - setVariable(0x0837b228, getConfig()->height); // Set ResY + } + setVariable(0x0837b12d, 0x0000f0e9); // Force set resolution + setVariable(0x0837b223, gWidth); // Set ResX + setVariable(0x0837b228, gHeight); // Set ResY // Renderbuffer Resolution - setVariable(0x0825728a, getConfig()->width); // Set ResX - setVariable(0x08257282, getConfig()->height); // Set ResY - setVariable(0x0825734a, getConfig()->width); // Set ResX - setVariable(0x08257342, getConfig()->height); // Set ResY - setVariable(0x0825740a, getConfig()->width); // Set ResX - setVariable(0x08257402, getConfig()->height); // Set ResY - setVariable(0x08257469, getConfig()->width); // Set ResX - setVariable(0x08257461, getConfig()->height); // Set ResY - setVariable(0x08257d0f, getConfig()->width); // Set ResX - setVariable(0x08257d07, getConfig()->height); // Set ResY - setVariable(0x08257d9a, getConfig()->width); // Set ResX - setVariable(0x08257d92, getConfig()->height); // Set ResY + setVariable(0x0825728a, gWidth); // Set ResX + setVariable(0x08257282, gHeight); // Set ResY + setVariable(0x0825734a, gWidth); // Set ResX + setVariable(0x08257342, gHeight); // Set ResY + setVariable(0x0825740a, gWidth); // Set ResX + setVariable(0x08257402, gHeight); // Set ResY + setVariable(0x08257469, gWidth); // Set ResX + setVariable(0x08257461, gHeight); // Set ResY + setVariable(0x08257d0f, gWidth); // Set ResX + setVariable(0x08257d07, gHeight); // Set ResY + setVariable(0x08257d9a, gWidth); // Set ResX + setVariable(0x08257d92, gHeight); // Set ResY idDisplayTextureCAVEAddress = (void *)0x08338d50 + 5; detourFunction(0x08338d50, idDisplayTexture); @@ -1611,7 +1663,7 @@ int initResolutionPatches() patchMemory(0x0857f879, "01"); // FSAA Enabled setVariable(0x089ed930, 1); // FSAA Quality // Fix Subtitles Position - id4NewCaptionY = ((getConfig()->height - 768.0) / 2) + 64.0; + id4NewCaptionY = ((gHeight - 768.0) / 2) + 64.0; detourFunction(0x081f2061, yTxtPatch); id4NewCaptionYCAVEAddress = (void *)(0x081f2061 + 8); // Ballon fix @@ -1620,10 +1672,10 @@ int initResolutionPatches() detourFunction(0x081f03be, idDrawBallon); replaceCallAtAddress(0x081f191a, id4DrawText); // Scale Testmode text - if (isTestMode() && getConfig()->width >= 1920) + if (isTestMode() && gWidth >= 1920) { patchMemory(0x0899f2d8, "02"); - idTextShift = (getConfig()->width == 1920 ? 27 : ((1920 / getConfig()->width) * 27) + 2); + idTextShift = (gWidth == 1920 ? 27 : ((1920 / gWidth) * 27) + 2); idTestTextAddress = (void *)0x0857b722; replaceCallAtAddress(0x0835bbee, idTestText); } @@ -1631,24 +1683,33 @@ int initResolutionPatches() break; case INITIALD_4_REVA: { - if (getConfig()->width == 1360 && getConfig()->height == 768) + if (gWidth == 1360 && gHeight == 768) + { + if (getConfig()->boostRenderRes) + { + setVariable(0x08247e77, gWidth); // Set ResX + setVariable(0x08247f37, gWidth); // Set ResX + setVariable(0x08247ff7, gWidth); // Set ResX + setVariable(0x08248056, gWidth); // Set ResX + } break; + } setVariable(0x0835640d, 0x0000f0e9); // Force set resolution - setVariable(0x08356503, getConfig()->width); // Set ResX - setVariable(0x08356508, getConfig()->height); // Set ResY + setVariable(0x08356503, gWidth); // Set ResX + setVariable(0x08356508, gHeight); // Set ResY // Renderbuffer Resolution - setVariable(0x08247e77, getConfig()->width); // Set ResX - setVariable(0x08247e6f, getConfig()->height); // Set ResY - setVariable(0x08247f37, getConfig()->width); // Set ResX - setVariable(0x08247f2f, getConfig()->height); // Set ResY - setVariable(0x08247ff7, getConfig()->width); // Set ResX - setVariable(0x08247fef, getConfig()->height); // Set ResY - setVariable(0x08248056, getConfig()->width); // Set ResX - setVariable(0x0824804e, getConfig()->height); // Set ResY - setVariable(0x082487e7, getConfig()->width); // Set ResX - setVariable(0x082487df, getConfig()->height); // Set ResY - setVariable(0x08248872, getConfig()->width); // Set ResX - setVariable(0x0824886a, getConfig()->height); // Set ResY + setVariable(0x08247e77, gWidth); // Set ResX + setVariable(0x08247e6f, gHeight); // Set ResY + setVariable(0x08247f37, gWidth); // Set ResX + setVariable(0x08247f2f, gHeight); // Set ResY + setVariable(0x08247ff7, gWidth); // Set ResX + setVariable(0x08247fef, gHeight); // Set ResY + setVariable(0x08248056, gWidth); // Set ResX + setVariable(0x0824804e, gHeight); // Set ResY + setVariable(0x082487e7, gWidth); // Set ResX + setVariable(0x082487df, gHeight); // Set ResY + setVariable(0x08248872, gWidth); // Set ResX + setVariable(0x0824886a, gHeight); // Set ResY idDisplayTextureCAVEAddress = (void *)0x083188a0 + 5; detourFunction(0x083188a0, idDisplayTexture); @@ -1665,24 +1726,33 @@ int initResolutionPatches() break; case INITIALD_4_REVB: { - if (getConfig()->width == 1360 && getConfig()->height == 768) + if (gWidth == 1360 && gHeight == 768) + { + if (getConfig()->boostRenderRes) + { + setVariable(0x08248037, gWidth); // Set ResX + setVariable(0x082480f7, gWidth); // Set ResX + setVariable(0x082481b7, gWidth); // Set ResX + setVariable(0x08248216, gWidth); // Set ResX + } break; + } setVariable(0x0835664d, 0x0000f0e9); // Force set resolution - setVariable(0x08356743, getConfig()->width); // Set ResX - setVariable(0x08356748, getConfig()->height); // Set ResY + setVariable(0x08356743, gWidth); // Set ResX + setVariable(0x08356748, gHeight); // Set ResY // Renderbuffer Resolution - setVariable(0x08248037, getConfig()->width); // Set ResX - setVariable(0x0824802f, getConfig()->height); // Set ResY - setVariable(0x082480f7, getConfig()->width); // Set ResX - setVariable(0x082480ef, getConfig()->height); // Set ResY - setVariable(0x082481b7, getConfig()->width); // Set ResX - setVariable(0x082481af, getConfig()->height); // Set ResY - setVariable(0x08248216, getConfig()->width); // Set ResX - setVariable(0x0824820e, getConfig()->height); // Set ResY - setVariable(0x082489a7, getConfig()->width); // Set ResX - setVariable(0x0824899f, getConfig()->height); // Set ResY - setVariable(0x08248a32, getConfig()->width); // Set ResX - setVariable(0x08248a2a, getConfig()->height); // Set ResY + setVariable(0x08248037, gWidth); // Set ResX + setVariable(0x0824802f, gHeight); // Set ResY + setVariable(0x082480f7, gWidth); // Set ResX + setVariable(0x082480ef, gHeight); // Set ResY + setVariable(0x082481b7, gWidth); // Set ResX + setVariable(0x082481af, gHeight); // Set ResY + setVariable(0x08248216, gWidth); // Set ResX + setVariable(0x0824820e, gHeight); // Set ResY + setVariable(0x082489a7, gWidth); // Set ResX + setVariable(0x0824899f, gHeight); // Set ResY + setVariable(0x08248a32, gWidth); // Set ResX + setVariable(0x08248a2a, gHeight); // Set ResY idDisplayTextureCAVEAddress = (void *)0x08318ab0 + 5; detourFunction(0x08318ab0, idDisplayTexture); @@ -1699,24 +1769,33 @@ int initResolutionPatches() break; case INITIALD_4_REVC: { - if (getConfig()->width == 1360 && getConfig()->height == 768) + if (gWidth == 1360 && gHeight == 768) + { + if (getConfig()->boostRenderRes) + { + setVariable(0x08248ad7, gWidth); // Set ResX + setVariable(0x08248b97, gWidth); // Set ResX + setVariable(0x08248c57, gWidth); // Set ResX + setVariable(0x08248cb6, gWidth); // Set ResX + } break; + } setVariable(0x0835eebd, 0x0000f0e9); // Force set resolution - setVariable(0x0835efb3, getConfig()->width); // Set ResX - setVariable(0x0835efb8, getConfig()->height); // Set ResY + setVariable(0x0835efb3, gWidth); // Set ResX + setVariable(0x0835efb8, gHeight); // Set ResY // Renderbuffer Resolution - setVariable(0x08248ad7, getConfig()->width); // Set ResX - setVariable(0x08248acf, getConfig()->height); // Set ResY - setVariable(0x08248b97, getConfig()->width); // Set ResX - setVariable(0x08248b8f, getConfig()->height); // Set ResY - setVariable(0x08248c57, getConfig()->width); // Set ResX - setVariable(0x08248c4f, getConfig()->height); // Set ResY - setVariable(0x08248cb6, getConfig()->width); // Set ResX - setVariable(0x08248cae, getConfig()->height); // Set ResY - setVariable(0x08249447, getConfig()->width); // Set ResX - setVariable(0x0824943f, getConfig()->height); // Set ResY - setVariable(0x082494d2, getConfig()->width); // Set ResX - setVariable(0x082494ca, getConfig()->height); // Set ResY + setVariable(0x08248ad7, gWidth); // Set ResX + setVariable(0x08248acf, gHeight); // Set ResY + setVariable(0x08248b97, gWidth); // Set ResX + setVariable(0x08248b8f, gHeight); // Set ResY + setVariable(0x08248c57, gWidth); // Set ResX + setVariable(0x08248c4f, gHeight); // Set ResY + setVariable(0x08248cb6, gWidth); // Set ResX + setVariable(0x08248cae, gHeight); // Set ResY + setVariable(0x08249447, gWidth); // Set ResX + setVariable(0x0824943f, gHeight); // Set ResY + setVariable(0x082494d2, gWidth); // Set ResX + setVariable(0x082494ca, gHeight); // Set ResY idDisplayTextureCAVEAddress = (void *)0x0831ea60 + 5; detourFunction(0x0831ea60, idDisplayTexture); @@ -1733,24 +1812,33 @@ int initResolutionPatches() break; case INITIALD_4_REVD: { - if (getConfig()->width == 1360 && getConfig()->height == 768) + if (gWidth == 1360 && gHeight == 768) + { + if (getConfig()->boostRenderRes) + { + setVariable(0x08248f47, gWidth); // Set ResX + setVariable(0x08249007, gWidth); // Set ResX + setVariable(0x082490c7, gWidth); // Set ResX + setVariable(0x08249126, gWidth); // Set ResX + } break; + } setVariable(0x0835c55d, 0x0000f0e9); // Force set resolution - setVariable(0x0835c653, getConfig()->width); // Set ResX - setVariable(0x0835c658, getConfig()->height); // Set ResY + setVariable(0x0835c653, gWidth); // Set ResX + setVariable(0x0835c658, gHeight); // Set ResY // Renderbuffer Resolution - setVariable(0x08248f47, getConfig()->width); // Set ResX - setVariable(0x08248f3f, getConfig()->height); // Set ResY - setVariable(0x08249007, getConfig()->width); // Set ResX - setVariable(0x08248fff, getConfig()->height); // Set ResY - setVariable(0x082490c7, getConfig()->width); // Set ResX - setVariable(0x082490bf, getConfig()->height); // Set ResY - setVariable(0x08249126, getConfig()->width); // Set ResX - setVariable(0x0824911e, getConfig()->height); // Set ResY - setVariable(0x082498b7, getConfig()->width); // Set ResX - setVariable(0x082498af, getConfig()->height); // Set ResY - setVariable(0x08249942, getConfig()->width); // Set ResX - setVariable(0x0824993a, getConfig()->height); // Set ResY + setVariable(0x08248f47, gWidth); // Set ResX + setVariable(0x08248f3f, gHeight); // Set ResY + setVariable(0x08249007, gWidth); // Set ResX + setVariable(0x08248fff, gHeight); // Set ResY + setVariable(0x082490c7, gWidth); // Set ResX + setVariable(0x082490bf, gHeight); // Set ResY + setVariable(0x08249126, gWidth); // Set ResX + setVariable(0x0824911e, gHeight); // Set ResY + setVariable(0x082498b7, gWidth); // Set ResX + setVariable(0x082498af, gHeight); // Set ResY + setVariable(0x08249942, gWidth); // Set ResX + setVariable(0x0824993a, gHeight); // Set ResY idDisplayTextureCAVEAddress = (void *)0x0831bf90 + 5; detourFunction(0x0831bf90, idDisplayTexture); @@ -1767,24 +1855,33 @@ int initResolutionPatches() break; case INITIALD_4_REVG: { - if (getConfig()->width == 1360 && getConfig()->height == 768) + if (gWidth == 1360 && gHeight == 768) + { + if (getConfig()->boostRenderRes) + { + setVariable(0x08262eda, gWidth); // Set ResX + setVariable(0x08262f9a, gWidth); // Set ResX + setVariable(0x0826305a, gWidth); // Set ResX + setVariable(0x082630b9, gWidth); // Set ResX + } break; + } setVariable(0x08393fbd, 0x0000f0e9); // Force set resolution - setVariable(0x083940b3, getConfig()->width); // Set ResX - setVariable(0x083940b8, getConfig()->height); // Set ResY + setVariable(0x083940b3, gWidth); // Set ResX + setVariable(0x083940b8, gHeight); // Set ResY // Renderbuffer Resolution - setVariable(0x08262eda, getConfig()->width); // Set ResX - setVariable(0x08262ed2, getConfig()->height); // Set ResY - setVariable(0x08262f9a, getConfig()->width); // Set ResX - setVariable(0x08262f92, getConfig()->height); // Set ResY - setVariable(0x0826305a, getConfig()->width); // Set ResX - setVariable(0x08263052, getConfig()->height); // Set ResY - setVariable(0x082630b9, getConfig()->width); // Set ResX - setVariable(0x082630b1, getConfig()->height); // Set ResY - setVariable(0x0826395f, getConfig()->width); // Set ResX - setVariable(0x08263957, getConfig()->height); // Set ResY - setVariable(0x082639ea, getConfig()->width); // Set ResX - setVariable(0x082639e2, getConfig()->height); // Set ResY + setVariable(0x08262eda, gWidth); // Set ResX + setVariable(0x08262ed2, gHeight); // Set ResY + setVariable(0x08262f9a, gWidth); // Set ResX + setVariable(0x08262f92, gHeight); // Set ResY + setVariable(0x0826305a, gWidth); // Set ResX + setVariable(0x08263052, gHeight); // Set ResY + setVariable(0x082630b9, gWidth); // Set ResX + setVariable(0x082630b1, gHeight); // Set ResY + setVariable(0x0826395f, gWidth); // Set ResX + setVariable(0x08263957, gHeight); // Set ResY + setVariable(0x082639ea, gWidth); // Set ResX + setVariable(0x082639e2, gHeight); // Set ResY idDisplayTextureCAVEAddress = (void *)0x083502b0 + 5; detourFunction(0x083502b0, idDisplayTexture); @@ -1798,10 +1895,10 @@ int initResolutionPatches() detourFunction(0x081f2b7e, idDrawBallon); replaceCallAtAddress(0x081f40da, id4DrawText); // Scale Testmode text - if (isTestMode() && getConfig()->width >= 1920) + if (isTestMode() && gWidth >= 1920) { patchMemory(0x089e15d8, "02"); - idTextShift = (getConfig()->width == 1920 ? 27 : ((1920 / getConfig()->width) * 27) + 2); + idTextShift = (gWidth == 1920 ? 27 : ((1920 / gWidth) * 27) + 2); idTestTextAddress = (void *)0x085945c2; replaceCallAtAddress(0x083748ce, idTestText); } @@ -1809,30 +1906,38 @@ int initResolutionPatches() break; case INITIALD_5_EXP: { - if (getConfig()->width == 1360 && getConfig()->height == 768) + bool origRes = (gWidth == 1360 && gHeight == 768); + if (!getConfig()->boostRenderRes && origRes) + { break; - patchMemory(0x0853d8cd, "E9f000"); // Accept different Resolutions - setVariable(0x0853d9c3, getConfig()->width); // Set ResX - setVariable(0x0853d9c8, getConfig()->height); // Set ResY + } + if (gWidth >= 1360 && gHeight >= 768) + { + patchMemory(0x08356054, "bb01000000eb6b"); // Prevents renrer.ini from loading + setVariable(0x08355f30, gWidth); // Framebuffer Main Width + setVariable(0x08355f37, gHeight); // Framebuffer Main Height + setVariable(0x08355fd1, 256); // Framebuffer Road Specular width + setVariable(0x08355fd8, 256); // Framebuffer Road Specular height + setVariable(0x08355ff7, gWidth); // Framebuffer Glare Width + setVariable(0x08355ffe, gHeight); // Framebuffer Glare Height + setVariable(0x08356024, gWidth >> 2); // Framebuffer Reduced width + patchMemory(0x08356049, "00000001"); // Enable Cube Secular + if (origRes) + break; + } + patchMemory(0x0853d8cd, "E9f000"); // Accept different Resolutions + setVariable(0x0853d9c3, gWidth); // Set ResX + setVariable(0x0853d9c8, gHeight); // Set ResY - patchMemory(0x08356054, "bb01000000eb6b"); // Prevents renrer.ini from loading - setVariable(0x08355f30, getConfig()->width); // Framebuffer Main Width - setVariable(0x08355f37, getConfig()->height); // Framebuffer Main Height - setVariable(0x08355fd1, 256); // Framebuffer Road Specular width - setVariable(0x08355fd8, 256); // Framebuffer Road Specular height - setVariable(0x08355ff7, getConfig()->width); // Framebuffer Glare Width - setVariable(0x08355ffe, getConfig()->height); // Framebuffer Glare Height - setVariable(0x08356024, getConfig()->width >> 2); // Framebuffer Reduced width - patchMemory(0x08356049, "00000001"); // Enable Cube Secular // Fix Press start and Insert coins text idDisplayTextureCAVEAddress = (void *)0x084e2470 + 5; detourFunction(0x084e2470, idDisplayTexture); // setViewport for track selection screen - setVariable(0x08215cae, (int)(getConfig()->height * (112.0 / 768))); - setVariable(0x08215cb6, (int)(getConfig()->width * (724.0 / 1315))); - setVariable(0x08215cbe, (int)(getConfig()->height * (592.0 / 768))); - setVariable(0x08215cc6, (int)(getConfig()->width * (962.0 / 1315))); - setVariable(0x08215cce, getConfig()->height); + setVariable(0x08215cae, (int)(gHeight * (112.0 / 768))); + setVariable(0x08215cb6, (int)(gWidth * (724.0 / 1315))); + setVariable(0x08215cbe, (int)(gHeight * (592.0 / 768))); + setVariable(0x08215cc6, (int)(gWidth * (962.0 / 1315))); + setVariable(0x08215cce, gHeight); // FSAA patchMemory(0x0875aaa6, "9090"); patchMemory(0x08788949, "01"); // FSAA Enabled @@ -1844,15 +1949,15 @@ int initResolutionPatches() replaceCallAtAddress(0x08254b68, idBalloonPut); replaceCallAtAddress(0x08254c29, idBalloonPut); // START and VIEW CHANGE Text fix - float explanationScaleX = getConfig()->width - (1360.0 - 815.0); - float explanationScaleY = (getConfig()->height / 768.0) * 680.0; + float explanationScaleX = gWidth - (1360.0 - 815.0); + float explanationScaleY = (gHeight / 768.0) * 680.0; setVariable(0x0826ac45, *(unsigned int *)&explanationScaleY); setVariable(0x0826acbd, *(unsigned int *)&explanationScaleX); // Scale Testmode text - if (isTestMode() && getConfig()->width >= 1920) + if (isTestMode() && gWidth >= 1920) { patchMemory(0x08c55ca0, "02"); - idTextShift = (getConfig()->width == 1920 ? 27 : ((1920 / getConfig()->width) * 27) + 2); + idTextShift = (gWidth == 1920 ? 27 : ((1920 / gWidth) * 27) + 2); idTestTextAddress = (void *)0x08775c1c; replaceCallAtAddress(0x0850853e, idTestText); } @@ -1860,30 +1965,37 @@ int initResolutionPatches() break; case INITIALD_5_EXP_20: { - if (getConfig()->width == 1360 && getConfig()->height == 768) + bool origRes = (gWidth == 1360 && gHeight == 768); + if (!getConfig()->boostRenderRes && origRes) + { break; - patchMemory(0x0855a48d, "E9f000"); // Accept different Resolutions - setVariable(0x0855a583, getConfig()->width); // Set ResX - setVariable(0x0855a588, getConfig()->height); // Set ResY - - patchMemory(0x08363c24, "bb01000000eb6b"); // Prevents renrer.ini from loading - setVariable(0x08363b00, getConfig()->width); // Framebuffer Main Width - setVariable(0x08363b07, getConfig()->height); // Framebuffer Main Height - setVariable(0x08363ba1, 256); // Framebuffer Road Specular width - setVariable(0x08363ba8, 256); // Framebuffer Road Specular height - setVariable(0x08363bc7, getConfig()->width); // Framebuffer Glare Width - setVariable(0x08363bce, getConfig()->height); // Framebuffer Glare Height - setVariable(0x08363bf4, getConfig()->width >> 2); // Framebuffer Reduced width - patchMemory(0x08363c19, "00000001"); // Enable Cube Secular + } + if (gWidth >= 1360 && gHeight >= 768) + { + patchMemory(0x08363c24, "bb01000000eb6b"); // Prevents renrer.ini from loading + setVariable(0x08363b00, gWidth); // Framebuffer Main Width + setVariable(0x08363b07, gHeight); // Framebuffer Main Height + setVariable(0x08363ba1, 256); // Framebuffer Road Specular width + setVariable(0x08363ba8, 256); // Framebuffer Road Specular height + setVariable(0x08363bc7, gWidth); // Framebuffer Glare Width + setVariable(0x08363bce, gHeight); // Framebuffer Glare Height + setVariable(0x08363bf4, gWidth >> 2); // Framebuffer Reduced width + patchMemory(0x08363c19, "00000001"); // Enable Cube Secular + if (origRes) + break; + } + patchMemory(0x0855a48d, "E9f000"); // Accept different Resolutions + setVariable(0x0855a583, gWidth); // Set ResX + setVariable(0x0855a588, gHeight); // Set ResY // Fix Press start and Insert coins text idDisplayTextureCAVEAddress = (void *)0x084fdfa0 + 5; detourFunction(0x084fdfa0, idDisplayTexture); // setViewport for track selection screen - setVariable(0x0821e75e, (int)(getConfig()->height * (112.0 / 768))); - setVariable(0x0821e766, (int)(getConfig()->width * (724.0 / 1315))); - setVariable(0x0821e76e, (int)(getConfig()->height * (592.0 / 768))); - setVariable(0x0821e776, (int)(getConfig()->width * (962.0 / 1315))); - setVariable(0x0821e77e, getConfig()->height); + setVariable(0x0821e75e, (int)(gHeight * (112.0 / 768))); + setVariable(0x0821e766, (int)(gWidth * (724.0 / 1315))); + setVariable(0x0821e76e, (int)(gHeight * (592.0 / 768))); + setVariable(0x0821e776, (int)(gWidth * (962.0 / 1315))); + setVariable(0x0821e77e, gHeight); // FSAA patchMemory(0x087775f6, "9090"); patchMemory(0x087a5499, "01"); // FSAA Enabled @@ -1895,15 +2007,15 @@ int initResolutionPatches() replaceCallAtAddress(0x0825d4e8, idBalloonPut); replaceCallAtAddress(0x0825d5a9, idBalloonPut); // START and VIEW CHANGE Text fix - float explanationScaleX = getConfig()->width - (1360.0 - 815.0); - float explanationScaleY = (getConfig()->height / 768.0) * 680.0; + float explanationScaleX = gWidth - (1360.0 - 815.0); + float explanationScaleY = (gHeight / 768.0) * 680.0; setVariable(0x082737b5, *(unsigned int *)&explanationScaleY); setVariable(0x0827382d, *(unsigned int *)&explanationScaleX); // Scale Testmode text - if (isTestMode() && getConfig()->width >= 1920) + if (isTestMode() && gWidth >= 1920) { patchMemory(0x08ca3d00, "02"); - idTextShift = (getConfig()->width == 1920 ? 27 : ((1920 / getConfig()->width) * 27) + 2); + idTextShift = (gWidth == 1920 ? 27 : ((1920 / gWidth) * 27) + 2); idTestTextAddress = (void *)0x0879276c; replaceCallAtAddress(0x0852528a, idTestText); } @@ -1911,30 +2023,38 @@ int initResolutionPatches() break; case INITIALD_5_EXP_20A: { - if (getConfig()->width == 1360 && getConfig()->height == 768) + bool origRes = (gWidth == 1360 && gHeight == 768); + if (!getConfig()->boostRenderRes && origRes) + { break; - patchMemory(0x0855a6dd, "E9f000"); // Accept different Resolutions - setVariable(0x0855a7d3, getConfig()->width); // Set ResX - setVariable(0x0855a7d8, getConfig()->height); // Set ResY + } + if (gWidth >= 1360 && gHeight >= 768) + { + patchMemory(0x08363d94, "bb01000000eb6b"); // Prevents renrer.ini from loading + setVariable(0x08363c70, gWidth); // Framebuffer Main Width + setVariable(0x08363c77, gHeight); // Framebuffer Main Height + setVariable(0x08363d11, 256); // Framebuffer Road Specular width + setVariable(0x08363d18, 256); // Framebuffer Road Specular height + setVariable(0x08363d37, gWidth); // Framebuffer Glare Width + setVariable(0x08363d3e, gHeight); // Framebuffer Glare Height + setVariable(0x08363d64, gWidth >> 2); // Framebuffer Reduced width + patchMemory(0x08363d89, "00000001"); // Enable Cube Secular + if (origRes) + break; + } + patchMemory(0x0855a6dd, "E9f000"); // Accept different Resolutions + setVariable(0x0855a7d3, gWidth); // Set ResX + setVariable(0x0855a7d8, gHeight); // Set ResY - patchMemory(0x08363d94, "bb01000000eb6b"); // Prevents renrer.ini from loading - setVariable(0x08363c70, getConfig()->width); // Framebuffer Main Width - setVariable(0x08363c77, getConfig()->height); // Framebuffer Main Height - setVariable(0x08363d11, 256); // Framebuffer Road Specular width - setVariable(0x08363d18, 256); // Framebuffer Road Specular height - setVariable(0x08363d37, getConfig()->width); // Framebuffer Glare Width - setVariable(0x08363d3e, getConfig()->height); // Framebuffer Glare Height - setVariable(0x08363d64, getConfig()->width >> 2); // Framebuffer Reduced width - patchMemory(0x08363d89, "00000001"); // Enable Cube Secular // Fix Press start and Insert coins text idDisplayTextureCAVEAddress = (void *)0x084fe1d0 + 5; detourFunction(0x084fe1d0, idDisplayTexture); // setViewport for track selection screen - setVariable(0x0821e8ee, (int)(getConfig()->height * (112.0 / 768))); - setVariable(0x0821e8f6, (int)(getConfig()->width * (724.0 / 1315))); - setVariable(0x0821e8fe, (int)(getConfig()->height * (592.0 / 768))); - setVariable(0x0821e906, (int)(getConfig()->width * (962.0 / 1315))); - setVariable(0x0821e90e, getConfig()->height); + setVariable(0x0821e8ee, (int)(gHeight * (112.0 / 768))); + setVariable(0x0821e8f6, (int)(gWidth * (724.0 / 1315))); + setVariable(0x0821e8fe, (int)(gHeight * (592.0 / 768))); + setVariable(0x0821e906, (int)(gWidth * (962.0 / 1315))); + setVariable(0x0821e90e, gHeight); // FSAA patchMemory(0x08777846, "9090"); patchMemory(0x087a56e9, "01"); // FSAA Enabled @@ -1946,15 +2066,15 @@ int initResolutionPatches() replaceCallAtAddress(0x0825d656, idBalloonPut); replaceCallAtAddress(0x0825d717, idBalloonPut); // START and VIEW CHANGE Text fix - float explanationScaleX = getConfig()->width - (1360.0 - 815.0); - float explanationScaleY = (getConfig()->height / 768.0) * 680.0; + float explanationScaleX = gWidth - (1360.0 - 815.0); + float explanationScaleY = (gHeight / 768.0) * 680.0; setVariable(0x08273915, *(unsigned int *)&explanationScaleY); setVariable(0x0827398d, *(unsigned int *)&explanationScaleX); // Scale Testmode text - if (isTestMode() && getConfig()->width >= 1920) + if (isTestMode() && gWidth >= 1920) { patchMemory(0x08ca3d00, "02"); - idTextShift = (getConfig()->width == 1920 ? 27 : ((1920 / getConfig()->width) * 27) + 2); + idTextShift = (gWidth == 1920 ? 27 : ((1920 / gWidth) * 27) + 2); idTestTextAddress = (void *)0x087929bc; replaceCallAtAddress(0x085254ea, idTestText); } @@ -1962,30 +2082,38 @@ int initResolutionPatches() break; case INITIALD_5_JAP_REVA: // ID5 - DVP-0070A { - if (getConfig()->width == 1360 && getConfig()->height == 768) + bool origRes = (gWidth == 1360 && gHeight == 768); + if (!getConfig()->boostRenderRes && origRes) + { break; - patchMemory(0x0853ccdd, "E9f000"); // Accept different Resolutions - setVariable(0x0853cdd3, getConfig()->width); // Set ResX - setVariable(0x0853cdd8, getConfig()->height); // Set ResY + } + if (gWidth >= 1360 && gHeight >= 768) + { + patchMemory(0x083557f4, "bb01000000eb6b"); // Prevents renrer.ini from loading + setVariable(0x083556d0, gWidth); // Framebuffer Main Width + setVariable(0x083556d7, gHeight); // Framebuffer Main Height + setVariable(0x08355771, 256); // Framebuffer Road Specular width + setVariable(0x08355778, 256); // Framebuffer Road Specular height + setVariable(0x08355797, gWidth); // Framebuffer Glare Width + setVariable(0x0835579e, gHeight); // Framebuffer Glare Height + setVariable(0x083557c4, gWidth >> 2); // Framebuffer Reduced width + patchMemory(0x083557e9, "00000001"); // Enable Cube Secular + if (origRes) + break; + } + patchMemory(0x0853ccdd, "E9f000"); // Accept different Resolutions + setVariable(0x0853cdd3, gWidth); // Set ResX + setVariable(0x0853cdd8, gHeight); // Set ResY - patchMemory(0x083557f4, "bb01000000eb6b"); // Prevents renrer.ini from loading - setVariable(0x083556d0, getConfig()->width); // Framebuffer Main Width - setVariable(0x083556d7, getConfig()->height); // Framebuffer Main Height - setVariable(0x08355771, 256); // Framebuffer Road Specular width - setVariable(0x08355778, 256); // Framebuffer Road Specular height - setVariable(0x08355797, getConfig()->width); // Framebuffer Glare Width - setVariable(0x0835579e, getConfig()->height); // Framebuffer Glare Height - setVariable(0x083557c4, getConfig()->width >> 2); // Framebuffer Reduced width - patchMemory(0x083557e9, "00000001"); // Enable Cube Secular // Fix Press start and Insert coins text idDisplayTextureCAVEAddress = (void *)0x084e1770 + 5; detourFunction(0x084e1770, idDisplayTexture); // setViewport for track selection screen - setVariable(0x08214b9e, (int)(getConfig()->height * (112.0 / 768))); - setVariable(0x08214ba6, (int)(getConfig()->width * (724.0 / 1315))); - setVariable(0x08214bae, (int)(getConfig()->height * (592.0 / 768))); - setVariable(0x08214bb6, (int)(getConfig()->width * (962.0 / 1315))); - setVariable(0x08214bbe, getConfig()->height); + setVariable(0x08214b9e, (int)(gHeight * (112.0 / 768))); + setVariable(0x08214ba6, (int)(gWidth * (724.0 / 1315))); + setVariable(0x08214bae, (int)(gHeight * (592.0 / 768))); + setVariable(0x08214bb6, (int)(gWidth * (962.0 / 1315))); + setVariable(0x08214bbe, gHeight); // FSAA patchMemory(0x08759eb6, "9090"); patchMemory(0x08787d59, "01"); // FSAA Enabled @@ -1997,15 +2125,15 @@ int initResolutionPatches() replaceCallAtAddress(0x08253b48, idBalloonPut); replaceCallAtAddress(0x08253c09, idBalloonPut); // START and VIEW CHANGE Text fix - float explanationScaleX = getConfig()->width - (1360.0 - 815.0); - float explanationScaleY = (getConfig()->height / 768.0) * 680.0; + float explanationScaleX = gWidth - (1360.0 - 815.0); + float explanationScaleY = (gHeight / 768.0) * 680.0; setVariable(0x08269c25, *(unsigned int *)&explanationScaleY); setVariable(0x08269c9d, *(unsigned int *)&explanationScaleX); // Scale Testmode text - if (isTestMode() && getConfig()->width >= 1920) + if (isTestMode() && gWidth >= 1920) { patchMemory(0x08c55b80, "02"); - idTextShift = (getConfig()->width == 1920 ? 27 : ((1920 / getConfig()->width) * 27) + 2); + idTextShift = (gWidth == 1920 ? 27 : ((1920 / gWidth) * 27) + 2); idTestTextAddress = (void *)0x0877502c; replaceCallAtAddress(0x0850783e, idTestText); } @@ -2013,30 +2141,38 @@ int initResolutionPatches() break; case INITIALD_5_JAP_REVF: // ID5 - DVP-0070F { - if (getConfig()->width == 1360 && getConfig()->height == 768) + bool origRes = (gWidth == 1360 && gHeight == 768); + if (!getConfig()->boostRenderRes && origRes) + { break; - patchMemory(0x08556bbd, "E9f000"); // Accept different Resolutions - setVariable(0x08556cb3, getConfig()->width); // Set ResX - setVariable(0x08556cb8, getConfig()->height); // Set ResY + } + if (gWidth >= 1360 && gHeight >= 768) + { + patchMemory(0x08364484, "bb01000000eb6b"); // Prevents renrer.ini from loading + setVariable(0x08364360, gWidth); // Framebuffer Main Width + setVariable(0x08364367, gHeight); // Framebuffer Main Height + setVariable(0x08364401, 256); // Framebuffer Road Specular width + setVariable(0x08364408, 256); // Framebuffer Road Specular height + setVariable(0x08364427, gWidth); // Framebuffer Glare Width + setVariable(0x0836442e, gHeight); // Framebuffer Glare Height + setVariable(0x08364454, gWidth >> 2); // Framebuffer Reduced width + patchMemory(0x08364479, "00000001"); // Enable Cube Secular + if (origRes) + break; + } + patchMemory(0x08556bbd, "E9f000"); // Accept different Resolutions + setVariable(0x08556cb3, gWidth); // Set ResX + setVariable(0x08556cb8, gHeight); // Set ResY - patchMemory(0x08364484, "bb01000000eb6b"); // Prevents renrer.ini from loading - setVariable(0x08364360, getConfig()->width); // Framebuffer Main Width - setVariable(0x08364367, getConfig()->height); // Framebuffer Main Height - setVariable(0x08364401, 256); // Framebuffer Road Specular width - setVariable(0x08364408, 256); // Framebuffer Road Specular height - setVariable(0x08364427, getConfig()->width); // Framebuffer Glare Width - setVariable(0x0836442e, getConfig()->height); // Framebuffer Glare Height - setVariable(0x08364454, getConfig()->width >> 2); // Framebuffer Reduced width - patchMemory(0x08364479, "00000001"); // Enable Cube Secular // Fix Press start and Insert coins text idDisplayTextureCAVEAddress = (void *)0x084fa3c0 + 5; detourFunction(0x084fa3c0, idDisplayTexture); // setViewport for track selection screen - setVariable(0x0821ec6e, (int)(getConfig()->height * (112.0 / 768))); - setVariable(0x0821ec76, (int)(getConfig()->width * (724.0 / 1315))); - setVariable(0x0821ec7e, (int)(getConfig()->height * (592.0 / 768))); - setVariable(0x0821ec86, (int)(getConfig()->width * (962.0 / 1315))); - setVariable(0x0821ec8e, getConfig()->height); + setVariable(0x0821ec6e, (int)(gHeight * (112.0 / 768))); + setVariable(0x0821ec76, (int)(gWidth * (724.0 / 1315))); + setVariable(0x0821ec7e, (int)(gHeight * (592.0 / 768))); + setVariable(0x0821ec86, (int)(gWidth * (962.0 / 1315))); + setVariable(0x0821ec8e, gHeight); // FSAA patchMemory(0x08773d26, "9090"); patchMemory(0x087a1bc9, "01"); // FSAA Enabled @@ -2048,15 +2184,15 @@ int initResolutionPatches() replaceCallAtAddress(0x0825d9f8, idBalloonPut); replaceCallAtAddress(0x0825dab9, idBalloonPut); // START and VIEW CHANGE Text fix - float explanationScaleX = getConfig()->width - (1360.0 - 815.0); - float explanationScaleY = (getConfig()->height / 768.0) * 680.0; + float explanationScaleX = gWidth - (1360.0 - 815.0); + float explanationScaleY = (gHeight / 768.0) * 680.0; setVariable(0x08273ce5, *(unsigned int *)&explanationScaleY); setVariable(0x08273d5d, *(unsigned int *)&explanationScaleX); // Scale Testmode text - if (isTestMode() && getConfig()->width >= 1920) + if (isTestMode() && gWidth >= 1920) { patchMemory(0x08c92040, "02"); - idTextShift = (getConfig()->width == 1920 ? 27 : ((1920 / getConfig()->width) * 27) + 2); + idTextShift = (gWidth == 1920 ? 27 : ((1920 / gWidth) * 27) + 2); idTestTextAddress = (void *)0x0878ee9c; replaceCallAtAddress(0x08521aaa, idTestText); } @@ -2064,24 +2200,67 @@ int initResolutionPatches() break; case LETS_GO_JUNGLE_REVA: { - setVariable(0x082e1323, getConfig()->width); // Set ResX - setVariable(0x082e1330, getConfig()->height); // Set ResY + setVariable(0x082e1323, gWidth); // Set ResX + setVariable(0x082e1330, gHeight); // Set ResY // FSAA patchMemory(0x082e12ff, "01"); + + // Render Res + setVariable(0x080ce59a, gWidth); // 800 + setVariable(0x080ce5a4, gHeight); // 600 } break; case LETS_GO_JUNGLE: { - setVariable(0x082E006b, getConfig()->width); // Set ResX - setVariable(0x082E0078, getConfig()->height); // Set ResY + setVariable(0x082E006b, gWidth); // Set ResX + setVariable(0x082E0078, gHeight); // Set ResY // FSAA patchMemory(0x082e0047, "01"); + + // Render Res + setVariable(0x080ce2f2, gWidth); // 800 + setVariable(0x080ce2fc, gHeight); // 600 } break; case LETS_GO_JUNGLE_SPECIAL: { - // setVariable(0x08303C4B, 0x00000780); // Set ResX - // setVariable(0x08303C58, 0x00000438); // Set ResY + if ((gWidth == 1024 && gHeight == 768) || (gWidth == 2048 && gHeight == 768)) + break; + setVariable(0x08303C4B, gWidth * 2); // Set ResX Width x 2 + setVariable(0x08303C58, gHeight); // Set ResY + + setVariable(0x080d6e8c, gWidth); // 1024 + setVariable(0x080d6e96, gHeight); // 768 + + setVariable(0x080d6ea0, gWidth); // 800 + setVariable(0x080d6eaa, gHeight); // 600 + + setVariable(0x080cf6ac, gWidth); // 800 + setVariable(0x080cf6b9, gHeight); // 600 + patchMemory(0x08303c27, "01"); // FSAA + + float newWidthLGJ = (float)gWidth; + float newHeightLGJ = (float)gHeight; + uint32_t *newWidthPtrLGJ = (uint32_t *)&newWidthLGJ; + uint32_t *newHeightPtrLGJ = (uint32_t *)&newHeightLGJ; + + float newWidth2LGJ = (float)gWidth * 2.0; + uint32_t *newWidth2PtrLGJ = (uint32_t *)&newWidth2LGJ; + unsigned int address = 0x080cb730; + + float newWidthHLGJ = (float)gWidth / 2.0; + uint32_t *newWidthHPtrLGJ = (uint32_t *)&newWidthHLGJ; + float newWidthSLGJ = 1360.0 / (float)gWidth; + uint32_t *newWidthSPtrLGJ = (uint32_t *)&newWidthSLGJ; + unsigned int addressC = 0x080cb3be; + + setVariable(0x082dcd10, (size_t)newHeightPtrLGJ); // LGJSceneManagerbegin + + setVariable(address, (size_t)newHeightPtrLGJ); // StageSelect + setVariable(address + 0xF, (size_t)newWidth2PtrLGJ); + + setVariable(addressC, (size_t)newWidthHPtrLGJ); // StageSelectonCursor + setVariable(addressC + 0x8, (size_t)newWidthSPtrLGJ); } break; case MJ4_REVG: @@ -2089,27 +2268,27 @@ int initResolutionPatches() // Not Supported yet. // patchMemory(0x080524a1, "01"); // Enable Anti Alias // patchMemory(0x08053668, "b80a000000"); // Skips resolution set by the Dip Switches. - // vf5FSwidth = (getConfig()->height * 4) / 3; + // vf5FSwidth = (gHeight * 4) / 3; // setVariable(0x08901598, vf5FSwidth); - // setVariable(0x0890159c, getConfig()->height); + // setVariable(0x0890159c, gHeight); // setVariable(0x089015a4, vf5FSwidth); - // setVariable(0x089015a8, getConfig()->height); + // setVariable(0x089015a8, gHeight); // setVariable(0x08901544, vf5FSwidth); - // setVariable(0x08901548, getConfig()->height); + // setVariable(0x08901548, gHeight); // setVariable(0x0890158c, vf5FSwidth); - // setVariable(0x08901590, getConfig()->height); + // setVariable(0x08901590, gHeight); } break; case OUTRUN_2_SP_SDX: { - if (getConfig()->width <= 800 && getConfig()->height <= 480) + if (gWidth <= 800 && gHeight <= 480) break; // If resolution is not the native of the game this patch kind of fix the Sun when the LensGlare effect is // shown. - if ((getConfig()->width > 800) && (getConfig()->height > 480)) + if ((gWidth > 800) && (gHeight > 480)) { patchMemory(0x080e8e72, "9090909090"); // removes a call to a light function patchMemory(0x080e8e83, "9090909090"); // removes a call to a light function @@ -2125,17 +2304,17 @@ int initResolutionPatches() break; case OUTRUN_2_SP_SDX_TEST: { - setVariable(0x0804a490, getConfig()->width); - setVariable(0x0804a4ad, getConfig()->height); + setVariable(0x0804a490, gWidth); + setVariable(0x0804a4ad, gHeight); } break; case OUTRUN_2_SP_SDX_REVA: { - if (getConfig()->width <= 800 && getConfig()->height <= 480) + if (gWidth <= 800 && gHeight <= 480) break; // If resolution is not the native of the game this patch kind of fix the Sun when the LensGlare effect is // shown. - if ((getConfig()->width > 800) && (getConfig()->height > 480)) + if ((gWidth > 800) && (gHeight > 480)) { patchMemory(0x080e8e06, "9090909090"); // removes a call to a light function patchMemory(0x080e8e17, "9090909090"); // removes a call to a light function @@ -2169,21 +2348,26 @@ int initResolutionPatches() case OUTRUN_2_SP_SDX_REVA_TEST: case OUTRUN_2_SP_SDX_REVA_TEST2: { - if (getConfig()->width <= 800 && getConfig()->height <= 480) + if (gWidth <= 800 && gHeight <= 480) break; - setVariable(0x0804a490, getConfig()->width); - setVariable(0x0804a4ad, getConfig()->height); + setVariable(0x0804a490, gWidth); + setVariable(0x0804a4ad, gHeight); } break; case PRIMEVAL_HUNT: { - if (getConfig()->width <= 640 && getConfig()->height <= 480) + if (gWidth <= 1280 && gHeight <= 480) break; + + if (isTestMode()) + { + EmulatorConfig *config = getConfig(); + config->phMode = 2; + } phX = 0; phY = 0; - phW = getConfig()->width; - phH = getConfig()->height; - int phX2, phY2, phW2, phH2; + phW = gWidth; + phH = gHeight; switch (getConfig()->phMode) { case 0: @@ -2194,8 +2378,8 @@ int initResolutionPatches() { if (getConfig()->keepAspectRatio) { - phX = (getConfig()->width - (getConfig()->height / 3) * 4) / 2; - phW = (getConfig()->height / 3) * 4; + phX = (gWidth - (gHeight / 3) * 4) / 2; + phW = (gHeight / 3) * 4; } phW2 = 0; phH2 = 0; @@ -2207,8 +2391,8 @@ int initResolutionPatches() { if (getConfig()->keepAspectRatio) { - phH = ((getConfig()->width / 2) / 4) * 3; - phY = (getConfig()->height - phH) / 2; + phH = ((gWidth / 2) / 4) * 3; + phY = (gHeight - phH) / 2; } phX = 0; phW = phW / 2; @@ -2222,26 +2406,26 @@ int initResolutionPatches() { // We always force 4:3 aspect ratio for this mode. phX = 0; - phW = (getConfig()->height / 3) * 4; - phH2 = ((getConfig()->width - phW) / 4) * 3; + phW = (gHeight / 3) * 4; + phH2 = ((gWidth - phW) / 4) * 3; phX2 = phW; phY2 = (phH - phH2) / 2; - phW2 = getConfig()->width - phW; + phW2 = gWidth - phW; } break; - case 4: + case 4: // 3ds Mode 1 (Small screen to the bottom) { // We always force 4:3 aspect ratio for this mode. - phW = (getConfig()->height / 3) * 4; - phX2 = (getConfig()->width / 2) - ((getConfig()->width - phW) / 2); - phW2 = getConfig()->width - phW; + phW = (gHeight / 3) * 4; + phX2 = (gWidth / 2) - ((gWidth - phW) / 2); + phW2 = gWidth - phW; phY2 = 0; // phH - ((phW2 / 4) * 3); phH2 = (phW2 / 4) * 3; phW = phW - phW2; phH = phH - phH2; - phX = (getConfig()->width - (phH / 3) * 4) / 2; + phX = (gWidth - (phH / 3) * 4) / 2; phY = phH2; } break; @@ -2250,7 +2434,6 @@ int initResolutionPatches() setVariable(0x0805b0fd, phY); // Y 1st screen setVariable(0x0805b0f5, phW); // Width 1st screen setVariable(0x0805b0ed, phH); // Height 1st screen - setVariable(0x0805afa2, phX2); // X 2nd screen setVariable(0x0805af9b, phY2); // Y 2st screen setVariable(0x0805af93, phW2); // Width 2nd screen @@ -2259,16 +2442,34 @@ int initResolutionPatches() detourFunction(0x0804c628, glClearColorPH); if (getConfig()->phMode == 4) // In mode 4, the screens are inverted. phY = 0; + + // Test Menu + if (isTestMode()) + { + setVariable(0x0807f95d, gHeight); // test HxW + setVariable(0x0807f965, gWidth); + + setVariable(0x08055d3e, gHeight); // text right screen HxW + setVariable(0x08055d46, gWidth / 2); + } } break; case RAMBO: { - if (getConfig()->width <= 1360 && getConfig()->height <= 768) + if (gWidth == 1360 && gHeight == 768) + { + if (getConfig()->boostRenderRes) + setVariable(0x08416df0, gWidth); // render res break; - patchMemory(0x080c70d0, "9090909090"); // setresolutiontype - setVariable(0x08416df0, getConfig()->width); // render res - setVariable(0x08416d60, getConfig()->width); // main res - setVariable(0x08416d64, getConfig()->height); + } + else if (gWidth == 640 && gHeight == 480) + { + break; + } + patchMemory(0x080c70d0, "9090909090"); // setresolutiontype + setVariable(0x08416df0, gWidth); // render res + setVariable(0x08416d60, gWidth); // main res + setVariable(0x08416d64, gHeight); patchMemory(0x08416d68, "5005"); // Allwinres patchMemory(0x08416d6c, "0003"); @@ -2281,8 +2482,8 @@ int initResolutionPatches() { patchMemory(0x08051c2b, "01"); // Enable Anti Alias patchMemory(0x08052d58, "b80a000000"); // Skips resolution set by the Dip Switches. - setVariable(0x083c7db8, getConfig()->width); - setVariable(0x083c7dbc, getConfig()->height); + setVariable(0x083c7db8, gWidth); + setVariable(0x083c7dbc, gHeight); patchMemory(0x083c7dc0, "00"); } break; @@ -2294,8 +2495,8 @@ int initResolutionPatches() patchMemory(0x08050c12, "07"); patchMemory(0x08050c25, "07"); patchMemory(0x08050c37, "07"); - setVariable(0x08064611, getConfig()->width); - setVariable(0x080645c6, getConfig()->height); + setVariable(0x08064611, gWidth); + setVariable(0x080645c6, gHeight); } break; case SEGABOOT_2_4: @@ -2307,103 +2508,124 @@ int initResolutionPatches() patchMemory(0x080597c7, "07"); patchMemory(0x08059780, "07"); patchMemory(0x08059768, "07"); - setVariable(0x0809129d, getConfig()->width); - setVariable(0x08091252, getConfig()->height); + setVariable(0x0809129d, gWidth); + setVariable(0x08091252, gHeight); } break; case SEGA_RACE_TV: { - if (getConfig()->width == 640 && getConfig()->height == 480) + if (gWidth == 640 && gHeight == 480) break; if (getConfig()->keepAspectRatio) { - srtvX = (getConfig()->width - (getConfig()->height / 3) * 4) / 2; - srtvW = (getConfig()->height / 3) * 4; + srtvX = (gWidth - (gHeight / 3) * 4) / 2; + srtvW = (gHeight / 3) * 4; } else { - srtvW = getConfig()->width; + srtvW = gWidth; } - srtvH = getConfig()->height; + srtvH = gHeight; } break; case THE_HOUSE_OF_THE_DEAD_4_REVA: { - if (getConfig()->width <= 1280 && getConfig()->height <= 768) + if (gWidth == 1280 && gHeight == 768) + { + if (getConfig()->boostRenderRes) + setVariable(0x084c9dbc, 1280); + return 0; + } + else if (gWidth == 640 && gHeight == 480) + { break; + } patchMemory(0x0804d142, "9090909090"); // setresolutiontype // patchMemory(0x084c9dbc, "0005"); // patchMemory(0x08448458, "0005"); // patchMemory(0x0844845c, "0003"); - setVariable(0x084c9dbc, getConfig()->width); - setVariable(0x08448458, getConfig()->width); - setVariable(0x0844845c, getConfig()->height); + setVariable(0x084c9dbc, gWidth); + setVariable(0x08448458, gWidth); + setVariable(0x0844845c, gHeight); patchMemory(0x08448460, "0005"); patchMemory(0x08448464, "0003"); patchMemory(0x0817ff6d, "e80ed5ecff"); // call crtgetresolution patchMemory(0x08448468, "0005"); // set crtgetresolution to 640x480 patchMemory(0x0844846c, "0003"); - setVariable(0x08448338, getConfig()->width); - setVariable(0x0844833c, getConfig()->height); + setVariable(0x08448338, gWidth); + setVariable(0x0844833c, gHeight); detourFunction(0x0804c024, glVertex3fHOD4); - detourFunction(0x0804ca54, glBindTextureGE); + detourFunction(0x0804ca54, myGlBindTexture); } break; case THE_HOUSE_OF_THE_DEAD_4_REVB: { - if (getConfig()->width <= 1280 && getConfig()->height <= 768) + if (gWidth == 1280 && gHeight == 768) + { + if (getConfig()->boostRenderRes) + setVariable(0x084c3a9c, 1280); + return 0; + } + else if (gWidth == 640 && gHeight == 480) + { break; + } patchMemory(0x0804d174, "9090909090"); // setresolutiontype - setVariable(0x084c3a9c, getConfig()->width); - setVariable(0x08443118, getConfig()->width); - setVariable(0x0844311c, getConfig()->height); + setVariable(0x084c3a9c, gWidth); + setVariable(0x08443118, gWidth); + setVariable(0x0844311c, gHeight); patchMemory(0x08443120, "0005"); patchMemory(0x08443124, "0003"); patchMemory(0x0818080d, "e89eccecff"); // call crtgetresolution patchMemory(0x08443128, "0005"); // set crtgetresolution to 640x480 patchMemory(0x0844312c, "0003"); - setVariable(0x08442ff8, getConfig()->width); - setVariable(0x08442ffc, getConfig()->height); + setVariable(0x08442ff8, gWidth); + setVariable(0x08442ffc, gHeight); detourFunction(0x0804c014, glVertex3fHOD4); - detourFunction(0x0804ca84, glBindTextureGE); + detourFunction(0x0804ca84, myGlBindTexture); } break; case THE_HOUSE_OF_THE_DEAD_4_REVC: { - if (getConfig()->width <= 1280 && getConfig()->height <= 768) + if (gWidth == 1280 && gHeight == 768) { - setVariable(0x084c3a9c, 1280); + if (getConfig()->boostRenderRes) + setVariable(0x084c3a9c, 1280); return 0; } + else if (gWidth == 640 && gHeight == 480) + { + break; + } patchMemory(0x0804d174, "9090909090"); // setresolutiontype - setVariable(0x084c3a9c, getConfig()->width); - setVariable(0x08443118, getConfig()->width); - setVariable(0x0844311c, getConfig()->height); + setVariable(0x084c3a9c, gWidth); + setVariable(0x08443118, gWidth); + setVariable(0x0844311c, gHeight); patchMemory(0x08443120, "0005"); // gallwinres (2D) patchMemory(0x08443124, "0003"); patchMemory(0x0818080d, "e89eccecff"); // sideselect fix patchMemory(0x08443128, "0005"); patchMemory(0x0844312c, "0003"); - setVariable(0x08442ff8, getConfig()->width); - setVariable(0x08442ffc, getConfig()->height); + setVariable(0x08442ff8, gWidth); + setVariable(0x08442ffc, gHeight); detourFunction(0x0804c014, glVertex3fHOD4); - detourFunction(0x0804ca84, glBindTextureGE); + detourFunction(0x0804ca84, myGlBindTexture); } break; case THE_HOUSE_OF_THE_DEAD_4_SPECIAL: { - if (getConfig()->width <= 1024 && getConfig()->height <= 768) + if (gWidth <= 1024 && gHeight <= 768) break; patchMemory(0x0804d2f4, "9090909090"); // setresolutiontype - setVariable(0x084563c4, getConfig()->width); - setVariable(0x08424448, getConfig()->width); - setVariable(0x0842444c, getConfig()->height); + setVariable(0x084563c4, gWidth); + setVariable(0x08424448, gWidth); + setVariable(0x0842444c, gHeight); patchMemory(0x0815bfa9, "e8de7f0100"); // sideselect fix patchMemory(0x08424450, "0004"); patchMemory(0x08424454, "0003"); @@ -2411,12 +2633,12 @@ int initResolutionPatches() break; case THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB: { - if (getConfig()->width <= 1024 && getConfig()->height <= 768) + if (gWidth <= 1024 && gHeight <= 768) break; patchMemory(0x0804d7e2, "9090909090"); // setresolutiontype - setVariable(0x084c35c4, getConfig()->width); - setVariable(0x08491648, getConfig()->width); - setVariable(0x0849164c, getConfig()->height); + setVariable(0x084c35c4, gWidth); + setVariable(0x08491648, gWidth); + setVariable(0x0849164c, gHeight); patchMemory(0x081b268f, "e8264d0200"); // sideselect fix patchMemory(0x08491650, "0004"); patchMemory(0x08491654, "0003"); @@ -2424,159 +2646,185 @@ int initResolutionPatches() break; case THE_HOUSE_OF_THE_DEAD_EX: { + if (gWidth == 1360 && gHeight == 768) + { + if (getConfig()->boostRenderRes) + setVariable(0x087aa080, 1280); // render res + break; + } + else if (gWidth == 640 && gHeight == 480) + { + break; + } } break; case TOO_SPICY: { - patchMemory(0x08202b22, "0005"); // render res 1280 + if (gWidth == 1280 && gHeight == 768) + { + if (getConfig()->boostRenderRes) + setVariable(0x08202b22, 1280); // render res + break; + } + else if (gWidth == 640 && gHeight == 480) + { + break; + } + } + break; + case TOO_SPICY_TEST: + { + if (gWidth <= 1280 && gHeight <= 768) + break; + setVariable(0x080565b3, gWidth); + setVariable(0x080565bb, gHeight); } break; case VIRTUA_FIGHTER_5: { - if ((getConfig()->width == 640 && getConfig()->height == 480) || (getConfig()->width == 1280 && getConfig()->height == 768)) + if ((gWidth == 640 && gHeight == 480) || (gWidth == 1280 && gHeight == 768)) return 0; patchMemory(0x08054057, "b80a000000"); // Skips resolution set by the Dip Switches. - setVariable(0x0847cf58, getConfig()->width); - setVariable(0x0847cf5c, getConfig()->height); + setVariable(0x0847cf58, gWidth); + setVariable(0x0847cf5c, gHeight); replaceCallAtAddress(0x080d40c4, vf5WidthFix); } break; case VIRTUA_FIGHTER_5_EXPORT: { - if ((getConfig()->width == 640 && getConfig()->height == 480) || (getConfig()->width == 1280 && getConfig()->height == 768)) + if ((gWidth == 640 && gHeight == 480) || (gWidth == 1280 && gHeight == 768)) break; patchMemory(0x08052b97, "01"); // Enable Anti Alias patchMemory(0x08053c67, "b80a000000"); // Skips resolution set by the Dip Switches. - setVariable(0x085259f8, getConfig()->width); - setVariable(0x085259fc, getConfig()->height); + setVariable(0x085259f8, gWidth); + setVariable(0x085259fc, gHeight); } break; case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA: { - if ((getConfig()->width == 640 && getConfig()->height == 480) || (getConfig()->width == 1280 && getConfig()->height == 768)) + if ((gWidth == 640 && gHeight == 480) || (gWidth == 1280 && gHeight == 768)) break; patchMemory(0x08054b5e, "01"); // Enable Anti Alias patchMemory(0x08055980, "b80a000000"); // Skips resolution set by the Dip Switches. - vf5FSwidth = (getConfig()->height * 5) / 3; + vf5FSwidth = (gHeight * 5) / 3; setVariable(0x088b2bd8, vf5FSwidth); - setVariable(0x088b2bdc, getConfig()->height); - setVariable(0x088b2bec, getConfig()->width); - setVariable(0x088b2bf0, getConfig()->height); + setVariable(0x088b2bdc, gHeight); + setVariable(0x088b2bec, gWidth); + setVariable(0x088b2bf0, gHeight); } break; case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB: { - if ((getConfig()->width == 640 && getConfig()->height == 480) || (getConfig()->width == 1280 && getConfig()->height == 768)) + if ((gWidth == 640 && gHeight == 480) || (gWidth == 1280 && gHeight == 768)) break; patchMemory(0x080548c4, "01"); // Enable Anti Alias patchMemory(0x080556e6, "b80a000000"); // Skips resolution set by the Dip Switches. - vf5FSwidth = (getConfig()->height * 5) / 3; + vf5FSwidth = (gHeight * 5) / 3; setVariable(0x088d2b78, vf5FSwidth); - setVariable(0x088d2b7c, getConfig()->height); - setVariable(0x088d2b8c, getConfig()->width); - setVariable(0x088d2b90, getConfig()->height); + setVariable(0x088d2b7c, gHeight); + setVariable(0x088d2b8c, gWidth); + setVariable(0x088d2b90, gHeight); } break; case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000: { - if ((getConfig()->width == 640 && getConfig()->height == 480) || (getConfig()->width == 1280 && getConfig()->height == 768)) + if ((gWidth == 640 && gHeight == 480) || (gWidth == 1280 && gHeight == 768)) break; patchMemory(0x08054bfe, "01"); // Enable Anti Alias patchMemory(0x08055a20, "b80a000000"); // Skips resolution set by the Dip Switches. - vf5FSwidth = (getConfig()->height * 5) / 3; + vf5FSwidth = (gHeight * 5) / 3; setVariable(0x088d53d8, vf5FSwidth); - setVariable(0x088d53dc, getConfig()->height); - setVariable(0x088d53ec, getConfig()->width); - setVariable(0x088d53f0, getConfig()->height); + setVariable(0x088d53dc, gHeight); + setVariable(0x088d53ec, gWidth); + setVariable(0x088d53f0, gHeight); } break; case VIRTUA_FIGHTER_5_R: { - if ((getConfig()->width == 640 && getConfig()->height == 480) || (getConfig()->width == 1280 && getConfig()->height == 768)) + if ((gWidth == 640 && gHeight == 480) || (gWidth == 1280 && gHeight == 768)) break; patchMemory(0x0805421a, "01"); // Enable Anti Alias patchMemory(0x080554b0, "b80a000000"); // Skips resolution set by the Dip Switches. - vf5FSwidth = (getConfig()->height * 5) / 3; + vf5FSwidth = (gHeight * 5) / 3; setVariable(0x08767d58, vf5FSwidth); - setVariable(0x08767d5c, getConfig()->height); - setVariable(0x08767d6c, getConfig()->width); - setVariable(0x08767d70, getConfig()->height); + setVariable(0x08767d5c, gHeight); + setVariable(0x08767d6c, gWidth); + setVariable(0x08767d70, gHeight); } break; case VIRTUA_FIGHTER_5_R_REVD: { - if ((getConfig()->width == 640 && getConfig()->height == 480) || (getConfig()->width == 1280 && getConfig()->height == 768)) + if ((gWidth == 640 && gHeight == 480) || (gWidth == 1280 && gHeight == 768)) break; patchMemory(0x080543aa, "01"); // Enable Anti Alias patchMemory(0x080555f6, "b80a000000"); // Skips resolution set by the Dip Switches. - vf5FSwidth = (getConfig()->height * 5) / 3; + vf5FSwidth = (gHeight * 5) / 3; setVariable(0x08822b18, vf5FSwidth); - setVariable(0x08822b1c, getConfig()->height); - setVariable(0x08822b2c, getConfig()->width); - setVariable(0x08822b30, getConfig()->height); + setVariable(0x08822b1c, gHeight); + setVariable(0x08822b2c, gWidth); + setVariable(0x08822b30, gHeight); } break; case VIRTUA_FIGHTER_5_R_REVG: { - if ((getConfig()->width == 640 && getConfig()->height == 480) || (getConfig()->width == 1280 && getConfig()->height == 768)) + if ((gWidth == 640 && gHeight == 480) || (gWidth == 1280 && gHeight == 768)) break; patchMemory(0x0805436a, "01"); // Enable Anti Alias patchMemory(0x0805577c, "b80a000000"); // Skips resolution set by the Dip Switches. - vf5FSwidth = (getConfig()->height * 5) / 3; + vf5FSwidth = (gHeight * 5) / 3; setVariable(0x0887d4d8, vf5FSwidth); - setVariable(0x0887d4dc, getConfig()->height); - setVariable(0x0887d4ec, getConfig()->width); - setVariable(0x0887d4f0, getConfig()->height); + setVariable(0x0887d4dc, gHeight); + setVariable(0x0887d4ec, gWidth); + setVariable(0x0887d4f0, gHeight); } break; case VIRTUA_FIGHTER_5_REVA: { - if ((getConfig()->width == 640 && getConfig()->height == 480) || (getConfig()->width == 1280 && getConfig()->height == 768)) + if ((gWidth == 640 && gHeight == 480) || (gWidth == 1280 && gHeight == 768)) break; patchMemory(0x8053167, "01"); // Enable Anti Alias patchMemory(0x080541af, "b80a000000"); // Skips resolution set by the Dip Switches. - setVariable(0x08487df8, getConfig()->width); - setVariable(0x08487dfc, getConfig()->height); + setVariable(0x08487df8, gWidth); + setVariable(0x08487dfc, gHeight); } break; case VIRTUA_FIGHTER_5_REVB: { - if ((getConfig()->width == 640 && getConfig()->height == 480) || (getConfig()->width == 1280 && getConfig()->height == 768)) + if ((gWidth == 640 && gHeight == 480) || (gWidth == 1280 && gHeight == 768)) break; patchMemory(0x08053673, "01"); // Enable Anti Alias patchMemory(0x080546cf, "b80a000000"); // Skips resolution set by the Dip Switches. - setVariable(0x08536bb8, getConfig()->width); - setVariable(0x08536bbc, getConfig()->height); + setVariable(0x08536bb8, gWidth); + setVariable(0x08536bbc, gHeight); } break; case VIRTUA_FIGHTER_5_REVE: // Also the public REV C version { - if ((getConfig()->width == 640 && getConfig()->height == 480) || (getConfig()->width == 1280 && getConfig()->height == 768)) + if ((gWidth == 640 && gHeight == 480) || (gWidth == 1280 && gHeight == 768)) break; patchMemory(0x080546c7, "01"); // Enable Anti Alias patchMemory(0x080557a3, "b80a000000"); // Skips resolution set by the Dip Switches. - setVariable(0x085efb18, getConfig()->width); - setVariable(0x085efb1c, getConfig()->height); + setVariable(0x085efb18, gWidth); + setVariable(0x085efb1c, gHeight); } break; - case VIRTUA_TENNIS_3: { - if (getConfig()->width <= 1360 && getConfig()->height <= 768) + if (gWidth <= 1360 && gHeight <= 768) break; patchMemory(0x081759b3, "9090"); - setVariable(0x081759bb, getConfig()->width); - setVariable(0x081759c5, getConfig()->height); + setVariable(0x081759bb, gWidth); + setVariable(0x081759c5, gHeight); // setPerspective - newVT3 = getConfig()->width / 1360.0; + newVT3 = gWidth / 1360.0; intnewVT3PTr = (uint32_t *)&newVT3; setVariable(0x082682b6, (size_t)intnewVT3PTr); // vecToScr_check - newVT3HW = (getConfig()->width / 1360.0) * 320.0; - newVT3HH = (getConfig()->height / 768.0) * 240.0; + newVT3HW = (gWidth / 1360.0) * 320.0; + newVT3HH = (gHeight / 768.0) * 240.0; intnewVT3HWPTr = (uint32_t *)&newVT3HW; intnewVT3HHPTr = (uint32_t *)&newVT3HH; uint32_t addressvt31 = 0x0817a55e; @@ -2586,21 +2834,21 @@ int initResolutionPatches() break; case VIRTUA_TENNIS_3_REVA: { - if (getConfig()->width <= 1360 && getConfig()->height <= 768) + if (gWidth <= 1360 && gHeight <= 768) break; patchMemory(0x081759e3, "9090"); - setVariable(0x081759eb, getConfig()->width); - setVariable(0x081759f5, getConfig()->height); + setVariable(0x081759eb, gWidth); + setVariable(0x081759f5, gHeight); // setPerspective - newVT3 = getConfig()->width / 1360.0; + newVT3 = gWidth / 1360.0; intnewVT3PTr = (uint32_t *)&newVT3; setVariable(0x082682e6, (size_t)intnewVT3PTr); // vecToScr_check - newVT3HW = (getConfig()->width / 1360.0) * 320.0; - newVT3HH = (getConfig()->height / 768.0) * 240.0; + newVT3HW = (gWidth / 1360.0) * 320.0; + newVT3HH = (gHeight / 768.0) * 240.0; intnewVT3HWPTr = (uint32_t *)&newVT3HW; intnewVT3HHPTr = (uint32_t *)&newVT3HH; uint32_t addressvt31 = 0x0817a58e; @@ -2610,21 +2858,21 @@ int initResolutionPatches() break; case VIRTUA_TENNIS_3_REVB: { - if (getConfig()->width <= 1360 && getConfig()->height <= 768) + if (gWidth <= 1360 && gHeight <= 768) break; patchMemory(0x08175ad7, "9090"); - setVariable(0x08175adf, getConfig()->width); - setVariable(0x08175ae9, getConfig()->height); + setVariable(0x08175adf, gWidth); + setVariable(0x08175ae9, gHeight); // setPerspective - newVT3 = getConfig()->width / 1360.0; + newVT3 = gWidth / 1360.0; intnewVT3PTr = (uint32_t *)&newVT3; setVariable(0x082684d2, (size_t)intnewVT3PTr); // vecToScr_check - newVT3HW = (getConfig()->width / 1360.0) * 320.0; - newVT3HH = (getConfig()->height / 768.0) * 240.0; + newVT3HW = (gWidth / 1360.0) * 320.0; + newVT3HH = (gHeight / 768.0) * 240.0; intnewVT3HWPTr = (uint32_t *)&newVT3HW; intnewVT3HHPTr = (uint32_t *)&newVT3HH; uint32_t addressvt31 = 0x0817a77a; @@ -2634,21 +2882,21 @@ int initResolutionPatches() break; case VIRTUA_TENNIS_3_REVC: { - if (getConfig()->width <= 1360 && getConfig()->height <= 768) + if (gWidth <= 1360 && gHeight <= 768) break; patchMemory(0x08175b03, "9090"); - setVariable(0x08175b0b, getConfig()->width); - setVariable(0x08175b15, getConfig()->height); + setVariable(0x08175b0b, gWidth); + setVariable(0x08175b15, gHeight); // setPerspective - newVT3 = getConfig()->width / 1360.0; + newVT3 = gWidth / 1360.0; intnewVT3PTr = (uint32_t *)&newVT3; setVariable(0x082684fe, (size_t)intnewVT3PTr); // vecToScr_check - newVT3HW = (getConfig()->width / 1360.0) * 320.0; - newVT3HH = (getConfig()->height / 768.0) * 240.0; + newVT3HW = (gWidth / 1360.0) * 320.0; + newVT3HH = (gHeight / 768.0) * 240.0; intnewVT3HWPTr = (uint32_t *)&newVT3HW; intnewVT3HHPTr = (uint32_t *)&newVT3HH; uint32_t addressvt31 = 0x0817a7a6; @@ -2658,8 +2906,8 @@ int initResolutionPatches() break; case VIRTUA_TENNIS_3_REVC_TEST: { - setVariable(0x0806fb3b, getConfig()->width); - setVariable(0x0806fb04, getConfig()->height); + setVariable(0x0806fb3b, gWidth); + setVariable(0x0806fb04, gHeight); } break; default: diff --git a/src/lindbergh/sdlcalls.c b/src/lindbergh/sdlcalls.c index 1e26432..946e1c0 100644 --- a/src/lindbergh/sdlcalls.c +++ b/src/lindbergh/sdlcalls.c @@ -14,13 +14,9 @@ #include "input.h" #include "sdlcalls.h" #include "fps_limiter.h" -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -#define STBI_ONLY_PNG -#define STBI_SUPPORT_ZLIB -#define STBI_NO_SIMD +#include "customcursor.h" +extern uint32_t gId; bool SDLWindowCreated = false; extern bool GLUTGame; SDL_Window *SDLwindow; @@ -30,6 +26,11 @@ Window x11Window; char SDLgameTitle[256] = {0}; extern fps_limit fpsLimit; +extern void *customCursor; +extern void *phTouchCursor; + +int glutInitialized = 0; + void GLAPIENTRY openglDebugCallback2(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) { @@ -50,125 +51,32 @@ void GLAPIENTRY openglDebugCallback2(GLenum source, GLenum type, GLuint id, GLen } } -SDL_Surface *createSurfaceFromStb(unsigned char *data, int width, int height, int channels) -{ - Uint32 rmask, gmask, bmask, amask; - - if (channels == 4) - { // RGBA - rmask = 0x000000FF; - gmask = 0x0000FF00; - bmask = 0x00FF0000; - amask = 0xFF000000; - } - else if (channels == 3) - { // RGB - rmask = 0x000000FF; - gmask = 0x0000FF00; - bmask = 0x00FF0000; - amask = 0; - } - else - { - fprintf(stderr, "Unsupported image format with %d channels.\n", channels); - return NULL; - } - - SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(data, width, height, channels * 8, width * channels, rmask, gmask, bmask, amask); - - if (!surface) - { - fprintf(stderr, "SDL_CreateRGBSurfaceFrom Error: %s\n", SDL_GetError()); - } - return surface; -} - -int loadNewCursor(char *cursorFileName) -{ - int width, height, channels; - unsigned char *imageData = stbi_load(cursorFileName, &width, &height, &channels, 0); - if (!imageData) - { - fprintf(stderr, "Failed to load image: %s\n", cursorFileName); - SDL_Quit(); - return 0; - } - - SDL_Surface *originalSurface = createSurfaceFromStb(imageData, width, height, channels); - if (!originalSurface) - { - stbi_image_free(imageData); - SDL_Quit(); - return 0; - } - - int newWidth = getConfig()->customCursorWidth; - int newHeight = getConfig()->customCursorHeight; - SDL_Surface *resizedSurface = - SDL_CreateRGBSurface(0, newWidth, newHeight, originalSurface->format->BitsPerPixel, originalSurface->format->Rmask, - originalSurface->format->Gmask, originalSurface->format->Bmask, originalSurface->format->Amask); - if (!resizedSurface) - { - fprintf(stderr, "SDL_CreateRGBSurface Error: %s\n", SDL_GetError()); - SDL_FreeSurface(originalSurface); - stbi_image_free(imageData); - SDL_Quit(); - return 0; - } - - SDL_Rect srcRect = {0, 0, originalSurface->w, originalSurface->h}; - SDL_Rect destRect = {0, 0, newWidth, newHeight}; - if (SDL_BlitScaled(originalSurface, &srcRect, resizedSurface, &destRect) != 0) - { - fprintf(stderr, "SDL_BlitScaled Error: %s\n", SDL_GetError()); - SDL_FreeSurface(resizedSurface); - SDL_FreeSurface(originalSurface); - stbi_image_free(imageData); - SDL_Quit(); - return 0; - } - - SDL_Cursor *customCursor = SDL_CreateColorCursor(resizedSurface, newWidth / 2, newHeight / 2); - if (!customCursor) - { - fprintf(stderr, "SDL_CreateColorCursor Error: %s\n", SDL_GetError()); - SDL_FreeSurface(resizedSurface); - SDL_FreeSurface(originalSurface); - stbi_image_free(imageData); - SDL_Quit(); - return 0; - } - - SDL_SetCursor(customCursor); - - SDL_FreeSurface(resizedSurface); - SDL_FreeSurface(originalSurface); - stbi_image_free(imageData); - - return 1; -} - void initSDL(int *argcp, char **argv) { - int gId = getConfig()->crc32; - void FGAPIENTRY (*_glutInit)(int *argcp, char **argv) = dlsym(RTLD_NEXT, "glutInit"); - if (getConfig()->noSDL && GLUTGame) + switch (gId) { - _glutInit(argcp, argv); - return; + case OUTRUN_2_SP_SDX_TEST: + case OUTRUN_2_SP_SDX_REVA_TEST: + case OUTRUN_2_SP_SDX_REVA_TEST2: + if (!glutInitialized) + { + glutInitialized = 1; + _glutInit(argcp, argv); + return; + } } - if ((gId == OUTRUN_2_SP_SDX_TEST || gId == OUTRUN_2_SP_SDX_REVA_TEST || gId == OUTRUN_2_SP_SDX_REVA_TEST2) && GLUTGame) - { - _glutInit(argcp, argv); - } - - if ((gId == AFTER_BURNER_CLIMAX) || (gId == AFTER_BURNER_CLIMAX_REVA) || (gId == AFTER_BURNER_CLIMAX_REVB) || - (gId == AFTER_BURNER_CLIMAX_SDX) || (gId == AFTER_BURNER_CLIMAX_SDX_REVA) || (gId == AFTER_BURNER_CLIMAX_SE) || - (gId == AFTER_BURNER_CLIMAX_SE_REVA)) + switch (gId) { + case AFTER_BURNER_CLIMAX: + case AFTER_BURNER_CLIMAX_REVA: + case AFTER_BURNER_CLIMAX_REVB: + case AFTER_BURNER_CLIMAX_SDX: + case AFTER_BURNER_CLIMAX_SDX_REVA: + case AFTER_BURNER_CLIMAX_SE: + case AFTER_BURNER_CLIMAX_SE_REVA: setenv("SDL_VIDEODRIVER", "x11", 1); } @@ -183,14 +91,31 @@ void initSDL(int *argcp, char **argv) SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); // Double buffering SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 1); // 24-bit depth buffer SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); // Set the alpha size to 8 bits - if (gId == AFTER_BURNER_CLIMAX || gId == AFTER_BURNER_CLIMAX_REVA || gId == AFTER_BURNER_CLIMAX_REVB || - gId == AFTER_BURNER_CLIMAX_SDX || gId == AFTER_BURNER_CLIMAX_SDX_REVA || gId == AFTER_BURNER_CLIMAX_SE || - gId == AFTER_BURNER_CLIMAX_SE_REVA || gId == R_TUNED || gId == VIRTUA_FIGHTER_5 || gId == VIRTUA_FIGHTER_5_REVA || - gId == VIRTUA_FIGHTER_5_REVB || gId == VIRTUA_FIGHTER_5_REVE || gId == VIRTUA_FIGHTER_5_EXPORT || gId == VIRTUA_FIGHTER_5_R || - gId == VIRTUA_FIGHTER_5_R_REVD || gId == VIRTUA_FIGHTER_5_R_REVG || gId == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA || - gId == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB || gId == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000 || gId == GHOST_SQUAD_EVOLUTION || - gId == SEGA_RACE_TV || gId == MJ4_REVG || gId == MJ4_EVO) + switch (gId) { + case AFTER_BURNER_CLIMAX: + case AFTER_BURNER_CLIMAX_REVA: + case AFTER_BURNER_CLIMAX_REVB: + case AFTER_BURNER_CLIMAX_SDX: + case AFTER_BURNER_CLIMAX_SDX_REVA: + case AFTER_BURNER_CLIMAX_SE: + case AFTER_BURNER_CLIMAX_SE_REVA: + case R_TUNED: + case VIRTUA_FIGHTER_5: + case VIRTUA_FIGHTER_5_REVA: + case VIRTUA_FIGHTER_5_REVB: + case VIRTUA_FIGHTER_5_REVE: + case VIRTUA_FIGHTER_5_EXPORT: + case VIRTUA_FIGHTER_5_R: + case VIRTUA_FIGHTER_5_R_REVD: + case VIRTUA_FIGHTER_5_R_REVG: + case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA: + case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB: + case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000: + case GHOST_SQUAD_EVOLUTION: + case SEGA_RACE_TV: + case MJ4_REVG: + case MJ4_EVO: SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1); } @@ -236,18 +161,12 @@ void initSDL(int *argcp, char **argv) if (getConfig()->fullscreen) { SDL_SetWindowFullscreen(SDLwindow, SDL_WINDOW_FULLSCREEN); - } - - if (strcmp(getConfig()->customCursor, "") != 0) - { - if (!loadNewCursor(getConfig()->customCursor)) - { - fprintf(stderr, "Custom cursor could not be loaded!\n"); - exit(1); - } } - if (getConfig()->hideCursor) + loadCursors(); + setCursor(customCursor); + + if (getConfig()->hideCursor || gId == PRIMEVAL_HUNT) SDL_ShowCursor(SDL_DISABLE); } diff --git a/src/lindbergh/securityboard.c b/src/lindbergh/securityboard.c index f91ab48..fa17ef5 100644 --- a/src/lindbergh/securityboard.c +++ b/src/lindbergh/securityboard.c @@ -1,8 +1,8 @@ #include +#include "config.h" #include "securityboard.h" #include "log.h" -#include "config.h" #define SECURITY_BOARD_FRONT_PANEL 0x38 #define SECURITY_BOARD_FRONT_PANEL_NON_ROOT 0x1038 diff --git a/src/lindbergh/shader_patches.c b/src/lindbergh/shader_patches.c index 61e1cb3..5e55932 100644 --- a/src/lindbergh/shader_patches.c +++ b/src/lindbergh/shader_patches.c @@ -23,11 +23,30 @@ #include "../libxdiff/xdiff/xdiff.h" #include "config.h" #include "patch.h" -#include "shader_work/shaders.h" + +#include "shader_work/2spicy.h" +#include "shader_work/abc.h" +#include "shader_work/gsevo.h" +#include "shader_work/harley.h" +#include "shader_work/hod4.h" +#include "shader_work/hod4sp.h" +#include "shader_work/hodex.h" +#include "shader_work/hummer.h" +#include "shader_work/id.h" +#include "shader_work/lgj.h" +#include "shader_work/mj4.h" +#include "shader_work/or2.h" +#include "shader_work/primeval.h" +#include "shader_work/rambo.h" +#include "shader_work/rtuned.h" +#include "shader_work/srtv.h" +#include "shader_work/vf5.h" +#include "shader_work/vt3.h" #define MAX_FILENAME_LENGTH 256 #define XDLT_STD_BLKSIZE (1024 * 8) +extern uint32_t gId; char tmpShader[150000]; bool cachedShaderFilesLoaded = false; int idxError = 0; @@ -262,8 +281,7 @@ void glEnable(GLenum cap) { void *(*_glEnable)(GLenum cap) = dlsym(RTLD_NEXT, "glEnable"); - if ((cap == GL_FRAGMENT_PROGRAM_NV) && - ((getConfig()->crc32 == OUTRUN_2_SP_SDX) || (getConfig()->crc32 == OUTRUN_2_SP_SDX_REVA)) && + if ((cap == GL_FRAGMENT_PROGRAM_NV) && ((gId == OUTRUN_2_SP_SDX) || (gId == OUTRUN_2_SP_SDX_REVA)) && (getConfig()->GPUVendor != NVIDIA_GPU)) { cap = GL_FRAGMENT_PROGRAM_ARB; @@ -278,8 +296,7 @@ void glDisable(GLenum cap) { void *(*_glDisable)(GLenum cap) = dlsym(RTLD_NEXT, "glDisable"); - if ((cap == GL_FRAGMENT_PROGRAM_NV) && - ((getConfig()->crc32 == OUTRUN_2_SP_SDX) || (getConfig()->crc32 == OUTRUN_2_SP_SDX_REVA)) && + if ((cap == GL_FRAGMENT_PROGRAM_NV) && ((gId == OUTRUN_2_SP_SDX) || (gId == OUTRUN_2_SP_SDX_REVA)) && (getConfig()->GPUVendor != NVIDIA_GPU)) { cap = GL_FRAGMENT_PROGRAM_ARB; @@ -433,17 +450,16 @@ void srtvElfShaderPatcher() */ bool shaderFileInList(const char *pathname, int *idx) { - uint32_t gId = getConfig()->crc32; char cwd[256]; int gpuVendor = getConfig()->GPUVendor; - if (gId == GHOST_SQUAD_EVOLUTION) + switch (gId) { + case GHOST_SQUAD_EVOLUTION: if (getConfig()->GPUVendor != NVIDIA_GPU) { for (int x = 0; x < gsevoShaderPatchesCount; x++) { - if ((strcmp(gsevoMesaShaderPatches[x].fileName, pathname) == 0) && - (gsevoMesaShaderPatches[x].shaderBufferSize != 0)) + if ((strcmp(gsevoMesaShaderPatches[x].fileName, pathname) == 0) && (gsevoMesaShaderPatches[x].shaderBufferSize != 0)) { *idx = x; return true; @@ -455,8 +471,7 @@ bool shaderFileInList(const char *pathname, int *idx) { for (int x = 0; x < gsevoShaderPatchesCount; x++) { - if ((strcmp(gsevoNvidiaShaderPatches[x].fileName, pathname) == 0) && - (gsevoNvidiaShaderPatches[x].shaderBufferSize != 0)) + if ((strcmp(gsevoNvidiaShaderPatches[x].fileName, pathname) == 0) && (gsevoNvidiaShaderPatches[x].shaderBufferSize != 0)) { *idx = x; return true; @@ -464,9 +479,8 @@ bool shaderFileInList(const char *pathname, int *idx) } return false; } - } - else if (gId == RAMBO) - { + break; + case RAMBO: if (getConfig()->GPUVendor != NVIDIA_GPU) { for (int x = 0; x < ramboMesaShaderPatchesCount; x++) @@ -493,22 +507,20 @@ bool shaderFileInList(const char *pathname, int *idx) } return false; } - } - else if (gId == THE_HOUSE_OF_THE_DEAD_4_REVA || gId == THE_HOUSE_OF_THE_DEAD_4_REVB || gId == THE_HOUSE_OF_THE_DEAD_4_REVC) - { + case THE_HOUSE_OF_THE_DEAD_4_REVA: + case THE_HOUSE_OF_THE_DEAD_4_REVB: + case THE_HOUSE_OF_THE_DEAD_4_REVC: for (int x = 0; x < hod4ShaderPatchesCount; x++) { - if ((strcmp(hod4ShaderPatches[x].fileName, basename((char *)pathname)) == 0) && - (hod4ShaderPatches[x].shaderBufferSize != 0)) + if ((strcmp(hod4ShaderPatches[x].fileName, basename((char *)pathname)) == 0) && (hod4ShaderPatches[x].shaderBufferSize != 0)) { *idx = x; return true; } } return false; - } - else if (gId == THE_HOUSE_OF_THE_DEAD_4_SPECIAL || gId == THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB) - { + case THE_HOUSE_OF_THE_DEAD_4_SPECIAL: + case THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB: for (int x = 0; x < hod4spShaderPatchesCount; x++) { if ((strcmp(hod4spShaderPatches[x].fileName, basename((char *)pathname)) == 0) && @@ -519,9 +531,7 @@ bool shaderFileInList(const char *pathname, int *idx) } } return false; - } - else if (gId == HARLEY_DAVIDSON) - { + case HARLEY_DAVIDSON: for (int x = 0; x < harleyShaderPatchesCount; x++) { if ((strcmp(harleyShaderPatches[x].fileName, basename((char *)pathname)) == 0) && @@ -532,9 +542,7 @@ bool shaderFileInList(const char *pathname, int *idx) } } return false; - } - else if (gId == PRIMEVAL_HUNT) - { + case PRIMEVAL_HUNT: for (int x = 0; x < phShaderPatchesCount; x++) { if ((strcmp(basename((char *)phShaderPatches[x].fileName), basename((char *)pathname)) == 0) && @@ -545,10 +553,10 @@ bool shaderFileInList(const char *pathname, int *idx) } } return false; - } - else if (gId == HUMMER || gId == HUMMER_SDLX || gId == HUMMER_EXTREME || gId == HUMMER_EXTREME_MDX) - { - + case HUMMER: + case HUMMER_SDLX: + case HUMMER_EXTREME: + case HUMMER_EXTREME_MDX: for (int x = 0; x < hummerFilesToModCount; x++) { if ((strcmp(basename((char *)hummerShaderFilesToMod[x].fileName), basename((char *)pathname)) == 0) && @@ -559,28 +567,31 @@ bool shaderFileInList(const char *pathname, int *idx) } } return false; - } - else if (gId == TOO_SPICY && gpuVendor != NVIDIA_GPU) - { - for (int x = 0; x < tooSpicyShaderPatchesCount; x++) + case TOO_SPICY: + if (gpuVendor != NVIDIA_GPU) { - if ((strcmp(tooSpicyShaderPatches[x].fileName, basename((char *)pathname)) == 0) && - (tooSpicyShaderPatches[x].shaderBufferSize != 0)) + for (int x = 0; x < tooSpicyShaderPatchesCount; x++) { - *idx = x; - return true; + if ((strcmp(tooSpicyShaderPatches[x].fileName, basename((char *)pathname)) == 0) && + (tooSpicyShaderPatches[x].shaderBufferSize != 0)) + { + *idx = x; + return true; + } } } return false; - } - else if (gId == THE_HOUSE_OF_THE_DEAD_EX && gpuVendor != NVIDIA_GPU) - { - for (int x = 0; x < hodexShaderPatchesCount; x++) + case THE_HOUSE_OF_THE_DEAD_EX: + if (gpuVendor != NVIDIA_GPU) { - if ((strcmp(hodexShaderPatches[x].fileName, basename((char *)pathname)) == 0) && (hodexShaderPatches[x].shaderBufferSize != 0)) + for (int x = 0; x < hodexShaderPatchesCount; x++) { - *idx = x; - return true; + if ((strcmp(hodexShaderPatches[x].fileName, basename((char *)pathname)) == 0) && + (hodexShaderPatches[x].shaderBufferSize != 0)) + { + *idx = x; + return true; + } } } return false; @@ -593,49 +604,83 @@ bool shaderFileInList(const char *pathname, int *idx) ShaderFilesToMod *filesToMod; int filesToModCount; - if ((gId == LETS_GO_JUNGLE || gId == LETS_GO_JUNGLE_REVA || gId == LETS_GO_JUNGLE_SPECIAL) && - (gpuVendor != NVIDIA_GPU || getConfig()->lgjRenderWithMesa == 1)) + switch (gId) { + case LETS_GO_JUNGLE: + case LETS_GO_JUNGLE_REVA: + case LETS_GO_JUNGLE_SPECIAL: + if (gpuVendor == NVIDIA_GPU && getConfig()->lgjRenderWithMesa != 1) + return false; filesToMod = lgjShaderFilesToMod; filesToModCount = lgjFilesToModCount; searchFolder1 = "/shader/Cg"; searchFolder2 = "/extraShader/Cg"; format = "%s/inc%s"; - } + break; + case INITIALD_4_EXP_REVB: + case INITIALD_4_EXP_REVC: + case INITIALD_4_EXP_REVD: + case INITIALD_4_REVA: + case INITIALD_4_REVB: + case INITIALD_4_REVC: + case INITIALD_4_REVD: + case INITIALD_4_REVG: + case INITIALD_5_JAP_REVA: + case INITIALD_5_JAP_REVF: + case INITIALD_5_EXP: + case INITIALD_5_EXP_20: + case INITIALD_5_EXP_20A: + if (gpuVendor == NVIDIA_GPU) + return false; - else if ((gId == INITIALD_4_EXP_REVB || gId == INITIALD_4_EXP_REVC || gId == INITIALD_4_EXP_REVD || gId == INITIALD_4_REVA || - gId == INITIALD_4_REVB || gId == INITIALD_4_REVC || gId == INITIALD_4_REVD || gId == INITIALD_4_REVG || - gId == INITIALD_5_JAP_REVA || gId == INITIALD_5_JAP_REVF || gId == INITIALD_5_EXP || gId == INITIALD_5_EXP_20 || - gId == INITIALD_5_EXP_20A) && - gpuVendor != NVIDIA_GPU) - { + // Set default values filesToMod = idShaderFilesToMod; filesToModCount = idFilesToModCount; - if (gId == INITIALD_4_REVA || gId == INITIALD_4_REVB || gId == INITIALD_4_REVC || gId == INITIALD_4_REVD || gId == INITIALD_4_REVG) - { - filesToMod = id4jShaderFilesToMod; - filesToModCount = id4FilesToModCount; - } searchFolder1 = "/shader/Cg/inc"; searchFolder2 = "/data/Shader"; - if (gId == INITIALD_5_JAP_REVA || gId == INITIALD_5_JAP_REVF || gId == INITIALD_5_EXP || gId == INITIALD_5_EXP_20 || - gId == INITIALD_5_EXP_20A) - { - searchFolder2 = "/data/V5SHADER"; - } format = "%s%s"; - } - else if ((gId == VIRTUA_TENNIS_3 || gId == VIRTUA_TENNIS_3_TEST || gId == VIRTUA_TENNIS_3_REVA || gId == VIRTUA_TENNIS_3_REVA_TEST || - gId == VIRTUA_TENNIS_3_REVB || gId == VIRTUA_TENNIS_3_REVB_TEST || gId == VIRTUA_TENNIS_3_REVC || - gId == VIRTUA_TENNIS_3_REVC_TEST) && - gpuVendor != NVIDIA_GPU) - { + + switch (gId) + { + case INITIALD_4_REVA: + case INITIALD_4_REVB: + case INITIALD_4_REVC: + case INITIALD_4_REVD: + case INITIALD_4_REVG: + filesToMod = id4jShaderFilesToMod; + filesToModCount = id4FilesToModCount; + break; + } + + switch (gId) + { + case INITIALD_5_JAP_REVA: + case INITIALD_5_JAP_REVF: + case INITIALD_5_EXP: + case INITIALD_5_EXP_20: + case INITIALD_5_EXP_20A: + searchFolder2 = "/data/V5SHADER"; + break; + } + break; + case VIRTUA_TENNIS_3: + case VIRTUA_TENNIS_3_TEST: + case VIRTUA_TENNIS_3_REVA: + case VIRTUA_TENNIS_3_REVA_TEST: + case VIRTUA_TENNIS_3_REVB: + case VIRTUA_TENNIS_3_REVB_TEST: + case VIRTUA_TENNIS_3_REVC: + case VIRTUA_TENNIS_3_REVC_TEST: + if (gpuVendor == NVIDIA_GPU) + return false; + filesToMod = vt3ShaderFilesToMod; filesToModCount = vt3FilesToModCount; searchFolder1 = "/shader/Cg/inc"; searchFolder2 = "/shader"; format = "%s%s"; } + if (strstr(pathname, searchFolder1) != NULL) { sprintf((void *)searchFileName, format, searchFolder1, fName); @@ -648,6 +693,7 @@ bool shaderFileInList(const char *pathname, int *idx) { return false; } + for (int x = 0; x < filesToModCount; x++) { if (strcmp(filesToMod[x].fileName, searchFileName) == 0) @@ -665,71 +711,70 @@ bool shaderFileInList(const char *pathname, int *idx) */ long int ftellGetShaderSize(int idx) { - uint32_t gId = getConfig()->crc32; - if (gId == GHOST_SQUAD_EVOLUTION) - { - if (getConfig()->GPUVendor != NVIDIA_GPU) - { - return gsevoMesaShaderPatches[idx].shaderBufferSize; - } - return gsevoNvidiaShaderPatches[idx].shaderBufferSize; - } - else if (gId == LETS_GO_JUNGLE || gId == LETS_GO_JUNGLE_REVA || gId == LETS_GO_JUNGLE_SPECIAL) + switch (gId) { + case GHOST_SQUAD_EVOLUTION: + return getConfig()->GPUVendor != NVIDIA_GPU ? gsevoMesaShaderPatches[idx].shaderBufferSize + : gsevoNvidiaShaderPatches[idx].shaderBufferSize; + + case LETS_GO_JUNGLE: + case LETS_GO_JUNGLE_REVA: + case LETS_GO_JUNGLE_SPECIAL: return lgjShaderFilesToMod[idx].shaderBufferSize; - } - else if (gId == INITIALD_4_EXP_REVB || gId == INITIALD_4_EXP_REVC || gId == INITIALD_4_EXP_REVD || gId == INITIALD_5_JAP_REVA || - gId == INITIALD_5_JAP_REVF || gId == INITIALD_5_EXP || gId == INITIALD_5_EXP_20 || gId == INITIALD_5_EXP_20A) - { + + case INITIALD_4_EXP_REVB: + case INITIALD_4_EXP_REVC: + case INITIALD_4_EXP_REVD: + case INITIALD_5_JAP_REVA: + case INITIALD_5_JAP_REVF: + case INITIALD_5_EXP: + case INITIALD_5_EXP_20: + case INITIALD_5_EXP_20A: return idShaderFilesToMod[idx].shaderBufferSize; - } - else if (gId == INITIALD_4_REVA || gId == INITIALD_4_REVB || gId == INITIALD_4_REVC || gId == INITIALD_4_REVD || gId == INITIALD_4_REVG) - { + + case INITIALD_4_REVA: + case INITIALD_4_REVB: + case INITIALD_4_REVC: + case INITIALD_4_REVD: + case INITIALD_4_REVG: return id4jShaderFilesToMod[idx].shaderBufferSize; - } - else if (gId == VIRTUA_TENNIS_3 || gId == VIRTUA_TENNIS_3_TEST || gId == VIRTUA_TENNIS_3_REVA || gId == VIRTUA_TENNIS_3_REVA_TEST || - gId == VIRTUA_TENNIS_3_REVB || gId == VIRTUA_TENNIS_3_REVB_TEST || gId == VIRTUA_TENNIS_3_REVC || - gId == VIRTUA_TENNIS_3_REVC_TEST) - { + + case VIRTUA_TENNIS_3: + case VIRTUA_TENNIS_3_TEST: + case VIRTUA_TENNIS_3_REVA: + case VIRTUA_TENNIS_3_REVA_TEST: + case VIRTUA_TENNIS_3_REVB: + case VIRTUA_TENNIS_3_REVB_TEST: + case VIRTUA_TENNIS_3_REVC: + case VIRTUA_TENNIS_3_REVC_TEST: return vt3ShaderFilesToMod[idx].shaderBufferSize; - } - else if (gId == TOO_SPICY) - { + + case TOO_SPICY: return tooSpicyShaderPatches[idx].shaderBufferSize; - } - else if (gId == RAMBO) - { - if (getConfig()->GPUVendor != NVIDIA_GPU) - { - return ramboMesaShaderPatches[idx].shaderBufferSize; - } - else - { - return ramboNvidiaShaderPatches[idx].shaderBufferSize; - } - } - else if (gId == THE_HOUSE_OF_THE_DEAD_4_REVA || gId == THE_HOUSE_OF_THE_DEAD_4_REVB || gId == THE_HOUSE_OF_THE_DEAD_4_REVC) - { + + case RAMBO: + return getConfig()->GPUVendor != NVIDIA_GPU ? ramboMesaShaderPatches[idx].shaderBufferSize + : ramboNvidiaShaderPatches[idx].shaderBufferSize; + + case THE_HOUSE_OF_THE_DEAD_4_REVA: + case THE_HOUSE_OF_THE_DEAD_4_REVB: + case THE_HOUSE_OF_THE_DEAD_4_REVC: return hod4ShaderPatches[idx].shaderBufferSize; - } - else if (gId == THE_HOUSE_OF_THE_DEAD_4_SPECIAL || gId == THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB) - { + + case THE_HOUSE_OF_THE_DEAD_4_SPECIAL: + case THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB: return hod4spShaderPatches[idx].shaderBufferSize; - } - else if (gId == THE_HOUSE_OF_THE_DEAD_EX) - { + case THE_HOUSE_OF_THE_DEAD_EX: return hodexShaderPatches[idx].shaderBufferSize; - } - else if (gId == HUMMER || gId == HUMMER_SDLX || gId == HUMMER_EXTREME || gId == HUMMER_EXTREME_MDX) - { + + case HUMMER: + case HUMMER_SDLX: + case HUMMER_EXTREME: + case HUMMER_EXTREME_MDX: return hummerShaderFilesToMod[idx].shaderBufferSize; - } - else if (gId == PRIMEVAL_HUNT) - { + case PRIMEVAL_HUNT: return phShaderPatches[idx].shaderBufferSize; - } - else if (gId == HARLEY_DAVIDSON) - { + case HARLEY_DAVIDSON: return harleyShaderPatches[idx].shaderBufferSize; } return -1; @@ -741,9 +786,9 @@ long int ftellGetShaderSize(int idx) */ size_t freadReplace(void *buf, size_t size, size_t count, int idx) { - uint32_t gId = getConfig()->crc32; - if (gId == GHOST_SQUAD_EVOLUTION) + switch (gId) { + case GHOST_SQUAD_EVOLUTION: if (getConfig()->GPUVendor != NVIDIA_GPU) { memcpy(buf, gsevoMesaShaderPatches[idx].shaderBuffer, gsevoMesaShaderPatches[idx].shaderBufferSize); @@ -753,37 +798,48 @@ size_t freadReplace(void *buf, size_t size, size_t count, int idx) memcpy(buf, gsevoNvidiaShaderPatches[idx].shaderBuffer, gsevoNvidiaShaderPatches[idx].shaderBufferSize); } return 1; - } - else if (gId == LETS_GO_JUNGLE || gId == LETS_GO_JUNGLE_REVA || gId == LETS_GO_JUNGLE_SPECIAL) - { + + case LETS_GO_JUNGLE: + case LETS_GO_JUNGLE_REVA: + case LETS_GO_JUNGLE_SPECIAL: memcpy(buf, lgjShaderFilesToMod[idx].shaderBuffer, size); return size; - } - else if (gId == INITIALD_4_EXP_REVB || gId == INITIALD_4_EXP_REVC || gId == INITIALD_4_EXP_REVD || gId == INITIALD_5_JAP_REVA || - gId == INITIALD_5_JAP_REVF || gId == INITIALD_5_EXP || gId == INITIALD_5_EXP_20 || gId == INITIALD_5_EXP_20A) - { + + case INITIALD_4_EXP_REVB: + case INITIALD_4_EXP_REVC: + case INITIALD_4_EXP_REVD: + case INITIALD_5_JAP_REVA: + case INITIALD_5_JAP_REVF: + case INITIALD_5_EXP: + case INITIALD_5_EXP_20: + case INITIALD_5_EXP_20A: memcpy(buf, idShaderFilesToMod[idx].shaderBuffer, size); return size; - } - else if (gId == INITIALD_4_REVA || gId == INITIALD_4_REVB || gId == INITIALD_4_REVC || gId == INITIALD_4_REVD || gId == INITIALD_4_REVG) - { + + case INITIALD_4_REVA: + case INITIALD_4_REVB: + case INITIALD_4_REVC: + case INITIALD_4_REVD: + case INITIALD_4_REVG: memcpy(buf, id4jShaderFilesToMod[idx].shaderBuffer, size); return size; - } - else if (gId == VIRTUA_TENNIS_3 || gId == VIRTUA_TENNIS_3_TEST || gId == VIRTUA_TENNIS_3_REVA || gId == VIRTUA_TENNIS_3_REVA_TEST || - gId == VIRTUA_TENNIS_3_REVB || gId == VIRTUA_TENNIS_3_REVB_TEST || gId == VIRTUA_TENNIS_3_REVC || - gId == VIRTUA_TENNIS_3_REVC_TEST) - { + + case VIRTUA_TENNIS_3: + case VIRTUA_TENNIS_3_TEST: + case VIRTUA_TENNIS_3_REVA: + case VIRTUA_TENNIS_3_REVA_TEST: + case VIRTUA_TENNIS_3_REVB: + case VIRTUA_TENNIS_3_REVB_TEST: + case VIRTUA_TENNIS_3_REVC: + case VIRTUA_TENNIS_3_REVC_TEST: memcpy(buf, vt3ShaderFilesToMod[idx].shaderBuffer, size); return size; - } - else if (gId == TOO_SPICY) - { + + case TOO_SPICY: memcpy(buf, tooSpicyShaderPatches[idx].shaderBuffer, tooSpicyShaderPatches[idx].shaderBufferSize); return tooSpicyShaderPatches[idx].shaderBufferSize; - } - else if (gId == RAMBO) - { + + case RAMBO: if (getConfig()->GPUVendor != NVIDIA_GPU) { memcpy(buf, ramboMesaShaderPatches[idx].shaderBuffer, ramboMesaShaderPatches[idx].shaderBufferSize); @@ -794,38 +850,40 @@ size_t freadReplace(void *buf, size_t size, size_t count, int idx) memcpy(buf, ramboNvidiaShaderPatches[idx].shaderBuffer, ramboNvidiaShaderPatches[idx].shaderBufferSize); return ramboNvidiaShaderPatches[idx].shaderBufferSize; } - } - else if (gId == THE_HOUSE_OF_THE_DEAD_4_REVA || gId == THE_HOUSE_OF_THE_DEAD_4_REVB || gId == THE_HOUSE_OF_THE_DEAD_4_REVC) - { + + case THE_HOUSE_OF_THE_DEAD_4_REVA: + case THE_HOUSE_OF_THE_DEAD_4_REVB: + case THE_HOUSE_OF_THE_DEAD_4_REVC: memcpy(buf, hod4ShaderPatches[idx].shaderBuffer, hod4ShaderPatches[idx].shaderBufferSize); return hod4ShaderPatches[idx].shaderBufferSize; - } - else if (gId == THE_HOUSE_OF_THE_DEAD_4_SPECIAL || gId == THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB) - { + + case THE_HOUSE_OF_THE_DEAD_4_SPECIAL: + case THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB: memcpy(buf, hod4spShaderPatches[idx].shaderBuffer, hod4spShaderPatches[idx].shaderBufferSize); return hod4spShaderPatches[idx].shaderBufferSize; - } - else if (gId == THE_HOUSE_OF_THE_DEAD_EX) - { + + case THE_HOUSE_OF_THE_DEAD_EX: memcpy(buf, hodexShaderPatches[idx].shaderBuffer, hodexShaderPatches[idx].shaderBufferSize); return hodexShaderPatches[idx].shaderBufferSize; - } - else if (gId == HUMMER || gId == HUMMER_SDLX || gId == HUMMER_EXTREME || gId == HUMMER_EXTREME_MDX) - { + + case HUMMER: + case HUMMER_SDLX: + case HUMMER_EXTREME: + case HUMMER_EXTREME_MDX: memcpy(buf, hummerShaderFilesToMod[idx].shaderBuffer, hummerShaderFilesToMod[idx].shaderBufferSize); return hummerShaderFilesToMod[idx].shaderBufferSize; - } - else if (gId == PRIMEVAL_HUNT) - { + + case PRIMEVAL_HUNT: memcpy(buf, phShaderPatches[idx].shaderBuffer, phShaderPatches[idx].shaderBufferSize); return phShaderPatches[idx].shaderBufferSize; - } - else if (gId == HARLEY_DAVIDSON) - { + + case HARLEY_DAVIDSON: memcpy(buf, harleyShaderPatches[idx].shaderBuffer, harleyShaderPatches[idx].shaderBufferSize); return harleyShaderPatches[idx].shaderBufferSize; + + default: + return -1; } - return -1; } /** @@ -838,13 +896,23 @@ char *cgGetProgramString(char *program, int e) { char *(*_cgGetProgramString)(char *program, int e) = dlsym(RTLD_NEXT, "cgGetProgramString"); - uint32_t gId = getConfig()->crc32; - - if (gId != INITIALD_4_EXP_REVB && gId != INITIALD_4_EXP_REVC && gId != INITIALD_4_EXP_REVD && gId != INITIALD_4_REVA && - gId != INITIALD_4_REVB && gId != INITIALD_4_REVC && gId != INITIALD_4_REVD && gId != INITIALD_4_REVG && - gId != INITIALD_5_JAP_REVA && gId != INITIALD_5_JAP_REVF && gId != INITIALD_5_EXP && gId != INITIALD_5_EXP_20 && - gId != INITIALD_5_EXP_20A) + switch (gId) { + case INITIALD_4_EXP_REVB: + case INITIALD_4_EXP_REVC: + case INITIALD_4_EXP_REVD: + case INITIALD_4_REVA: + case INITIALD_4_REVB: + case INITIALD_4_REVC: + case INITIALD_4_REVD: + case INITIALD_4_REVG: + case INITIALD_5_JAP_REVA: + case INITIALD_5_JAP_REVF: + case INITIALD_5_EXP: + case INITIALD_5_EXP_20: + case INITIALD_5_EXP_20A: + break; + default: return _cgGetProgramString(program, e); } @@ -870,33 +938,36 @@ char *cgGetProgramString(char *program, int e) */ void gl_ProgramStringARB(int target, int program_fmt, int program_len, char *program) { - uint32_t gId = getConfig()->crc32; + char *newProgram; + int newProgramLen; + void *addr = __builtin_return_address(0); - if (gId == GHOST_SQUAD_EVOLUTION) + switch (gId) { - void *addr = __builtin_return_address(0); + case GHOST_SQUAD_EVOLUTION: if (addr == (void *)0x8179fab) { - char *newProgram; newProgram = replaceInBlock(program, gsevoSet1, gsevoSetCount1, "", ""); int newProgramLen = strlen(newProgram); program = newProgram; program_len = newProgramLen; } - } - else if ((gId == LETS_GO_JUNGLE) || (gId == LETS_GO_JUNGLE_REVA) || gId == LETS_GO_JUNGLE_SPECIAL) - { - char *newProgram; + break; + case LETS_GO_JUNGLE: + case LETS_GO_JUNGLE_REVA: + case LETS_GO_JUNGLE_SPECIAL: newProgram = replaceInBlock(program, lgjCompiledShadersPatch, lgjCompiledShadersPatchCount, "", ""); - int newProgramLen = strlen(newProgram); + newProgramLen = strlen(newProgram); program = newProgram; program_len = newProgramLen; - } - else if ((gId == AFTER_BURNER_CLIMAX) || (gId == AFTER_BURNER_CLIMAX_REVA) || (gId == AFTER_BURNER_CLIMAX_REVB) || - (gId == AFTER_BURNER_CLIMAX_SDX) || (gId == AFTER_BURNER_CLIMAX_SDX_REVA) || - (gId == AFTER_BURNER_CLIMAX_SE) || (gId == AFTER_BURNER_CLIMAX_SE_REVA)) - { - char *newProgram; + break; + case AFTER_BURNER_CLIMAX: + case AFTER_BURNER_CLIMAX_REVA: + case AFTER_BURNER_CLIMAX_REVB: + case AFTER_BURNER_CLIMAX_SDX: + case AFTER_BURNER_CLIMAX_SDX_REVA: + case AFTER_BURNER_CLIMAX_SE: + case AFTER_BURNER_CLIMAX_SE_REVA: if (target == GL_VERTEX_PROGRAM_ARB) { newProgram = replaceInBlock(program, abcVsMesa, abcVsMesaCount, "", ""); @@ -905,13 +976,12 @@ void gl_ProgramStringARB(int target, int program_fmt, int program_len, char *pro { newProgram = replaceInBlock(program, abcFsMesa, abcFsMesaCount, "", ""); } - int newProgramLen = strlen(newProgram); + newProgramLen = strlen(newProgram); program = newProgram; program_len = newProgramLen; - } - else if ((gId == OUTRUN_2_SP_SDX) || (gId == OUTRUN_2_SP_SDX_REVA)) - { - char *newProgram; + break; + case OUTRUN_2_SP_SDX: + case OUTRUN_2_SP_SDX_REVA: if (target == GL_VERTEX_PROGRAM_ARB) { if (getConfig()->GPUVendor == NVIDIA_GPU) @@ -928,17 +998,21 @@ void gl_ProgramStringARB(int target, int program_fmt, int program_len, char *pro else newProgram = replaceInBlock(program, orFsMesa, orFsMesaCount, "", ""); } - int newProgramLen = strlen(newProgram); + newProgramLen = strlen(newProgram); program = newProgram; program_len = newProgramLen; - } - else if (gId == VIRTUA_FIGHTER_5 || gId == VIRTUA_FIGHTER_5_REVA || gId == VIRTUA_FIGHTER_5_REVB || - gId == VIRTUA_FIGHTER_5_REVE || gId == VIRTUA_FIGHTER_5_REVE || gId == VIRTUA_FIGHTER_5_EXPORT || - gId == VIRTUA_FIGHTER_5_R || gId == VIRTUA_FIGHTER_5_R_REVD || gId == VIRTUA_FIGHTER_5_R_REVG || - gId == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA || gId == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB || - gId == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000) - { - char *newProgram; + break; + case VIRTUA_FIGHTER_5: + case VIRTUA_FIGHTER_5_REVA: + case VIRTUA_FIGHTER_5_REVB: + case VIRTUA_FIGHTER_5_REVE: + case VIRTUA_FIGHTER_5_EXPORT: + case VIRTUA_FIGHTER_5_R: + case VIRTUA_FIGHTER_5_R_REVD: + case VIRTUA_FIGHTER_5_R_REVG: + case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA: + case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB: + case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000: if (target == GL_VERTEX_PROGRAM_ARB) { if (getConfig()->GPUVendor == ATI_GPU) @@ -962,13 +1036,11 @@ void gl_ProgramStringARB(int target, int program_fmt, int program_len, char *pro else newProgram = replaceInBlock(program, vf5FsMesa, vf5FsMesaCount, "", ""); } - int newProgramLen = strlen(newProgram); + newProgramLen = strlen(newProgram); program = newProgram; program_len = newProgramLen; - } - else if (gId == R_TUNED) - { - char *newProgram; + break; + case R_TUNED: if (target == GL_VERTEX_PROGRAM_ARB) { newProgram = replaceInBlock(program, rtunedVsMesa, rtunedVsMesaCount, "", ""); @@ -977,13 +1049,12 @@ void gl_ProgramStringARB(int target, int program_fmt, int program_len, char *pro { newProgram = replaceInBlock(program, rtunedFsMesa, rtunedFsMesaCount, "", ""); } - int newProgramLen = strlen(newProgram); + newProgramLen = strlen(newProgram); program = newProgram; program_len = newProgramLen; - } - else if (gId == MJ4_REVG || gId == MJ4_EVO) - { - char *newProgram; + break; + case MJ4_REVG: + case MJ4_EVO: if (target == GL_VERTEX_PROGRAM_ARB) { newProgram = replaceInBlock(program, mj4VsMesa, mj4VsMesaCount, "", ""); @@ -992,29 +1063,40 @@ void gl_ProgramStringARB(int target, int program_fmt, int program_len, char *pro { newProgram = replaceInBlock(program, mj4FsMesa, mj4FsMesaCount, "", ""); } - int newProgramLen = strlen(newProgram); + newProgramLen = strlen(newProgram); program = newProgram; program_len = newProgramLen; } glProgramStringARB(target, program_fmt, program_len, program); - if ((gId == VIRTUA_FIGHTER_5 || gId == VIRTUA_FIGHTER_5_REVA || gId == VIRTUA_FIGHTER_5_REVB || - gId == VIRTUA_FIGHTER_5_REVE || gId == VIRTUA_FIGHTER_5_REVE || gId == VIRTUA_FIGHTER_5_EXPORT || - gId == VIRTUA_FIGHTER_5_R || gId == VIRTUA_FIGHTER_5_R_REVD || gId == VIRTUA_FIGHTER_5_R_REVG || gId == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA || - gId == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB || gId == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000) && - getConfig()->GPUVendor == ATI_GPU) + switch (gId) { - int err = glGetError(); - if (err == 1282) + case VIRTUA_FIGHTER_5: + case VIRTUA_FIGHTER_5_REVA: + case VIRTUA_FIGHTER_5_REVB: + case VIRTUA_FIGHTER_5_REVE: + case VIRTUA_FIGHTER_5_EXPORT: + case VIRTUA_FIGHTER_5_R: + case VIRTUA_FIGHTER_5_R_REVD: + case VIRTUA_FIGHTER_5_R_REVG: + case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA: + case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB: + case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000: + if (getConfig()->GPUVendor == ATI_GPU) { - char *newProgram; - newProgram = replaceInBlock(program, vf5VsAti2, vf5VsAtiCount2, "", ""); - int newProgramLen = strlen(newProgram); - program = newProgram; - program_len = newProgramLen; - glProgramStringARB(target, program_fmt, program_len, program); + int err = glGetError(); + if (err == 1282) + { + char *newProgram; + newProgram = replaceInBlock(program, vf5VsAti2, vf5VsAtiCount2, "", ""); + int newProgramLen = strlen(newProgram); + program = newProgram; + program_len = newProgramLen; + glProgramStringARB(target, program_fmt, program_len, program); + } } } + if ((getConfig()->showDebugMessages)) { GLint result; @@ -1088,31 +1170,34 @@ char *cgCreateProgram(uint32_t context, int program_type, const char *program, i char *(*_cgCreateProgram)(uint32_t context, int program_type, const char *program, int profile, const char *entry, const char **args) = dlsym(RTLD_NEXT, "cgCreateProgram"); - uint32_t gId = getConfig()->crc32; - if ((gId != VIRTUA_TENNIS_3 && gId != VIRTUA_TENNIS_3_TEST && gId != VIRTUA_TENNIS_3_REVA && gId != VIRTUA_TENNIS_3_REVA_TEST && - gId != VIRTUA_TENNIS_3_REVB && gId != VIRTUA_TENNIS_3_REVB_TEST && gId != VIRTUA_TENNIS_3_REVC && - gId != VIRTUA_TENNIS_3_REVC_TEST && gId != INITIALD_4_EXP_REVB && gId != INITIALD_4_EXP_REVC && gId != INITIALD_4_EXP_REVD && - gId != LETS_GO_JUNGLE && gId != LETS_GO_JUNGLE_REVA && gId != LETS_GO_JUNGLE_SPECIAL && gId != INITIALD_4_REVA && - gId != INITIALD_4_REVB && gId != INITIALD_4_REVC && gId != INITIALD_4_REVD && gId != INITIALD_4_REVG && - gId != INITIALD_5_JAP_REVA && gId != INITIALD_5_JAP_REVF && gId != INITIALD_5_EXP && gId != INITIALD_5_EXP_20 && - gId != INITIALD_5_EXP_20A) || - (getConfig()->GPUVendor == NVIDIA_GPU)) + if (getConfig()->GPUVendor == NVIDIA_GPU) { if ((gId != LETS_GO_JUNGLE && gId != LETS_GO_JUNGLE_REVA && gId != LETS_GO_JUNGLE_SPECIAL) || getConfig()->lgjRenderWithMesa == 0) return _cgCreateProgram(context, program_type, program, profile, entry, args); } - if (gId == INITIALD_4_EXP_REVB || gId == INITIALD_4_EXP_REVC || gId == INITIALD_4_EXP_REVD || gId == INITIALD_4_REVA || - gId == INITIALD_4_REVB || gId == INITIALD_4_REVC || gId == INITIALD_4_REVD || gId == INITIALD_4_REVG || - gId == INITIALD_5_JAP_REVA || gId == INITIALD_5_JAP_REVF || gId == INITIALD_5_EXP || gId == INITIALD_5_EXP_20 || - gId == INITIALD_5_EXP_20A) + switch (gId) { + case INITIALD_4_EXP_REVB: + case INITIALD_4_EXP_REVC: + case INITIALD_4_EXP_REVD: + case INITIALD_4_REVA: + case INITIALD_4_REVB: + case INITIALD_4_REVC: + case INITIALD_4_REVD: + case INITIALD_4_REVG: + case INITIALD_5_JAP_REVA: + case INITIALD_5_JAP_REVF: + case INITIALD_5_EXP: + case INITIALD_5_EXP_20: + case INITIALD_5_EXP_20A: if ((profile == 6148) || (profile == 6150) || profile == 7001) profile = 6150; else if ((profile == 6149) || (profile == 6151) || profile == 7000) profile = 7000; else printf("profile %d not supported\n", profile); + break; } const char *op6150[] = {"NumTemps=31", "MaxInstructions=1024", "MaxAddressRegs=1", "MaxLocalParams=256", NULL}; @@ -1139,23 +1224,30 @@ char *cgCreateProgram(uint32_t context, int program_type, const char *program, i void gl_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count, const GLcharARB **const string, const GLint *length) { - uint32_t gId = getConfig()->crc32; - if (gId != SEGA_RACE_TV && gId != HUMMER && gId != HUMMER_SDLX && gId != HUMMER_EXTREME && gId != HUMMER_EXTREME_MDX) + switch (gId) { + case SEGA_RACE_TV: + case HUMMER: + case HUMMER_SDLX: + case HUMMER_EXTREME: + case HUMMER_EXTREME_MDX: + break; + default: glShaderSourceARB(shaderObj, count, string, length); return; } char *newProgram = malloc(250000); - if (gId == SEGA_RACE_TV) + switch (gId) { - void *addr = __builtin_return_address(0); // load the address of the function that called glShaderSourceARB - + case SEGA_RACE_TV: + { + void *addr = __builtin_return_address(0); if (addr <= (void *)0x82fd823) { newProgram = strdup(*string); } - else if (addr == (void *)0x84bbff1) // check the address to apply the patches in the right place. + else if (addr == (void *)0x84bbff1) { if (getConfig()->GPUVendor != NVIDIA_GPU) { @@ -1168,7 +1260,7 @@ void gl_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count, const GLcharARB ** newProgram = replaceInBlock(newProgram, srtvVsNvidia, srtvVsNvidiaCount, "", ""); } } - else if (addr == (void *)0x084bc06b) // check the address to apply the patches in the right place. + else if (addr == (void *)0x084bc06b) { if (getConfig()->GPUVendor != NVIDIA_GPU) { @@ -1181,12 +1273,15 @@ void gl_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count, const GLcharARB ** } } } - else if (gId == HUMMER || gId == HUMMER_SDLX || gId == HUMMER_EXTREME || gId == HUMMER_EXTREME_MDX) + break; + case HUMMER: + case HUMMER_SDLX: + case HUMMER_EXTREME: + case HUMMER_EXTREME_MDX: { void *addr = __builtin_return_address(0); - if ((addr != (void *)0x830a501) && (addr != (void *)0x830a485) && (addr != (void *)0x08319841) && - (addr != (void *)0x083197c5) && (addr != (void *)0x83af939) && (addr != (void *)0x83af9b3) && - (addr != (void *)0x83b0515) && (addr != (void *)0x83b058f)) + if ((addr != (void *)0x830a501) && (addr != (void *)0x830a485) && (addr != (void *)0x08319841) && (addr != (void *)0x083197c5) && + (addr != (void *)0x83af939) && (addr != (void *)0x83af9b3) && (addr != (void *)0x83b0515) && (addr != (void *)0x83b058f)) { sprintf(newProgram, "%s", hummerShaderFilesToMod[hummerExtremeShaderFileIndex].shaderBuffer); } @@ -1196,6 +1291,12 @@ void gl_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count, const GLcharARB ** return; } } + break; + default: + glShaderSourceARB(shaderObj, count, string, length); + return; + } + const char *newString = malloc(250000); memset((void *)newString, '\0', 250000); newString = strdup(newProgram); @@ -1220,8 +1321,7 @@ void gl_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count, const GLcharARB ** void *gl_XGetProcAddressARB(const unsigned char *procName) { int dbgMsg = getConfig()->showDebugMessages; - if (getConfig()->crc32 != HUMMER && getConfig()->crc32 != HUMMER_SDLX && getConfig()->crc32 != HUMMER_EXTREME && - getConfig()->crc32 != HUMMER_EXTREME_MDX) + if (gId != HUMMER && gId != HUMMER_SDLX && gId != HUMMER_EXTREME && gId != HUMMER_EXTREME_MDX) { if (strcmp((const char *)procName, "glGenOcclusionQueriesNV") == 0) { @@ -1372,14 +1472,26 @@ void glBindTexture(GLenum target, GLuint texture) { void (*_glBindTexture)(GLenum target, GLuint texture) = dlsym(RTLD_NEXT, "glBindTexture"); _glBindTexture(target, texture); - int gId = getConfig()->crc32; - if ((gId == VIRTUA_FIGHTER_5 || gId == VIRTUA_FIGHTER_5_REVA || gId == VIRTUA_FIGHTER_5_REVB || - gId == VIRTUA_FIGHTER_5_REVE || gId == VIRTUA_FIGHTER_5_EXPORT || gId == VIRTUA_FIGHTER_5_R || - gId == VIRTUA_FIGHTER_5_R_REVD || gId == VIRTUA_FIGHTER_5_R_REVG ||gId == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA || - gId == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB || gId == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000) && - getConfig()->GPUVendor != NVIDIA_GPU) + switch (gId) { - glTexParameterf(target, GL_TEXTURE_LOD_BIAS, -10.0f); // Adjust LOD bias + case VIRTUA_FIGHTER_5: + case VIRTUA_FIGHTER_5_REVA: + case VIRTUA_FIGHTER_5_REVB: + case VIRTUA_FIGHTER_5_REVE: + case VIRTUA_FIGHTER_5_EXPORT: + case VIRTUA_FIGHTER_5_R: + case VIRTUA_FIGHTER_5_R_REVD: + case VIRTUA_FIGHTER_5_R_REVG: + case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA: + case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB: + case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000: + if (getConfig()->GPUVendor != NVIDIA_GPU) + { + glTexParameterf(target, GL_TEXTURE_LOD_BIAS, -10.0f); // Adjust LOD bias + } + break; + default: + break; } } @@ -1612,7 +1724,7 @@ int xdlt_load_mmfile(char const *path, mmfile_t *mf) int pos = 0; long size; char *blk; - uint32_t gId = getConfig()->crc32; + if (xdl_init_mmfile(mf, XDLT_STD_BLKSIZE, XDL_MMF_ATOMIC) < 0) { exit(1); @@ -1677,13 +1789,30 @@ int handle_patch(void *priv, mmbuffer_t *mb, int nbuf) */ void cacheModedShaderFiles() { - uint32_t gId = getConfig()->crc32; char cwd[256]; char fullPath[512]; char shaderBuffer[100000]; char *newProgram; - if ((gId == LETS_GO_JUNGLE) || (gId == LETS_GO_JUNGLE_REVA) || (gId == LETS_GO_JUNGLE_SPECIAL)) + ShaderFilesToMod *shaderFilesToMod; + int filesToModCount; + + memallocator_t malt; + malt.priv = NULL; + malt.malloc = wrap_malloc; + malt.free = wrap_free; + malt.realloc = wrap_realloc; + xdl_set_allocator(&malt); + mmfile_t patchedFile; + ShaderFilesToPatch *shaderFilesToPatch; + int shaderFilesToPatchCount; + char folderName[50]; + sprintf(folderName, "/../fs/shader/"); + + switch (gId) { + case LETS_GO_JUNGLE: + case LETS_GO_JUNGLE_REVA: + case LETS_GO_JUNGLE_SPECIAL: for (int x = 0; x < lgjFilesToModCount; x++) { getcwd(cwd, sizeof(cwd)); @@ -1702,14 +1831,20 @@ void cacheModedShaderFiles() lgjShaderFilesToMod[x].shaderBuffer = strndup(newProgram, strlen(newProgram)); free(newProgram); } - } - else if (gId == INITIALD_4_EXP_REVB || gId == INITIALD_4_EXP_REVC || gId == INITIALD_4_EXP_REVD || gId == INITIALD_4_REVA || - gId == INITIALD_4_REVB || gId == INITIALD_4_REVC || gId == INITIALD_4_REVD || gId == INITIALD_4_REVG || - gId == INITIALD_5_JAP_REVA || gId == INITIALD_5_JAP_REVF || gId == INITIALD_5_EXP || gId == INITIALD_5_EXP_20 || - gId == INITIALD_5_EXP_20A) - { - ShaderFilesToMod *shaderFilesToMod; - int filesToModCount; + break; + case INITIALD_4_EXP_REVB: + case INITIALD_4_EXP_REVC: + case INITIALD_4_EXP_REVD: + case INITIALD_4_REVA: + case INITIALD_4_REVB: + case INITIALD_4_REVC: + case INITIALD_4_REVD: + case INITIALD_4_REVG: + case INITIALD_5_JAP_REVA: + case INITIALD_5_JAP_REVF: + case INITIALD_5_EXP: + case INITIALD_5_EXP_20: + case INITIALD_5_EXP_20A: if (gId == INITIALD_4_REVA || gId == INITIALD_4_REVB || gId == INITIALD_4_REVC || gId == INITIALD_4_REVD || gId == INITIALD_4_REVG) { shaderFilesToMod = id4jShaderFilesToMod; @@ -1733,8 +1868,7 @@ void cacheModedShaderFiles() loadShader(fullPath, shaderBuffer); if (strcmp(shaderFilesToMod[x].fileName, "/data/V5SHADER/effect_p.fx") == 0) { - newProgram = - replaceInBlock(shaderBuffer, id5ShaderReplaceSetForSmoke, id5ShaderReplaceSetForSmokeCount, "", ""); + newProgram = replaceInBlock(shaderBuffer, id5ShaderReplaceSetForSmoke, id5ShaderReplaceSetForSmokeCount, "", ""); } else if (strcmp(shaderFilesToMod[x].fileName, "/data/Shader/effect_p.fx") == 0) { @@ -1743,19 +1877,22 @@ void cacheModedShaderFiles() else { newProgram = replaceInBlock(shaderBuffer, attribsSet, attribsSetCount, "struct\tVS_INPUT_P", ""); - newProgram = - replaceInBlock(newProgram, attribsSet, attribsSetCount, "struct VS_INPUT", "struct VS_OUTPUT"); + newProgram = replaceInBlock(newProgram, attribsSet, attribsSetCount, "struct VS_INPUT", "struct VS_OUTPUT"); newProgram = replaceInBlock(newProgram, idShaderReplaceSet, idShaderReplaceCount, "", ""); } shaderFilesToMod[x].shaderBufferSize = strlen(newProgram); shaderFilesToMod[x].shaderBuffer = strndup(newProgram, strlen(newProgram)); free(newProgram); } - } - else if (gId == VIRTUA_TENNIS_3 || gId == VIRTUA_TENNIS_3_TEST || gId == VIRTUA_TENNIS_3_REVA || gId == VIRTUA_TENNIS_3_REVA_TEST || - gId == VIRTUA_TENNIS_3_REVB || gId == VIRTUA_TENNIS_3_REVB_TEST || gId == VIRTUA_TENNIS_3_REVC || - gId == VIRTUA_TENNIS_3_REVC_TEST) - { + break; + case VIRTUA_TENNIS_3: + case VIRTUA_TENNIS_3_TEST: + case VIRTUA_TENNIS_3_REVA: + case VIRTUA_TENNIS_3_REVA_TEST: + case VIRTUA_TENNIS_3_REVB: + case VIRTUA_TENNIS_3_REVB_TEST: + case VIRTUA_TENNIS_3_REVC: + case VIRTUA_TENNIS_3_REVC_TEST: for (int x = 0; x < vt3FilesToModCount; x++) { getcwd(cwd, sizeof(cwd)); @@ -1769,9 +1906,11 @@ void cacheModedShaderFiles() vt3ShaderFilesToMod[x].shaderBuffer = strndup(newProgram, strlen(newProgram)); free(newProgram); } - } - else if ((gId == HUMMER) || (gId == HUMMER_SDLX) || (gId == HUMMER_EXTREME) || (gId == HUMMER_EXTREME_MDX)) - { + break; + case HUMMER: + case HUMMER_SDLX: + case HUMMER_EXTREME: + case HUMMER_EXTREME_MDX: for (int x = 0; x < hummerFilesToModCount; x++) { getcwd(cwd, sizeof(cwd)); @@ -1784,34 +1923,21 @@ void cacheModedShaderFiles() } if (getConfig()->hummerFlickerFix) { - newProgram = - replaceInBlock(newProgram, hummerShaderReplaceFlicker, hummerShaderReplaceFlickerCount, "", ""); + newProgram = replaceInBlock(newProgram, hummerShaderReplaceFlicker, hummerShaderReplaceFlickerCount, "", ""); } hummerShaderFilesToMod[x].shaderBufferSize = strlen(newProgram); hummerShaderFilesToMod[x].shaderBuffer = strndup(newProgram, strlen(newProgram)); free(newProgram); } - } - else - { - memallocator_t malt; - malt.priv = NULL; - malt.malloc = wrap_malloc; - malt.free = wrap_free; - malt.realloc = wrap_realloc; - xdl_set_allocator(&malt); - mmfile_t patchedFile; - ShaderFilesToPatch *shaderFilesToPatch; - int shaderFilesToPatchCount; - char folderName[50]; - sprintf(folderName, "/../fs/shader/"); - if (gId == TOO_SPICY) + break; + default: + switch (gId) { + case TOO_SPICY: shaderFilesToPatch = tooSpicyShaderPatches; shaderFilesToPatchCount = tooSpicyShaderPatchesCount; - } - else if (gId == RAMBO) - { + break; + case RAMBO: if (getConfig()->GPUVendor != NVIDIA_GPU) { shaderFilesToPatch = ramboMesaShaderPatches; @@ -1822,37 +1948,34 @@ void cacheModedShaderFiles() shaderFilesToPatch = ramboNvidiaShaderPatches; shaderFilesToPatchCount = ramboNvidiaShaderPatchesCount; } - } - else if (gId == HARLEY_DAVIDSON) - { + break; + case HARLEY_DAVIDSON: shaderFilesToPatch = harleyShaderPatches; shaderFilesToPatchCount = harleyShaderPatchesCount; - } - else if (gId == THE_HOUSE_OF_THE_DEAD_EX) - { + break; + case THE_HOUSE_OF_THE_DEAD_EX: shaderFilesToPatch = hodexShaderPatches; shaderFilesToPatchCount = hodexShaderPatchesCount; - } - else if (gId == THE_HOUSE_OF_THE_DEAD_4_REVA || gId == THE_HOUSE_OF_THE_DEAD_4_REVB || gId == THE_HOUSE_OF_THE_DEAD_4_REVC) - { + break; + case THE_HOUSE_OF_THE_DEAD_4_REVA: + case THE_HOUSE_OF_THE_DEAD_4_REVB: + case THE_HOUSE_OF_THE_DEAD_4_REVC: sprintf(folderName, "/../fs/dat/"); shaderFilesToPatchCount = hod4ShaderPatchesCount; shaderFilesToPatch = hod4ShaderPatches; - } - else if (gId == THE_HOUSE_OF_THE_DEAD_4_SPECIAL || gId == THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB) - { + break; + case THE_HOUSE_OF_THE_DEAD_4_SPECIAL: + case THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB: sprintf(folderName, "/../fs/dat/"); shaderFilesToPatchCount = hod4spShaderPatchesCount; shaderFilesToPatch = hod4spShaderPatches; - } - else if (gId == PRIMEVAL_HUNT) - { + break; + case PRIMEVAL_HUNT: sprintf(folderName, "/../data/nnstdshader/"); shaderFilesToPatchCount = phShaderPatchesCount; shaderFilesToPatch = phShaderPatches; - } - else if (gId == GHOST_SQUAD_EVOLUTION) - { + break; + case GHOST_SQUAD_EVOLUTION: shaderFilesToPatchCount = gsevoShaderPatchesCount; sprintf(folderName, "/%s", ""); if (getConfig()->GPUVendor != NVIDIA_GPU) @@ -1863,7 +1986,9 @@ void cacheModedShaderFiles() { shaderFilesToPatch = gsevoNvidiaShaderPatches; } + break; } + for (int x = 0; x < shaderFilesToPatchCount; x++) { mmfile_t oriFile, patch; diff --git a/src/lindbergh/stb_image.h b/src/lindbergh/stb_image.h index e4919b4..8ae27e0 100644 --- a/src/lindbergh/stb_image.h +++ b/src/lindbergh/stb_image.h @@ -702,14 +702,14 @@ static int stbi__sse2_available() static int stbi__sse2_available() { -//#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later - // GCC 4.8+ has a nice way to do this - //return __builtin_cpu_supports("sse2"); -//#else - // portable way to do this, preferably without using GCC inline ASM? - // just bail for now. - return 0; -//#endif + // #if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later + // // GCC 4.8+ has a nice way to do this + // return __builtin_cpu_supports("sse2"); + // #else + // portable way to do this, preferably without using GCC inline ASM? + // just bail for now. + return 0; + // #endif } #endif #endif diff --git a/src/lindbergh/touchscreen.c b/src/lindbergh/touchscreen.c new file mode 100644 index 0000000..2a55ce0 --- /dev/null +++ b/src/lindbergh/touchscreen.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include +#include + +char phSendBuf[10]; +bool phBufferFilled = false; +int phCommand = 1; +int phCommandByte = 0; +uint16_t coordX; +uint16_t coordY; +#define TOUCH_START 0x81 +#define TOUCH_TOUCHING 0x82 +#define TOUCH_END 0x84 + +void phCoordinates(int x, int y, int w, int h, int button) +{ + coordX = (float)x / ((float)w * 0.0002441406); + coordY = (float)y / ((float)h * 0.0002441406); + memset(phSendBuf, 0, sizeof(phSendBuf)); + + if (button == SDL_MOUSEBUTTONDOWN || button == ButtonPress) + { + phSendBuf[2] = TOUCH_START; + phCommand = 1; + } + else if (button == SDL_MOUSEBUTTONUP || button == ButtonRelease) + { + phSendBuf[2] = TOUCH_END; + phCommand = 3; + } + else if (button == SDL_MOUSEMOTION || button == MotionNotify) + { + phSendBuf[2] = TOUCH_TOUCHING; + phCommand = 2; + } + phSendBuf[0] = 0x55; + phSendBuf[1] = 0x54; + phSendBuf[3] = (char)(coordX & 0xFF); + phSendBuf[4] = (char)((coordX >> 8) & 0xff); + phSendBuf[5] = (char)(coordY & 0xFF); + phSendBuf[6] = (char)((coordY >> 8) & 0xff); + + phBufferFilled = true; +} + +uint8_t phCalcChecksum() +{ + int8_t checksum = -0x56; + for (int x = 0; x < 9;x++) + { + checksum += phSendBuf[x]; + } + return (uint8_t)(checksum & 0xff); +} + +ssize_t phRead(int fd, void *buf, size_t count) +{ + if(!phBufferFilled) + return 0; + + + if(phCommandByte == 9) + { + switch (phCommand) + { + case 1: + phCommand = 2; + break; + case 2: + phSendBuf[2] = TOUCH_TOUCHING; + break; + case 3: + phBufferFilled = false; + } + phSendBuf[9] = phCalcChecksum(); + } + memcpy(buf, &phSendBuf[phCommandByte], sizeof(char)); + phCommandByte++; + if (phCommandByte == 10) + phCommandByte = 0; + return 1; +} \ No newline at end of file diff --git a/src/lindbergh/touchscreen.h b/src/lindbergh/touchscreen.h new file mode 100644 index 0000000..81eafbd --- /dev/null +++ b/src/lindbergh/touchscreen.h @@ -0,0 +1,9 @@ +#ifndef TOUCHSCREEN_H +#define TOUCHSCREEN_H + +#include + +void phCoordinates(int x, int y, int w, int h, int button); +ssize_t phRead(int fd, void *buf, size_t count); + +#endif \ No newline at end of file diff --git a/src/lindbergh/x11hooks.c b/src/lindbergh/x11hooks.c index cf2d5a2..5760548 100644 --- a/src/lindbergh/x11hooks.c +++ b/src/lindbergh/x11hooks.c @@ -19,6 +19,7 @@ #include "securityboard.h" #include "fps_limiter.h" #include "sdlcalls.h" +#include "customcursor.h" extern bool SDLWindowCreated; extern bool gettingGPUVendor; @@ -26,11 +27,14 @@ extern bool GLUTGame; bool creatingWindow = false; -Window win; +Window window; extern Display *x11Display; extern Window x11Window; +extern void *customCursor; +extern void *phTouchCursor; + /** * Stop the house of the dead games turning keyboard repeating off. */ @@ -42,12 +46,17 @@ int XAutoRepeatOff(Display *display) Display *XOpenDisplay(const char *display_name) { Display *(*_XOpenDisplay)(const char *display_name) = dlsym(RTLD_NEXT, "XOpenDisplay"); - if (SDLWindowCreated || gettingGPUVendor || GLUTGame || getConfig()->noSDL) - return _XOpenDisplay(display_name); - creatingWindow = true; - initSDL(0, 0); - creatingWindow = false; + if (SDLWindowCreated || gettingGPUVendor || getConfig()->noSDL) + { + x11Display = _XOpenDisplay(display_name); + } + else + { + creatingWindow = true; + initSDL(0, 0); + creatingWindow = false; + } return x11Display; } @@ -61,19 +70,16 @@ Window XCreateWindow(Display *display, Window parent, int x, int y, unsigned int if ((gettingGPUVendor || creatingWindow) || (GLUTGame && getConfig()->noSDL == 0)) { - Window window = _XCreateWindow(display, parent, x, y, width, height, border_width, depth, class, visual, - valueMask, attributes); - return window; + window = _XCreateWindow(display, parent, x, y, width, height, border_width, depth, class, visual, valueMask, attributes); } - - if (getConfig()->noSDL) + else if (getConfig()->noSDL) { width = getConfig()->width; height = getConfig()->height; attributes->event_mask = attributes->event_mask | KeyPressMask | KeyReleaseMask | PointerMotionMask; - Window window = _XCreateWindow(display, parent, x, y, width, height, border_width, depth, class, visual, valueMask, attributes); + window = _XCreateWindow(display, parent, x, y, width, height, border_width, depth, class, visual, valueMask, attributes); printf(" X11 RESOLUTION: %dx%d\n\n", width, height); if (getConfig()->fullscreen) @@ -82,13 +88,17 @@ Window XCreateWindow(Display *display, Window parent, int x, int y, unsigned int Atom wm_fullscreen = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", true); XChangeProperty(display, window, wm_state, XA_ATOM, 32, PropModeReplace, (unsigned char *)&wm_fullscreen, 1); } - win = window; + x11Window = window; + loadCursors(); + setCursor(customCursor); + if (getConfig()->hideCursor) + hideCursor(); } else { - win = x11Window; + window = x11Window; } - return win; + return window; } int XGrabPointer(Display *display, Window grab_window, Bool owner_events, unsigned int event_mask, int pointer_mode, @@ -203,38 +213,6 @@ int XF86VidModeGetAllModeLines(Display *display, int screen, int *modecount_retu return true; } -// Cursor XCreatePixmapCursor(Display *display, Pixmap source, Pixmap mask, XColor *fg, XColor *bg, unsigned int x, -// unsigned int y) -// { -// int (*_XCreatePixmapCursor)(Display *display, Pixmap source, Pixmap mask, XColor *fg, XColor *bg, unsigned int x, -// unsigned int y) = dlsym(RTLD_NEXT, "XCreatePixmapCursor"); -// if (SDLGame) -// return 0; -// return _XCreatePixmapCursor(display, source, mask, fg, bg, x, y); -// } - -// int XFreePixmap(Display *display, Pixmap pixmap) -// { -// int (*_XFreePixmap)(Display *display, Pixmap pixmap) = dlsym(RTLD_NEXT, "XFreePixmap"); -// if (SDLGame) -// return 0; -// return _XFreePixmap(display, pixmap); -// } - -// Pixmap XCreateBitmapFromData(Display *display, Drawable drawable, const char *data, unsigned int x, unsigned int y) -// { -// Pixmap (*_XCreateBitmapFromData)(Display *display, Drawable drawable, const char *data, unsigned int x, -// unsigned int y) = dlsym(RTLD_NEXT, "XCreateBitmapFromData"); -// if (SDLGame) -// return 0; -// return _XCreateBitmapFromData(display, drawable, data, x, y); -// } - -// int XDefineCursor(Display *display, Window w, Cursor cursor) -// { -// return 0; -// } - typedef unsigned int uint; void glGenFencesNV(int n, uint *fences)