Compare commits

...
Author SHA1 Message Date
cambragol 3e574882f3 Update worldmap.cc 2025-05-20 14:57:14 +09:00
cambragol 5995592664 Update worldmap.cc 2025-05-20 07:02:01 +09:00
Mike Klaas 982c5fcb42 Fix visibility of city circles and names
Currently, cities are not drawn until at least half of it is onscreen, meaning they "pop in" suddenly.  This fixes that problem.

Also, the check for city name was too aggressive, meaning the name of small cities (e.g. Motel in Sonora) would fail to render near the bottom of the screen.
2025-05-14 21:58:49 -07:00
sherief 9cd309b263 Merge pull request #128 from fallout2-ce/gapless-music
Gapless music.
2025-05-14 01:51:24 -07:00
Mike Klaas de7f12f3ca Merge pull request #125 from fallout2-ce/remove-text-on-wm-transition
Remove floaters when moving to a new world map location
2025-05-13 23:20:51 -07:00
Sherief Farouk 7a2edd5677 The clang-format gods are fickle. 2025-05-13 04:02:05 -07:00
Sherief Farouk 66b68f84dc Pleasing the code formatting gods. 2025-05-13 03:57:59 -07:00
Sherief Farouk fef49692e1 _gsound_background_play_level_music() skips rewind when asked to play same track and gapless is on. 2025-05-13 03:37:02 -07:00
Sherief Farouk 6c3c0d34c2 Skipping loading sound when gapless music is enabled. 2025-05-13 03:34:01 -07:00
Sherief Farouk 42e016e4f9 Declared SFall config flag for gapless music. 2025-05-13 03:33:00 -07:00
Mike Klaas 66542dc28a Merge pull request #121 from fallout2-ce/deobfuscate-item
Deobfuscate item.h,cc
2025-05-12 23:20:10 -07:00
Mike Klaas 5270cf0d55 Merge pull request #124 from fallout2-ce/mikeklaas-update-readme
Update README.md
2025-05-12 23:19:27 -07:00
Vasilii Rogin e598d06c4a Merge pull request #86 from roginvs/test_winxp_support
Linking stdlib statically for win32
2025-05-13 08:34:32 +03:00
Mike Klaas 66f7137f74 Remove floaters when moving to a new world map location
Fixes #115
2025-05-12 21:35:13 -07:00
Mike Klaas cf59439352 Update README.md 2025-05-12 16:51:40 -07:00
Mike Klaas 02ee5cba5d Update README.md
Update README with a pointer to the right release url, updated f2_res.ini support, and mention that this is a fork.
2025-05-12 16:50:37 -07:00
sherief 218fd20700 Merge pull request #51 from cambragol/patch-11
Update pipboy.cc for full pagination
2025-05-12 01:26:12 -07:00
Mike Klaas 7e18a6980a Deobfuscate item.h,cc
As always, no logic changes, only variable/field renames
2025-05-11 23:05:44 -07:00
Vasilii Rogin 66c0218741 Merge pull request #117 from fallout2-ce/fix_crash_on_game_load
Load pipboy messages when rendering saveslots
2025-05-11 14:05:01 +03:00
Vasilii Rogin 8fc789d6f9 Merge pull request #118 from fallout2-ce/add_pr_template
Add pull request template
2025-05-11 12:50:01 +03:00
Vasilii Rogin ddc5be3b6d Add PR template 2025-05-11 12:49:03 +03:00
Vasilii Rogin 833b6d8213 Fix formatting using this command:
docker run --rm \
  -v $(pwd):/app --workdir /app  \
  --user $(id -u):$(id -g) silkeh/clang:18 \
  bash -c 'find src -type f -name \*.cc -o -name \*.h | xargs clang-format -i'
2025-05-11 12:37:42 +03:00
Vasilii Rogin 4f117678ee Fix func declaration 2025-05-11 12:35:16 +03:00
Vasilii Rogin 499f994c37 Use struct initializer 2025-05-11 12:34:40 +03:00
Vasilii Rogin d6c17c1876 Emit warning if message is not found 2025-05-11 12:32:26 +03:00
Vasilii Rogin 347bf8b135 Load and unload pipboy messages for loadsave 2025-05-11 12:30:01 +03:00
Vasilii Rogin faf6439293 Load pipboy messages when rendering saveslots 2025-05-11 12:17:00 +03:00
Vasilii Rogin a259a3318e Merge pull request #114 from fallout2-ce/fix-skill-oob-access
Fix for #76 (occasional crash when using skills on scenery objects).
2025-05-11 08:58:14 +03:00
sherief 50e9fab544 Merge pull request #112 from fallout2-ce/deobfus-animation
Deobfuscate animation.cc
2025-05-10 17:42:42 -07:00
sherief 54a3b0c05c Merge pull request #111 from fallout2-ce/sherief-fix-ai-reload
Fixed AI loading single-rounds in magazines (duplicate with preview)
2025-05-10 13:11:21 -07:00
Sherief Farouk 0873eaab37 Fix for #76 (occasional crash when using skills on scenery objects). 2025-05-10 12:48:27 -07:00
Mike Klaas dff92e56fc Rename AnimationSequence.field_0 -> step 2025-05-10 12:31:28 -07:00
Mike Klaas 34748a2894 Deobfuscate animation.cc
Almost entirely renaming three struct fields of "AnimationSad" (an in-progress movement) and adding constants.

As usual, there are zero functional changes in this PR.
2025-05-10 00:02:03 -07:00
Vasilii Rogin 39160992ef Merge pull request #77 from sherief/asan-builds
Added CMake option for Address Sanitizer builds.
2025-05-10 09:27:24 +03:00
Vasilii Rogin eaa53b3e8e Merge pull request #108 from fallout2-ce/tmp_fix_web_ui_hash_until_fixed
Temp workaround: add commit hash for web interface
2025-05-09 18:39:43 +03:00
Vasilii Rogin 39bcb9875d Fix action parameter name 2025-05-09 18:33:30 +03:00
Vasilii Rogin 9097c2e76d Add commit hash to fix web builds until web ui is fixed 2025-05-09 18:28:49 +03:00
Vasilii Rogin 50db3587e4 Merge pull request #107 from mikeklaas/deobfus-action
Deobfucate action.h,cc
2025-05-09 17:49:50 +03:00
Mike Klaas 9e5a440895 typo 2025-05-08 22:52:12 -07:00
Mike Klaas 61ca374c03 Deobfuscate function parameters in action.{h,cc}
Zero functional changes were made.  This PR renames function parameters only
2025-05-08 22:49:15 -07:00
Vasilii Rogin 8f2b3a10dd Merge pull request #104 from fallout2-ce/IronKing24-code-decryption
Update tile.cc (duplicate)
2025-05-05 21:29:36 +03:00
Vasilii Rogin bbc4f44845 Merge pull request #99 from fallout2-ce/roginvs-use-webinterface-from-organization
Use web interface from organization
2025-05-05 20:30:32 +03:00
Vasilii Rogin 5367eba4f2 Add export 2025-05-05 20:12:34 +03:00
Vasilii Rogin 2d617883d3 Provide env as yml option 2025-05-05 20:07:30 +03:00
Vasilii Rogin 34f666fe55 Empty to trigger re-build 2025-05-05 20:03:26 +03:00
Vasilii Rogin 5ae46be317 Add debug info 2025-05-05 19:44:35 +03:00
Vasilii Rogin a4f9d7b940 Use env variables for debug info 2025-05-05 19:36:04 +03:00
Vasilii Rogin 251656e15b Merge pull request #102 from fallout2-ce/cambragol-patch-12-with-pipboy-text
Update loadsave with pipboy texts
2025-05-05 18:00:15 +03:00
Vasilii Rogin e1a8dc7adc Remove delay_ms 2025-05-05 17:55:06 +03:00
Vasilii Rogin ca029b3412 Merge pull request #103 from mikeklaas/deobfus-1
Deobfuscate several function parameters in art, game, game_mouse, reaction
2025-05-05 17:52:19 +03:00
Vasilii Rogin 70c3035cde Merge branch 'main' into cambragol-patch-12-with-pipboy-text 2025-05-05 07:53:08 +03:00
Mike Klaas 57b6b0caed Deobfuscate several function parameters
Some were already deobfuscated in the .c and I copied over to .h.  Others are new.

