mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
125
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e574882f3 | ||
|
|
5995592664 | ||
|
|
982c5fcb42 | ||
|
|
9cd309b263 | ||
|
|
de7f12f3ca | ||
|
|
7a2edd5677 | ||
|
|
66b68f84dc | ||
|
|
fef49692e1 | ||
|
|
6c3c0d34c2 | ||
|
|
42e016e4f9 | ||
|
|
66542dc28a | ||
|
|
5270cf0d55 | ||
|
|
e598d06c4a | ||
|
|
66f7137f74 | ||
|
|
cf59439352 | ||
|
|
02ee5cba5d | ||
|
|
218fd20700 | ||
|
|
7e18a6980a | ||
|
|
66c0218741 | ||
|
|
8fc789d6f9 | ||
|
|
ddc5be3b6d | ||
|
|
833b6d8213 | ||
|
|
4f117678ee | ||
|
|
499f994c37 | ||
|
|
d6c17c1876 | ||
|
|
347bf8b135 | ||
|
|
faf6439293 | ||
|
|
a259a3318e | ||
|
|
50e9fab544 | ||
|
|
54a3b0c05c | ||
|
|
0873eaab37 | ||
|
|
dff92e56fc | ||
|
|
34748a2894 | ||
|
|
39160992ef | ||
|
|
eaa53b3e8e | ||
|
|
39bcb9875d | ||
|
|
9097c2e76d | ||
|
|
50db3587e4 | ||
|
|
9e5a440895 | ||
|
|
61ca374c03 | ||
|
|
8f2b3a10dd | ||
|
|
bbc4f44845 | ||
|
|
5367eba4f2 | ||
|
|
2d617883d3 | ||
|
|
34f666fe55 | ||
|
|
5ae46be317 | ||
|
|
a4f9d7b940 | ||
|
|
251656e15b | ||
|
|
e1a8dc7adc | ||
|
|
ca029b3412 | ||
|
|
70c3035cde | ||
|
|
57b6b0caed | ||
|
|
37ec7b1874 | ||
|
|
2395a6da3f | ||
|
|
7338c2f428 | ||
|
|
2e2655ee1a | ||
|
|
43c633bb89 | ||
|
|
d5b4486d6e | ||
|
|
590b832ba7 | ||
|
|
cc7d9ed866 | ||
|
|
8ad2cb7e2e | ||
|
|
e638c4cf0d | ||
|
|
2f40ce663c | ||
|
|
7b1a99a706 | ||
|
|
398c7adb9a | ||
|
|
424f2ffecc | ||
|
|
d4c4022f55 | ||
|
|
1d0212ef5a | ||
|
|
c7417bb7e5 | ||
|
|
4d05fc1c4a | ||
|
|
aa70a28509 | ||
|
|
49471a6154 | ||
|
|
1b65466d44 | ||
|
|
aed6c37c67 | ||
|
|
1d48fb35b2 | ||
|
|
1d4171727b | ||
|
|
af046127e9 | ||
|
|
5a2c429956 | ||
|
|
ff5fa993f2 | ||
|
|
5a0507200b | ||
|
|
54442f0cfe | ||
|
|
ae9912b7ea | ||
|
|
f6da491246 | ||
|
|
5fa6ec679d | ||
|
|
d029bf3cd0 | ||
|
|
f81e1f7ba7 | ||
|
|
f672ba4ddf | ||
|
|
14cd1844d0 | ||
|
|
2b8f18ff0c | ||
|
|
07b52e0b76 | ||
|
|
c79696326d | ||
|
|
132626912a | ||
|
|
3163319290 | ||
|
|
252d2ef263 | ||
|
|
ef09142375 | ||
|
|
a4ba0240f1 | ||
|
|
2e8a65593e | ||
|
|
f35d1efab2 | ||
|
|
42a6a16f73 | ||
|
|
85389ef2f3 | ||
|
|
f7c1ccfada | ||
|
|
767ae9af25 | ||
|
|
0ba670f0f7 | ||
|
|
58fdf2ff9e | ||
|
|
cb1d2d6ed3 | ||
|
|
4ce09d8cdb | ||
|
|
787fa1b1b1 | ||
|
|
3d4fcf23ba | ||
|
|
74c2125606 | ||
|
|
b1df5a084c | ||
|
|
2a610cf479 | ||
|
|
7d093030e7 | ||
|
|
01be11fce5 | ||
|
|
12fe582e6f | ||
|
|
bdb4feedf9 | ||
|
|
5e93479192 | ||
|
|
503695cd4d | ||
|
|
cc6d803517 | ||
|
|
4dfc7538db | ||
|
|
afeec298bf | ||
|
|
8ad0067510 | ||
|
|
894d9aab52 | ||
|
|
043b43d04b | ||
|
|
144b3beb79 | ||
|
|
30bbb3702a |
@@ -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.
|
||||
|
||||
--->
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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
@@ -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
@@ -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>"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user