Compare commits
36 Commits
fix-macos-
...
customize-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
071563beb9 | ||
|
|
d631bfcdd0 | ||
|
|
4382d67c19 | ||
|
|
e38e7060d4 | ||
|
|
d6fc3bb2d8 | ||
|
|
82793d14f4 | ||
|
|
a5d252f19b | ||
|
|
e5d4d310c0 | ||
|
|
fa1621ff56 | ||
|
|
52e5611e1b | ||
|
|
d540a9ff04 | ||
|
|
1b6fe7e15b | ||
|
|
900140f8f7 | ||
|
|
14430c4f0a | ||
|
|
a1fc68f13a | ||
|
|
2e15d01be3 | ||
|
|
96335aebc9 | ||
|
|
6ab3c508e6 | ||
|
|
f790a10e88 | ||
|
|
6b879e71b8 | ||
|
|
9878e205e6 | ||
|
|
0a5afd1e18 | ||
|
|
625bf69b33 | ||
|
|
48c01eb8a1 | ||
|
|
b105517ab3 | ||
|
|
7d6371fd1c | ||
|
|
dc9824e2be | ||
|
|
60a0d3ab8c | ||
|
|
58c82f9268 | ||
|
|
8fcdbe0bee | ||
|
|
afff399fca | ||
|
|
080f999626 | ||
|
|
593f80144c | ||
|
|
4df9ee557d | ||
|
|
f6ba9d38fd | ||
|
|
c4cc713272 |
150
.github/workflows/ci-build.yml
vendored
150
.github/workflows/ci-build.yml
vendored
@@ -99,44 +99,33 @@ jobs:
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build
|
||||
key: ios-cmake-v4
|
||||
path: out
|
||||
key: ios-cmake-v5
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake \
|
||||
-B build \
|
||||
-D CMAKE_TOOLCHAIN_FILE=cmake/toolchain/ios.toolchain.cmake \
|
||||
-D ENABLE_BITCODE=0 \
|
||||
-D PLATFORM=OS64 \
|
||||
-G Xcode \
|
||||
-D CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY='' \
|
||||
# EOL
|
||||
cmake --preset ios
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake \
|
||||
--build build \
|
||||
--config RelWithDebInfo \
|
||||
-j $(sysctl -n hw.physicalcpu) \
|
||||
# EOL
|
||||
cmake --build --preset ios-debug
|
||||
|
||||
- name: Pack
|
||||
run: |
|
||||
cd build
|
||||
cpack -C RelWithDebInfo
|
||||
cd out/build/ios
|
||||
cpack -C Debug
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fallout2-ce.ipa
|
||||
path: build/fallout2-ce.ipa
|
||||
path: out/build/ios/fallout2-ce.ipa
|
||||
retention-days: 7
|
||||
|
||||
linux:
|
||||
name: Linux (${{ matrix.arch }})
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -154,7 +143,6 @@ jobs:
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt update
|
||||
sudo apt install --allow-downgrades libpcre2-8-0=10.34-7
|
||||
sudo apt install g++-multilib libsdl2-dev:i386 zlib1g-dev:i386
|
||||
|
||||
- name: Dependencies (x64)
|
||||
@@ -166,37 +154,84 @@ jobs:
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build
|
||||
path: out
|
||||
key: linux-${{ matrix.arch }}-cmake-v3
|
||||
|
||||
- name: Configure (x86)
|
||||
if: matrix.arch == 'x86'
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake \
|
||||
-B build \
|
||||
-D CMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-D CMAKE_TOOLCHAIN_FILE=cmake/toolchain/Linux32.cmake \
|
||||
# EOL
|
||||
|
||||
- name: Configure (x64)
|
||||
if: matrix.arch == 'x64'
|
||||
run: |
|
||||
cmake \
|
||||
-B build \
|
||||
-D CMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
# EOL
|
||||
cmake --preset linux-${{ matrix.arch }}-debug
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake \
|
||||
--build build \
|
||||
-j $(nproc) \
|
||||
# EOL
|
||||
cmake --build --preset linux-${{ matrix.arch }}-debug
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fallout2-ce-linux-${{ matrix.arch }}
|
||||
path: out/build/linux-${{ matrix.arch }}-debug/fallout2-ce
|
||||
retention-days: 7
|
||||
|
||||
linux-armhf:
|
||||
name: Linux (armhf)
|
||||
|
||||
runs-on: ubuntu-22.04-arm
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Dependencies
|
||||
run: |
|
||||
sudo dpkg --add-architecture armhf
|
||||
sudo apt update
|
||||
sudo apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf libsdl2-dev:armhf zlib1g-dev:armhf
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake \
|
||||
-B build \
|
||||
-D CMAKE_BUILD_TYPE=Debug \
|
||||
-D FALLOUT_VENDORED=OFF \
|
||||
-D CMAKE_SYSTEM_PROCESSOR=arm \
|
||||
-D CMAKE_C_COMPILER=arm-linux-gnueabihf-gcc \
|
||||
-D CMAKE_CXX_COMPILER=arm-linux-gnueabihf-g++ \
|
||||
# EOL
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fallout2-ce-linux-armhf
|
||||
path: build/fallout2-ce
|
||||
retention-days: 7
|
||||
|
||||
linux-arm64:
|
||||
name: Linux (arm64)
|
||||
|
||||
runs-on: ubuntu-22.04-arm
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install libsdl2-dev zlib1g-dev
|
||||
|
||||
- name: Configure
|
||||
run: cmake -B build -D CMAKE_BUILD_TYPE=Debug -D FALLOUT_VENDORED=OFF
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fallout2-ce-linux-arm64
|
||||
path: build/fallout2-ce
|
||||
retention-days: 7
|
||||
|
||||
@@ -212,35 +247,27 @@ jobs:
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build
|
||||
path: out
|
||||
key: macos-cmake-v6
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake \
|
||||
-B build \
|
||||
-G Xcode \
|
||||
-D CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY='' \
|
||||
# EOL
|
||||
cmake --preset macos
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake \
|
||||
--build build \
|
||||
--config RelWithDebInfo \
|
||||
-j $(sysctl -n hw.physicalcpu) \
|
||||
# EOL
|
||||
cmake --build --preset macos-debug
|
||||
|
||||
- name: Pack
|
||||
run: |
|
||||
cd build
|
||||
cpack -C RelWithDebInfo
|
||||
cd out/build/macos
|
||||
cpack -C Debug
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fallout2-ce-macos.dmg
|
||||
path: build/Fallout II Community Edition.dmg
|
||||
path: out/build/macos/Fallout II Community Edition.dmg
|
||||
retention-days: 7
|
||||
|
||||
windows:
|
||||
@@ -264,27 +291,20 @@ jobs:
|
||||
- name: Cache cmake build
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build
|
||||
path: out
|
||||
key: windows-${{ matrix.arch }}-cmake-v2
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake \
|
||||
-B build \
|
||||
-G "Visual Studio 16 2019" \
|
||||
-A ${{ matrix.generator-platform }} \
|
||||
# EOL
|
||||
cmake --preset windows-${{ matrix.arch }}
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake \
|
||||
--build build \
|
||||
--config RelWithDebInfo \
|
||||
# EOL
|
||||
cmake --build --preset windows-${{ matrix.arch }}-debug
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fallout2-ce-windows-${{ matrix.arch }}
|
||||
path: build/RelWithDebInfo/fallout2-ce.exe
|
||||
path: out/build/windows-${{ matrix.arch }}/Debug/fallout2-ce.exe
|
||||
retention-days: 7
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -391,3 +391,4 @@ FodyWeavers.xsd
|
||||
# CMake
|
||||
/out
|
||||
/build
|
||||
CMakeUserPresets.json
|
||||
|
||||
@@ -20,6 +20,8 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED YES)
|
||||
set(CMAKE_CXX_EXTENSIONS NO)
|
||||
|
||||
option(FALLOUT_VENDORED "Use vendored third-party libraries" ON)
|
||||
|
||||
if(ANDROID)
|
||||
add_library(${EXECUTABLE_NAME} SHARED)
|
||||
else()
|
||||
@@ -363,7 +365,7 @@ endif()
|
||||
add_subdirectory("third_party/fpattern")
|
||||
target_link_libraries(${EXECUTABLE_NAME} fpattern::fpattern)
|
||||
|
||||
if((NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux") AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD"))
|
||||
if(FALLOUT_VENDORED)
|
||||
add_subdirectory("third_party/zlib")
|
||||
add_subdirectory("third_party/sdl2")
|
||||
else()
|
||||
@@ -389,7 +391,8 @@ if(APPLE)
|
||||
install(TARGETS ${EXECUTABLE_NAME} DESTINATION .)
|
||||
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
set(CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK ON)
|
||||
set(CPACK_DMG_DS_STORE_SETUP_SCRIPT "${CMAKE_SOURCE_DIR}/os/macos/dmg/setup.scpt")
|
||||
set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/os/macos/dmg/background.png")
|
||||
set(CPACK_PACKAGE_FILE_NAME "Fallout II Community Edition")
|
||||
endif()
|
||||
|
||||
|
||||
196
CMakePresets.json
Normal file
196
CMakePresets.json
Normal file
@@ -0,0 +1,196 @@
|
||||
{
|
||||
"version": 6,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 19,
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "base",
|
||||
"hidden": true,
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}"
|
||||
},
|
||||
{
|
||||
"name": "windows-base",
|
||||
"hidden": true,
|
||||
"inherits": [
|
||||
"base"
|
||||
],
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "windows-x86",
|
||||
"inherits": [
|
||||
"windows-base"
|
||||
],
|
||||
"generator": "Visual Studio 16 2019",
|
||||
"architecture": "Win32"
|
||||
},
|
||||
{
|
||||
"name": "windows-x64",
|
||||
"inherits": [
|
||||
"windows-base"
|
||||
],
|
||||
"generator": "Visual Studio 16 2019",
|
||||
"architecture": "x64"
|
||||
},
|
||||
{
|
||||
"name": "linux-base",
|
||||
"hidden": true,
|
||||
"inherits": [
|
||||
"base"
|
||||
],
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Linux"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"FALLOUT_VENDORED": "OFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-x86-base",
|
||||
"hidden": true,
|
||||
"inherits": [
|
||||
"linux-base"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_FLAGS": "-m32",
|
||||
"CMAKE_CXX_FLAGS": "-m32",
|
||||
"CMAKE_SYSTEM_NAME": "Linux",
|
||||
"CMAKE_SYSTEM_PROCESSOR": "i386"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-x86-debug",
|
||||
"inherits": [
|
||||
"linux-x86-base"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-x86-release",
|
||||
"inherits": [
|
||||
"linux-x86-base"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-x64-debug",
|
||||
"inherits": [
|
||||
"linux-base"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-x64-release",
|
||||
"inherits": [
|
||||
"linux-base"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "darwin-base",
|
||||
"hidden": true,
|
||||
"inherits": [
|
||||
"base"
|
||||
],
|
||||
"generator": "Xcode",
|
||||
"cacheVariables": {
|
||||
"CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY": ""
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Darwin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "macos",
|
||||
"inherits": [
|
||||
"darwin-base"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ios",
|
||||
"inherits": [
|
||||
"darwin-base"
|
||||
],
|
||||
"cacheVariables": {
|
||||
"CMAKE_SYSTEM_NAME": "iOS"
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "windows-x86-debug",
|
||||
"configurePreset": "windows-x86",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "windows-x86-release",
|
||||
"configurePreset": "windows-x86",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "windows-x64-debug",
|
||||
"configurePreset": "windows-x64",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "windows-x64-release",
|
||||
"configurePreset": "windows-x64",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "linux-x86-debug",
|
||||
"configurePreset": "linux-x86-debug"
|
||||
},
|
||||
{
|
||||
"name": "linux-x86-release",
|
||||
"configurePreset": "linux-x86-release"
|
||||
},
|
||||
{
|
||||
"name": "linux-x64-debug",
|
||||
"configurePreset": "linux-x64-debug"
|
||||
},
|
||||
{
|
||||
"name": "linux-x64-release",
|
||||
"configurePreset": "linux-x64-release"
|
||||
},
|
||||
{
|
||||
"name": "macos-debug",
|
||||
"configurePreset": "macos",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "macos-release",
|
||||
"configurePreset": "macos",
|
||||
"configuration": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "ios-debug",
|
||||
"configurePreset": "ios",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "ios-release",
|
||||
"configurePreset": "ios",
|
||||
"configuration": "RelWithDebInfo"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "x86-Debug",
|
||||
"generator": "Visual Studio 16 2019",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [ "msvc_x86" ],
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "x86-Release",
|
||||
"generator": "Visual Studio 16 2019",
|
||||
"configurationType": "Release",
|
||||
"inheritEnvironments": [ "msvc_x86" ],
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "x64-Debug",
|
||||
"generator": "Visual Studio 16 2019 Win64",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||
"variables": []
|
||||
},
|
||||
{
|
||||
"name": "x64-Release",
|
||||
"generator": "Visual Studio 16 2019 Win64",
|
||||
"configurationType": "Release",
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||
"variables": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
set( CMAKE_SYSTEM_NAME "Linux" )
|
||||
set( CMAKE_SYSTEM_PROCESSOR "i386" )
|
||||
set( CMAKE_C_FLAGS "-m32" )
|
||||
set( CMAKE_CXX_FLAGS "-m32" )
|
||||
File diff suppressed because it is too large
Load Diff
BIN
os/macos/dmg/background.png
Normal file
BIN
os/macos/dmg/background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
46
os/macos/dmg/setup.scpt
Normal file
46
os/macos/dmg/setup.scpt
Normal file
@@ -0,0 +1,46 @@
|
||||
on run argv
|
||||
set image_name to item 1 of argv
|
||||
|
||||
tell application "Finder"
|
||||
tell disk image_name
|
||||
|
||||
set open_attempts to 0
|
||||
repeat while open_attempts < 4
|
||||
try
|
||||
open
|
||||
delay 1
|
||||
set open_attempts to 5
|
||||
close
|
||||
on error errStr number errorNumber
|
||||
set open_attempts to open_attempts + 1
|
||||
delay 10
|
||||
end try
|
||||
end repeat
|
||||
delay 5
|
||||
|
||||
open
|
||||
set current view of container window to icon view
|
||||
set theViewOptions to the icon view options of container window
|
||||
set background picture of theViewOptions to file ".background:background.png"
|
||||
set arrangement of theViewOptions to not arranged
|
||||
set icon size of theViewOptions to 128
|
||||
delay 5
|
||||
close
|
||||
|
||||
open
|
||||
update without registering applications
|
||||
tell container window
|
||||
set sidebar width to 0
|
||||
set statusbar visible to false
|
||||
set toolbar visible to false
|
||||
set the bounds to {400, 100, 1040, 609}
|
||||
set position of item "Fallout II Community Edition.app" to {160, 240}
|
||||
set position of item "Applications" to {480, 240}
|
||||
end tell
|
||||
update without registering applications
|
||||
delay 5
|
||||
close
|
||||
end tell
|
||||
delay 1
|
||||
end tell
|
||||
end run
|
||||
112
src/actions.cc
112
src/actions.cc
@@ -1060,21 +1060,21 @@ int _action_climb_ladder(Object* a1, Object* a2)
|
||||
}
|
||||
|
||||
// 0x411F2C
|
||||
int _action_use_an_item_on_object(Object* a1, Object* a2, Object* a3)
|
||||
int _action_use_an_item_on_object(Object* user, Object* targetObj, Object* item)
|
||||
{
|
||||
Proto* proto = nullptr;
|
||||
int type = FID_TYPE(a2->fid);
|
||||
int type = FID_TYPE(targetObj->fid);
|
||||
int sceneryType = -1;
|
||||
if (type == OBJ_TYPE_SCENERY) {
|
||||
if (protoGetProto(a2->pid, &proto) == -1) {
|
||||
if (protoGetProto(targetObj->pid, &proto) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceneryType = proto->scenery.type;
|
||||
}
|
||||
|
||||
if (sceneryType != SCENERY_TYPE_LADDER_UP || a3 != nullptr) {
|
||||
if (a1 == gDude) {
|
||||
if (sceneryType != SCENERY_TYPE_LADDER_UP || item != nullptr) {
|
||||
if (user == gDude) {
|
||||
int anim = FID_ANIM_TYPE(gDude->fid);
|
||||
if (anim == ANIM_WALK || anim == ANIM_RUNNING) {
|
||||
reg_anim_clear(gDude);
|
||||
@@ -1085,40 +1085,40 @@ int _action_use_an_item_on_object(Object* a1, Object* a2, Object* a3)
|
||||
int actionPoints;
|
||||
if (isInCombat()) {
|
||||
animationRequestOptions = ANIMATION_REQUEST_RESERVED;
|
||||
actionPoints = a1->data.critter.combat.ap;
|
||||
actionPoints = user->data.critter.combat.ap;
|
||||
} else {
|
||||
animationRequestOptions = ANIMATION_REQUEST_UNRESERVED;
|
||||
actionPoints = -1;
|
||||
}
|
||||
|
||||
if (a1 == gDude) {
|
||||
if (user == gDude) {
|
||||
animationRequestOptions = ANIMATION_REQUEST_RESERVED;
|
||||
}
|
||||
|
||||
reg_anim_begin(animationRequestOptions);
|
||||
|
||||
if (actionPoints != -1 || objectGetDistanceBetween(a1, a2) < 5) {
|
||||
animationRegisterMoveToObject(a1, a2, actionPoints, 0);
|
||||
if (actionPoints != -1 || objectGetDistanceBetween(user, targetObj) < 5) {
|
||||
animationRegisterMoveToObject(user, targetObj, actionPoints, 0);
|
||||
} else {
|
||||
animationRegisterRunToObject(a1, a2, -1, 0);
|
||||
animationRegisterRunToObject(user, targetObj, -1, 0);
|
||||
}
|
||||
|
||||
animationRegisterCallbackForced(a1, a2, (AnimationCallback*)_is_next_to, -1);
|
||||
animationRegisterCallbackForced(user, targetObj, (AnimationCallback*)_is_next_to, -1);
|
||||
|
||||
if (a3 == nullptr) {
|
||||
animationRegisterCallback(a1, a2, (AnimationCallback*)_check_scenery_ap_cost, -1);
|
||||
if (item == nullptr) {
|
||||
animationRegisterCallback(user, targetObj, (AnimationCallback*)_check_scenery_ap_cost, -1);
|
||||
}
|
||||
|
||||
int a2a = (a1->fid & 0xF000) >> 12;
|
||||
if (a2a != 0) {
|
||||
const char* sfx = sfxBuildCharName(a1, ANIM_PUT_AWAY, CHARACTER_SOUND_EFFECT_UNUSED);
|
||||
animationRegisterPlaySoundEffect(a1, sfx, -1);
|
||||
animationRegisterAnimate(a1, ANIM_PUT_AWAY, 0);
|
||||
int weaponAnimCode = (user->fid & 0xF000) >> 12;
|
||||
if (weaponAnimCode != 0) {
|
||||
const char* sfx = sfxBuildCharName(user, ANIM_PUT_AWAY, CHARACTER_SOUND_EFFECT_UNUSED);
|
||||
animationRegisterPlaySoundEffect(user, sfx, -1);
|
||||
animationRegisterAnimate(user, ANIM_PUT_AWAY, 0);
|
||||
}
|
||||
|
||||
int anim;
|
||||
int objectType = FID_TYPE(a2->fid);
|
||||
if (objectType == OBJ_TYPE_CRITTER && _critter_is_prone(a2)) {
|
||||
int objectType = FID_TYPE(targetObj->fid);
|
||||
if (objectType == OBJ_TYPE_CRITTER && _critter_is_prone(targetObj)) {
|
||||
anim = ANIM_MAGIC_HANDS_GROUND;
|
||||
} else if (objectType == OBJ_TYPE_SCENERY && (proto->scenery.extendedFlags & 0x01) != 0) {
|
||||
anim = ANIM_MAGIC_HANDS_GROUND;
|
||||
@@ -1126,31 +1126,31 @@ int _action_use_an_item_on_object(Object* a1, Object* a2, Object* a3)
|
||||
anim = ANIM_MAGIC_HANDS_MIDDLE;
|
||||
}
|
||||
|
||||
if (sceneryType != SCENERY_TYPE_STAIRS && a3 == nullptr) {
|
||||
animationRegisterAnimate(a1, anim, -1);
|
||||
if (sceneryType != SCENERY_TYPE_STAIRS && item == nullptr) {
|
||||
animationRegisterAnimate(user, anim, -1);
|
||||
}
|
||||
|
||||
if (a3 != nullptr) {
|
||||
if (item != nullptr) {
|
||||
// TODO: Get rid of cast.
|
||||
animationRegisterCallback3(a1, a2, a3, (AnimationCallback3*)_obj_use_item_on, -1);
|
||||
animationRegisterCallback3(user, targetObj, item, (AnimationCallback3*)_obj_use_item_on, -1);
|
||||
} else {
|
||||
animationRegisterCallback(a1, a2, (AnimationCallback*)_obj_use, -1);
|
||||
animationRegisterCallback(user, targetObj, (AnimationCallback*)_obj_use, -1);
|
||||
}
|
||||
|
||||
if (a2a != 0) {
|
||||
animationRegisterTakeOutWeapon(a1, a2a, -1);
|
||||
if (weaponAnimCode != 0) {
|
||||
animationRegisterTakeOutWeapon(user, weaponAnimCode, -1);
|
||||
}
|
||||
|
||||
return reg_anim_end();
|
||||
}
|
||||
|
||||
return _action_climb_ladder(a1, a2);
|
||||
return _action_climb_ladder(user, targetObj);
|
||||
}
|
||||
|
||||
// 0x412114
|
||||
int _action_use_an_object(Object* a1, Object* a2)
|
||||
int _action_use_an_object(Object* user, Object* targetObj)
|
||||
{
|
||||
return _action_use_an_item_on_object(a1, a2, nullptr);
|
||||
return _action_use_an_item_on_object(user, targetObj, nullptr);
|
||||
}
|
||||
|
||||
// 0x412134
|
||||
@@ -1322,27 +1322,27 @@ static int _action_use_skill_in_combat_error(Object* critter)
|
||||
|
||||
// skill_use
|
||||
// 0x41255C
|
||||
int actionUseSkill(Object* a1, Object* a2, int skill)
|
||||
int actionUseSkill(Object* user, Object* target, int skill)
|
||||
{
|
||||
switch (skill) {
|
||||
case SKILL_FIRST_AID:
|
||||
case SKILL_DOCTOR:
|
||||
if (isInCombat()) {
|
||||
// NOTE: Uninline.
|
||||
return _action_use_skill_in_combat_error(a1);
|
||||
return _action_use_skill_in_combat_error(user);
|
||||
}
|
||||
|
||||
if (PID_TYPE(a2->pid) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(target->pid) != OBJ_TYPE_CRITTER) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case SKILL_LOCKPICK:
|
||||
if (isInCombat()) {
|
||||
// NOTE: Uninline.
|
||||
return _action_use_skill_in_combat_error(a1);
|
||||
return _action_use_skill_in_combat_error(user);
|
||||
}
|
||||
|
||||
if (PID_TYPE(a2->pid) != OBJ_TYPE_ITEM && PID_TYPE(a2->pid) != OBJ_TYPE_SCENERY) {
|
||||
if (PID_TYPE(target->pid) != OBJ_TYPE_ITEM && PID_TYPE(target->pid) != OBJ_TYPE_SCENERY) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1350,14 +1350,14 @@ int actionUseSkill(Object* a1, Object* a2, int skill)
|
||||
case SKILL_STEAL:
|
||||
if (isInCombat()) {
|
||||
// NOTE: Uninline.
|
||||
return _action_use_skill_in_combat_error(a1);
|
||||
return _action_use_skill_in_combat_error(user);
|
||||
}
|
||||
|
||||
if (PID_TYPE(a2->pid) != OBJ_TYPE_ITEM && PID_TYPE(a2->pid) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(target->pid) != OBJ_TYPE_ITEM && PID_TYPE(target->pid) != OBJ_TYPE_CRITTER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a2 == a1) {
|
||||
if (target == user) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1365,10 +1365,10 @@ int actionUseSkill(Object* a1, Object* a2, int skill)
|
||||
case SKILL_TRAPS:
|
||||
if (isInCombat()) {
|
||||
// NOTE: Uninline.
|
||||
return _action_use_skill_in_combat_error(a1);
|
||||
return _action_use_skill_in_combat_error(user);
|
||||
}
|
||||
|
||||
if (PID_TYPE(a2->pid) == OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(target->pid) == OBJ_TYPE_CRITTER) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1377,18 +1377,18 @@ int actionUseSkill(Object* a1, Object* a2, int skill)
|
||||
case SKILL_REPAIR:
|
||||
if (isInCombat()) {
|
||||
// NOTE: Uninline.
|
||||
return _action_use_skill_in_combat_error(a1);
|
||||
return _action_use_skill_in_combat_error(user);
|
||||
}
|
||||
|
||||
if (PID_TYPE(a2->pid) != OBJ_TYPE_CRITTER) {
|
||||
if (PID_TYPE(target->pid) != OBJ_TYPE_CRITTER) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (critterGetKillType(a2) == KILL_TYPE_ROBOT) {
|
||||
if (critterGetKillType(target) == KILL_TYPE_ROBOT) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (critterGetKillType(a2) == KILL_TYPE_BRAHMIN
|
||||
if (critterGetKillType(target) == KILL_TYPE_BRAHMIN
|
||||
&& skill == SKILL_SCIENCE) {
|
||||
break;
|
||||
}
|
||||
@@ -1398,7 +1398,7 @@ int actionUseSkill(Object* a1, Object* a2, int skill)
|
||||
int targetType = SCIENCE_REPAIR_TARGET_TYPE_DEFAULT;
|
||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_SCIENCE_REPAIR_TARGET_TYPE_KEY, &targetType);
|
||||
if (targetType == SCIENCE_REPAIR_TARGET_TYPE_DUDE) {
|
||||
if (a2 == gDude) {
|
||||
if (target == gDude) {
|
||||
break;
|
||||
}
|
||||
} else if (targetType == SCIENCE_REPAIR_TARGET_TYPE_ANYONE) {
|
||||
@@ -1418,7 +1418,7 @@ int actionUseSkill(Object* a1, Object* a2, int skill)
|
||||
// skill in entire party, and this skill is his/her own best.
|
||||
Object* performer = gDude;
|
||||
|
||||
if (a1 == gDude) {
|
||||
if (user == gDude) {
|
||||
Object* partyMember = partyMemberGetBestInSkill(skill);
|
||||
|
||||
if (partyMember == gDude) {
|
||||
@@ -1451,7 +1451,7 @@ int actionUseSkill(Object* a1, Object* a2, int skill)
|
||||
|
||||
if (partyMember != nullptr) {
|
||||
bool isDude = false;
|
||||
if (objectGetDistanceBetween(gDude, a2) <= 1) {
|
||||
if (objectGetDistanceBetween(gDude, target) <= 1) {
|
||||
isDude = true;
|
||||
}
|
||||
|
||||
@@ -1478,21 +1478,21 @@ int actionUseSkill(Object* a1, Object* a2, int skill)
|
||||
|
||||
if (isInCombat()) {
|
||||
reg_anim_begin(ANIMATION_REQUEST_RESERVED);
|
||||
animationRegisterMoveToObject(performer, a2, performer->data.critter.combat.ap, 0);
|
||||
animationRegisterMoveToObject(performer, target, performer->data.critter.combat.ap, 0);
|
||||
} else {
|
||||
reg_anim_begin(a1 == gDude ? ANIMATION_REQUEST_RESERVED : ANIMATION_REQUEST_UNRESERVED);
|
||||
if (a2 != gDude) {
|
||||
if (objectGetDistanceBetween(performer, a2) >= 5) {
|
||||
animationRegisterRunToObject(performer, a2, -1, 0);
|
||||
reg_anim_begin(user == gDude ? ANIMATION_REQUEST_RESERVED : ANIMATION_REQUEST_UNRESERVED);
|
||||
if (target != gDude) {
|
||||
if (objectGetDistanceBetween(performer, target) >= 5) {
|
||||
animationRegisterRunToObject(performer, target, -1, 0);
|
||||
} else {
|
||||
animationRegisterMoveToObject(performer, a2, -1, 0);
|
||||
animationRegisterMoveToObject(performer, target, -1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
animationRegisterCallbackForced(performer, a2, (AnimationCallback*)_is_next_to, -1);
|
||||
animationRegisterCallbackForced(performer, target, (AnimationCallback*)_is_next_to, -1);
|
||||
|
||||
int anim = (FID_TYPE(a2->fid) == OBJ_TYPE_CRITTER && _critter_is_prone(a2)) ? ANIM_MAGIC_HANDS_GROUND : ANIM_MAGIC_HANDS_MIDDLE;
|
||||
int anim = (FID_TYPE(target->fid) == OBJ_TYPE_CRITTER && _critter_is_prone(target)) ? ANIM_MAGIC_HANDS_GROUND : ANIM_MAGIC_HANDS_MIDDLE;
|
||||
int fid = buildFid(OBJ_TYPE_CRITTER, performer->fid & 0xFFF, anim, 0, performer->rotation + 1);
|
||||
|
||||
CacheEntry* artHandle;
|
||||
@@ -1504,7 +1504,7 @@ int actionUseSkill(Object* a1, Object* a2, int skill)
|
||||
|
||||
animationRegisterAnimate(performer, anim, -1);
|
||||
// TODO: Get rid of casts.
|
||||
animationRegisterCallback3(performer, a2, (void*)skill, (AnimationCallback3*)_obj_use_skill_on, -1);
|
||||
animationRegisterCallback3(performer, target, (void*)skill, (AnimationCallback3*)_obj_use_skill_on, -1);
|
||||
return reg_anim_end();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@ namespace fallout {
|
||||
extern int rotation;
|
||||
|
||||
int _action_attack(Attack* attack);
|
||||
int _action_use_an_item_on_object(Object* a1, Object* a2, Object* a3);
|
||||
int _action_use_an_object(Object* a1, Object* a2);
|
||||
int _action_use_an_item_on_object(Object* user, Object* targetObj, Object* item);
|
||||
int _action_use_an_object(Object* user, Object* targetObj);
|
||||
int actionPickUp(Object* critter, Object* item);
|
||||
int _action_loot_container(Object* critter, Object* container);
|
||||
int _action_skill_use(int a1);
|
||||
int actionUseSkill(Object* a1, Object* a2, int skill);
|
||||
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 _action_explode_running();
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "tile.h"
|
||||
#include "trait.h"
|
||||
#include "vcr.h"
|
||||
#include "worldmap.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
@@ -1033,7 +1034,7 @@ int animationRegisterHideObjectForced(Object* object)
|
||||
}
|
||||
|
||||
// 0x414E98
|
||||
int animationRegisterCallback(void* a1, void* a2, AnimationCallback* proc, int delay)
|
||||
int animationRegisterCallback(void* param1, void* param2, AnimationCallback* proc, int delay)
|
||||
{
|
||||
if (_check_registry(nullptr) == -1 || proc == nullptr) {
|
||||
_anim_cleanup();
|
||||
@@ -1045,8 +1046,8 @@ int animationRegisterCallback(void* a1, void* a2, AnimationCallback* proc, int d
|
||||
animationDescription->kind = ANIM_KIND_CALLBACK;
|
||||
animationDescription->extendedFlags = 0;
|
||||
animationDescription->artCacheKey = nullptr;
|
||||
animationDescription->param2 = a2;
|
||||
animationDescription->param1 = a1;
|
||||
animationDescription->param2 = param2;
|
||||
animationDescription->param1 = param1;
|
||||
animationDescription->callback = proc;
|
||||
animationDescription->delay = delay;
|
||||
|
||||
@@ -1058,7 +1059,7 @@ int animationRegisterCallback(void* a1, void* a2, AnimationCallback* proc, int d
|
||||
// Same as `animationRegisterCallback` but accepting 3 parameters.
|
||||
//
|
||||
// 0x414F20
|
||||
int animationRegisterCallback3(void* a1, void* a2, void* a3, AnimationCallback3* proc, int delay)
|
||||
int animationRegisterCallback3(void* param1, void* param2, void* param3, AnimationCallback3* proc, int delay)
|
||||
{
|
||||
if (_check_registry(nullptr) == -1 || proc == nullptr) {
|
||||
_anim_cleanup();
|
||||
@@ -1070,10 +1071,10 @@ int animationRegisterCallback3(void* a1, void* a2, void* a3, AnimationCallback3*
|
||||
animationDescription->kind = ANIM_KIND_CALLBACK3;
|
||||
animationDescription->extendedFlags = 0;
|
||||
animationDescription->artCacheKey = nullptr;
|
||||
animationDescription->param2 = a2;
|
||||
animationDescription->param1 = a1;
|
||||
animationDescription->param2 = param2;
|
||||
animationDescription->param1 = param1;
|
||||
animationDescription->callback3 = proc;
|
||||
animationDescription->param3 = a3;
|
||||
animationDescription->param3 = param3;
|
||||
animationDescription->delay = delay;
|
||||
|
||||
gAnimationDescriptionCurrentIndex++;
|
||||
@@ -3062,7 +3063,7 @@ void _dude_fidget()
|
||||
objectGetRect(object, &rect);
|
||||
|
||||
Rect intersection;
|
||||
if (rectIntersection(&rect, &_scr_size, &intersection) == 0 && (gMapHeader.field_34 != 97 || object->pid != 0x10000FA)) {
|
||||
if (rectIntersection(&rect, &_scr_size, &intersection) == 0 && (gMapHeader.index != MAP_SPECIAL_RND_WOODSMAN || object->pid != 0x10000FA)) {
|
||||
candidates[candidatesLength++] = object;
|
||||
}
|
||||
}
|
||||
|
||||
55
src/art.cc
55
src/art.cc
@@ -1006,45 +1006,28 @@ static void artCacheFreeImpl(void* ptr)
|
||||
internal_free(ptr);
|
||||
}
|
||||
|
||||
// 0x419C88
|
||||
int buildFid(int objectType, int frmId, int animType, int a3, int rotation)
|
||||
static int buildFidInternal(unsigned short frmId, unsigned char weaponCode, unsigned char animType, unsigned char objectType, unsigned char rotation)
|
||||
{
|
||||
int v7, v8, v9, v10;
|
||||
return ((rotation << 28) & 0x70000000) | (objectType << 24) | ((animType << 16) & 0xFF0000) | ((weaponCode << 12) & 0xF000) | (frmId & 0xFFF);
|
||||
}
|
||||
|
||||
v10 = rotation;
|
||||
|
||||
if (objectType != OBJ_TYPE_CRITTER) {
|
||||
goto zero;
|
||||
// 0x419C88
|
||||
int buildFid(int objectType, int frmId, int animType, int weaponCode, int rotation)
|
||||
{
|
||||
// Always use rotation 0 (NE) for non-critters, for certain critter animations.
|
||||
// For other critter animations, check if art for the given rotation exists, if not try rotation 1 (E) and if that also doesn't exist, then default to 0 (NE).
|
||||
if (objectType != OBJ_TYPE_CRITTER
|
||||
|| animType == ANIM_FIRE_DANCE
|
||||
|| animType < ANIM_FALL_BACK
|
||||
|| animType > ANIM_FALL_FRONT_BLOOD) {
|
||||
rotation = ROTATION_NE;
|
||||
} else if (!artExists(buildFidInternal(frmId, weaponCode, animType, OBJ_TYPE_CRITTER, rotation))) {
|
||||
rotation = rotation != ROTATION_E
|
||||
&& artExists(buildFidInternal(frmId, weaponCode, animType, OBJ_TYPE_CRITTER, ROTATION_E))
|
||||
? ROTATION_E
|
||||
: ROTATION_NE;
|
||||
}
|
||||
|
||||
if (animType == ANIM_FIRE_DANCE || animType < ANIM_FALL_BACK || animType > ANIM_FALL_FRONT_BLOOD) {
|
||||
goto zero;
|
||||
}
|
||||
|
||||
v7 = ((a3 << 12) & 0xF000) | ((animType << 16) & 0xFF0000) | 0x1000000;
|
||||
v8 = ((rotation << 28) & 0x70000000) | v7;
|
||||
v9 = frmId & 0xFFF;
|
||||
|
||||
if (artExists(v9 | v8) != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (objectType == rotation) {
|
||||
goto zero;
|
||||
}
|
||||
|
||||
v10 = objectType;
|
||||
if (artExists(v9 | v7 | 0x10000000) != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
zero:
|
||||
|
||||
v10 = 0;
|
||||
|
||||
out:
|
||||
|
||||
return ((v10 << 28) & 0x70000000) | (objectType << 24) | ((animType << 16) & 0xFF0000) | ((a3 << 12) & 0xF000) | (frmId & 0xFFF);
|
||||
return buildFidInternal(frmId, weaponCode, animType, objectType, rotation);
|
||||
}
|
||||
|
||||
// 0x419D60
|
||||
|
||||
@@ -147,7 +147,7 @@ bool _art_fid_valid(int fid);
|
||||
int _art_alias_num(int a1);
|
||||
int artCritterFidShouldRun(int a1);
|
||||
int artAliasFid(int fid);
|
||||
int buildFid(int objectType, int frmId, int animType, int a4, int rotation);
|
||||
int buildFid(int objectType, int frmId, int animType, int weaponCode, int rotation);
|
||||
Art* artLoad(const char* path);
|
||||
int artRead(const char* path, unsigned char* data);
|
||||
int artWrite(const char* path, unsigned char* data);
|
||||
|
||||
197
src/color.cc
197
src/color.cc
@@ -5,24 +5,12 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "db.h"
|
||||
#include "memory.h"
|
||||
#include "svga.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define COLOR_PALETTE_STACK_CAPACITY 16
|
||||
|
||||
typedef struct ColorPaletteStackEntry {
|
||||
unsigned char mappedColors[256];
|
||||
unsigned char cmap[768];
|
||||
unsigned char colorTable[32768];
|
||||
} ColorPaletteStackEntry;
|
||||
|
||||
static int colorPaletteFileOpen(const char* filePath, int flags);
|
||||
static int colorPaletteFileRead(int fd, void* buffer, size_t size);
|
||||
static int colorPaletteFileClose(int fd);
|
||||
static void* colorPaletteMallocDefaultImpl(size_t size);
|
||||
static void* colorPaletteReallocDefaultImpl(void* ptr, size_t size);
|
||||
static void colorPaletteFreeDefaultImpl(void* ptr);
|
||||
static void _setIntensityTableColor(int a1);
|
||||
static void _setIntensityTables();
|
||||
static void _setMixTableColor(int a1);
|
||||
@@ -53,15 +41,6 @@ static double gBrightness = 1.0;
|
||||
// 0x51DF20
|
||||
static ColorTransitionCallback* gColorPaletteTransitionCallback = nullptr;
|
||||
|
||||
// 0x51DF24
|
||||
static MallocProc* gColorPaletteMallocProc = colorPaletteMallocDefaultImpl;
|
||||
|
||||
// 0x51DF28
|
||||
static ReallocProc* gColorPaletteReallocProc = colorPaletteReallocDefaultImpl;
|
||||
|
||||
// 0x51DF2C
|
||||
static FreeProc* gColorPaletteFreeProc = colorPaletteFreeDefaultImpl;
|
||||
|
||||
// 0x51DF30
|
||||
static ColorFileNameManger* gColorFileNameMangler = nullptr;
|
||||
|
||||
@@ -70,9 +49,6 @@ unsigned char _cmap[768] = {
|
||||
0x3F, 0x3F, 0x3F
|
||||
};
|
||||
|
||||
// 0x673050
|
||||
static ColorPaletteStackEntry* gColorPaletteStack[COLOR_PALETTE_STACK_CAPACITY];
|
||||
|
||||
// 0x673090
|
||||
unsigned char _systemCmap[256 * 3];
|
||||
|
||||
@@ -97,80 +73,6 @@ Color colorMixMulTable[256][256];
|
||||
// 0x6A38D0
|
||||
unsigned char _colorTable[32768];
|
||||
|
||||
// 0x6AB8D0
|
||||
static int gColorPaletteStackSize;
|
||||
|
||||
// 0x6AB928
|
||||
static ColorPaletteFileReadProc* gColorPaletteFileReadProc;
|
||||
|
||||
// 0x6AB92C
|
||||
static ColorPaletteCloseProc* gColorPaletteFileCloseProc;
|
||||
|
||||
// 0x6AB930
|
||||
static ColorPaletteFileOpenProc* gColorPaletteFileOpenProc;
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x4C7200
|
||||
static int colorPaletteFileOpen(const char* filePath, int flags)
|
||||
{
|
||||
if (gColorPaletteFileOpenProc != nullptr) {
|
||||
return gColorPaletteFileOpenProc(filePath, flags);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x4C7218
|
||||
static int colorPaletteFileRead(int fd, void* buffer, size_t size)
|
||||
{
|
||||
if (gColorPaletteFileReadProc != nullptr) {
|
||||
return gColorPaletteFileReadProc(fd, buffer, size);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE: Inlined.
|
||||
//
|
||||
// 0x4C7230
|
||||
static int colorPaletteFileClose(int fd)
|
||||
{
|
||||
if (gColorPaletteFileCloseProc != nullptr) {
|
||||
return gColorPaletteFileCloseProc(fd);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x4C7248
|
||||
void colorPaletteSetFileIO(ColorPaletteFileOpenProc* openProc, ColorPaletteFileReadProc* readProc, ColorPaletteCloseProc* closeProc)
|
||||
{
|
||||
gColorPaletteFileOpenProc = openProc;
|
||||
gColorPaletteFileReadProc = readProc;
|
||||
gColorPaletteFileCloseProc = closeProc;
|
||||
}
|
||||
|
||||
// 0x4C725C
|
||||
static void* colorPaletteMallocDefaultImpl(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
// 0x4C7264
|
||||
static void* colorPaletteReallocDefaultImpl(void* ptr, size_t size)
|
||||
{
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
// 0x4C726C
|
||||
static void colorPaletteFreeDefaultImpl(void* ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
// 0x4C72B4
|
||||
int _calculateColor(int intensity, Color color)
|
||||
{
|
||||
@@ -395,9 +297,8 @@ bool colorPaletteLoad(const char* path)
|
||||
path = gColorFileNameMangler(path);
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
int fd = colorPaletteFileOpen(path, 0x200);
|
||||
if (fd == -1) {
|
||||
File* stream = fileOpen(path, "rb");
|
||||
if (stream == nullptr) {
|
||||
_errorStr = _aColor_cColorTa;
|
||||
return false;
|
||||
}
|
||||
@@ -408,13 +309,13 @@ bool colorPaletteLoad(const char* path)
|
||||
unsigned char b;
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, &r, sizeof(r));
|
||||
fileRead(&r, sizeof(r), 1, stream);
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, &g, sizeof(g));
|
||||
fileRead(&g, sizeof(g), 1, stream);
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, &b, sizeof(b));
|
||||
fileRead(&b, sizeof(b), 1, stream);
|
||||
|
||||
if (r <= 0x3F && g <= 0x3F && b <= 0x3F) {
|
||||
_mappedColor[index] = 1;
|
||||
@@ -431,23 +332,23 @@ bool colorPaletteLoad(const char* path)
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, _colorTable, 0x8000);
|
||||
fileRead(_colorTable, 0x8000, 1, stream);
|
||||
|
||||
unsigned int type;
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, &type, sizeof(type));
|
||||
fileRead(&type, sizeof(type), 1, stream);
|
||||
|
||||
// NOTE: The value is "NEWC". Original code uses cmp opcode, not stricmp,
|
||||
// or comparing characters one-by-one.
|
||||
if (type == 'NEWC') {
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, intensityColorTable, sizeof(intensityColorTable));
|
||||
fileRead(intensityColorTable, sizeof(intensityColorTable), 1, stream);
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, colorMixAddTable, sizeof(colorMixAddTable));
|
||||
fileRead(colorMixAddTable, sizeof(colorMixAddTable), 1, stream);
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileRead(fd, colorMixMulTable, sizeof(colorMixMulTable));
|
||||
fileRead(colorMixMulTable, sizeof(colorMixMulTable), 1, stream);
|
||||
} else {
|
||||
_setIntensityTables();
|
||||
|
||||
@@ -459,7 +360,7 @@ bool colorPaletteLoad(const char* path)
|
||||
_rebuildColorBlendTables();
|
||||
|
||||
// NOTE: Uninline.
|
||||
colorPaletteFileClose(fd);
|
||||
fileClose(stream);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -548,7 +449,7 @@ unsigned char* _getColorBlendTable(int ch)
|
||||
unsigned char* ptr;
|
||||
|
||||
if (_blendTable[ch] == nullptr) {
|
||||
ptr = (unsigned char*)gColorPaletteMallocProc(4100);
|
||||
ptr = (unsigned char*)internal_malloc(4100);
|
||||
*(int*)ptr = 1;
|
||||
_blendTable[ch] = ptr + 4;
|
||||
_buildBlendTable(_blendTable[ch], ch);
|
||||
@@ -568,20 +469,12 @@ void _freeColorBlendTable(int a1)
|
||||
int* count = (int*)(v2 - sizeof(int));
|
||||
*count -= 1;
|
||||
if (*count == 0) {
|
||||
gColorPaletteFreeProc(count);
|
||||
internal_free(count);
|
||||
_blendTable[a1] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4C7E58
|
||||
void colorPaletteSetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc)
|
||||
{
|
||||
gColorPaletteMallocProc = mallocProc;
|
||||
gColorPaletteReallocProc = reallocProc;
|
||||
gColorPaletteFreeProc = freeProc;
|
||||
}
|
||||
|
||||
// 0x4C7E6C
|
||||
void colorSetBrightness(double value)
|
||||
{
|
||||
@@ -595,60 +488,6 @@ void colorSetBrightness(double value)
|
||||
_setSystemPalette(_systemCmap);
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4C8828
|
||||
bool colorPushColorPalette()
|
||||
{
|
||||
if (gColorPaletteStackSize >= COLOR_PALETTE_STACK_CAPACITY) {
|
||||
_errorStr = _aColor_cColorpa;
|
||||
return false;
|
||||
}
|
||||
|
||||
ColorPaletteStackEntry* entry = (ColorPaletteStackEntry*)malloc(sizeof(*entry));
|
||||
gColorPaletteStack[gColorPaletteStackSize] = entry;
|
||||
|
||||
memcpy(entry->mappedColors, _mappedColor, sizeof(_mappedColor));
|
||||
memcpy(entry->cmap, _cmap, sizeof(_cmap));
|
||||
memcpy(entry->colorTable, _colorTable, sizeof(_colorTable));
|
||||
|
||||
gColorPaletteStackSize++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4C88E0
|
||||
bool colorPopColorPalette()
|
||||
{
|
||||
if (gColorPaletteStackSize == 0) {
|
||||
_errorStr = aColor_cColor_0;
|
||||
return false;
|
||||
}
|
||||
|
||||
gColorPaletteStackSize--;
|
||||
|
||||
ColorPaletteStackEntry* entry = gColorPaletteStack[gColorPaletteStackSize];
|
||||
|
||||
memcpy(_mappedColor, entry->mappedColors, sizeof(_mappedColor));
|
||||
memcpy(_cmap, entry->cmap, sizeof(_cmap));
|
||||
memcpy(_colorTable, entry->colorTable, sizeof(_colorTable));
|
||||
|
||||
free(entry);
|
||||
gColorPaletteStack[gColorPaletteStackSize] = nullptr;
|
||||
|
||||
_setIntensityTables();
|
||||
|
||||
for (int index = 0; index < 256; index++) {
|
||||
_setMixTableColor(index);
|
||||
}
|
||||
|
||||
_rebuildColorBlendTables();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4C89CC
|
||||
bool _initColors()
|
||||
{
|
||||
@@ -675,12 +514,6 @@ void _colorsClose()
|
||||
for (int index = 0; index < 256; index++) {
|
||||
_freeColorBlendTable(index);
|
||||
}
|
||||
|
||||
for (int index = 0; index < gColorPaletteStackSize; index++) {
|
||||
free(gColorPaletteStack[index]);
|
||||
}
|
||||
|
||||
gColorPaletteStackSize = 0;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
10
src/color.h
10
src/color.h
@@ -1,18 +1,12 @@
|
||||
#ifndef COLOR_H
|
||||
#define COLOR_H
|
||||
|
||||
#include "memory_defs.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef unsigned char Color;
|
||||
typedef const char*(ColorFileNameManger)(const char*);
|
||||
typedef void(ColorTransitionCallback)();
|
||||
|
||||
typedef int(ColorPaletteFileOpenProc)(const char* path, int mode);
|
||||
typedef int(ColorPaletteFileReadProc)(int fd, void* buffer, size_t size);
|
||||
typedef int(ColorPaletteCloseProc)(int fd);
|
||||
|
||||
extern unsigned char _cmap[768];
|
||||
|
||||
extern unsigned char _systemCmap[256 * 3];
|
||||
@@ -24,7 +18,6 @@ extern Color intensityColorTable[256][256];
|
||||
extern Color colorMixMulTable[256][256];
|
||||
extern unsigned char _colorTable[32768];
|
||||
|
||||
void colorPaletteSetFileIO(ColorPaletteFileOpenProc* openProc, ColorPaletteFileReadProc* readProc, ColorPaletteCloseProc* closeProc);
|
||||
int _calculateColor(int intensity, Color color);
|
||||
int Color2RGB(Color c);
|
||||
void colorPaletteFadeBetween(unsigned char* oldPalette, unsigned char* newPalette, int steps);
|
||||
@@ -36,10 +29,7 @@ bool colorPaletteLoad(const char* path);
|
||||
char* _colorError();
|
||||
unsigned char* _getColorBlendTable(int ch);
|
||||
void _freeColorBlendTable(int a1);
|
||||
void colorPaletteSetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc);
|
||||
void colorSetBrightness(double value);
|
||||
bool colorPushColorPalette();
|
||||
bool colorPopColorPalette();
|
||||
bool _initColors();
|
||||
void _colorsClose();
|
||||
|
||||
|
||||
@@ -2620,7 +2620,7 @@ static int _ai_switch_weapons(Object* attacker, int* hitMode, Object** weapon, O
|
||||
}
|
||||
|
||||
if (*weapon != nullptr) {
|
||||
_inven_wield(attacker, *weapon, 1);
|
||||
_inven_wield(attacker, *weapon, HAND_RIGHT);
|
||||
_combat_turn_run();
|
||||
if (weaponGetActionPointCost(attacker, *hitMode, 0) <= attacker->data.critter.combat.ap) {
|
||||
return 0;
|
||||
|
||||
@@ -238,19 +238,19 @@ char* critterGetName(Object* obj)
|
||||
return gDudeName;
|
||||
}
|
||||
|
||||
if (obj->field_80 == -1) {
|
||||
if (obj->scriptIndex == -1) {
|
||||
if (obj->sid != -1) {
|
||||
Script* script;
|
||||
if (scriptGetScript(obj->sid, &script) != -1) {
|
||||
obj->field_80 = script->field_14;
|
||||
obj->scriptIndex = script->index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char* name = nullptr;
|
||||
if (obj->field_80 != -1) {
|
||||
if (obj->scriptIndex != -1) {
|
||||
MessageListItem messageListItem;
|
||||
messageListItem.num = 101 + obj->field_80;
|
||||
messageListItem.num = 101 + obj->scriptIndex;
|
||||
if (messageListGetItem(&gCritterMessageList, &messageListItem)) {
|
||||
name = messageListItem.text;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "memory.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
namespace fallout {
|
||||
@@ -13,38 +14,8 @@ namespace fallout {
|
||||
// with a check for this value.
|
||||
#define DICTIONARY_MARKER 0xFEBAFEBA
|
||||
|
||||
static void* dictionaryMallocDefaultImpl(size_t size);
|
||||
static void* dictionaryReallocDefaultImpl(void* ptr, size_t newSize);
|
||||
static void dictionaryFreeDefaultImpl(void* ptr);
|
||||
static int dictionaryFindIndexForKey(Dictionary* dictionary, const char* key, int* index);
|
||||
|
||||
// 0x51E408
|
||||
static MallocProc* gDictionaryMallocProc = dictionaryMallocDefaultImpl;
|
||||
|
||||
// 0x51E40C
|
||||
static ReallocProc* gDictionaryReallocProc = dictionaryReallocDefaultImpl;
|
||||
|
||||
// 0x51E410
|
||||
static FreeProc* gDictionaryFreeProc = dictionaryFreeDefaultImpl;
|
||||
|
||||
// 0x4D9B90
|
||||
static void* dictionaryMallocDefaultImpl(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
// 0x4D9B98
|
||||
static void* dictionaryReallocDefaultImpl(void* ptr, size_t newSize)
|
||||
{
|
||||
return realloc(ptr, newSize);
|
||||
}
|
||||
|
||||
// 0x4D9BA0
|
||||
static void dictionaryFreeDefaultImpl(void* ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
// 0x4D9BA8
|
||||
int dictionaryInit(Dictionary* dictionary, int initialCapacity, size_t valueSize, DictionaryIO* io)
|
||||
{
|
||||
@@ -64,7 +35,7 @@ int dictionaryInit(Dictionary* dictionary, int initialCapacity, size_t valueSize
|
||||
int rc = 0;
|
||||
|
||||
if (initialCapacity != 0) {
|
||||
dictionary->entries = (DictionaryEntry*)gDictionaryMallocProc(sizeof(*dictionary->entries) * initialCapacity);
|
||||
dictionary->entries = (DictionaryEntry*)internal_malloc(sizeof(*dictionary->entries) * initialCapacity);
|
||||
if (dictionary->entries == nullptr) {
|
||||
rc = -1;
|
||||
}
|
||||
@@ -90,7 +61,7 @@ int dictionarySetCapacity(Dictionary* dictionary, int newCapacity)
|
||||
return -1;
|
||||
}
|
||||
|
||||
DictionaryEntry* entries = (DictionaryEntry*)gDictionaryReallocProc(dictionary->entries, sizeof(*dictionary->entries) * newCapacity);
|
||||
DictionaryEntry* entries = (DictionaryEntry*)internal_realloc(dictionary->entries, sizeof(*dictionary->entries) * newCapacity);
|
||||
if (entries == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
@@ -111,16 +82,16 @@ int dictionaryFree(Dictionary* dictionary)
|
||||
for (int index = 0; index < dictionary->entriesLength; index++) {
|
||||
DictionaryEntry* entry = &(dictionary->entries[index]);
|
||||
if (entry->key != nullptr) {
|
||||
gDictionaryFreeProc(entry->key);
|
||||
internal_free(entry->key);
|
||||
}
|
||||
|
||||
if (entry->value != nullptr) {
|
||||
gDictionaryFreeProc(entry->value);
|
||||
internal_free(entry->value);
|
||||
}
|
||||
}
|
||||
|
||||
if (dictionary->entries != nullptr) {
|
||||
gDictionaryFreeProc(dictionary->entries);
|
||||
internal_free(dictionary->entries);
|
||||
}
|
||||
|
||||
memset(dictionary, 0, sizeof(*dictionary));
|
||||
@@ -223,7 +194,7 @@ int dictionaryAddValue(Dictionary* dictionary, const char* key, const void* valu
|
||||
}
|
||||
|
||||
// Make a copy of the key.
|
||||
char* keyCopy = (char*)gDictionaryMallocProc(strlen(key) + 1);
|
||||
char* keyCopy = (char*)internal_malloc(strlen(key) + 1);
|
||||
if (keyCopy == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
@@ -233,9 +204,9 @@ int dictionaryAddValue(Dictionary* dictionary, const char* key, const void* valu
|
||||
// Make a copy of the value.
|
||||
void* valueCopy = nullptr;
|
||||
if (value != nullptr && dictionary->valueSize != 0) {
|
||||
valueCopy = gDictionaryMallocProc(dictionary->valueSize);
|
||||
valueCopy = internal_malloc(dictionary->valueSize);
|
||||
if (valueCopy == nullptr) {
|
||||
gDictionaryFreeProc(keyCopy);
|
||||
internal_free(keyCopy);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -281,9 +252,9 @@ int dictionaryRemoveValue(Dictionary* dictionary, const char* key)
|
||||
DictionaryEntry* entry = &(dictionary->entries[indexToRemove]);
|
||||
|
||||
// Free key and value (which are copies).
|
||||
gDictionaryFreeProc(entry->key);
|
||||
internal_free(entry->key);
|
||||
if (entry->value != nullptr) {
|
||||
gDictionaryFreeProc(entry->value);
|
||||
internal_free(entry->value);
|
||||
}
|
||||
|
||||
dictionary->entriesLength--;
|
||||
@@ -398,16 +369,16 @@ int dictionaryLoad(FILE* stream, Dictionary* dictionary, int a3)
|
||||
for (int index = 0; index < dictionary->entriesLength; index++) {
|
||||
DictionaryEntry* entry = &(dictionary->entries[index]);
|
||||
if (entry->key != nullptr) {
|
||||
gDictionaryFreeProc(entry->key);
|
||||
internal_free(entry->key);
|
||||
}
|
||||
|
||||
if (entry->value != nullptr) {
|
||||
gDictionaryFreeProc(entry->value);
|
||||
internal_free(entry->value);
|
||||
}
|
||||
}
|
||||
|
||||
if (dictionary->entries != nullptr) {
|
||||
gDictionaryFreeProc(dictionary->entries);
|
||||
internal_free(dictionary->entries);
|
||||
}
|
||||
|
||||
if (dictionaryReadHeader(stream, dictionary) != 0) {
|
||||
@@ -420,7 +391,7 @@ int dictionaryLoad(FILE* stream, Dictionary* dictionary, int a3)
|
||||
return 0;
|
||||
}
|
||||
|
||||
dictionary->entries = (DictionaryEntry*)gDictionaryMallocProc(sizeof(*dictionary->entries) * dictionary->entriesCapacity);
|
||||
dictionary->entries = (DictionaryEntry*)internal_malloc(sizeof(*dictionary->entries) * dictionary->entriesCapacity);
|
||||
if (dictionary->entries == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
@@ -442,7 +413,7 @@ int dictionaryLoad(FILE* stream, Dictionary* dictionary, int a3)
|
||||
return -1;
|
||||
}
|
||||
|
||||
entry->key = (char*)gDictionaryMallocProc(keyLength + 1);
|
||||
entry->key = (char*)internal_malloc(keyLength + 1);
|
||||
if (entry->key == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
@@ -452,7 +423,7 @@ int dictionaryLoad(FILE* stream, Dictionary* dictionary, int a3)
|
||||
}
|
||||
|
||||
if (dictionary->valueSize != 0) {
|
||||
entry->value = gDictionaryMallocProc(dictionary->valueSize);
|
||||
entry->value = internal_malloc(dictionary->valueSize);
|
||||
if (entry->value == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
@@ -541,18 +512,4 @@ int dictionaryWrite(FILE* stream, Dictionary* dictionary, int a3)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4DA498
|
||||
void dictionarySetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc)
|
||||
{
|
||||
if (mallocProc != nullptr && reallocProc != nullptr && freeProc != nullptr) {
|
||||
gDictionaryMallocProc = mallocProc;
|
||||
gDictionaryReallocProc = reallocProc;
|
||||
gDictionaryFreeProc = freeProc;
|
||||
} else {
|
||||
gDictionaryMallocProc = dictionaryMallocDefaultImpl;
|
||||
gDictionaryReallocProc = dictionaryReallocDefaultImpl;
|
||||
gDictionaryFreeProc = dictionaryFreeDefaultImpl;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "memory_defs.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef int(DictionaryReadProc)(FILE* stream, void* buffer, unsigned int size, int a4);
|
||||
@@ -63,7 +61,6 @@ int dictionaryLoad(FILE* stream, Dictionary* dictionary, int a3);
|
||||
int dictionaryWriteInt(FILE* stream, int value);
|
||||
int dictionaryWriteHeader(FILE* stream, Dictionary* dictionary);
|
||||
int dictionaryWrite(FILE* stream, Dictionary* dictionary, int a3);
|
||||
void dictionarySetMemoryProcs(MallocProc* mallocProc, ReallocProc* reallocProc, FreeProc* freeProc);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
|
||||
@@ -103,9 +103,9 @@ typedef struct GameDialogOptionEntry {
|
||||
int reaction;
|
||||
int proc;
|
||||
int btn;
|
||||
int field_14;
|
||||
int top;
|
||||
char text[900];
|
||||
int field_39C;
|
||||
int bottom;
|
||||
} GameDialogOptionEntry;
|
||||
|
||||
// Provides button configuration for party member combat control and
|
||||
@@ -587,7 +587,10 @@ static void _demo_copy_title(int win);
|
||||
static void _demo_copy_options(int win);
|
||||
static void _gDialogRefreshOptionsRect(int win, Rect* drawRect);
|
||||
static void gameDialogTicker();
|
||||
static void _gdialog_scroll_subwin(int a1, int a2, unsigned char* a3, unsigned char* a4, unsigned char* a5, int a6, int a7);
|
||||
// Animates scroll up or down of a given dialog sub-window.
|
||||
// If scrolling up - only uses subWindowFrmData to gradually fill the window (must be pre-filled with bg window contents).
|
||||
// If scroliing down - uses both subWindowFrmData and bgWindowFrmData to fill parts of window buffer.
|
||||
static void _gdialog_scroll_subwin(int windowIdx, bool scrollUp, unsigned char* subWindowFrmData, unsigned char* windowBuf, unsigned char* bgWindowFrmData, int windowHeight, bool instantScrollUp = false);
|
||||
static int _text_num_lines(const char* a1, int a2);
|
||||
static int text_to_rect_wrapped(unsigned char* buffer, Rect* rect, char* string, int* a4, int height, int pitch, int color);
|
||||
static int gameDialogDrawText(unsigned char* buffer, Rect* rect, char* string, int* a4, int height, int pitch, int color, int a7);
|
||||
@@ -2103,9 +2106,9 @@ void gameDialogOptionOnMouseEnter(int index)
|
||||
}
|
||||
|
||||
_optionRect.left = 0;
|
||||
_optionRect.top = dialogOptionEntry->field_14;
|
||||
_optionRect.top = dialogOptionEntry->top;
|
||||
_optionRect.right = 391;
|
||||
_optionRect.bottom = dialogOptionEntry->field_39C;
|
||||
_optionRect.bottom = dialogOptionEntry->bottom;
|
||||
_gDialogRefreshOptionsRect(gGameDialogOptionsWindow, &_optionRect);
|
||||
|
||||
_optionRect.left = 5;
|
||||
@@ -2140,7 +2143,7 @@ void gameDialogOptionOnMouseEnter(int index)
|
||||
|
||||
_optionRect.left = 0;
|
||||
_optionRect.right = 391;
|
||||
_optionRect.top = dialogOptionEntry->field_14;
|
||||
_optionRect.top = dialogOptionEntry->top;
|
||||
windowRefreshRect(gGameDialogOptionsWindow, &_optionRect);
|
||||
}
|
||||
|
||||
@@ -2150,9 +2153,9 @@ void gameDialogOptionOnMouseExit(int index)
|
||||
GameDialogOptionEntry* dialogOptionEntry = &(gDialogOptionEntries[index]);
|
||||
|
||||
_optionRect.left = 0;
|
||||
_optionRect.top = dialogOptionEntry->field_14;
|
||||
_optionRect.top = dialogOptionEntry->top;
|
||||
_optionRect.right = 391;
|
||||
_optionRect.bottom = dialogOptionEntry->field_39C;
|
||||
_optionRect.bottom = dialogOptionEntry->bottom;
|
||||
_gDialogRefreshOptionsRect(gGameDialogOptionsWindow, &_optionRect);
|
||||
|
||||
int color = _colorTable[992] | 0x2000000;
|
||||
@@ -2187,7 +2190,7 @@ void gameDialogOptionOnMouseExit(int index)
|
||||
color);
|
||||
|
||||
_optionRect.right = 391;
|
||||
_optionRect.top = dialogOptionEntry->field_14;
|
||||
_optionRect.top = dialogOptionEntry->top;
|
||||
_optionRect.left = 0;
|
||||
windowRefreshRect(gGameDialogOptionsWindow, &_optionRect);
|
||||
}
|
||||
@@ -2330,12 +2333,12 @@ void _gdProcessUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
int v11 = _text_num_lines(dialogOptionEntry->text, _optionRect.right - _optionRect.left) * fontGetLineHeight() + _optionRect.top + 2;
|
||||
if (v11 < _optionRect.bottom) {
|
||||
int estimate = _text_num_lines(dialogOptionEntry->text, _optionRect.right - _optionRect.left) * fontGetLineHeight() + _optionRect.top + 2;
|
||||
if (estimate < _optionRect.bottom) {
|
||||
int y = _optionRect.top;
|
||||
|
||||
dialogOptionEntry->field_39C = v11;
|
||||
dialogOptionEntry->field_14 = y;
|
||||
dialogOptionEntry->bottom = estimate;
|
||||
dialogOptionEntry->top = y;
|
||||
|
||||
if (index == 0) {
|
||||
y = 0;
|
||||
@@ -2350,6 +2353,7 @@ void _gdProcessUpdate()
|
||||
393,
|
||||
color);
|
||||
|
||||
dialogOptionEntry->bottom = _optionRect.top;
|
||||
_optionRect.top += 2;
|
||||
|
||||
dialogOptionEntry->btn = buttonCreate(gGameDialogOptionsWindow, 2, y, width, _optionRect.top - y - 4, 1200 + index, 1300 + index, -1, 49 + index, nullptr, nullptr, nullptr, 0);
|
||||
@@ -2932,44 +2936,42 @@ void _talk_to_critter_reacts(int a1)
|
||||
}
|
||||
|
||||
// 0x447D98
|
||||
void _gdialog_scroll_subwin(int win, int a2, unsigned char* a3, unsigned char* a4, unsigned char* a5, int a6, int a7)
|
||||
void _gdialog_scroll_subwin(int windowIdx, bool scrollUp, unsigned char* windowFrmData, unsigned char* windowBuf, unsigned char* bgWindowFrmData, int windowHeight, bool instantScrollUp)
|
||||
{
|
||||
int v7;
|
||||
unsigned char* v9;
|
||||
constexpr int stripHeight = 10;
|
||||
int height = windowHeight;
|
||||
unsigned char* dest = windowBuf;
|
||||
Rect rect;
|
||||
|
||||
v7 = a6;
|
||||
v9 = a4;
|
||||
|
||||
if (a2 == 1) {
|
||||
if (scrollUp) {
|
||||
rect.left = 0;
|
||||
rect.right = GAME_DIALOG_WINDOW_WIDTH - 1;
|
||||
rect.bottom = a6 - 1;
|
||||
rect.bottom = windowHeight - 1;
|
||||
|
||||
int v18 = a6 / 10;
|
||||
if (a7 == -1) {
|
||||
rect.top = 10;
|
||||
v18 = 0;
|
||||
int strips = windowHeight / stripHeight;
|
||||
if (instantScrollUp) {
|
||||
rect.top = stripHeight;
|
||||
strips = 0;
|
||||
} else {
|
||||
rect.top = v18 * 10;
|
||||
v7 = a6 % 10;
|
||||
v9 += GAME_DIALOG_WINDOW_WIDTH * rect.top;
|
||||
rect.top = strips * stripHeight;
|
||||
height = windowHeight % stripHeight;
|
||||
dest += GAME_DIALOG_WINDOW_WIDTH * rect.top;
|
||||
}
|
||||
|
||||
for (; v18 >= 0; v18--) {
|
||||
for (; strips >= 0; strips--) {
|
||||
sharedFpsLimiter.mark();
|
||||
|
||||
soundContinueAll();
|
||||
blitBufferToBuffer(a3,
|
||||
blitBufferToBuffer(windowFrmData,
|
||||
GAME_DIALOG_WINDOW_WIDTH,
|
||||
v7,
|
||||
height,
|
||||
GAME_DIALOG_WINDOW_WIDTH,
|
||||
v9,
|
||||
dest,
|
||||
GAME_DIALOG_WINDOW_WIDTH);
|
||||
rect.top -= 10;
|
||||
windowRefreshRect(win, &rect);
|
||||
v7 += 10;
|
||||
v9 -= 10 * (GAME_DIALOG_WINDOW_WIDTH);
|
||||
rect.top -= stripHeight;
|
||||
windowRefreshRect(windowIdx, &rect);
|
||||
height += stripHeight;
|
||||
dest -= stripHeight * (GAME_DIALOG_WINDOW_WIDTH);
|
||||
|
||||
delay_ms(33);
|
||||
|
||||
@@ -2978,36 +2980,36 @@ void _gdialog_scroll_subwin(int win, int a2, unsigned char* a3, unsigned char* a
|
||||
}
|
||||
} else {
|
||||
rect.right = GAME_DIALOG_WINDOW_WIDTH - 1;
|
||||
rect.bottom = a6 - 1;
|
||||
rect.bottom = windowHeight - 1;
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
|
||||
for (int index = a6 / 10; index > 0; index--) {
|
||||
for (int strips = windowHeight / stripHeight; strips > 0; strips--) {
|
||||
sharedFpsLimiter.mark();
|
||||
|
||||
soundContinueAll();
|
||||
|
||||
blitBufferToBuffer(a5,
|
||||
blitBufferToBuffer(bgWindowFrmData,
|
||||
GAME_DIALOG_WINDOW_WIDTH,
|
||||
10,
|
||||
stripHeight,
|
||||
GAME_DIALOG_WINDOW_WIDTH,
|
||||
v9,
|
||||
dest,
|
||||
GAME_DIALOG_WINDOW_WIDTH);
|
||||
|
||||
v9 += 10 * (GAME_DIALOG_WINDOW_WIDTH);
|
||||
v7 -= 10;
|
||||
a5 += 10 * (GAME_DIALOG_WINDOW_WIDTH);
|
||||
dest += stripHeight * (GAME_DIALOG_WINDOW_WIDTH);
|
||||
height -= stripHeight;
|
||||
bgWindowFrmData += stripHeight * (GAME_DIALOG_WINDOW_WIDTH);
|
||||
|
||||
blitBufferToBuffer(a3,
|
||||
blitBufferToBuffer(windowFrmData,
|
||||
GAME_DIALOG_WINDOW_WIDTH,
|
||||
v7,
|
||||
height,
|
||||
GAME_DIALOG_WINDOW_WIDTH,
|
||||
v9,
|
||||
dest,
|
||||
GAME_DIALOG_WINDOW_WIDTH);
|
||||
|
||||
windowRefreshRect(win, &rect);
|
||||
windowRefreshRect(windowIdx, &rect);
|
||||
|
||||
rect.top += 10;
|
||||
rect.top += stripHeight;
|
||||
|
||||
delay_ms(33);
|
||||
|
||||
@@ -3228,7 +3230,7 @@ int _gdialog_barter_create_win()
|
||||
unsigned char* backgroundWindowBuffer = windowGetBuffer(gGameDialogBackgroundWindow);
|
||||
blitBufferToBuffer(backgroundWindowBuffer + width * (480 - _dialogue_subwin_len), width, _dialogue_subwin_len, width, windowBuffer, width);
|
||||
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, 1, backgroundData, windowBuffer, nullptr, _dialogue_subwin_len, 0);
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, true, backgroundData, windowBuffer, nullptr, _dialogue_subwin_len);
|
||||
|
||||
backgroundFrmImage.unlock();
|
||||
|
||||
@@ -3306,7 +3308,7 @@ void _gdialog_barter_destroy_win()
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, frmId, 0, 0, 0);
|
||||
if (backgroundFrmImage.lock(backgroundFid)) {
|
||||
unsigned char* windowBuffer = windowGetBuffer(gGameDialogWindow);
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, 0, backgroundFrmImage.getData(), windowBuffer, backgroundWindowBuffer, _dialogue_subwin_len, 0);
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, false, backgroundFrmImage.getData(), windowBuffer, backgroundWindowBuffer, _dialogue_subwin_len);
|
||||
}
|
||||
|
||||
windowDestroy(gGameDialogWindow);
|
||||
@@ -3380,7 +3382,7 @@ int partyMemberControlWindowInit()
|
||||
unsigned char* windowBuffer = windowGetBuffer(gGameDialogWindow);
|
||||
unsigned char* src = windowGetBuffer(gGameDialogBackgroundWindow);
|
||||
blitBufferToBuffer(src + (GAME_DIALOG_WINDOW_WIDTH) * (GAME_DIALOG_WINDOW_HEIGHT - _dialogue_subwin_len), GAME_DIALOG_WINDOW_WIDTH, _dialogue_subwin_len, GAME_DIALOG_WINDOW_WIDTH, windowBuffer, GAME_DIALOG_WINDOW_WIDTH);
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, 1, backgroundData, windowBuffer, nullptr, _dialogue_subwin_len, 0);
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, true, backgroundData, windowBuffer, nullptr, _dialogue_subwin_len);
|
||||
backgroundFrmImage.unlock();
|
||||
|
||||
// TALK
|
||||
@@ -3529,7 +3531,7 @@ void partyMemberControlWindowFree()
|
||||
FrmImage backgroundFrmImage;
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 390, 0, 0, 0);
|
||||
if (backgroundFrmImage.lock(backgroundFid)) {
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, 0, backgroundFrmImage.getData(), windowGetBuffer(gGameDialogWindow), windowGetBuffer(gGameDialogBackgroundWindow) + (GAME_DIALOG_WINDOW_WIDTH) * (480 - _dialogue_subwin_len), _dialogue_subwin_len, 0);
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, false, backgroundFrmImage.getData(), windowGetBuffer(gGameDialogWindow), windowGetBuffer(gGameDialogBackgroundWindow) + (GAME_DIALOG_WINDOW_WIDTH) * (480 - _dialogue_subwin_len), _dialogue_subwin_len);
|
||||
}
|
||||
|
||||
windowDestroy(gGameDialogWindow);
|
||||
@@ -3715,7 +3717,7 @@ void partyMemberControlWindowHandleEvents()
|
||||
|
||||
Object* weapon = _ai_search_inven_weap(gGameDialogSpeaker, 0, nullptr);
|
||||
if (weapon != nullptr) {
|
||||
_inven_wield(gGameDialogSpeaker, weapon, 1);
|
||||
_inven_wield(gGameDialogSpeaker, weapon, HAND_RIGHT);
|
||||
aiAttemptWeaponReload(gGameDialogSpeaker, 0);
|
||||
|
||||
int num = _gdPickAIUpdateMsg(gGameDialogSpeaker);
|
||||
@@ -3826,7 +3828,7 @@ int partyMemberCustomizationWindowInit()
|
||||
windowBuffer,
|
||||
GAME_DIALOG_WINDOW_WIDTH);
|
||||
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, 1, backgroundFrmData, windowBuffer, nullptr, _dialogue_subwin_len, 0);
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, true, backgroundFrmData, windowBuffer, nullptr, _dialogue_subwin_len);
|
||||
backgroundFrmImage.unlock();
|
||||
|
||||
_gdialog_buttons[0] = buttonCreate(gGameDialogWindow, 593, 101, 14, 14, -1, -1, -1, 13, _redButtonNormalFrmImage.getData(), _redButtonPressedFrmImage.getData(), nullptr, BUTTON_FLAG_TRANSPARENT);
|
||||
@@ -3934,7 +3936,7 @@ void partyMemberCustomizationWindowFree()
|
||||
// custom.frm - party member control interface
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 391, 0, 0, 0);
|
||||
if (backgroundFrmImage.lock(backgroundFid)) {
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, 0, backgroundFrmImage.getData(), windowGetBuffer(gGameDialogWindow), windowGetBuffer(gGameDialogBackgroundWindow) + (GAME_DIALOG_WINDOW_WIDTH) * (480 - _dialogue_subwin_len), _dialogue_subwin_len, 0);
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, false, backgroundFrmImage.getData(), windowGetBuffer(gGameDialogWindow), windowGetBuffer(gGameDialogBackgroundWindow) + (GAME_DIALOG_WINDOW_WIDTH) * (480 - _dialogue_subwin_len), _dialogue_subwin_len);
|
||||
}
|
||||
|
||||
windowDestroy(gGameDialogWindow);
|
||||
@@ -4339,17 +4341,17 @@ int _gdialog_window_create()
|
||||
gGameDialogWindow = windowCreate(dialogSubwindowX, dialogSubwindowY, screenWidth, _dialogue_subwin_len, 256, WINDOW_DONT_MOVE_TOP);
|
||||
if (gGameDialogWindow != -1) {
|
||||
|
||||
unsigned char* v10 = windowGetBuffer(gGameDialogWindow);
|
||||
unsigned char* v14 = windowGetBuffer(gGameDialogBackgroundWindow);
|
||||
unsigned char* windowBuf = windowGetBuffer(gGameDialogWindow);
|
||||
unsigned char* bgWindowBuf = windowGetBuffer(gGameDialogBackgroundWindow);
|
||||
// TODO: Not sure about offsets.
|
||||
blitBufferToBuffer(v14 + screenWidth * (GAME_DIALOG_WINDOW_HEIGHT - _dialogue_subwin_len), screenWidth, _dialogue_subwin_len, screenWidth, v10, screenWidth);
|
||||
blitBufferToBuffer(bgWindowBuf + screenWidth * (GAME_DIALOG_WINDOW_HEIGHT - _dialogue_subwin_len), screenWidth, _dialogue_subwin_len, screenWidth, windowBuf, screenWidth);
|
||||
|
||||
if (_dialogue_just_started) {
|
||||
windowRefresh(gGameDialogBackgroundWindow);
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, 1, backgroundFrmData, v10, nullptr, _dialogue_subwin_len, -1);
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, true, backgroundFrmData, windowBuf, nullptr, _dialogue_subwin_len, true);
|
||||
_dialogue_just_started = 0;
|
||||
} else {
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, 1, backgroundFrmData, v10, nullptr, _dialogue_subwin_len, 0);
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, true, backgroundFrmData, windowBuf, nullptr, _dialogue_subwin_len, false);
|
||||
}
|
||||
|
||||
// BARTER/TRADE
|
||||
@@ -4438,7 +4440,7 @@ void _gdialog_window_destroy()
|
||||
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, frmId, 0, 0, 0);
|
||||
if (backgroundFrmImage.lock(backgroundFid)) {
|
||||
unsigned char* windowBuffer = windowGetBuffer(gGameDialogWindow);
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, 0, backgroundFrmImage.getData(), windowBuffer, backgroundWindowBuffer, _dialogue_subwin_len, 0);
|
||||
_gdialog_scroll_subwin(gGameDialogWindow, false, backgroundFrmImage.getData(), windowBuffer, backgroundWindowBuffer, _dialogue_subwin_len);
|
||||
windowDestroy(gGameDialogWindow);
|
||||
_gdialog_window_created = 0;
|
||||
gGameDialogWindow = -1;
|
||||
@@ -4457,7 +4459,7 @@ static int talk_to_create_background_window()
|
||||
GAME_DIALOG_WINDOW_WIDTH,
|
||||
GAME_DIALOG_WINDOW_HEIGHT,
|
||||
256,
|
||||
WINDOW_DONT_MOVE_TOP);
|
||||
WINDOW_DONT_MOVE_TOP | WINDOW_MODAL);
|
||||
|
||||
if (gGameDialogBackgroundWindow != -1) {
|
||||
return 0;
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
#include "game_memory.h"
|
||||
|
||||
#include "db.h"
|
||||
#include "dictionary.h"
|
||||
#include "memory.h"
|
||||
#include "memory_defs.h"
|
||||
#include "memory_manager.h"
|
||||
|
||||
namespace fallout {
|
||||
@@ -15,7 +12,6 @@ static void gameMemoryFree(void* ptr);
|
||||
// 0x44B250
|
||||
int gameMemoryInit()
|
||||
{
|
||||
dictionarySetMemoryProcs(internal_malloc, internal_realloc, internal_free);
|
||||
memoryManagerSetProcs(gameMemoryMalloc, gameMemoryRealloc, gameMemoryFree);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -318,7 +318,7 @@ static int gameMouseActionMenuInit();
|
||||
static void gameMouseActionMenuFree();
|
||||
static int gmouse_3d_set_flat_fid(int fid, Rect* rect);
|
||||
static int gameMouseUpdateHexCursorFid(Rect* rect);
|
||||
static int _gmouse_3d_move_to(int x, int y, int elevation, Rect* a4);
|
||||
static int _gmouse_3d_move_to(int x, int y, int elevation, Rect* rect);
|
||||
static int gameMouseHandleScrolling(int x, int y, int cursor);
|
||||
static int objectIsDoor(Object* object);
|
||||
static bool gameMouseClickOnInterfaceBar();
|
||||
@@ -950,46 +950,46 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
}
|
||||
|
||||
if (gGameMouseMode == GAME_MOUSE_MODE_ARROW) {
|
||||
Object* v5 = gameMouseGetObjectUnderCursor(-1, true, gElevation);
|
||||
if (v5 != nullptr) {
|
||||
switch (FID_TYPE(v5->fid)) {
|
||||
Object* targetObj = gameMouseGetObjectUnderCursor(-1, true, gElevation);
|
||||
if (targetObj != nullptr) {
|
||||
switch (FID_TYPE(targetObj->fid)) {
|
||||
case OBJ_TYPE_ITEM:
|
||||
actionPickUp(gDude, v5);
|
||||
actionPickUp(gDude, targetObj);
|
||||
break;
|
||||
case OBJ_TYPE_CRITTER:
|
||||
if (v5 == gDude) {
|
||||
if (targetObj == gDude) {
|
||||
if (FID_ANIM_TYPE(gDude->fid) == ANIM_STAND) {
|
||||
Rect a1;
|
||||
if (objectRotateClockwise(v5, &a1) == 0) {
|
||||
tileWindowRefreshRect(&a1, v5->elevation);
|
||||
Rect dudeRect;
|
||||
if (objectRotateClockwise(targetObj, &dudeRect) == 0) {
|
||||
tileWindowRefreshRect(&dudeRect, targetObj->elevation);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (_obj_action_can_talk_to(v5)) {
|
||||
if (_obj_action_can_talk_to(targetObj)) {
|
||||
if (isInCombat()) {
|
||||
if (_obj_examine(gDude, v5) == -1) {
|
||||
_obj_look_at(gDude, v5);
|
||||
if (_obj_examine(gDude, targetObj) == -1) {
|
||||
_obj_look_at(gDude, targetObj);
|
||||
}
|
||||
} else {
|
||||
actionTalk(gDude, v5);
|
||||
actionTalk(gDude, targetObj);
|
||||
}
|
||||
} else {
|
||||
_action_loot_container(gDude, v5);
|
||||
_action_loot_container(gDude, targetObj);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJ_TYPE_SCENERY:
|
||||
if (_obj_action_can_use(v5)) {
|
||||
_action_use_an_object(gDude, v5);
|
||||
if (_obj_action_can_use(targetObj)) {
|
||||
_action_use_an_object(gDude, targetObj);
|
||||
} else {
|
||||
if (_obj_examine(gDude, v5) == -1) {
|
||||
_obj_look_at(gDude, v5);
|
||||
if (_obj_examine(gDude, targetObj) == -1) {
|
||||
_obj_look_at(gDude, targetObj);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJ_TYPE_WALL:
|
||||
if (_obj_examine(gDude, v5) == -1) {
|
||||
_obj_look_at(gDude, v5);
|
||||
if (_obj_examine(gDude, targetObj) == -1) {
|
||||
_obj_look_at(gDude, targetObj);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -998,16 +998,16 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
}
|
||||
|
||||
if (gGameMouseMode == GAME_MOUSE_MODE_CROSSHAIR) {
|
||||
Object* v7 = gameMouseGetObjectUnderCursor(OBJ_TYPE_CRITTER, false, gElevation);
|
||||
if (v7 == nullptr) {
|
||||
v7 = gameMouseGetObjectUnderCursor(-1, false, gElevation);
|
||||
if (!objectIsDoor(v7)) {
|
||||
v7 = nullptr;
|
||||
Object* targetObj = gameMouseGetObjectUnderCursor(OBJ_TYPE_CRITTER, false, gElevation);
|
||||
if (targetObj == nullptr) {
|
||||
targetObj = gameMouseGetObjectUnderCursor(-1, false, gElevation);
|
||||
if (!objectIsDoor(targetObj)) {
|
||||
targetObj = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (v7 != nullptr) {
|
||||
_combat_attack_this(v7);
|
||||
if (targetObj != nullptr) {
|
||||
_combat_attack_this(targetObj);
|
||||
_gmouse_3d_hover_test = true;
|
||||
gGameMouseLastY = mouseY;
|
||||
gGameMouseLastX = mouseX;
|
||||
@@ -1065,35 +1065,35 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
}
|
||||
|
||||
if ((mouseState & MOUSE_EVENT_LEFT_BUTTON_DOWN_REPEAT) == MOUSE_EVENT_LEFT_BUTTON_DOWN_REPEAT && gGameMouseMode == GAME_MOUSE_MODE_ARROW) {
|
||||
Object* v16 = gameMouseGetObjectUnderCursor(-1, true, gElevation);
|
||||
if (v16 != nullptr) {
|
||||
Object* targetObj = gameMouseGetObjectUnderCursor(-1, true, gElevation);
|
||||
if (targetObj != nullptr) {
|
||||
int actionMenuItemsCount = 0;
|
||||
int actionMenuItems[6];
|
||||
switch (FID_TYPE(v16->fid)) {
|
||||
switch (FID_TYPE(targetObj->fid)) {
|
||||
case OBJ_TYPE_ITEM:
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_USE;
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_LOOK;
|
||||
if (itemGetType(v16) == ITEM_TYPE_CONTAINER) {
|
||||
if (itemGetType(targetObj) == ITEM_TYPE_CONTAINER) {
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_INVENTORY;
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_USE_SKILL;
|
||||
}
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_CANCEL;
|
||||
break;
|
||||
case OBJ_TYPE_CRITTER:
|
||||
if (v16 == gDude) {
|
||||
if (targetObj == gDude) {
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_ROTATE;
|
||||
} else {
|
||||
if (_obj_action_can_talk_to(v16)) {
|
||||
if (_obj_action_can_talk_to(targetObj)) {
|
||||
if (!isInCombat()) {
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_TALK;
|
||||
}
|
||||
} else {
|
||||
if (!_critter_flag_check(v16->pid, CRITTER_NO_STEAL)) {
|
||||
if (!_critter_flag_check(targetObj->pid, CRITTER_NO_STEAL)) {
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_USE;
|
||||
}
|
||||
}
|
||||
|
||||
if (actionCheckPush(gDude, v16)) {
|
||||
if (actionCheckPush(gDude, targetObj)) {
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_PUSH;
|
||||
}
|
||||
}
|
||||
@@ -1104,7 +1104,7 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_CANCEL;
|
||||
break;
|
||||
case OBJ_TYPE_SCENERY:
|
||||
if (_obj_action_can_use(v16)) {
|
||||
if (_obj_action_can_use(targetObj)) {
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_USE;
|
||||
}
|
||||
|
||||
@@ -1115,7 +1115,7 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
break;
|
||||
case OBJ_TYPE_WALL:
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_LOOK;
|
||||
if (_obj_action_can_use(v16)) {
|
||||
if (_obj_action_can_use(targetObj)) {
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_INVENTORY;
|
||||
}
|
||||
actionMenuItems[actionMenuItemsCount++] = GAME_MOUSE_ACTION_MENU_ITEM_CANCEL;
|
||||
@@ -1123,14 +1123,14 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
}
|
||||
|
||||
if (gameMouseRenderActionMenuItems(mouseX, mouseY, actionMenuItems, actionMenuItemsCount, _scr_size.right - _scr_size.left + 1, _scr_size.bottom - _scr_size.top - 99) == 0) {
|
||||
Rect v43;
|
||||
Rect cursorRect;
|
||||
int fid = buildFid(OBJ_TYPE_INTERFACE, 283, 0, 0, 0);
|
||||
// NOTE: Uninline.
|
||||
if (gmouse_3d_set_flat_fid(fid, &v43) == 0 && _gmouse_3d_move_to(mouseX, mouseY, gElevation, &v43) == 0) {
|
||||
tileWindowRefreshRect(&v43, gElevation);
|
||||
if (gmouse_3d_set_flat_fid(fid, &cursorRect) == 0 && _gmouse_3d_move_to(mouseX, mouseY, gElevation, &cursorRect) == 0) {
|
||||
tileWindowRefreshRect(&cursorRect, gElevation);
|
||||
isoDisable();
|
||||
|
||||
int v33 = mouseY;
|
||||
int newMouseY = mouseY;
|
||||
int actionIndex = 0;
|
||||
while ((mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_UP) == 0) {
|
||||
sharedFpsLimiter.mark();
|
||||
@@ -1141,21 +1141,21 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
actionMenuItems[actionIndex] = 0;
|
||||
}
|
||||
|
||||
int v48;
|
||||
int v47;
|
||||
mouseGetPosition(&v48, &v47);
|
||||
int updatedMouseX;
|
||||
int updatedMouseY;
|
||||
mouseGetPosition(&updatedMouseX, &updatedMouseY);
|
||||
|
||||
if (abs(v47 - v33) > 10) {
|
||||
if (v33 >= v47) {
|
||||
if (abs(updatedMouseY - newMouseY) > 10) {
|
||||
if (newMouseY >= updatedMouseY) {
|
||||
actionIndex -= 1;
|
||||
} else {
|
||||
actionIndex += 1;
|
||||
}
|
||||
|
||||
if (gameMouseHighlightActionMenuItemAtIndex(actionIndex) == 0) {
|
||||
tileWindowRefreshRect(&v43, gElevation);
|
||||
tileWindowRefreshRect(&cursorRect, gElevation);
|
||||
}
|
||||
v33 = v47;
|
||||
newMouseY = updatedMouseY;
|
||||
}
|
||||
|
||||
renderPresent();
|
||||
@@ -1169,39 +1169,39 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
gGameMouseLastY = mouseY;
|
||||
_gmouse_3d_last_move_time = getTicks();
|
||||
|
||||
_mouse_set_position(mouseX, v33);
|
||||
_mouse_set_position(mouseX, newMouseY);
|
||||
|
||||
if (gameMouseUpdateHexCursorFid(&v43) == 0) {
|
||||
tileWindowRefreshRect(&v43, gElevation);
|
||||
if (gameMouseUpdateHexCursorFid(&cursorRect) == 0) {
|
||||
tileWindowRefreshRect(&cursorRect, gElevation);
|
||||
}
|
||||
|
||||
switch (actionMenuItems[actionIndex]) {
|
||||
case GAME_MOUSE_ACTION_MENU_ITEM_INVENTORY:
|
||||
inventoryOpenUseItemOn(v16);
|
||||
inventoryOpenUseItemOn(targetObj);
|
||||
break;
|
||||
case GAME_MOUSE_ACTION_MENU_ITEM_LOOK:
|
||||
if (_obj_examine(gDude, v16) == -1) {
|
||||
_obj_look_at(gDude, v16);
|
||||
if (_obj_examine(gDude, targetObj) == -1) {
|
||||
_obj_look_at(gDude, targetObj);
|
||||
}
|
||||
break;
|
||||
case GAME_MOUSE_ACTION_MENU_ITEM_ROTATE:
|
||||
if (objectRotateClockwise(v16, &v43) == 0) {
|
||||
tileWindowRefreshRect(&v43, v16->elevation);
|
||||
if (objectRotateClockwise(targetObj, &cursorRect) == 0) {
|
||||
tileWindowRefreshRect(&cursorRect, targetObj->elevation);
|
||||
}
|
||||
break;
|
||||
case GAME_MOUSE_ACTION_MENU_ITEM_TALK:
|
||||
actionTalk(gDude, v16);
|
||||
actionTalk(gDude, targetObj);
|
||||
break;
|
||||
case GAME_MOUSE_ACTION_MENU_ITEM_USE:
|
||||
switch (FID_TYPE(v16->fid)) {
|
||||
switch (FID_TYPE(targetObj->fid)) {
|
||||
case OBJ_TYPE_SCENERY:
|
||||
_action_use_an_object(gDude, v16);
|
||||
_action_use_an_object(gDude, targetObj);
|
||||
break;
|
||||
case OBJ_TYPE_CRITTER:
|
||||
_action_loot_container(gDude, v16);
|
||||
_action_loot_container(gDude, targetObj);
|
||||
break;
|
||||
default:
|
||||
actionPickUp(gDude, v16);
|
||||
actionPickUp(gDude, targetObj);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1238,12 +1238,12 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
||||
}
|
||||
|
||||
if (skill != -1) {
|
||||
actionUseSkill(gDude, v16, skill);
|
||||
actionUseSkill(gDude, targetObj, skill);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GAME_MOUSE_ACTION_MENU_ITEM_PUSH:
|
||||
actionPush(gDude, v16);
|
||||
actionPush(gDude, targetObj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1370,9 +1370,9 @@ void gameMouseSetMode(int mode)
|
||||
int mouseY;
|
||||
mouseGetPosition(&mouseX, &mouseY);
|
||||
|
||||
Rect r2;
|
||||
if (_gmouse_3d_move_to(mouseX, mouseY, gElevation, &r2) == 0) {
|
||||
rectUnion(&rect, &r2, &rect);
|
||||
Rect cursorRect;
|
||||
if (_gmouse_3d_move_to(mouseX, mouseY, gElevation, &cursorRect) == 0) {
|
||||
rectUnion(&rect, &cursorRect, &rect);
|
||||
}
|
||||
|
||||
int v5 = 0;
|
||||
@@ -1386,13 +1386,13 @@ void gameMouseSetMode(int mode)
|
||||
}
|
||||
|
||||
if (gGameMouseMode == 0) {
|
||||
if (objectDisableOutline(gGameMouseHexCursor, &r2) == 0) {
|
||||
rectUnion(&rect, &r2, &rect);
|
||||
if (objectDisableOutline(gGameMouseHexCursor, &cursorRect) == 0) {
|
||||
rectUnion(&rect, &cursorRect, &rect);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (objectEnableOutline(gGameMouseHexCursor, &r2) == 0) {
|
||||
rectUnion(&rect, &r2, &rect);
|
||||
if (objectEnableOutline(gGameMouseHexCursor, &cursorRect) == 0) {
|
||||
rectUnion(&rect, &cursorRect, &rect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2193,7 +2193,7 @@ int gameMouseUpdateHexCursorFid(Rect* rect)
|
||||
}
|
||||
|
||||
// 0x44DF94
|
||||
int _gmouse_3d_move_to(int x, int y, int elevation, Rect* a4)
|
||||
int _gmouse_3d_move_to(int x, int y, int elevation, Rect* rect)
|
||||
{
|
||||
if (_gmouse_mapper_mode == 0) {
|
||||
if (gGameMouseMode != GAME_MOUSE_MODE_MOVE) {
|
||||
@@ -2214,7 +2214,7 @@ int _gmouse_3d_move_to(int x, int y, int elevation, Rect* a4)
|
||||
artUnlock(hexCursorFrmHandle);
|
||||
}
|
||||
|
||||
_obj_move(gGameMouseHexCursor, x + offsetX, y + offsetY, elevation, a4);
|
||||
_obj_move(gGameMouseHexCursor, x + offsetX, y + offsetY, elevation, rect);
|
||||
} else {
|
||||
int tile = tileFromScreenXY(x, y, 0);
|
||||
if (tile != -1) {
|
||||
@@ -2237,7 +2237,7 @@ int _gmouse_3d_move_to(int x, int y, int elevation, Rect* a4)
|
||||
rectCopy(&rect1, &rect2);
|
||||
}
|
||||
|
||||
rectCopy(a4, &rect1);
|
||||
rectCopy(rect, &rect1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2323,7 +2323,7 @@ int _gmouse_3d_move_to(int x, int y, int elevation, Rect* a4)
|
||||
}
|
||||
|
||||
if (v1) {
|
||||
rectCopy(a4, &rect1);
|
||||
rectCopy(rect, &rect1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,14 +6,6 @@
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum Hand {
|
||||
// Item1 (Punch)
|
||||
HAND_LEFT,
|
||||
// Item2 (Kick)
|
||||
HAND_RIGHT,
|
||||
HAND_COUNT,
|
||||
} Hand;
|
||||
|
||||
#define INDICATOR_BOX_WIDTH 130
|
||||
#define INDICATOR_BOX_HEIGHT 21
|
||||
|
||||
|
||||
@@ -482,7 +482,7 @@ static void opScrReturn(Program* program)
|
||||
|
||||
Script* script;
|
||||
if (scriptGetScript(sid, &script) != -1) {
|
||||
script->field_28 = data;
|
||||
script->returnValue = data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -934,7 +934,7 @@ static void opCreateObject(Program* program)
|
||||
goto out;
|
||||
}
|
||||
|
||||
script->field_14 = sid - 1;
|
||||
script->index = sid - 1;
|
||||
|
||||
if (scriptType == SCRIPT_TYPE_SPATIAL) {
|
||||
script->sp.built_tile = builtTileCreate(object->tile, object->elevation);
|
||||
@@ -942,7 +942,7 @@ static void opCreateObject(Program* program)
|
||||
}
|
||||
|
||||
object->id = scriptsNewObjectId();
|
||||
script->field_1C = object->id;
|
||||
script->ownerId = object->id;
|
||||
script->owner = object;
|
||||
_scr_find_str_run_info(sid - 1, &(script->field_50), object->sid);
|
||||
};
|
||||
|
||||
765
src/inventory.cc
765
src/inventory.cc
File diff suppressed because it is too large
Load Diff
@@ -5,28 +5,41 @@
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum Hand {
|
||||
// Item1 (Punch)
|
||||
HAND_LEFT,
|
||||
// Item2 (Kick)
|
||||
HAND_RIGHT,
|
||||
HAND_COUNT,
|
||||
} Hand;
|
||||
|
||||
typedef void InventoryPrintItemDescriptionHandler(char* string);
|
||||
|
||||
void _inven_reset_dude();
|
||||
void inventoryOpen();
|
||||
void _adjust_ac(Object* critter, Object* oldArmor, Object* newArmor);
|
||||
void inventoryOpenUseItemOn(Object* a1);
|
||||
Object* critterGetItem2(Object* obj);
|
||||
Object* critterGetItem1(Object* obj);
|
||||
Object* critterGetArmor(Object* obj);
|
||||
void inventoryOpenUseItemOn(Object* targetObj);
|
||||
Object* critterGetItem2(Object* critter);
|
||||
Object* critterGetItem1(Object* critter);
|
||||
Object* critterGetArmor(Object* critter);
|
||||
Object* objectGetCarriedObjectByPid(Object* obj, int pid);
|
||||
int objectGetCarriedQuantityByPid(Object* obj, int pid);
|
||||
Object* _inven_find_type(Object* obj, int a2, int* inout_a3);
|
||||
Object* _inven_find_id(Object* obj, int a2);
|
||||
Object* _inven_index_ptr(Object* obj, int a2);
|
||||
int _inven_wield(Object* a1, Object* a2, int a3);
|
||||
int _invenWieldFunc(Object* a1, Object* a2, int a3, bool a4);
|
||||
int _inven_unwield(Object* critter_obj, int a2);
|
||||
int _invenUnwieldFunc(Object* obj, int a2, int a3);
|
||||
Object* _inven_find_type(Object* obj, int itemType, int* indexPtr);
|
||||
Object* _inven_find_id(Object* obj, int id);
|
||||
Object* _inven_index_ptr(Object* obj, int index);
|
||||
// Makes critter equip a given item in a given hand slot with an animation.
|
||||
// 0 - left hand, 1 - right hand. If item is armor, hand value is ignored.
|
||||
int _inven_wield(Object* critter, Object* item, int hand);
|
||||
// Same as inven_wield but allows to wield item without animation.
|
||||
int _invenWieldFunc(Object* critter, Object* item, int hand, bool animate);
|
||||
// Makes critter unequip an item in a given hand slot with an animation.
|
||||
int _inven_unwield(Object* critter, int hand);
|
||||
// Same as inven_unwield but allows to unwield item without animation.
|
||||
int _invenUnwieldFunc(Object* critter, int hand, bool animate);
|
||||
int inventoryOpenLooting(Object* looter, Object* target);
|
||||
int inventoryOpenStealing(Object* thief, Object* target);
|
||||
void inventoryOpenTrade(int win, Object* barterer, Object* playerTable, Object* bartererTable, int barterMod);
|
||||
int _inven_set_timer(Object* a1);
|
||||
int _inven_set_timer(Object* item);
|
||||
Object* inven_get_current_target_obj();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
88
src/item.cc
88
src/item.cc
@@ -47,8 +47,8 @@ static int _item_move_func(Object* source, Object* target, Object* item, int qua
|
||||
static bool _item_identical(Object* item1, Object* item2);
|
||||
static int stealthBoyTurnOn(Object* object);
|
||||
static int stealthBoyTurnOff(Object* critter, Object* item);
|
||||
static int _insert_drug_effect(Object* critter_obj, Object* item_obj, int a3, int* stats, int* mods);
|
||||
static void _perform_drug_effect(Object* critter_obj, int* stats, int* mods, bool is_immediate);
|
||||
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);
|
||||
@@ -319,7 +319,7 @@ int itemAttemptAdd(Object* owner, Object* itemToAdd, int quantity)
|
||||
return itemAdd(owner, itemToAdd, quantity);
|
||||
}
|
||||
|
||||
// item_add
|
||||
// item_add_force
|
||||
// 0x4772B8
|
||||
int itemAdd(Object* owner, Object* itemToAdd, int quantity)
|
||||
{
|
||||
@@ -675,26 +675,24 @@ static bool _item_identical(Object* item1, Object* item2)
|
||||
return false;
|
||||
}
|
||||
|
||||
int v1;
|
||||
int item2Quantity;
|
||||
if (proto->item.type == ITEM_TYPE_AMMO || item1->pid == PROTO_ID_MONEY) {
|
||||
v1 = item2->data.item.ammo.quantity;
|
||||
item2Quantity = item2->data.item.ammo.quantity;
|
||||
item2->data.item.ammo.quantity = item1->data.item.ammo.quantity;
|
||||
}
|
||||
|
||||
// NOTE: Probably inlined memcmp, but I'm not sure why it only checks 32
|
||||
// bytes.
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (item1->field_2C_array[i] != item2->field_2C_array[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// CE: Original code is different. It compares exactly 32 bytes one by one
|
||||
// in the loop starting with `data` (which means it also checks `Inventory`
|
||||
// object). Objects with inventories are filtered a moment earlier, so it
|
||||
// should be safe to check only the item-specific data.
|
||||
bool same = item1->data.flags == item2->data.flags
|
||||
&& memcmp(&(item1->data.item), &(item2->data.item), sizeof(ItemObjectData)) == 0;
|
||||
|
||||
if (proto->item.type == ITEM_TYPE_AMMO || item1->pid == PROTO_ID_MONEY) {
|
||||
item2->data.item.ammo.quantity = v1;
|
||||
item2->data.item.ammo.quantity = item2Quantity;
|
||||
}
|
||||
|
||||
return i == 8;
|
||||
return same;
|
||||
}
|
||||
|
||||
// 0x477AE4
|
||||
@@ -2593,8 +2591,11 @@ int ammoGetDamageDivisor(Object* armor)
|
||||
return proto->item.data.ammo.damageDivisor;
|
||||
}
|
||||
|
||||
// Adds Drug event to event queue.
|
||||
// [duration] is in minutes
|
||||
//
|
||||
// 0x479B44
|
||||
static int _insert_drug_effect(Object* critter, Object* item, int a3, int* stats, int* mods)
|
||||
static int _insert_drug_effect(Object* critter, Object* item, int duration, int* stats, int* mods)
|
||||
{
|
||||
int index;
|
||||
for (index = 0; index < 3; index++) {
|
||||
@@ -2619,7 +2620,7 @@ static int _insert_drug_effect(Object* critter, Object* item, int a3, int* stats
|
||||
drugEffectEvent->modifiers[index] = mods[index];
|
||||
}
|
||||
|
||||
int delay = 600 * a3;
|
||||
int delay = 600 * duration;
|
||||
if (critter == gDude) {
|
||||
if (traitIsSelected(TRAIT_CHEM_RESISTANT)) {
|
||||
delay /= 2;
|
||||
@@ -2637,25 +2638,23 @@ static int _insert_drug_effect(Object* critter, Object* item, int a3, int* stats
|
||||
// 0x479C20
|
||||
static void _perform_drug_effect(Object* critter, int* stats, int* mods, bool isImmediate)
|
||||
{
|
||||
int v10;
|
||||
int v11;
|
||||
int v12;
|
||||
MessageListItem messageListItem;
|
||||
const char* name;
|
||||
const char* text;
|
||||
char v24[92]; // TODO: Size is probably wrong.
|
||||
char str[92]; // TODO: Size is probably wrong.
|
||||
char msgBuf[92]; // TODO: Size is probably wrong.
|
||||
|
||||
bool statsChanged = false;
|
||||
|
||||
int v5 = 0;
|
||||
bool v32 = false;
|
||||
int startIndex = 0;
|
||||
bool firstStatIsMinimum = false;
|
||||
if (stats[0] == -2) {
|
||||
v5 = 1;
|
||||
v32 = true;
|
||||
startIndex = 1;
|
||||
firstStatIsMinimum = true;
|
||||
}
|
||||
|
||||
for (int index = v5; index < 3; index++) {
|
||||
for (int index = startIndex; index < 3; index++) {
|
||||
int oldStatBonus;
|
||||
int statBonus;
|
||||
int stat = stats[index];
|
||||
if (stat == -1) {
|
||||
continue;
|
||||
@@ -2665,32 +2664,31 @@ static void _perform_drug_effect(Object* critter, int* stats, int* mods, bool is
|
||||
critter->data.critter.combat.maneuver &= ~CRITTER_MANUEVER_FLEEING;
|
||||
}
|
||||
|
||||
v10 = critterGetBonusStat(critter, stat);
|
||||
oldStatBonus = critterGetBonusStat(critter, stat);
|
||||
|
||||
int before;
|
||||
if (critter == gDude) {
|
||||
before = critterGetStat(gDude, stat);
|
||||
}
|
||||
int before = (critter == gDude)
|
||||
? critterGetStat(gDude, stat)
|
||||
: 0;
|
||||
|
||||
if (v32) {
|
||||
v11 = randomBetween(mods[index - 1], mods[index]) + v10;
|
||||
v32 = false;
|
||||
if (firstStatIsMinimum) {
|
||||
statBonus = randomBetween(mods[index - 1], mods[index]) + oldStatBonus;
|
||||
firstStatIsMinimum = false;
|
||||
} else {
|
||||
v11 = mods[index] + v10;
|
||||
statBonus = mods[index] + oldStatBonus;
|
||||
}
|
||||
|
||||
if (stat == STAT_CURRENT_HIT_POINTS) {
|
||||
v12 = critterGetBaseStatWithTraitModifier(critter, STAT_CURRENT_HIT_POINTS);
|
||||
if (v11 + v12 <= 0 && critter != gDude) {
|
||||
int currentHp = critterGetBaseStatWithTraitModifier(critter, STAT_CURRENT_HIT_POINTS);
|
||||
if (statBonus + currentHp <= 0 && critter != gDude) {
|
||||
name = critterGetName(critter);
|
||||
// %s succumbs to the adverse effects of chems.
|
||||
text = getmsg(&gItemsMessageList, &messageListItem, 600);
|
||||
snprintf(v24, sizeof(v24), text, name);
|
||||
_combatKillCritterOutsideCombat(critter, v24);
|
||||
snprintf(msgBuf, sizeof(msgBuf), text, name);
|
||||
_combatKillCritterOutsideCombat(critter, msgBuf);
|
||||
}
|
||||
}
|
||||
|
||||
critterSetBonusStat(critter, stat, v11);
|
||||
critterSetBonusStat(critter, stat, statBonus);
|
||||
|
||||
if (critter == gDude) {
|
||||
if (stat == STAT_CURRENT_HIT_POINTS) {
|
||||
@@ -2704,8 +2702,8 @@ static void _perform_drug_effect(Object* critter, int* stats, int* mods, bool is
|
||||
messageListItem.num = after < before ? 2 : 1;
|
||||
if (messageListGetItem(&gItemsMessageList, &messageListItem)) {
|
||||
char* statName = statGetName(stat);
|
||||
snprintf(str, sizeof(str), messageListItem.text, after < before ? before - after : after - before, statName);
|
||||
displayMonitorAddMessage(str);
|
||||
snprintf(msgBuf, sizeof(msgBuf), messageListItem.text, after < before ? before - after : after - before, statName);
|
||||
displayMonitorAddMessage(msgBuf);
|
||||
statsChanged = true;
|
||||
}
|
||||
}
|
||||
@@ -2725,14 +2723,14 @@ static void _perform_drug_effect(Object* critter, int* stats, int* mods, bool is
|
||||
// You suffer a fatal heart attack from chem overdose.
|
||||
messageListItem.num = 4;
|
||||
if (messageListGetItem(&gItemsMessageList, &messageListItem)) {
|
||||
strcpy(v24, messageListItem.text);
|
||||
strcpy(msgBuf, messageListItem.text);
|
||||
// TODO: Why message is ignored?
|
||||
}
|
||||
} else {
|
||||
name = critterGetName(critter);
|
||||
// %s succumbs to the adverse effects of chems.
|
||||
text = getmsg(&gItemsMessageList, &messageListItem, 600);
|
||||
snprintf(v24, sizeof(v24), text, name);
|
||||
snprintf(msgBuf, sizeof(msgBuf), text, name);
|
||||
// TODO: Why message is ignored?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ int falloutMain(int argc, char** argv)
|
||||
switch (mainMenuRc) {
|
||||
case MAIN_MENU_INTRO:
|
||||
mainMenuWindowHide(true);
|
||||
gameMoviePlay(MOVIE_INTRO, GAME_MOVIE_PAUSE_MUSIC);
|
||||
gameMoviePlay(MOVIE_INTRO, GAME_MOVIE_STOP_MUSIC);
|
||||
gameMoviePlay(MOVIE_CREDITS, 0);
|
||||
break;
|
||||
case MAIN_MENU_NEW_GAME:
|
||||
|
||||
26
src/map.cc
26
src/map.cc
@@ -373,7 +373,7 @@ int mapSetElevation(int elevation)
|
||||
}
|
||||
|
||||
if (elevation != gElevation) {
|
||||
wmMapMarkMapEntranceState(gMapHeader.field_34, elevation, 1);
|
||||
wmMapMarkMapEntranceState(gMapHeader.index, elevation, 1);
|
||||
}
|
||||
|
||||
gElevation = elevation;
|
||||
@@ -596,7 +596,7 @@ char* _map_get_description_idx_(int map)
|
||||
// 0x4826B8
|
||||
int mapGetCurrentMap()
|
||||
{
|
||||
return gMapHeader.field_34;
|
||||
return gMapHeader.index;
|
||||
}
|
||||
|
||||
// 0x4826C0
|
||||
@@ -927,7 +927,7 @@ static int mapLoad(File* stream)
|
||||
lightSetAmbientIntensity(LIGHT_INTENSITY_MAX, false);
|
||||
objectSetLocation(gDude, gCenterTile, gElevation, nullptr);
|
||||
objectSetRotation(gDude, gEnteringRotation, nullptr);
|
||||
gMapHeader.field_34 = wmMapMatchNameToIdx(gMapHeader.name);
|
||||
gMapHeader.index = wmMapMatchNameToIdx(gMapHeader.name);
|
||||
|
||||
if ((gMapHeader.flags & 1) == 0) {
|
||||
char path[COMPAT_MAX_PATH];
|
||||
@@ -965,10 +965,10 @@ static int mapLoad(File* stream)
|
||||
|
||||
Script* script;
|
||||
scriptGetScript(gMapSid, &script);
|
||||
script->field_14 = gMapHeader.scriptIndex - 1;
|
||||
script->index = gMapHeader.scriptIndex - 1;
|
||||
script->flags |= SCRIPT_FLAG_0x08;
|
||||
object->id = scriptsNewObjectId();
|
||||
script->field_1C = object->id;
|
||||
script->ownerId = object->id;
|
||||
script->owner = object;
|
||||
_scr_spatials_disable();
|
||||
scriptExecProc(gMapSid, SCRIPT_PROC_MAP_ENTER);
|
||||
@@ -1025,8 +1025,8 @@ err:
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
wmMapMarkVisited(gMapHeader.field_34);
|
||||
wmMapMarkMapEntranceState(gMapHeader.field_34, gElevation, 1);
|
||||
wmMapMarkVisited(gMapHeader.index);
|
||||
wmMapMarkMapEntranceState(gMapHeader.index, gElevation, 1);
|
||||
|
||||
if (wmCheckGameAreaEvents() != 0) {
|
||||
rc = -1;
|
||||
@@ -1203,7 +1203,7 @@ static int _map_age_dead_critters()
|
||||
int _map_target_load_area()
|
||||
{
|
||||
int city = -1;
|
||||
if (wmMatchAreaContainingMapIdx(gMapHeader.field_34, &city) == -1) {
|
||||
if (wmMatchAreaContainingMapIdx(gMapHeader.index, &city) == -1) {
|
||||
city = -1;
|
||||
}
|
||||
return city;
|
||||
@@ -1254,7 +1254,7 @@ int mapHandleTransition()
|
||||
}
|
||||
} else {
|
||||
if (!isInCombat()) {
|
||||
if (gMapTransition.map != gMapHeader.field_34 || gElevation == gMapTransition.elevation) {
|
||||
if (gMapTransition.map != gMapHeader.index || gElevation == gMapTransition.elevation) {
|
||||
// SFALL: Remove text floaters after moving to another map.
|
||||
textObjectsReset();
|
||||
|
||||
@@ -1262,7 +1262,7 @@ int mapHandleTransition()
|
||||
}
|
||||
|
||||
if (gMapTransition.tile != -1 && gMapTransition.tile != 0
|
||||
&& gMapHeader.field_34 != MAP_MODOC_BEDNBREAKFAST && gMapHeader.field_34 != MAP_THE_SQUAT_A
|
||||
&& gMapHeader.index != MAP_MODOC_BEDNBREAKFAST && gMapHeader.index != MAP_THE_SQUAT_A
|
||||
&& elevationIsValid(gMapTransition.elevation)) {
|
||||
objectSetLocation(gDude, gMapTransition.tile, gMapTransition.elevation, nullptr);
|
||||
mapSetElevation(gMapTransition.elevation);
|
||||
@@ -1276,7 +1276,7 @@ int mapHandleTransition()
|
||||
memset(&gMapTransition, 0, sizeof(gMapTransition));
|
||||
|
||||
int city;
|
||||
wmMatchAreaContainingMapIdx(gMapHeader.field_34, &city);
|
||||
wmMatchAreaContainingMapIdx(gMapHeader.index, &city);
|
||||
if (wmTeleportToArea(city) == -1) {
|
||||
debugPrint("\nError: couldn't make jump on worldmap for map jump!");
|
||||
}
|
||||
@@ -1748,7 +1748,7 @@ static int mapHeaderWrite(MapHeader* ptr, File* stream)
|
||||
if (fileWriteInt32(stream, ptr->flags) == -1) return -1;
|
||||
if (fileWriteInt32(stream, ptr->darkness) == -1) return -1;
|
||||
if (fileWriteInt32(stream, ptr->globalVariablesCount) == -1) return -1;
|
||||
if (fileWriteInt32(stream, ptr->field_34) == -1) return -1;
|
||||
if (fileWriteInt32(stream, ptr->index) == -1) return -1;
|
||||
if (fileWriteUInt32(stream, ptr->lastVisitTime) == -1) return -1;
|
||||
if (fileWriteInt32List(stream, ptr->field_3C, 44) == -1) return -1;
|
||||
|
||||
@@ -1768,7 +1768,7 @@ static int mapHeaderRead(MapHeader* ptr, File* stream)
|
||||
if (fileReadInt32(stream, &(ptr->flags)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(ptr->darkness)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(ptr->globalVariablesCount)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(ptr->field_34)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(ptr->index)) == -1) return -1;
|
||||
if (fileReadUInt32(stream, &(ptr->lastVisitTime)) == -1) return -1;
|
||||
if (fileReadInt32List(stream, ptr->field_3C, 44) == -1) return -1;
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ typedef struct MapHeader {
|
||||
int globalVariablesCount;
|
||||
|
||||
// map_number
|
||||
int field_34;
|
||||
int index;
|
||||
|
||||
// Time in game ticks when PC last visited this map.
|
||||
unsigned int lastVisitTime;
|
||||
|
||||
10
src/mouse.cc
10
src/mouse.cc
@@ -632,12 +632,12 @@ void mouseGetPosition(int* xPtr, int* yPtr)
|
||||
}
|
||||
|
||||
// 0x4CAA04
|
||||
void _mouse_set_position(int a1, int a2)
|
||||
void _mouse_set_position(int x, int y)
|
||||
{
|
||||
gMouseCursorX = a1 - _mouse_hotx;
|
||||
gMouseCursorY = a2 - _mouse_hoty;
|
||||
_raw_y = a2 - _mouse_hoty;
|
||||
_raw_x = a1 - _mouse_hotx;
|
||||
gMouseCursorX = x - _mouse_hotx;
|
||||
gMouseCursorY = y - _mouse_hoty;
|
||||
_raw_y = y - _mouse_hoty;
|
||||
_raw_x = x - _mouse_hotx;
|
||||
_mouse_clip();
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ bool _mouse_in(int left, int top, int right, int bottom);
|
||||
bool _mouse_click_in(int left, int top, int right, int bottom);
|
||||
void mouseGetRect(Rect* rect);
|
||||
void mouseGetPosition(int* out_x, int* out_y);
|
||||
void _mouse_set_position(int a1, int a2);
|
||||
void _mouse_set_position(int x, int y);
|
||||
int mouseGetEvent();
|
||||
bool cursorIsHidden();
|
||||
void _mouse_get_raw_state(int* out_x, int* out_y, int* out_buttons);
|
||||
|
||||
274
src/movie.cc
274
src/movie.cc
@@ -14,7 +14,6 @@
|
||||
#include "movie_effect.h"
|
||||
#include "movie_lib.h"
|
||||
#include "platform_compat.h"
|
||||
#include "pointer_registry.h"
|
||||
#include "sound.h"
|
||||
#include "svga.h"
|
||||
#include "text_font.h"
|
||||
@@ -31,9 +30,9 @@ typedef struct MovieSubtitleListNode {
|
||||
|
||||
static void* movieMallocImpl(size_t size);
|
||||
static void movieFreeImpl(void* ptr);
|
||||
static bool movieReadImpl(int fileHandle, void* buf, int count);
|
||||
static void movieDirectImpl(SDL_Surface* surface, int srcWidth, int srcHeight, int srcX, int srcY, int destWidth, int destHeight, int a8, int a9);
|
||||
static void movieBufferedImpl(SDL_Surface* surface, int srcWidth, int srcHeight, int srcX, int srcY, int destWidth, int destHeight, int a8, int a9);
|
||||
static bool movieReadImpl(void* handle, void* buf, int count);
|
||||
static void movieDirectImpl(unsigned char* pixels, int src_width, int src_height, int src_x, int src_y, int dst_width, int dst_height, int dst_x, int dst_y);
|
||||
static void movieBufferedImpl(unsigned char* pixels, int src_width, int src_height, int src_x, int src_y, int dst_width, int dst_height, int dst_x, int dst_y);
|
||||
static int _movieScaleSubRect(int win, unsigned char* data, int width, int height, int pitch);
|
||||
static int _movieScaleSubRectAlpha(int win, unsigned char* data, int width, int height, int pitch);
|
||||
static int _movieScaleWindowAlpha(int win, unsigned char* data, int width, int height, int pitch);
|
||||
@@ -41,13 +40,12 @@ static int _blitAlpha(int win, unsigned char* data, int width, int height, int p
|
||||
static int _movieScaleWindow(int win, unsigned char* data, int width, int height, int pitch);
|
||||
static int _blitNormal(int win, unsigned char* data, int width, int height, int pitch);
|
||||
static void movieSetPaletteEntriesImpl(unsigned char* palette, int start, int end);
|
||||
static int _noop();
|
||||
static void _cleanupMovie(int a1);
|
||||
static void _cleanupLast();
|
||||
static File* movieOpen(char* filePath);
|
||||
static void movieLoadSubtitles(char* filePath);
|
||||
static void movieRenderSubtitles();
|
||||
static int _movieStart(int win, char* filePath, int (*a3)());
|
||||
static int _movieStart(int win, char* filePath);
|
||||
static bool _localMovieCallback();
|
||||
static int _stepMovie();
|
||||
|
||||
@@ -102,21 +100,12 @@ static Rect _movieRect;
|
||||
// 0x638E30
|
||||
static void (*_movieCallback)();
|
||||
|
||||
// 0x638E34
|
||||
MovieEndFunc* _endMovieFunc;
|
||||
|
||||
// 0x638E38
|
||||
static MovieSetPaletteProc* gMoviePaletteProc;
|
||||
|
||||
// 0x638E3C
|
||||
static MovieFailedOpenFunc* _failedOpenFunc;
|
||||
|
||||
// 0x638E40
|
||||
static MovieBuildSubtitleFilePathProc* gMovieBuildSubtitleFilePathProc;
|
||||
|
||||
// 0x638E44
|
||||
static MovieStartFunc* _startMovieFunc;
|
||||
|
||||
// 0x638E48
|
||||
static int _subtitleW;
|
||||
|
||||
@@ -135,9 +124,6 @@ static int _lastMovieSY;
|
||||
// 0x638E5C
|
||||
static int _movieScaleFlag;
|
||||
|
||||
// 0x638E60
|
||||
static MoviePreDrawFunc* _moviePreDrawFunc;
|
||||
|
||||
// 0x638E64
|
||||
static int _lastMovieH;
|
||||
|
||||
@@ -168,18 +154,12 @@ static int _movieH;
|
||||
// 0x638E88
|
||||
static int _movieOffset;
|
||||
|
||||
// 0x638E8C
|
||||
static MovieCaptureFrameProc* _movieCaptureFrameFunc;
|
||||
|
||||
// 0x638E90
|
||||
static unsigned char* _lastMovieBuffer;
|
||||
|
||||
// 0x638E94
|
||||
static int _movieW;
|
||||
|
||||
// 0x638E98
|
||||
static MovieFrameGrabProc* _movieFrameGrabFunc;
|
||||
|
||||
// 0x638EA0
|
||||
static int _subtitleH;
|
||||
|
||||
@@ -204,33 +184,7 @@ static File* _alphaHandle;
|
||||
// 0x638EC0
|
||||
static unsigned char* _alphaBuf;
|
||||
|
||||
static SDL_Surface* gMovieSdlSurface = nullptr;
|
||||
static int gMovieFileStreamPointerKey = 0;
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4865E0
|
||||
void _movieSetPreDrawFunc(MoviePreDrawFunc* preDrawFunc)
|
||||
{
|
||||
_moviePreDrawFunc = preDrawFunc;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4865E8
|
||||
void _movieSetFailedOpenFunc(MovieFailedOpenFunc* failedOpenFunc)
|
||||
{
|
||||
_failedOpenFunc = failedOpenFunc;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x4865F0
|
||||
void _movieSetFunc(MovieStartFunc* startFunc, MovieEndFunc* endFunc)
|
||||
{
|
||||
_startMovieFunc = startFunc;
|
||||
_endMovieFunc = endFunc;
|
||||
}
|
||||
static unsigned char* MVE_lastBuffer = nullptr;
|
||||
|
||||
// 0x4865FC
|
||||
static void* movieMallocImpl(size_t size)
|
||||
@@ -245,22 +199,22 @@ static void movieFreeImpl(void* ptr)
|
||||
}
|
||||
|
||||
// 0x48662C
|
||||
static bool movieReadImpl(int fileHandle, void* buf, int count)
|
||||
static bool movieReadImpl(void* handle, void* buf, int count)
|
||||
{
|
||||
return fileRead(buf, 1, count, (File*)intToPtr(fileHandle)) == count;
|
||||
return fileRead(buf, 1, count, (File*)handle) == count;
|
||||
}
|
||||
|
||||
// 0x486654
|
||||
static void movieDirectImpl(SDL_Surface* surface, int srcWidth, int srcHeight, int srcX, int srcY, int destWidth, int destHeight, int a8, int a9)
|
||||
static void movieDirectImpl(unsigned char* pixels, int src_width, int src_height, int src_x, int src_y, int dst_width, int dst_height, int dst_x, int dst_y)
|
||||
{
|
||||
int v14;
|
||||
int v15;
|
||||
|
||||
SDL_Rect srcRect;
|
||||
srcRect.x = srcX;
|
||||
srcRect.y = srcY;
|
||||
srcRect.w = srcWidth;
|
||||
srcRect.h = srcHeight;
|
||||
srcRect.x = src_x;
|
||||
srcRect.y = src_y;
|
||||
srcRect.w = src_width;
|
||||
srcRect.h = src_height;
|
||||
|
||||
v14 = gMovieWindowRect.right - gMovieWindowRect.left;
|
||||
v15 = gMovieWindowRect.right - gMovieWindowRect.left + 1;
|
||||
@@ -269,35 +223,35 @@ static void movieDirectImpl(SDL_Surface* surface, int srcWidth, int srcHeight, i
|
||||
|
||||
if (_movieScaleFlag) {
|
||||
if ((gMovieFlags & MOVIE_EXTENDED_FLAG_0x08) != 0) {
|
||||
destRect.y = (gMovieWindowRect.bottom - gMovieWindowRect.top + 1 - destHeight) / 2;
|
||||
destRect.x = (v15 - 4 * srcWidth / 3) / 2;
|
||||
destRect.y = (gMovieWindowRect.bottom - gMovieWindowRect.top + 1 - dst_height) / 2;
|
||||
destRect.x = (v15 - 4 * src_width / 3) / 2;
|
||||
} else {
|
||||
destRect.y = _movieY + gMovieWindowRect.top;
|
||||
destRect.x = gMovieWindowRect.left + _movieX;
|
||||
}
|
||||
|
||||
destRect.w = 4 * srcWidth / 3;
|
||||
destRect.h = destHeight;
|
||||
destRect.w = 4 * src_width / 3;
|
||||
destRect.h = dst_height;
|
||||
} else {
|
||||
if ((gMovieFlags & MOVIE_EXTENDED_FLAG_0x08) != 0) {
|
||||
destRect.y = (gMovieWindowRect.bottom - gMovieWindowRect.top + 1 - destHeight) / 2;
|
||||
destRect.x = (v15 - destWidth) / 2;
|
||||
destRect.y = (gMovieWindowRect.bottom - gMovieWindowRect.top + 1 - dst_height) / 2;
|
||||
destRect.x = (v15 - dst_width) / 2;
|
||||
} else {
|
||||
destRect.y = _movieY + gMovieWindowRect.top;
|
||||
destRect.x = gMovieWindowRect.left + _movieX;
|
||||
}
|
||||
destRect.w = destWidth;
|
||||
destRect.h = destHeight;
|
||||
destRect.w = dst_width;
|
||||
destRect.h = dst_height;
|
||||
}
|
||||
|
||||
_lastMovieSX = srcX;
|
||||
_lastMovieSY = srcY;
|
||||
_lastMovieSX = src_x;
|
||||
_lastMovieSY = src_y;
|
||||
_lastMovieX = destRect.x;
|
||||
_lastMovieY = destRect.y;
|
||||
_lastMovieBH = srcHeight;
|
||||
_lastMovieBH = src_height;
|
||||
_lastMovieW = destRect.w;
|
||||
gMovieSdlSurface = surface;
|
||||
_lastMovieBW = srcWidth;
|
||||
MVE_lastBuffer = pixels;
|
||||
_lastMovieBW = src_width;
|
||||
_lastMovieH = destRect.h;
|
||||
|
||||
// The code above assumes `gMovieWindowRect` is always at (0,0) which is not
|
||||
@@ -307,84 +261,31 @@ static void movieDirectImpl(SDL_Surface* surface, int srcWidth, int srcHeight, i
|
||||
destRect.x += gMovieWindowRect.left;
|
||||
destRect.y += gMovieWindowRect.top;
|
||||
|
||||
if (_movieCaptureFrameFunc != nullptr) {
|
||||
if (SDL_LockSurface(surface) == 0) {
|
||||
_movieCaptureFrameFunc(static_cast<unsigned char*>(surface->pixels),
|
||||
srcWidth,
|
||||
srcHeight,
|
||||
surface->pitch,
|
||||
destRect.x,
|
||||
destRect.y,
|
||||
destRect.w,
|
||||
destRect.h);
|
||||
SDL_UnlockSurface(surface);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This is a super-ugly hack. The reason is that surfaces managed by
|
||||
// MVE does not have palette. If we blit from these internal surfaces into
|
||||
// backbuffer surface (with palette set), all we get is shiny white box.
|
||||
SDL_SetSurfacePalette(surface, gSdlSurface->format->palette);
|
||||
SDL_BlitSurface(surface, &srcRect, gSdlSurface, &destRect);
|
||||
SDL_BlitSurface(gSdlSurface, nullptr, gSdlTextureSurface, nullptr);
|
||||
_scr_blit(pixels, src_width, src_height, src_x, src_y, dst_width, dst_height, dst_x, dst_y);
|
||||
renderPresent();
|
||||
}
|
||||
|
||||
// 0x486900
|
||||
static void movieBufferedImpl(SDL_Surface* a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9)
|
||||
static void movieBufferedImpl(unsigned char* pixels, int src_width, int src_height, int src_x, int src_y, int dst_width, int dst_height, int dst_x, int dst_y)
|
||||
{
|
||||
if (gMovieWindow == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
_lastMovieBW = a2;
|
||||
gMovieSdlSurface = a1;
|
||||
_lastMovieBH = a2;
|
||||
_lastMovieW = a6;
|
||||
_lastMovieH = a7;
|
||||
_lastMovieX = a4;
|
||||
_lastMovieY = a5;
|
||||
_lastMovieSX = a4;
|
||||
_lastMovieSY = a5;
|
||||
_lastMovieBW = src_width;
|
||||
MVE_lastBuffer = pixels;
|
||||
_lastMovieBH = src_width;
|
||||
_lastMovieW = dst_width;
|
||||
_lastMovieH = dst_height;
|
||||
_lastMovieX = src_x;
|
||||
_lastMovieY = src_y;
|
||||
_lastMovieSX = src_x;
|
||||
_lastMovieSY = src_y;
|
||||
|
||||
if (SDL_LockSurface(a1) != 0) {
|
||||
return;
|
||||
MovieBlitFunc* func = gMovieBlitFuncs[_movieAlphaFlag][_movieScaleFlag][_movieSubRectFlag];
|
||||
if (func(gMovieWindow, pixels, src_width, src_height, src_width) != 0) {
|
||||
windowRefreshRect(gMovieWindow, &_movieRect);
|
||||
}
|
||||
|
||||
if (_movieCaptureFrameFunc != nullptr) {
|
||||
_movieCaptureFrameFunc(static_cast<unsigned char*>(a1->pixels), a2, a3, a1->pitch, _movieRect.left, _movieRect.top, a6, a7);
|
||||
}
|
||||
|
||||
if (_movieFrameGrabFunc != nullptr) {
|
||||
_movieFrameGrabFunc(static_cast<unsigned char*>(a1->pixels), a2, a3, a1->pitch);
|
||||
} else {
|
||||
MovieBlitFunc* func = gMovieBlitFuncs[_movieAlphaFlag][_movieScaleFlag][_movieSubRectFlag];
|
||||
if (func(gMovieWindow, static_cast<unsigned char*>(a1->pixels), a2, a3, a1->pitch) != 0) {
|
||||
if (_moviePreDrawFunc != nullptr) {
|
||||
_moviePreDrawFunc(gMovieWindow, &_movieRect);
|
||||
}
|
||||
|
||||
windowRefreshRect(gMovieWindow, &_movieRect);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UnlockSurface(a1);
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x486A98
|
||||
void _movieSetFrameGrabFunc(MovieFrameGrabProc* proc)
|
||||
{
|
||||
_movieFrameGrabFunc = proc;
|
||||
}
|
||||
|
||||
// NOTE: Unused.
|
||||
//
|
||||
// 0x486AA0
|
||||
void _movieSetCaptureFrameFunc(MovieCaptureFrameProc* func)
|
||||
{
|
||||
_movieCaptureFrameFunc = func;
|
||||
}
|
||||
|
||||
// 0x486B68
|
||||
@@ -492,20 +393,14 @@ static void movieSetPaletteEntriesImpl(unsigned char* palette, int start, int en
|
||||
}
|
||||
}
|
||||
|
||||
// 0x486E08
|
||||
static int _noop()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// initMovie
|
||||
// 0x486E0C
|
||||
void movieInit()
|
||||
{
|
||||
movieLibSetMemoryProcs(movieMallocImpl, movieFreeImpl);
|
||||
movieLibSetPaletteEntriesProc(movieSetPaletteEntriesImpl);
|
||||
_MVE_sfSVGA(640, 480, 480, 0, 0, 0, 0, 0, 0);
|
||||
movieLibSetReadProc(movieReadImpl);
|
||||
MveSetMemory(movieMallocImpl, movieFreeImpl);
|
||||
MveSetPalette(movieSetPaletteEntriesImpl);
|
||||
MveSetScreenSize(screenGetWidth(), screenGetHeight());
|
||||
MveSetIO(movieReadImpl);
|
||||
}
|
||||
|
||||
// 0x486E98
|
||||
@@ -515,13 +410,9 @@ static void _cleanupMovie(int a1)
|
||||
return;
|
||||
}
|
||||
|
||||
if (_endMovieFunc != nullptr) {
|
||||
_endMovieFunc(gMovieWindow, _movieX, _movieY, _movieW, _movieH);
|
||||
}
|
||||
|
||||
int frame;
|
||||
int dropped;
|
||||
_MVE_rmFrameCounts(&frame, &dropped);
|
||||
MVE_rmFrameCounts(&frame, &dropped);
|
||||
debugPrint("Frames %d, dropped %d\n", frame, dropped);
|
||||
|
||||
if (_lastMovieBuffer != nullptr) {
|
||||
@@ -529,23 +420,17 @@ static void _cleanupMovie(int a1)
|
||||
_lastMovieBuffer = nullptr;
|
||||
}
|
||||
|
||||
if (gMovieSdlSurface != nullptr) {
|
||||
if (SDL_LockSurface(gMovieSdlSurface) == 0) {
|
||||
_lastMovieBuffer = (unsigned char*)internal_malloc_safe(_lastMovieBH * _lastMovieBW, __FILE__, __LINE__); // "..\\int\\MOVIE.C", 802
|
||||
blitBufferToBuffer((unsigned char*)gMovieSdlSurface->pixels + gMovieSdlSurface->pitch * _lastMovieSX + _lastMovieSY, _lastMovieBW, _lastMovieBH, gMovieSdlSurface->pitch, _lastMovieBuffer, _lastMovieBW);
|
||||
SDL_UnlockSurface(gMovieSdlSurface);
|
||||
} else {
|
||||
debugPrint("Couldn't lock movie surface\n");
|
||||
}
|
||||
|
||||
gMovieSdlSurface = nullptr;
|
||||
if (MVE_lastBuffer != nullptr) {
|
||||
_lastMovieBuffer = (unsigned char*)internal_malloc_safe(_lastMovieBH * _lastMovieBW, __FILE__, __LINE__); // "..\\int\\MOVIE.C", 802
|
||||
memcpy(_lastMovieBuffer, MVE_lastBuffer, _lastMovieBW * _lastMovieBH);
|
||||
MVE_lastBuffer = nullptr;
|
||||
}
|
||||
|
||||
if (a1) {
|
||||
_MVE_rmEndMovie();
|
||||
MVE_rmEndMovie();
|
||||
}
|
||||
|
||||
_MVE_ReleaseMem();
|
||||
MVE_ReleaseMem();
|
||||
|
||||
fileClose(gMovieFileStream);
|
||||
|
||||
@@ -619,16 +504,10 @@ int movieSetFlags(int flags)
|
||||
|
||||
if ((flags & MOVIE_FLAG_0x01) != 0) {
|
||||
_movieScaleFlag = 1;
|
||||
|
||||
if ((gMovieFlags & MOVIE_EXTENDED_FLAG_0x04) != 0) {
|
||||
_sub_4F4BB(3);
|
||||
}
|
||||
} else {
|
||||
_movieScaleFlag = 0;
|
||||
|
||||
if ((gMovieFlags & MOVIE_EXTENDED_FLAG_0x04) != 0) {
|
||||
_sub_4F4BB(4);
|
||||
} else {
|
||||
if ((gMovieFlags & MOVIE_EXTENDED_FLAG_0x04) == 0) {
|
||||
gMovieFlags &= ~MOVIE_EXTENDED_FLAG_0x08;
|
||||
}
|
||||
}
|
||||
@@ -662,7 +541,7 @@ static void _cleanupLast()
|
||||
_lastMovieBuffer = nullptr;
|
||||
}
|
||||
|
||||
gMovieSdlSurface = nullptr;
|
||||
MVE_lastBuffer = nullptr;
|
||||
}
|
||||
|
||||
// 0x48731C
|
||||
@@ -670,14 +549,8 @@ static File* movieOpen(char* filePath)
|
||||
{
|
||||
gMovieFileStream = fileOpen(filePath, "rb");
|
||||
if (gMovieFileStream == nullptr) {
|
||||
if (_failedOpenFunc == nullptr) {
|
||||
debugPrint("Couldn't find movie file %s\n", filePath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (gMovieFileStream == nullptr && _failedOpenFunc(filePath) != 0) {
|
||||
gMovieFileStream = fileOpen(filePath, "rb");
|
||||
}
|
||||
debugPrint("Couldn't find movie file %s\n", filePath);
|
||||
return nullptr;
|
||||
}
|
||||
return gMovieFileStream;
|
||||
}
|
||||
@@ -773,7 +646,7 @@ static void movieRenderSubtitles()
|
||||
|
||||
int frame;
|
||||
int dropped;
|
||||
_MVE_rmFrameCounts(&frame, &dropped);
|
||||
MVE_rmFrameCounts(&frame, &dropped);
|
||||
|
||||
while (gMovieSubtitleHead != nullptr) {
|
||||
if (frame < gMovieSubtitleHead->num) {
|
||||
@@ -812,12 +685,8 @@ static void movieRenderSubtitles()
|
||||
}
|
||||
|
||||
// 0x487710
|
||||
static int _movieStart(int win, char* filePath, int (*a3)())
|
||||
static int _movieStart(int win, char* filePath)
|
||||
{
|
||||
int v15;
|
||||
int v16;
|
||||
int v17;
|
||||
|
||||
if (_running) {
|
||||
return 1;
|
||||
}
|
||||
@@ -829,8 +698,6 @@ static int _movieStart(int win, char* filePath, int (*a3)())
|
||||
return 1;
|
||||
}
|
||||
|
||||
gMovieFileStreamPointerKey = ptrToInt(gMovieFileStream);
|
||||
|
||||
gMovieWindow = win;
|
||||
_running = 1;
|
||||
gMovieFlags &= ~MOVIE_EXTENDED_FLAG_0x01;
|
||||
@@ -843,33 +710,20 @@ static int _movieStart(int win, char* filePath, int (*a3)())
|
||||
debugPrint("Direct ");
|
||||
windowGetRect(gMovieWindow, &gMovieWindowRect);
|
||||
debugPrint("Playing at (%d, %d) ", _movieX + gMovieWindowRect.left, _movieY + gMovieWindowRect.top);
|
||||
_MVE_rmCallbacks(a3);
|
||||
_MVE_sfCallbacks(movieDirectImpl);
|
||||
|
||||
v17 = 0;
|
||||
v16 = _movieY + gMovieWindowRect.top;
|
||||
v15 = _movieX + gMovieWindowRect.left;
|
||||
MveSetShowFrame(movieDirectImpl);
|
||||
MVE_rmPrepMovie(gMovieFileStream, _movieX + gMovieWindowRect.left, _movieY + gMovieWindowRect.top, 0);
|
||||
} else {
|
||||
debugPrint("Buffered ");
|
||||
_MVE_rmCallbacks(a3);
|
||||
_MVE_sfCallbacks(movieBufferedImpl);
|
||||
v17 = 0;
|
||||
v16 = 0;
|
||||
v15 = 0;
|
||||
MveSetShowFrame(movieBufferedImpl);
|
||||
MVE_rmPrepMovie(gMovieFileStream, 0, 0, 0);
|
||||
}
|
||||
|
||||
_MVE_rmPrepMovie(gMovieFileStreamPointerKey, v15, v16, v17);
|
||||
|
||||
if (_movieScaleFlag) {
|
||||
debugPrint("scaled\n");
|
||||
} else {
|
||||
debugPrint("not scaled\n");
|
||||
}
|
||||
|
||||
if (_startMovieFunc != nullptr) {
|
||||
_startMovieFunc(gMovieWindow);
|
||||
}
|
||||
|
||||
if (_alphaHandle != nullptr) {
|
||||
int size;
|
||||
fileReadInt32(_alphaHandle, &size);
|
||||
@@ -923,7 +777,7 @@ int _movieRun(int win, char* filePath)
|
||||
_movieW = windowGetWidth(win);
|
||||
_movieH = windowGetHeight(win);
|
||||
_movieSubRectFlag = 0;
|
||||
return _movieStart(win, filePath, _noop);
|
||||
return _movieStart(win, filePath);
|
||||
}
|
||||
|
||||
// 0x487B1C
|
||||
@@ -940,7 +794,7 @@ int _movieRunRect(int win, char* filePath, int a3, int a4, int a5, int a6)
|
||||
_movieH = a6;
|
||||
_movieSubRectFlag = 1;
|
||||
|
||||
return _movieStart(win, filePath, _noop);
|
||||
return _movieStart(win, filePath);
|
||||
}
|
||||
|
||||
// 0x487B7C
|
||||
@@ -970,7 +824,7 @@ void movieSetBuildSubtitleFilePathProc(MovieBuildSubtitleFilePathProc* proc)
|
||||
void movieSetVolume(int volume)
|
||||
{
|
||||
int normalizedVolume = _soundVolumeHMItoDirectSound(volume);
|
||||
movieLibSetVolume(normalizedVolume);
|
||||
MveSetVolume(normalizedVolume);
|
||||
}
|
||||
|
||||
// 0x487BEC
|
||||
@@ -1000,7 +854,7 @@ void _movieUpdate()
|
||||
if (gMoviePaletteProc != nullptr) {
|
||||
int frame;
|
||||
int dropped;
|
||||
_MVE_rmFrameCounts(&frame, &dropped);
|
||||
MVE_rmFrameCounts(&frame, &dropped);
|
||||
gMoviePaletteProc(frame);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,13 +23,7 @@ typedef enum MovieExtendedFlags {
|
||||
typedef char* MovieBuildSubtitleFilePathProc(char* movieFilePath);
|
||||
typedef void MovieSetPaletteEntriesProc(unsigned char* palette, int start, int end);
|
||||
typedef void MovieSetPaletteProc(int frame);
|
||||
typedef void(MovieFrameGrabProc)(unsigned char* data, int width, int height, int pitch);
|
||||
typedef void(MovieCaptureFrameProc)(unsigned char* data, int width, int height, int pitch, int movieX, int movieY, int movieWidth, int movieHeight);
|
||||
typedef int(MovieBlitFunc)(int win, unsigned char* data, int width, int height, int pitch);
|
||||
typedef void(MoviePreDrawFunc)(int win, Rect* rect);
|
||||
typedef void(MovieStartFunc)(int win);
|
||||
typedef void(MovieEndFunc)(int win, int x, int y, int width, int height);
|
||||
typedef int(MovieFailedOpenFunc)(char* path);
|
||||
|
||||
void movieInit();
|
||||
void movieExit();
|
||||
|
||||
1070
src/movie_lib.cc
1070
src/movie_lib.cc
File diff suppressed because it is too large
Load Diff
@@ -1,29 +1,27 @@
|
||||
#ifndef MOVIE_LIB_H
|
||||
#define MOVIE_LIB_H
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "memory_defs.h"
|
||||
#include <stddef.h>
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef bool MovieReadProc(int fileHandle, void* buffer, int count);
|
||||
typedef void(MovieShowFrameProc)(SDL_Surface*, int, int, int, int, int, int, int, int);
|
||||
typedef void*(MveMallocFunc)(size_t size);
|
||||
typedef void(MveFreeFunc)(void* ptr);
|
||||
typedef bool(MveReadFunc)(void* handle, void* buffer, int count);
|
||||
typedef void(MveShowFrameFunc)(unsigned char* pixels, int src_width, int src_height, int src_x, int src_y, int dst_width, int dst_height, int dst_x, int dst_y);
|
||||
typedef void(MveSetPaletteFunc)(unsigned char* palette, int start, int count);
|
||||
|
||||
void movieLibSetMemoryProcs(MallocProc* mallocProc, FreeProc* freeProc);
|
||||
void movieLibSetReadProc(MovieReadProc* readProc);
|
||||
void movieLibSetVolume(int volume);
|
||||
void movieLibSetPan(int pan);
|
||||
void _MVE_sfSVGA(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9);
|
||||
void _MVE_sfCallbacks(MovieShowFrameProc* proc);
|
||||
void movieLibSetPaletteEntriesProc(void (*fn)(unsigned char*, int, int));
|
||||
void _MVE_rmCallbacks(int (*fn)());
|
||||
void _sub_4F4BB(int a1);
|
||||
void _MVE_rmFrameCounts(int* a1, int* a2);
|
||||
int _MVE_rmPrepMovie(int fileHandle, int a2, int a3, char a4);
|
||||
void MveSetMemory(MveMallocFunc* malloc_func, MveFreeFunc* free_func);
|
||||
void MveSetIO(MveReadFunc* read_func);
|
||||
void MveSetVolume(int volume);
|
||||
void MveSetScreenSize(int width, int height);
|
||||
void MveSetShowFrame(MveShowFrameFunc* proc);
|
||||
void MveSetPalette(MveSetPaletteFunc* set_palette_func);
|
||||
void MVE_rmFrameCounts(int* frame_count_ptr, int* frame_drop_count_ptr);
|
||||
int MVE_rmPrepMovie(void* handle, int dx, int dy, unsigned char track);
|
||||
int _MVE_rmStepMovie();
|
||||
void _MVE_rmEndMovie();
|
||||
void _MVE_ReleaseMem();
|
||||
void MVE_rmEndMovie();
|
||||
void MVE_ReleaseMem();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
|
||||
@@ -248,6 +248,7 @@ typedef struct MiscObjectData {
|
||||
int rotation;
|
||||
} MiscObjectData;
|
||||
|
||||
// TODO: use C-style inheritance for different ObjectData variants instead of unions within unions.
|
||||
typedef struct ObjectData {
|
||||
Inventory inventory;
|
||||
union {
|
||||
@@ -275,10 +276,7 @@ typedef struct Object {
|
||||
int fid; // obj_fid
|
||||
int flags; // obj_flags
|
||||
int elevation; // obj_elev
|
||||
union {
|
||||
int field_2C_array[14];
|
||||
ObjectData data;
|
||||
};
|
||||
ObjectData data;
|
||||
int pid; // obj_pid
|
||||
int cid; // obj_cid
|
||||
int lightDistance; // obj_light_distance
|
||||
@@ -286,7 +284,7 @@ typedef struct Object {
|
||||
int outline; // obj_outline
|
||||
int sid; // obj_sid
|
||||
Object* owner;
|
||||
int field_80;
|
||||
int scriptIndex;
|
||||
} Object;
|
||||
|
||||
typedef struct ObjectListNode {
|
||||
|
||||
@@ -430,7 +430,7 @@ int objectRead(Object* obj, File* stream)
|
||||
if (fileReadInt32(stream, &(obj->lightIntensity)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &field_74) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(obj->sid)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(obj->field_80)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(obj->scriptIndex)) == -1) return -1;
|
||||
|
||||
obj->outline = 0;
|
||||
obj->owner = nullptr;
|
||||
@@ -539,7 +539,7 @@ static int objectLoadAllInternal(File* stream)
|
||||
debugPrint("\nError connecting object to script!");
|
||||
} else {
|
||||
script->owner = objectListNode->obj;
|
||||
objectListNode->obj->field_80 = script->field_14;
|
||||
objectListNode->obj->scriptIndex = script->index;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,7 +661,7 @@ static int objectWrite(Object* obj, File* stream)
|
||||
if (fileWriteInt32(stream, obj->lightIntensity) == -1) return -1;
|
||||
if (fileWriteInt32(stream, obj->outline) == -1) return -1;
|
||||
if (fileWriteInt32(stream, obj->sid) == -1) return -1;
|
||||
if (fileWriteInt32(stream, obj->field_80) == -1) return -1;
|
||||
if (fileWriteInt32(stream, obj->scriptIndex) == -1) return -1;
|
||||
if (objectDataWrite(obj, stream) == -1) return -1;
|
||||
|
||||
return 0;
|
||||
@@ -3719,7 +3719,7 @@ static int objectAllocate(Object** objectPtr)
|
||||
object->pid = -1;
|
||||
object->sid = -1;
|
||||
object->owner = nullptr;
|
||||
object->field_80 = -1;
|
||||
object->scriptIndex = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ int objectHide(Object* obj, Rect* rect);
|
||||
int objectEnableOutline(Object* obj, Rect* rect);
|
||||
int objectDisableOutline(Object* obj, Rect* rect);
|
||||
int _obj_toggle_flat(Object* obj, Rect* rect);
|
||||
int objectDestroy(Object* a1, Rect* a2);
|
||||
int objectDestroy(Object* object, Rect* rect);
|
||||
int _obj_inven_free(Inventory* inventory);
|
||||
bool _obj_action_can_use(Object* obj);
|
||||
bool _obj_action_can_talk_to(Object* obj);
|
||||
|
||||
@@ -58,10 +58,10 @@ typedef struct PartyMemberDescription {
|
||||
int level_pids[PARTY_MEMBER_MAX_LEVEL];
|
||||
} PartyMemberDescription;
|
||||
|
||||
typedef struct STRU_519DBC {
|
||||
int field_0;
|
||||
int field_4; // party member level
|
||||
int field_8; // early what?
|
||||
typedef struct PartyMemberLevelUpInfo {
|
||||
int level; // party member level
|
||||
int numLevelUps; // number of PC level ups with this member in party
|
||||
int isEarly; // last level up was "early" due to successful roll
|
||||
} STRU_519DBC;
|
||||
|
||||
typedef struct PartyMemberListItem {
|
||||
@@ -113,7 +113,7 @@ static int _partyStatePrepped = 0;
|
||||
static PartyMemberDescription* gPartyMemberDescriptions = nullptr;
|
||||
|
||||
// 0x519DBC
|
||||
static STRU_519DBC* _partyMemberLevelUpInfoList = nullptr;
|
||||
static PartyMemberLevelUpInfo* _partyMemberLevelUpInfoList = nullptr;
|
||||
|
||||
// 0x519DC0
|
||||
static int _curID = 20000;
|
||||
@@ -164,7 +164,7 @@ int partyMembersInit()
|
||||
|
||||
memset(gPartyMemberDescriptions, 0, sizeof(*gPartyMemberDescriptions) * gPartyMemberDescriptionsLength);
|
||||
|
||||
_partyMemberLevelUpInfoList = (STRU_519DBC*)internal_malloc(sizeof(*_partyMemberLevelUpInfoList) * gPartyMemberDescriptionsLength);
|
||||
_partyMemberLevelUpInfoList = (PartyMemberLevelUpInfo*)internal_malloc(sizeof(*_partyMemberLevelUpInfoList) * gPartyMemberDescriptionsLength);
|
||||
if (_partyMemberLevelUpInfoList == nullptr) goto err;
|
||||
|
||||
memset(_partyMemberLevelUpInfoList, 0, sizeof(*_partyMemberLevelUpInfoList) * gPartyMemberDescriptionsLength);
|
||||
@@ -275,9 +275,9 @@ err:
|
||||
void partyMembersReset()
|
||||
{
|
||||
for (int index = 0; index < gPartyMemberDescriptionsLength; index++) {
|
||||
_partyMemberLevelUpInfoList[index].field_0 = 0;
|
||||
_partyMemberLevelUpInfoList[index].field_4 = 0;
|
||||
_partyMemberLevelUpInfoList[index].field_8 = 0;
|
||||
_partyMemberLevelUpInfoList[index].level = 0;
|
||||
_partyMemberLevelUpInfoList[index].numLevelUps = 0;
|
||||
_partyMemberLevelUpInfoList[index].isEarly = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,9 +285,9 @@ void partyMembersReset()
|
||||
void partyMembersExit()
|
||||
{
|
||||
for (int index = 0; index < gPartyMemberDescriptionsLength; index++) {
|
||||
_partyMemberLevelUpInfoList[index].field_0 = 0;
|
||||
_partyMemberLevelUpInfoList[index].field_4 = 0;
|
||||
_partyMemberLevelUpInfoList[index].field_8 = 0;
|
||||
_partyMemberLevelUpInfoList[index].level = 0;
|
||||
_partyMemberLevelUpInfoList[index].numLevelUps = 0;
|
||||
_partyMemberLevelUpInfoList[index].isEarly = 0;
|
||||
}
|
||||
|
||||
gPartyMemberDescriptionsLength = 0;
|
||||
@@ -364,9 +364,9 @@ static void partyMemberDescriptionInit(PartyMemberDescription* partyMemberDescri
|
||||
partyMemberDescription->level_pids[0] = -1;
|
||||
|
||||
for (int index = 0; index < gPartyMemberDescriptionsLength; index++) {
|
||||
_partyMemberLevelUpInfoList[index].field_0 = 0;
|
||||
_partyMemberLevelUpInfoList[index].field_4 = 0;
|
||||
_partyMemberLevelUpInfoList[index].field_8 = 0;
|
||||
_partyMemberLevelUpInfoList[index].level = 0;
|
||||
_partyMemberLevelUpInfoList[index].numLevelUps = 0;
|
||||
_partyMemberLevelUpInfoList[index].isEarly = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,7 +403,7 @@ int partyMemberAdd(Object* object)
|
||||
Script* script;
|
||||
if (scriptGetScript(object->sid, &script) != -1) {
|
||||
script->flags |= (SCRIPT_FLAG_0x08 | SCRIPT_FLAG_0x10);
|
||||
script->field_1C = object->id;
|
||||
script->ownerId = object->id;
|
||||
|
||||
object->sid = ((object->pid & 0xFFFFFF) + 18000) | (object->sid & 0xFF000000);
|
||||
script->sid = object->sid;
|
||||
@@ -528,10 +528,10 @@ int partyMembersSave(File* stream)
|
||||
}
|
||||
|
||||
for (int index = 1; index < gPartyMemberDescriptionsLength; index++) {
|
||||
STRU_519DBC* ptr = &(_partyMemberLevelUpInfoList[index]);
|
||||
if (fileWriteInt32(stream, ptr->field_0) == -1) return -1;
|
||||
if (fileWriteInt32(stream, ptr->field_4) == -1) return -1;
|
||||
if (fileWriteInt32(stream, ptr->field_8) == -1) return -1;
|
||||
PartyMemberLevelUpInfo* ptr = &(_partyMemberLevelUpInfoList[index]);
|
||||
if (fileWriteInt32(stream, ptr->level) == -1) return -1;
|
||||
if (fileWriteInt32(stream, ptr->numLevelUps) == -1) return -1;
|
||||
if (fileWriteInt32(stream, ptr->isEarly) == -1) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -763,11 +763,11 @@ int partyMembersLoad(File* stream)
|
||||
partyFixMultipleMembers();
|
||||
|
||||
for (int index = 1; index < gPartyMemberDescriptionsLength; index++) {
|
||||
STRU_519DBC* ptr_519DBC = &(_partyMemberLevelUpInfoList[index]);
|
||||
PartyMemberLevelUpInfo* levelUpInfo = &(_partyMemberLevelUpInfoList[index]);
|
||||
|
||||
if (fileReadInt32(stream, &(ptr_519DBC->field_0)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(ptr_519DBC->field_4)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(ptr_519DBC->field_8)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(levelUpInfo->level)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(levelUpInfo->numLevelUps)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(levelUpInfo->isEarly)) == -1) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1021,8 +1021,8 @@ static int _partyMemberItemSave(Object* object)
|
||||
}
|
||||
|
||||
if (object->id < 20000) {
|
||||
script->field_1C = _partyMemberNewObjID();
|
||||
object->id = script->field_1C;
|
||||
script->ownerId = _partyMemberNewObjID();
|
||||
object->id = script->ownerId;
|
||||
}
|
||||
|
||||
PartyMemberListItem* node = (PartyMemberListItem*)internal_malloc(sizeof(*node));
|
||||
@@ -1454,25 +1454,25 @@ bool partyMemberSupportsChemUse(Object* object, int chemUse)
|
||||
int _partyMemberIncLevels()
|
||||
{
|
||||
int i;
|
||||
PartyMemberListItem* ptr;
|
||||
PartyMemberListItem* listItem;
|
||||
Object* obj;
|
||||
PartyMemberDescription* party_member;
|
||||
PartyMemberDescription* memberDescription;
|
||||
const char* name;
|
||||
int j;
|
||||
int v0;
|
||||
STRU_519DBC* ptr_519DBC;
|
||||
int v24;
|
||||
int memberIndex;
|
||||
PartyMemberLevelUpInfo* levelUpInfo;
|
||||
int levelMod;
|
||||
char* text;
|
||||
MessageListItem msg;
|
||||
char str[260];
|
||||
Rect v19;
|
||||
Rect levelUpMessageRect;
|
||||
|
||||
v0 = -1;
|
||||
memberIndex = -1;
|
||||
for (i = 1; i < gPartyMembersLength; i++) {
|
||||
ptr = &(gPartyMembers[i]);
|
||||
obj = ptr->object;
|
||||
listItem = &(gPartyMembers[i]);
|
||||
obj = listItem->object;
|
||||
|
||||
if (partyMemberGetDescription(obj, &party_member) == -1) {
|
||||
if (partyMemberGetDescription(obj, &memberDescription) == -1) {
|
||||
// SFALL: NPC level fix.
|
||||
continue;
|
||||
}
|
||||
@@ -1484,67 +1484,75 @@ int _partyMemberIncLevels()
|
||||
name = critterGetName(obj);
|
||||
debugPrint("\npartyMemberIncLevels: %s", name);
|
||||
|
||||
if (party_member->level_up_every == 0) {
|
||||
if (memberDescription->level_up_every == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = 1; j < gPartyMemberDescriptionsLength; j++) {
|
||||
if (gPartyMemberPids[j] == obj->pid) {
|
||||
v0 = j;
|
||||
memberIndex = j;
|
||||
}
|
||||
}
|
||||
|
||||
if (v0 == -1) {
|
||||
if (memberIndex == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pcGetStat(PC_STAT_LEVEL) < party_member->level_minimum) {
|
||||
if (pcGetStat(PC_STAT_LEVEL) < memberDescription->level_minimum) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ptr_519DBC = &(_partyMemberLevelUpInfoList[v0]);
|
||||
levelUpInfo = &(_partyMemberLevelUpInfoList[memberIndex]);
|
||||
|
||||
if (ptr_519DBC->field_0 >= party_member->level_pids_num) {
|
||||
if (levelUpInfo->level >= memberDescription->level_pids_num) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ptr_519DBC->field_4++;
|
||||
levelUpInfo->numLevelUps++;
|
||||
|
||||
v24 = ptr_519DBC->field_4 % party_member->level_pids_num;
|
||||
debugPrint("pm: levelMod: %d, Lvl: %d, Early: %d, Every: %d", v24, ptr_519DBC->field_4, ptr_519DBC->field_8, party_member->level_up_every);
|
||||
levelMod = levelUpInfo->numLevelUps % memberDescription->level_up_every;
|
||||
debugPrint("pm: levelMod: %d, Lvl: %d, Early: %d, Every: %d", levelMod, levelUpInfo->numLevelUps, levelUpInfo->isEarly, memberDescription->level_up_every);
|
||||
|
||||
if (v24 != 0 || ptr_519DBC->field_8 == 0) {
|
||||
if (ptr_519DBC->field_8 == 0) {
|
||||
if (v24 == 0 || randomBetween(0, 100) <= 100 * v24 / party_member->level_up_every) {
|
||||
ptr_519DBC->field_0++;
|
||||
if (v24 != 0) {
|
||||
ptr_519DBC->field_8 = 1;
|
||||
}
|
||||
// Party member level up with a probability that depends on how "far" we are in the current "level_up_every" progression.
|
||||
// For example, if level_up_every is 5 and NPC observed 7 level ups with the player, 5 % 7 = 2, 2 * 100 / 5 = 40 (40% probability).
|
||||
// If levelMod is 0 (so we got 5, 10, etc. levels in the example above), probability is 100% (no roll).
|
||||
// If previous level up occured "early" (due to probability roll), then we skip until we get to levelMod = 0, to begin the next cycle.
|
||||
|
||||
if (_partyMemberCopyLevelInfo(obj, party_member->level_pids[ptr_519DBC->field_0]) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
name = critterGetName(obj);
|
||||
// %s has gained in some abilities.
|
||||
text = getmsg(&gMiscMessageList, &msg, 9000);
|
||||
snprintf(str, sizeof(str), text, name);
|
||||
displayMonitorAddMessage(str);
|
||||
|
||||
debugPrint(str);
|
||||
|
||||
// Individual message
|
||||
msg.num = 9000 + 10 * v0 + ptr_519DBC->field_0 - 1;
|
||||
if (messageListGetItem(&gMiscMessageList, &msg)) {
|
||||
name = critterGetName(obj);
|
||||
snprintf(str, sizeof(str), msg.text, name);
|
||||
textObjectAdd(obj, str, 101, _colorTable[0x7FFF], _colorTable[0], &v19);
|
||||
tileWindowRefreshRect(&v19, obj->elevation);
|
||||
}
|
||||
}
|
||||
if (levelUpInfo->isEarly != 0) {
|
||||
if (levelMod == 0) {
|
||||
levelUpInfo->isEarly = 0;
|
||||
}
|
||||
} else {
|
||||
ptr_519DBC->field_8 = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (levelMod != 0 && randomBetween(0, 100) > 100 * levelMod / memberDescription->level_up_every) {
|
||||
continue;
|
||||
}
|
||||
|
||||
levelUpInfo->level++;
|
||||
if (levelMod != 0) {
|
||||
levelUpInfo->isEarly = 1;
|
||||
}
|
||||
|
||||
if (_partyMemberCopyLevelInfo(obj, memberDescription->level_pids[levelUpInfo->level]) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
name = critterGetName(obj);
|
||||
// %s has gained in some abilities.
|
||||
text = getmsg(&gMiscMessageList, &msg, 9000);
|
||||
snprintf(str, sizeof(str), text, name);
|
||||
displayMonitorAddMessage(str);
|
||||
|
||||
debugPrint(str);
|
||||
|
||||
// Individual message
|
||||
msg.num = 9000 + 10 * memberIndex + levelUpInfo->level - 1;
|
||||
if (messageListGetItem(&gMiscMessageList, &msg)) {
|
||||
name = critterGetName(obj);
|
||||
snprintf(str, sizeof(str), msg.text, name);
|
||||
textObjectAdd(obj, str, 101, _colorTable[0x7FFF], _colorTable[0], &levelUpMessageRect);
|
||||
tileWindowRefreshRect(&levelUpMessageRect, obj->elevation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1552,23 +1560,23 @@ int _partyMemberIncLevels()
|
||||
}
|
||||
|
||||
// 0x495EA8
|
||||
static int _partyMemberCopyLevelInfo(Object* critter, int a2)
|
||||
static int _partyMemberCopyLevelInfo(Object* critter, int stagePid)
|
||||
{
|
||||
if (critter == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a2 == -1) {
|
||||
if (stagePid == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Proto* proto1;
|
||||
if (protoGetProto(critter->pid, &proto1) == -1) {
|
||||
Proto* proto;
|
||||
if (protoGetProto(critter->pid, &proto) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Proto* proto2;
|
||||
if (protoGetProto(a2, &proto2) == -1) {
|
||||
Proto* stageProto;
|
||||
if (protoGetProto(stagePid, &stageProto) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1583,15 +1591,15 @@ static int _partyMemberCopyLevelInfo(Object* critter, int a2)
|
||||
critterAdjustHitPoints(critter, maxHp);
|
||||
|
||||
for (int stat = 0; stat < SPECIAL_STAT_COUNT; stat++) {
|
||||
proto1->critter.data.baseStats[stat] = proto2->critter.data.baseStats[stat];
|
||||
proto->critter.data.baseStats[stat] = stageProto->critter.data.baseStats[stat];
|
||||
}
|
||||
|
||||
for (int stat = 0; stat < SPECIAL_STAT_COUNT; stat++) {
|
||||
proto1->critter.data.bonusStats[stat] = proto2->critter.data.bonusStats[stat];
|
||||
proto->critter.data.bonusStats[stat] = stageProto->critter.data.bonusStats[stat];
|
||||
}
|
||||
|
||||
for (int skill = 0; skill < SKILL_COUNT; skill++) {
|
||||
proto1->critter.data.skills[skill] = proto2->critter.data.skills[skill];
|
||||
proto->critter.data.skills[skill] = stageProto->critter.data.skills[skill];
|
||||
}
|
||||
|
||||
critter->data.critter.hp = critterGetStat(critter, STAT_MAXIMUM_HIT_POINTS);
|
||||
@@ -1604,7 +1612,7 @@ static int _partyMemberCopyLevelInfo(Object* critter, int a2)
|
||||
if (item2 != nullptr) {
|
||||
// SFALL: Fix for party member's equipped weapon being placed in the
|
||||
// incorrect item slot after leveling up.
|
||||
_invenWieldFunc(critter, item2, 1, false);
|
||||
_invenWieldFunc(critter, item2, HAND_RIGHT, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
32
src/perk.cc
32
src/perk.cc
@@ -14,19 +14,33 @@
|
||||
|
||||
namespace fallout {
|
||||
|
||||
enum PerkParamMode {
|
||||
PERK_PARAM_MODE_FIRST_ONLY,
|
||||
PERK_PARAM_MODE_OR,
|
||||
PERK_PARAM_MODE_AND,
|
||||
};
|
||||
|
||||
typedef struct PerkDescription {
|
||||
char* name;
|
||||
char* description;
|
||||
int frmId;
|
||||
int maxRank;
|
||||
int minLevel;
|
||||
// Critter stat to modify for every perk rank.
|
||||
int stat;
|
||||
// Stat modifier for every perk rank.
|
||||
int statModifier;
|
||||
// Skill number, normally. If bit 0x4000000 is set, will be treated as global var number instead.
|
||||
int param1;
|
||||
// Required value of a skill or global var.
|
||||
int value1;
|
||||
int field_24;
|
||||
// Specifies wether to require both params, either one or just use the first one.
|
||||
int paramMode;
|
||||
// Skill or gvar number, see param1.
|
||||
int param2;
|
||||
// Required value of a skill or global var.
|
||||
int value2;
|
||||
// Required minimum value for every primary stat.
|
||||
int stats[PRIMARY_STAT_COUNT];
|
||||
} PerkDescription;
|
||||
|
||||
@@ -308,7 +322,7 @@ static bool perkCanAdd(Object* critter, int perk)
|
||||
}
|
||||
}
|
||||
|
||||
bool v1 = true;
|
||||
bool req1Fulfilled = true;
|
||||
|
||||
int param1 = perkDescription->param1;
|
||||
if (param1 != -1) {
|
||||
@@ -322,32 +336,32 @@ static bool perkCanAdd(Object* critter, int perk)
|
||||
if (value1 < 0) {
|
||||
if (isVariable) {
|
||||
if (gameGetGlobalVar(param1) >= value1) {
|
||||
v1 = false;
|
||||
req1Fulfilled = false;
|
||||
}
|
||||
} else {
|
||||
if (skillGetValue(critter, param1) >= -value1) {
|
||||
v1 = false;
|
||||
req1Fulfilled = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isVariable) {
|
||||
if (gameGetGlobalVar(param1) < value1) {
|
||||
v1 = false;
|
||||
req1Fulfilled = false;
|
||||
}
|
||||
} else {
|
||||
if (skillGetValue(critter, param1) < value1) {
|
||||
v1 = false;
|
||||
req1Fulfilled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!v1 || perkDescription->field_24 == 2) {
|
||||
if (perkDescription->field_24 == 0) {
|
||||
if (!req1Fulfilled || perkDescription->paramMode == PERK_PARAM_MODE_AND) {
|
||||
if (perkDescription->paramMode == PERK_PARAM_MODE_FIRST_ONLY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!v1 && perkDescription->field_24 == 2) {
|
||||
if (!req1Fulfilled && perkDescription->paramMode == PERK_PARAM_MODE_AND) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "random.h"
|
||||
#include "scripts.h"
|
||||
#include "settings.h"
|
||||
#include "sfall_config.h"
|
||||
#include "stat.h"
|
||||
#include "svga.h"
|
||||
#include "text_font.h"
|
||||
@@ -211,13 +212,13 @@ static int _PrintAMelevList(int a1);
|
||||
static int _PrintAMList(int a1);
|
||||
static void pipboyHandleVideoArchive(int a1);
|
||||
static int pipboyRenderVideoArchive(int a1);
|
||||
static void pipboyHandleAlarmClock(int a1);
|
||||
static void pipboyHandleAlarmClock(int eventCode);
|
||||
static void pipboyWindowRenderRestOptions(int a1);
|
||||
static void pipboyDrawHitPoints();
|
||||
static void pipboyWindowCreateButtons(int a1, int a2, bool a3);
|
||||
static void pipboyWindowDestroyButtons();
|
||||
static bool pipboyRest(int hours, int minutes, int kind);
|
||||
static bool _Check4Health(int a1);
|
||||
static bool _Check4Health(int minutes);
|
||||
static bool _AddHealth();
|
||||
static void _ClacTime(int* hours, int* minutes, int wakeUpHour);
|
||||
static int pipboyRenderScreensaver();
|
||||
@@ -394,13 +395,14 @@ unsigned char _holo_flag;
|
||||
unsigned char _stat_flag;
|
||||
|
||||
static int gPipboyPrevTab;
|
||||
static bool pipboy_available_at_game_start = false;
|
||||
|
||||
static FrmImage _pipboyFrmImages[PIPBOY_FRM_COUNT];
|
||||
|
||||
// 0x497004
|
||||
int pipboyOpen(int intent)
|
||||
{
|
||||
if (!wmMapPipboyActive()) {
|
||||
if (!wmMapPipboyActive() && !pipboy_available_at_game_start) {
|
||||
// You aren't wearing the pipboy!
|
||||
const char* text = getmsg(&gMiscMessageList, &gPipboyMessageListItem, 7000);
|
||||
showDialogBox(text, nullptr, 0, 192, 135, _colorTable[32328], nullptr, _colorTable[32328], 1);
|
||||
@@ -742,6 +744,19 @@ static void pipboyWindowFree()
|
||||
// 0x497918
|
||||
static void _pip_init_()
|
||||
{
|
||||
// SFALL: Make the pipboy available at the start of the game.
|
||||
// CE: The implementation is slightly different. SFALL has two values for
|
||||
// making the pipboy available at the start of the game. When the option is
|
||||
// set to (1), the `MOVIE_VSUIT` is automatically marked as viewed (the suit
|
||||
// grants the pipboy, see `wmMapPipboyActive`). Doing so exposes that movie
|
||||
// in the "Video Archives" section of the pipboy, which is likely an
|
||||
// undesired side effect. When the option is set to (2), the check is simply
|
||||
// bypassed. CE implements only the latter approach, as it does not have any
|
||||
// side effects.
|
||||
int value = 0;
|
||||
if (configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PIPBOY_AVAILABLE_AT_GAMESTART, &value)) {
|
||||
pipboy_available_at_game_start = value == 1 || value == 2;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Uncollapsed 0x497918.
|
||||
@@ -1751,9 +1766,9 @@ static int pipboyRenderVideoArchive(int a1)
|
||||
}
|
||||
|
||||
// 0x499518
|
||||
static void pipboyHandleAlarmClock(int a1)
|
||||
static void pipboyHandleAlarmClock(int eventCode)
|
||||
{
|
||||
if (a1 == 1024) {
|
||||
if (eventCode == 1024) {
|
||||
if (_critter_can_obj_dude_rest()) {
|
||||
pipboyWindowDestroyButtons();
|
||||
pipboyWindowRenderRestOptions(0);
|
||||
@@ -1769,15 +1784,14 @@ static void pipboyHandleAlarmClock(int a1)
|
||||
// appropriate handler (not the alarm clock).
|
||||
gPipboyTab = gPipboyPrevTab;
|
||||
}
|
||||
} else if (a1 >= 4 && a1 <= 17) {
|
||||
} else if (eventCode >= 4 && eventCode <= 17) {
|
||||
soundPlayFile("ib1p1xx1");
|
||||
|
||||
pipboyWindowRenderRestOptions(a1 - 3);
|
||||
pipboyWindowRenderRestOptions(eventCode - 3);
|
||||
|
||||
int duration = a1 - 4;
|
||||
int duration = eventCode - 4;
|
||||
int minutes = 0;
|
||||
int hours = 0;
|
||||
int v10 = 0;
|
||||
|
||||
switch (duration) {
|
||||
case PIPBOY_REST_DURATION_TEN_MINUTES:
|
||||
@@ -2160,9 +2174,9 @@ static bool pipboyRest(int hours, int minutes, int duration)
|
||||
}
|
||||
|
||||
// 0x499FCC
|
||||
static bool _Check4Health(int a1)
|
||||
static bool _Check4Health(int minutes)
|
||||
{
|
||||
_rest_time += a1;
|
||||
_rest_time += minutes;
|
||||
|
||||
if (_rest_time < 180) {
|
||||
return false;
|
||||
|
||||
@@ -818,9 +818,7 @@ int _proto_update_init(Object* obj)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 14; i++) {
|
||||
obj->field_2C_array[i] = 0;
|
||||
}
|
||||
memset(&(obj->data), 0, sizeof(ObjectData));
|
||||
|
||||
if (PID_TYPE(obj->pid) != OBJ_TYPE_CRITTER) {
|
||||
return _proto_update_gen(obj);
|
||||
|
||||
@@ -35,27 +35,29 @@
|
||||
namespace fallout {
|
||||
|
||||
static int _obj_remove_from_inven(Object* critter, Object* item);
|
||||
static int _obj_use_book(Object* item_obj);
|
||||
static int _obj_use_flare(Object* critter_obj, Object* item_obj);
|
||||
static int _obj_use_radio(Object* item_obj);
|
||||
static int _obj_use_book(Object* item);
|
||||
static int _obj_use_flare(Object* critter, Object* item);
|
||||
static int _obj_use_radio(Object* item);
|
||||
static int _obj_use_explosive(Object* explosive);
|
||||
static int _obj_use_power_on_car(Object* ammo);
|
||||
static int _obj_use_misc_item(Object* item_obj);
|
||||
static int _protinstTestDroppedExplosive(Object* a1);
|
||||
static int _protinst_default_use_item(Object* a1, Object* a2, Object* item);
|
||||
static int useLadderDown(Object* a1, Object* ladder, int a3);
|
||||
static int useLadderUp(Object* a1, Object* ladder, int a3);
|
||||
static int useStairs(Object* a1, Object* stairs, int a3);
|
||||
static int _set_door_state_open(Object* a1, Object* a2);
|
||||
static int _set_door_state_closed(Object* a1, Object* a2);
|
||||
static int _check_door_state(Object* a1, Object* a2);
|
||||
static int _obj_use_misc_item(Object* item);
|
||||
static int _protinstTestDroppedExplosive(Object* explosiveItem);
|
||||
static int _protinst_default_use_item(Object* user, Object* targetObj, Object* item);
|
||||
static int useLadderDown(Object* user, Object* ladder);
|
||||
static int useLadderUp(Object* user, Object* ladder);
|
||||
static int useStairs(Object* user, Object* stairs);
|
||||
static int _set_door_state_open(Object* door, Object* obj2);
|
||||
static int _set_door_state_closed(Object* door, Object* obj2);
|
||||
static int _check_door_state(Object* door, Object* obj2);
|
||||
static bool _obj_is_portal(Object* obj);
|
||||
static bool _obj_is_lockable(Object* obj);
|
||||
static bool _obj_is_openable(Object* obj);
|
||||
static int objectOpenClose(Object* obj);
|
||||
static bool objectIsJammed(Object* obj);
|
||||
|
||||
// 0x49A990
|
||||
// Accessed but not really used
|
||||
//
|
||||
// 0x49A990
|
||||
static MessageListItem stru_49A990;
|
||||
|
||||
// 0x49A9A0
|
||||
@@ -105,10 +107,10 @@ int _obj_new_sid(Object* object, int* sidPtr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
script->field_14 = sid & 0xFFFFFF;
|
||||
script->index = sid & 0xFFFFFF;
|
||||
|
||||
if (objectType == OBJ_TYPE_CRITTER) {
|
||||
object->field_80 = script->field_14;
|
||||
object->scriptIndex = script->index;
|
||||
}
|
||||
|
||||
if (scriptType == SCRIPT_TYPE_SPATIAL) {
|
||||
@@ -120,7 +122,7 @@ int _obj_new_sid(Object* object, int* sidPtr)
|
||||
object->id = scriptsNewObjectId();
|
||||
}
|
||||
|
||||
script->field_1C = object->id;
|
||||
script->ownerId = object->id;
|
||||
script->owner = object;
|
||||
|
||||
_scr_find_str_run_info(sid & 0xFFFFFF, &(script->field_50), *sidPtr);
|
||||
@@ -129,9 +131,9 @@ int _obj_new_sid(Object* object, int* sidPtr)
|
||||
}
|
||||
|
||||
// 0x49AAC0
|
||||
int _obj_new_sid_inst(Object* obj, int scriptType, int a3)
|
||||
int _obj_new_sid_inst(Object* obj, int scriptType, int scriptIndex)
|
||||
{
|
||||
if (a3 == -1) {
|
||||
if (scriptIndex == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -145,7 +147,7 @@ int _obj_new_sid_inst(Object* obj, int scriptType, int a3)
|
||||
return -1;
|
||||
}
|
||||
|
||||
script->field_14 = a3;
|
||||
script->index = scriptIndex;
|
||||
if (scriptType == SCRIPT_TYPE_SPATIAL) {
|
||||
script->sp.built_tile = builtTileCreate(obj->tile, obj->elevation);
|
||||
script->sp.radius = 3;
|
||||
@@ -154,14 +156,14 @@ int _obj_new_sid_inst(Object* obj, int scriptType, int a3)
|
||||
obj->sid = sid;
|
||||
|
||||
obj->id = scriptsNewObjectId();
|
||||
script->field_1C = obj->id;
|
||||
script->ownerId = obj->id;
|
||||
|
||||
script->owner = obj;
|
||||
|
||||
_scr_find_str_run_info(a3 & 0xFFFFFF, &(script->field_50), sid);
|
||||
_scr_find_str_run_info(scriptIndex & 0xFFFFFF, &(script->field_50), sid);
|
||||
|
||||
if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) {
|
||||
obj->field_80 = script->field_14;
|
||||
obj->scriptIndex = script->index;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -810,7 +812,7 @@ static int _obj_use_book(Object* book)
|
||||
// Light a flare.
|
||||
//
|
||||
// 0x49BBA8
|
||||
static int _obj_use_flare(Object* critter_obj, Object* flare)
|
||||
static int _obj_use_flare(Object* critter, Object* flare)
|
||||
{
|
||||
MessageListItem messageListItem;
|
||||
|
||||
@@ -819,7 +821,7 @@ static int _obj_use_flare(Object* critter_obj, Object* flare)
|
||||
}
|
||||
|
||||
if ((flare->flags & OBJECT_QUEUED) != 0) {
|
||||
if (critter_obj == gDude) {
|
||||
if (critter == gDude) {
|
||||
// The flare is already lit.
|
||||
messageListItem.num = 588;
|
||||
if (messageListGetItem(&gProtoMessageList, &messageListItem)) {
|
||||
@@ -827,7 +829,7 @@ static int _obj_use_flare(Object* critter_obj, Object* flare)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (critter_obj == gDude) {
|
||||
if (critter == gDude) {
|
||||
// You light the flare.
|
||||
messageListItem.num = 588;
|
||||
if (messageListGetItem(&gProtoMessageList, &messageListItem)) {
|
||||
@@ -1072,10 +1074,10 @@ int _protinst_use_item(Object* critter, Object* item)
|
||||
}
|
||||
|
||||
// 0x49BFE8
|
||||
static int _protinstTestDroppedExplosive(Object* a1)
|
||||
static int _protinstTestDroppedExplosive(Object* explosiveItem)
|
||||
{
|
||||
// SFALL
|
||||
if (explosiveIsActiveExplosive(a1->pid)) {
|
||||
if (explosiveIsActiveExplosive(explosiveItem->pid)) {
|
||||
Attack attack;
|
||||
attackInit(&attack, gDude, nullptr, HIT_MODE_PUNCH, HIT_LOCATION_TORSO);
|
||||
attack.attackerFlags = DAM_HIT;
|
||||
@@ -1157,7 +1159,7 @@ int _obj_use_item(Object* a1, Object* a2)
|
||||
}
|
||||
|
||||
// 0x49C240
|
||||
static int _protinst_default_use_item(Object* a1, Object* a2, Object* item)
|
||||
static int _protinst_default_use_item(Object* user, Object* targetObj, Object* item)
|
||||
{
|
||||
char formattedText[90];
|
||||
MessageListItem messageListItem;
|
||||
@@ -1165,8 +1167,8 @@ static int _protinst_default_use_item(Object* a1, Object* a2, Object* item)
|
||||
int rc;
|
||||
switch (itemGetType(item)) {
|
||||
case ITEM_TYPE_DRUG:
|
||||
if (PID_TYPE(a2->pid) != OBJ_TYPE_CRITTER) {
|
||||
if (a1 == gDude) {
|
||||
if (PID_TYPE(targetObj->pid) != OBJ_TYPE_CRITTER) {
|
||||
if (user == gDude) {
|
||||
// That does nothing
|
||||
messageListItem.num = 582;
|
||||
if (messageListGetItem(&gProtoMessageList, &messageListItem)) {
|
||||
@@ -1176,7 +1178,7 @@ static int _protinst_default_use_item(Object* a1, Object* a2, Object* item)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (critterIsDead(a2)) {
|
||||
if (critterIsDead(targetObj)) {
|
||||
// 583: To your dismay, you realize that it is already dead.
|
||||
// 584: As you reach down, you realize that it is already dead.
|
||||
// 585: Alas, you are too late.
|
||||
@@ -1188,24 +1190,24 @@ static int _protinst_default_use_item(Object* a1, Object* a2, Object* item)
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = _item_d_take_drug(a2, item);
|
||||
rc = _item_d_take_drug(targetObj, item);
|
||||
|
||||
if (a1 == gDude && a2 != gDude) {
|
||||
if (user == gDude && targetObj != gDude) {
|
||||
// TODO: Looks like there is bug in this branch, message 580 will never be shown,
|
||||
// as we can only be here when target is not dude.
|
||||
|
||||
// 580: You use the %s.
|
||||
// 581: You use the %s on %s.
|
||||
messageListItem.num = 580 + (a2 != gDude);
|
||||
messageListItem.num = 580 + (targetObj != gDude);
|
||||
if (!messageListGetItem(&gProtoMessageList, &messageListItem)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(formattedText, sizeof(formattedText), messageListItem.text, objectGetName(item), objectGetName(a2));
|
||||
snprintf(formattedText, sizeof(formattedText), messageListItem.text, objectGetName(item), objectGetName(targetObj));
|
||||
displayMonitorAddMessage(formattedText);
|
||||
}
|
||||
|
||||
if (a2 == gDude) {
|
||||
if (targetObj == gDude) {
|
||||
interfaceRenderHitPoints(true);
|
||||
}
|
||||
|
||||
@@ -1213,7 +1215,7 @@ static int _protinst_default_use_item(Object* a1, Object* a2, Object* item)
|
||||
case ITEM_TYPE_AMMO:
|
||||
// SFALL: Fix for being able to charge the car by using cells on other
|
||||
// scenery/critters.
|
||||
if (a2->pid == PROTO_ID_CAR || a2->pid == PROTO_ID_CAR_TRUNK) {
|
||||
if (targetObj->pid == PROTO_ID_CAR || targetObj->pid == PROTO_ID_CAR_TRUNK) {
|
||||
rc = _obj_use_power_on_car(item);
|
||||
if (rc == 1) {
|
||||
return 1;
|
||||
@@ -1224,7 +1226,7 @@ static int _protinst_default_use_item(Object* a1, Object* a2, Object* item)
|
||||
break;
|
||||
case ITEM_TYPE_WEAPON:
|
||||
case ITEM_TYPE_MISC:
|
||||
rc = _obj_use_flare(a1, item);
|
||||
rc = _obj_use_flare(user, item);
|
||||
if (rc == 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -1240,7 +1242,7 @@ static int _protinst_default_use_item(Object* a1, Object* a2, Object* item)
|
||||
}
|
||||
|
||||
// 0x49C3CC
|
||||
int _protinst_use_item_on(Object* a1, Object* a2, Object* item)
|
||||
int _protinst_use_item_on(Object* critter, Object* targetObj, Object* item)
|
||||
{
|
||||
int messageId = -1;
|
||||
int criticalChanceModifier = 0;
|
||||
@@ -1277,55 +1279,55 @@ int _protinst_use_item_on(Object* a1, Object* a2, Object* item)
|
||||
Script* script;
|
||||
|
||||
if (item->sid == -1) {
|
||||
if (a2->sid == -1) {
|
||||
return _protinst_default_use_item(a1, a2, item);
|
||||
if (targetObj->sid == -1) {
|
||||
return _protinst_default_use_item(critter, targetObj, item);
|
||||
}
|
||||
|
||||
scriptSetObjects(a2->sid, a1, item);
|
||||
scriptExecProc(a2->sid, SCRIPT_PROC_USE_OBJ_ON);
|
||||
scriptSetObjects(targetObj->sid, critter, item);
|
||||
scriptExecProc(targetObj->sid, SCRIPT_PROC_USE_OBJ_ON);
|
||||
|
||||
if (scriptGetScript(a2->sid, &script) == -1) {
|
||||
if (scriptGetScript(targetObj->sid, &script) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!script->scriptOverrides) {
|
||||
return _protinst_default_use_item(a1, a2, item);
|
||||
return _protinst_default_use_item(critter, targetObj, item);
|
||||
}
|
||||
} else {
|
||||
scriptSetObjects(item->sid, a1, a2);
|
||||
scriptSetObjects(item->sid, critter, targetObj);
|
||||
scriptExecProc(item->sid, SCRIPT_PROC_USE_OBJ_ON);
|
||||
|
||||
if (scriptGetScript(item->sid, &script) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (script->field_28 == 0) {
|
||||
if (a2->sid == -1) {
|
||||
return _protinst_default_use_item(a1, a2, item);
|
||||
if (script->returnValue == 0) {
|
||||
if (targetObj->sid == -1) {
|
||||
return _protinst_default_use_item(critter, targetObj, item);
|
||||
}
|
||||
|
||||
scriptSetObjects(a2->sid, a1, item);
|
||||
scriptExecProc(a2->sid, SCRIPT_PROC_USE_OBJ_ON);
|
||||
scriptSetObjects(targetObj->sid, critter, item);
|
||||
scriptExecProc(targetObj->sid, SCRIPT_PROC_USE_OBJ_ON);
|
||||
|
||||
Script* script;
|
||||
if (scriptGetScript(a2->sid, &script) == -1) {
|
||||
if (scriptGetScript(targetObj->sid, &script) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!script->scriptOverrides) {
|
||||
return _protinst_default_use_item(a1, a2, item);
|
||||
return _protinst_default_use_item(critter, targetObj, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return script->field_28;
|
||||
return script->returnValue;
|
||||
}
|
||||
|
||||
if (isInCombat()) {
|
||||
MessageListItem messageListItem;
|
||||
// You cannot do that in combat.
|
||||
messageListItem.num = 902;
|
||||
if (a1 == gDude) {
|
||||
if (critter == gDude) {
|
||||
if (messageListGetItem(&gProtoMessageList, &messageListItem)) {
|
||||
displayMonitorAddMessage(messageListItem.text);
|
||||
}
|
||||
@@ -1333,7 +1335,7 @@ int _protinst_use_item_on(Object* a1, Object* a2, Object* item)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (skillUse(a1, a2, skill, criticalChanceModifier) != 0) {
|
||||
if (skillUse(critter, targetObj, skill, criticalChanceModifier) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1343,7 +1345,7 @@ int _protinst_use_item_on(Object* a1, Object* a2, Object* item)
|
||||
|
||||
MessageListItem messageListItem;
|
||||
messageListItem.num = messageId;
|
||||
if (a1 == gDude) {
|
||||
if (critter == gDude) {
|
||||
if (messageListGetItem(&gProtoMessageList, &messageListItem)) {
|
||||
displayMonitorAddMessage(messageListItem.text);
|
||||
}
|
||||
@@ -1353,21 +1355,21 @@ int _protinst_use_item_on(Object* a1, Object* a2, Object* item)
|
||||
}
|
||||
|
||||
// 0x49C5FC
|
||||
int _obj_use_item_on(Object* a1, Object* a2, Object* a3)
|
||||
int _obj_use_item_on(Object* user, Object* targetObj, Object* item)
|
||||
{
|
||||
int rc = _protinst_use_item_on(a1, a2, a3);
|
||||
int rc = _protinst_use_item_on(user, targetObj, item);
|
||||
|
||||
if (rc == 1) {
|
||||
if (a1 != nullptr) {
|
||||
int flags = a3->flags & OBJECT_IN_ANY_HAND;
|
||||
itemRemove(a1, a3, 1);
|
||||
if (user != nullptr) {
|
||||
int flags = item->flags & OBJECT_IN_ANY_HAND;
|
||||
itemRemove(user, item, 1);
|
||||
|
||||
Object* replacedItem = itemReplace(a1, a3, flags);
|
||||
Object* replacedItem = itemReplace(user, item, flags);
|
||||
|
||||
// CE: Fix rare crash when using uninitialized action variables. The
|
||||
// following code is on par with |_obj_use_item| which does not
|
||||
// crash.
|
||||
if (a1 == gDude) {
|
||||
if (user == gDude) {
|
||||
int leftItemAction;
|
||||
int rightItemAction;
|
||||
interfaceGetItemActions(&leftItemAction, &rightItemAction);
|
||||
@@ -1387,7 +1389,7 @@ int _obj_use_item_on(Object* a1, Object* a2, Object* a3)
|
||||
}
|
||||
}
|
||||
|
||||
_obj_destroy(a3);
|
||||
_obj_destroy(item);
|
||||
|
||||
rc = 0;
|
||||
}
|
||||
@@ -1429,10 +1431,10 @@ int _check_scenery_ap_cost(Object* obj, Object* a2)
|
||||
}
|
||||
|
||||
// 0x49C740
|
||||
int _obj_use(Object* a1, Object* a2)
|
||||
int _obj_use(Object* user, Object* targetObj)
|
||||
{
|
||||
int type = FID_TYPE(a2->fid);
|
||||
if (a1 == gDude) {
|
||||
int type = FID_TYPE(targetObj->fid);
|
||||
if (user == gDude) {
|
||||
if (type != OBJ_TYPE_SCENERY) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1443,22 +1445,22 @@ int _obj_use(Object* a1, Object* a2)
|
||||
}
|
||||
|
||||
Proto* sceneryProto;
|
||||
if (protoGetProto(a2->pid, &sceneryProto) == -1) {
|
||||
if (protoGetProto(targetObj->pid, &sceneryProto) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PID_TYPE(a2->pid) == OBJ_TYPE_SCENERY && sceneryProto->scenery.type == SCENERY_TYPE_DOOR) {
|
||||
return _obj_use_door(a1, a2, 0);
|
||||
if (PID_TYPE(targetObj->pid) == OBJ_TYPE_SCENERY && sceneryProto->scenery.type == SCENERY_TYPE_DOOR) {
|
||||
return _obj_use_door(user, targetObj);
|
||||
}
|
||||
|
||||
bool scriptOverrides = false;
|
||||
|
||||
if (a2->sid != -1) {
|
||||
scriptSetObjects(a2->sid, a1, a2);
|
||||
scriptExecProc(a2->sid, SCRIPT_PROC_USE);
|
||||
if (targetObj->sid != -1) {
|
||||
scriptSetObjects(targetObj->sid, user, targetObj);
|
||||
scriptExecProc(targetObj->sid, SCRIPT_PROC_USE);
|
||||
|
||||
Script* script;
|
||||
if (scriptGetScript(a2->sid, &script) == -1) {
|
||||
if (scriptGetScript(targetObj->sid, &script) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1466,17 +1468,17 @@ int _obj_use(Object* a1, Object* a2)
|
||||
}
|
||||
|
||||
if (!scriptOverrides) {
|
||||
if (PID_TYPE(a2->pid) == OBJ_TYPE_SCENERY) {
|
||||
if (PID_TYPE(targetObj->pid) == OBJ_TYPE_SCENERY) {
|
||||
if (sceneryProto->scenery.type == SCENERY_TYPE_LADDER_DOWN) {
|
||||
if (useLadderDown(a1, a2, 0) == 0) {
|
||||
if (useLadderDown(user, targetObj) == 0) {
|
||||
scriptOverrides = true;
|
||||
}
|
||||
} else if (sceneryProto->scenery.type == SCENERY_TYPE_LADDER_UP) {
|
||||
if (useLadderUp(a1, a2, 0) == 0) {
|
||||
if (useLadderUp(user, targetObj) == 0) {
|
||||
scriptOverrides = true;
|
||||
}
|
||||
} else if (sceneryProto->scenery.type == SCENERY_TYPE_STAIRS) {
|
||||
if (useStairs(a1, a2, 0) == 0) {
|
||||
if (useStairs(user, targetObj) == 0) {
|
||||
scriptOverrides = true;
|
||||
}
|
||||
}
|
||||
@@ -1484,7 +1486,7 @@ int _obj_use(Object* a1, Object* a2)
|
||||
}
|
||||
|
||||
if (!scriptOverrides) {
|
||||
if (a1 == gDude) {
|
||||
if (user == gDude) {
|
||||
// You see: %s
|
||||
MessageListItem messageListItem;
|
||||
messageListItem.num = 480;
|
||||
@@ -1493,7 +1495,7 @@ int _obj_use(Object* a1, Object* a2)
|
||||
}
|
||||
|
||||
char formattedText[260];
|
||||
const char* name = objectGetName(a2);
|
||||
const char* name = objectGetName(targetObj);
|
||||
snprintf(formattedText, sizeof(formattedText), messageListItem.text, name);
|
||||
displayMonitorAddMessage(formattedText);
|
||||
}
|
||||
@@ -1505,7 +1507,7 @@ int _obj_use(Object* a1, Object* a2)
|
||||
}
|
||||
|
||||
// 0x49C900
|
||||
static int useLadderDown(Object* a1, Object* ladder, int a3)
|
||||
static int useLadderDown(Object* user, Object* ladder)
|
||||
{
|
||||
int builtTile = ladder->data.scenery.ladder.destinationBuiltTile;
|
||||
if (builtTile == -1) {
|
||||
@@ -1528,7 +1530,7 @@ static int useLadderDown(Object* a1, Object* ladder, int a3)
|
||||
wmMapMarkMapEntranceState(transition.map, elevation, 1);
|
||||
} else {
|
||||
Rect updatedRect;
|
||||
if (objectSetLocation(a1, tile, elevation, &updatedRect) == -1) {
|
||||
if (objectSetLocation(user, tile, elevation, &updatedRect) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1539,7 +1541,7 @@ static int useLadderDown(Object* a1, Object* ladder, int a3)
|
||||
}
|
||||
|
||||
// 0x49C9A4
|
||||
static int useLadderUp(Object* a1, Object* ladder, int a3)
|
||||
static int useLadderUp(Object* user, Object* ladder)
|
||||
{
|
||||
int builtTile = ladder->data.scenery.ladder.destinationBuiltTile;
|
||||
if (builtTile == -1) {
|
||||
@@ -1562,7 +1564,7 @@ static int useLadderUp(Object* a1, Object* ladder, int a3)
|
||||
wmMapMarkMapEntranceState(transition.map, elevation, 1);
|
||||
} else {
|
||||
Rect updatedRect;
|
||||
if (objectSetLocation(a1, tile, elevation, &updatedRect) == -1) {
|
||||
if (objectSetLocation(user, tile, elevation, &updatedRect) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1573,7 +1575,7 @@ static int useLadderUp(Object* a1, Object* ladder, int a3)
|
||||
}
|
||||
|
||||
// 0x49CA48
|
||||
static int useStairs(Object* a1, Object* stairs, int a3)
|
||||
static int useStairs(Object* user, Object* stairs)
|
||||
{
|
||||
int builtTile = stairs->data.scenery.stairs.destinationBuiltTile;
|
||||
if (builtTile == -1) {
|
||||
@@ -1596,7 +1598,7 @@ static int useStairs(Object* a1, Object* stairs, int a3)
|
||||
wmMapMarkMapEntranceState(transition.map, elevation, 1);
|
||||
} else {
|
||||
Rect updatedRect;
|
||||
if (objectSetLocation(a1, tile, elevation, &updatedRect) == -1) {
|
||||
if (objectSetLocation(user, tile, elevation, &updatedRect) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1607,37 +1609,37 @@ static int useStairs(Object* a1, Object* stairs, int a3)
|
||||
}
|
||||
|
||||
// 0x49CAF4
|
||||
static int _set_door_state_open(Object* a1, Object* a2)
|
||||
static int _set_door_state_open(Object* door, Object* obj2)
|
||||
{
|
||||
a1->data.scenery.door.openFlags |= 0x01;
|
||||
door->data.scenery.door.openFlags |= 0x01;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x49CB04
|
||||
static int _set_door_state_closed(Object* a1, Object* a2)
|
||||
static int _set_door_state_closed(Object* door, Object* obj2)
|
||||
{
|
||||
a1->data.scenery.door.openFlags &= ~0x01;
|
||||
door->data.scenery.door.openFlags &= ~0x01;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x49CB14
|
||||
static int _check_door_state(Object* a1, Object* a2)
|
||||
static int _check_door_state(Object* door, Object* obj2)
|
||||
{
|
||||
if ((a1->data.scenery.door.openFlags & 0x01) == 0) {
|
||||
if ((door->data.scenery.door.openFlags & 0x01) == 0) {
|
||||
// SFALL: Fix flags on non-door objects.
|
||||
if (_obj_is_portal(a1)) {
|
||||
a1->flags &= ~OBJECT_OPEN_DOOR;
|
||||
if (_obj_is_portal(door)) {
|
||||
door->flags &= ~OBJECT_OPEN_DOOR;
|
||||
}
|
||||
|
||||
_obj_rebuild_all_light();
|
||||
tileWindowRefresh();
|
||||
|
||||
if (a1->frame == 0) {
|
||||
if (door->frame == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CacheEntry* artHandle;
|
||||
Art* art = artLock(a1->fid, &artHandle);
|
||||
Art* art = artLock(door->fid, &artHandle);
|
||||
if (art == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1645,16 +1647,16 @@ static int _check_door_state(Object* a1, Object* a2)
|
||||
Rect dirty;
|
||||
Rect temp;
|
||||
|
||||
objectGetRect(a1, &dirty);
|
||||
objectGetRect(door, &dirty);
|
||||
|
||||
for (int frame = a1->frame - 1; frame >= 0; frame--) {
|
||||
for (int frame = door->frame - 1; frame >= 0; frame--) {
|
||||
int x;
|
||||
int y;
|
||||
artGetFrameOffsets(art, frame, a1->rotation, &x, &y);
|
||||
_obj_offset(a1, -x, -y, &temp);
|
||||
artGetFrameOffsets(art, frame, door->rotation, &x, &y);
|
||||
_obj_offset(door, -x, -y, &temp);
|
||||
}
|
||||
|
||||
objectSetFrame(a1, 0, &temp);
|
||||
objectSetFrame(door, 0, &temp);
|
||||
rectUnion(&dirty, &temp, &dirty);
|
||||
|
||||
tileWindowRefreshRect(&dirty, gElevation);
|
||||
@@ -1663,21 +1665,21 @@ static int _check_door_state(Object* a1, Object* a2)
|
||||
return 0;
|
||||
} else {
|
||||
// SFALL: Fix flags on non-door objects.
|
||||
if (_obj_is_portal(a1)) {
|
||||
a1->flags |= OBJECT_OPEN_DOOR;
|
||||
if (_obj_is_portal(door)) {
|
||||
door->flags |= OBJECT_OPEN_DOOR;
|
||||
}
|
||||
|
||||
_obj_rebuild_all_light();
|
||||
tileWindowRefresh();
|
||||
|
||||
CacheEntry* artHandle;
|
||||
Art* art = artLock(a1->fid, &artHandle);
|
||||
Art* art = artLock(door->fid, &artHandle);
|
||||
if (art == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int frameCount = artGetFrameCount(art);
|
||||
if (a1->frame == frameCount - 1) {
|
||||
if (door->frame == frameCount - 1) {
|
||||
artUnlock(artHandle);
|
||||
return 0;
|
||||
}
|
||||
@@ -1685,16 +1687,16 @@ static int _check_door_state(Object* a1, Object* a2)
|
||||
Rect dirty;
|
||||
Rect temp;
|
||||
|
||||
objectGetRect(a1, &dirty);
|
||||
objectGetRect(door, &dirty);
|
||||
|
||||
for (int frame = a1->frame + 1; frame < frameCount; frame++) {
|
||||
for (int frame = door->frame + 1; frame < frameCount; frame++) {
|
||||
int x;
|
||||
int y;
|
||||
artGetFrameOffsets(art, frame, a1->rotation, &x, &y);
|
||||
_obj_offset(a1, x, y, &temp);
|
||||
artGetFrameOffsets(art, frame, door->rotation, &x, &y);
|
||||
_obj_offset(door, x, y, &temp);
|
||||
}
|
||||
|
||||
objectSetFrame(a1, frameCount - 1, &temp);
|
||||
objectSetFrame(door, frameCount - 1, &temp);
|
||||
rectUnion(&dirty, &temp, &dirty);
|
||||
|
||||
tileWindowRefreshRect(&dirty, gElevation);
|
||||
@@ -1705,20 +1707,20 @@ static int _check_door_state(Object* a1, Object* a2)
|
||||
}
|
||||
|
||||
// 0x49CCB8
|
||||
int _obj_use_door(Object* a1, Object* a2, int a3)
|
||||
int _obj_use_door(Object* user, Object* door, bool animateOnly)
|
||||
{
|
||||
if (objectIsLocked(a2)) {
|
||||
const char* sfx = sfxBuildOpenName(a2, SCENERY_SOUND_EFFECT_LOCKED);
|
||||
if (objectIsLocked(door)) {
|
||||
const char* sfx = sfxBuildOpenName(door, SCENERY_SOUND_EFFECT_LOCKED);
|
||||
soundPlayFile(sfx);
|
||||
}
|
||||
|
||||
bool scriptOverrides = false;
|
||||
if (a2->sid != -1) {
|
||||
scriptSetObjects(a2->sid, a1, a2);
|
||||
scriptExecProc(a2->sid, SCRIPT_PROC_USE);
|
||||
if (door->sid != -1) {
|
||||
scriptSetObjects(door->sid, user, door);
|
||||
scriptExecProc(door->sid, SCRIPT_PROC_USE);
|
||||
|
||||
Script* script;
|
||||
if (scriptGetScript(a2->sid, &script) == -1) {
|
||||
if (scriptGetScript(door->sid, &script) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1729,23 +1731,25 @@ int _obj_use_door(Object* a1, Object* a2, int a3)
|
||||
int start;
|
||||
int end;
|
||||
int step;
|
||||
if (a2->frame != 0) {
|
||||
if (_obj_blocking_at(nullptr, a2->tile, a2->elevation) != nullptr) {
|
||||
if (door->frame != 0) {
|
||||
if (_obj_blocking_at(nullptr, door->tile, door->elevation) != nullptr) {
|
||||
MessageListItem messageListItem;
|
||||
char* text = getmsg(&gProtoMessageList, &messageListItem, 597);
|
||||
displayMonitorAddMessage(text);
|
||||
return -1;
|
||||
}
|
||||
start = 1;
|
||||
end = (a3 == 0) - 1;
|
||||
// TODO: strange logic, check if correct
|
||||
end = animateOnly ? -1 : 0;
|
||||
step = -1;
|
||||
} else {
|
||||
if (a2->data.scenery.door.openFlags & 0x01) {
|
||||
if (door->data.scenery.door.openFlags & 0x01) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
start = 0;
|
||||
end = (a3 != 0) + 1;
|
||||
// TODO: strange logic, check if correct
|
||||
end = animateOnly ? 2 : 1;
|
||||
step = 1;
|
||||
}
|
||||
|
||||
@@ -1753,27 +1757,27 @@ int _obj_use_door(Object* a1, Object* a2, int a3)
|
||||
|
||||
for (int i = start; i != end; i += step) {
|
||||
if (i != 0) {
|
||||
if (a3 == 0) {
|
||||
animationRegisterCallback(a2, a2, (AnimationCallback*)_set_door_state_closed, -1);
|
||||
if (!animateOnly) {
|
||||
animationRegisterCallback(door, door, (AnimationCallback*)_set_door_state_closed, -1);
|
||||
}
|
||||
|
||||
const char* sfx = sfxBuildOpenName(a2, SCENERY_SOUND_EFFECT_CLOSED);
|
||||
animationRegisterPlaySoundEffect(a2, sfx, -1);
|
||||
const char* sfx = sfxBuildOpenName(door, SCENERY_SOUND_EFFECT_CLOSED);
|
||||
animationRegisterPlaySoundEffect(door, sfx, -1);
|
||||
|
||||
animationRegisterAnimateReversed(a2, ANIM_STAND, 0);
|
||||
animationRegisterAnimateReversed(door, ANIM_STAND, 0);
|
||||
} else {
|
||||
if (a3 == 0) {
|
||||
animationRegisterCallback(a2, a2, (AnimationCallback*)_set_door_state_open, -1);
|
||||
if (!animateOnly) {
|
||||
animationRegisterCallback(door, door, (AnimationCallback*)_set_door_state_open, -1);
|
||||
}
|
||||
|
||||
const char* sfx = sfxBuildOpenName(a2, SCENERY_SOUND_EFFECT_OPEN);
|
||||
animationRegisterPlaySoundEffect(a2, sfx, -1);
|
||||
const char* sfx = sfxBuildOpenName(door, SCENERY_SOUND_EFFECT_OPEN);
|
||||
animationRegisterPlaySoundEffect(door, sfx, -1);
|
||||
|
||||
animationRegisterAnimate(a2, ANIM_STAND, 0);
|
||||
animationRegisterAnimate(door, ANIM_STAND, 0);
|
||||
}
|
||||
}
|
||||
|
||||
animationRegisterCallbackForced(a2, a2, (AnimationCallback*)_check_door_state, -1);
|
||||
animationRegisterCallbackForced(door, door, (AnimationCallback*)_check_door_state, -1);
|
||||
|
||||
reg_anim_end();
|
||||
}
|
||||
@@ -2177,37 +2181,40 @@ int objectUnjamAll()
|
||||
|
||||
// critter_attempt_placement
|
||||
// 0x49D4D4
|
||||
int _obj_attempt_placement(Object* obj, int tile, int elevation, int a4)
|
||||
int _obj_attempt_placement(Object* obj, int tile, int elevation, int radius)
|
||||
{
|
||||
constexpr int maxDist = 7;
|
||||
constexpr int maxAttempts = 100;
|
||||
|
||||
if (tile == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int newTile = tile;
|
||||
if (_obj_blocking_at(nullptr, tile, elevation) != nullptr) {
|
||||
int v6 = a4;
|
||||
if (a4 < 1) {
|
||||
v6 = 1;
|
||||
}
|
||||
|
||||
// Find a suitable alternative tile where the dude can get to.
|
||||
int dist = radius >= 1 ? radius : 1;
|
||||
int attempts = 0;
|
||||
while (v6 < 7) {
|
||||
while (dist < maxDist) {
|
||||
attempts++;
|
||||
if (attempts >= 100) {
|
||||
if (attempts >= maxAttempts) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (int rotation = 0; rotation < ROTATION_COUNT; rotation++) {
|
||||
newTile = tileGetTileInDirection(tile, rotation, v6);
|
||||
if (_obj_blocking_at(nullptr, newTile, elevation) == nullptr && v6 > 1 && _make_path(gDude, gDude->tile, newTile, nullptr, 0) != 0) {
|
||||
newTile = tileGetTileInDirection(tile, rotation, dist);
|
||||
if (_obj_blocking_at(nullptr, newTile, elevation) == nullptr
|
||||
&& dist > 1
|
||||
&& _make_path(gDude, gDude->tile, newTile, nullptr, 0) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
v6++;
|
||||
dist++;
|
||||
}
|
||||
|
||||
if (a4 != 1 && v6 > a4 + 2) {
|
||||
// If location is too far (or not found at all), find any free adjacent tile, regardless if it's reachable or not.
|
||||
if (radius != 1 && dist > radius + 2) {
|
||||
for (int rotation = 0; rotation < ROTATION_COUNT; rotation++) {
|
||||
int candidate = tileGetTileInDirection(tile, rotation, 1);
|
||||
if (_obj_blocking_at(nullptr, candidate, elevation) == nullptr) {
|
||||
|
||||
@@ -17,11 +17,11 @@ int _obj_drop(Object* a1, Object* a2);
|
||||
int _obj_destroy(Object* obj);
|
||||
int _protinst_use_item(Object* a1, Object* a2);
|
||||
int _obj_use_item(Object* a1, Object* a2);
|
||||
int _protinst_use_item_on(Object* a1, Object* a2, Object* item);
|
||||
int _obj_use_item_on(Object* a1, Object* a2, Object* a3);
|
||||
int _protinst_use_item_on(Object* critter, Object* targetObj, Object* item);
|
||||
int _obj_use_item_on(Object* user, Object* targetObj, Object* item);
|
||||
int _check_scenery_ap_cost(Object* obj, Object* a2);
|
||||
int _obj_use(Object* a1, Object* a2);
|
||||
int _obj_use_door(Object* a1, Object* a2, int a3);
|
||||
int _obj_use(Object* user, Object* targetObj);
|
||||
int _obj_use_door(Object* user, Object* doorObj, bool animateOnly = false);
|
||||
int _obj_use_container(Object* critter, Object* item);
|
||||
int _obj_use_skill_on(Object* a1, Object* a2, int skill);
|
||||
bool objectIsLocked(Object* obj);
|
||||
@@ -33,7 +33,7 @@ int objectClose(Object* obj);
|
||||
int objectJamLock(Object* obj);
|
||||
int objectUnjamLock(Object* obj);
|
||||
int objectUnjamAll();
|
||||
int _obj_attempt_placement(Object* obj, int tile, int elevation, int a4);
|
||||
int _obj_attempt_placement(Object* obj, int tile, int elevation, int radius);
|
||||
int _objPMAttemptPlacement(Object* obj, int tile, int elevation);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -603,7 +603,7 @@ Object* scriptGetSelf(Program* program)
|
||||
}
|
||||
|
||||
object->id = scriptsNewObjectId();
|
||||
v1->field_1C = object->id;
|
||||
v1->ownerId = object->id;
|
||||
v1->owner = object;
|
||||
|
||||
for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) {
|
||||
@@ -924,7 +924,7 @@ int scriptsHandleRequests()
|
||||
}
|
||||
|
||||
if ((gScriptsRequests & SCRIPT_REQUEST_ELEVATOR) != 0) {
|
||||
int map = gMapHeader.field_34;
|
||||
int map = gMapHeader.index;
|
||||
int elevation = gScriptsRequestedElevatorLevel;
|
||||
int tile = -1;
|
||||
|
||||
@@ -933,7 +933,7 @@ int scriptsHandleRequests()
|
||||
if (elevatorSelectLevel(gScriptsRequestedElevatorType, &map, &elevation, &tile) != -1) {
|
||||
automapSaveCurrent();
|
||||
|
||||
if (map == gMapHeader.field_34) {
|
||||
if (map == gMapHeader.index) {
|
||||
if (elevation == gElevation) {
|
||||
reg_anim_clear(gDude);
|
||||
objectSetRotation(gDude, ROTATION_SE, nullptr);
|
||||
@@ -1034,14 +1034,14 @@ int scriptsHandleRequests()
|
||||
int _scripts_check_state_in_combat()
|
||||
{
|
||||
if ((gScriptsRequests & SCRIPT_REQUEST_ELEVATOR) != 0) {
|
||||
int map = gMapHeader.field_34;
|
||||
int map = gMapHeader.index;
|
||||
int elevation = gScriptsRequestedElevatorLevel;
|
||||
int tile = -1;
|
||||
|
||||
if (elevatorSelectLevel(gScriptsRequestedElevatorType, &map, &elevation, &tile) != -1) {
|
||||
automapSaveCurrent();
|
||||
|
||||
if (map == gMapHeader.field_34) {
|
||||
if (map == gMapHeader.index) {
|
||||
if (elevation == gElevation) {
|
||||
reg_anim_clear(gDude);
|
||||
objectSetRotation(gDude, ROTATION_SE, nullptr);
|
||||
@@ -1276,7 +1276,7 @@ int scriptExecProc(int sid, int proc)
|
||||
clock();
|
||||
|
||||
char name[16];
|
||||
if (scriptsGetFileName(script->field_14 & 0xFFFFFF, name, sizeof(name)) == -1) {
|
||||
if (scriptsGetFileName(script->index & 0xFFFFFF, name, sizeof(name)) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1817,13 +1817,13 @@ static int scriptWrite(Script* scr, File* stream)
|
||||
}
|
||||
|
||||
if (fileWriteInt32(stream, scr->flags) == -1) return -1;
|
||||
if (fileWriteInt32(stream, scr->field_14) == -1) return -1;
|
||||
if (fileWriteInt32(stream, scr->index) == -1) return -1;
|
||||
// NOTE: Original code writes `scr->program` pointer which is meaningless.
|
||||
if (fileWriteInt32(stream, 0) == -1) return -1;
|
||||
if (fileWriteInt32(stream, scr->field_1C) == -1) return -1;
|
||||
if (fileWriteInt32(stream, scr->ownerId) == -1) return -1;
|
||||
if (fileWriteInt32(stream, scr->localVarsOffset) == -1) return -1;
|
||||
if (fileWriteInt32(stream, scr->localVarsCount) == -1) return -1;
|
||||
if (fileWriteInt32(stream, scr->field_28) == -1) return -1;
|
||||
if (fileWriteInt32(stream, scr->returnValue) == -1) return -1;
|
||||
if (fileWriteInt32(stream, scr->action) == -1) return -1;
|
||||
if (fileWriteInt32(stream, scr->fixedParam) == -1) return -1;
|
||||
if (fileWriteInt32(stream, scr->actionBeingUsed) == -1) return -1;
|
||||
@@ -1971,12 +1971,12 @@ static int scriptRead(Script* scr, File* stream)
|
||||
}
|
||||
|
||||
if (fileReadInt32(stream, &(scr->flags)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(scr->field_14)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(scr->index)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(prg)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(scr->field_1C)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(scr->ownerId)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(scr->localVarsOffset)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(scr->localVarsCount)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(scr->field_28)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(scr->returnValue)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(scr->action)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(scr->fixedParam)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(scr->actionBeingUsed)) == -1) return -1;
|
||||
@@ -2196,11 +2196,11 @@ int scriptAdd(int* sidPtr, int scriptType)
|
||||
scr->sp.built_tile = -1;
|
||||
scr->sp.radius = -1;
|
||||
scr->flags = 0;
|
||||
scr->field_14 = -1;
|
||||
scr->index = -1;
|
||||
scr->program = nullptr;
|
||||
scr->localVarsOffset = -1;
|
||||
scr->localVarsCount = 0;
|
||||
scr->field_28 = 0;
|
||||
scr->returnValue = 0;
|
||||
scr->action = 0;
|
||||
scr->fixedParam = 0;
|
||||
scr->owner = nullptr;
|
||||
@@ -2797,7 +2797,7 @@ int scriptGetLocalVar(int sid, int variable, ProgramValue& value)
|
||||
|
||||
if (script->localVarsCount == 0) {
|
||||
// NOTE: Uninline.
|
||||
_scr_find_str_run_info(script->field_14, &(script->field_50), sid);
|
||||
_scr_find_str_run_info(script->index, &(script->field_50), sid);
|
||||
}
|
||||
|
||||
if (script->localVarsCount > 0) {
|
||||
@@ -2825,7 +2825,7 @@ int scriptSetLocalVar(int sid, int variable, ProgramValue& value)
|
||||
|
||||
if (script->localVarsCount == 0) {
|
||||
// NOTE: Uninline.
|
||||
_scr_find_str_run_info(script->field_14, &(script->field_50), sid);
|
||||
_scr_find_str_run_info(script->index, &(script->field_50), sid);
|
||||
}
|
||||
|
||||
if (script->localVarsCount <= 0) {
|
||||
|
||||
@@ -102,12 +102,12 @@ typedef struct Script {
|
||||
int flags;
|
||||
|
||||
// scr_script_idx
|
||||
int field_14;
|
||||
int index;
|
||||
|
||||
Program* program;
|
||||
|
||||
// scr_oid
|
||||
int field_1C;
|
||||
int ownerId;
|
||||
|
||||
// scr_local_var_offset
|
||||
int localVarsOffset;
|
||||
@@ -115,8 +115,8 @@ typedef struct Script {
|
||||
// scr_num_local_vars
|
||||
int localVarsCount;
|
||||
|
||||
// return value?
|
||||
int field_28;
|
||||
// set by scr_return opcode
|
||||
int returnValue;
|
||||
|
||||
// Currently executed action.
|
||||
//
|
||||
|
||||
@@ -65,6 +65,8 @@ bool sfallConfigInit(int argc, char** argv)
|
||||
configSetString(&gSfallConfig, SFALL_CONFIG_SCRIPTS_KEY, SFALL_CONFIG_INI_CONFIG_FOLDER, "");
|
||||
configSetString(&gSfallConfig, SFALL_CONFIG_SCRIPTS_KEY, SFALL_CONFIG_GLOBAL_SCRIPT_PATHS, "");
|
||||
|
||||
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PIPBOY_AVAILABLE_AT_GAMESTART, 0);
|
||||
|
||||
char path[COMPAT_MAX_PATH];
|
||||
char* executable = argv[0];
|
||||
char* ch = strrchr(executable, '\\');
|
||||
|
||||
@@ -75,6 +75,7 @@ namespace fallout {
|
||||
#define SFALL_CONFIG_VERSION_STRING "VersionString"
|
||||
#define SFALL_CONFIG_CONFIG_FILE "ConfigFile"
|
||||
#define SFALL_CONFIG_PATCH_FILE "PatchFile"
|
||||
#define SFALL_CONFIG_PIPBOY_AVAILABLE_AT_GAMESTART "PipBoyAvailableAtGameStart"
|
||||
|
||||
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_MULTIPLIER 1
|
||||
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_DIVISOR 3
|
||||
|
||||
@@ -292,7 +292,7 @@ static void op_abs(Program* program)
|
||||
static void op_get_script(Program* program)
|
||||
{
|
||||
Object* obj = static_cast<Object*>(programStackPopPointer(program));
|
||||
programStackPushInteger(program, obj->field_80 + 1);
|
||||
programStackPushInteger(program, obj->scriptIndex + 1);
|
||||
}
|
||||
|
||||
// get_proto_data
|
||||
|
||||
@@ -29,7 +29,7 @@ int skillAddForce(Object* critter, int skill);
|
||||
int skillsGetCost(int a1);
|
||||
int skillSub(Object* critter, int skill);
|
||||
int skillSubForce(Object* critter, int skill);
|
||||
int skillRoll(Object* critter, int skill, int a3, int* a4);
|
||||
int skillRoll(Object* critter, int skill, int modifier, int* howMuch);
|
||||
char* skillGetName(int skill);
|
||||
char* skillGetDescription(int skill);
|
||||
char* skillGetAttributes(int skill);
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "memory.h"
|
||||
#include "mouse.h"
|
||||
#include "palette.h"
|
||||
#include "pointer_registry.h"
|
||||
#include "svga.h"
|
||||
#include "text_font.h"
|
||||
#include "vcr.h"
|
||||
@@ -35,9 +34,6 @@ static void _win_clip(Window* window, RectListNode** rect, unsigned char* a3);
|
||||
static void win_drag(int win);
|
||||
static void _refresh_all(Rect* rect, unsigned char* a2);
|
||||
static Button* buttonGetButton(int btn, Window** out_win);
|
||||
static int paletteOpenFileImpl(const char* path, int flags);
|
||||
static int paletteReadFileImpl(int fd, void* buf, size_t count);
|
||||
static int paletteCloseFileImpl(int fd);
|
||||
static Button* buttonCreateInternal(int win, int x, int y, int width, int height, int mouseEnterEventCode, int mouseExitEventCode, int mouseDownEventCode, int mouseUpEventCode, int flags, unsigned char* up, unsigned char* dn, unsigned char* hover);
|
||||
static int _GNW_check_buttons(Window* window, int* keyCodePtr);
|
||||
static bool _button_under_mouse(Button* button, Rect* rect);
|
||||
@@ -184,9 +180,6 @@ int windowManagerInit(VideoSystemInitProc* videoSystemInitProc, VideoSystemExitP
|
||||
_buffering = false;
|
||||
_doing_refresh_all = 0;
|
||||
|
||||
colorPaletteSetFileIO(paletteOpenFileImpl, paletteReadFileImpl, paletteCloseFileImpl);
|
||||
colorPaletteSetMemoryProcs(internal_malloc, internal_realloc, internal_free);
|
||||
|
||||
if (!_initColors()) {
|
||||
unsigned char* palette = (unsigned char*)internal_malloc(768);
|
||||
if (palette == nullptr) {
|
||||
@@ -1345,52 +1338,6 @@ void programWindowSetTitle(const char* title)
|
||||
}
|
||||
}
|
||||
|
||||
// [open] implementation for palette operations backed by [XFile].
|
||||
//
|
||||
// 0x4D8174
|
||||
int paletteOpenFileImpl(const char* path, int flags)
|
||||
{
|
||||
char mode[4];
|
||||
memset(mode, 0, sizeof(mode));
|
||||
|
||||
if ((flags & 0x01) != 0) {
|
||||
mode[0] = 'w';
|
||||
} else if ((flags & 0x10) != 0) {
|
||||
mode[0] = 'a';
|
||||
} else {
|
||||
mode[0] = 'r';
|
||||
}
|
||||
|
||||
if ((flags & 0x100) != 0) {
|
||||
mode[1] = 't';
|
||||
} else if ((flags & 0x200) != 0) {
|
||||
mode[1] = 'b';
|
||||
}
|
||||
|
||||
File* stream = fileOpen(path, mode);
|
||||
if (stream != nullptr) {
|
||||
return ptrToInt(stream);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// [read] implementation for palette file operations backed by [XFile].
|
||||
//
|
||||
// 0x4D81E8
|
||||
int paletteReadFileImpl(int fd, void* buf, size_t count)
|
||||
{
|
||||
return fileRead(buf, 1, count, (File*)intToPtr(fd));
|
||||
}
|
||||
|
||||
// [close] implementation for palette file operations backed by [XFile].
|
||||
//
|
||||
// 0x4D81E0
|
||||
int paletteCloseFileImpl(int fd)
|
||||
{
|
||||
return fileClose((File*)intToPtr(fd));
|
||||
}
|
||||
|
||||
// 0x4D8200
|
||||
bool showMesageBox(const char* text)
|
||||
{
|
||||
|
||||
129
src/worldmap.cc
129
src/worldmap.cc
@@ -167,6 +167,11 @@ typedef enum EncounterConditionalOperator {
|
||||
ENCOUNTER_CONDITIONAL_OPERATOR_COUNT,
|
||||
} EncounterConditionalOperator;
|
||||
|
||||
typedef enum EncounterRatioMode {
|
||||
ENCOUNTER_RATIO_MODE_USE_RATIO,
|
||||
ENCOUNTER_RATIO_MODE_SINGLE,
|
||||
} EncounterRatioMode;
|
||||
|
||||
typedef enum Daytime {
|
||||
DAY_PART_MORNING,
|
||||
DAY_PART_AFTERNOON,
|
||||
@@ -326,7 +331,7 @@ typedef struct EncounterItem {
|
||||
typedef struct EncounterEntry {
|
||||
char field_0[40];
|
||||
int field_28;
|
||||
int field_2C;
|
||||
int ratioMode;
|
||||
int ratio;
|
||||
int pid;
|
||||
int flags;
|
||||
@@ -1689,7 +1694,7 @@ static int wmParseEncBaseSubTypeStr(EncounterEntry* encounterEntry, char** strin
|
||||
}
|
||||
|
||||
if (strParseIntWithKey(&string, "ratio", &(encounterEntry->ratio), ":") == 0) {
|
||||
encounterEntry->field_2C = 0;
|
||||
encounterEntry->ratioMode = ENCOUNTER_RATIO_MODE_USE_RATIO;
|
||||
}
|
||||
|
||||
if (strstr(string, "dead,") == string) {
|
||||
@@ -1739,7 +1744,7 @@ static int wmEncBaseTypeSlotInit(Encounter* encounter)
|
||||
static int wmEncBaseSubTypeSlotInit(EncounterEntry* encounterEntry)
|
||||
{
|
||||
encounterEntry->field_28 = -1;
|
||||
encounterEntry->field_2C = 1;
|
||||
encounterEntry->ratioMode = ENCOUNTER_RATIO_MODE_SINGLE;
|
||||
encounterEntry->ratio = 100;
|
||||
encounterEntry->pid = -1;
|
||||
encounterEntry->flags = 0;
|
||||
@@ -2822,13 +2827,13 @@ bool wmMapIdxIsSaveable(int mapIdx)
|
||||
// 0x4BFA64
|
||||
bool wmMapIsSaveable()
|
||||
{
|
||||
return (wmMapInfoList[gMapHeader.field_34].flags & MAP_SAVED) != 0;
|
||||
return (wmMapInfoList[gMapHeader.index].flags & MAP_SAVED) != 0;
|
||||
}
|
||||
|
||||
// 0x4BFA90
|
||||
bool wmMapDeadBodiesAge()
|
||||
{
|
||||
return (wmMapInfoList[gMapHeader.field_34].flags & MAP_DEAD_BODIES_AGE) != 0;
|
||||
return (wmMapInfoList[gMapHeader.index].flags & MAP_DEAD_BODIES_AGE) != 0;
|
||||
}
|
||||
|
||||
// 0x4BFABC
|
||||
@@ -2839,7 +2844,7 @@ bool wmMapCanRestHere(int elevation)
|
||||
// NOTE: I'm not sure why they're copied.
|
||||
memcpy(flags, _can_rest_here, sizeof(flags));
|
||||
|
||||
MapInfo* map = &(wmMapInfoList[gMapHeader.field_34]);
|
||||
MapInfo* map = &(wmMapInfoList[gMapHeader.index]);
|
||||
|
||||
return (map->flags & flags[elevation]) != 0;
|
||||
}
|
||||
@@ -3791,11 +3796,11 @@ static int wmSetupCritterObjs(int encounterIndex, Object** critterPtr, int critt
|
||||
}
|
||||
|
||||
int encounterEntryCritterCount;
|
||||
switch (encounterEntry->field_2C) {
|
||||
case 0:
|
||||
switch (encounterEntry->ratioMode) {
|
||||
case ENCOUNTER_RATIO_MODE_USE_RATIO:
|
||||
encounterEntryCritterCount = encounterEntry->ratio * critterCount / 100;
|
||||
break;
|
||||
case 1:
|
||||
case ENCOUNTER_RATIO_MODE_SINGLE:
|
||||
encounterEntryCritterCount = 1;
|
||||
break;
|
||||
default:
|
||||
@@ -3884,7 +3889,7 @@ static int wmSetupCritterObjs(int encounterIndex, Object** critterPtr, int critt
|
||||
_obj_disconnect(item, nullptr);
|
||||
|
||||
if (encounterItem->isEquipped) {
|
||||
if (_inven_wield(object, item, 1) == -1) {
|
||||
if (_inven_wield(object, item, HAND_RIGHT) == -1) {
|
||||
debugPrint("\nERROR: wmSetupCritterObjs: Inven Wield Failed: %d on %s: Critter Fid: %d", item->pid, critterGetName(object), object->fid);
|
||||
}
|
||||
}
|
||||
@@ -3924,33 +3929,32 @@ static int wmSetupRndNextTileNumInit(Encounter* encounter)
|
||||
case ENCOUNTER_FORMATION_TYPE_DOUBLE_LINE:
|
||||
case ENCOUNTER_FORMATION_TYPE_WEDGE:
|
||||
case ENCOUNTER_FORMATION_TYPE_CONE:
|
||||
case ENCOUNTER_FORMATION_TYPE_HUDDLE:
|
||||
if (1) {
|
||||
MapInfo* map = &(wmMapInfoList[gMapHeader.field_34]);
|
||||
if (map->startPointsLength != 0) {
|
||||
int rspIndex = randomBetween(0, map->startPointsLength - 1);
|
||||
MapStartPointInfo* rsp = &(map->startPoints[rspIndex]);
|
||||
case ENCOUNTER_FORMATION_TYPE_HUDDLE: {
|
||||
MapInfo* map = &(wmMapInfoList[gMapHeader.index]);
|
||||
if (map->startPointsLength != 0) {
|
||||
int rspIndex = randomBetween(0, map->startPointsLength - 1);
|
||||
MapStartPointInfo* rsp = &(map->startPoints[rspIndex]);
|
||||
|
||||
wmRndCenterTiles[0] = rsp->tile;
|
||||
wmRndCenterTiles[1] = wmRndCenterTiles[0];
|
||||
wmRndCenterTiles[0] = rsp->tile;
|
||||
wmRndCenterTiles[1] = wmRndCenterTiles[0];
|
||||
|
||||
wmRndCenterRotations[0] = rsp->rotation;
|
||||
wmRndCenterRotations[1] = wmRndCenterRotations[0];
|
||||
} else {
|
||||
wmRndCenterRotations[0] = 0;
|
||||
wmRndCenterRotations[1] = 0;
|
||||
wmRndCenterRotations[0] = rsp->rotation;
|
||||
wmRndCenterRotations[1] = wmRndCenterRotations[0];
|
||||
} else {
|
||||
wmRndCenterRotations[0] = 0;
|
||||
wmRndCenterRotations[1] = 0;
|
||||
|
||||
wmRndCenterTiles[0] = gDude->tile;
|
||||
wmRndCenterTiles[1] = gDude->tile;
|
||||
}
|
||||
|
||||
wmRndTileDirs[0] = tileGetRotationTo(wmRndCenterTiles[0], gDude->tile);
|
||||
wmRndTileDirs[1] = tileGetRotationTo(wmRndCenterTiles[1], gDude->tile);
|
||||
|
||||
wmRndOriginalCenterTile = wmRndCenterTiles[0];
|
||||
|
||||
return 0;
|
||||
wmRndCenterTiles[0] = gDude->tile;
|
||||
wmRndCenterTiles[1] = gDude->tile;
|
||||
}
|
||||
|
||||
wmRndTileDirs[0] = tileGetRotationTo(wmRndCenterTiles[0], gDude->tile);
|
||||
wmRndTileDirs[1] = tileGetRotationTo(wmRndCenterTiles[1], gDude->tile);
|
||||
|
||||
wmRndOriginalCenterTile = wmRndCenterTiles[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
debugPrint("\nERROR: wmSetupCritterObjs: invalid Formation Type!");
|
||||
|
||||
@@ -3958,6 +3962,8 @@ static int wmSetupRndNextTileNumInit(Encounter* encounter)
|
||||
}
|
||||
}
|
||||
|
||||
// Determines tile to place the next object in the EncounterEntry at.
|
||||
//
|
||||
// wmSetupRndNextTileNum
|
||||
// 0x4C16F0
|
||||
static int wmSetupRndNextTileNum(Encounter* encounter, EncounterEntry* encounterEntry, int* tilePtr)
|
||||
@@ -3965,41 +3971,40 @@ static int wmSetupRndNextTileNum(Encounter* encounter, EncounterEntry* encounter
|
||||
int tile;
|
||||
|
||||
int attempt = 0;
|
||||
while (1) {
|
||||
while (true) {
|
||||
switch (encounter->position) {
|
||||
case ENCOUNTER_FORMATION_TYPE_SURROUNDING:
|
||||
if (1) {
|
||||
int distance;
|
||||
if (encounterEntry->distance != 0) {
|
||||
distance = encounterEntry->distance;
|
||||
} else {
|
||||
distance = randomBetween(-2, 2);
|
||||
case ENCOUNTER_FORMATION_TYPE_SURROUNDING: {
|
||||
int distance;
|
||||
if (encounterEntry->distance != 0) {
|
||||
distance = encounterEntry->distance;
|
||||
} else {
|
||||
distance = randomBetween(-2, 2);
|
||||
|
||||
distance += critterGetStat(gDude, STAT_PERCEPTION);
|
||||
distance += critterGetStat(gDude, STAT_PERCEPTION);
|
||||
|
||||
if (perkHasRank(gDude, PERK_CAUTIOUS_NATURE)) {
|
||||
distance += 3;
|
||||
}
|
||||
if (perkHasRank(gDude, PERK_CAUTIOUS_NATURE)) {
|
||||
distance += 3;
|
||||
}
|
||||
|
||||
if (distance < 0) {
|
||||
distance = 0;
|
||||
}
|
||||
|
||||
int origin = encounterEntry->tile;
|
||||
if (origin == -1) {
|
||||
origin = tileGetTileInDirection(gDude->tile, wmRndTileDirs[0], distance);
|
||||
}
|
||||
|
||||
if (++wmRndTileDirs[0] >= ROTATION_COUNT) {
|
||||
wmRndTileDirs[0] = 0;
|
||||
}
|
||||
|
||||
int randomizedDistance = randomBetween(0, distance / 2);
|
||||
int randomizedRotation = randomBetween(0, ROTATION_COUNT - 1);
|
||||
tile = tileGetTileInDirection(origin, (randomizedRotation + wmRndTileDirs[0]) % ROTATION_COUNT, randomizedDistance);
|
||||
}
|
||||
|
||||
if (distance < 0) {
|
||||
distance = 0;
|
||||
}
|
||||
|
||||
int origin = encounterEntry->tile;
|
||||
if (origin == -1) {
|
||||
origin = tileGetTileInDirection(gDude->tile, wmRndTileDirs[0], distance);
|
||||
}
|
||||
|
||||
if (++wmRndTileDirs[0] >= ROTATION_COUNT) {
|
||||
wmRndTileDirs[0] = 0;
|
||||
}
|
||||
|
||||
int randomizedDistance = randomBetween(0, distance / 2);
|
||||
int randomizedRotation = randomBetween(0, ROTATION_COUNT - 1);
|
||||
tile = tileGetTileInDirection(origin, (randomizedRotation + wmRndTileDirs[0]) % ROTATION_COUNT, randomizedDistance);
|
||||
break;
|
||||
}
|
||||
case ENCOUNTER_FORMATION_TYPE_STRAIGHT_LINE:
|
||||
tile = wmRndCenterTiles[wmRndIndex];
|
||||
if (wmRndCallCount != 0) {
|
||||
|
||||
1
third_party/fpattern/CMakeLists.txt
vendored
1
third_party/fpattern/CMakeLists.txt
vendored
@@ -5,6 +5,7 @@ FetchContent_Declare(fpattern
|
||||
GIT_TAG 8523173ec252c3b796fcdfca0fcc6329642fbbe3 # v1.9
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(fpattern)
|
||||
|
||||
11
third_party/sdl2/CMakeLists.txt
vendored
11
third_party/sdl2/CMakeLists.txt
vendored
@@ -1,5 +1,4 @@
|
||||
# Build static lib only
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
set(SDL_SHARED OFF)
|
||||
set(SDL_STATIC ON)
|
||||
|
||||
@@ -15,14 +14,12 @@ include(FetchContent)
|
||||
FetchContent_Declare(sdl2
|
||||
GIT_REPOSITORY "https://github.com/libsdl-org/SDL"
|
||||
GIT_TAG "release-2.26.1"
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
|
||||
FetchContent_GetProperties(sdl2)
|
||||
if (NOT sdl2_POPULATED)
|
||||
FetchContent_Populate(sdl2)
|
||||
endif()
|
||||
|
||||
add_subdirectory(${sdl2_SOURCE_DIR} ${sdl2_BINARY_DIR} EXCLUDE_FROM_ALL)
|
||||
FetchContent_MakeAvailable(sdl2)
|
||||
|
||||
set(SDL2_INCLUDE_DIRS ${sdl2_SOURCE_DIR} ${sdl2_BINARY_DIR} PARENT_SCOPE)
|
||||
set(SDL2_LIBRARIES SDL2-static SDL2::SDL2main PARENT_SCOPE)
|
||||
|
||||
10
third_party/zlib/CMakeLists.txt
vendored
10
third_party/zlib/CMakeLists.txt
vendored
@@ -6,14 +6,12 @@ include(FetchContent)
|
||||
FetchContent_Declare(zlib
|
||||
GIT_REPOSITORY "https://github.com/madler/zlib"
|
||||
GIT_TAG "v1.3.1"
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
|
||||
FetchContent_GetProperties(zlib)
|
||||
if (NOT zlib_POPULATED)
|
||||
FetchContent_Populate(zlib)
|
||||
endif()
|
||||
|
||||
add_subdirectory("${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}" EXCLUDE_FROM_ALL)
|
||||
FetchContent_MakeAvailable(zlib)
|
||||
|
||||
set(ZLIB_LIBRARIES "zlibstatic" PARENT_SCOPE)
|
||||
set(ZLIB_INCLUDE_DIRS "${zlib_SOURCE_DIR}" "${zlib_BINARY_DIR}" PARENT_SCOPE)
|
||||
|
||||
Reference in New Issue
Block a user