There are no semantic changes here.  Variable renames only
2025-05-04 16:21:04 -07:00
Vasilii Rogin 37ec7b1874 Merge pull request #98 from fallout2-ce/cambragol-patch-12
Update loadsave.cc (duplicate)
2025-05-05 01:58:27 +03:00
Vasilii Rogin 2395a6da3f Fix formatting 2025-05-04 20:34:02 +03:00
Vasilii Rogin 7338c2f428 Fix pipboy messages memory leak 2025-05-04 20:25:05 +03:00
Vasilii Rogin 2e2655ee1a Fix formatting 2025-05-04 20:09:31 +03:00
Vasilii Rogin 43c633bb89 Use messages from pipboy 2025-05-04 20:08:27 +03:00
Vasilii Rogin d5b4486d6e Revert back to pipboy text 2025-05-04 20:02:47 +03:00
Vasilii Rogin 590b832ba7 Use static texts, add comment 2025-05-04 20:00:42 +03:00
Vasilii Rogin cc7d9ed866 Revert "Use messages from pipboy"
This reverts commit 2f40ce663c.
2025-05-04 19:59:56 +03:00
Vasilii Rogin 8ad2cb7e2e Revert "Fix dependency"
This reverts commit e638c4cf0d.
2025-05-04 19:59:52 +03:00
Vasilii Rogin e638c4cf0d Fix dependency 2025-05-04 19:39:01 +03:00
Vasilii Rogin 2f40ce663c Use messages from pipboy 2025-05-04 19:36:24 +03:00
Vasilii Rogin 7b1a99a706 Merge remote-tracking branch 'fallout2-ce/main' into cambragol-patch-12 2025-05-04 19:27:50 +03:00
Vasilii Rogin 398c7adb9a Do not use designated initializers 2025-05-04 19:27:33 +03:00
Vasilii Rogin 424f2ffecc Use texts from proto 2025-05-04 19:21:51 +03:00
Vasilii Rogin d4c4022f55 Use color variables 2025-05-04 19:17:01 +03:00
Vasilii Rogin 1d0212ef5a Rename variables, use pages as config option 2025-05-04 19:11:51 +03:00
Vasilii Rogin c7417bb7e5 Merge pull request #101 from fallout2-ce/do_not_check_labels_if_it_is_main_push
Do not check PR labels if it is not a pull request
2025-05-04 19:06:58 +03:00
Vasilii Rogin 4d05fc1c4a Do not read PR labels if it is not a PR 2025-05-04 18:57:13 +03:00
Vasilii Rogin aa70a28509 Merge pull request #100 from roginvs/show_formatting_warnings_if_label_is_present
Show formatting warnings if label is present but do not raise error
2025-05-04 18:44:42 +03:00
Vasilii Rogin 49471a6154 Show formatting warnings if label is present but do not raise error 2025-05-04 17:50:02 +03:00
Vasilii Rogin 1b65466d44 Use web interface from organization 2025-05-04 16:44:21 +03:00
Vasilii Rogin aed6c37c67 Merge remote-tracking branch 'fallout2-ce/main' into cambragol-patch-12 2025-05-04 15:48:21 +03:00
Vasilii Rogin 1d48fb35b2 Merge pull request #97 from fallout2-ce/add_preview_builds
Add preview builds (from this repo branch)
2025-05-04 15:35:28 +03:00
Vasilii Rogin 1d4171727b Empty 2025-05-04 14:58:19 +03:00
Vasilii Rogin af046127e9 Add forgotten permission for auto-remove of previews 2025-05-04 14:48:41 +03:00
Vasilii Rogin 5a2c429956 Add hash info into auto comment 2025-05-04 14:47:25 +03:00
Vasilii Rogin ff5fa993f2 Add sudo for rsync 2025-05-04 14:39:38 +03:00
Vasilii Rogin 5a0507200b fix emsdk setup 2025-05-04 14:36:05 +03:00
Vasilii Rogin 54442f0cfe Install emsdk as step 2025-05-04 14:32:37 +03:00
Vasilii Rogin ae9912b7ea Add github hash 2025-05-04 14:09:03 +03:00
Vasilii Rogin f6da491246 Add gh cli 2025-05-04 14:02:06 +03:00
Vasilii Rogin 5fa6ec679d Do not make preview build if PR is from fork 2025-05-04 13:55:32 +03:00
Vasilii Rogin d029bf3cd0 Revert rsync step 2025-05-03 19:05:29 +03:00
Vasilii Rogin f81e1f7ba7 Use previous action for pushing to gh-pages 2025-05-03 19:04:14 +03:00
Vasilii Rogin f672ba4ddf Log GITHUB_OUTPUT for debugging 2025-05-03 18:57:15 +03:00
Vasilii Rogin 14cd1844d0 Add remove PR job 2025-05-03 18:53:04 +03:00
Vasilii Rogin 2b8f18ff0c Add github preview builds 2025-05-03 18:52:15 +03:00
Vasilii Rogin 07b52e0b76 Merge pull request #54 from cambragol/patch-14
Update loadsave.cc to fit longer location names in Infobox
2025-04-29 19:43:47 +03:00
cambragol c79696326d Update loadsave.cc
missed other x value
2025-04-29 09:15:00 +09:00
cambragol 132626912a Update loadsave.cc
should fix the artifacts
2025-04-29 02:26:09 +09:00
Vasilii Rogin 3163319290 Revert "Set MSVC_RUNTIME_LIBRARY in the makefile"
This reverts commit 2e8a65593e.
2025-04-27 18:25:15 +03:00
Vasilii Rogin 252d2ef263 Bump required cmake version 2025-04-27 18:20:39 +03:00
Vasilii Rogin ef09142375 Revert "Use cache string force"
This reverts commit a4ba0240f1.
2025-04-27 18:19:35 +03:00
Vasilii Rogin a4ba0240f1 Use cache string force 2025-04-27 18:13:14 +03:00
Vasilii Rogin 2e8a65593e Set MSVC_RUNTIME_LIBRARY in the makefile 2025-04-27 18:05:42 +03:00
Vasilii Rogin f35d1efab2 Revert "Set MSVC_RUNTIME_LIBRARY in the makefile"
This reverts commit 42a6a16f73.
2025-04-27 18:03:17 +03:00
Vasilii Rogin 42a6a16f73 Set MSVC_RUNTIME_LIBRARY in the makefile 2025-04-27 17:58:12 +03:00
Vasilii Rogin 85389ef2f3 Linking stdlib statically 2025-04-27 14:45:05 +03:00
Vasilii Rogin f7c1ccfada Merge pull request #81 from roginvs/add_label_to_ignore_clang_format_check
Add label to ignore clang format check
2025-04-27 09:24:00 +03:00
Sherief Farouk 767ae9af25 Fixed crash when running out of ammo before clip is full. 2025-04-26 05:36:03 -07:00
Vasilii Rogin 0ba670f0f7 Add debug message when everything is ok 2025-04-25 21:39:26 +03:00
Vasilii Rogin 58fdf2ff9e Empty commit 2025-04-25 21:38:26 +03:00
Vasilii Rogin cb1d2d6ed3 Exit step if label is found 2025-04-25 21:36:57 +03:00
Vasilii Rogin 4ce09d8cdb Debugging 2025-04-25 21:33:34 +03:00
Vasilii Rogin 787fa1b1b1 Show labels for debug 2025-04-25 21:32:09 +03:00
Vasilii Rogin 3d4fcf23ba Check labels before checkout 2025-04-25 21:31:17 +03:00
Vasilii Rogin 74c2125606 Fix env 2025-04-25 21:29:00 +03:00
Vasilii Rogin b1df5a084c Add token 2025-04-25 21:25:31 +03:00
Vasilii Rogin 2a610cf479 Skip code formatting check if skip-formatting label is present 2025-04-25 21:20:37 +03:00
Vasilii Rogin 7d093030e7 Fix find filtering 2025-04-25 21:17:27 +03:00
Sherief Farouk 01be11fce5 Added CMake option for Address Sanitizer builds. 2025-04-25 04:11:46 -07:00
Sherief Farouk 12fe582e6f Fixed AI loading single-rounds in magazines.
IIRC, the "unit" for things like 10mm ammo in F1 used to be a dozen (12x).
In F2CE, the unit of ammo seems to be a single round. Prior to this patch,
AI companions (in my case, the Mercenary in Sonora) would reload a single
round into their weapon when they run out, so turns in combat become a loop
of fire, reload, fire, reload, etc.

With this patch, AI reloading keeps inserting ammo into the weapon until
capacity is reached or the critter runs out of ammo.
2025-04-22 00:35:30 -07:00
cambragol bdb4feedf9 Update loadsave.cc
Clang formatting.
2025-04-21 20:43:54 +09:00
cambragol 5e93479192 Update pipboy.cc
Clang formatting?
2025-04-21 20:39:11 +09:00
cambragol 503695cd4d Update loadsave.cc
Restored the emscripten and touchscreen stuff.
2025-04-21 07:14:42 +09:00
cambragol cc6d803517 Update loadsave.cc
Small fix to Load/Save descriptions in the info box.

Allows for longer names, and wraps them to second line if they are too long.
2025-04-20 19:19:08 +09:00
cambragol 4dfc7538db Update loadsave.cc
Increases Load/Save slots to 100 - sFall?

Adds pagination and controls to move between slots - previous scrolling/key functions work as normal, and move between pages

No ini setting yet, code it set up to shift based off a single ini setting.
2025-04-20 18:48:58 +09:00
cambragol afeec298bf Update pipboy.cc for full pagination
Adds full pagination to Status, Data and Automaps main and sub pages to prevent overflow.
2025-04-20 18:37:52 +09:00
IronKing24 8ad0067510 2025-02-09 12:51:11 +03:00
IronKing24 894d9aab52 code formatting 2025-02-09 12:47:46 +03:00
IronKing24 043b43d04b Merge branch 'fallout2-ce:main' into code-decryption 2025-02-09 12:24:28 +03:00
MADMAN7 144b3beb79 remove side effects from the conditionals 2024-06-24 11:21:31 +03:00
MADMAN7 30bbb3702a Update tile.cc
decrypt tileFromScreenXY based on code from SFall HRP
2024-06-17 17:05:59 +03:00
32 changed files with 1655 additions and 890 deletions
+31
View File
@@ -0,0 +1,31 @@
### Description
<!--- Clearly describe the changes introduced by this PR. What was fixed, added, or updated? --->
### Reproduction Steps and Savefile (if available)
<!--- Provide detailed steps to reproduce the issue. Include a savefile if applicable, preferrably for Sonora --->
### Screenshots
<!--- If the PR includes visual changes, add screenshots here. --->
<!---
**Important Notes**
- *Preview builds are not available for pull requests from forked repositories.* To enable preview builds, submit the PR from a branch within this repository.
- *Formatting issues? You have two options:*
1. **Fix formatting automatically** using the following Docker command: *(If you're using Windows, remove `--user $(id -u):$(id -g)`)*
```bash
docker run --rm \
-v $(pwd):/app --workdir /app \
--user $(id -u):$(id -g) silkeh/clang:18 \
bash -c 'find src -type f -name \*.cc -o -name \*.h | xargs clang-format -i'
```
2. **Skip formatting check** by adding the `skip-formatting` label to this PR.
--->
+47 -10
View File
@@ -12,14 +12,21 @@ jobs:
build_webassembly_version:
name: Build webassembly version
runs-on: ubuntu-latest
container: emscripten/emsdk:4.0.4
permissions: write-all
steps:
- name: Clone
uses: actions/checkout@v4
- name: Install Emscripten SDK
run: |
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install 4.0.4
./emsdk activate 4.0.4
- name: Build fallout2 wasm module
run: |
source emsdk/emsdk_env.sh
git config --global --add safe.directory "*"
mkdir -p build
cd build
@@ -27,36 +34,66 @@ jobs:
cd ..
- name: Add node
if: github.ref == 'refs/heads/main'
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
uses: actions/setup-node@v2
with:
node-version: '22'
- name: Checkout web interface
if: github.ref == 'refs/heads/main'
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
uses: actions/checkout@v4
with:
repository: ololoken/fallout2-ce-ems
ref: 46ac3be3da9d01ef204779073b1c1254fa037021
repository: fallout2-ce/fallout2-ce-ems
ref: 8dc61ba6e8e62116f4810ffe89d0cece00f508d7
path: fallout2-ce-ems
- name: Set deployment path
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
id: set-path
run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
echo "DEST_DIR=PR-${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT
echo "SITE_BASE=/fallout2-ce/PR-${{ github.event.pull_request.number }}/" >> $GITHUB_OUTPUT
else
echo "DEST_DIR=." >> $GITHUB_OUTPUT
echo "SITE_BASE=/fallout2-ce/" >> $GITHUB_OUTPUT
fi
echo ===============================
cat $GITHUB_OUTPUT
- name: Build web interface
if: github.ref == 'refs/heads/main'
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
run: |
cd fallout2-ce-ems
npm install
cp ../build/fallout2-ce.js src/assets/fallout2ce
cp ../build/fallout2-ce.wasm src/assets/fallout2ce
sed -i 's/\/fallout2-ce-ems/\/fallout2-ce/' vite.config.ts
export F2_WEB_INFO=Web=$(git rev-parse HEAD)
echo "F2_WEB_INFO=$F2_WEB_INFO"
echo "F2_GAME_VERSION=$F2_GAME_VERSION"
npm run build
env:
SITE_BASE: ${{ steps.set-path.outputs.SITE_BASE }}
F2_GAME_VERSION: Game=${{github.event.pull_request.head.sha || github.sha }}
- name: Install rsync (required for the next step)
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
run: |
apt-get update && apt-get install -y rsync
sudo apt-get update && sudo apt-get install -y rsync
- name: Deploy to gh-pages
- name: Deploy PR preview or main site
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
uses: JamesIves/github-pages-deploy-action@v4
if: github.ref == 'refs/heads/main'
with:
branch: gh-pages
folder: fallout2-ce-ems/dist
target-folder: ${{ steps.set-path.outputs.DEST_DIR }}
clean: false
- name: Comment preview URL on PR
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
run: |
gh pr comment ${{ github.event.pull_request.number }} \
--body "🚀 WebAssembly PR Preview for ${{github.event.pull_request.head.sha || github.sha }} is available at: https://${{ github.repository_owner }}.github.io/fallout2-ce/PR-${{ github.event.pull_request.number }}/"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+21 -1
View File
@@ -45,7 +45,27 @@ jobs:
clang-format --version
- name: clang-format
run: find src -type f -name \*.cc -o -name \*.h | xargs clang-format --dry-run --Werror
run: |
if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then
echo "Showing PR labels..."
gh pr view ${{ github.event.pull_request.number }} --repo "${{ github.repository }}" --json labels
echo "Checking labels on PR..."
if gh pr view ${{ github.event.pull_request.number }} --repo "${{ github.repository }}" --json labels --jq '.labels[].name' | grep -q "skip-formatting"; then
echo "skip-formatting label found - do not raise error"
echo "==============================="
find src -type f \( -name \*.cc -o -name \*.h \) | xargs clang-format --dry-run
exit 0
fi
echo "skip-formatting label not found - raise error if formatting is not correct"
else
echo "Not a PR, do not check labels"
fi
find src -type f \( -name \*.cc -o -name \*.h \) | xargs clang-format --dry-run --Werror
echo "Code is formatted correctly"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
android:
name: Android
@@ -0,0 +1,33 @@
name: Cleanup PR Preview
on:
pull_request:
types:
- closed
jobs:
delete_pr_preview:
name: Delete PR preview from gh-pages
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout gh-pages branch
uses: actions/checkout@v4
with:
ref: gh-pages
token: ${{ secrets.GITHUB_TOKEN }}
- name: Remove PR preview folder
run: |
PR_FOLDER="PR-${{ github.event.pull_request.number }}"
echo "Removing preview folder: $PR_FOLDER"
git rm -r --ignore-unmatch "$PR_FOLDER" || true
- name: Commit and push changes
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git commit -am "đźš® Remove preview for closed PR #${{ github.event.pull_request.number }}"
git push
+55 -1
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.13)
cmake_minimum_required(VERSION 3.18)
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
@@ -305,12 +305,14 @@ if(WIN32)
_CRT_NONSTDC_NO_WARNINGS
NOMINMAX
WIN32_LEAN_AND_MEAN
_STATIC_CPPLIB
)
endif()
if(WIN32)
target_link_libraries(${EXECUTABLE_NAME}
winmm
libcpmt
)
endif()
@@ -447,3 +449,55 @@ if(APPLE)
include(CPack)
endif()
# Add option to enable AddressSanitizer
option(ENABLE_ASAN "Enable AddressSanitizer for debug builds" OFF)
# Set C++ standard and other existing settings
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_EXTENSIONS NO)
# Define ASan flags for supported compilers (GCC, Clang, MSVC)
if(ENABLE_ASAN)
if(CMAKE_SYSTEM_NAME MATCHES "Emscripten|Android|iOS")
message(WARNING "AddressSanitizer is not supported on ${CMAKE_SYSTEM_NAME}. Disabling ASan.")
set(ENABLE_ASAN OFF)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
message(STATUS "Enabling AddressSanitizer for debug build (GCC/Clang)")
set(ASAN_FLAGS "-fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${ASAN_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${ASAN_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${ASAN_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${ASAN_FLAGS}")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
# Check if using clang-cl or native MSVC
if(CMAKE_CXX_COMPILER MATCHES "clang-cl")
message(STATUS "Enabling AddressSanitizer for debug build (clang-cl)")
set(ASAN_FLAGS "-fsanitize=address -fno-omit-frame-pointer")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${ASAN_FLAGS}")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${ASAN_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fsanitize=address")
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=address")
else()
message(STATUS "Enabling AddressSanitizer for debug build (MSVC)")
set(ASAN_FLAGS "/fsanitize=address")
# MSVC requires /Zi or /Z7 for debug info with ASan
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${ASAN_FLAGS} /Zi")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${ASAN_FLAGS} /Zi")
# No additional linker flags needed for MSVC ASan
# Disable incremental linking as it's incompatible with ASan
string(REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG}")
string(REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}")
endif()
else()
message(WARNING "AddressSanitizer is not supported with ${CMAKE_CXX_COMPILER_ID}. Disabling ASan.")
set(ENABLE_ASAN OFF)
endif()
endif()
# Existing debug flags for Emscripten (ensure ASan doesn't conflict)
if(CMAKE_SYSTEM_NAME MATCHES "Emscripten")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g")
endif()
+1 -1
View File
@@ -33,7 +33,7 @@
"cacheVariables": {
"CMAKE_GENERATOR_TOOLSET": "v141_xp",
"CMAKE_C_FLAGS": "/D_WIN32_WINNT=0x0501",
"CMAKE_CXX_FLAGS": "/D_WIN32_WINNT=0x0501",
"CMAKE_CXX_FLAGS": "/D_WIN32_WINNT=0x0501 /D_STATIC_CPPLIB",
"CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded$<$<CONFIG:Debug>:Debug>"
}
},
+13 -6
View File
@@ -1,14 +1,14 @@
# Fallout 2 Community Edition
Fallout 2 Community Edition is a fully working re-implementation of Fallout 2, with the same original gameplay, engine bugfixes, and some quality of life improvements, that works (mostly) hassle-free on multiple platforms.
Fallout 2 Community Edition is a fully working re-implementation of Fallout 2, with the same original gameplay, engine bugfixes, and some quality of life improvements, that works (mostly) hassle-free on multiple platforms. This is a fork of the original project, which isn't getting regular updates.
Popular Fallout 2 total conversion mods are partially supported. Original versions of Nevada and Sonora (that do not rely on extended features provided by Sfall) likely work, although there is no complete walkthrough confirmation yet. [Fallout 2 Restoration Project](https://github.com/BGforgeNet/Fallout2_Restoration_Project), [Fallout Et Tu](https://github.com/rotators/Fo1in2) and [Olympus 2207](https://olympus2207.com) are not yet supported. Other mods (particularly Resurrection and Yesterday) are not tested.
Popular Fallout 2 total conversion mods are partially supported. Original versions of Nevada and Sonora (that do not rely on extended features provided by Sfall) work. [Fallout 2 Restoration Project](https://github.com/BGforgeNet/Fallout2_Restoration_Project), [Fallout Et Tu](https://github.com/rotators/Fo1in2) and [Olympus 2207](https://olympus2207.com) are not yet supported. Other mods (particularly Resurrection and Yesterday) are not tested.
There is also [Fallout Community Edition](https://github.com/alexbatalov/fallout1-ce).
There is also [Fallout Community Edition](https://github.com/alexbatalov/fallout1-ce) (not affiliated with this fork).
## Installation
You must own the game to play. Purchase your copy on [GOG](https://www.gog.com/game/fallout_2), [Epic Games](https://store.epicgames.com/p/fallout-2) or [Steam](https://store.steampowered.com/app/38410). Download latest [release](https://github.com/alexbatalov/fallout2-ce/releases) or build from source. You can also check latest [debug](https://github.com/alexbatalov/fallout2-ce/actions) build intended for testers.
You must own the game to play. Purchase your copy on [GOG](https://www.gog.com/game/fallout_2), [Epic Games](https://store.epicgames.com/p/fallout-2) or [Steam](https://store.steampowered.com/app/38410). Download latest [release](https://github.com/fallout2-ce/fallout2-ce/releases) or build from source.
### Windows
@@ -102,7 +102,11 @@ The second configuration file is `f2_res.ini`. Use it to change game window size
[MAIN]
SCR_WIDTH=1280
SCR_HEIGHT=720
WINDOWED=1
WINDOWED=1 ; 0 = fullscreen
SCALE_2X=1 ; 0 = original scale, 1 = 2x
[IFACE]
IFACE_BAR_MODE, IFACE_BAR_SIDE_ART, IFACE_BAR_SIDES_ORI, IFACE_BAR_WIDTH supported (require assets in appropriate places)
```
Recommendations:
@@ -112,7 +116,10 @@ Recommendations:
In time this stuff will receive in-game interface, right now you have to do it manually.
The third configuration file is `ddraw.ini` (part of Sfall). There are dozens of options that adjust or override engine behaviour and gameplay mechanics. This file is intended for modders and advanced users. Currently only a small subset of these settings are actually implemented.
The third configuration file is `ddraw.ini` (part of Sfall). There are dozens of options that adjust or override engine behaviour and gameplay mechanics. This file is intended for modders and advanced users. Currently only a small subset of these settings are actually implemented. For high res configs, the following is recommended:
```[Main]
HiResMode=1
```
## Contributing
+95 -93
View File
@@ -73,30 +73,32 @@ static const int gMaximumBloodDeathAnimations[DAMAGE_TYPE_COUNT] = {
ANIM_EXPLODED_TO_NOTHING,
};
// Note: some of these are callbacks that always take two Object*, but may not use them.
// Ignored parameters are marked with underscores.
static int actionKnockdown(Object* obj, int* anim, int maxDistance, int rotation, int delay);
static int _action_blood(Object* obj, int anim, int delay);
static int _pick_death(Object* attacker, Object* defender, Object* weapon, int damage, int attackerAnimation, bool hitFromFront);
static int _check_death(Object* obj, int anim, int minViolenceLevel, bool hitFromFront);
static int _internal_destroy(Object* a1, Object* a2);
static int _internal_destroy(Object* _, Object* toDestroy);
static void _show_damage_to_object(Object* defender, int damage, int flags, Object* weapon, bool hitFromFront, int knockbackDistance, int knockbackRotation, int attackerAnimation, Object* attacker, int delay);
static int _show_death(Object* obj, int anim);
static int _show_damage_extras(Attack* attack);
static void _show_damage(Attack* attack, int attackerAnimation, int delay);
static int _action_melee(Attack* attack, int a2);
static int _action_ranged(Attack* attack, int a2);
static int _is_next_to(Object* a1, Object* a2);
static int _action_climb_ladder(Object* a1, Object* a2);
static int _action_melee(Attack* attack, int anim);
static int _action_ranged(Attack* attack, int anim);
static int _is_next_to(Object* obj1, Object* obj2);
static int _action_climb_ladder(Object* critter, Object* ladder);
static int _action_use_skill_in_combat_error(Object* critter);
static int _pick_fall(Object* obj, int anim);
static int _report_explosion(Attack* attack, Object* sourceObj);
static int _finished_explosion(Object* a1, Object* a2);
static int _finished_explosion(Object*, Object*);
static int _compute_explosion_damage(int min, int max, Object* defender, int* knockbackDistancePtr);
static int _can_talk_to(Object* a1, Object* a2);
static int _talk_to(Object* a1, Object* a2);
static int _report_dmg(Attack* attack, Object* a2);
static int _can_talk_to(Object* obj, Object* critter);
static int _talk_to(Object* _, Object* critter);
static int _report_dmg(Attack* attack, Object* _);
static int _compute_dmg_damage(int min, int max, Object* obj, int* knockbackDistancePtr, int damageType);
static int hideProjectile(void* a1, void* a2);
static int hideProjectile(void* _, void* projectile);
// 0x410468
int actionKnockdown(Object* obj, int* anim, int maxDistance, int rotation, int delay)
@@ -281,9 +283,9 @@ int _check_death(Object* obj, int anim, int minViolenceLevel, bool hitFromFront)
}
// 0x4108C8
int _internal_destroy(Object* a1, Object* a2)
int _internal_destroy(Object* _, Object* toDestroy)
{
return _obj_destroy(a2);
return _obj_destroy(toDestroy);
}
// TODO: Check very carefully, lots of conditions and jumps.
@@ -985,10 +987,10 @@ int _action_ranged(Attack* attack, int anim)
}
// 0x411D68
int _is_next_to(Object* a1, Object* a2)
int _is_next_to(Object* obj1, Object* obj2)
{
if (objectGetDistanceBetween(a1, a2) > 1) {
if (a2 == gDude) {
if (objectGetDistanceBetween(obj1, obj2) > 1) {
if (obj2 == gDude) {
MessageListItem messageListItem;
// You cannot get there.
messageListItem.num = 2000;
@@ -1003,9 +1005,9 @@ int _is_next_to(Object* a1, Object* a2)
}
// 0x411DB4
int _action_climb_ladder(Object* a1, Object* a2)
int _action_climb_ladder(Object* critter, Object* ladder)
{
if (a1 == gDude) {
if (critter == gDude) {
int anim = FID_ANIM_TYPE(gDude->fid);
if (anim == ANIM_WALK || anim == ANIM_RUNNING) {
reg_anim_clear(gDude);
@@ -1016,46 +1018,46 @@ int _action_climb_ladder(Object* a1, Object* a2)
int actionPoints;
if (isInCombat()) {
animationRequestOptions = ANIMATION_REQUEST_RESERVED;
actionPoints = a1->data.critter.combat.ap;
actionPoints = critter->data.critter.combat.ap;
} else {
animationRequestOptions = ANIMATION_REQUEST_UNRESERVED;
actionPoints = -1;
}
if (a1 == gDude) {
if (critter == gDude) {
animationRequestOptions = ANIMATION_REQUEST_RESERVED;
}
animationRequestOptions |= ANIMATION_REQUEST_NO_STAND;
reg_anim_begin(animationRequestOptions);
int tile = tileGetTileInDirection(a2->tile, ROTATION_SE, 1);
int tile = tileGetTileInDirection(ladder->tile, ROTATION_SE, 1);
int walkDistance = 5;
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_USE_WALK_DISTANCE, &walkDistance);
if (actionPoints != -1 || objectGetDistanceBetween(a1, a2) < walkDistance) {
animationRegisterMoveToTile(a1, tile, a2->elevation, actionPoints, 0);
if (actionPoints != -1 || objectGetDistanceBetween(critter, ladder) < walkDistance) {
animationRegisterMoveToTile(critter, tile, ladder->elevation, actionPoints, 0);
} else {
animationRegisterRunToTile(a1, tile, a2->elevation, actionPoints, 0);
animationRegisterRunToTile(critter, tile, ladder->elevation, actionPoints, 0);
}
animationRegisterCallbackForced(a1, a2, (AnimationCallback*)_is_next_to, -1);
animationRegisterRotateToTile(a1, a2->tile);
animationRegisterCallbackForced(a1, a2, (AnimationCallback*)_check_scenery_ap_cost, -1);
animationRegisterCallbackForced(critter, ladder, (AnimationCallback*)_is_next_to, -1);
animationRegisterRotateToTile(critter, ladder->tile);
animationRegisterCallbackForced(critter, ladder, (AnimationCallback*)_check_scenery_ap_cost, -1);
int weaponAnimationCode = (a1->fid & 0xF000) >> 12;
int weaponAnimationCode = (critter->fid & 0xF000) >> 12;
if (weaponAnimationCode != 0) {
const char* puttingAwaySfx = sfxBuildCharName(a1, ANIM_PUT_AWAY, CHARACTER_SOUND_EFFECT_UNUSED);
animationRegisterPlaySoundEffect(a1, puttingAwaySfx, -1);
animationRegisterAnimate(a1, ANIM_PUT_AWAY, 0);
const char* puttingAwaySfx = sfxBuildCharName(critter, ANIM_PUT_AWAY, CHARACTER_SOUND_EFFECT_UNUSED);
animationRegisterPlaySoundEffect(critter, puttingAwaySfx, -1);
animationRegisterAnimate(critter, ANIM_PUT_AWAY, 0);
}
const char* climbingSfx = sfxBuildCharName(a1, ANIM_CLIMB_LADDER, CHARACTER_SOUND_EFFECT_UNUSED);
animationRegisterPlaySoundEffect(a1, climbingSfx, -1);
animationRegisterAnimate(a1, ANIM_CLIMB_LADDER, 0);
animationRegisterCallback(a1, a2, (AnimationCallback*)_obj_use, -1);
const char* climbingSfx = sfxBuildCharName(critter, ANIM_CLIMB_LADDER, CHARACTER_SOUND_EFFECT_UNUSED);
animationRegisterPlaySoundEffect(critter, climbingSfx, -1);
animationRegisterAnimate(critter, ANIM_CLIMB_LADDER, 0);
animationRegisterCallback(critter, ladder, (AnimationCallback*)_obj_use, -1);
if (weaponAnimationCode != 0) {
animationRegisterTakeOutWeapon(a1, weaponAnimationCode, -1);
animationRegisterTakeOutWeapon(critter, weaponAnimationCode, -1);
}
return reg_anim_end();
@@ -1522,9 +1524,9 @@ int actionUseSkill(Object* user, Object* target, int skill)
}
// 0x412BC4
bool _is_hit_from_front(Object* a1, Object* a2)
bool _is_hit_from_front(Object* attacker, Object* defender)
{
int diff = a1->rotation - a2->rotation;
int diff = attacker->rotation - defender->rotation;
if (diff < 0) {
diff = -diff;
}
@@ -1533,11 +1535,11 @@ bool _is_hit_from_front(Object* a1, Object* a2)
}
// 0x412BEC
bool _can_see(Object* a1, Object* a2)
bool _can_see(Object* source, Object* target)
{
int diff;
diff = a1->rotation - tileGetRotationTo(a1->tile, a2->tile);
diff = source->rotation - tileGetRotationTo(source->tile, target->tile);
if (diff < 0) {
diff = -diff;
}
@@ -1813,7 +1815,7 @@ int _report_explosion(Attack* attack, Object* sourceObj)
}
// 0x4132C0
int _finished_explosion(Object* a1, Object* a2)
int _finished_explosion(Object* _, Object* __)
{
_action_in_explode = false;
return 0;
@@ -1842,13 +1844,13 @@ int _compute_explosion_damage(int min, int max, Object* defender, int* knockback
}
// 0x413330
int actionTalk(Object* a1, Object* a2)
int actionTalk(Object* obj, Object* critter)
{
if (a1 != gDude) {
if (obj != gDude) {
return -1;
}
if (FID_TYPE(a2->fid) != OBJ_TYPE_CRITTER) {
if (FID_TYPE(critter->fid) != OBJ_TYPE_CRITTER) {
return -1;
}
@@ -1859,25 +1861,25 @@ int actionTalk(Object* a1, Object* a2)
if (isInCombat()) {
reg_anim_begin(ANIMATION_REQUEST_RESERVED);
animationRegisterMoveToObject(a1, a2, a1->data.critter.combat.ap, 0);
animationRegisterMoveToObject(obj, critter, obj->data.critter.combat.ap, 0);
} else {
reg_anim_begin(a1 == gDude ? ANIMATION_REQUEST_RESERVED : ANIMATION_REQUEST_UNRESERVED);
reg_anim_begin(obj == gDude ? ANIMATION_REQUEST_RESERVED : ANIMATION_REQUEST_UNRESERVED);
if (objectGetDistanceBetween(a1, a2) >= 9 || _combat_is_shot_blocked(a1, a1->tile, a2->tile, a2, nullptr)) {
animationRegisterRunToObject(a1, a2, -1, 0);
if (objectGetDistanceBetween(obj, critter) >= 9 || _combat_is_shot_blocked(obj, obj->tile, critter->tile, critter, nullptr)) {
animationRegisterRunToObject(obj, critter, -1, 0);
}
}
animationRegisterCallbackForced(a1, a2, (AnimationCallback*)_can_talk_to, -1);
animationRegisterCallback(a1, a2, (AnimationCallback*)_talk_to, -1);
animationRegisterCallbackForced(obj, critter, (AnimationCallback*)_can_talk_to, -1);
animationRegisterCallback(obj, critter, (AnimationCallback*)_talk_to, -1);
return reg_anim_end();
}
// 0x413420
int _can_talk_to(Object* a1, Object* a2)
int _can_talk_to(Object* obj, Object* critter)
{
if (_combat_is_shot_blocked(a1, a1->tile, a2->tile, a2, nullptr) || objectGetDistanceBetween(a1, a2) >= 9) {
if (a1 == gDude) {
if (_combat_is_shot_blocked(obj, obj->tile, critter->tile, critter, nullptr) || objectGetDistanceBetween(obj, critter) >= 9) {
if (obj == gDude) {
// You cannot get there. (used in actions.c)
MessageListItem messageListItem;
messageListItem.num = 2000;
@@ -1893,9 +1895,9 @@ int _can_talk_to(Object* a1, Object* a2)
}
// 0x413488
int _talk_to(Object* a1, Object* a2)
int _talk_to(Object* _, Object* critter)
{
scriptsRequestDialog(a2);
scriptsRequestDialog(critter);
return 0;
}
@@ -1969,7 +1971,7 @@ void actionDamage(int tile, int elevation, int minDamage, int maxDamage, int dam
}
// 0x41363C
int _report_dmg(Attack* attack, Object* a2)
int _report_dmg(Attack* attack, Object* _)
{
_combat_display(attack);
_apply_damage(attack, false);
@@ -2006,42 +2008,42 @@ int _compute_dmg_damage(int min, int max, Object* obj, int* knockbackDistancePtr
}
// 0x4136EC
bool actionCheckPush(Object* a1, Object* a2)
bool actionCheckPush(Object* obj, Object* target)
{
// Cannot push anything but critters.
if (FID_TYPE(a2->fid) != OBJ_TYPE_CRITTER) {
if (FID_TYPE(target->fid) != OBJ_TYPE_CRITTER) {
return false;
}
// Cannot push itself.
if (a1 == a2) {
if (obj == target) {
return false;
}
// Cannot push inactive critters.
if (!critterIsActive(a2)) {
if (!critterIsActive(target)) {
return false;
}
if (_action_can_talk_to(a1, a2) != 0) {
if (_action_can_talk_to(obj, target) != 0) {
return false;
}
// Can only push critters that have push handler.
if (!scriptHasProc(a2->sid, SCRIPT_PROC_PUSH)) {
if (!scriptHasProc(target->sid, SCRIPT_PROC_PUSH)) {
return false;
}
if (isInCombat()) {
if (a2->data.critter.combat.team == a1->data.critter.combat.team
&& a2 == a1->data.critter.combat.whoHitMe) {
if (target->data.critter.combat.team == obj->data.critter.combat.team
&& target == obj->data.critter.combat.whoHitMe) {
return false;
}
// TODO: Check.
Object* whoHitMe = a2->data.critter.combat.whoHitMe;
Object* whoHitMe = target->data.critter.combat.whoHitMe;
if (whoHitMe != nullptr
&& whoHitMe->data.critter.combat.team == a1->data.critter.combat.team) {
&& whoHitMe->data.critter.combat.team == obj->data.critter.combat.team) {
return false;
}
}
@@ -2050,15 +2052,15 @@ bool actionCheckPush(Object* a1, Object* a2)
}
// 0x413790
int actionPush(Object* a1, Object* a2)
int actionPush(Object* obj, Object* target)
{
if (!actionCheckPush(a1, a2)) {
if (!actionCheckPush(obj, target)) {
return -1;
}
int sid;
if (_obj_sid(a2, &sid) == 0) {
scriptSetObjects(sid, a1, a2);
if (_obj_sid(target, &sid) == 0) {
scriptSetObjects(sid, obj, target);
scriptExecProc(sid, SCRIPT_PROC_PUSH);
bool scriptOverrides = false;
@@ -2073,36 +2075,36 @@ int actionPush(Object* a1, Object* a2)
}
}
int rotation = tileGetRotationTo(a1->tile, a2->tile);
int rotation = tileGetRotationTo(obj->tile, target->tile);
int tile;
do {
tile = tileGetTileInDirection(a2->tile, rotation, 1);
if (_obj_blocking_at(a2, tile, a2->elevation) == nullptr) {
tile = tileGetTileInDirection(target->tile, rotation, 1);
if (_obj_blocking_at(target, tile, target->elevation) == nullptr) {
break;
}
tile = tileGetTileInDirection(a2->tile, (rotation + 1) % ROTATION_COUNT, 1);
if (_obj_blocking_at(a2, tile, a2->elevation) == nullptr) {
tile = tileGetTileInDirection(target->tile, (rotation + 1) % ROTATION_COUNT, 1);
if (_obj_blocking_at(target, tile, target->elevation) == nullptr) {
break;
}
tile = tileGetTileInDirection(a2->tile, (rotation + 5) % ROTATION_COUNT, 1);
if (_obj_blocking_at(a2, tile, a2->elevation) == nullptr) {
tile = tileGetTileInDirection(target->tile, (rotation + 5) % ROTATION_COUNT, 1);
if (_obj_blocking_at(target, tile, target->elevation) == nullptr) {
break;
}
tile = tileGetTileInDirection(a2->tile, (rotation + 2) % ROTATION_COUNT, 1);
if (_obj_blocking_at(a2, tile, a2->elevation) == nullptr) {
tile = tileGetTileInDirection(target->tile, (rotation + 2) % ROTATION_COUNT, 1);
if (_obj_blocking_at(target, tile, target->elevation) == nullptr) {
break;
}
tile = tileGetTileInDirection(a2->tile, (rotation + 4) % ROTATION_COUNT, 1);
if (_obj_blocking_at(a2, tile, a2->elevation) == nullptr) {
tile = tileGetTileInDirection(target->tile, (rotation + 4) % ROTATION_COUNT, 1);
if (_obj_blocking_at(target, tile, target->elevation) == nullptr) {
break;
}
tile = tileGetTileInDirection(a2->tile, (rotation + 3) % ROTATION_COUNT, 1);
if (_obj_blocking_at(a2, tile, a2->elevation) == nullptr) {
tile = tileGetTileInDirection(target->tile, (rotation + 3) % ROTATION_COUNT, 1);
if (_obj_blocking_at(target, tile, target->elevation) == nullptr) {
break;
}
@@ -2111,14 +2113,14 @@ int actionPush(Object* a1, Object* a2)
int actionPoints;
if (isInCombat()) {
actionPoints = a2->data.critter.combat.ap;
actionPoints = target->data.critter.combat.ap;
} else {
actionPoints = -1;
}
reg_anim_begin(ANIMATION_REQUEST_RESERVED);
animationRegisterRotateToTile(a2, tile);
animationRegisterMoveToTile(a2, tile, a2->elevation, actionPoints, 0);
animationRegisterRotateToTile(target, tile);
animationRegisterMoveToTile(target, tile, target->elevation, actionPoints, 0);
return reg_anim_end();
}
@@ -2126,29 +2128,29 @@ int actionPush(Object* a1, Object* a2)
// Returns -2 if it's too far (> 12 tiles).
//
// 0x413970
int _action_can_talk_to(Object* a1, Object* a2)
int _action_can_talk_to(Object* obj, Object* target)
{
if (pathfinderFindPath(a1, a1->tile, a2->tile, nullptr, 0, _obj_sight_blocking_at) == 0) {
if (pathfinderFindPath(obj, obj->tile, target->tile, nullptr, 0, _obj_sight_blocking_at) == 0) {
return -1;
}
if (tileDistanceBetween(a1->tile, a2->tile) > 12) {
if (tileDistanceBetween(obj->tile, target->tile) > 12) {
return -2;
}
return 0;
}
static int hideProjectile(void* a1, void* a2)
static int hideProjectile(void* _, void* projectile)
{
Object* projectile = reinterpret_cast<Object*>(a2);
Object* proj = reinterpret_cast<Object*>(projectile);
Rect rect;
if (objectHide(projectile, &rect) == 0) {
tileWindowRefreshRect(&rect, projectile->elevation);
if (objectHide(proj, &rect) == 0) {
tileWindowRefreshRect(&rect, proj->elevation);
}
projectile->flags |= OBJECT_NO_SAVE;
proj->flags |= OBJECT_NO_SAVE;
return 0;
}
+5 -5
View File
@@ -16,14 +16,14 @@ int _action_loot_container(Object* critter, Object* container);
int _action_skill_use(int skill);
int actionUseSkill(Object* user, Object* target, int skill);
bool _is_hit_from_front(Object* attacker, Object* defender);
bool _can_see(Object* a1, Object* a2);
bool _can_see(Object* source, Object* target);
bool _action_explode_running();
int actionExplode(int tile, int elevation, int minDamage, int maxDamage, Object* sourceObj, bool animate);
int actionTalk(Object* a1, Object* a2);
int actionTalk(Object* obj, Object* critter);
void actionDamage(int tile, int elevation, int minDamage, int maxDamage, int damageType, bool animated, bool bypassArmor);
bool actionCheckPush(Object* a1, Object* a2);
int actionPush(Object* a1, Object* a2);
int _action_can_talk_to(Object* a1, Object* a2);
bool actionCheckPush(Object* obj, Object* target);
int actionPush(Object* obj, Object* target);
int _action_can_talk_to(Object* obj, Object* critter);
} // namespace fallout
+100 -88
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -31,8 +31,8 @@ typedef struct HeadDescription {
} HeadDescription;
static int artReadList(const char* path, char** out_arr, int* out_count);
static int artCacheGetFileSizeImpl(int a1, int* out_size);
static int artCacheReadDataImpl(int a1, int* a2, unsigned char* data);
static int artCacheGetFileSizeImpl(int fid, int* out_size);
static int artCacheReadDataImpl(int fid, int* sizePtr, unsigned char* data);
static void artCacheFreeImpl(void* ptr);
static int artReadFrameData(unsigned char* data, File* stream, int count, int* paddingPtr);
static int artReadHeader(Art* art, File* stream);
+5 -5
View File
@@ -129,9 +129,9 @@ unsigned char* artLockFrameData(int fid, int frame, int direction, CacheEntry**
unsigned char* artLockFrameDataReturningSize(int fid, CacheEntry** out_cache_entry, int* widthPtr, int* heightPtr);
int artUnlock(CacheEntry* cache_entry);
int artCacheFlush();
int artCopyFileName(int objectType, int a2, char* a3);
int _art_get_code(int a1, int a2, char* a3, char* a4);
char* artBuildFilePath(int a1);
int artCopyFileName(int objectType, int id, char* a3);
int _art_get_code(int animation, int weaponType, char* a3, char* a4);
char* artBuildFilePath(int fid);
int artGetFramesPerSecond(Art* art);
int artGetActionFrame(Art* art);
int artGetFrameCount(Art* art);
@@ -144,8 +144,8 @@ unsigned char* artGetFrameData(Art* art, int frame, int direction);
ArtFrame* artGetFrame(Art* art, int frame, int direction);
bool artExists(int fid);
bool _art_fid_valid(int fid);
int _art_alias_num(int a1);
int artCritterFidShouldRun(int a1);
int _art_alias_num(int index);
int artCritterFidShouldRun(int fid);
int artAliasFid(int fid);
int buildFid(int objectType, int frmId, int animType, int weaponCode, int rotation);
Art* artLoad(const char* path);
+32 -18
View File
@@ -2731,13 +2731,19 @@ static int _ai_try_attack(Object* attacker, Object* defender)
int reason = _combat_check_bad_shot(attacker, defender, hitMode, false);
if (reason == COMBAT_BAD_SHOT_NO_AMMO) {
// out of ammo
int roundsLoaded = 0;
if (aiHaveAmmo(attacker, weapon, &ammo)) {
int remainingAmmoQuantity = weaponReload(weapon, ammo);
if (remainingAmmoQuantity == 0 && ammo != nullptr) {
_obj_destroy(ammo);
while (aiHaveAmmo(attacker, weapon, &ammo)) {
int remainingAmmoQuantity = weaponReload(weapon, ammo);
if (remainingAmmoQuantity == 0 && ammo != nullptr) {
_obj_destroy(ammo);
++roundsLoaded;
} else {
break;
}
}
if (remainingAmmoQuantity != -1) {
if (roundsLoaded > 0) {
int volume = _gsound_compute_relative_volume(attacker);
const char* sfx = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_READY, weapon, hitMode, nullptr);
_gsound_play_sfx_file_volume(sfx, volume);
@@ -2920,22 +2926,30 @@ void aiAttemptWeaponReload(Object* critter, int animate)
int ammoQuantity = ammoGetQuantity(weapon);
int ammoCapacity = ammoGetCapacity(weapon);
int loadedRounds = 0;
if (ammoQuantity < ammoCapacity) {
Object* ammo;
if (aiHaveAmmo(critter, weapon, &ammo)) {
int rc = weaponReload(weapon, ammo);
if (rc == 0) {
_obj_destroy(ammo);
}
if (rc != -1 && objectIsPartyMember(critter)) {
int volume = _gsound_compute_relative_volume(critter);
const char* sfx = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_READY, weapon, HIT_MODE_RIGHT_WEAPON_PRIMARY, nullptr);
_gsound_play_sfx_file_volume(sfx, volume);
if (animate) {
_ai_magic_hands(critter, weapon, 5002);
for (int i = 0; i < (ammoCapacity - ammoQuantity); ++i) {
Object* ammo;
if (aiHaveAmmo(critter, weapon, &ammo)) {
int rc = weaponReload(weapon, ammo);
if (rc == 0) {
_obj_destroy(ammo);
++loadedRounds;
} else {
break;
}
} else {
break;
}
}
if (loadedRounds != 0 && objectIsPartyMember(critter)) {
int volume = _gsound_compute_relative_volume(critter);
const char* sfx = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_READY, weapon, HIT_MODE_RIGHT_WEAPON_PRIMARY, nullptr);
_gsound_play_sfx_file_volume(sfx, volume);
if (animate) {
_ai_magic_hands(critter, weapon, 5002);
}
}
}
+3 -2
View File
@@ -952,11 +952,12 @@ int gameHandleKey(int eventCode, bool isInCombatMode)
// game_ui_disable
// 0x443BFC
void gameUiDisable(int a1)
// pass allowScrolling = 1 to allow scrolling
void gameUiDisable(int allowScrolling)
{
if (!gGameUiDisabled) {
gameMouseObjectsHide();
_gmouse_disable(a1);
_gmouse_disable(allowScrolling);
keyboardDisable();
interfaceBarDisable();
gGameUiDisabled = true;
+1 -1
View File
@@ -27,7 +27,7 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int a3, int a4,
void gameReset();
void gameExit();
int gameHandleKey(int eventCode, bool isInCombatMode);
void gameUiDisable(int a1);
void gameUiDisable(int allowScrolling);
void gameUiEnable();
bool gameUiIsDisabled();
int gameGetGlobalVar(int var);
+2 -2
View File
@@ -408,13 +408,13 @@ void _gmouse_enable()
}
// 0x44B48C
void _gmouse_disable(int a1)
void _gmouse_disable(int allowScrolling)
{
if (_gmouse_enabled) {
gameMouseSetCursor(MOUSE_CURSOR_NONE);
_gmouse_enabled = 0;
if (a1 & 1) {
if (allowScrolling & 1) {
_gmouse_scrolling_enabled = 1;
} else {
_gmouse_scrolling_enabled = 0;
+1 -1
View File
@@ -77,7 +77,7 @@ int gameMouseInit();
int gameMouseReset();
void gameMouseExit();
void _gmouse_enable();
void _gmouse_disable(int a1);
void _gmouse_disable(int allowScrolling);
void _gmouse_enable_scrolling();
void _gmouse_disable_scrolling();
bool gmouse_scrolling_is_enabled();
+11 -2
View File
@@ -21,6 +21,7 @@
#include "queue.h"
#include "random.h"
#include "settings.h"
#include "sfall_config.h"
#include "sound_effects_cache.h"
#include "stat.h"
#include "svga.h"
@@ -745,9 +746,17 @@ int backgroundSoundLoad(const char* fileName, int a2, int a3, int a4)
}
// 0x450A08
int _gsound_background_play_level_music(const char* a1, int a2)
int _gsound_background_play_level_music(const char* fileName, int a2)
{
return backgroundSoundLoad(a1, a2, 14, 16);
int gaplessMusic = 0;
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_GAPLESS_MUSIC, &gaplessMusic);
if (gaplessMusic) {
if (!strcmp(fileName, gBackgroundSoundFileName)) {
return 0;
}
}
return backgroundSoundLoad(fileName, a2, 14, 16);
}
// 0x450AB4
+30 -25
View File
@@ -50,10 +50,10 @@ static int stealthBoyTurnOff(Object* critter, Object* item);
static int _insert_drug_effect(Object* critter, Object* item, int duration, int* stats, int* mods);
static void _perform_drug_effect(Object* critter, int* stats, int* mods, bool isImmediate);
static bool _drug_effect_allowed(Object* critter, int pid);
static int _insert_withdrawal(Object* obj, int a2, int a3, int a4, int a5);
static int _item_wd_clear_all(Object* a1, void* data);
static void performWithdrawalStart(Object* obj, int perk, int a3);
static void performWithdrawalEnd(Object* obj, int a2);
static int _insert_withdrawal(Object* obj, int active, int duration, int perk, int pid);
static int _item_wd_clear_all(Object* obj, void* data);
static void performWithdrawalStart(Object* obj, int perk, int pid);
static void performWithdrawalEnd(Object* obj, int perk);
static int drugGetAddictionGvarByPid(int drugPid);
static void dudeSetAddiction(int drugPid);
static void dudeClearAddiction(int drugPid);
@@ -1550,6 +1550,9 @@ bool weaponCanBeReloadedWith(Object* weapon, Object* ammo)
}
// 0x478918
// weaponReload adds ammo to the weapon and removes it from the given ammo stack
// return -1 if ammo is incompatible with weapon; otherwise returns the number of
// rounds left in the ammo stack
int weaponReload(Object* weapon, Object* ammo)
{
if (!weaponCanBeReloadedWith(weapon, ammo)) {
@@ -1568,26 +1571,26 @@ int weaponReload(Object* weapon, Object* ammo)
}
// NOTE: Uninline.
int v10 = ammoGetQuantity(ammo);
int quantity = ammoGetQuantity(ammo);
int v11 = v10;
int left = quantity;
if (ammoQuantity < ammoCapacity) {
int v12;
if (ammoQuantity + v10 > ammoCapacity) {
v11 = v10 - (ammoCapacity - ammoQuantity);
v12 = ammoCapacity;
int newQuantity;
if (ammoQuantity + quantity > ammoCapacity) {
left = quantity - (ammoCapacity - ammoQuantity);
newQuantity = ammoCapacity;
} else {
v11 = 0;
v12 = ammoQuantity + v10;
left = 0;
newQuantity = ammoQuantity + quantity;
}
weapon->data.item.weapon.ammoTypePid = ammo->pid;
ammoSetQuantity(ammo, v11);
ammoSetQuantity(weapon, v12);
ammoSetQuantity(ammo, left);
ammoSetQuantity(weapon, newQuantity);
}
return v11;
return left;
}
// 0x478A1C
@@ -2914,14 +2917,14 @@ int drugEffectEventWrite(File* stream, void* data)
}
// 0x47A290
static int _insert_withdrawal(Object* obj, int a2, int duration, int perk, int pid)
static int _insert_withdrawal(Object* obj, int active, int duration, int perk, int pid)
{
WithdrawalEvent* withdrawalEvent = (WithdrawalEvent*)internal_malloc(sizeof(*withdrawalEvent));
if (withdrawalEvent == nullptr) {
return -1;
}
withdrawalEvent->field_0 = a2;
withdrawalEvent->active = active;
withdrawalEvent->pid = pid;
withdrawalEvent->perk = perk;
@@ -2942,7 +2945,7 @@ int _item_wd_clear(Object* obj, void* data)
return 0;
}
if (!withdrawalEvent->field_0) {
if (!withdrawalEvent->active) {
performWithdrawalEnd(obj, withdrawalEvent->perk);
}
@@ -2950,11 +2953,11 @@ int _item_wd_clear(Object* obj, void* data)
}
// 0x47A324
static int _item_wd_clear_all(Object* a1, void* data)
static int _item_wd_clear_all(Object* obj, void* data)
{
WithdrawalEvent* withdrawalEvent = (WithdrawalEvent*)data;
if (a1 != _wd_obj) {
if (obj != _wd_obj) {
return 0;
}
@@ -2962,11 +2965,12 @@ static int _item_wd_clear_all(Object* a1, void* data)
return 0;
}
if (!withdrawalEvent->field_0) {
if (!withdrawalEvent->active) {
performWithdrawalEnd(_wd_obj, withdrawalEvent->perk);
}
_insert_withdrawal(a1, 1, _wd_onset, withdrawalEvent->perk, withdrawalEvent->pid);
// schedule start of withdrawal
_insert_withdrawal(obj, 1, _wd_onset, withdrawalEvent->perk, withdrawalEvent->pid);
_wd_obj = nullptr;
@@ -2978,7 +2982,7 @@ int withdrawalEventProcess(Object* obj, void* data)
{
WithdrawalEvent* withdrawalEvent = (WithdrawalEvent*)data;
if (withdrawalEvent->field_0) {
if (withdrawalEvent->active) {
performWithdrawalStart(obj, withdrawalEvent->perk, withdrawalEvent->pid);
} else {
if (withdrawalEvent->perk == PERK_JET_ADDICTION) {
@@ -3009,7 +3013,7 @@ int withdrawalEventRead(File* stream, void** dataPtr)
return -1;
}
if (fileReadInt32(stream, &(withdrawalEvent->field_0)) == -1) goto err;
if (fileReadInt32(stream, &(withdrawalEvent->active)) == -1) goto err;
if (fileReadInt32(stream, &(withdrawalEvent->pid)) == -1) goto err;
if (fileReadInt32(stream, &(withdrawalEvent->perk)) == -1) goto err;
@@ -3027,7 +3031,7 @@ int withdrawalEventWrite(File* stream, void* data)
{
WithdrawalEvent* withdrawalEvent = (WithdrawalEvent*)data;
if (fileWriteInt32(stream, withdrawalEvent->field_0) == -1) return -1;
if (fileWriteInt32(stream, withdrawalEvent->active) == -1) return -1;
if (fileWriteInt32(stream, withdrawalEvent->pid) == -1) return -1;
if (fileWriteInt32(stream, withdrawalEvent->perk) == -1) return -1;
@@ -3064,6 +3068,7 @@ static void performWithdrawalStart(Object* obj, int perk, int pid)
}
}
// schedule end of withdrawal
_insert_withdrawal(obj, 0, duration, perk, pid);
}
+7 -7
View File
@@ -49,13 +49,13 @@ bool dudeIsWeaponDisabled(Object* weapon);
int itemGetInventoryFid(Object* obj);
Object* critterGetWeaponForHitMode(Object* critter, int hitMode);
int itemGetActionPointCost(Object* obj, int hitMode, bool aiming);
int itemGetQuantity(Object* obj, Object* a2);
int itemGetQuantity(Object* obj, Object* item);
int itemIsQueued(Object* obj);
Object* itemReplace(Object* a1, Object* a2, int a3);
Object* itemReplace(Object* owner, Object* itemToReplace, int flags);
bool itemIsHidden(Object* obj);
int weaponGetAttackTypeForHitMode(Object* a1, int a2);
int weaponGetSkillForHitMode(Object* a1, int a2);
int weaponGetSkillValue(Object* a1, int a2);
int weaponGetAttackTypeForHitMode(Object* weapon, int hitMode);
int weaponGetSkillForHitMode(Object* weapon, int hitMode);
int weaponGetSkillValue(Object* critter, int hitMode);
int weaponGetDamageMinMax(Object* weapon, int* minDamagePtr, int* maxDamagePtr);
int weaponGetDamage(Object* critter, int hitMode);
int weaponGetDamageType(Object* critter, Object* weapon);
@@ -123,14 +123,14 @@ int _item_d_clear(Object* obj, void* data);
int drugEffectEventProcess(Object* obj, void* data);
int drugEffectEventRead(File* stream, void** dataPtr);
int drugEffectEventWrite(File* stream, void* data);
int _item_wd_clear(Object* obj, void* a2);
int _item_wd_clear(Object* obj, void* data);
int withdrawalEventProcess(Object* obj, void* data);
int withdrawalEventRead(File* stream, void** dataPtr);
int withdrawalEventWrite(File* stream, void* data);
int itemGetTotalCaps(Object* obj);
int itemCapsAdjust(Object* obj, int amount);
int itemGetMoney(Object* obj);
int itemSetMoney(Object* obj, int a2);
int itemSetMoney(Object* obj, int amount);
bool booksGetInfo(int bookPid, int* messageIdPtr, int* skillPtr);
bool explosionEmitsLight();

Some files were not shown because too many files have changed in this diff Show More